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