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