xref: /haiku/src/apps/icon-o-matic/MainWindow.cpp (revision 9ecf9d1c1d4888d341a6eac72112c72d1ae3a4cb)
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 <ScrollView.h>
19 
20 #include "AddPathsCommand.h"
21 #include "AddShapesCommand.h"
22 #include "AddStylesCommand.h"
23 #include "Document.h"
24 #include "CanvasView.h"
25 #include "CommandStack.h"
26 #include "CurrentColor.h"
27 #include "IconObjectListView.h"
28 #include "IconEditorApp.h"
29 #include "IconView.h"
30 #include "PathListView.h"
31 #include "ScrollView.h"
32 #include "ShapeListView.h"
33 #include "StyleListView.h"
34 #include "StyleView.h"
35 #include "SwatchGroup.h"
36 #include "TransformerFactory.h"
37 #include "TransformerListView.h"
38 #include "TransformShapesBox.h"
39 
40 // TODO: just for testing
41 #include "AffineTransformer.h"
42 #include "Gradient.h"
43 #include "Icon.h"
44 #include "MultipleManipulatorState.h"
45 #include "PathManipulator.h"
46 #include "Shape.h"
47 #include "ShapeContainer.h"
48 #include "ShapeListView.h"
49 #include "StrokeTransformer.h"
50 #include "Style.h"
51 #include "StyleManager.h"
52 #include "VectorPath.h"
53 
54 using std::nothrow;
55 
56 enum {
57 	MSG_UNDO						= 'undo',
58 	MSG_REDO						= 'redo',
59 
60 	MSG_NEW_PATH					= 'nwvp',
61 	MSG_PATH_SELECTED				= 'vpsl',
62 	MSG_NEW_STYLE					= 'nwst',
63 	MSG_STYLE_SELECTED				= 'stsl',
64 	MSG_NEW_SHAPE					= 'nwsp',
65 	MSG_SHAPE_SELECTED				= 'spsl',
66 
67 	MSG_ADD_TRANSFORMER				= 'adtr',
68 };
69 
70 // constructor
71 MainWindow::MainWindow(IconEditorApp* app, Document* document)
72 	: BWindow(BRect(50, 50, 900, 750), "Icon-O-Matic",
73 			  B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
74 			  B_ASYNCHRONOUS_CONTROLS),
75 	  fApp(app),
76 	  fDocument(document)
77 {
78 	_Init();
79 }
80 
81 // destructor
82 MainWindow::~MainWindow()
83 {
84 	delete fState;
85 
86 	fDocument->CommandStack()->RemoveObserver(this);
87 }
88 
89 // #pragma mark -
90 
91 // MessageReceived
92 void
93 MainWindow::MessageReceived(BMessage* message)
94 {
95 	if (!fDocument->WriteLock())
96 		return;
97 
98 	switch (message->what) {
99 
100 		case MSG_UNDO:
101 			fDocument->CommandStack()->Undo();
102 			break;
103 		case MSG_REDO:
104 			fDocument->CommandStack()->Redo();
105 			break;
106 
107 // TODO: listen to selection in CanvasView to add a manipulator
108 case MSG_NEW_PATH: {
109 	VectorPath* path = new (nothrow) VectorPath();
110 	VectorPath* paths[1];
111 	paths[0] = path;
112 	PathContainer* container = fDocument->Icon()->Paths();
113 	AddPathsCommand* command = new (nothrow) AddPathsCommand(
114 		container, paths, 1, true,
115 		container->CountPaths());
116 	fDocument->CommandStack()->Perform(command);
117 	break;
118 }
119 case MSG_PATH_SELECTED: {
120 	VectorPath* path;
121 	if (message->FindPointer("path", (void**)&path) < B_OK)
122 		path = NULL;
123 
124 	fState->DeleteManipulators();
125 	if (path) {
126 		PathManipulator* pathManipulator = new (nothrow) PathManipulator(path);
127 		fState->AddManipulator(pathManipulator);
128 	}
129 	break;
130 }
131 case MSG_NEW_STYLE: {
132 	Style* style = new (nothrow) Style();
133 	if (style) {
134 		style->SetColor((rgb_color){ rand() % 255,
135 									 rand() % 255,
136 									 rand() % 255,
137 									 255 });
138 		Style* styles[1];
139 		styles[0] = style;
140 		StyleManager* container = StyleManager::Default();
141 		AddStylesCommand* command = new (nothrow) AddStylesCommand(
142 			container, styles, 1,
143 			container->CountStyles());
144 		fDocument->CommandStack()->Perform(command);
145 	}
146 	break;
147 }
148 case MSG_STYLE_SELECTED: {
149 	Style* style;
150 	if (message->FindPointer("style", (void**)&style) < B_OK)
151 		style = NULL;
152 	fStyleView->SetStyle(style);
153 	break;
154 }
155 case MSG_NEW_SHAPE: {
156 	Shape* shape = new (nothrow) Shape(StyleManager::Default()->StyleAt(0));
157 	Shape* shapes[1];
158 	shapes[0] = shape;
159 	AddShapesCommand* command = new (nothrow) AddShapesCommand(
160 		fDocument->Icon()->Shapes(), shapes, 1,
161 		fDocument->Icon()->Shapes()->CountShapes());
162 	fDocument->CommandStack()->Perform(command);
163 	break;
164 }
165 case MSG_SHAPE_SELECTED: {
166 	Shape* shape;
167 	if (message->FindPointer("shape", (void**)&shape) < B_OK)
168 		shape = NULL;
169 	fPathListView->SetCurrentShape(shape);
170 	fStyleListView->SetCurrentShape(shape);
171 	fTransformerListView->SetShape(shape);
172 
173 	BList selectedShapes;
174 	ShapeContainer* shapes = fDocument->Icon()->Shapes();
175 	int32 count = shapes->CountShapes();
176 	for (int32 i = 0; i < count; i++) {
177 		shape = shapes->ShapeAtFast(i);
178 		if (shape->IsSelected()) {
179 			selectedShapes.AddItem((void*)shape);
180 		}
181 	}
182 
183 	if (selectedShapes.CountItems() > 0) {
184 		TransformShapesBox* transformBox = new (nothrow) TransformShapesBox(
185 			fCanvasView,
186 			(const Shape**)selectedShapes.Items(),
187 			selectedShapes.CountItems());
188 		fState->DeleteManipulators();
189 		fState->AddManipulator(transformBox);
190 	}
191 	break;
192 }
193 
194 		case MSG_ADD_TRANSFORMER: {
195 			Shape* shape = fPathListView->CurrentShape();
196 			if (!shape)
197 				break;
198 
199 			uint32 type;
200 			if (message->FindInt32("type", (int32*)&type) < B_OK)
201 				break;
202 
203 			Transformer* transformer
204 				= TransformerFactory::TransformerFor(type,
205 													 shape->VertexSource());
206 			// TODO: command
207 			if (transformer)
208 				shape->AddTransformer(transformer);
209 			break;
210 		}
211 
212 		default:
213 			BWindow::MessageReceived(message);
214 	}
215 
216 	fDocument->WriteUnlock();
217 }
218 
219 // QuitRequested
220 bool
221 MainWindow::QuitRequested()
222 {
223 	// forward this to app but return "false" in order
224 	// to have a single code path for quitting
225 	be_app->PostMessage(B_QUIT_REQUESTED);
226 
227 	return false;
228 }
229 
230 // #pragma mark -
231 // ObjectChanged
232 void
233 MainWindow::ObjectChanged(const Observable* object)
234 {
235 	if (!fDocument)
236 		return;
237 
238 	if (!Lock())
239 		return;
240 
241 	if (object == fDocument->CommandStack()) {
242 		// relable Undo item and update enabled status
243 		BString label("Undo");
244 		fUndoMI->SetEnabled(fDocument->CommandStack()->GetUndoName(label));
245 		if (fUndoMI->IsEnabled())
246 			fUndoMI->SetLabel(label.String());
247 		else
248 			fUndoMI->SetLabel("<nothing to undo>");
249 
250 		// relable Redo item and update enabled status
251 		label.SetTo("Redo");
252 		fRedoMI->SetEnabled(fDocument->CommandStack()->GetRedoName(label));
253 		if (fRedoMI->IsEnabled())
254 			fRedoMI->SetLabel(label.String());
255 		else
256 			fRedoMI->SetLabel("<nothing to redo>");
257 	}
258 
259 	Unlock();
260 }
261 
262 // #pragma mark -
263 
264 // _Init
265 void
266 MainWindow::_Init()
267 {
268 	// create the GUI
269 	_CreateGUI(Bounds());
270 
271 	fCanvasView->SetCatchAllEvents(true);
272 	fCanvasView->SetCommandStack(fDocument->CommandStack());
273 //	fCanvasView->SetSelection(fDocument->Selection());
274 	fCanvasView->SetIcon(fDocument->Icon());
275 
276 	fPathListView->SetPathContainer(fDocument->Icon()->Paths());
277 	fPathListView->SetShapeContainer(fDocument->Icon()->Shapes());
278 	fPathListView->SetCommandStack(fDocument->CommandStack());
279 	fPathListView->SetSelection(fDocument->Selection());
280 
281 	fStyleListView->SetStyleManager(StyleManager::Default());
282 	fStyleListView->SetShapeContainer(fDocument->Icon()->Shapes());
283 //	fStyleListView->SetCommandStack(fDocument->CommandStack());
284 	fStyleListView->SetSelection(fDocument->Selection());
285 
286 	fStyleView->SetCommandStack(fDocument->CommandStack());
287 	fStyleView->SetCurrentColor(CurrentColor::Default());
288 
289 	fShapeListView->SetShapeContainer(fDocument->Icon()->Shapes());
290 	fShapeListView->SetCommandStack(fDocument->CommandStack());
291 	fShapeListView->SetSelection(fDocument->Selection());
292 
293 	fTransformerListView->SetCommandStack(fDocument->CommandStack());
294 	fTransformerListView->SetSelection(fDocument->Selection());
295 
296 	fPropertyListView->SetCommandStack(fDocument->CommandStack());
297 	fPropertyListView->SetSelection(fDocument->Selection());
298 	fPropertyListView->SetMenu(fPropertyMenu);
299 
300 	fIconPreview16->SetIcon(fDocument->Icon());
301 	fIconPreview32->SetIcon(fDocument->Icon());
302 //	fIconPreview48->SetIcon(fDocument->Icon());
303 	fIconPreview64->SetIcon(fDocument->Icon());
304 
305 	fDocument->CommandStack()->AddObserver(this);
306 
307 	fSwatchGroup->SetCurrentColor(CurrentColor::Default());
308 
309 // TODO: for testing only:
310 	MultipleManipulatorState* state = new MultipleManipulatorState(fCanvasView);
311 	fCanvasView->SetState(state);
312 
313 	VectorPath* path = new VectorPath();
314 
315 	fDocument->Icon()->Paths()->AddPath(path);
316 
317 	Style* style1 = new Style();
318 	style1->SetName("Style White");
319 	style1->SetColor((rgb_color){ 255, 255, 255, 255 });
320 
321 	StyleManager::Default()->AddStyle(style1);
322 
323 	Style* style2 = new Style();
324 	style2->SetName("Style Gradient");
325 	Gradient gradient(true);
326 	gradient.AddColor((rgb_color){ 255, 211, 6, 255 }, 0.0);
327 	gradient.AddColor((rgb_color){ 255, 238, 160, 255 }, 0.5);
328 	gradient.AddColor((rgb_color){ 208, 43, 92, 255 }, 1.0);
329 	style2->SetGradient(&gradient);
330 
331 	StyleManager::Default()->AddStyle(style2);
332 
333 	Shape* shape = new Shape(style2);
334 	shape->Paths()->AddPath(path);
335 
336 	shape->SetName("Gradient");
337 	fDocument->Icon()->Shapes()->AddShape(shape);
338 
339 	shape = new Shape(style1);
340 	shape->Paths()->AddPath(path);
341 	StrokeTransformer* transformer
342 		= new StrokeTransformer(shape->VertexSource());
343 	transformer->width(5.0);
344 	shape->AddTransformer(transformer);
345 
346 	shape->SetName("Outline");
347 	fDocument->Icon()->Shapes()->AddShape(shape);
348 
349 	Style* style3 = new Style();
350 	style3->SetName("Style Red");
351 	style3->SetColor((rgb_color){ 255, 0, 169,200 });
352 
353 	StyleManager::Default()->AddStyle(style3);
354 
355 	shape = new Shape(style3);
356 	shape->Paths()->AddPath(path);
357 	AffineTransformer* transformer2
358 		= new AffineTransformer(shape->VertexSource());
359 	*transformer2 *= agg::trans_affine_translation(10.0, 6.0);
360 	*transformer2 *= agg::trans_affine_rotation(0.2);
361 	*transformer2 *= agg::trans_affine_scaling(0.8, 0.6);
362 	shape->AddTransformer(transformer2);
363 
364 	shape->SetName("Transformed");
365 	fDocument->Icon()->Shapes()->AddShape(shape);
366 
367 	PathManipulator* pathManipulator = new PathManipulator(path);
368 	state->AddManipulator(pathManipulator);
369 	fState = state;
370 // ----
371 }
372 
373 // _CreateGUI
374 void
375 MainWindow::_CreateGUI(BRect bounds)
376 {
377 	const float splitWidth = 150;
378 
379 	BView* bg = new BView(bounds, "bg", B_FOLLOW_ALL, 0);
380 	bg->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
381 	AddChild(bg);
382 
383 	BRect menuFrame = bounds;
384 	menuFrame.bottom = menuFrame.top + 15;
385 	BMenuBar* menuBar = _CreateMenuBar(menuFrame);
386 	bg->AddChild(menuBar);
387 	float menuWidth;
388 	float menuHeight;
389 	menuBar->GetPreferredSize(&menuWidth, &menuHeight);
390 	menuBar->ResizeTo(splitWidth - 1, menuHeight);
391 	menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP);
392 
393 	bounds.top = menuBar->Frame().bottom + 1;
394 
395 	// swatch group
396 	fSwatchGroup = new SwatchGroup(bounds);
397 		// SwatchGroup auto resizes itself
398 	fSwatchGroup->MoveTo(bounds.right - fSwatchGroup->Bounds().Width(),
399 						 bounds.top);
400 	fSwatchGroup->SetResizingMode(B_FOLLOW_RIGHT | B_FOLLOW_TOP);
401 
402 	bounds.left = fSwatchGroup->Frame().left;
403 	bounds.right = bg->Bounds().right;
404 	bounds.top = bg->Bounds().top;
405 	bounds.bottom = bounds.top + menuHeight;
406 	menuBar = new BMenuBar(bounds, "swatches menu bar");
407 	menuBar->AddItem(fSwatchMenu);
408 	bg->AddChild(menuBar);
409 	menuBar->ResizeTo(bounds.Width(), menuHeight);
410 		// menu bars resize themselves to window width
411 	menuBar->SetResizingMode(B_FOLLOW_RIGHT | B_FOLLOW_TOP);
412 
413 	// canvas view
414 	bounds.left = splitWidth;
415 	bounds.top = fSwatchGroup->Frame().bottom + 1;
416 	bounds.right = bg->Bounds().right;
417 	bounds.bottom = bg->Bounds().bottom;
418 	fCanvasView = new CanvasView(bounds);
419 
420 	// icon previews
421 	bounds.left = 5;
422 	bounds.top = fSwatchGroup->Frame().top + 5;
423 	bounds.right = bounds.left + 15;
424 	bounds.bottom = bounds.top + 15;
425 	fIconPreview16 = new IconView(bounds, "icon preview 16");
426 
427 	bounds.OffsetBy(bounds.Width() + 6, 0);
428 	bounds.right = bounds.left + 31;
429 	bounds.bottom = bounds.top + 31;
430 	fIconPreview32 = new IconView(bounds, "icon preview 32");
431 
432 //	bounds.OffsetBy(bounds.Width() + 6, 0);
433 //	bounds.right = bounds.left + 47;
434 //	bounds.bottom = bounds.top + 47;
435 //	fIconPreview48 = new IconView(bounds, "icon preview 48");
436 
437 	bounds.OffsetBy(bounds.Width() + 6, 0);
438 	bounds.right = bounds.left + 63;
439 	bounds.bottom = bounds.top + 63;
440 	fIconPreview64 = new IconView(bounds, "icon preview 64");
441 
442 	// style list view
443 	bounds.left = fCanvasView->Frame().left;
444 	bounds.right = bounds.left + splitWidth;
445 	bounds.top = bg->Bounds().top;
446 	bounds.bottom = bounds.top + menuHeight;
447 	menuBar = new BMenuBar(bounds, "style menu bar");
448 	menuBar->AddItem(fStyleMenu);
449 	bg->AddChild(menuBar);
450 	menuBar->ResizeTo(bounds.Width(), menuHeight);
451 		// menu bars resize themselves to window width
452 	menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP);
453 
454 	bounds.right -= B_V_SCROLL_BAR_WIDTH + 1;
455 	bounds.top = menuBar->Frame().bottom + 1;
456 	bounds.bottom = fCanvasView->Frame().top - 1;
457 
458 	fStyleListView = new StyleListView(bounds, "style list view",
459 									   new BMessage(MSG_STYLE_SELECTED), this);
460 
461 
462 	// style view
463 	bounds.left = menuBar->Frame().right + 1;
464 	bounds.top = bg->Bounds().top;
465 	bounds.right = fSwatchGroup->Frame().left - 1;
466 	bounds.bottom = fCanvasView->Frame().top - 1;
467 	fStyleView = new StyleView(bounds);
468 	bg->AddChild(fStyleView);
469 
470 	// path list view
471 	bounds.left = 0;
472 	bounds.right = fCanvasView->Frame().left - 1;
473 	bounds.top = fCanvasView->Frame().top;
474 	bounds.bottom = bounds.top + menuHeight;
475 	menuBar = new BMenuBar(bounds, "path menu bar");
476 	menuBar->AddItem(fPathMenu);
477 	bg->AddChild(menuBar);
478 	menuBar->ResizeTo(bounds.Width(), menuHeight);
479 		// menu bars resize themselves to window width
480 	menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP);
481 
482 	bounds.right -= B_V_SCROLL_BAR_WIDTH + 1;
483 	bounds.top = menuBar->Frame().bottom + 1;
484 	bounds.bottom = bounds.top + 130;
485 
486 	fPathListView = new PathListView(bounds, "path list view",
487 									 new BMessage(MSG_PATH_SELECTED), this);
488 
489 
490 	// shape list view
491 	bounds.right += B_V_SCROLL_BAR_WIDTH + 1;
492 	bounds.top = fPathListView->Frame().bottom + 1;
493 	bounds.bottom = bounds.top + menuHeight;
494 	menuBar = new BMenuBar(bounds, "shape menu bar");
495 	menuBar->AddItem(fShapeMenu);
496 	bg->AddChild(menuBar);
497 	menuBar->ResizeTo(bounds.Width(), menuHeight);
498 		// menu bars resize themselves to window width
499 	menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP);
500 
501 	bounds.right -= B_V_SCROLL_BAR_WIDTH + 1;
502 	bounds.top = menuBar->Frame().bottom + 1;
503 	bounds.bottom = bounds.top + 130;
504 
505 	fShapeListView = new ShapeListView(bounds, "shape list view",
506 									   new BMessage(MSG_SHAPE_SELECTED), this);
507 
508 	// transformer list view
509 	bounds.right += B_V_SCROLL_BAR_WIDTH + 1;
510 	bounds.top = fShapeListView->Frame().bottom + 1;
511 	bounds.bottom = bounds.top + menuHeight;
512 	menuBar = new BMenuBar(bounds, "transformer menu bar");
513 	menuBar->AddItem(fTransformerMenu);
514 	bg->AddChild(menuBar);
515 	menuBar->ResizeTo(bounds.Width(), bounds.Height());
516 		// menu bars resize themselves to window width
517 	menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP);
518 
519 	bounds.right -= B_V_SCROLL_BAR_WIDTH + 1;
520 	bounds.top = menuBar->Frame().bottom + 1;
521 	bounds.bottom = bounds.top + 80;
522 	fTransformerListView = new TransformerListView(bounds,
523 												   "transformer list view");
524 
525 	// property list view
526 	bounds.right += B_V_SCROLL_BAR_WIDTH + 1;
527 	bounds.top = fTransformerListView->Frame().bottom + 1;
528 	bounds.bottom = bounds.top + menuHeight;
529 	menuBar = new BMenuBar(bounds, "property menu bar");
530 	menuBar->AddItem(fPropertyMenu);
531 	bg->AddChild(menuBar);
532 	menuBar->ResizeTo(bounds.Width(), bounds.Height());
533 		// menu bars resize themselves to window width
534 	menuBar->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP);
535 
536 	fPropertyListView = new IconObjectListView();
537 
538 	bg->AddChild(fSwatchGroup);
539 
540 	bg->AddChild(fIconPreview16);
541 	bg->AddChild(fIconPreview32);
542 //	bg->AddChild(fIconPreview48);
543 	bg->AddChild(fIconPreview64);
544 
545 	bg->AddChild(new BScrollView("path list scroll view",
546 								 fPathListView,
547 								 B_FOLLOW_LEFT | B_FOLLOW_TOP,
548 								 0, false, true,
549 								 B_NO_BORDER));
550 	bg->AddChild(new BScrollView("style list scroll view",
551 								 fStyleListView,
552 								 B_FOLLOW_LEFT | B_FOLLOW_TOP,
553 								 0, false, true,
554 								 B_NO_BORDER));
555 	bg->AddChild(new BScrollView("shape list scroll view",
556 								 fShapeListView,
557 								 B_FOLLOW_LEFT | B_FOLLOW_TOP,
558 								 0, false, true,
559 								 B_NO_BORDER));
560 	bg->AddChild(new BScrollView("transformer list scroll view",
561 								 fTransformerListView,
562 								 B_FOLLOW_LEFT | B_FOLLOW_TOP,
563 								 0, false, true,
564 								 B_NO_BORDER));
565 
566 	// scroll view around property list view
567 	bounds.top = menuBar->Frame().bottom + 1;
568 	bounds.bottom = bg->Bounds().bottom;
569 	bg->AddChild(new ScrollView(fPropertyListView,
570 								SCROLL_VERTICAL | SCROLL_NO_FRAME,
571 								bounds, "property scroll view",
572 								B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
573 								B_WILL_DRAW | B_FRAME_EVENTS));
574 
575 
576 	bg->AddChild(fCanvasView);
577 }
578 
579 // _CreateMenuBar
580 BMenuBar*
581 MainWindow::_CreateMenuBar(BRect frame)
582 {
583 	BMenuBar* menuBar = new BMenuBar(frame, "main menu");
584 
585 	BMenu* fileMenu = new BMenu("File");
586 	BMenu* editMenu = new BMenu("Edit");
587 	fPathMenu = new BMenu("Path");
588 	fStyleMenu = new BMenu("Style");
589 	fShapeMenu = new BMenu("Shape");
590 	fTransformerMenu = new BMenu("Transformer");
591 	fPropertyMenu = new BMenu("Property");
592 	fSwatchMenu = new BMenu("Swatches");
593 
594 	menuBar->AddItem(fileMenu);
595 	menuBar->AddItem(editMenu);
596 
597 	// Edit
598 	fUndoMI = new BMenuItem("<nothing to undo>",
599 							new BMessage(MSG_UNDO), 'Z');
600 	fRedoMI = new BMenuItem("<nothing to redo>",
601 							new BMessage(MSG_REDO), 'Z', B_SHIFT_KEY);
602 
603 	fUndoMI->SetEnabled(false);
604 	fRedoMI->SetEnabled(false);
605 
606 	editMenu->AddItem(fUndoMI);
607 	editMenu->AddItem(fRedoMI);
608 
609 	// Path
610 	fPathMenu->AddItem(new BMenuItem("Add", new BMessage(MSG_NEW_PATH)));
611 
612 	// Style
613 	fStyleMenu->AddItem(new BMenuItem("Add", new BMessage(MSG_NEW_STYLE)));
614 
615 	// Shape
616 	fShapeMenu->AddItem(new BMenuItem("Add", new BMessage(MSG_NEW_SHAPE)));
617 
618 
619 	// Transformer
620 	BMenu* addMenu = new BMenu("Add");
621 	int32 cookie = 0;
622 	uint32 type;
623 	BString name;
624 	while (TransformerFactory::NextType(&cookie, &type, &name)) {
625 		BMessage* message = new BMessage(MSG_ADD_TRANSFORMER);
626 		message->AddInt32("type", type);
627 		addMenu->AddItem(new BMenuItem(name.String(), message));
628 	}
629 	addMenu->SetTargetForItems(this);
630 	fTransformerMenu->AddItem(addMenu);
631 
632 	return menuBar;
633 }
634 
635