xref: /haiku/src/libs/print/libprint/PageSetupDlg.cpp (revision b06a48ab8f30b45916a9c157b992827779182163)
1 /*
2  * PageSetupDlg.cpp
3  * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4  */
5 
6 #include <string>
7 #include <cstring>
8 #include <cstdlib>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <sys/stat.h>
12 
13 #include <Alert.h>
14 #include <Bitmap.h>
15 #include <Box.h>
16 #include <Button.h>
17 #include <Font.h>
18 #include <Looper.h>
19 #include <MessageFilter.h>
20 #include <MenuField.h>
21 #include <MenuItem.h>
22 #include <Message.h>
23 #include <Point.h>
24 #include <PopUpMenu.h>
25 #include <PrintJob.h>
26 #include <RadioButton.h>
27 #include <Rect.h>
28 #include <String.h>
29 #include <SupportDefs.h>
30 #include <TextControl.h>
31 #include <View.h>
32 
33 
34 #include "DbgMsg.h"
35 #include "JobData.h"
36 #include "MarginView.h"
37 #include "PageSetupDlg.h"
38 #include "PrinterData.h"
39 #include "PrinterCap.h"
40 #include "PrintUtils.h"
41 
42 
43 #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE))
44 using namespace std;
45 #else
46 #define std
47 #endif
48 
49 #define	MENU_HEIGHT			16
50 #define MENU_WIDTH          200
51 #define BUTTON_WIDTH		70
52 #define BUTTON_HEIGHT		20
53 #define TEXT_HEIGHT         16
54 
55 #define MARGIN_H            10
56 #define MARGIN_V            10
57 #define MARGIN_WIDTH        180
58 #define MARGIN_HEIGHT       140
59 
60 #define	PAGESETUP_WIDTH		MARGIN_H + MARGIN_WIDTH + 15 + MENU_WIDTH + 10
61 #define PAGESETUP_HEIGHT	MARGIN_V + MARGIN_HEIGHT + BUTTON_HEIGHT + 20
62 
63 #define PAPER_H				MARGIN_H + MARGIN_WIDTH + 15
64 #define PAPER_V				10
65 #define PAPER_WIDTH			MENU_WIDTH
66 #define PAPER_HEIGHT		MENU_HEIGHT
67 #define PAPER_TEXT			"Paper Size:"
68 
69 #define ORIENT_H			PAPER_H
70 #define ORIENT_V			PAPER_V + 24
71 #define ORIENT_WIDTH		MENU_WIDTH
72 #define ORIENT_HEIGHT		MENU_HEIGHT
73 #define ORIENTATION_TEXT    "Orientation:"
74 #define PORTRAIT_TEXT		"Portrait"
75 #define LANDSCAPE_TEXT		"Landscape"
76 
77 #define RES_H				PAPER_H
78 #define RES_V				ORIENT_V + 24
79 #define RES_WIDTH			MENU_WIDTH
80 #define RES_HEIGHT			MENU_HEIGHT
81 #define RES_TEXT			"Resolution:"
82 
83 #define SCALE_H				PAPER_H
84 #define SCALE_V				RES_V + 24
85 #define SCALE_WIDTH			100
86 #define SCALE_HEIGHT		TEXT_HEIGHT
87 #define SCALE_TEXT			"Scale [%]:"
88 
89 #define OK_H				(PAGESETUP_WIDTH  - BUTTON_WIDTH  - 11)
90 #define OK_V				(PAGESETUP_HEIGHT - BUTTON_HEIGHT - 11)
91 #define OK_TEXT				"OK"
92 
93 #define CANCEL_H			(OK_H - BUTTON_WIDTH - 12)
94 #define CANCEL_V			OK_V
95 #define CANCEL_TEXT			"Cancel"
96 
97 #define PRINT_LINE_V		(PAGESETUP_HEIGHT - BUTTON_HEIGHT - 23)
98 
99 const BRect MARGIN_RECT(
100 	MARGIN_H,
101 	MARGIN_V,
102 	MARGIN_H + MARGIN_WIDTH,
103 	MARGIN_V + MARGIN_HEIGHT);
104 
105 const BRect ORIENTATION_RECT(
106 	ORIENT_H,
107 	ORIENT_V,
108 	ORIENT_H + ORIENT_WIDTH,
109 	ORIENT_V + ORIENT_HEIGHT);
110 
111 const BRect PAPER_RECT(
112 	PAPER_H,
113 	PAPER_V,
114 	PAPER_H + PAPER_WIDTH,
115 	PAPER_V + PAPER_HEIGHT);
116 
117 const BRect RESOLUTION_RECT(
118 	RES_H,
119 	RES_V,
120 	RES_H + RES_WIDTH,
121 	RES_V + RES_HEIGHT);
122 
123 const BRect SCALE_RECT(
124 	SCALE_H,
125 	SCALE_V,
126 	SCALE_H + SCALE_WIDTH,
127 	SCALE_V + SCALE_HEIGHT);
128 
129 const BRect OK_RECT(
130 	OK_H,
131 	OK_V,
132 	OK_H + BUTTON_WIDTH,
133 	OK_V + BUTTON_HEIGHT);
134 
135 const BRect CANCEL_RECT(
136 	CANCEL_H,
137 	CANCEL_V,
138 	CANCEL_H + BUTTON_WIDTH,
139 	CANCEL_V + BUTTON_HEIGHT);
140 
141 enum MSGS {
142 	kMsgCancel = 1,
143 	kMsgOK,
144 	kMsgOrientationChanged,
145 	kMsgPaperChanged,
146 };
147 
148 PageSetupView::PageSetupView(BRect frame, JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap)
149 	: BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW), fJobData(job_data), fPrinterData(printer_data), fPrinterCap(printer_cap)
150 {
151 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
152 }
153 
154 PageSetupView::~PageSetupView()
155 {
156 }
157 
158 void
159 PageSetupView::AddOrientationItem(const char* name, JobData::Orientation orientation)
160 {
161 	BMessage *msg = new BMessage(kMsgOrientationChanged);
162 	msg->AddInt32("orientation", orientation);
163 	BMenuItem *item = new BMenuItem(name, msg);
164 
165 	fOrientation->AddItem(item);
166 	item->SetTarget(this);
167 	if (fJobData->getOrientation() == orientation) {
168 		item->SetMarked(true);
169 	} else if (fOrientation->CountItems() == 1) {
170 		item->SetMarked(true);
171 	}
172 }
173 
174 void
175 PageSetupView::AttachedToWindow()
176 {
177 	BMenuItem  *item = NULL;
178 	BMenuField *menuField;
179 	BButton    *button;
180 	bool       marked;
181 	int        count;
182 
183 	/* margin */
184 	MarginUnit units = fJobData->getMarginUnit();
185 	BRect paper = fJobData->getPaperRect();
186 	BRect margin = fJobData->getPrintableRect();
187 
188 	// re-calculate the margin from the printable rect in points
189 	margin.top -= paper.top;
190 	margin.left -= paper.left;
191 	margin.right = paper.right - margin.right;
192 	margin.bottom = paper.bottom - margin.bottom;
193 
194 	fMarginView = new MarginView(MARGIN_RECT,
195 		paper.IntegerWidth(),
196 		paper.IntegerHeight(),
197 			margin, units);
198 	AddChild(fMarginView);
199 
200 	/* paper selection */
201 
202 	marked = false;
203 	fPaper = new BPopUpMenu("");
204 	fPaper->SetRadioMode(true);
205 	count = fPrinterCap->countCap(PrinterCap::kPaper);
206 	PaperCap **paper_cap = (PaperCap **)fPrinterCap->enumCap(PrinterCap::kPaper);
207 	while (count--) {
208 		BMessage *msg = new BMessage(kMsgPaperChanged);
209 		msg->AddPointer("paperCap", *paper_cap);
210 		item = new BMenuItem((*paper_cap)->label.c_str(), msg);
211 		fPaper->AddItem(item);
212 		item->SetTarget(this);
213 		if ((*paper_cap)->paper == fJobData->getPaper()) {
214 			item->SetMarked(true);
215 			marked = true;
216 		}
217 		paper_cap++;
218 	}
219 	if (!marked)
220 		item->SetMarked(true);
221 	menuField = new BMenuField(PAPER_RECT, "", PAPER_TEXT, fPaper);
222 	AddChild(menuField);
223 	float width = StringWidth(PAPER_TEXT) + 7;
224 	menuField->SetDivider(width);
225 
226 	/* orientaion */
227 	fOrientation = new BPopUpMenu("orientation");
228 	fOrientation->SetRadioMode(true);
229 
230 	menuField = new BMenuField(ORIENTATION_RECT, "orientation", ORIENTATION_TEXT, fOrientation);
231 	menuField->SetDivider(width);
232 
233 	count = fPrinterCap->countCap(PrinterCap::kOrientation);
234 	if (count == 0) {
235 		AddOrientationItem(PORTRAIT_TEXT, JobData::kPortrait);
236 		AddOrientationItem(LANDSCAPE_TEXT, JobData::kLandscape);
237 	} else {
238 		OrientationCap **orientation_cap = (OrientationCap **)fPrinterCap->enumCap(PrinterCap::kOrientation);
239 		while (count--) {
240 			AddOrientationItem((*orientation_cap)->label.c_str(),
241 				(*orientation_cap)->orientation);
242 			orientation_cap++;
243 		}
244 	}
245 
246 	AddChild(menuField);
247 
248 	/* resolution */
249 
250 	marked = false;
251 	fResolution = new BPopUpMenu("");
252 	fResolution->SetRadioMode(true);
253 	count = fPrinterCap->countCap(PrinterCap::kResolution);
254 	ResolutionCap **resolution_cap = (ResolutionCap **)fPrinterCap->enumCap(PrinterCap::kResolution);
255 	while (count--) {
256 		item = new BMenuItem((*resolution_cap)->label.c_str(), NULL);
257 		fResolution->AddItem(item);
258 		item->SetTarget(this);
259 		if (((*resolution_cap)->xres == fJobData->getXres()) && ((*resolution_cap)->yres == fJobData->getYres())) {
260 			item->SetMarked(true);
261 			marked = true;
262 		}
263 		resolution_cap++;
264 	}
265 	if (!marked)
266 		item->SetMarked(true);
267 	menuField = new BMenuField(RESOLUTION_RECT, "", RES_TEXT, fResolution);
268 	AddChild(menuField);
269 	menuField->SetDivider(width);
270 
271 	/* scale */
272 	BString scale;
273 	scale << (int)fJobData->getScaling();
274 	fScaling = new BTextControl(SCALE_RECT, "scale", "Scale [%]:",
275 									scale.String(),
276 	                                NULL, B_FOLLOW_RIGHT);
277 	int num;
278 	for (num = 0; num <= 255; num++) {
279 		fScaling->TextView()->DisallowChar(num);
280 	}
281 	for (num = 0; num <= 9; num++) {
282 		fScaling->TextView()->AllowChar('0' + num);
283 	}
284 	fScaling->TextView()->SetMaxBytes(3);
285 	fScaling->SetDivider(width);
286 
287 	AddChild(fScaling);
288 
289 	/* cancel */
290 
291 	button = new BButton(CANCEL_RECT, "", CANCEL_TEXT, new BMessage(kMsgCancel));
292 	AddChild(button);
293 
294 	/* ok */
295 
296 	button = new BButton(OK_RECT, "", OK_TEXT, new BMessage(kMsgOK));
297 	AddChild(button);
298 	button->MakeDefault(true);
299 }
300 
301 inline void
302 swap(float *e1, float *e2)
303 {
304 	float e = *e1;
305 	*e1 = *e2;
306 	*e2 = e;
307 }
308 
309 JobData::Orientation
310 PageSetupView::GetOrientation()
311 {
312 	BMenuItem *item = fOrientation->FindMarked();
313 	int32 orientation;
314 	if (item != NULL &&
315 		item->Message()->FindInt32("orientation", &orientation) == B_OK) {
316 		return (JobData::Orientation)orientation;
317 	} else {
318 		return JobData::kPortrait;
319 	}
320 }
321 
322 PaperCap *
323 PageSetupView::GetPaperCap()
324 {
325 	BMenuItem *item = fPaper->FindMarked();
326 	void *pointer;
327 	if (item != NULL &&
328 		item->Message()->FindPointer("paperCap", &pointer) == B_OK) {
329 		return (PaperCap*)pointer;
330 	} else {
331 		return (PaperCap*)fPrinterCap->getDefaultCap(PrinterCap::kPaper);
332 	}
333 }
334 
335 bool
336 PageSetupView::UpdateJobData()
337 {
338 	fJobData->setOrientation(GetOrientation());
339 
340 	PaperCap *paperCap = GetPaperCap();
341 	BRect paper_rect = paperCap->paper_rect;
342 	BRect physical_rect = paperCap->physical_rect;
343 	fJobData->setPaper(paperCap->paper);
344 
345 	int count;
346 
347 	count = fPrinterCap->countCap(PrinterCap::kResolution);
348 	ResolutionCap **resolution_cap = (ResolutionCap **)fPrinterCap->enumCap(PrinterCap::kResolution);
349 	const char *resolution_label = fResolution->FindMarked()->Label();
350 	while (count--) {
351 		if (!strcmp((*resolution_cap)->label.c_str(), resolution_label)) {
352 			fJobData->setXres((*resolution_cap)->xres);
353 			fJobData->setYres((*resolution_cap)->yres);
354 			break;
355 		}
356 		resolution_cap++;
357 	}
358 
359 	// rotate paper and physical rectangle if landscape orientation
360 	if (JobData::kLandscape == fJobData->getOrientation()) {
361 		swap(&paper_rect.left, &paper_rect.top);
362 		swap(&paper_rect.right, &paper_rect.bottom);
363 		swap(&physical_rect.left, &physical_rect.top);
364 		swap(&physical_rect.right, &physical_rect.bottom);
365 	}
366 
367 	// adjust printable rect by margin
368 	fJobData->setMarginUnit(fMarginView->Unit());
369 	BRect margin = fMarginView->Margin();
370 	BRect printable_rect;
371 	printable_rect.left = paper_rect.left + margin.left;
372 	printable_rect.top = paper_rect.top + margin.top;
373 	printable_rect.right = paper_rect.right - margin.right;
374 	printable_rect.bottom = paper_rect.bottom - margin.bottom;
375 
376 	printable_rect.left = max_c(printable_rect.left, physical_rect.left);
377 	printable_rect.top = max_c(printable_rect.top, physical_rect.top);
378 	printable_rect.right = min_c(printable_rect.right, physical_rect.right);
379 	printable_rect.bottom = min_c(printable_rect.bottom, physical_rect.bottom);
380 
381 	float scaling = atoi(fScaling->Text());
382 	if (scaling <= 0.0) { // sanity check
383 		scaling = 100.0;
384 	}
385 	if (scaling > 1000.0) {
386 		scaling = 1000.0;
387 	}
388 
389 	float scalingR = 100.0 / scaling;
390 
391 	fJobData->setScaling(scaling);
392 	fJobData->setPaperRect(paper_rect);
393 	fJobData->setScaledPaperRect(ScaleRect(paper_rect, scalingR));
394 	fJobData->setPrintableRect(printable_rect);
395 	fJobData->setScaledPrintableRect(ScaleRect(printable_rect, scalingR));
396 	fJobData->setPhysicalRect(physical_rect);
397 	fJobData->setScaledPhysicalRect(ScaleRect(physical_rect, scalingR));
398 
399 	fJobData->save();
400 	return true;
401 }
402 
403 void
404 PageSetupView::MessageReceived(BMessage *msg)
405 {
406 	switch (msg->what) {
407 		case kMsgPaperChanged:
408 		case kMsgOrientationChanged:
409 			{
410 				JobData::Orientation orientation = GetOrientation();
411 				PaperCap *paperCap = GetPaperCap();
412 				float width = paperCap->paper_rect.Width();
413 				float height = paperCap->paper_rect.Height();
414 				if (orientation != JobData::kPortrait) {
415 					swap(&width, &height);
416 				}
417 				fMarginView->SetPageSize(width, height);
418 				fMarginView->UpdateView(MARGIN_CHANGED);
419 
420 			}
421 			break;
422 	}
423 }
424 
425 //====================================================================
426 
427 PageSetupDlg::PageSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap)
428 	: DialogWindow(BRect(100, 100, 100 + PAGESETUP_WIDTH, 100 + PAGESETUP_HEIGHT),
429 		"Page Setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
430 		B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE)
431 {
432 	AddShortcut('W',B_COMMAND_KEY,new BMessage(B_QUIT_REQUESTED));
433 
434 	PageSetupView *view = new PageSetupView(Bounds(), job_data, printer_data, printer_cap);
435 	AddChild(view);
436 
437 	SetResult(B_ERROR);
438 }
439 
440 void
441 PageSetupDlg::MessageReceived(BMessage *msg)
442 {
443 	switch (msg->what) {
444 	case kMsgOK:
445 		Lock();
446 		((PageSetupView *)ChildAt(0))->UpdateJobData();
447 		Unlock();
448 		SetResult(B_NO_ERROR);
449 		PostMessage(B_QUIT_REQUESTED);
450 		break;
451 
452 	case kMsgCancel:
453 		PostMessage(B_QUIT_REQUESTED);
454 		break;
455 
456 	default:
457 		DialogWindow::MessageReceived(msg);
458 	}
459 }
460 
461