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