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 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 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 65 } 66 67 PageSetupView::~PageSetupView() 68 { 69 } 70 71 void 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 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 227 swap(float *e1, float *e2) 228 { 229 float e = *e1; 230 *e1 = *e2; 231 *e2 = e; 232 } 233 234 JobData::Orientation 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 * 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 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 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 349 PageSetupDlg::PageSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) 350 : DialogWindow(BRect(100, 100, 160, 160), 351 "Page 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 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