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