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