xref: /haiku/src/libs/print/libprint/PageSetupDlg.cpp (revision 08d759feae5967ad75d0f0d4ee33c21c72ae6db8)
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 <GridView.h>
19 #include <GroupLayout.h>
20 #include <GroupLayoutBuilder.h>
21 #include <Looper.h>
22 #include <MessageFilter.h>
23 #include <MenuField.h>
24 #include <MenuItem.h>
25 #include <Message.h>
26 #include <Point.h>
27 #include <PopUpMenu.h>
28 #include <PrintJob.h>
29 #include <RadioButton.h>
30 #include <Rect.h>
31 #include <String.h>
32 #include <SupportDefs.h>
33 #include <TextControl.h>
34 #include <View.h>
35 
36 
37 #include "DbgMsg.h"
38 #include "JobData.h"
39 #include "MarginView.h"
40 #include "PageSetupDlg.h"
41 #include "PrinterData.h"
42 #include "PrinterCap.h"
43 #include "PrintUtils.h"
44 
45 
46 using namespace std;
47 
48 
49 enum MSGS {
50 	kMsgCancel = 1,
51 	kMsgOK,
52 	kMsgOrientationChanged,
53 	kMsgPaperChanged,
54 };
55 
56 PageSetupView::PageSetupView(JobData *job_data, PrinterData *printer_data,
57 	const PrinterCap *printer_cap)
58 	: BView("pageSetupView", B_WILL_DRAW)
59 	, fJobData(job_data)
60 	, fPrinterData(printer_data)
61 	, fPrinterCap(printer_cap)
62 {
63 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
64 }
65 
66 PageSetupView::~PageSetupView()
67 {
68 }
69 
70 void
71 PageSetupView::AddOrientationItem(const char* name, JobData::Orientation orientation)
72 {
73 	BMessage *msg = new BMessage(kMsgOrientationChanged);
74 	msg->AddInt32("orientation", orientation);
75 	BMenuItem *item = new BMenuItem(name, msg);
76 
77 	fOrientation->AddItem(item);
78 	item->SetTarget(this);
79 	if (fJobData->getOrientation() == orientation) {
80 		item->SetMarked(true);
81 	} else if (fOrientation->CountItems() == 1) {
82 		item->SetMarked(true);
83 	}
84 }
85 
86 void
87 PageSetupView::AttachedToWindow()
88 {
89 	BMenuItem  *item = NULL;
90 	bool       marked;
91 	int        count;
92 
93 	// margin
94 	MarginUnit units = fJobData->getMarginUnit();
95 	BRect paper = fJobData->getPaperRect();
96 	BRect margin = fJobData->getPrintableRect();
97 
98 	// re-calculate the margin from the printable rect in points
99 	margin.top -= paper.top;
100 	margin.left -= paper.left;
101 	margin.right = paper.right - margin.right;
102 	margin.bottom = paper.bottom - margin.bottom;
103 
104 	fMarginView = new MarginView(
105 		paper.IntegerWidth(),
106 		paper.IntegerHeight(),
107 			margin, units);
108 
109 	// paper selection
110 	marked = false;
111 	fPaper = new BPopUpMenu("paperSize");
112 	fPaper->SetRadioMode(true);
113 	count = fPrinterCap->countCap(PrinterCap::kPaper);
114 	PaperCap **paper_cap = (PaperCap **)fPrinterCap->enumCap(PrinterCap::kPaper);
115 	while (count--) {
116 		BMessage *msg = new BMessage(kMsgPaperChanged);
117 		msg->AddPointer("paperCap", *paper_cap);
118 		item = new BMenuItem((*paper_cap)->fLabel.c_str(), msg);
119 		fPaper->AddItem(item);
120 		item->SetTarget(this);
121 		if ((*paper_cap)->fPaper == fJobData->getPaper()) {
122 			item->SetMarked(true);
123 			marked = true;
124 		}
125 		paper_cap++;
126 	}
127 	if (!marked)
128 		item->SetMarked(true);
129 	BMenuField* paperSize = new BMenuField("paperSize", "Paper Size:", fPaper);
130 
131 	// orientation
132 	fOrientation = new BPopUpMenu("orientation");
133 	fOrientation->SetRadioMode(true);
134 
135 	BMenuField* orientation = new BMenuField("orientation", "Orientation:", fOrientation);
136 
137 	count = fPrinterCap->countCap(PrinterCap::kOrientation);
138 	if (count == 0) {
139 		AddOrientationItem("Portrait", JobData::kPortrait);
140 		AddOrientationItem("Landscape", JobData::kLandscape);
141 	} else {
142 		OrientationCap **orientation_cap = (OrientationCap **)fPrinterCap->enumCap(PrinterCap::kOrientation);
143 		while (count--) {
144 			AddOrientationItem((*orientation_cap)->fLabel.c_str(),
145 				(*orientation_cap)->fOrientation);
146 			orientation_cap++;
147 		}
148 	}
149 
150 	// resolution
151 	marked = false;
152 	fResolution = new BPopUpMenu("resolution");
153 	fResolution->SetRadioMode(true);
154 	count = fPrinterCap->countCap(PrinterCap::kResolution);
155 	ResolutionCap **resolution_cap = (ResolutionCap **)fPrinterCap->enumCap(PrinterCap::kResolution);
156 	while (count--) {
157 		item = new BMenuItem((*resolution_cap)->fLabel.c_str(), NULL);
158 		fResolution->AddItem(item);
159 		item->SetTarget(this);
160 		if (((*resolution_cap)->fXResolution == fJobData->getXres()) &&
161 			((*resolution_cap)->fYResolution == fJobData->getYres())) {
162 			item->SetMarked(true);
163 			marked = true;
164 		}
165 		resolution_cap++;
166 	}
167 	if (!marked)
168 		item->SetMarked(true);
169 	BMenuField* resolution = new BMenuField("resolution", "Resolution:", fResolution);
170 
171 	// scale
172 	BString scale;
173 	scale << (int)fJobData->getScaling();
174 	fScaling = new BTextControl("scale", "Scale [%]:",
175 									scale.String(),
176 	                                NULL);
177 	int num;
178 	for (num = 0; num <= 255; num++) {
179 		fScaling->TextView()->DisallowChar(num);
180 	}
181 	for (num = 0; num <= 9; num++) {
182 		fScaling->TextView()->AllowChar('0' + num);
183 	}
184 	fScaling->TextView()->SetMaxBytes(3);
185 
186 	// cancel and ok
187 	BButton* cancel = new BButton("cancel", "Cancel", new BMessage(kMsgCancel));
188 	BButton* ok = new BButton("ok", "OK", new BMessage(kMsgOK));
189 
190 	ok->MakeDefault(true);
191 
192 	BGridView* settings = new BGridView();
193 	BGridLayout* settingsLayout = settings->GridLayout();
194 	settingsLayout->AddItem(paperSize->CreateLabelLayoutItem(), 0, 0);
195 	settingsLayout->AddItem(paperSize->CreateMenuBarLayoutItem(), 1, 0);
196 	settingsLayout->AddItem(orientation->CreateLabelLayoutItem(), 0, 1);
197 	settingsLayout->AddItem(orientation->CreateMenuBarLayoutItem(), 1, 1);
198 	settingsLayout->AddItem(resolution->CreateLabelLayoutItem(), 0, 2);
199 	settingsLayout->AddItem(resolution->CreateMenuBarLayoutItem(), 1, 2);
200 	settingsLayout->AddItem(fScaling->CreateLabelLayoutItem(), 0, 3);
201 	settingsLayout->AddItem(fScaling->CreateTextViewLayoutItem(), 1, 3);
202 	settingsLayout->SetSpacing(0, 0);
203 
204 	SetLayout(new BGroupLayout(B_VERTICAL));
205 	AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
206 		.AddGroup(B_HORIZONTAL, 5, 1.0f)
207 			.AddGroup(B_VERTICAL, 0, 1.0f)
208 				.Add(fMarginView)
209 				.AddGlue()
210 			.End()
211 			.AddGroup(B_VERTICAL, 0, 1.0f)
212 				.Add(settings)
213 				.AddGlue()
214 			.End()
215 		.End()
216 		.AddGroup(B_HORIZONTAL, 10, 1.0f)
217 			.AddGlue()
218 			.Add(cancel)
219 			.Add(ok)
220 		.End()
221 		.SetInsets(10, 10, 10, 10)
222 	);
223 }
224 
225 inline void
226 swap(float *e1, float *e2)
227 {
228 	float e = *e1;
229 	*e1 = *e2;
230 	*e2 = e;
231 }
232 
233 JobData::Orientation
234 PageSetupView::GetOrientation()
235 {
236 	BMenuItem *item = fOrientation->FindMarked();
237 	int32 orientation;
238 	if (item != NULL &&
239 		item->Message()->FindInt32("orientation", &orientation) == B_OK) {
240 		return (JobData::Orientation)orientation;
241 	} else {
242 		return JobData::kPortrait;
243 	}
244 }
245 
246 PaperCap *
247 PageSetupView::GetPaperCap()
248 {
249 	BMenuItem *item = fPaper->FindMarked();
250 	void *pointer;
251 	if (item != NULL &&
252 		item->Message()->FindPointer("paperCap", &pointer) == B_OK) {
253 		return (PaperCap*)pointer;
254 	} else {
255 		return (PaperCap*)fPrinterCap->getDefaultCap(PrinterCap::kPaper);
256 	}
257 }
258 
259 bool
260 PageSetupView::UpdateJobData()
261 {
262 	fJobData->setOrientation(GetOrientation());
263 
264 	PaperCap *paperCap = GetPaperCap();
265 	BRect paper_rect = paperCap->fPaperRect;
266 	BRect physical_rect = paperCap->fPhysicalRect;
267 	fJobData->setPaper(paperCap->fPaper);
268 
269 	int count;
270 
271 	count = fPrinterCap->countCap(PrinterCap::kResolution);
272 	ResolutionCap **resolution_cap = (ResolutionCap **)fPrinterCap->enumCap(PrinterCap::kResolution);
273 	const char *resolution_label = fResolution->FindMarked()->Label();
274 	while (count--) {
275 		if (!strcmp((*resolution_cap)->fLabel.c_str(), resolution_label)) {
276 			fJobData->setXres((*resolution_cap)->fXResolution);
277 			fJobData->setYres((*resolution_cap)->fYResolution);
278 			break;
279 		}
280 		resolution_cap++;
281 	}
282 
283 	// rotate paper and physical rectangle if landscape orientation
284 	if (JobData::kLandscape == fJobData->getOrientation()) {
285 		swap(&paper_rect.left, &paper_rect.top);
286 		swap(&paper_rect.right, &paper_rect.bottom);
287 		swap(&physical_rect.left, &physical_rect.top);
288 		swap(&physical_rect.right, &physical_rect.bottom);
289 	}
290 
291 	// adjust printable rect by margin
292 	fJobData->setMarginUnit(fMarginView->Unit());
293 	BRect margin = fMarginView->Margin();
294 	BRect printable_rect;
295 	printable_rect.left = paper_rect.left + margin.left;
296 	printable_rect.top = paper_rect.top + margin.top;
297 	printable_rect.right = paper_rect.right - margin.right;
298 	printable_rect.bottom = paper_rect.bottom - margin.bottom;
299 
300 	printable_rect.left = max_c(printable_rect.left, physical_rect.left);
301 	printable_rect.top = max_c(printable_rect.top, physical_rect.top);
302 	printable_rect.right = min_c(printable_rect.right, physical_rect.right);
303 	printable_rect.bottom = min_c(printable_rect.bottom, physical_rect.bottom);
304 
305 	float scaling = atoi(fScaling->Text());
306 	if (scaling <= 0.0) { // sanity check
307 		scaling = 100.0;
308 	}
309 	if (scaling > 1000.0) {
310 		scaling = 1000.0;
311 	}
312 
313 	float scalingR = 100.0 / scaling;
314 
315 	fJobData->setScaling(scaling);
316 	fJobData->setPaperRect(paper_rect);
317 	fJobData->setScaledPaperRect(ScaleRect(paper_rect, scalingR));
318 	fJobData->setPrintableRect(printable_rect);
319 	fJobData->setScaledPrintableRect(ScaleRect(printable_rect, scalingR));
320 	fJobData->setPhysicalRect(physical_rect);
321 	fJobData->setScaledPhysicalRect(ScaleRect(physical_rect, scalingR));
322 
323 	fJobData->save();
324 	return true;
325 }
326 
327 void
328 PageSetupView::MessageReceived(BMessage *msg)
329 {
330 	switch (msg->what) {
331 		case kMsgPaperChanged:
332 		case kMsgOrientationChanged:
333 			{
334 				JobData::Orientation orientation = GetOrientation();
335 				PaperCap *paperCap = GetPaperCap();
336 				float width = paperCap->fPaperRect.Width();
337 				float height = paperCap->fPaperRect.Height();
338 				if (orientation != JobData::kPortrait) {
339 					swap(&width, &height);
340 				}
341 				fMarginView->SetPageSize(width, height);
342 				fMarginView->UpdateView(MARGIN_CHANGED);
343 
344 			}
345 			break;
346 	}
347 }
348 
349 //====================================================================
350 
351 // TODO center window on screen
352 PageSetupDlg::PageSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap)
353 	: DialogWindow(BRect(100, 100, 160, 160),
354 		"Page Setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
355 		B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE
356 			| B_AUTO_UPDATE_SIZE_LIMITS)
357 {
358 	AddShortcut('W',B_COMMAND_KEY,new BMessage(B_QUIT_REQUESTED));
359 
360 	fPageSetupView = new PageSetupView(job_data, printer_data,
361 		printer_cap);
362 
363 	SetLayout(new BGroupLayout(B_HORIZONTAL));
364 	AddChild(BGroupLayoutBuilder(B_HORIZONTAL, 0)
365 		.Add(fPageSetupView)
366 	);
367 
368 	SetResult(B_ERROR);
369 }
370 
371 void
372 PageSetupDlg::MessageReceived(BMessage *msg)
373 {
374 	switch (msg->what) {
375 	case kMsgOK:
376 		Lock();
377 		fPageSetupView->UpdateJobData();
378 		Unlock();
379 		SetResult(B_NO_ERROR);
380 		PostMessage(B_QUIT_REQUESTED);
381 		break;
382 
383 	case kMsgCancel:
384 		PostMessage(B_QUIT_REQUESTED);
385 		break;
386 
387 	default:
388 		DialogWindow::MessageReceived(msg);
389 	}
390 }
391 
392