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
60static 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
83static 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
95PageSetupWindow::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
244void
245PageSetupWindow::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
289void
290PageSetupWindow::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