1 /* 2 * Copyright 2006-2008, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "MainWindow.h" 10 11 #include <new> 12 #include <stdio.h> 13 14 #include <Menu.h> 15 #include <MenuBar.h> 16 #include <MenuItem.h> 17 #include <Message.h> 18 #include <Screen.h> 19 #include <ScrollView.h> 20 21 #ifdef __HAIKU__ 22 # include <GridLayout.h> 23 # include <GroupLayout.h> 24 # include <GroupView.h> 25 #endif 26 27 #include "support_ui.h" 28 29 #include "AddPathsCommand.h" 30 #include "AddShapesCommand.h" 31 #include "AddStylesCommand.h" 32 #include "CanvasView.h" 33 #include "CommandStack.h" 34 #include "CompoundCommand.h" 35 #include "CurrentColor.h" 36 #include "Document.h" 37 #include "Exporter.h" 38 #include "IconObjectListView.h" 39 #include "IconEditorApp.h" 40 #include "IconView.h" 41 #include "PathListView.h" 42 #include "ScrollView.h" 43 #include "ShapeListView.h" 44 #include "StyleListView.h" 45 #include "StyleView.h" 46 #include "SwatchGroup.h" 47 #include "TransformerListView.h" 48 #include "TransformGradientBox.h" 49 #include "TransformShapesBox.h" 50 #include "Util.h" 51 52 // TODO: just for testing 53 #include "AffineTransformer.h" 54 #include "Gradient.h" 55 #include "Icon.h" 56 #include "MultipleManipulatorState.h" 57 #include "PathManipulator.h" 58 #include "Shape.h" 59 #include "ShapeContainer.h" 60 #include "ShapeListView.h" 61 #include "StrokeTransformer.h" 62 #include "Style.h" 63 #include "StyleContainer.h" 64 #include "VectorPath.h" 65 66 using std::nothrow; 67 68 enum { 69 MSG_UNDO = 'undo', 70 MSG_REDO = 'redo', 71 72 MSG_PATH_SELECTED = 'vpsl', 73 MSG_STYLE_SELECTED = 'stsl', 74 MSG_SHAPE_SELECTED = 'spsl', 75 76 MSG_SHAPE_RESET_TRANSFORMATION = 'rtsh', 77 MSG_STYLE_RESET_TRANSFORMATION = 'rtst', 78 79 MSG_MOUSE_FILTER_MODE = 'mfmd', 80 }; 81 82 // constructor 83 MainWindow::MainWindow(IconEditorApp* app, Document* document, 84 const BMessage* settings) 85 : BWindow(BRect(50, 50, 900, 750), "Icon-O-Matic", 86 #ifdef __HAIKU__ 87 B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 88 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 89 #else 90 B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS), 91 #endif 92 fApp(app), 93 fDocument(document), 94 fIcon(NULL) 95 { 96 RestoreSettings(settings); 97 98 _Init(); 99 } 100 101 // destructor 102 MainWindow::~MainWindow() 103 { 104 delete fState; 105 106 if (fIcon) 107 fIcon->Release(); 108 109 fDocument->CommandStack()->RemoveObserver(this); 110 } 111 112 // #pragma mark - 113 114 // MessageReceived 115 void 116 MainWindow::MessageReceived(BMessage* message) 117 { 118 if (!fDocument || !fDocument->WriteLock()) { 119 BWindow::MessageReceived(message); 120 return; 121 } 122 123 switch (message->what) { 124 125 case B_REFS_RECEIVED: 126 case B_SIMPLE_DATA: 127 message->what = B_REFS_RECEIVED; 128 if (modifiers() & B_SHIFT_KEY) 129 message->AddBool("append", true); 130 be_app->PostMessage(message); 131 break; 132 133 case MSG_UNDO: 134 fDocument->CommandStack()->Undo(); 135 break; 136 case MSG_REDO: 137 fDocument->CommandStack()->Redo(); 138 break; 139 140 case MSG_MOUSE_FILTER_MODE: { 141 uint32 mode; 142 if (message->FindInt32("mode", (int32*)&mode) == B_OK) 143 fCanvasView->SetMouseFilterMode(mode); 144 break; 145 } 146 147 case MSG_SET_ICON: 148 SetIcon(fDocument->Icon()); 149 break; 150 151 case MSG_ADD_SHAPE: { 152 AddStylesCommand* styleCommand = NULL; 153 Style* style = NULL; 154 if (message->HasBool("style")) { 155 new_style(CurrentColor::Default()->Color(), 156 fDocument->Icon()->Styles(), &style, &styleCommand); 157 } 158 159 AddPathsCommand* pathCommand = NULL; 160 VectorPath* path = NULL; 161 if (message->HasBool("path")) { 162 new_path(fDocument->Icon()->Paths(), &path, &pathCommand); 163 } 164 165 if (!style) { 166 // use current or first style 167 int32 currentStyle = fStyleListView->CurrentSelection(0); 168 style = fDocument->Icon()->Styles()->StyleAt(currentStyle); 169 if (!style) 170 style = fDocument->Icon()->Styles()->StyleAt(0); 171 } 172 173 Shape* shape = new (nothrow) Shape(style); 174 Shape* shapes[1]; 175 shapes[0] = shape; 176 AddShapesCommand* shapeCommand = new (nothrow) AddShapesCommand( 177 fDocument->Icon()->Shapes(), shapes, 1, 178 fDocument->Icon()->Shapes()->CountShapes(), 179 fDocument->Selection()); 180 181 if (path && shape) 182 shape->Paths()->AddPath(path); 183 184 ::Command* command = NULL; 185 if (styleCommand || pathCommand) { 186 if (styleCommand && pathCommand) { 187 Command** commands = new Command*[3]; 188 commands[0] = styleCommand; 189 commands[1] = pathCommand; 190 commands[2] = shapeCommand; 191 command = new CompoundCommand(commands, 3, 192 "Add Shape With Path & Style", 0); 193 } else if (styleCommand) { 194 Command** commands = new Command*[2]; 195 commands[0] = styleCommand; 196 commands[1] = shapeCommand; 197 command = new CompoundCommand(commands, 2, 198 "Add Shape With Style", 0); 199 } else { 200 Command** commands = new Command*[2]; 201 commands[0] = pathCommand; 202 commands[1] = shapeCommand; 203 command = new CompoundCommand(commands, 2, 204 "Add Shape With Path", 0); 205 } 206 } else { 207 command = shapeCommand; 208 } 209 fDocument->CommandStack()->Perform(command); 210 break; 211 } 212 213 // TODO: listen to selection in CanvasView to add a manipulator 214 case MSG_PATH_SELECTED: { 215 VectorPath* path; 216 if (message->FindPointer("path", (void**)&path) < B_OK) 217 path = NULL; 218 219 fPathListView->SetCurrentShape(NULL); 220 fStyleListView->SetCurrentShape(NULL); 221 fTransformerListView->SetShape(NULL); 222 223 fState->DeleteManipulators(); 224 if (fDocument->Icon()->Paths()->HasPath(path)) { 225 PathManipulator* pathManipulator = new (nothrow) PathManipulator(path); 226 fState->AddManipulator(pathManipulator); 227 } 228 break; 229 } 230 case MSG_STYLE_SELECTED: 231 case MSG_STYLE_TYPE_CHANGED: { 232 Style* style; 233 if (message->FindPointer("style", (void**)&style) < B_OK) 234 style = NULL; 235 if (!fDocument->Icon()->Styles()->HasStyle(style)) 236 style = NULL; 237 238 fStyleView->SetStyle(style); 239 fPathListView->SetCurrentShape(NULL); 240 fStyleListView->SetCurrentShape(NULL); 241 fTransformerListView->SetShape(NULL); 242 243 fState->DeleteManipulators(); 244 Gradient* gradient = style ? style->Gradient() : NULL; 245 246 if (gradient) { 247 TransformGradientBox* transformBox 248 = new (nothrow) TransformGradientBox(fCanvasView, 249 gradient, 250 NULL); 251 fState->AddManipulator(transformBox); 252 } 253 break; 254 } 255 case MSG_SHAPE_SELECTED: { 256 Shape* shape; 257 if (message->FindPointer("shape", (void**)&shape) < B_OK) 258 shape = NULL; 259 if (!fIcon || !fIcon->Shapes()->HasShape(shape)) 260 shape = NULL; 261 262 fPathListView->SetCurrentShape(shape); 263 fStyleListView->SetCurrentShape(shape); 264 fTransformerListView->SetShape(shape); 265 266 BList selectedShapes; 267 ShapeContainer* shapes = fDocument->Icon()->Shapes(); 268 int32 count = shapes->CountShapes(); 269 for (int32 i = 0; i < count; i++) { 270 shape = shapes->ShapeAtFast(i); 271 if (shape->IsSelected()) { 272 selectedShapes.AddItem((void*)shape); 273 } 274 } 275 276 fState->DeleteManipulators(); 277 if (selectedShapes.CountItems() > 0) { 278 TransformShapesBox* transformBox = new (nothrow) TransformShapesBox( 279 fCanvasView, 280 (const Shape**)selectedShapes.Items(), 281 selectedShapes.CountItems()); 282 fState->AddManipulator(transformBox); 283 } 284 break; 285 } 286 default: 287 BWindow::MessageReceived(message); 288 } 289 290 fDocument->WriteUnlock(); 291 } 292 293 // QuitRequested 294 bool 295 MainWindow::QuitRequested() 296 { 297 // forward this to app but return "false" in order 298 // to have a single code path for quitting 299 be_app->PostMessage(B_QUIT_REQUESTED); 300 301 return false; 302 } 303 304 // WorkspaceActivated 305 void 306 MainWindow::WorkspaceActivated(int32 workspace, bool active) 307 { 308 BWindow::WorkspaceActivated(workspace, active); 309 310 // NOTE: hack to workaround buggy BScreen::DesktopColor() on R5 311 312 uint32 workspaces = Workspaces(); 313 if (!active || ((1 << workspace) & workspaces) == 0) 314 return; 315 316 WorkspacesChanged(workspaces, workspaces); 317 } 318 319 // WorkspacesChanged 320 void 321 MainWindow::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces) 322 { 323 if (oldWorkspaces != newWorkspaces) 324 BWindow::WorkspacesChanged(oldWorkspaces, newWorkspaces); 325 326 BScreen screen(this); 327 328 // Unfortunately, this is buggy on R5: screen.DesktopColor() 329 // as well as ui_color(B_DESKTOP_COLOR) return the color 330 // of the *active* screen, not the one on which this window 331 // is. So this trick only works when you drag this window 332 // from another workspace onto the current workspace, not 333 // when you drag the window from the current workspace onto 334 // another workspace and then switch to the other workspace. 335 336 fIconPreview32Desktop->SetIconBGColor(screen.DesktopColor()); 337 fIconPreview64->SetIconBGColor(screen.DesktopColor()); 338 } 339 340 // #pragma mark - 341 342 // ObjectChanged 343 void 344 MainWindow::ObjectChanged(const Observable* object) 345 { 346 if (!fDocument) 347 return; 348 349 if (!Lock()) 350 return; 351 352 if (object == fDocument->CommandStack()) { 353 // relable Undo item and update enabled status 354 BString label("Undo"); 355 fUndoMI->SetEnabled(fDocument->CommandStack()->GetUndoName(label)); 356 if (fUndoMI->IsEnabled()) 357 fUndoMI->SetLabel(label.String()); 358 else 359 fUndoMI->SetLabel("<nothing to undo>"); 360 361 // relable Redo item and update enabled status 362 label.SetTo("Redo"); 363 fRedoMI->SetEnabled(fDocument->CommandStack()->GetRedoName(label)); 364 if (fRedoMI->IsEnabled()) 365 fRedoMI->SetLabel(label.String()); 366 else 367 fRedoMI->SetLabel("<nothing to redo>"); 368 } 369 370 Unlock(); 371 } 372 373 // #pragma mark - 374 375 // MakeEmpty 376 void 377 MainWindow::MakeEmpty() 378 { 379 fPathListView->SetCurrentShape(NULL); 380 fStyleListView->SetCurrentShape(NULL); 381 fStyleView->SetStyle(NULL); 382 383 fTransformerListView->SetShape(NULL); 384 385 fState->DeleteManipulators(); 386 } 387 388 // SetIcon 389 void 390 MainWindow::SetIcon(Icon* icon) 391 { 392 if (fIcon == icon) 393 return; 394 395 Icon* oldIcon = fIcon; 396 397 fIcon = icon; 398 399 if (fIcon) 400 fIcon->Acquire(); 401 else 402 MakeEmpty(); 403 404 fCanvasView->SetIcon(fIcon); 405 406 fPathListView->SetPathContainer(fIcon ? fIcon->Paths() : NULL); 407 fPathListView->SetShapeContainer(fIcon ? fIcon->Shapes() : NULL); 408 409 fStyleListView->SetStyleContainer(fIcon ? fIcon->Styles() : NULL); 410 fStyleListView->SetShapeContainer(fIcon ? fIcon->Shapes() : NULL); 411 412 fShapeListView->SetShapeContainer(fIcon ? fIcon->Shapes() : NULL); 413 414 // icon previews 415 fIconPreview16Folder->SetIcon(fIcon); 416 fIconPreview16Menu->SetIcon(fIcon); 417 fIconPreview32Folder->SetIcon(fIcon); 418 fIconPreview32Desktop->SetIcon(fIcon); 419 // fIconPreview48->SetIcon(fIcon); 420 fIconPreview64->SetIcon(fIcon); 421 422 // keep this last 423 if (oldIcon) 424 oldIcon->Release(); 425 } 426 427 // #pragma mark - 428 429 // StoreSettings 430 void 431 MainWindow::StoreSettings(BMessage* archive) 432 { 433 if (archive->ReplaceRect("main window frame", Frame()) < B_OK) 434 archive->AddRect("main window frame", Frame()); 435 } 436 437 // RestoreSettings 438 void 439 MainWindow::RestoreSettings(const BMessage* archive) 440 { 441 BRect frame; 442 if (archive->FindRect("main window frame", &frame) == B_OK) { 443 make_sure_frame_is_on_screen(frame, this); 444 MoveTo(frame.LeftTop()); 445 ResizeTo(frame.Width(), frame.Height()); 446 } 447 } 448 449 // #pragma mark - 450 451 // _Init 452 void 453 MainWindow::_Init() 454 { 455 // create the GUI 456 _CreateGUI(Bounds()); 457 458 // fix up scrollbar layout in listviews 459 _ImproveScrollBarLayout(fPathListView); 460 _ImproveScrollBarLayout(fStyleListView); 461 _ImproveScrollBarLayout(fShapeListView); 462 _ImproveScrollBarLayout(fTransformerListView); 463 464 // TODO: move this to CanvasView? 465 fState = new MultipleManipulatorState(fCanvasView); 466 fCanvasView->SetState(fState); 467 468 fCanvasView->SetCatchAllEvents(true); 469 fCanvasView->SetCommandStack(fDocument->CommandStack()); 470 // fCanvasView->SetSelection(fDocument->Selection()); 471 472 fPathListView->SetMenu(fPathMenu); 473 fPathListView->SetCommandStack(fDocument->CommandStack()); 474 fPathListView->SetSelection(fDocument->Selection()); 475 476 fStyleListView->SetMenu(fStyleMenu); 477 fStyleListView->SetCommandStack(fDocument->CommandStack()); 478 fStyleListView->SetSelection(fDocument->Selection()); 479 480 fStyleView->SetCommandStack(fDocument->CommandStack()); 481 fStyleView->SetCurrentColor(CurrentColor::Default()); 482 483 fShapeListView->SetMenu(fShapeMenu); 484 fShapeListView->SetCommandStack(fDocument->CommandStack()); 485 fShapeListView->SetSelection(fDocument->Selection()); 486 487 fTransformerListView->SetMenu(fTransformerMenu); 488 fTransformerListView->SetCommandStack(fDocument->CommandStack()); 489 fTransformerListView->SetSelection(fDocument->Selection()); 490 491 fPropertyListView->SetCommandStack(fDocument->CommandStack()); 492 fPropertyListView->SetSelection(fDocument->Selection()); 493 fPropertyListView->SetMenu(fPropertyMenu); 494 495 fDocument->CommandStack()->AddObserver(this); 496 497 fSwatchGroup->SetCurrentColor(CurrentColor::Default()); 498 499 SetIcon(fDocument->Icon()); 500 501 AddShortcut('Y', 0, new BMessage(MSG_UNDO)); 502 AddShortcut('Y', B_SHIFT_KEY, new BMessage(MSG_REDO)); 503 } 504 505 // _CreateGUI 506 void 507 MainWindow::_CreateGUI(BRect bounds) 508 { 509 const float splitWidth = 13 * be_plain_font->Size(); 510 511 #ifdef __HAIKU__ 512 513 SetLayout(new BGroupLayout(B_HORIZONTAL)); 514 515 BGridLayout* layout = new BGridLayout(); 516 BView* rootView = new BView("root view", 0, layout); 517 AddChild(rootView); 518 rootView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 519 520 BGroupView* leftTopView = new BGroupView(B_VERTICAL); 521 layout->AddView(leftTopView, 0, 0); 522 leftTopView->SetExplicitMinSize(BSize(splitWidth, B_SIZE_UNSET)); 523 524 // views along the left side 525 leftTopView->AddChild(_CreateMenuBar(bounds)); 526 527 BGroupView* iconPreviews = new BGroupView(B_HORIZONTAL); 528 iconPreviews->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 529 iconPreviews->GroupLayout()->SetSpacing(5); 530 531 // icon previews 532 fIconPreview16Folder = new IconView(BRect(0, 0, 15, 15), 533 "icon preview 16 folder"); 534 fIconPreview16Menu = new IconView(BRect(0, 0, 15, 15), 535 "icon preview 16 menu"); 536 fIconPreview16Menu->SetLowColor(ui_color(B_MENU_BACKGROUND_COLOR)); 537 538 fIconPreview32Folder = new IconView(BRect(0, 0, 31, 31), 539 "icon preview 32 folder"); 540 fIconPreview32Desktop = new IconView(BRect(0, 0, 31, 31), 541 "icon preview 32 desktop"); 542 fIconPreview32Desktop->SetLowColor(ui_color(B_DESKTOP_COLOR)); 543 544 // fIconPreview48 = new IconView(bounds, "icon preview 48"); 545 fIconPreview64 = new IconView(BRect(0, 0, 63, 63), "icon preview 64"); 546 fIconPreview64->SetLowColor(ui_color(B_DESKTOP_COLOR)); 547 548 549 BGroupView* smallPreviews = new BGroupView(B_VERTICAL); 550 smallPreviews->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 551 smallPreviews->GroupLayout()->SetSpacing(5); 552 553 smallPreviews->AddChild(fIconPreview16Folder); 554 smallPreviews->AddChild(fIconPreview16Menu); 555 556 BGroupView* mediumPreviews = new BGroupView(B_VERTICAL); 557 mediumPreviews->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 558 mediumPreviews->GroupLayout()->SetSpacing(5); 559 560 mediumPreviews->AddChild(fIconPreview32Folder); 561 mediumPreviews->AddChild(fIconPreview32Desktop); 562 563 // iconPreviews->AddChild(fIconPreview48); 564 565 iconPreviews->AddChild(smallPreviews); 566 iconPreviews->AddChild(mediumPreviews); 567 iconPreviews->AddChild(fIconPreview64); 568 iconPreviews->SetExplicitMaxSize(BSize(B_SIZE_UNSET, B_SIZE_UNLIMITED)); 569 570 leftTopView->AddChild(iconPreviews); 571 572 573 BGroupView* leftSideView = new BGroupView(B_VERTICAL); 574 layout->AddView(leftSideView, 0, 1); 575 leftSideView->SetExplicitMinSize(BSize(splitWidth, B_SIZE_UNSET)); 576 577 // path menu and list view 578 BMenuBar* menuBar = new BMenuBar(bounds, "path menu bar"); 579 menuBar->AddItem(fPathMenu); 580 leftSideView->AddChild(menuBar); 581 582 fPathListView = new PathListView(BRect(0, 0, splitWidth, 100), 583 "path list view", 584 new BMessage(MSG_PATH_SELECTED), this); 585 586 BView* scrollView = new BScrollView("path list scroll view", 587 fPathListView, 588 B_FOLLOW_NONE, 0, false, true, 589 B_NO_BORDER); 590 leftSideView->AddChild(scrollView); 591 592 // shape list view 593 menuBar = new BMenuBar(bounds, "shape menu bar"); 594 menuBar->AddItem(fShapeMenu); 595 leftSideView->AddChild(menuBar); 596 597 fShapeListView = new ShapeListView(BRect(0, 0, splitWidth, 100), 598 "shape list view", 599 new BMessage(MSG_SHAPE_SELECTED), this); 600 scrollView = new BScrollView("shape list scroll view", 601 fShapeListView, 602 B_FOLLOW_NONE, 0, false, true, 603 B_NO_BORDER); 604 leftSideView->AddChild(scrollView); 605 606 // transformer list view 607 menuBar = new BMenuBar(bounds, "transformer menu bar"); 608 menuBar->AddItem(fTransformerMenu); 609 leftSideView->AddChild(menuBar); 610 611 fTransformerListView = new TransformerListView(BRect(0, 0, splitWidth, 100), 612 "transformer list view"); 613 scrollView = new BScrollView("transformer list scroll view", 614 fTransformerListView, 615 B_FOLLOW_NONE, 0, false, true, 616 B_NO_BORDER); 617 leftSideView->AddChild(scrollView); 618 619 // property list view 620 menuBar = new BMenuBar(bounds, "property menu bar"); 621 menuBar->AddItem(fPropertyMenu); 622 leftSideView->AddChild(menuBar); 623 624 fPropertyListView = new IconObjectListView(); 625 626 // scroll view around property list view 627 ScrollView* propScrollView = new ScrollView(fPropertyListView, 628 SCROLL_VERTICAL, BRect(0, 0, splitWidth, 100), "property scroll view", 629 B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER, 630 BORDER_RIGHT); 631 leftSideView->AddChild(propScrollView); 632 633 BGroupLayout* topSide = new BGroupLayout(B_HORIZONTAL); 634 BView* topSideView = new BView("top side view", 0, topSide); 635 layout->AddView(topSideView, 1, 0); 636 637 // canvas view 638 BRect canvasBounds = BRect(0, 0, 200, 200); 639 fCanvasView = new CanvasView(canvasBounds); 640 641 // scroll view around canvas view 642 canvasBounds.bottom += B_H_SCROLL_BAR_HEIGHT; 643 canvasBounds.right += B_V_SCROLL_BAR_WIDTH; 644 ScrollView* canvasScrollView 645 = new ScrollView(fCanvasView, SCROLL_VERTICAL | SCROLL_HORIZONTAL 646 | SCROLL_VISIBLE_RECT_IS_CHILD_BOUNDS, 647 canvasBounds, "canvas scroll view", 648 B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS, B_NO_BORDER); 649 layout->AddView(canvasScrollView, 1, 1); 650 651 // views along the top 652 653 BGroupLayout* styleGroup = new BGroupLayout(B_VERTICAL); 654 BView* styleGroupView = new BView("style group", 0, styleGroup); 655 topSide->AddView(styleGroupView); 656 657 // style list view 658 menuBar = new BMenuBar(bounds, "style menu bar"); 659 menuBar->AddItem(fStyleMenu); 660 styleGroup->AddView(menuBar); 661 662 fStyleListView = new StyleListView(BRect(0, 0, splitWidth, 100), 663 "style list view", 664 new BMessage(MSG_STYLE_SELECTED), this); 665 scrollView = new BScrollView("style list scroll view", 666 fStyleListView, 667 B_FOLLOW_NONE, 0, false, true, 668 B_NO_BORDER); 669 scrollView->SetExplicitMaxSize(BSize(splitWidth, B_SIZE_UNLIMITED)); 670 styleGroup->AddView(scrollView); 671 672 // style view 673 fStyleView = new StyleView(BRect(0, 0, 200, 100)); 674 topSide->AddView(fStyleView); 675 676 // swatch group 677 BGroupLayout* swatchGroup = new BGroupLayout(B_VERTICAL); 678 BView* swatchGroupView = new BView("swatch group", 0, swatchGroup); 679 topSide->AddView(swatchGroupView); 680 681 menuBar = new BMenuBar(bounds, "swatches menu bar"); 682 menuBar->AddItem(fSwatchMenu); 683 swatchGroup->AddView(menuBar); 684 685 fSwatchGroup = new SwatchGroup(BRect(0, 0, 100, 100)); 686 swatchGroup->AddView(fSwatchGroup); 687 688 swatchGroupView->SetExplicitMaxSize(swatchGroupView->MinSize()); 689 690 // make sure the top side has fixed height 691 topSideView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 692 swatchGroupView->MinSize().height)); 693 694 #else // !__HAIKU__ 695 696 BView* bg = new BView(bounds, "bg", B_FOLLOW_ALL, 0); 697 bg->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 698 AddChild(bg); 699 700 BRect menuFrame = bounds; 701 menuFrame.bottom = menuFrame.top + 15; 702 BMenuBar* menuBar = _CreateMenuBar(menuFrame); 703 bg->AddChild(menuBar); 704 float menuWidth; 705 float menuHeight; 706 menuBar->GetPreferredSize(&menuWidth, &menuHeight); 707 menuBar->ResizeTo(splitWidth - 1, menuHeight); 708 menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP); 709 710 bounds.top = menuBar->Frame().bottom + 1; 711 712 // swatch group 713 fSwatchGroup = new SwatchGroup(bounds); 714 // SwatchGroup auto resizes itself 715 fSwatchGroup->MoveTo(bounds.right - fSwatchGroup->Bounds().Width(), 716 bounds.top); 717 fSwatchGroup->SetResizingMode(B_FOLLOW_RIGHT | B_FOLLOW_TOP); 718 719 bounds.left = fSwatchGroup->Frame().left; 720 bounds.right = bg->Bounds().right; 721 bounds.top = bg->Bounds().top; 722 bounds.bottom = bounds.top + menuHeight; 723 menuBar = new BMenuBar(bounds, "swatches menu bar"); 724 menuBar->AddItem(fSwatchMenu); 725 bg->AddChild(menuBar); 726 menuBar->ResizeTo(bounds.Width(), menuHeight); 727 // menu bars resize themselves to window width 728 menuBar->SetResizingMode(B_FOLLOW_RIGHT | B_FOLLOW_TOP); 729 730 // canvas view 731 bounds.left = splitWidth; 732 bounds.top = fSwatchGroup->Frame().bottom + 1; 733 bounds.right = bg->Bounds().right - B_V_SCROLL_BAR_WIDTH; 734 bounds.bottom = bg->Bounds().bottom - B_H_SCROLL_BAR_HEIGHT; 735 fCanvasView = new CanvasView(bounds); 736 737 // scroll view around canvas view 738 bounds.bottom += B_H_SCROLL_BAR_HEIGHT; 739 bounds.right += B_V_SCROLL_BAR_WIDTH; 740 ScrollView* canvasScrollView 741 = new ScrollView(fCanvasView, SCROLL_HORIZONTAL | SCROLL_VERTICAL 742 | SCROLL_VISIBLE_RECT_IS_CHILD_BOUNDS, bounds, 743 "canvas scroll view", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, 744 B_NO_BORDER); 745 746 // icon previews 747 bounds.left = 5; 748 bounds.top = fSwatchGroup->Frame().top + 5; 749 bounds.right = bounds.left + 15; 750 bounds.bottom = bounds.top + 15; 751 fIconPreview16Folder = new IconView(bounds, "icon preview 16 folder"); 752 753 bounds.top = fIconPreview16Folder->Frame().bottom + 5; 754 bounds.bottom = bounds.top + 15; 755 fIconPreview16Menu = new IconView(bounds, "icon preview 16 menu"); 756 fIconPreview16Menu->SetLowColor(ui_color(B_MENU_BACKGROUND_COLOR)); 757 758 bounds.left = fIconPreview16Folder->Frame().right + 5; 759 bounds.top = fSwatchGroup->Frame().top + 5; 760 bounds.right = bounds.left + 31; 761 bounds.bottom = bounds.top + 31; 762 fIconPreview32Folder = new IconView(bounds, "icon preview 32 folder"); 763 764 bounds.top = fIconPreview32Folder->Frame().bottom + 5; 765 bounds.bottom = bounds.top + 31; 766 fIconPreview32Desktop = new IconView(bounds, "icon preview 32 desktop"); 767 fIconPreview32Desktop->SetLowColor(ui_color(B_DESKTOP_COLOR)); 768 769 // bounds.OffsetBy(bounds.Width() + 6, 0); 770 // bounds.right = bounds.left + 47; 771 // bounds.bottom = bounds.top + 47; 772 // fIconPreview48 = new IconView(bounds, "icon preview 48"); 773 774 bounds.left = fIconPreview32Folder->Frame().right + 5; 775 bounds.top = fSwatchGroup->Frame().top + 5; 776 bounds.right = bounds.left + 63; 777 bounds.bottom = bounds.top + 63; 778 fIconPreview64 = new IconView(bounds, "icon preview 64"); 779 fIconPreview64->SetLowColor(ui_color(B_DESKTOP_COLOR)); 780 781 // style list view 782 bounds.left = fCanvasView->Frame().left; 783 bounds.right = bounds.left + splitWidth; 784 bounds.top = bg->Bounds().top; 785 bounds.bottom = bounds.top + menuHeight; 786 menuBar = new BMenuBar(bounds, "style menu bar"); 787 menuBar->AddItem(fStyleMenu); 788 bg->AddChild(menuBar); 789 menuBar->ResizeTo(bounds.Width(), menuHeight); 790 // menu bars resize themselves to window width 791 menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP); 792 793 bounds.right -= B_V_SCROLL_BAR_WIDTH + 1; 794 bounds.top = menuBar->Frame().bottom + 1; 795 bounds.bottom = fCanvasView->Frame().top - 1; 796 797 fStyleListView = new StyleListView(bounds, "style list view", 798 new BMessage(MSG_STYLE_SELECTED), this); 799 800 801 // style view 802 bounds.left = menuBar->Frame().right + 1; 803 bounds.top = bg->Bounds().top; 804 bounds.right = fSwatchGroup->Frame().left - 1; 805 bounds.bottom = fCanvasView->Frame().top - 1; 806 fStyleView = new StyleView(bounds); 807 fStyleView->SetResizingMode(B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT); 808 bg->AddChild(fStyleView); 809 810 // path list view 811 bounds.left = 0; 812 bounds.right = fCanvasView->Frame().left - 1; 813 bounds.top = fCanvasView->Frame().top; 814 bounds.bottom = bounds.top + menuHeight; 815 menuBar = new BMenuBar(bounds, "path menu bar"); 816 menuBar->AddItem(fPathMenu); 817 bg->AddChild(menuBar); 818 menuBar->ResizeTo(bounds.Width(), menuHeight); 819 // menu bars resize themselves to window width 820 menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP); 821 822 bounds.right -= B_V_SCROLL_BAR_WIDTH + 1; 823 bounds.top = menuBar->Frame().bottom + 1; 824 bounds.bottom = bounds.top + 130; 825 826 fPathListView = new PathListView(bounds, "path list view", 827 new BMessage(MSG_PATH_SELECTED), this); 828 829 830 // shape list view 831 bounds.right += B_V_SCROLL_BAR_WIDTH + 1; 832 bounds.top = fPathListView->Frame().bottom + 1; 833 bounds.bottom = bounds.top + menuHeight; 834 menuBar = new BMenuBar(bounds, "shape menu bar"); 835 menuBar->AddItem(fShapeMenu); 836 bg->AddChild(menuBar); 837 menuBar->ResizeTo(bounds.Width(), menuHeight); 838 // menu bars resize themselves to window width 839 menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP); 840 841 bounds.right -= B_V_SCROLL_BAR_WIDTH + 1; 842 bounds.top = menuBar->Frame().bottom + 1; 843 bounds.bottom = bounds.top + 130; 844 845 fShapeListView = new ShapeListView(bounds, "shape list view", 846 new BMessage(MSG_SHAPE_SELECTED), this); 847 848 // transformer list view 849 bounds.right += B_V_SCROLL_BAR_WIDTH + 1; 850 bounds.top = fShapeListView->Frame().bottom + 1; 851 bounds.bottom = bounds.top + menuHeight; 852 menuBar = new BMenuBar(bounds, "transformer menu bar"); 853 menuBar->AddItem(fTransformerMenu); 854 bg->AddChild(menuBar); 855 menuBar->ResizeTo(bounds.Width(), bounds.Height()); 856 // menu bars resize themselves to window width 857 menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP); 858 859 bounds.right -= B_V_SCROLL_BAR_WIDTH + 1; 860 bounds.top = menuBar->Frame().bottom + 1; 861 bounds.bottom = bounds.top + 80; 862 fTransformerListView = new TransformerListView(bounds, 863 "transformer list view"); 864 865 // property list view 866 bounds.right += B_V_SCROLL_BAR_WIDTH + 1; 867 bounds.top = fTransformerListView->Frame().bottom + 1; 868 bounds.bottom = bounds.top + menuHeight; 869 menuBar = new BMenuBar(bounds, "property menu bar"); 870 menuBar->AddItem(fPropertyMenu); 871 bg->AddChild(menuBar); 872 menuBar->ResizeTo(bounds.Width(), bounds.Height()); 873 // menu bars resize themselves to window width 874 menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP); 875 876 fPropertyListView = new IconObjectListView(); 877 878 bg->AddChild(fSwatchGroup); 879 880 bg->AddChild(fIconPreview16Folder); 881 bg->AddChild(fIconPreview16Menu); 882 bg->AddChild(fIconPreview32Folder); 883 bg->AddChild(fIconPreview32Desktop); 884 // bg->AddChild(fIconPreview48); 885 bg->AddChild(fIconPreview64); 886 887 bg->AddChild(new BScrollView("path list scroll view", 888 fPathListView, 889 B_FOLLOW_LEFT | B_FOLLOW_TOP, 890 0, false, true, 891 B_NO_BORDER)); 892 bg->AddChild(new BScrollView("style list scroll view", 893 fStyleListView, 894 B_FOLLOW_LEFT | B_FOLLOW_TOP, 895 0, false, true, 896 B_NO_BORDER)); 897 bg->AddChild(new BScrollView("shape list scroll view", 898 fShapeListView, 899 B_FOLLOW_LEFT | B_FOLLOW_TOP, 900 0, false, true, 901 B_NO_BORDER)); 902 bg->AddChild(new BScrollView("transformer list scroll view", 903 fTransformerListView, 904 B_FOLLOW_LEFT | B_FOLLOW_TOP, 905 0, false, true, 906 B_NO_BORDER)); 907 908 // scroll view around property list view 909 bounds.top = menuBar->Frame().bottom + 1; 910 bounds.bottom = bg->Bounds().bottom; 911 bg->AddChild(new ScrollView(fPropertyListView, SCROLL_VERTICAL, 912 bounds, "property scroll view", B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, 913 B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER, BORDER_RIGHT)); 914 915 916 bg->AddChild(canvasScrollView); 917 #endif // __HAIKU__ 918 } 919 920 // _CreateMenuBar 921 BMenuBar* 922 MainWindow::_CreateMenuBar(BRect frame) 923 { 924 BMenuBar* menuBar = new BMenuBar(frame, "main menu"); 925 926 BMenu* fileMenu = new BMenu("File"); 927 BMenu* editMenu = new BMenu("Edit"); 928 BMenu* settingsMenu = new BMenu("Options"); 929 fPathMenu = new BMenu("Path"); 930 fStyleMenu = new BMenu("Style"); 931 fShapeMenu = new BMenu("Shape"); 932 fTransformerMenu = new BMenu("Transformer"); 933 fPropertyMenu = new BMenu("Property"); 934 fSwatchMenu = new BMenu("Swatches"); 935 936 menuBar->AddItem(fileMenu); 937 menuBar->AddItem(editMenu); 938 menuBar->AddItem(settingsMenu); 939 940 // File 941 fileMenu->AddItem(new BMenuItem("New", 942 new BMessage(MSG_NEW), 943 'N')); 944 fileMenu->AddItem(new BMenuItem("Open", 945 new BMessage(MSG_OPEN), 946 'O')); 947 fileMenu->AddItem(new BMenuItem("Append", 948 new BMessage(MSG_APPEND), 949 'O', B_SHIFT_KEY)); 950 fileMenu->AddSeparatorItem(); 951 fileMenu->AddItem(new BMenuItem("Save", 952 new BMessage(MSG_SAVE), 953 'S')); 954 fileMenu->AddItem(new BMenuItem("Save As", 955 new BMessage(MSG_SAVE_AS), 956 'S', B_SHIFT_KEY)); 957 fileMenu->AddSeparatorItem(); 958 fileMenu->AddItem(new BMenuItem("Export", 959 new BMessage(MSG_EXPORT), 960 'E')); 961 fileMenu->AddItem(new BMenuItem("Export As", 962 new BMessage(MSG_EXPORT_AS), 963 'E', B_SHIFT_KEY)); 964 fileMenu->AddSeparatorItem(); 965 fileMenu->AddItem(new BMenuItem("Quit", 966 new BMessage(B_QUIT_REQUESTED), 967 'Q')); 968 fileMenu->SetTargetForItems(be_app); 969 970 // Edit 971 fUndoMI = new BMenuItem("<nothing to undo>", 972 new BMessage(MSG_UNDO), 'Z'); 973 fRedoMI = new BMenuItem("<nothing to redo>", 974 new BMessage(MSG_REDO), 'Z', B_SHIFT_KEY); 975 976 fUndoMI->SetEnabled(false); 977 fRedoMI->SetEnabled(false); 978 979 editMenu->AddItem(fUndoMI); 980 editMenu->AddItem(fRedoMI); 981 982 // Settings 983 BMenu* filterModeMenu = new BMenu("Snap to Grid"); 984 BMessage* message = new BMessage(MSG_MOUSE_FILTER_MODE); 985 message->AddInt32("mode", SNAPPING_OFF); 986 filterModeMenu->AddItem(new BMenuItem("Off", message)); 987 988 message = new BMessage(MSG_MOUSE_FILTER_MODE); 989 message->AddInt32("mode", SNAPPING_64); 990 filterModeMenu->AddItem(new BMenuItem("64 x 64", message)); 991 992 message = new BMessage(MSG_MOUSE_FILTER_MODE); 993 message->AddInt32("mode", SNAPPING_32); 994 filterModeMenu->AddItem(new BMenuItem("32 x 32", message)); 995 996 message = new BMessage(MSG_MOUSE_FILTER_MODE); 997 message->AddInt32("mode", SNAPPING_16); 998 filterModeMenu->AddItem(new BMenuItem("16 x 16", message)); 999 1000 filterModeMenu->ItemAt(0)->SetMarked(true); 1001 filterModeMenu->SetRadioMode(true); 1002 1003 settingsMenu->AddItem(filterModeMenu); 1004 1005 return menuBar; 1006 } 1007 1008 //// _CreateDefaultIcon 1009 //void 1010 //MainWindow::_CreateDefaultIcon() 1011 //{ 1012 // // add some stuff to an empty document (NOTE: for testing only) 1013 // VectorPath* path = new VectorPath(); 1014 // 1015 // fDocument->Icon()->Paths()->AddPath(path); 1016 // 1017 // Style* style1 = new Style(); 1018 // style1->SetName("Style White"); 1019 // style1->SetColor((rgb_color){ 255, 255, 255, 255 }); 1020 // 1021 // fDocument->Icon()->Styles()->AddStyle(style1); 1022 // 1023 // Style* style2 = new Style(); 1024 // style2->SetName("Style Gradient"); 1025 // Gradient gradient(true); 1026 // gradient.AddColor((rgb_color){ 255, 211, 6, 255 }, 0.0); 1027 // gradient.AddColor((rgb_color){ 255, 238, 160, 255 }, 0.5); 1028 // gradient.AddColor((rgb_color){ 208, 43, 92, 255 }, 1.0); 1029 // style2->SetGradient(&gradient); 1030 // 1031 // fDocument->Icon()->Styles()->AddStyle(style2); 1032 // 1033 // Shape* shape = new Shape(style2); 1034 // shape->Paths()->AddPath(path); 1035 // 1036 // shape->SetName("Gradient"); 1037 // fDocument->Icon()->Shapes()->AddShape(shape); 1038 // 1039 // shape = new Shape(style1); 1040 // shape->Paths()->AddPath(path); 1041 // StrokeTransformer* transformer 1042 // = new StrokeTransformer(shape->VertexSource()); 1043 // transformer->width(5.0); 1044 // shape->AddTransformer(transformer); 1045 // 1046 // shape->SetName("Outline"); 1047 // fDocument->Icon()->Shapes()->AddShape(shape); 1048 // 1049 // Style* style3 = new Style(); 1050 // style3->SetName("Style Red"); 1051 // style3->SetColor((rgb_color){ 255, 0, 169,200 }); 1052 // 1053 // fDocument->Icon()->Styles()->AddStyle(style3); 1054 // 1055 // shape = new Shape(style3); 1056 // shape->Paths()->AddPath(path); 1057 // AffineTransformer* transformer2 1058 // = new AffineTransformer(shape->VertexSource()); 1059 // *transformer2 *= agg::trans_affine_translation(10.0, 6.0); 1060 // *transformer2 *= agg::trans_affine_rotation(0.2); 1061 // *transformer2 *= agg::trans_affine_scaling(0.8, 0.6); 1062 // shape->AddTransformer(transformer2); 1063 // 1064 // shape->SetName("Transformed"); 1065 // fDocument->Icon()->Shapes()->AddShape(shape); 1066 // 1067 // PathManipulator* pathManipulator = new PathManipulator(path); 1068 // fState->AddManipulator(pathManipulator); 1069 //} 1070 1071 // _ImproveScrollBarLayout 1072 void 1073 MainWindow::_ImproveScrollBarLayout(BView* target) 1074 { 1075 // NOTE: The BListViews for which this function is used 1076 // are directly below a BMenuBar. If the BScrollBar and 1077 // the BMenuBar share bottom/top border respectively, the 1078 // GUI looks a little more polished. This trick can be 1079 // removed if/when the BScrollViews are embedded in a 1080 // surounding border like in WonderBrush. 1081 1082 if (BScrollBar* scrollBar = target->ScrollBar(B_VERTICAL)) { 1083 scrollBar->MoveBy(0, -1); 1084 scrollBar->ResizeBy(0, 1); 1085 } 1086 } 1087