xref: /haiku/src/add-ons/print/drivers/preview/PageSetupWindow.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Copyright 2003-2009, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Philippe Houdoin
7  *		Simon Gauvin
8  *		Michael Pfeiffer
9  *		Dr. Hartmut Reh
10  *		julun <host.haiku@gmx.de>
11  */
12 
13 #include "MarginView.h"
14 #include "PrinterDriver.h"
15 #include "PageSetupWindow.h"
16 #include "PrintUtils.h"
17 
18 #include <stdlib.h>
19 
20 
21 #include <Box.h>
22 #include <Button.h>
23 #include <MenuField.h>
24 #include <Message.h>
25 #include <PopUpMenu.h>
26 #include <Screen.h>
27 #include <TextControl.h>
28 
29 
30 /* copied from PDFlib.h: */
31 #define a0_width	 (float) 2380.0
32 #define a0_height	 (float) 3368.0
33 #define a1_width	 (float) 1684.0
34 #define a1_height	 (float) 2380.0
35 #define a2_width	 (float) 1190.0
36 #define a2_height	 (float) 1684.0
37 #define a3_width	 (float) 842.0
38 #define a3_height	 (float) 1190.0
39 #define a4_width	 (float) 595.0
40 #define a4_height	 (float) 842.0
41 #define a5_width	 (float) 421.0
42 #define a5_height	 (float) 595.0
43 #define a6_width	 (float) 297.0
44 #define a6_height	 (float) 421.0
45 #define b5_width	 (float) 501.0
46 #define b5_height	 (float) 709.0
47 #define letter_width	 (float) 612.0
48 #define letter_height	 (float) 792.0
49 #define legal_width 	 (float) 612.0
50 #define legal_height 	 (float) 1008.0
51 #define ledger_width	 (float) 1224.0
52 #define ledger_height	 (float) 792.0
53 #define p11x17_width	 (float) 792.0
54 #define p11x17_height	 (float) 1224.0
55 
56 
57 static struct
58 {
59 	char  *label;
60 	float width;
61 	float height;
62 } pageFormat[] =
63 {
64 	{"Letter", letter_width, letter_height },
65 	{"Legal",  legal_width,  legal_height  },
66 	{"Ledger", ledger_width, ledger_height  },
67 	{"p11x17", p11x17_width, p11x17_height  },
68 	{"A0",     a0_width,     a0_height     },
69 	{"A1",     a1_width,     a1_height     },
70 	{"A2",     a2_width,     a2_height     },
71 	{"A3",     a3_width,     a3_height     },
72 	{"A4",     a4_width,     a4_height     },
73 	{"A5",     a5_width,     a5_height     },
74 	{"A6",     a6_width,     a6_height     },
75 	{"B5",     b5_width,     b5_height     },
76 	{NULL,     0.0,          0.0           }
77 };
78 
79 
80 static struct
81 {
82 	char  *label;
83 	int32 orientation;
84 } orientation[] =
85 {
86 	{ "Portrait", PrinterDriver::PORTRAIT_ORIENTATION },
87 	{ "Landscape", PrinterDriver::LANDSCAPE_ORIENTATION },
88 	{ NULL, 0 }
89 };
90 
91 
92 PageSetupWindow::PageSetupWindow(BMessage *msg, const char *printerName)
93 	:	BlockingWindow(BRect(0,0,400,220), "Page setup", B_TITLED_WINDOW_LOOK,
94  			B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_MINIMIZABLE |
95  			B_NOT_ZOOMABLE),
96 	fSetupMsg(msg),
97 	fPrinterDirName(printerName)
98 {
99 	if (printerName)
100 		SetTitle(BString(printerName).Append(" Page setup").String());
101 
102 	// load orientation
103 	if (fSetupMsg->FindInt32("orientation", &fCurrentOrientation) != B_OK)
104 		fCurrentOrientation = PrinterDriver::PORTRAIT_ORIENTATION;
105 
106 	// load page rect
107 	BRect page;
108 	float width = letter_width;
109 	float height = letter_height;
110 	if (fSetupMsg->FindRect("preview:paper_rect", &page) == B_OK) {
111 		width = page.Width();
112 		height = page.Height();
113 	} else {
114 		page.Set(0, 0, width, height);
115 	}
116 
117 	BString label;
118 	if (fSetupMsg->FindString("preview:paper_size", &label) != B_OK)
119 		label = "Letter";
120 
121 	// Load units
122 	int32 units;
123 	if (fSetupMsg->FindInt32("units", &units) != B_OK)
124 		units = kUnitInch;
125 
126 	// re-calculate the margin from the printable rect in points
127 	BRect margin = page;
128 	if (fSetupMsg->FindRect("preview:printable_rect", &margin) == B_OK) {
129 		margin.top -= page.top;
130 		margin.left -= page.left;
131 		margin.right = page.right - margin.right;
132 		margin.bottom = page.bottom - margin.bottom;
133 	} else {
134 		margin.Set(28.34, 28.34, 28.34, 28.34);		// 28.34 dots = 1cm
135 	}
136 
137 	BRect bounds(Bounds());
138 	BBox *panel = new BBox(bounds, "background", B_FOLLOW_ALL,
139 		B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, B_PLAIN_BORDER);
140 	AddChild(panel);
141 
142 	bounds.InsetBy(10.0, 10.0);
143 	bounds.right = 230.0;
144 	bounds.bottom = 160.0;
145 	fMarginView = new MarginView(bounds, int32(width), int32(height), margin,
146 		MarginUnit(units));
147 	panel->AddChild(fMarginView);
148 	fMarginView->SetResizingMode(B_FOLLOW_NONE);
149 
150 	BPopUpMenu* m = new BPopUpMenu("Page size");
151 	m->SetRadioMode(true);
152 
153 	bounds.OffsetBy(bounds.Width() + 10.0, 5.0);
154 	float divider = be_plain_font->StringWidth("Orientation: ");
155 	fPageSizeMenu = new BMenuField(bounds, "page_size", "Page size:", m);
156 	panel->AddChild(fPageSizeMenu);
157 	fPageSizeMenu->ResizeToPreferred();
158 	fPageSizeMenu->SetDivider(divider);
159 	fPageSizeMenu->Menu()->SetLabelFromMarked(true);
160 
161 	for (int32 i = 0; pageFormat[i].label != NULL; i++) {
162 		BMessage* message = new BMessage(PAGE_SIZE_CHANGED);
163 		message->AddFloat("width", pageFormat[i].width);
164 		message->AddFloat("height", pageFormat[i].height);
165 		BMenuItem* item = new BMenuItem(pageFormat[i].label, message);
166 		m->AddItem(item);
167 
168 		if (label.Compare(pageFormat[i].label) == 0)
169 			item->SetMarked(true);
170 	}
171 
172 	m = new BPopUpMenu("Orientation");
173 	m->SetRadioMode(true);
174 
175 	bounds.OffsetBy(0.0, fPageSizeMenu->Bounds().Height() + 10.0);
176 	fOrientationMenu = new BMenuField(bounds, "orientation", "Orientation:", m);
177 	panel->AddChild(fOrientationMenu);
178 	fOrientationMenu->ResizeToPreferred();
179 	fOrientationMenu->SetDivider(divider);
180 	fOrientationMenu->Menu()->SetLabelFromMarked(true);
181 
182 	for (int32 i = 0; orientation[i].label != NULL; i++) {
183 	 	BMessage* message = new BMessage(ORIENTATION_CHANGED);
184 		message->AddInt32("orientation", orientation[i].orientation);
185 		BMenuItem* item = new BMenuItem(orientation[i].label, message);
186 		m->AddItem(item);
187 
188 		if (fCurrentOrientation == orientation[i].orientation)
189 			item->SetMarked(true);
190 	}
191 
192 	float scale0;
193 	BString scale;
194 	if (fSetupMsg->FindFloat("scale", &scale0) == B_OK)
195 		scale << (int)scale0;
196 	else
197 		scale = "100";
198 
199 	bounds.OffsetBy(0.0, fOrientationMenu->Bounds().Height() + 10.0);
200 	bounds.right -= 30.0;
201 	fScaleControl = new BTextControl(bounds, "scale", "Scale [%]:",
202 		scale.String(), NULL);
203 	panel->AddChild(fScaleControl);
204 	fScaleControl->ResizeToPreferred();
205 	fScaleControl->SetDivider(divider);
206 
207 	for (uint32 i = 0; i < '0'; i++)
208 		fScaleControl->TextView()->DisallowChar(i);
209 
210 	for (uint32 i = '9' + 1; i < 255; i++)
211 		fScaleControl->TextView()->DisallowChar(i);
212 
213 	fScaleControl->TextView()->SetMaxBytes(3);
214 
215 	bounds = Bounds();
216 	bounds.InsetBy(5.0, 0.0);
217 	bounds.top =
218 		MAX(fScaleControl->Frame().bottom, fMarginView->Frame().bottom) + 10.0;
219 	BBox *line = new BBox(BRect(bounds.left, bounds.top, bounds.right,
220 		bounds.top + 1.0), NULL, B_FOLLOW_LEFT_RIGHT);
221 	panel->AddChild(line);
222 
223 	bounds.InsetBy(5.0, 0.0);
224 	bounds.OffsetBy(0.0, 11.0);
225 	BButton *cancel = new BButton(bounds, NULL, "Cancel", new BMessage(CANCEL_MSG));
226 	panel->AddChild(cancel);
227 	cancel->ResizeToPreferred();
228 
229 	BButton *ok = new BButton(bounds, NULL, "OK", new BMessage(OK_MSG));
230 	panel->AddChild(ok, cancel);
231 	ok->ResizeToPreferred();
232 
233 	bounds.right = fScaleControl->Frame().right;
234 	ok->MoveTo(bounds.right - ok->Bounds().Width(), ok->Frame().top);
235 
236 	bounds = ok->Frame();
237 	cancel->MoveTo(bounds.left - cancel->Bounds().Width() - 10.0, bounds.top);
238 
239 	ok->MakeDefault(true);
240 	ResizeTo(bounds.right + 10.0, bounds.bottom + 10.0);
241 
242 	BRect winFrame(Frame());
243 	BRect screenFrame(BScreen().Frame());
244 	MoveTo((screenFrame.right - winFrame.right) / 2,
245 		(screenFrame.bottom - winFrame.bottom) / 2);
246 }
247 
248 
249 void
250 PageSetupWindow::UpdateSetupMessage()
251 {
252 	SetInt32(fSetupMsg, "xres", 300);
253 	SetInt32(fSetupMsg, "yres", 300);
254 	SetInt32(fSetupMsg, "orientation", fCurrentOrientation);
255 
256 	// Save scaling factor
257 	float scale = atoi(fScaleControl->Text());
258 	if (scale <= 0.0) scale = 100.0;
259 	if (scale > 1000.0) scale = 1000.0;
260 	SetFloat(fSetupMsg, "scale", scale);
261 
262 	float scaleR = 100.0 / scale;
263 	BMenuItem *item = fPageSizeMenu->Menu()->FindMarked();
264 	if (item) {
265 		float w, h;
266 		BMessage *msg = item->Message();
267 		msg->FindFloat("width", &w);
268 		msg->FindFloat("height", &h);
269 		BRect r(0, 0, w, h);
270 		if (fCurrentOrientation == PrinterDriver::LANDSCAPE_ORIENTATION)
271 			r.Set(0, 0, h, w);
272 
273 		SetRect(fSetupMsg, "preview:paper_rect", r);
274 		SetRect(fSetupMsg, "paper_rect", ScaleRect(r, scaleR));
275 		SetString(fSetupMsg, "preview:paper_size", item->Label());
276 
277 		// Save the printable_rect
278 		BRect margin = fMarginView->Margin();
279 		if (fCurrentOrientation == PrinterDriver::PORTRAIT_ORIENTATION) {
280 			margin.right = w - margin.right;
281 			margin.bottom = h - margin.bottom;
282 		} else {
283 			margin.right = h - margin.right;
284 			margin.bottom = w - margin.bottom;
285 		}
286 		SetRect(fSetupMsg, "preview:printable_rect", margin);
287 		SetRect(fSetupMsg, "printable_rect", ScaleRect(margin, scaleR));
288 
289 		SetInt32(fSetupMsg, "units", fMarginView->Unit());
290 	}
291 }
292 
293 
294 void
295 PageSetupWindow::MessageReceived(BMessage *msg)
296 {
297 	switch (msg->what) {
298 		case OK_MSG: {
299 			UpdateSetupMessage();
300 			Quit(B_OK);
301 		}	break;
302 
303 		case CANCEL_MSG: {
304 			Quit(B_ERROR);
305 		}	break;
306 
307 		case PAGE_SIZE_CHANGED:	{
308 			float w, h;
309 			msg->FindFloat("width", &w);
310 			msg->FindFloat("height", &h);
311 			if (fCurrentOrientation == PrinterDriver::PORTRAIT_ORIENTATION) {
312 				fMarginView->SetPageSize(w, h);
313 			} else {
314 				fMarginView->SetPageSize(h, w);
315 			}
316 			fMarginView->UpdateView(MARGIN_CHANGED);
317 		}	break;
318 
319 		case ORIENTATION_CHANGED: {
320 			int32 orientation;
321 			msg->FindInt32("orientation", &orientation);
322 
323 			if (fCurrentOrientation != orientation) {
324 				fCurrentOrientation = orientation;
325 				BPoint p = fMarginView->PageSize();
326 				fMarginView->SetPageSize(p.y, p.x);
327 				fMarginView->UpdateView(MARGIN_CHANGED);
328 			}
329 		}	break;
330 
331 		default:
332 			BlockingWindow::MessageReceived(msg);
333 			break;
334 	}
335 }
336