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