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