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 <Looper.h> 19 #include <MessageFilter.h> 20 #include <MenuField.h> 21 #include <MenuItem.h> 22 #include <Message.h> 23 #include <Point.h> 24 #include <PopUpMenu.h> 25 #include <PrintJob.h> 26 #include <RadioButton.h> 27 #include <Rect.h> 28 #include <String.h> 29 #include <SupportDefs.h> 30 #include <TextControl.h> 31 #include <View.h> 32 33 34 #include "DbgMsg.h" 35 #include "JobData.h" 36 #include "MarginView.h" 37 #include "PageSetupDlg.h" 38 #include "PrinterData.h" 39 #include "PrinterCap.h" 40 #include "PrintUtils.h" 41 42 43 #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) 44 using namespace std; 45 #else 46 #define std 47 #endif 48 49 #define MENU_HEIGHT 16 50 #define MENU_WIDTH 200 51 #define BUTTON_WIDTH 70 52 #define BUTTON_HEIGHT 20 53 #define TEXT_HEIGHT 16 54 55 #define MARGIN_H 10 56 #define MARGIN_V 10 57 #define MARGIN_WIDTH 180 58 #define MARGIN_HEIGHT 140 59 60 #define PAGESETUP_WIDTH MARGIN_H + MARGIN_WIDTH + 15 + MENU_WIDTH + 10 61 #define PAGESETUP_HEIGHT MARGIN_V + MARGIN_HEIGHT + BUTTON_HEIGHT + 20 62 63 #define PAPER_H MARGIN_H + MARGIN_WIDTH + 15 64 #define PAPER_V 10 65 #define PAPER_WIDTH MENU_WIDTH 66 #define PAPER_HEIGHT MENU_HEIGHT 67 #define PAPER_TEXT "Paper Size:" 68 69 #define ORIENT_H PAPER_H 70 #define ORIENT_V PAPER_V + 24 71 #define ORIENT_WIDTH MENU_WIDTH 72 #define ORIENT_HEIGHT MENU_HEIGHT 73 #define ORIENTATION_TEXT "Orientation:" 74 #define PORTRAIT_TEXT "Portrait" 75 #define LANDSCAPE_TEXT "Landscape" 76 77 #define RES_H PAPER_H 78 #define RES_V ORIENT_V + 24 79 #define RES_WIDTH MENU_WIDTH 80 #define RES_HEIGHT MENU_HEIGHT 81 #define RES_TEXT "Resolution:" 82 83 #define SCALE_H PAPER_H 84 #define SCALE_V RES_V + 24 85 #define SCALE_WIDTH 100 86 #define SCALE_HEIGHT TEXT_HEIGHT 87 #define SCALE_TEXT "Scale [%]:" 88 89 #define OK_H (PAGESETUP_WIDTH - BUTTON_WIDTH - 11) 90 #define OK_V (PAGESETUP_HEIGHT - BUTTON_HEIGHT - 11) 91 #define OK_TEXT "OK" 92 93 #define CANCEL_H (OK_H - BUTTON_WIDTH - 12) 94 #define CANCEL_V OK_V 95 #define CANCEL_TEXT "Cancel" 96 97 #define PRINT_LINE_V (PAGESETUP_HEIGHT - BUTTON_HEIGHT - 23) 98 99 const BRect MARGIN_RECT( 100 MARGIN_H, 101 MARGIN_V, 102 MARGIN_H + MARGIN_WIDTH, 103 MARGIN_V + MARGIN_HEIGHT); 104 105 const BRect ORIENTATION_RECT( 106 ORIENT_H, 107 ORIENT_V, 108 ORIENT_H + ORIENT_WIDTH, 109 ORIENT_V + ORIENT_HEIGHT); 110 111 const BRect PAPER_RECT( 112 PAPER_H, 113 PAPER_V, 114 PAPER_H + PAPER_WIDTH, 115 PAPER_V + PAPER_HEIGHT); 116 117 const BRect RESOLUTION_RECT( 118 RES_H, 119 RES_V, 120 RES_H + RES_WIDTH, 121 RES_V + RES_HEIGHT); 122 123 const BRect SCALE_RECT( 124 SCALE_H, 125 SCALE_V, 126 SCALE_H + SCALE_WIDTH, 127 SCALE_V + SCALE_HEIGHT); 128 129 const BRect OK_RECT( 130 OK_H, 131 OK_V, 132 OK_H + BUTTON_WIDTH, 133 OK_V + BUTTON_HEIGHT); 134 135 const BRect CANCEL_RECT( 136 CANCEL_H, 137 CANCEL_V, 138 CANCEL_H + BUTTON_WIDTH, 139 CANCEL_V + BUTTON_HEIGHT); 140 141 enum MSGS { 142 kMsgCancel = 1, 143 kMsgOK, 144 kMsgOrientationChanged, 145 kMsgPaperChanged, 146 }; 147 148 PageSetupView::PageSetupView(BRect frame, JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) 149 : BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW), fJobData(job_data), fPrinterData(printer_data), fPrinterCap(printer_cap) 150 { 151 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 152 } 153 154 PageSetupView::~PageSetupView() 155 { 156 } 157 158 void 159 PageSetupView::AddOrientationItem(const char* name, JobData::Orientation orientation) 160 { 161 BMessage *msg = new BMessage(kMsgOrientationChanged); 162 msg->AddInt32("orientation", orientation); 163 BMenuItem *item = new BMenuItem(name, msg); 164 165 fOrientation->AddItem(item); 166 item->SetTarget(this); 167 if (fJobData->getOrientation() == orientation) { 168 item->SetMarked(true); 169 } else if (fOrientation->CountItems() == 1) { 170 item->SetMarked(true); 171 } 172 } 173 174 void 175 PageSetupView::AttachedToWindow() 176 { 177 BMenuItem *item = NULL; 178 BMenuField *menuField; 179 BButton *button; 180 bool marked; 181 int count; 182 183 /* margin */ 184 MarginUnit units = fJobData->getMarginUnit(); 185 BRect paper = fJobData->getPaperRect(); 186 BRect margin = fJobData->getPrintableRect(); 187 188 // re-calculate the margin from the printable rect in points 189 margin.top -= paper.top; 190 margin.left -= paper.left; 191 margin.right = paper.right - margin.right; 192 margin.bottom = paper.bottom - margin.bottom; 193 194 fMarginView = new MarginView(MARGIN_RECT, 195 paper.IntegerWidth(), 196 paper.IntegerHeight(), 197 margin, units); 198 AddChild(fMarginView); 199 200 /* paper selection */ 201 202 marked = false; 203 fPaper = new BPopUpMenu(""); 204 fPaper->SetRadioMode(true); 205 count = fPrinterCap->countCap(PrinterCap::kPaper); 206 PaperCap **paper_cap = (PaperCap **)fPrinterCap->enumCap(PrinterCap::kPaper); 207 while (count--) { 208 BMessage *msg = new BMessage(kMsgPaperChanged); 209 msg->AddPointer("paperCap", *paper_cap); 210 item = new BMenuItem((*paper_cap)->label.c_str(), msg); 211 fPaper->AddItem(item); 212 item->SetTarget(this); 213 if ((*paper_cap)->paper == fJobData->getPaper()) { 214 item->SetMarked(true); 215 marked = true; 216 } 217 paper_cap++; 218 } 219 if (!marked) 220 item->SetMarked(true); 221 menuField = new BMenuField(PAPER_RECT, "", PAPER_TEXT, fPaper); 222 AddChild(menuField); 223 float width = StringWidth(PAPER_TEXT) + 7; 224 menuField->SetDivider(width); 225 226 /* orientaion */ 227 fOrientation = new BPopUpMenu("orientation"); 228 fOrientation->SetRadioMode(true); 229 230 menuField = new BMenuField(ORIENTATION_RECT, "orientation", ORIENTATION_TEXT, fOrientation); 231 menuField->SetDivider(width); 232 233 count = fPrinterCap->countCap(PrinterCap::kOrientation); 234 if (count == 0) { 235 AddOrientationItem(PORTRAIT_TEXT, JobData::kPortrait); 236 AddOrientationItem(LANDSCAPE_TEXT, JobData::kLandscape); 237 } else { 238 OrientationCap **orientation_cap = (OrientationCap **)fPrinterCap->enumCap(PrinterCap::kOrientation); 239 while (count--) { 240 AddOrientationItem((*orientation_cap)->label.c_str(), 241 (*orientation_cap)->orientation); 242 orientation_cap++; 243 } 244 } 245 246 AddChild(menuField); 247 248 /* resolution */ 249 250 marked = false; 251 fResolution = new BPopUpMenu(""); 252 fResolution->SetRadioMode(true); 253 count = fPrinterCap->countCap(PrinterCap::kResolution); 254 ResolutionCap **resolution_cap = (ResolutionCap **)fPrinterCap->enumCap(PrinterCap::kResolution); 255 while (count--) { 256 item = new BMenuItem((*resolution_cap)->label.c_str(), NULL); 257 fResolution->AddItem(item); 258 item->SetTarget(this); 259 if (((*resolution_cap)->xres == fJobData->getXres()) && ((*resolution_cap)->yres == fJobData->getYres())) { 260 item->SetMarked(true); 261 marked = true; 262 } 263 resolution_cap++; 264 } 265 if (!marked) 266 item->SetMarked(true); 267 menuField = new BMenuField(RESOLUTION_RECT, "", RES_TEXT, fResolution); 268 AddChild(menuField); 269 menuField->SetDivider(width); 270 271 /* scale */ 272 BString scale; 273 scale << (int)fJobData->getScaling(); 274 fScaling = new BTextControl(SCALE_RECT, "scale", "Scale [%]:", 275 scale.String(), 276 NULL, B_FOLLOW_RIGHT); 277 int num; 278 for (num = 0; num <= 255; num++) { 279 fScaling->TextView()->DisallowChar(num); 280 } 281 for (num = 0; num <= 9; num++) { 282 fScaling->TextView()->AllowChar('0' + num); 283 } 284 fScaling->TextView()->SetMaxBytes(3); 285 fScaling->SetDivider(width); 286 287 AddChild(fScaling); 288 289 /* cancel */ 290 291 button = new BButton(CANCEL_RECT, "", CANCEL_TEXT, new BMessage(kMsgCancel)); 292 AddChild(button); 293 294 /* ok */ 295 296 button = new BButton(OK_RECT, "", OK_TEXT, new BMessage(kMsgOK)); 297 AddChild(button); 298 button->MakeDefault(true); 299 } 300 301 inline void 302 swap(float *e1, float *e2) 303 { 304 float e = *e1; 305 *e1 = *e2; 306 *e2 = e; 307 } 308 309 JobData::Orientation 310 PageSetupView::GetOrientation() 311 { 312 BMenuItem *item = fOrientation->FindMarked(); 313 int32 orientation; 314 if (item != NULL && 315 item->Message()->FindInt32("orientation", &orientation) == B_OK) { 316 return (JobData::Orientation)orientation; 317 } else { 318 return JobData::kPortrait; 319 } 320 } 321 322 PaperCap * 323 PageSetupView::GetPaperCap() 324 { 325 BMenuItem *item = fPaper->FindMarked(); 326 void *pointer; 327 if (item != NULL && 328 item->Message()->FindPointer("paperCap", &pointer) == B_OK) { 329 return (PaperCap*)pointer; 330 } else { 331 return (PaperCap*)fPrinterCap->getDefaultCap(PrinterCap::kPaper); 332 } 333 } 334 335 bool 336 PageSetupView::UpdateJobData() 337 { 338 fJobData->setOrientation(GetOrientation()); 339 340 PaperCap *paperCap = GetPaperCap(); 341 BRect paper_rect = paperCap->paper_rect; 342 BRect physical_rect = paperCap->physical_rect; 343 fJobData->setPaper(paperCap->paper); 344 345 int count; 346 347 count = fPrinterCap->countCap(PrinterCap::kResolution); 348 ResolutionCap **resolution_cap = (ResolutionCap **)fPrinterCap->enumCap(PrinterCap::kResolution); 349 const char *resolution_label = fResolution->FindMarked()->Label(); 350 while (count--) { 351 if (!strcmp((*resolution_cap)->label.c_str(), resolution_label)) { 352 fJobData->setXres((*resolution_cap)->xres); 353 fJobData->setYres((*resolution_cap)->yres); 354 break; 355 } 356 resolution_cap++; 357 } 358 359 // rotate paper and physical rectangle if landscape orientation 360 if (JobData::kLandscape == fJobData->getOrientation()) { 361 swap(&paper_rect.left, &paper_rect.top); 362 swap(&paper_rect.right, &paper_rect.bottom); 363 swap(&physical_rect.left, &physical_rect.top); 364 swap(&physical_rect.right, &physical_rect.bottom); 365 } 366 367 // adjust printable rect by margin 368 fJobData->setMarginUnit(fMarginView->Unit()); 369 BRect margin = fMarginView->Margin(); 370 BRect printable_rect; 371 printable_rect.left = paper_rect.left + margin.left; 372 printable_rect.top = paper_rect.top + margin.top; 373 printable_rect.right = paper_rect.right - margin.right; 374 printable_rect.bottom = paper_rect.bottom - margin.bottom; 375 376 printable_rect.left = max_c(printable_rect.left, physical_rect.left); 377 printable_rect.top = max_c(printable_rect.top, physical_rect.top); 378 printable_rect.right = min_c(printable_rect.right, physical_rect.right); 379 printable_rect.bottom = min_c(printable_rect.bottom, physical_rect.bottom); 380 381 float scaling = atoi(fScaling->Text()); 382 if (scaling <= 0.0) { // sanity check 383 scaling = 100.0; 384 } 385 if (scaling > 1000.0) { 386 scaling = 1000.0; 387 } 388 389 float scalingR = 100.0 / scaling; 390 391 fJobData->setScaling(scaling); 392 fJobData->setPaperRect(paper_rect); 393 fJobData->setScaledPaperRect(ScaleRect(paper_rect, scalingR)); 394 fJobData->setPrintableRect(printable_rect); 395 fJobData->setScaledPrintableRect(ScaleRect(printable_rect, scalingR)); 396 fJobData->setPhysicalRect(physical_rect); 397 fJobData->setScaledPhysicalRect(ScaleRect(physical_rect, scalingR)); 398 399 fJobData->save(); 400 return true; 401 } 402 403 void 404 PageSetupView::MessageReceived(BMessage *msg) 405 { 406 switch (msg->what) { 407 case kMsgPaperChanged: 408 case kMsgOrientationChanged: 409 { 410 JobData::Orientation orientation = GetOrientation(); 411 PaperCap *paperCap = GetPaperCap(); 412 float width = paperCap->paper_rect.Width(); 413 float height = paperCap->paper_rect.Height(); 414 if (orientation != JobData::kPortrait) { 415 swap(&width, &height); 416 } 417 fMarginView->SetPageSize(width, height); 418 fMarginView->UpdateView(MARGIN_CHANGED); 419 420 } 421 break; 422 } 423 } 424 425 //==================================================================== 426 427 PageSetupDlg::PageSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) 428 : DialogWindow(BRect(100, 100, 100 + PAGESETUP_WIDTH, 100 + PAGESETUP_HEIGHT), 429 "Page Setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, 430 B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE) 431 { 432 AddShortcut('W',B_COMMAND_KEY,new BMessage(B_QUIT_REQUESTED)); 433 434 PageSetupView *view = new PageSetupView(Bounds(), job_data, printer_data, printer_cap); 435 AddChild(view); 436 437 SetResult(B_ERROR); 438 } 439 440 void 441 PageSetupDlg::MessageReceived(BMessage *msg) 442 { 443 switch (msg->what) { 444 case kMsgOK: 445 Lock(); 446 ((PageSetupView *)ChildAt(0))->UpdateJobData(); 447 Unlock(); 448 SetResult(B_NO_ERROR); 449 PostMessage(B_QUIT_REQUESTED); 450 break; 451 452 case kMsgCancel: 453 PostMessage(B_QUIT_REQUESTED); 454 break; 455 456 default: 457 DialogWindow::MessageReceived(msg); 458 } 459 } 460 461