vfs: check userland buffers before reading them.
[haiku.git] / src / libs / print / libprint / MarginView.cpp
blobbecc93b807039c9d9f59388b88f99378e8a73540
1 /*
3 MarginView.cpp
5 Copyright (c) 2002 OpenBeOS.
7 Authors:
8 Philippe Houdoin
9 Simon Gauvin
10 Michael Pfeiffer
12 Permission is hereby granted, free of charge, to any person obtaining a copy of
13 this software and associated documentation files (the "Software"), to deal in
14 the Software without restriction, including without limitation the rights to
15 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
16 of the Software, and to permit persons to whom the Software is furnished to do
17 so, subject to the following conditions:
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 THE SOFTWARE.
30 Todo:
32 2 Make Strings constants or UI resources
36 #include "MarginView.h"
39 #include <AppKit.h>
40 #include <GridView.h>
41 #include <GridLayout.h>
42 #include <GroupLayout.h>
43 #include <GroupLayoutBuilder.h>
44 #include <SupportKit.h>
45 #include <TextControl.h>
48 #include <stdio.h>
49 #include <stdlib.h>
52 /*----------------- MarginView Private Constants --------------------*/
54 const int kOffsetY = 20;
55 const int kOffsetX = 10;
56 const int kStringSize = 50;
57 const int kWidth = 50;
58 const int kNumCount = 10;
60 const static float kPointUnits = 1; // 1 point = 1 point
61 const static float kInchUnits = 72; // 1" = 72 points
62 const static float kCMUnits = 28.346; // 72/2.54 1cm = 28.346 points
64 const static float kMinFieldWidth = 100; // pixels
65 const static float kMinUnitHeight = 30; // pixels
67 const static float kUnitFormat[] = { kInchUnits, kCMUnits, kPointUnits };
68 const static char *kUnitNames[] = { "inch", "cm", "points", NULL };
69 const static MarginUnit kUnitMsg[] = { kUnitInch, kUnitCM, kUnitPoint };
71 const pattern kDots = {{ 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }};
73 const rgb_color kBlack = { 0,0,0,0 };
74 const rgb_color kRed = { 255,0,0,0 };
75 const rgb_color kWhite = { 255,255,255,0 };
76 const rgb_color kGray = { 220,220,220,0 };
79 PageView::PageView()
80 : BView("pageView", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
81 , fPageWidth(0)
82 , fPageHeight(0)
83 , fMargins(0, 0, 0, 0)
89 void
90 PageView::SetPageSize(float pageWidth, float pageHeight)
92 fPageWidth = pageWidth;
93 fPageHeight = pageHeight;
97 void
98 PageView::SetMargins(BRect margins)
100 fMargins = margins;
104 void
105 PageView::Draw(BRect bounds)
107 BRect frame(Frame());
108 float totalWidth = frame.Width();
109 float totalHeight = frame.Height();
111 // fit page into available space
112 // keeping the ratio fPageWidth : fPageHeight
113 float pageWidth = totalWidth;
114 float pageHeight = totalWidth * fPageHeight / fPageWidth;
115 if (pageHeight > totalHeight) {
116 pageHeight = totalHeight;
117 pageWidth = totalHeight * fPageWidth / fPageHeight;
120 // center page
121 BPoint offset(0, 0);
122 offset.x = static_cast<int>((totalWidth - pageWidth) / 2);
123 offset.y = static_cast<int>((totalHeight - pageHeight) / 2);
125 // draw the page
126 SetHighColor(kWhite);
127 BRect r = BRect(0, 0, pageWidth, pageHeight);
128 r.OffsetBy(offset);
129 FillRect(r);
130 SetHighColor(kBlack);
131 StrokeRect(r);
133 // draw margin
134 SetHighColor(kRed);
135 SetLowColor(kWhite);
136 r.top += (fMargins.top / fPageHeight) * pageHeight;
137 r.right -= (fMargins.right / fPageWidth) * pageWidth;
138 r.bottom -= (fMargins.bottom / fPageHeight) * pageHeight;
139 r.left += (fMargins.left / fPageWidth) * pageWidth;
140 StrokeRect(r, kDots);
145 * Constructor
147 * @param pageWidth, float that is the points value of the page width
148 * @param pageHeight, float that is the points value of the page height
149 * @param margins, BRect values of margins
150 * @param units, unit32 enum for units used in view
151 * @return void
153 MarginView::MarginView(int32 pageWidth, int32 pageHeight,
154 BRect margins, MarginUnit units)
155 : BBox("marginView")
157 fMarginUnit = units;
158 fUnitValue = kUnitFormat[units];
160 SetLabel("Margins");
162 fMargins = margins;
164 fPageWidth = pageWidth;
165 fPageHeight = pageHeight;
170 * Destructor
172 * @param none
173 * @return void
175 MarginView::~MarginView()
181 * AttachToWindow
183 * @param none
184 * @return void
186 void
187 MarginView::AttachedToWindow()
189 if (Parent())
190 SetViewColor(Parent()->ViewColor());
192 _ConstructGUI();
197 * MesssageReceived()
199 * Receive messages for the view
201 * @param BMessage* , the message being received
202 * @return void
204 void
205 MarginView::MessageReceived(BMessage *msg)
207 switch (msg->what) {
208 case CHANGE_PAGE_SIZE: {
209 float w;
210 float h;
211 msg->FindFloat("width", &w);
212 msg->FindFloat("height", &h);
213 SetPageSize(w, h);
214 UpdateView(MARGIN_CHANGED);
215 } break;
217 case FLIP_PAGE: {
218 BPoint p = PageSize();
219 SetPageSize(p.y, p.x);
220 UpdateView(MARGIN_CHANGED);
221 } break;
223 case MARGIN_CHANGED:
224 UpdateView(MARGIN_CHANGED);
225 break;
227 case TOP_MARGIN_CHANGED:
228 UpdateView(TOP_MARGIN_CHANGED);
229 break;
231 case LEFT_MARGIN_CHANGED:
232 UpdateView(LEFT_MARGIN_CHANGED);
233 break;
235 case RIGHT_MARGIN_CHANGED:
236 UpdateView(RIGHT_MARGIN_CHANGED);
237 break;
239 case BOTTOM_MARGIN_CHANGED:
240 UpdateView(BOTTOM_MARGIN_CHANGED);
241 break;
243 case MARGIN_UNIT_CHANGED: {
244 int32 marginUnit;
245 if (msg->FindInt32("marginUnit", &marginUnit) == B_OK)
246 _SetMarginUnit((MarginUnit)marginUnit);
247 } break;
249 default:
250 BView::MessageReceived(msg);
251 break;
256 /*----------------- MarginView Public Methods --------------------*/
259 * PageSize
261 * @param none
262 * @return BPoint, contains actual point values of page in x, y of point
264 BPoint
265 MarginView::PageSize() const
267 return BPoint(fPageWidth, fPageHeight);
272 * SetPageSize
274 * @param pageWidth, float that is the unit value of the page width
275 * @param pageHeight, float that is the unit value of the page height
276 * @return void
278 void
279 MarginView::SetPageSize(float pageWidth, float pageHeight)
281 fPageWidth = pageWidth;
282 fPageHeight = pageHeight;
287 * Margin
289 * @param none
290 * @return rect, return margin values always in points
292 BRect
293 MarginView::Margin() const
295 BRect margin;
297 // convert the field text to values
298 float top = atof(fTop->Text());
299 float right = atof(fRight->Text());
300 float left = atof(fLeft->Text());
301 float bottom = atof(fBottom->Text());
303 // convert to units to points
304 switch (fMarginUnit) {
305 case kUnitInch:
306 // convert to points
307 top *= kInchUnits;
308 right *= kInchUnits;
309 left *= kInchUnits;
310 bottom *= kInchUnits;
311 break;
312 case kUnitCM:
313 // convert to points
314 top *= kCMUnits;
315 right *= kCMUnits;
316 left *= kCMUnits;
317 bottom *= kCMUnits;
318 break;
319 case kUnitPoint:
320 break;
323 margin.Set(left, top, right, bottom);
325 return margin;
331 * Unit
333 * @param none
334 * @return uint32 enum, units in inches, cm, points
336 MarginUnit
337 MarginView::Unit() const
339 return fMarginUnit;
344 * UpdateView, recalculate and redraw the view
346 * @param msg is a message to the calculate size to tell which field caused
347 * the update to occur, or it is a general update.
348 * @return void
350 void
351 MarginView::UpdateView(uint32 msg)
353 Window()->Lock();
356 char pageSize[kStringSize];
357 sprintf(pageSize, "%2.1f x %2.1f",
358 fPageWidth / fUnitValue,
359 fPageHeight / fUnitValue);
360 fPageSize->SetText(pageSize);
362 fPage->SetPageSize(fPageWidth, fPageHeight);
363 fPage->SetMargins(Margin());
364 fPage->Invalidate();
367 Invalidate();
368 Window()->Unlock();
372 /*----------------- MarginView Private Methods --------------------*/
375 * _ConstructGUI()
377 * Creates the GUI for the View. MUST be called AFTER the View is attached to
378 * the Window, or will crash and/or create strange behaviour
380 * @param none
381 * @return void
383 void
384 MarginView::_ConstructGUI()
386 fPage = new PageView();
387 fPage->SetViewColor(ViewColor());
389 fPageSize = new BStringView("pageSize", "?x?");
391 BString str;
392 // Create text fields
394 // top
395 str << fMargins.top/fUnitValue;
396 fTop = new BTextControl("top", "Top:", str.String(), NULL);
398 fTop->SetModificationMessage(new BMessage(TOP_MARGIN_CHANGED));
399 fTop->SetTarget(this);
400 _AllowOnlyNumbers(fTop, kNumCount);
402 //left
403 str = "";
404 str << fMargins.left/fUnitValue;
405 fLeft = new BTextControl("left", "Left:", str.String(), NULL);
407 fLeft->SetModificationMessage(new BMessage(LEFT_MARGIN_CHANGED));
408 fLeft->SetTarget(this);
409 _AllowOnlyNumbers(fLeft, kNumCount);
411 //bottom
412 str = "";
413 str << fMargins.bottom/fUnitValue;
414 fBottom = new BTextControl("bottom", "Bottom:", str.String(), NULL);
416 fBottom->SetModificationMessage(new BMessage(BOTTOM_MARGIN_CHANGED));
417 fBottom->SetTarget(this);
418 _AllowOnlyNumbers(fBottom, kNumCount);
420 //right
421 str = "";
422 str << fMargins.right/fUnitValue;
423 fRight = new BTextControl("right", "Right:", str.String(), NULL);
425 fRight->SetModificationMessage(new BMessage(RIGHT_MARGIN_CHANGED));
426 fRight->SetTarget(this);
427 _AllowOnlyNumbers(fRight, kNumCount);
429 // Create Units popup
431 BPopUpMenu *menu = new BPopUpMenu("units");
432 BMenuField *units = new BMenuField("units", "Units:", menu);
434 BMenuItem *item;
435 // Construct menu items
436 for (int32 i = 0; kUnitNames[i] != NULL; i++) {
437 BMessage *msg = new BMessage(MARGIN_UNIT_CHANGED);
438 msg->AddInt32("marginUnit", kUnitMsg[i]);
439 menu->AddItem(item = new BMenuItem(kUnitNames[i], msg));
440 item->SetTarget(this);
441 if (fMarginUnit == kUnitMsg[i])
442 item->SetMarked(true);
445 BGridView* settings = new BGridView();
446 BGridLayout* settingsLayout = settings->GridLayout();
447 settingsLayout->AddItem(fTop->CreateLabelLayoutItem(), 0, 0);
448 settingsLayout->AddItem(fTop->CreateTextViewLayoutItem(), 1, 0);
449 settingsLayout->AddItem(fLeft->CreateLabelLayoutItem(), 0, 1);
450 settingsLayout->AddItem(fLeft->CreateTextViewLayoutItem(), 1, 1);
451 settingsLayout->AddItem(fBottom->CreateLabelLayoutItem(), 0, 2);
452 settingsLayout->AddItem(fBottom->CreateTextViewLayoutItem(), 1, 2);
453 settingsLayout->AddItem(fRight->CreateLabelLayoutItem(), 0, 3);
454 settingsLayout->AddItem(fRight->CreateTextViewLayoutItem(), 1, 3);
455 settingsLayout->AddItem(units->CreateLabelLayoutItem(), 0, 4);
456 settingsLayout->AddItem(units->CreateMenuBarLayoutItem(), 1, 4);
457 settingsLayout->SetSpacing(0, 0);
459 BGroupView* groupView = new BGroupView(B_HORIZONTAL, 10);
460 BGroupLayout* groupLayout = groupView->GroupLayout();
461 groupLayout->AddView(BGroupLayoutBuilder(B_VERTICAL, 0)
462 .Add(fPage)
463 .Add(fPageSize)
464 .SetInsets(0, 0, 0, 0)
465 .TopView()
467 groupLayout->AddView(settings);
468 groupLayout->SetInsets(5, 5, 5, 5);
470 AddChild(groupView);
472 UpdateView(MARGIN_CHANGED);
477 * AllowOnlyNumbers()
479 * @param BTextControl, the control we want to only allow numbers
480 * @param maxNum, the maximun number of characters allowed
481 * @return void
483 void
484 MarginView::_AllowOnlyNumbers(BTextControl *textControl, int32 maxNum)
486 BTextView *tv = textControl->TextView();
488 for (int32 i = 0; i < 256; i++)
489 tv->DisallowChar(i);
491 for (int32 i = '0'; i <= '9'; i++)
492 tv->AllowChar(i);
494 tv->AllowChar(B_BACKSPACE);
495 // TODO internationalization; e.g. "." or ","
496 tv->AllowChar('.');
497 tv->SetMaxBytes(maxNum);
501 * SetMargin
503 * @param brect, margin values in rect
504 * @return void
506 void
507 MarginView::_SetMargin(BRect margin)
509 fMargins = margin;
514 * SetUnits, called by the MarginMgr when the units popup is selected
516 * @param uint32, the enum that identifies the units requested to change to.
517 * @return void
519 void
520 MarginView::_SetMarginUnit(MarginUnit unit)
522 // do nothing if the current units are the same as requested
523 if (unit == fMarginUnit) {
524 return;
527 // set the units Format
528 fUnitValue = kUnitFormat[unit];
530 // convert the field text to values
531 float top = atof(fTop->Text());
532 float right = atof(fRight->Text());
533 float left = atof(fLeft->Text());
534 float bottom = atof(fBottom->Text());
536 // convert to target units
537 switch (fMarginUnit)
539 case kUnitInch:
540 // convert to points
541 top *= kInchUnits;
542 right *= kInchUnits;
543 left *= kInchUnits;
544 bottom *= kInchUnits;
545 // check for target unit is cm
546 if (unit == kUnitCM) {
547 top /= kCMUnits;
548 right /= kCMUnits;
549 left /= kCMUnits;
550 bottom /= kCMUnits;
552 break;
553 case kUnitCM:
554 // convert to points
555 top *= kCMUnits;
556 right *= kCMUnits;
557 left *= kCMUnits;
558 bottom *= kCMUnits;
559 // check for target unit is inches
560 if (unit == kUnitInch) {
561 top /= kInchUnits;
562 right /= kInchUnits;
563 left /= kInchUnits;
564 bottom /= kInchUnits;
566 break;
567 case kUnitPoint:
568 // check for target unit is cm
569 if (unit == kUnitCM) {
570 top /= kCMUnits;
571 right /= kCMUnits;
572 left /= kCMUnits;
573 bottom /= kCMUnits;
575 // check for target unit is inches
576 if (unit == kUnitInch) {
577 top /= kInchUnits;
578 right /= kInchUnits;
579 left /= kInchUnits;
580 bottom /= kInchUnits;
582 break;
584 fMarginUnit = unit;
586 // lock Window since these changes are from another thread
587 Window()->Lock();
589 // set the fields to new units
590 BString str;
591 str << top;
592 fTop->SetText(str.String());
594 str = "";
595 str << left;
596 fLeft->SetText(str.String());
598 str = "";
599 str << right;
600 fRight->SetText(str.String());
602 str = "";
603 str << bottom;
604 fBottom->SetText(str.String());
606 // update UI
607 Invalidate();
609 Window()->Unlock();