1 // main.cpp 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 6 #include <Application.h> 7 #include <Alert.h> 8 #include <Bitmap.h> 9 #include <Box.h> 10 #include <Button.h> 11 #include <Catalog.h> 12 #include <CheckBox.h> 13 #include <ColorControl.h> 14 #include <ListItem.h> 15 #include <ListView.h> 16 #include <Menu.h> 17 #include <MenuBar.h> 18 #include <MenuField.h> 19 #include <MenuItem.h> 20 #include <PopUpMenu.h> 21 #include <ScrollBar.h> 22 #include <ScrollView.h> 23 #include <Slider.h> 24 #include <String.h> 25 #include <RadioButton.h> 26 #include <Region.h> 27 #include <TabView.h> 28 #include <TextControl.h> 29 #include <TextView.h> 30 31 #include "ObjectView.h" 32 #include "ObjectWindow.h" 33 #include "States.h" 34 //#include "StatusView.h" 35 36 37 #undef B_TRANSLATION_CONTEXT 38 #define B_TRANSLATION_CONTEXT "Playground" 39 40 enum { 41 MSG_SET_OBJECT_TYPE = 'stot', 42 MSG_SET_FILL_OR_STROKE = 'stfs', 43 MSG_SET_COLOR = 'stcl', 44 MSG_SET_PEN_SIZE = 'stps', 45 MSG_SET_DRAWING_MODE = 'stdm', 46 47 MSG_NEW_OBJECT = 'nobj', 48 49 MSG_UNDO = 'undo', 50 MSG_REDO = 'redo', 51 52 MSG_CLEAR = 'clir', 53 54 MSG_OBJECT_SELECTED = 'obsl', 55 MSG_REMOVE_OBJECT = 'rmob', 56 }; 57 58 // ObjectItem 59 class ObjectItem : public BStringItem { 60 public: 61 ObjectItem(const char* name, State* object) 62 : BStringItem(name), 63 fObject(object) 64 { 65 } 66 67 State* Object() const 68 { return fObject; } 69 70 private: 71 State* fObject; 72 }; 73 74 // ObjectListView 75 class ObjectListView : public BListView { 76 public: 77 ObjectListView(BRect frame, const char* name, list_view_type listType) 78 : BListView(frame, name, listType) 79 { 80 } 81 82 virtual void KeyDown(const char* bytes, int32 numBytes) 83 { 84 switch (*bytes) { 85 case B_DELETE: 86 Window()->PostMessage(MSG_REMOVE_OBJECT); 87 break; 88 default: 89 BListView::KeyDown(bytes, numBytes); 90 } 91 } 92 93 virtual bool InitiateDrag(BPoint point, int32 itemIndex, bool wasSelected) 94 { 95 printf("InitiateDrag(BPoint(%.1f, %.1f), itemIndex: %" B_PRId32 96 ", wasSelected: %d)\n", point.x, point.y, itemIndex, 97 wasSelected); 98 SwapItems(itemIndex, itemIndex + 1); 99 return true; 100 } 101 102 virtual void SelectionChanged() 103 { 104 // printf("SelectionChanged() - first selected: %ld\n", CurrentSelection(0)); 105 } 106 }; 107 108 // #pragma mark - 109 110 class TestView : public BView { 111 public: 112 TestView(BRect frame, const char* name, uint32 resizeMode, uint32 flags) 113 : BView(frame, name, resizeMode, flags) 114 { 115 } 116 117 void AttachedToWindow() 118 { 119 SetViewColor(255, 0, 0); 120 } 121 }; 122 123 // constructor 124 ObjectWindow::ObjectWindow(BRect frame, const char* name) 125 : BWindow(frame, name, B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 126 B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE) 127 { 128 BRect b(Bounds()); 129 130 b.bottom = b.top + 8; 131 BMenuBar* menuBar = new BMenuBar(b, "menu bar"); 132 AddChild(menuBar); 133 134 BMenu* menu = new BMenu(B_TRANSLATE("File")); 135 menuBar->AddItem(menu); 136 137 menu->AddItem(new BMenu(B_TRANSLATE("Submenu"))); 138 139 BMenuItem* menuItem = new BMenuItem(B_TRANSLATE("Quit"), new BMessage(B_QUIT_REQUESTED), 140 'Q'); 141 menu->AddItem(menuItem); 142 143 b = Bounds(); 144 b.top = menuBar->Bounds().bottom + 1; 145 b.right = ceilf((b.left + b.right) / 2.0); 146 BBox* bg = new BBox(b, "bg box", B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW, 147 B_PLAIN_BORDER); 148 149 AddChild(bg); 150 bg->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 151 152 // object view occupies the right side of the window 153 b.left = b.right + 1.0; 154 b.right = Bounds().right - B_V_SCROLL_BAR_WIDTH; 155 b.bottom -= B_H_SCROLL_BAR_HEIGHT; 156 fObjectView = new ObjectView(b, "object view", B_FOLLOW_ALL, 157 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE); 158 // wrap a scroll view around the object view 159 BScrollView* scrollView = new BScrollView("object scroller", fObjectView, 160 B_FOLLOW_ALL, 0, true, true, B_NO_BORDER); 161 162 if (BScrollBar* scrollBar = fObjectView->ScrollBar(B_VERTICAL)) { 163 scrollBar->SetRange(0.0, fObjectView->Bounds().Height()); 164 scrollBar->SetProportion(0.5); 165 } 166 if (BScrollBar* scrollBar = fObjectView->ScrollBar(B_HORIZONTAL)) { 167 scrollBar->SetRange(0.0, fObjectView->Bounds().Width()); 168 scrollBar->SetProportion(0.5); 169 } 170 AddChild(scrollView); 171 172 b = bg->Bounds(); 173 // controls occupy the left side of the window 174 b.InsetBy(5.0, 5.0); 175 BBox* controlGroup = new BBox(b, "controls box", 176 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW, B_FANCY_BORDER); 177 178 controlGroup->SetLabel(B_TRANSLATE("Controls")); 179 bg->AddChild(controlGroup); 180 181 b = controlGroup->Bounds(); 182 b.top += controlGroup->InnerFrame().top; 183 b.bottom = b.top + 25.0; 184 b.InsetBy(10.0, 10.0); 185 b.right = b.left + b.Width() / 2.0 - 5.0; 186 187 // new button 188 fNewB = new BButton(b, "new button", B_TRANSLATE("New object"), 189 new BMessage(MSG_NEW_OBJECT)); 190 controlGroup->AddChild(fNewB); 191 SetDefaultButton(fNewB); 192 193 // clear button 194 b.OffsetBy(0, fNewB->Bounds().Height() + 5.0); 195 fClearB = new BButton(b, "clear button", B_TRANSLATE("Clear"), new BMessage(MSG_CLEAR)); 196 controlGroup->AddChild(fClearB); 197 198 // object type radio buttons 199 BMessage* message; 200 BRadioButton* radioButton; 201 202 b.OffsetBy(0, fClearB->Bounds().Height() + 5.0); 203 message = new BMessage(MSG_SET_OBJECT_TYPE); 204 message->AddInt32("type", OBJECT_LINE); 205 radioButton = new BRadioButton(b, "radio 1", B_TRANSLATE("Line"), message); 206 controlGroup->AddChild(radioButton); 207 208 radioButton->SetValue(B_CONTROL_ON); 209 210 b.OffsetBy(0, radioButton->Bounds().Height() + 5.0); 211 message = new BMessage(MSG_SET_OBJECT_TYPE); 212 message->AddInt32("type", OBJECT_RECT); 213 radioButton = new BRadioButton(b, "radio 2", B_TRANSLATE("Rect"), message); 214 controlGroup->AddChild(radioButton); 215 216 b.OffsetBy(0, radioButton->Bounds().Height() + 5.0); 217 message = new BMessage(MSG_SET_OBJECT_TYPE); 218 message->AddInt32("type", OBJECT_ROUND_RECT); 219 radioButton = new BRadioButton(b, "radio 3", B_TRANSLATE("Round rect"), message); 220 controlGroup->AddChild(radioButton); 221 222 b.OffsetBy(0, radioButton->Bounds().Height() + 5.0); 223 message = new BMessage(MSG_SET_OBJECT_TYPE); 224 message->AddInt32("type", OBJECT_ELLIPSE); 225 radioButton = new BRadioButton(b, "radio 4", B_TRANSLATE("Ellipse"), message); 226 controlGroup->AddChild(radioButton); 227 228 // drawing mode 229 BPopUpMenu* popupMenu = new BPopUpMenu(B_TRANSLATE("<pick>")); 230 231 message = new BMessage(MSG_SET_DRAWING_MODE); 232 message->AddInt32("mode", B_OP_COPY); 233 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Copy"), message)); 234 235 message = new BMessage(MSG_SET_DRAWING_MODE); 236 message->AddInt32("mode", B_OP_OVER); 237 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Over"), message)); 238 239 message = new BMessage(MSG_SET_DRAWING_MODE); 240 message->AddInt32("mode", B_OP_INVERT); 241 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Invert"), message)); 242 243 message = new BMessage(MSG_SET_DRAWING_MODE); 244 message->AddInt32("mode", B_OP_BLEND); 245 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Blend"), message)); 246 247 message = new BMessage(MSG_SET_DRAWING_MODE); 248 message->AddInt32("mode", B_OP_SELECT); 249 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Select"), message)); 250 251 message = new BMessage(MSG_SET_DRAWING_MODE); 252 message->AddInt32("mode", B_OP_ERASE); 253 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Erase"), message)); 254 255 message = new BMessage(MSG_SET_DRAWING_MODE); 256 message->AddInt32("mode", B_OP_ADD); 257 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Add"), message)); 258 259 message = new BMessage(MSG_SET_DRAWING_MODE); 260 message->AddInt32("mode", B_OP_SUBTRACT); 261 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Subtract"), message)); 262 263 message = new BMessage(MSG_SET_DRAWING_MODE); 264 message->AddInt32("mode", B_OP_MIN); 265 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Min"), message)); 266 267 message = new BMessage(MSG_SET_DRAWING_MODE); 268 message->AddInt32("mode", B_OP_MAX); 269 popupMenu->AddItem(new BMenuItem(B_TRANSLATE("Max"), message)); 270 271 message = new BMessage(MSG_SET_DRAWING_MODE); 272 message->AddInt32("mode", B_OP_ALPHA); 273 BMenuItem* item = new BMenuItem(B_TRANSLATE("Alpha"), message); 274 item->SetMarked(true); 275 popupMenu->AddItem(item); 276 277 b.OffsetBy(0, radioButton->Bounds().Height() + 10.0); 278 fDrawingModeMF = new BMenuField(b, "drawing mode field", B_TRANSLATE("Mode:"), 279 popupMenu); 280 281 controlGroup->AddChild(fDrawingModeMF); 282 283 fDrawingModeMF->SetDivider(fDrawingModeMF->StringWidth( 284 fDrawingModeMF->Label()) + 10.0); 285 286 // color control 287 b.OffsetBy(0, fDrawingModeMF->Bounds().Height() + 10.0); 288 fColorControl = new BColorControl(b.LeftTop(), B_CELLS_16x16, 8, 289 "color control", new BMessage(MSG_SET_COLOR)); 290 controlGroup->AddChild(fColorControl); 291 292 // alpha text control 293 b.OffsetBy(0, fColorControl-> Bounds().Height() + 5.0); 294 fAlphaTC = new BTextControl(b, "alpha text control", B_TRANSLATE("Alpha:"), "", 295 new BMessage(MSG_SET_COLOR)); 296 controlGroup->AddChild(fAlphaTC); 297 298 // divide text controls the same 299 float mWidth = fDrawingModeMF->StringWidth(fDrawingModeMF->Label()); 300 float aWidth = fAlphaTC->StringWidth(fAlphaTC->Label()); 301 302 float width = max_c(mWidth, aWidth) + 20.0; 303 fDrawingModeMF->SetDivider(width); 304 fAlphaTC->SetDivider(width); 305 306 // fill check box 307 b.OffsetBy(0, fAlphaTC->Bounds().Height() + 5.0); 308 fFillCB = new BCheckBox(b, "fill check box", B_TRANSLATE("Fill"), 309 new BMessage(MSG_SET_FILL_OR_STROKE)); 310 controlGroup->AddChild(fFillCB); 311 312 // pen size text control 313 b.OffsetBy(0, radioButton->Bounds().Height() + 5.0); 314 b.bottom = b.top + 10.0;//35; 315 fPenSizeS = new BSlider(b, "width slider", B_TRANSLATE("Width:"), NULL, 1, 100, 316 B_TRIANGLE_THUMB); 317 fPenSizeS->SetLimitLabels("1", "100"); 318 fPenSizeS->SetModificationMessage(new BMessage(MSG_SET_PEN_SIZE)); 319 fPenSizeS->SetHashMarks(B_HASH_MARKS_BOTTOM); 320 fPenSizeS->SetHashMarkCount(10); 321 322 controlGroup->AddChild(fPenSizeS); 323 324 // list view with objects 325 b = controlGroup->Bounds(); 326 b.top += controlGroup->InnerFrame().top; 327 b.InsetBy(10.0, 10.0); 328 b.left = b.left + b.Width() / 2.0 + 6.0; 329 b.right -= B_V_SCROLL_BAR_WIDTH; 330 b.bottom = fDrawingModeMF->Frame().top - 10.0; 331 332 fObjectLV = new ObjectListView(b, "object list", B_SINGLE_SELECTION_LIST); 333 fObjectLV->SetSelectionMessage(new BMessage(MSG_OBJECT_SELECTED)); 334 335 // wrap a scroll view around the list view 336 scrollView = new BScrollView("list scroller", fObjectLV, 337 B_FOLLOW_NONE, 0, false, true, B_FANCY_BORDER); 338 controlGroup->AddChild(scrollView); 339 340 // enforce some size limits 341 float minWidth = controlGroup->Frame().Width() + 30.0; 342 float minHeight = fPenSizeS->Frame().bottom 343 + menuBar->Bounds().Height() + 15.0; 344 float maxWidth = minWidth * 4.0; 345 float maxHeight = minHeight + 100; 346 SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight); 347 348 ResizeTo(max_c(frame.Width(), minWidth), max_c(frame.Height(), minHeight)); 349 350 _UpdateControls(); 351 } 352 353 // destructor 354 ObjectWindow::~ObjectWindow() 355 { 356 } 357 358 // QuitRequested 359 bool 360 ObjectWindow::QuitRequested() 361 { 362 be_app->PostMessage(B_QUIT_REQUESTED); 363 return true; 364 } 365 366 // MessageReceived 367 void 368 ObjectWindow::MessageReceived(BMessage* message) 369 { 370 switch (message->what) { 371 case MSG_SET_OBJECT_TYPE: { 372 int32 type; 373 if (message->FindInt32("type", &type) >= B_OK) { 374 fObjectView->SetObjectType(type); 375 fFillCB->SetEnabled(type != OBJECT_LINE); 376 if (!fFillCB->IsEnabled()) 377 fPenSizeS->SetEnabled(true); 378 else 379 fPenSizeS->SetEnabled(fFillCB->Value() == B_CONTROL_OFF); 380 } 381 break; 382 } 383 case MSG_SET_FILL_OR_STROKE: { 384 int32 value; 385 if (message->FindInt32("be:value", &value) >= B_OK) { 386 fObjectView->SetStateFill(value); 387 fPenSizeS->SetEnabled(value == B_CONTROL_OFF); 388 } 389 break; 390 } 391 case MSG_SET_COLOR: 392 fObjectView->SetStateColor(_GetColor()); 393 _UpdateColorControls(); 394 break; 395 case MSG_OBJECT_ADDED: { 396 State* object; 397 if (message->FindPointer("object", (void**)&object) >= B_OK) { 398 fObjectLV->AddItem(new ObjectItem("Object", object)); 399 } 400 // fall through 401 } 402 case MSG_OBJECT_COUNT_CHANGED: 403 fClearB->SetEnabled(fObjectView->CountObjects() > 0); 404 break; 405 case MSG_OBJECT_SELECTED: 406 if (ObjectItem* item = (ObjectItem*)fObjectLV->ItemAt(fObjectLV->CurrentSelection(0))) { 407 fObjectView->SetState(item->Object()); 408 fObjectView->SetStateColor(item->Object()->Color()); 409 _UpdateControls(); 410 } else 411 fObjectView->SetState(NULL); 412 break; 413 case MSG_REMOVE_OBJECT: 414 while (ObjectItem* item = (ObjectItem*)fObjectLV->ItemAt(fObjectLV->CurrentSelection(0))) { 415 fObjectView->RemoveObject(item->Object()); 416 fObjectLV->RemoveItem(item); 417 delete item; 418 } 419 break; 420 case MSG_NEW_OBJECT: 421 fObjectView->SetState(NULL); 422 break; 423 case MSG_CLEAR: { 424 BAlert *alert = new BAlert("Playground", 425 B_TRANSLATE("Clear all drawing objects?"), 426 B_TRANSLATE("Cancel"), B_TRANSLATE("Clear")); 427 alert->SetShortcut(0, B_ESCAPE); 428 if (alert->Go() == 1) { 429 fObjectView->MakeEmpty(); 430 fObjectLV->MakeEmpty(); 431 } 432 break; 433 } 434 case MSG_SET_PEN_SIZE: 435 fObjectView->SetStatePenSize((float)fPenSizeS->Value()); 436 break; 437 case MSG_SET_DRAWING_MODE: { 438 drawing_mode mode; 439 if (message->FindInt32("mode", (int32*)&mode) >= B_OK) { 440 fObjectView->SetStateDrawingMode(mode); 441 } 442 break; 443 } 444 default: 445 BWindow::MessageReceived(message); 446 } 447 } 448 449 // _UpdateControls 450 void 451 ObjectWindow::_UpdateControls() const 452 { 453 _UpdateColorControls(); 454 455 // update buttons 456 fClearB->SetEnabled(fObjectView->CountObjects() > 0); 457 458 fFillCB->SetEnabled(fObjectView->ObjectType() != OBJECT_LINE); 459 460 // pen size 461 fPenSizeS->SetValue((int32)fObjectView->StatePenSize()); 462 463 // disable penSize if fill is on 464 if (!fFillCB->IsEnabled()) 465 fPenSizeS->SetEnabled(true); 466 else 467 fPenSizeS->SetEnabled(fFillCB->Value() == B_CONTROL_OFF); 468 } 469 470 // _UpdateColorControls 471 void 472 ObjectWindow::_UpdateColorControls() const 473 { 474 // update color 475 rgb_color c = fObjectView->StateColor(); 476 char string[32]; 477 478 sprintf(string, "%d", c.alpha); 479 fAlphaTC->SetText(string); 480 481 fColorControl->SetValue(c); 482 } 483 484 // _GetColor 485 rgb_color 486 ObjectWindow::_GetColor() const 487 { 488 rgb_color c; 489 490 c = fColorControl->ValueAsColor(); 491 c.alpha = max_c(0, min_c(255, atoi(fAlphaTC->Text()))); 492 493 return c; 494 } 495 496