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