xref: /haiku/src/libs/print/libprint/JobSetupDlg.cpp (revision f75a7bf508f3156d63a14f8fd77c5e0ca4d08c42)
1 /*
2  * JobSetupDlg.cpp
3  * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4  */
5 
6 #include <cstdio>
7 #include <cstring>
8 #include <cstdlib>
9 #include <string>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <sys/stat.h>
13 #include <math.h>
14 
15 #include <Alert.h>
16 #include <Bitmap.h>
17 #include <Box.h>
18 #include <Button.h>
19 #include <CheckBox.h>
20 #include <Looper.h>
21 #include <MessageFilter.h>
22 #include <MenuField.h>
23 #include <MenuItem.h>
24 #include <Message.h>
25 #include <Point.h>
26 #include <PopUpMenu.h>
27 #include <PrintJob.h>
28 #include <RadioButton.h>
29 #include <Rect.h>
30 #include <Slider.h>
31 #include <String.h>
32 #include <TextControl.h>
33 #include <TextView.h>
34 #include <View.h>
35 
36 #include "HalftoneView.h"
37 #include "JobSetupDlg.h"
38 #include "JobData.h"
39 #include "JSDSlider.h"
40 #include "PagesView.h"
41 #include "PrinterData.h"
42 #include "PrinterCap.h"
43 #include "DbgMsg.h"
44 
45 #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE))
46 using namespace std;
47 #else
48 #define std
49 #endif
50 
51 //#define	PRINT_COPIES		100
52 
53 #define QUALITY_H			10
54 #define QUALITY_V			10
55 #define QUALITY_WIDTH		180
56 
57 	#define BPP_H			10
58 	#define BPP_V			15
59 	#define BPP_WIDTH		120
60 	#define BPP_HEIGHT		16
61 
62 	#define DITHER_H        BPP_H
63 	#define DITHER_V        BPP_V + BPP_HEIGHT + 10
64 	#define DITHER_WIDTH    BPP_WIDTH
65 	#define DITHER_HEIGHT   BPP_HEIGHT
66 
67 	#define GAMMA_H			BPP_H
68 	#define GAMMA_V			DITHER_V + DITHER_HEIGHT + 10
69 	#define GAMMA_WIDTH		QUALITY_WIDTH - 20
70 	#define GAMMA_HEIGHT	55 // BPP_HEIGHT
71 
72 	#define INK_DENSITY_H           BPP_H
73 	#define INK_DENSITY_V           GAMMA_V + GAMMA_HEIGHT + 5
74 	#define INK_DENSITY_WIDTH       GAMMA_WIDTH
75 	#define INK_DENSITY_HEIGHT      55 // BPP_HEIGHT
76 
77 	#define HALFTONE_H      INK_DENSITY_H
78 	#define HALFTONE_V      INK_DENSITY_V + INK_DENSITY_HEIGHT + 5
79 	#define HALFTONE_WIDTH  160
80 	#define HALFTONE_HEIGHT 4*11
81 
82 #define QUALITY_HEIGHT		HALFTONE_V + HALFTONE_HEIGHT + 5
83 
84 #define PAGERABGE_H			QUALITY_H
85 #define PAGERABGE_V			QUALITY_V + QUALITY_HEIGHT + 5
86 #define PAGERABGE_WIDTH		QUALITY_WIDTH
87 #define PAGERABGE_HEIGHT	70
88 
89 	#define ALL_H				 10
90 	#define ALL_V				 20
91 	#define ALL_WIDTH			 36
92 	#define ALL_HEIGHT			 16
93 
94 	#define SELECTION_H			ALL_H
95 	#define SELECTION_V			ALL_V + ALL_HEIGHT + 4
96 	#define SELECTION_WIDTH		16
97 	#define SELECTION_HEIGHT	16
98 
99 	#define FROM_H				(SELECTION_H + SELECTION_WIDTH + 1)
100 	#define FROM_V				ALL_V + 19
101 	#define FROM_WIDTH			73
102 	#define FROM_HEIGHT			16
103 
104 	#define TO_H				(FROM_H + FROM_WIDTH + 7)
105 	#define TO_V				FROM_V
106 	#define TO_WIDTH			59
107 	#define TO_HEIGHT			FROM_HEIGHT
108 
109 #define	PRINT_WIDTH			365
110 #define PRINT_HEIGHT		QUALITY_HEIGHT + PAGERABGE_HEIGHT + 60
111 
112 #define PAPERFEED_H			QUALITY_H + QUALITY_WIDTH + 10
113 #define PAPERFEED_V			QUALITY_V + 5
114 #define PAPERFEED_WIDTH		160
115 #define PAPERFEED_HEIGHT	16
116 
117 #define NUP_H			 	PAPERFEED_H
118 #define NUP_V			 	PAPERFEED_V + PAPERFEED_HEIGHT + 7
119 #define NUP_WIDTH		 	PAPERFEED_WIDTH
120 #define NUP_HEIGHT		 	16
121 #define	MENU_HEIGHT			16
122 
123 #define COPIES_H			PAPERFEED_H
124 #define COPIES_V			NUP_V + NUP_HEIGHT + 10
125 #define COPIES_WIDTH		140
126 #define COPIES_HEIGHT		16
127 
128 #define DUPLEX_H			PAPERFEED_H
129 #define DUPLEX_V			COPIES_V + COPIES_HEIGHT + 7
130 #define DUPLEX_WIDTH		PAPERFEED_WIDTH
131 #define DUPLEX_HEIGHT		16
132 
133 #define COLLATE_H			PAPERFEED_H
134 #define COLLATE_V			DUPLEX_V + DUPLEX_HEIGHT + 5
135 #define COLLATE_WIDTH		PAPERFEED_WIDTH
136 #define COLLATE_HEIGHT		16
137 
138 #define REVERSE_H			PAPERFEED_H
139 #define REVERSE_V			COLLATE_V + COLLATE_HEIGHT + 5
140 #define REVERSE_WIDTH		PAPERFEED_WIDTH
141 #define REVERSE_HEIGHT		16
142 
143 #define PAGES_H				PAPERFEED_H
144 #define PAGES_V				REVERSE_V + REVERSE_HEIGHT + 5
145 #define PAGES_WIDTH			PAPERFEED_WIDTH
146 #define PAGES_HEIGHT		40
147 
148 #define PAGE_SELECTION_H      PAPERFEED_H
149 #define PAGE_SELECTION_V      PAGES_V + PAGES_HEIGHT + 5
150 #define PAGE_SELECTION_WIDTH  PAPERFEED_WIDTH
151 #define PAGE_SELECTION_HEIGHT 3 * 16 + 30
152 
153 	#define PS_ALL_PAGES_H       10
154 	#define PS_ALL_PAGES_V       20
155 	#define PS_ALL_PAGES_WIDTH   PAGE_SELECTION_WIDTH - 20
156 	#define PS_ALL_PAGES_HEIGHT  16
157 
158 	#define PS_ODD_PAGES_H       PS_ALL_PAGES_H
159 	#define PS_ODD_PAGES_V       PS_ALL_PAGES_V + PS_ALL_PAGES_HEIGHT
160 	#define PS_ODD_PAGES_WIDTH   PS_ALL_PAGES_WIDTH
161 	#define PS_ODD_PAGES_HEIGHT  PS_ALL_PAGES_HEIGHT
162 
163 	#define PS_EVEN_PAGES_H       PS_ALL_PAGES_H
164 	#define PS_EVEN_PAGES_V       PS_ODD_PAGES_V + PS_ODD_PAGES_HEIGHT
165 	#define PS_EVEN_PAGES_WIDTH   PS_ALL_PAGES_WIDTH
166 	#define PS_EVEN_PAGES_HEIGHT  PS_ALL_PAGES_HEIGHT
167 
168 #define PRINT_BUTTON_WIDTH	70
169 #define PRINT_BUTTON_HEIGHT	20
170 
171 #define PRINT_LINE_V			(PRINT_HEIGHT - PRINT_BUTTON_HEIGHT - 23)
172 
173 #define PRINT_OK_BUTTON_H		(PRINT_WIDTH - PRINT_BUTTON_WIDTH - 10)
174 #define PRINT_OK_BUTTON_V		(PRINT_HEIGHT - PRINT_BUTTON_HEIGHT - 11)
175 
176 #define PREVIEW_H				(PRINT_OK_BUTTON_H - PRINT_BUTTON_WIDTH - 12)
177 #define PREVIEW_V				(PRINT_OK_BUTTON_V)
178 
179 #define PRINT_CANCEL_BUTTON_H		(PREVIEW_H	 - PRINT_BUTTON_WIDTH - 12)
180 #define PRINT_CANCEL_BUTTON_V	PRINT_OK_BUTTON_V
181 
182 const BRect quality_rect(
183 	QUALITY_H,
184 	QUALITY_V,
185 	QUALITY_H + QUALITY_WIDTH,
186 	QUALITY_V + QUALITY_HEIGHT);
187 
188 BRect bpp_rect(
189 	BPP_H,
190 	BPP_V,
191 	BPP_H + BPP_WIDTH,
192 	BPP_V + BPP_HEIGHT);
193 
194 BRect dither_rect(
195 	DITHER_H,
196 	DITHER_V,
197 	DITHER_H + DITHER_WIDTH,
198 	DITHER_V + DITHER_HEIGHT);
199 
200 const BRect ink_density_rect(
201 	INK_DENSITY_H,
202 	INK_DENSITY_V,
203 	INK_DENSITY_H + INK_DENSITY_WIDTH,
204 	INK_DENSITY_V + INK_DENSITY_HEIGHT);
205 
206 const BRect halftone_rect(
207 	HALFTONE_H,
208 	HALFTONE_V,
209 	HALFTONE_H + HALFTONE_WIDTH,
210 	HALFTONE_V + HALFTONE_HEIGHT);
211 
212 const BRect gamma_rect(
213 	GAMMA_H,
214 	GAMMA_V,
215 	GAMMA_H + GAMMA_WIDTH,
216 	GAMMA_V + GAMMA_HEIGHT);
217 
218 const BRect pagerange_rect(
219 	PAGERABGE_H,
220 	PAGERABGE_V,
221 	PAGERABGE_H + PAGERABGE_WIDTH,
222 	PAGERABGE_V + PAGERABGE_HEIGHT);
223 
224 const BRect all_button_rect(
225 	ALL_H,
226 	ALL_V,
227 	ALL_H + ALL_WIDTH,
228 	ALL_V + ALL_HEIGHT);
229 
230 const BRect selection_rect(
231 	SELECTION_H,
232 	SELECTION_V,
233 	SELECTION_H + SELECTION_WIDTH,
234 	SELECTION_V + SELECTION_HEIGHT);
235 
236 const BRect from_rect(
237 	FROM_H,
238 	FROM_V,
239 	FROM_H + FROM_WIDTH,
240 	FROM_V + FROM_HEIGHT);
241 
242 const BRect to_rect(
243 	TO_H,
244 	TO_V,
245 	TO_H + TO_WIDTH,
246 	TO_V + TO_HEIGHT);
247 
248 const BRect paperfeed_rect(
249 	PAPERFEED_H,
250 	PAPERFEED_V,
251 	PAPERFEED_H + PAPERFEED_WIDTH,
252 	PAPERFEED_V + PAPERFEED_HEIGHT);
253 
254 BRect nup_rect(
255 	NUP_H,
256 	NUP_V,
257 	NUP_H + NUP_WIDTH,
258 	NUP_V + NUP_HEIGHT);
259 
260 const BRect copies_rect(
261 	COPIES_H,
262 	COPIES_V,
263 	COPIES_H + COPIES_WIDTH,
264 	COPIES_V + COPIES_HEIGHT);
265 
266 const BRect duplex_rect(
267 	DUPLEX_H,
268 	DUPLEX_V,
269 	DUPLEX_H + DUPLEX_WIDTH,
270 	DUPLEX_V + DUPLEX_HEIGHT);
271 
272 const BRect collate_rect(
273 	COLLATE_H,
274 	COLLATE_V,
275 	COLLATE_H + COLLATE_WIDTH,
276 	COLLATE_V + COLLATE_HEIGHT);
277 
278 const BRect reverse_rect(
279 	REVERSE_H,
280 	REVERSE_V,
281 	REVERSE_H + REVERSE_WIDTH,
282 	REVERSE_V + REVERSE_HEIGHT);
283 
284 const BRect pages_rect(
285 	PAGES_H,
286 	PAGES_V,
287 	PAGES_H + PAGES_WIDTH,
288 	PAGES_V + PAGES_HEIGHT);
289 
290 const BRect page_selection_rect(
291 	PAGE_SELECTION_H,
292 	PAGE_SELECTION_V,
293 	PAGE_SELECTION_H + PAGE_SELECTION_WIDTH,
294 	PAGE_SELECTION_V + PAGE_SELECTION_HEIGHT);
295 
296 const BRect page_selection_all_pages_rect(
297 	PS_ALL_PAGES_H,
298 	PS_ALL_PAGES_V,
299 	PS_ALL_PAGES_H + PS_ALL_PAGES_WIDTH,
300 	PS_ALL_PAGES_V + PS_ALL_PAGES_HEIGHT);
301 
302 const BRect page_selection_odd_pages_rect(
303 	PS_ODD_PAGES_H,
304 	PS_ODD_PAGES_V,
305 	PS_ODD_PAGES_H + PS_ODD_PAGES_WIDTH,
306 	PS_ODD_PAGES_V + PS_ODD_PAGES_HEIGHT);
307 
308 const BRect page_selection_even_pages_rect(
309 	PS_EVEN_PAGES_H,
310 	PS_EVEN_PAGES_V,
311 	PS_EVEN_PAGES_H + PS_EVEN_PAGES_WIDTH,
312 	PS_EVEN_PAGES_V + PS_EVEN_PAGES_HEIGHT);
313 
314 const BRect ok_rect(
315 	PRINT_OK_BUTTON_H,
316 	PRINT_OK_BUTTON_V,
317 	PRINT_OK_BUTTON_H + PRINT_BUTTON_WIDTH,
318 	PRINT_OK_BUTTON_V + PRINT_BUTTON_HEIGHT);
319 
320 const BRect cancel_rect(
321 	PRINT_CANCEL_BUTTON_H,
322 	PRINT_CANCEL_BUTTON_V,
323 	PRINT_CANCEL_BUTTON_H + PRINT_BUTTON_WIDTH,
324 	PRINT_CANCEL_BUTTON_V + PRINT_BUTTON_HEIGHT);
325 
326 const BRect preview_rect(
327 	PREVIEW_H,
328 	PREVIEW_V,
329 	PREVIEW_H + PRINT_BUTTON_WIDTH,
330 	PREVIEW_V + PRINT_BUTTON_HEIGHT);
331 
332 
333 
334 struct SurfaceCap : public BaseCap {
335 	color_space surface_type;
336 	SurfaceCap(const string &s, bool d, color_space cs) : BaseCap(s, d), surface_type(cs) {}
337 };
338 
339 struct NupCap : public BaseCap {
340 	int nup;
341 	NupCap(const string &s, bool d, int n) : BaseCap(s, d), nup(n) {}
342 };
343 
344 struct DitherCap : public BaseCap {
345 	Halftone::DitherType dither_type;
346 	DitherCap(const string &s, bool d, Halftone::DitherType type) : BaseCap(s, d), dither_type(type) {}
347 };
348 
349 static const SurfaceCap gRGB32("RGB32", false, B_RGB32);
350 static const SurfaceCap gCMAP8("CMAP8", true,  B_CMAP8);
351 static const SurfaceCap gGray8("GRAY8", false, B_GRAY8);
352 static const SurfaceCap gGray1("GRAY1", false, B_GRAY1);
353 
354 static const NupCap gNup1("1", true,  1);
355 static const NupCap gNup2("2",   false, 2);
356 static const NupCap gNup4("4",   false, 4);
357 static const NupCap gNup8("8",   false, 8);
358 static const NupCap gNup9("9",   false, 9);
359 static const NupCap gNup16("16", false, 16);
360 static const NupCap gNup25("25", false, 25);
361 static const NupCap gNup32("32", false, 32);
362 static const NupCap gNup36("36", false, 36);
363 
364 static const DitherCap gDitherType1("Crosshatch", false, Halftone::kType1);
365 static const DitherCap gDitherType2("Grid", false, Halftone::kType2);
366 static const DitherCap gDitherType3("Stipple", false, Halftone::kType3);
367 static const DitherCap gDitherFloydSteinberg("Floyd-Steinberg", false, Halftone::kTypeFloydSteinberg);
368 
369 const SurfaceCap *gSurfaces[] = {
370 	&gRGB32,
371 	&gCMAP8,
372 	&gGray8,
373 	&gGray1
374 };
375 
376 const NupCap *gNups[] = {
377 	&gNup1,
378 	&gNup2,
379 	&gNup4,
380 	&gNup8,
381 	&gNup9,
382 	&gNup16,
383 	&gNup25,
384 	&gNup32,
385 	&gNup36
386 };
387 
388 const DitherCap *gDitherTypes[] = {
389 	&gDitherType1,
390 	&gDitherType2,
391 	&gDitherType3,
392 	&gDitherFloydSteinberg
393 };
394 
395 enum {
396 	kMsgRangeAll = 'JSdl',
397 	kMsgRangeSelection,
398 	kMsgPreview,
399 	kMsgCancel,
400 	kMsgOK,
401 	kMsgQuality,
402 	kMsgCollateChanged,
403 	kMsgReverseChanged,
404 	kMsgDuplexChanged,
405 };
406 
407 JobSetupView::JobSetupView(BRect frame, JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap)
408 	: BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW), fJobData(job_data), fPrinterData(printer_data), fPrinterCap(printer_cap)
409 {
410 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
411 }
412 
413 BRadioButton*
414 JobSetupView::AddPageSelectionItem(BView* parent, BRect rect, const char* name, const char* label,
415 	JobData::PageSelection pageSelection)
416 {
417 	BRadioButton* button = new BRadioButton(rect, name, label, NULL);
418 	if (fJobData->getPageSelection() == pageSelection) {
419 		button->SetValue(B_CONTROL_ON);
420 	}
421 	parent->AddChild(button);
422 	return button;
423 }
424 
425 void
426 JobSetupView::AllowOnlyDigits(BTextView* textView, int maxDigits)
427 {
428 	int num;
429 	for (num = 0; num <= 255; num++) {
430 		textView->DisallowChar(num);
431 	}
432 	for (num = 0; num <= 9; num++) {
433 		textView->AllowChar('0' + num);
434 	}
435 	textView->SetMaxBytes(maxDigits);
436 }
437 
438 void
439 JobSetupView::AttachedToWindow()
440 {
441 	BBox *box;
442 	BMenuItem  *item = NULL;
443 	BMenuField *menufield;
444 	BButton *button;
445 	float width;
446 	bool marked;
447 	int  count;
448 
449 	/* quality */
450 
451 	box = new BBox(quality_rect);
452 	AddChild(box);
453 	box->SetLabel("Quality");
454 
455 /*
456 	// always B_RGB32
457 	fSurfaceType = new BPopUpMenu("");
458 	fSurfaceType->SetRadioMode(true);
459 
460 	count = sizeof(gSurfaces) / sizeof(gSurfaces[0]);
461 	const SurfaceCap **surface_cap = gSurfaces;
462 	uint32 support_flags;
463 	while (count--) {
464 		if (bitmaps_support_space((*surface_cap)->surface_type, &support_flags)) {
465 			item = new BMenuItem((*surface_cap)->label.c_str(), NULL);
466 			fSurfaceType->AddItem(item);
467 			if ((*surface_cap)->surface_type == fJobData->getSurfaceType()) {
468 				item->SetMarked(true);
469 				marked = true;
470 			}
471 		}
472 		surface_cap++;
473 	}
474 	menufield = new BMenuField(bpp_rect, "", "Surface Type", fSurfaceType);
475 	box->AddChild(menufield);
476 	width = StringWidth("Color") + 10;
477 	menufield->SetDivider(width);
478 */
479 
480 	/* color */
481 	marked = false;
482 	fColorType = new BPopUpMenu("");
483 	fColorType->SetRadioMode(true);
484 
485 	count = fPrinterCap->countCap(PrinterCap::kColor);
486 	const ColorCap **color_cap = (const ColorCap **)fPrinterCap->enumCap(PrinterCap::kColor);
487 	while (count--) {
488 		item = new BMenuItem((*color_cap)->label.c_str(), new BMessage(kMsgQuality));
489 		fColorType->AddItem(item);
490 		if ((*color_cap)->color == fJobData->getColor()) {
491 			item->SetMarked(true);
492 			marked = true;
493 		}
494 		color_cap++;
495 	}
496 	if (!marked && item)
497 		item->SetMarked(true);
498 	bpp_rect.right = bpp_rect.left + StringWidth("Color:") + fColorType->MaxContentWidth() + 10;
499 	menufield = new BMenuField(bpp_rect, "color", "Color:", fColorType);
500 
501 	box->AddChild(menufield);
502 	width = StringWidth("Color:") + 10;
503 	menufield->SetDivider(width);
504 	fColorType->SetTargetForItems(this);
505 
506 	/* dither type */
507 	marked = false;
508 	fDitherType = new BPopUpMenu("");
509 	fDitherType->SetRadioMode(true);
510 
511 	count = sizeof(gDitherTypes) / sizeof(gDitherTypes[0]);
512 	const DitherCap **dither_cap = gDitherTypes;
513 	while (count--) {
514 		item = new BMenuItem((*dither_cap)->label.c_str(), new BMessage(kMsgQuality));
515 		fDitherType->AddItem(item);
516 		if ((*dither_cap)->dither_type == fJobData->getDitherType()) {
517 			item->SetMarked(true);
518 			marked = true;
519 		}
520 		dither_cap++;
521 	}
522 	if (!marked && item)
523 		item->SetMarked(true);
524 	dither_rect.right = dither_rect.left + StringWidth("Dot Pattern:") + fDitherType->MaxContentWidth() + 20;
525 	menufield = new BMenuField(dither_rect, "dithering", "Dot Pattern:", fDitherType);
526 
527 	box->AddChild(menufield);
528 	width = StringWidth("Dot Pattern:") + 10;
529 	menufield->SetDivider(width);
530 	fDitherType->SetTargetForItems(this);
531 
532 	/* halftone preview view */
533 	BRect rect(halftone_rect);
534 	BBox* halftoneBorder = new BBox(rect.InsetByCopy(-1, -1));
535 	box->AddChild(halftoneBorder);
536 	halftoneBorder->SetBorder(B_PLAIN_BORDER);
537 
538 	fHalftone = new HalftoneView(rect.OffsetToCopy(1, 1), "halftone", B_FOLLOW_ALL, B_WILL_DRAW);
539 	halftoneBorder->AddChild(fHalftone);
540 	fHalftone->preview(fJobData->getGamma(), fJobData->getInkDensity(), fJobData->getDitherType(), fJobData->getColor() != JobData::kMonochrome);
541 
542 	/* gamma */
543 	fGamma = new JSDSlider(gamma_rect, "gamma", "Gamma", new BMessage(kMsgQuality), -300, 300, B_BLOCK_THUMB);
544 
545 	fGamma->SetLimitLabels("Lighter", "Darker");
546 	fGamma->SetValue((int32)(100 * log(fJobData->getGamma()) / log(2.0)));
547 	fGamma->SetHashMarks(B_HASH_MARKS_BOTH);
548 	fGamma->SetHashMarkCount(7);
549 	box->AddChild(fGamma);
550 	fGamma->SetModificationMessage(new BMessage(kMsgQuality));
551 	fGamma->SetTarget(this);
552 
553 	/* ink density */
554 	fInkDensity = new JSDSlider(ink_density_rect, "inkDensity", "Ink Usage", new BMessage(kMsgQuality), 0, 127, B_BLOCK_THUMB);
555 
556 	fInkDensity->SetLimitLabels("Min", "Max");
557 	fInkDensity->SetValue((int32)fJobData->getInkDensity());
558 	fInkDensity->SetHashMarks(B_HASH_MARKS_BOTH);
559 	fInkDensity->SetHashMarkCount(10);
560 	box->AddChild(fInkDensity);
561 	fInkDensity->SetModificationMessage(new BMessage(kMsgQuality));
562 	fInkDensity->SetTarget(this);
563 
564 	/* page range */
565 
566 	box = new BBox(pagerange_rect);
567 	AddChild(box);
568 	box->SetLabel("Page Range");
569 
570 	fAll = new BRadioButton(all_button_rect, "all", "All", new BMessage(kMsgRangeAll));
571 	box->AddChild(fAll);
572 
573 	BRadioButton *from = new BRadioButton(selection_rect, "selection", "", new BMessage(kMsgRangeSelection));
574 	box->AddChild(from);
575 
576 	fFromPage = new BTextControl(from_rect, "from", "From", "", NULL);
577 	box->AddChild(fFromPage);
578 	fFromPage->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT);
579 	fFromPage->SetDivider(StringWidth("From") + 7);
580 	AllowOnlyDigits(fFromPage->TextView(), 6);
581 
582 	fToPage = new BTextControl(to_rect, "to", "To", "", NULL);
583 	box->AddChild(fToPage);
584 	fToPage->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT);
585 	fToPage->SetDivider(StringWidth("To") + 7);
586 	AllowOnlyDigits(fToPage->TextView(), 6);
587 
588 	int first_page = fJobData->getFirstPage();
589 	int last_page  = fJobData->getLastPage();
590 
591 	if (first_page <= 1 && last_page <= 0) {
592 		fAll->SetValue(B_CONTROL_ON);
593 	} else {
594 		from->SetValue(B_CONTROL_ON);
595 		if (first_page < 1)
596 			first_page = 1;
597 		if (first_page > last_page)
598 			last_page = -1;
599 
600 		BString oss1;
601 		oss1 << first_page;
602 		fFromPage->SetText(oss1.String());
603 
604 		BString oss2;
605 		oss2 << last_page;
606 		fToPage->SetText(oss2.String());
607 	}
608 
609 	fAll->SetTarget(this);
610 	from->SetTarget(this);
611 
612 	/* paper source */
613 
614 	marked = false;
615 	fPaperFeed = new BPopUpMenu("");
616 	fPaperFeed->SetRadioMode(true);
617 	count = fPrinterCap->countCap(PrinterCap::kPaperSource);
618 	const PaperSourceCap **paper_source_cap = (const PaperSourceCap **)fPrinterCap->enumCap(PrinterCap::kPaperSource);
619 	while (count--) {
620 		item = new BMenuItem((*paper_source_cap)->label.c_str(), NULL);
621 		fPaperFeed->AddItem(item);
622 		if ((*paper_source_cap)->paper_source == fJobData->getPaperSource()) {
623 			item->SetMarked(true);
624 			marked = true;
625 		}
626 		paper_source_cap++;
627 	}
628 	if (!marked)
629 		item->SetMarked(true);
630 	menufield = new BMenuField(paperfeed_rect, "paperSource", "Paper Source:", fPaperFeed);
631 	AddChild(menufield);
632 	width = StringWidth("Number of Copies:") + 7;
633 	menufield->SetDivider(width);
634 
635 	/* Page Per Sheet */
636 
637 	marked = false;
638 	fNup = new BPopUpMenu("");
639 	fNup->SetRadioMode(true);
640 	count = sizeof(gNups) / sizeof(gNups[0]);
641 	const NupCap **nup_cap = gNups;
642 	while (count--) {
643 		item = new BMenuItem((*nup_cap)->label.c_str(), NULL);
644 		fNup->AddItem(item);
645 		if ((*nup_cap)->nup == fJobData->getNup()) {
646 			item->SetMarked(true);
647 			marked = true;
648 		}
649 		nup_cap++;
650 	}
651 	if (!marked)
652 		item->SetMarked(true);
653 	menufield = new BMenuField(nup_rect, "pagePerSheet", "Pages Per Sheet:", fNup);
654 	menufield->SetDivider(StringWidth("Number of Copies:") + 7);
655 	AddChild(menufield);
656 
657 	/* duplex */
658 
659 	if (fPrinterCap->isSupport(PrinterCap::kPrintStyle)) {
660 		fDuplex = new BCheckBox(duplex_rect, "duplex", "Duplex", new BMessage(kMsgDuplexChanged));
661 		AddChild(fDuplex);
662 		if (fJobData->getPrintStyle() != JobData::kSimplex) {
663 			fDuplex->SetValue(B_CONTROL_ON);
664 		}
665 		fDuplex->SetTarget(this);
666 	} else {
667 		fDuplex = NULL;
668 	}
669 
670 	/* copies */
671 
672 	fCopies = new BTextControl(copies_rect, "copies", "Number of Copies:", "", NULL);
673 	AddChild(fCopies);
674 	fCopies->SetDivider(width);
675 	AllowOnlyDigits(fCopies->TextView(), 3);
676 
677 	BString oss4;
678 	oss4 << fJobData->getCopies();
679 	fCopies->SetText(oss4.String());
680 
681 	/* collate */
682 
683 	fCollate = new BCheckBox(collate_rect, "collate", "Collate", new BMessage(kMsgCollateChanged));
684 	fCollate->ResizeToPreferred();
685 	AddChild(fCollate);
686 	if (fJobData->getCollate()) {
687 		fCollate->SetValue(B_CONTROL_ON);
688 	}
689 	fCollate->SetTarget(this);
690 
691 	/* reverse */
692 
693 	fReverse = new BCheckBox(reverse_rect, "reverse", "Reverse Order", new BMessage(kMsgReverseChanged));
694 	fReverse->ResizeToPreferred();
695 	AddChild(fReverse);
696 	if (fJobData->getReverse()) {
697 		fReverse->SetValue(B_CONTROL_ON);
698 	}
699 	fReverse->SetTarget(this);
700 
701 	/* pages view */
702 
703 	fPages = new PagesView(pages_rect, "pages", B_FOLLOW_ALL, B_WILL_DRAW);
704 	AddChild(fPages);
705 	fPages->setCollate(fJobData->getCollate());
706 	fPages->setReverse(fJobData->getReverse());
707 
708 	/* page selection */
709 	BBox* pageSelectionBox = new BBox(page_selection_rect);
710 	AddChild(pageSelectionBox);
711 	pageSelectionBox->SetLabel("Page Selection");
712 
713 	fAllPages = AddPageSelectionItem(pageSelectionBox, page_selection_all_pages_rect, "allPages", "All Pages", JobData::kAllPages);
714 	fOddNumberedPages = AddPageSelectionItem(pageSelectionBox, page_selection_odd_pages_rect, "oddPages", "Odd-Numbered Pages", JobData::kOddNumberedPages);
715 	fEvenNumberedPages = AddPageSelectionItem(pageSelectionBox, page_selection_even_pages_rect, "evenPages", "Even-Numbered Pages", JobData::kEvenNumberedPages);
716 
717 
718 
719 	/* preview */
720 
721 	button = new BButton(preview_rect, "preview", "Preview" B_UTF8_ELLIPSIS, new BMessage(kMsgPreview));
722 	AddChild(button);
723 
724 
725 	/* cancel */
726 
727 	button = new BButton(cancel_rect, "cancel", "Cancel", new BMessage(kMsgCancel));
728 	AddChild(button);
729 
730 	/* ok */
731 
732 	// TODO OK or "Print"?
733 	button = new BButton(ok_rect, "ok", "OK", new BMessage(kMsgOK));
734 	AddChild(button);
735 	button->MakeDefault(true);
736 
737 	UpdateButtonEnabledState();
738 }
739 
740 void
741 JobSetupView::UpdateButtonEnabledState()
742 {
743 	bool pageRangeEnabled = fAll->Value() != B_CONTROL_ON;
744 	fFromPage->SetEnabled(pageRangeEnabled);
745 	fToPage->SetEnabled(pageRangeEnabled);
746 
747 	bool pageSelectionEnabled = fDuplex == NULL ||
748 		fDuplex->Value() != B_CONTROL_ON;
749 	fAllPages->SetEnabled(pageSelectionEnabled);
750 	fOddNumberedPages->SetEnabled(pageSelectionEnabled);
751 	fEvenNumberedPages->SetEnabled(pageSelectionEnabled);
752 }
753 
754 void
755 JobSetupView::MessageReceived(BMessage *msg)
756 {
757 	switch (msg->what) {
758 	case kMsgRangeAll:
759 	case kMsgRangeSelection:
760 	case kMsgDuplexChanged:
761 		UpdateButtonEnabledState();
762 		break;
763 
764 	case kMsgQuality:
765 		fHalftone->preview(getGamma(), getInkDensity(), getDitherType(), getColor() != JobData::kMonochrome);
766 		break;
767 
768 	case kMsgCollateChanged:
769 		fPages->setCollate(fCollate->Value() == B_CONTROL_ON);
770 		break;
771 
772 	case kMsgReverseChanged:
773 		fPages->setReverse(fReverse->Value() == B_CONTROL_ON);
774 		break;
775 	}
776 }
777 
778 JobData::Color
779 JobSetupView::getColor()
780 {
781 	int count = fPrinterCap->countCap(PrinterCap::kColor);
782 	const ColorCap **color_cap = (const ColorCap**)fPrinterCap->enumCap(PrinterCap::kColor);
783 	const char *color_label = fColorType->FindMarked()->Label();
784 	while (count--) {
785 		if (!strcmp((*color_cap)->label.c_str(), color_label)) {
786 			return (*color_cap)->color;
787 		}
788 		color_cap++;
789 	}
790 	return JobData::kMonochrome;
791 }
792 
793 Halftone::DitherType
794 JobSetupView::getDitherType()
795 {
796 	int count = sizeof(gDitherTypes) / sizeof(gDitherTypes[0]);
797 	const DitherCap **dither_cap = gDitherTypes;
798 	const char *dithering_label = fDitherType->FindMarked()->Label();
799 	while (count --) {
800 		if (strcmp((*dither_cap)->label.c_str(), dithering_label) == 0) {
801 			return (*dither_cap)->dither_type;
802 		}
803 		dither_cap ++;
804 	}
805 	return Halftone::kTypeFloydSteinberg;
806 }
807 
808 float
809 JobSetupView::getGamma()
810 {
811 	const float value = (float)fGamma->Value();
812 	return pow(2.0, value / 100.0);
813 }
814 
815 float
816 JobSetupView::getInkDensity()
817 {
818 	const float value = (float)(127 - fInkDensity->Value());
819 	return value;
820 }
821 
822 bool
823 JobSetupView::UpdateJobData(bool showPreview)
824 {
825 	int count;
826 
827 /*
828 	count = sizeof(gSurfaces) / sizeof(gSurfaces[0]);
829 	const SurfaceCap **surface_cap = gSurfaces;
830 	const char *surface_label = fSurfaceType->FindMarked()->Label();
831 	while (count--) {
832 		if (!strcmp((*surface_cap)->label.c_str(), surface_label)) {
833 			fJobData->setSurfaceType((*surface_cap)->surface_type);
834 			break;
835 		}
836 		surface_cap++;
837 	}
838 */
839 	fJobData->setShowPreview(showPreview);
840 	fJobData->setColor(getColor());
841 	fJobData->setGamma(getGamma());
842 	fJobData->setInkDensity(getInkDensity());
843 	fJobData->setDitherType(getDitherType());
844 
845 	int first_page;
846 	int last_page;
847 
848 	if (B_CONTROL_ON == fAll->Value()) {
849 		first_page = 1;
850 		last_page  = -1;
851 	} else {
852 		first_page = atoi(fFromPage->Text());
853 		last_page  = atoi(fToPage->Text());
854 	}
855 
856 	fJobData->setFirstPage(first_page);
857 	fJobData->setLastPage(last_page);
858 
859 	count = fPrinterCap->countCap(PrinterCap::kPaperSource);
860 	const PaperSourceCap **paper_source_cap = (const PaperSourceCap **)fPrinterCap->enumCap(PrinterCap::kPaperSource);
861 	const char *paper_source_label = fPaperFeed->FindMarked()->Label();
862 	while (count--) {
863 		if (!strcmp((*paper_source_cap)->label.c_str(), paper_source_label)) {
864 			fJobData->setPaperSource((*paper_source_cap)->paper_source);
865 			break;
866 		}
867 		paper_source_cap++;
868 	}
869 
870 	count = sizeof(gNups) / sizeof(gNups[0]);
871 	const NupCap **nup_cap = gNups;
872 	const char *nup_label = fNup->FindMarked()->Label();
873 	while (count--) {
874 		if (!strcmp((*nup_cap)->label.c_str(), nup_label)) {
875 			fJobData->setNup((*nup_cap)->nup);
876 			break;
877 		}
878 		nup_cap++;
879 	}
880 
881 	if (fPrinterCap->isSupport(PrinterCap::kPrintStyle)) {
882 		fJobData->setPrintStyle((B_CONTROL_ON == fDuplex->Value()) ? JobData::kDuplex : JobData::kSimplex);
883 	}
884 
885 	fJobData->setCopies(atoi(fCopies->Text()));
886 
887 	fJobData->setCollate((B_CONTROL_ON == fCollate->Value()) ? true : false);
888 	fJobData->setReverse((B_CONTROL_ON == fReverse->Value()) ? true : false);
889 
890 	JobData::PageSelection pageSelection = JobData::kAllPages;
891 	if (fOddNumberedPages->Value() == B_CONTROL_ON)
892 		pageSelection = JobData::kOddNumberedPages;
893 	if (fEvenNumberedPages->Value() == B_CONTROL_ON)
894 		pageSelection = JobData::kEvenNumberedPages;
895 	fJobData->setPageSelection(pageSelection);
896 
897 	fJobData->save();
898 	return true;
899 }
900 
901 //====================================================================
902 
903 JobSetupDlg::JobSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap)
904 	: DialogWindow(BRect(100, 100, 100 + PRINT_WIDTH, 100 + PRINT_HEIGHT),
905 		"PrintJob Setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
906 		B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS)
907 {
908 	SetResult(B_ERROR);
909 	AddShortcut('W',B_COMMAND_KEY,new BMessage(B_QUIT_REQUESTED));
910 
911 	fJobSetup = new JobSetupView(Bounds(), job_data, printer_data, printer_cap);
912 	AddChild(fJobSetup);
913 }
914 
915 void
916 JobSetupDlg::MessageReceived(BMessage *msg)
917 {
918 	switch (msg->what) {
919 	case kMsgOK:
920 	case kMsgPreview:
921 		fJobSetup->UpdateJobData(msg->what == kMsgPreview);
922 		SetResult(B_NO_ERROR);
923 		PostMessage(B_QUIT_REQUESTED);
924 		break;
925 
926 	case kMsgCancel:
927 		PostMessage(B_QUIT_REQUESTED);
928 		break;
929 
930 	default:
931 		DialogWindow::MessageReceived(msg);
932 		break;
933 	}
934 }
935