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 47using namespace std; 48 49 50enum MSGS { 51 kMsgCancel = 1, 52 kMsgOK, 53 kMsgOrientationChanged, 54 kMsgPaperChanged, 55}; 56 57PageSetupView::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 67PageSetupView::~PageSetupView() 68{ 69} 70 71void 72PageSetupView::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 87void 88PageSetupView::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 226inline void 227swap(float *e1, float *e2) 228{ 229 float e = *e1; 230 *e1 = *e2; 231 *e2 = e; 232} 233 234JobData::Orientation 235PageSetupView::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 247PaperCap * 248PageSetupView::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 260bool 261PageSetupView::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 324void 325PageSetupView::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 349PageSetupDlg::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 368void 369PageSetupDlg::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