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