1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4 
5 #include "uieditcontroller.h"
6 
7 #if VSTGUI_LIVE_EDITING
8 
9 #include "uieditview.h"
10 #include "uiattributescontroller.h"
11 #include "uibitmapscontroller.h"
12 #include "uicolorscontroller.h"
13 #include "uigradientscontroller.h"
14 #include "uieditmenucontroller.h"
15 #include "uifontscontroller.h"
16 #include "uigridcontroller.h"
17 #include "uitagscontroller.h"
18 #include "uitemplatecontroller.h"
19 #include "uiviewcreatecontroller.h"
20 #include "uiundomanager.h"
21 #include "uiactions.h"
22 #include "uiselection.h"
23 #include "uidialogcontroller.h"
24 #include "uitemplatesettingscontroller.h"
25 #include "uifocussettingscontroller.h"
26 #include "../uiattributes.h"
27 #include "../../lib/controls/coptionmenu.h"
28 #include "../../lib/controls/csegmentbutton.h"
29 #include "../../lib/controls/csearchtextedit.h"
30 #include "../../lib/animation/animations.h"
31 #include "../../lib/animation/timingfunctions.h"
32 #include "../../lib/cdropsource.h"
33 #include "../../lib/cgraphicspath.h"
34 #include "../../lib/coffscreencontext.h"
35 #include "../../lib/iviewlistener.h"
36 #include "../../lib/cvstguitimer.h"
37 
38 #include <sstream>
39 #include <algorithm>
40 #include <cassert>
41 #include <array>
42 
43 #if WINDOWS
44 #define snprintf _snprintf
45 #endif
46 
47 namespace VSTGUI {
48 
49 #ifdef HAVE_EDITORUIDESC_H
50 #include "editoruidesc.h"
51 #endif
52 
53 //----------------------------------------------------------------------------------------------------
54 class UIEditControllerDescription
55 {
56 public:
get() const57 	SharedPointer<UIDescription> get () const
58 	{
59 		if (uiDesc == nullptr)
60 		{
61 #ifdef HAVE_EDITORUIDESC_H
62 			Xml::MemoryContentProvider provider (editorUIDesc, strlen (editorUIDesc));
63 			SharedPointer<UIDescription> editorDesc = owned (new UIDescription (&provider));
64 			if (editorDesc->parse ())
65 			{
66 				uiDesc = editorDesc;
67 			}
68 #else
69 			std::string descPath (__FILE__);
70 			unixfyPath (descPath);
71 			if (removeLastPathComponent (descPath))
72 			{
73 				descPath += "/uidescriptioneditor.uidesc";
74 				auto editorDesc = makeOwned<UIDescription> (descPath.c_str ());
75 				if (editorDesc->parse ())
76 				{
77 					uiDesc = std::move (editorDesc);
78 				}
79 				else
80 				{
81 					vstgui_assert (false, "the __FILE__ macro is relative, so it's not possible to find the uidescriptioneditor.uidesc. You can replace the macro with the absolute filename to make this work on your devel machine");
82 				}
83 			}
84 #endif
85 		}
86 		return uiDesc;
87 	}
88 
tryFree()89 	void tryFree ()
90 	{
91 		if (uiDesc->getNbReference () == 1)
92 			uiDesc = nullptr;
93 	}
94 
95 private:
96 	mutable SharedPointer<UIDescription> uiDesc;
97 };
98 
99 static UIEditControllerDescription gUIDescription;
100 
101 //----------------------------------------------------------------------------------------------------
getEditorDescription()102 SharedPointer<UIDescription> UIEditController::getEditorDescription ()
103 {
104 	return gUIDescription.get ();
105 }
106 
107 //----------------------------------------------------------------------------------------------------
setupDataSource(GenericStringListDataBrowserSource * source)108 void UIEditController::setupDataSource (GenericStringListDataBrowserSource* source)
109 {
110 	static CColor selectionColor;
111 	static CColor fontColor;
112 	static CColor rowlineColor;
113 	static CColor rowBackColor;
114 	static CColor rowAlternateBackColor;
115 	static bool once = true;
116 	auto editorDescription = UIEditController::getEditorDescription ();
117 	if (once)
118 	{
119 		editorDescription->getColor ("db.selection", selectionColor);
120 		editorDescription->getColor ("db.font", fontColor);
121 		editorDescription->getColor ("db.row.line", rowlineColor);
122 		editorDescription->getColor ("db.row.back", rowBackColor);
123 		editorDescription->getColor ("db.row.alternate.back", rowAlternateBackColor);
124 		once = false;
125 	}
126 	CFontRef font = editorDescription->getFont ("db.font");
127 	source->setupUI (selectionColor, fontColor, rowlineColor, rowBackColor, rowAlternateBackColor, font);
128 }
129 
130 //-----------------------------------------------------------------------------
std__stringCompare(const std::string * lhs,const std::string * rhs)131 bool UIEditController::std__stringCompare (const std::string* lhs, const std::string* rhs)
132 {
133 	for (std::string::const_iterator it = lhs->begin (), it2 = rhs->begin (); it != lhs->end () && it2 != rhs->end (); it++, it2++)
134 	{
135 		char c1 = static_cast<char> (tolower (*it));
136 		char c2 = static_cast<char> (tolower (*it2));
137 		if (c1 != c2)
138 			return c1 < c2;
139 	}
140 	return false;
141 }
142 
143 const UTF8StringPtr UIEditController::kEncodeBitmapsSettingsKey = "EncodeBitmaps";
144 const UTF8StringPtr UIEditController::kWriteWindowsRCFileSettingsKey = "WriteRCFile";
145 
146 //----------------------------------------------------------------------------------------------------
147 class UIEditControllerShadingView : public CView
148 {
149 public:
UIEditControllerShadingView(bool horizontal,bool drawTopLine=false,bool drawBottomLine=true)150 	UIEditControllerShadingView (bool horizontal, bool drawTopLine = false, bool drawBottomLine = true)
151 	: CView (CRect (0, 0, 0, 0))
152 	, horizontal (horizontal)
153 	, drawTopLine (drawTopLine)
154 	, drawBottomLine (drawBottomLine)
155 	{}
156 
draw(CDrawContext * context)157 	void draw (CDrawContext* context) override
158 	{
159 		drawGradient (context, getViewSize (), horizontal, drawTopLine, drawBottomLine);
160 	}
161 
drawGradient(CDrawContext * context,const CRect & _size,bool horizontal,bool drawTopLine=true,bool drawBottomLine=true)162 	static void drawGradient (CDrawContext* context, const CRect& _size, bool horizontal, bool drawTopLine = true, bool drawBottomLine = true)
163 	{
164 		SharedPointer<CGraphicsPath> path = owned (context->createGraphicsPath ());
165 		if (path)
166 		{
167 			static CColor lineColor = kBlackCColor;
168 			if (lineColor == kBlackCColor)
169 				UIEditController::getEditorDescription ()->getColor ("shading.light.frame", lineColor);
170 
171 			auto lineWidth = 1.;
172 
173 			CRect size (_size);
174 			context->setDrawMode (kAliasing);
175 			context->setLineStyle (kLineSolid);
176 			context->setLineWidth (lineWidth);
177 			context->setFrameColor (lineColor);
178 
179 			CGradient* shading = UIEditController::getEditorDescription ()->getGradient ("shading.light");
180 			if (shading)
181 			{
182 				path->addRect (size);
183 				if (horizontal)
184 				{
185 					context->fillLinearGradient (path, *shading, CPoint (size.left, size.top), CPoint (size.right, size.top));
186 					if (drawBottomLine)
187 						context->drawLine (CPoint (size.left, size.top), CPoint (size.left, size.bottom));
188 					if (drawTopLine)
189 						context->drawLine (CPoint (size.right-lineWidth, size.bottom), CPoint (size.right-lineWidth, size.top));
190 				}
191 				else
192 				{
193 					context->fillLinearGradient (path, *shading, CPoint (size.left, size.top), CPoint (size.left, size.bottom));
194 					if (drawTopLine)
195 						context->drawLine (CPoint (size.left, size.top), CPoint (size.right, size.top));
196 					if (drawBottomLine)
197 						context->drawLine (CPoint (size.right, size.bottom-lineWidth), CPoint (size.left, size.bottom-lineWidth));
198 				}
199 			}
200 		}
201 	}
202 
203 protected:
204 	bool horizontal;
205 	bool drawTopLine;
206 	bool drawBottomLine;
207 };
208 
209 //----------------------------------------------------------------------------------------------------
210 class UIZoomSettingController : public IController,
211                                 public IContextMenuController2,
212                                 public ViewMouseListenerAdapter,
213                                 public ViewListenerAdapter,
214                                 public CBaseObject
215 {
216 public:
UIZoomSettingController(UIEditController * editController)217 	UIZoomSettingController (UIEditController* editController)
218 	: editController (editController)
219 	{}
220 
~UIZoomSettingController()221 	~UIZoomSettingController () noexcept override
222 	{
223 		if (zoomValueControl)
224 			viewWillDelete (zoomValueControl);
225 	}
226 
restoreSetting(const UIAttributes & attributes)227 	void restoreSetting (const UIAttributes& attributes)
228 	{
229 		double value;
230 		if (attributes.getDoubleAttribute ("EditViewScale", value))
231 		{
232 			if (zoomValueControl)
233 			{
234 				zoomValueControl->setValue (static_cast<float> (value) * 100.f);
235 				valueChanged (zoomValueControl);
236 			}
237 		}
238 	}
239 
storeSetting(UIAttributes & attributes) const240 	void storeSetting (UIAttributes& attributes) const
241 	{
242 		if (zoomValueControl)
243 			attributes.setDoubleAttribute ("EditViewScale", zoomValueControl->getValue () / 100.f);
244 	}
245 
increaseZoom()246 	void increaseZoom ()
247 	{
248 		if (!zoomValueControl)
249 			return;
250 		float add = 10.f;
251 		float current = zoomValueControl->getValue ();
252 		if (current >= 100.f)
253 			add = 50.f;
254 		updateZoom (current + add);
255 	}
256 
decreaseZoom()257 	void decreaseZoom ()
258 	{
259 		if (!zoomValueControl)
260 			return;
261 		float sub = 10.f;
262 		float current = zoomValueControl->getValue ();
263 		if (current >= 150.f)
264 			sub = 50.f;
265 		updateZoom (current - sub);
266 	}
267 
resetZoom()268 	void resetZoom ()
269 	{
270 		if (!zoomValueControl)
271 			return;
272 		updateZoom (100.f);
273 	}
274 
verifyView(CView * view,const UIAttributes & attributes,const IUIDescription * description)275 	CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override
276 	{
277 		if (!zoomValueControl)
278 		{
279 			zoomValueControl = dynamic_cast<CTextEdit*> (view);
280 			if (zoomValueControl)
281 			{
282 				zoomValueControl->setMin (50.f);
283 				zoomValueControl->setMax (1000.f);
284 				zoomValueControl->setStringToValueFunction ([] (UTF8StringPtr txt, float& result, CTextEdit*) {
285 					int32_t intValue = static_cast<int32_t> (strtol (txt, nullptr, 10));
286 					if (intValue > 0)
287 					{
288 						result = static_cast<float> (intValue);
289 						return true;
290 					}
291 
292 					return false;
293 				});
294 				zoomValueControl->setValueToStringFunction ([] (float value, char utf8String[256], CParamDisplay*) {
295 					snprintf (utf8String, 255, "%d %%", static_cast<uint32_t> (value));
296 					return true;
297 				});
298 				zoomValueControl->setValue (100.f);
299 				CFontRef font = description->getFont ("control.font");
300 				CColor fontColor = kWhiteCColor, frameColor = kBlackCColor, backColor = kBlackCColor;
301 				description->getColor ("control.font", fontColor);
302 				description->getColor ("control.frame", frameColor);
303 				description->getColor ("control.back", backColor);
304 				zoomValueControl->setFont (font);
305 				zoomValueControl->setFontColor (fontColor);
306 				zoomValueControl->setBackColor (backColor);
307 				zoomValueControl->setFrameColor (frameColor);
308 				zoomValueControl->setFrameWidth (-1);
309 				zoomValueControl->setTooltipText ("Editor Zoom");
310 				zoomValueControl->registerViewListener (this);
311 				zoomValueControl->registerViewMouseListener (this);
312 				zoomValueControl->setStyle (zoomValueControl->getStyle () | CTextEdit::kDoubleClickStyle);
313 			}
314 		}
315 		return view;
316 	}
317 
valueChanged(CControl * pControl)318 	void valueChanged (CControl* pControl) override
319 	{
320 		if (pControl == zoomValueControl)
321 			editController->onZoomChanged (pControl->getValue () / 100.f);
322 	}
323 
appendContextMenuItems(COptionMenu & contextMenu,CView * view,const CPoint & where)324 	void appendContextMenuItems (COptionMenu& contextMenu, CView* view, const CPoint& where) override
325 	{
326 		if (view == zoomValueControl)
327 		{
328 			for (auto i = 50; i <= 250; i += 25)
329 			{
330 				auto item = new CCommandMenuItem ("Zoom " + toString (i) + "%");
331 				item->setActions ([this, i] (CCommandMenuItem*) {
332 					updateZoom (static_cast<float> (i));
333 				});
334 				if (zoomValueControl->getValue () == static_cast<float> (i))
335 					item->setChecked (true);
336 				contextMenu.addEntry (item);
337 			}
338 		}
339 	}
340 
viewOnMouseDown(CView * view,CPoint pos,CButtonState buttons)341 	CMouseEventResult viewOnMouseDown (CView* view, CPoint pos, CButtonState buttons) override
342 	{
343 		vstgui_assert (view == zoomValueControl);
344 		if (buttons.isDoubleClick ())
345 			popupTimer = nullptr;
346 		else if (buttons.isLeftButton () && buttons.getModifierState () == 0)
347 		{
348 			popupTimer = makeOwned<CVSTGUITimer> ([this] (CVSTGUITimer*) {
349 				popupTimer = nullptr;
350 				auto menu = makeOwned<COptionMenu> ();
351 				menu->setStyle (COptionMenu::kPopupStyle | COptionMenu::kMultipleCheckStyle);
352 				appendContextMenuItems (*menu, zoomValueControl, CPoint ());
353 				menu->popup (zoomValueControl->getFrame (),
354 				             zoomValueControl->translateToGlobal (
355 				                 zoomValueControl->getViewSize ().getTopLeft ()));
356 			}, 250);
357 		}
358 		return kMouseEventNotHandled;
359 	}
360 
viewWillDelete(CView * view)361 	void viewWillDelete (CView* view) override
362 	{
363 		vstgui_assert (view == zoomValueControl);
364 		view->unregisterViewListener (this);
365 		view->unregisterViewMouseListener (this);
366 		zoomValueControl = nullptr;
367 	}
368 
369 private:
updateZoom(float newZoom)370 	void updateZoom (float newZoom)
371 	{
372 		if (zoomValueControl)
373 		{
374 			zoomValueControl->setValue (newZoom);
375 			valueChanged (zoomValueControl);
376 		}
377 	}
378 
379 	UIEditController* editController{nullptr};
380 	CTextEdit* zoomValueControl{nullptr};
381 	SharedPointer<CVSTGUITimer> popupTimer;
382 };
383 
384 //----------------------------------------------------------------------------------------------------
385 //----------------------------------------------------------------------------------------------------
386 //----------------------------------------------------------------------------------------------------
UIEditController(UIDescription * description)387 UIEditController::UIEditController (UIDescription* description)
388 : editDescription (description)
389 , selection (makeOwned<UISelection> ())
390 , undoManager (makeOwned<UIUndoManager> ())
391 , gridController (makeOwned<UIGridController> (this, description))
392 , editView (nullptr)
393 , templateController (nullptr)
394 , dirty (false)
395 {
396 	editorDesc = getEditorDescription ();
397 	undoManager->addDependency (this);
398 	editDescription->registerListener (this);
399 	menuController = new UIEditMenuController (this, selection, undoManager, editDescription, this);
400 	onTemplatesChanged ();
401 }
402 
403 //----------------------------------------------------------------------------------------------------
~UIEditController()404 UIEditController::~UIEditController ()
405 {
406 	if (templateController)
407 		templateController->removeDependency (this);
408 	undoManager->removeDependency (this);
409 	editDescription->unregisterListener (this);
410 	editorDesc = nullptr;
411 	gUIDescription.tryFree ();
412 }
413 
414 //----------------------------------------------------------------------------------------------------
createEditView()415 CView* UIEditController::createEditView ()
416 {
417 	if (editorDesc->parse ())
418 	{
419 		IController* controller = this;
420 		CView* view = editorDesc->createView ("view", controller);
421 		if (view)
422 		{
423 			view->setAttribute (kCViewControllerAttribute, controller);
424 			CRect r;
425 			if (getSettings ()->getRectAttribute ("EditorSize", r))
426 			{
427 				view->setViewSize (r);
428 				view->setMouseableArea (r);
429 			}
430 			return view;
431 		}
432 	}
433 	return nullptr;
434 }
435 
436 //----------------------------------------------------------------------------------------------------
createView(const UIAttributes & attributes,const IUIDescription * description)437 CView* UIEditController::createView (const UIAttributes& attributes, const IUIDescription* description)
438 {
439 	const std::string* name = attributes.getAttributeValue (IUIDescription::kCustomViewName);
440 	if (name)
441 	{
442 		if (*name == "UIEditView")
443 		{
444 			vstgui_assert (editView == nullptr);
445 			editView = new UIEditView (CRect (0, 0, 0, 0), editDescription);
446 			editView->setSelection (selection);
447 			editView->setUndoManager (undoManager);
448 			editView->setGrid (gridController);
449 			editView->setupColors (description);
450 			return editView;
451 		}
452 		else if (*name == "ShadingViewHorizontal")
453 		{
454 			return new UIEditControllerShadingView (true);
455 		}
456 		else if (*name == "ShadingViewVertical")
457 		{
458 			return new UIEditControllerShadingView (false);
459 		}
460 		else if (*name == "ShadingViewVerticalTopLine")
461 		{
462 			return new UIEditControllerShadingView (false, true, false);
463 		}
464 	}
465 	return nullptr;
466 }
467 
468 //----------------------------------------------------------------------------------------------------
onZoomChanged(double zoom)469 void UIEditController::onZoomChanged (double zoom)
470 {
471 	if (editView)
472 		editView->setScale (zoom);
473 	if (zoomSettingController)
474 		zoomSettingController->storeSetting (*getSettings ());
475 }
476 
477 enum {
478 	kNotSavedTag = 666,
479 	kEditingTag,
480 	kAutosizeTag,
481 	kBackgroundSelectTag,
482 	kTabSwitchTag = 123456
483 };
484 
485 //----------------------------------------------------------------------------------------------------
createColorBitmap(CPoint size,CColor color)486 static SharedPointer<CBitmap> createColorBitmap (CPoint size, CColor color)
487 {
488 	auto bitmap = makeOwned<CBitmap> (size);
489 	if (auto pixelAccessor = owned (CBitmapPixelAccess::create (bitmap)))
490 	{
491 		for (auto y = 0u; y < static_cast<uint32_t> (size.y); y++)
492 		{
493 			pixelAccessor->setPosition (0, y);
494 			for (auto x = 0u; x < static_cast<uint32_t> (size.x); ++x)
495 			{
496 				pixelAccessor->setColor (color);
497 				++(*pixelAccessor);
498 			}
499 		}
500 	}
501 
502 	return bitmap;
503 }
504 
505 //----------------------------------------------------------------------------------------------------
506 using BackgroundColors = std::array<CColor, 4>;
507 
editViewBackgroundColors()508 static const BackgroundColors& editViewBackgroundColors ()
509 {
510 	static const BackgroundColors colors = {{
511 		{230, 230, 230},
512 		{150, 150, 150},
513 		kWhiteCColor,
514 		kBlackCColor
515 	}};
516 	return colors;
517 }
518 
519 //----------------------------------------------------------------------------------------------------
verifyView(CView * view,const UIAttributes & attributes,const IUIDescription * description)520 CView* UIEditController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
521 {
522 	if (view == editView)
523 	{
524 		editView->setBackgroundColor (editViewBackgroundColors ()[0]);
525 		return view;
526 	}
527 	auto* splitView = dynamic_cast<CSplitView*>(view);
528 	if (splitView)
529 	{
530 		splitViews.emplace_back (splitView);
531 		if (splitViews.size () == 1)
532 		{
533 			CFontRef font = description->getFont ("control.font");
534 			CColor fontColor = kWhiteCColor, frameColor = kBlackCColor, backColor = kBlackCColor;
535 			description->getColor ("control.font", fontColor);
536 			description->getColor ("control.frame", frameColor);
537 			description->getColor ("control.back", backColor);
538 			auto gradient = description->getGradient ("Default TextButton Gradient");
539 			auto gradientHighlighted = description->getGradient ("Default TextButton Gradient Highlighted");
540 
541 			// Add Background Menu
542 			CRect backSelectRect (0., 0., 20. * editViewBackgroundColors ().size (), splitView->getSeparatorWidth ());
543 			backSelectRect.inset (2, 2);
544 			auto backSelectControl = new CSegmentButton (backSelectRect, this, kBackgroundSelectTag);
545 			backSelectControl->setGradient (gradient);
546 			backSelectControl->setGradientHighlighted (gradientHighlighted);
547 			backSelectControl->setFrameColor (frameColor);
548 			backSelectControl->setFrameWidth (-1.);
549 			backSelectControl->setRoundRadius (2.);
550 			auto bitmapSize = splitView->getSeparatorWidth () - 12;
551 			for (auto& color : editViewBackgroundColors ())
552 			{
553 				CSegmentButton::Segment segment {};
554 				segment.iconPosition = CDrawMethods::kIconCenterAbove;
555 				segment.icon = segment.iconHighlighted = createColorBitmap ({bitmapSize, bitmapSize}, color);
556 				backSelectControl->addSegment (std::move (segment));
557 			}
558 			backSelectControl->setTooltipText ("Editor Background Color");
559 			splitView->addViewToSeparator (0, backSelectControl);
560 
561 			// Add Title
562 			CTextLabel* label = new CTextLabel (CRect (0, 0, splitView->getWidth (), splitView->getSeparatorWidth ()), "Templates | View Hierarchy");
563 			label->setTransparency (true);
564 			label->setMouseEnabled (false);
565 			label->setFont (font);
566 			label->setFontColor (kBlackCColor);
567 			label->setAutosizeFlags (kAutosizeAll);
568 			splitView->addViewToSeparator (0, label);
569 
570 			// Add Scale Menu
571 			CRect scaleMenuRect (0, 0, 50, splitView->getSeparatorWidth ());
572 			scaleMenuRect.offset (splitView->getWidth ()-scaleMenuRect.getWidth (), 0);
573 			scaleMenuRect.inset (2, 2);
574 
575 			zoomSettingController = new UIZoomSettingController (this); // not owned, shared with control
576 			auto* textEdit = new CTextEdit (scaleMenuRect, zoomSettingController, 0);
577 			textEdit->setAttribute (kCViewControllerAttribute, zoomSettingController);
578 			CView* zoomView = zoomSettingController->verifyView (textEdit, UIAttributes (), editorDesc);
579 			zoomView->setAutosizeFlags (kAutosizeRight|kAutosizeTop|kAutosizeBottom);
580 			splitView->addViewToSeparator (0, zoomView);
581 			zoomSettingController->restoreSetting (*getSettings ());
582 
583 		}
584 	}
585 	auto* control = dynamic_cast<CControl*>(view);
586 	if (control)
587 	{
588 		switch (control->getTag ())
589 		{
590 			case kNotSavedTag:
591 			{
592 				notSavedControl = control;
593 				notSavedControl->setAlphaValue (dirty ? 1.f : 0.f);
594 				break;
595 			}
596 			case kAutosizeTag:
597 			{
598 				control->setListener (this);
599 				control->setValue (1.);
600 				break;
601 			}
602 			case kEditingTag:
603 			{
604 				enableEditingControl = control;
605 				enableEditingControl->setValue (1.f);
606 				enableEditingControl->setListener (this);
607 				break;
608 			}
609 			case kTabSwitchTag:
610 			{
611 				auto* button = dynamic_cast<CSegmentButton*>(control);
612 				if (button)
613 				{
614 					size_t numSegments = button->getSegments ().size ();
615 					button->setMax (static_cast<float> (numSegments));
616 					tabSwitchControl = button;
617 					int32_t value = 0;
618 					getSettings ()->getIntegerAttribute ("TabSwitchValue", value);
619 					button->setSelectedSegment (static_cast<uint32_t> (value));
620 					static const char* segmentBitmapNames[] = {"segment-views", "segment-tags", "segment-colors", "segment-gradients", "segment-bitmaps", "segment-fonts", nullptr};
621 					size_t segmentBitmapNameIndex = 0;
622 					for (const auto& segment : button->getSegments())
623 					{
624 						if (segmentBitmapNames[segmentBitmapNameIndex])
625 						{
626 							CBitmap* bitmap = editorDesc->getBitmap (segmentBitmapNames[segmentBitmapNameIndex++]);
627 							if (!bitmap)
628 								continue;
629 							segment.icon = bitmap;
630 							segment.iconHighlighted = bitmap;
631 							segment.iconPosition = CDrawMethods::kIconLeft;
632 						}
633 					}
634 				}
635 				break;
636 			}
637 		}
638 	}
639 	return view;
640 }
641 
642 //----------------------------------------------------------------------------------------------------
createSubController(UTF8StringPtr name,const IUIDescription * description)643 IController* UIEditController::createSubController (UTF8StringPtr name, const IUIDescription* description)
644 {
645 	UTF8StringView subControllerName (name);
646 	if (subControllerName == "TemplatesController")
647 	{
648 		vstgui_assert (templateController == nullptr);
649 		templateController = new UITemplateController (this, editDescription, selection, undoManager, this);
650 		templateController->addDependency (this);
651 		return templateController;
652 	}
653 	else if (subControllerName == "MenuController")
654 	{
655 		return menuController;
656 	}
657 	else if (subControllerName == "ViewCreatorController")
658 	{
659 		return new UIViewCreatorController (this, editDescription);
660 	}
661 	else if (subControllerName == "AttributesController")
662 	{
663 		return new UIAttributesController (this, selection, undoManager, editDescription);
664 	}
665 	else if (subControllerName == "TagEditController")
666 	{
667 		return new UITagsController (this, editDescription, this);
668 	}
669 	else if (subControllerName == "ColorEditController")
670 	{
671 		return new UIColorsController (this, editDescription, this);
672 	}
673 	else if (subControllerName == "GradientEditController")
674 	{
675 		return new UIGradientsController (this, editDescription, this);
676 	}
677 	else if (subControllerName == "BitmapEditController")
678 	{
679 		return new UIBitmapsController (this, editDescription, this);
680 	}
681 	else if (subControllerName == "FontEditController")
682 	{
683 		return new UIFontsController (this, editDescription, this);
684 	}
685 	else if (subControllerName == "GridController")
686 	{
687 		gridController->remember ();
688 		return gridController;
689 	}
690 	return nullptr;
691 }
692 
693 //----------------------------------------------------------------------------------------------------
valueChanged(CControl * control)694 void UIEditController::valueChanged (CControl* control)
695 {
696 	if (editView)
697 	{
698 		switch (control->getTag ())
699 		{
700 			case kEditingTag:
701 			{
702 				selection->clear ();
703 				if (auto container = editView->getEditView () ? editView->getEditView ()->asViewContainer () : nullptr)
704 					resetScrollViewOffsets (container);
705 				editView->enableEditing (control->getValue () == control->getMax () ? true : false);
706 				break;
707 			}
708 			case kAutosizeTag:
709 			{
710 				editView->enableAutosizing (control->getValue () == 1.f);
711 				break;
712 			}
713 			case kBackgroundSelectTag:
714 			{
715 				if (auto seg = dynamic_cast<CSegmentButton*> (control))
716 				{
717 					CColor color = editViewBackgroundColors ()[seg->getSelectedSegment ()];
718 					editView->setBackgroundColor (color);
719 				}
720 				break;
721 			}
722 			case kTabSwitchTag:
723 			{
724 				getSettings ()->setIntegerAttribute ("TabSwitchValue", static_cast<int32_t> (tabSwitchControl->getValue ()));
725 				break;
726 			}
727 		}
728 	}
729 }
730 
731 //----------------------------------------------------------------------------------------------------
validateCommandMenuItem(CCommandMenuItem * item)732 bool UIEditController::validateCommandMenuItem (CCommandMenuItem* item)
733 {
734 	return validateMenuItem (item) == kMessageNotified;
735 }
736 
737 //----------------------------------------------------------------------------------------------------
onCommandMenuItemSelected(CCommandMenuItem * item)738 bool UIEditController::onCommandMenuItemSelected (CCommandMenuItem* item)
739 {
740 	return onMenuItemSelection (item) == kMessageNotified;
741 }
742 
743 //----------------------------------------------------------------------------------------------------
notify(CBaseObject * sender,IdStringPtr message)744 CMessageResult UIEditController::notify (CBaseObject* sender, IdStringPtr message)
745 {
746 	if (message == UITemplateController::kMsgTemplateChanged)
747 	{
748 		onTemplateSelectionChanged ();
749 		return kMessageNotified;
750 	}
751 	else if (message == UIUndoManager::kMsgChanged)
752 	{
753 		onUndoManagerChanged ();
754 		return kMessageNotified;
755 	}
756 	else if (message == UIEditView::kMsgAttached)
757 	{
758 		vstgui_assert (editView);
759 		editView->getFrame ()->registerKeyboardHook (this);
760 		return kMessageNotified;
761 	}
762 	else if (message == UIEditView::kMsgRemoved)
763 	{
764 		editView->getFrame ()->unregisterKeyboardHook (this);
765 		beforeSave ();
766 		splitViews.clear ();
767 		getEditorDescription ()->freePlatformResources ();
768 		return kMessageNotified;
769 	}
770 
771 	return kMessageUnknown;
772 }
773 
774 //----------------------------------------------------------------------------------------------------
onUIDescTemplateChanged(UIDescription * desc)775 void UIEditController::onUIDescTemplateChanged (UIDescription* desc)
776 {
777 	onTemplatesChanged ();
778 }
779 
780 //----------------------------------------------------------------------------------------------------
beforeUIDescSave(UIDescription * desc)781 void UIEditController::beforeUIDescSave (UIDescription* desc)
782 {
783 	beforeSave ();
784 }
785 
786 //----------------------------------------------------------------------------------------------------
doUIDescTemplateUpdate(UIDescription * desc,UTF8StringPtr name)787 bool UIEditController::doUIDescTemplateUpdate (UIDescription* desc, UTF8StringPtr name)
788 {
789 	if (onlyTemplateToUpdateName.empty ())
790 		return true;
791 	return onlyTemplateToUpdateName == name;
792 }
793 
794 //----------------------------------------------------------------------------------------------------
beforeSave()795 void UIEditController::beforeSave ()
796 {
797 	if (editView && editView->getEditView ())
798 	{
799 		if (undoManager->canUndo ())
800 		{
801 			if (!editTemplateName.empty ())
802 				updateTemplate (editTemplateName.c_str ());
803 			for (std::vector<Template>::const_iterator it = templates.begin (); it != templates.end (); it++)
804 			{
805 				onlyTemplateToUpdateName = it->name;
806 				updateTemplate (it);
807 			}
808 			onlyTemplateToUpdateName.clear ();
809 		}
810 		for (auto& splitView : splitViews)
811 			splitView->storeViewSizes ();
812 
813 		getSettings ()->setIntegerAttribute ("Version", 1);
814 		// find the view of this controller
815 		auto container = editView->getParentView ()->asViewContainer ();
816 		while (container && container != container->getFrame ())
817 		{
818 			if (getViewController (container, false) == this)
819 			{
820 				getSettings ()->setRectAttribute ("EditorSize", container->getViewSize ());
821 				break;
822 			}
823 			container = container->getParentView () ? container->getParentView ()->asViewContainer () : nullptr;
824 		}
825 		undoManager->markSavePosition ();
826 		if (zoomSettingController)
827 			zoomSettingController->storeSetting (*getSettings ());
828 		setDirty (false);
829 	}
830 }
831 
832 //----------------------------------------------------------------------------------------------------
onTemplateSelectionChanged()833 void UIEditController::onTemplateSelectionChanged ()
834 {
835 	if (editView && templateController)
836 	{
837 		const auto& name = templateController->getSelectedTemplateName ();
838 		if ((name && *name != editTemplateName) || name == nullptr)
839 		{
840 			if (undoManager->canUndo () && !editTemplateName.empty ())
841 				updateTemplate (editTemplateName.c_str ());
842 			if (name)
843 			{
844 				for (auto& it : templates)
845 				{
846 					if (*name == it.name)
847 					{
848 						CView* view = it.view;
849 						editView->setEditView (view);
850 						templateController->setTemplateView (static_cast<CViewContainer*> (view));
851 						editTemplateName = *templateController->getSelectedTemplateName ();
852 						view->remember ();
853 						break;
854 					}
855 				}
856 			}
857 			else
858 			{
859 				selection->clear ();
860 				editView->setEditView (nullptr);
861 				templateController->setTemplateView (nullptr);
862 				editTemplateName = "";
863 			}
864 		}
865 		if (editView->getEditView ())
866 		{
867 			if (!(selection->first () && editView->getEditView ()->asViewContainer ()->isChild (selection->first (), true)))
868 				selection->setExclusive (editView->getEditView ());
869 		}
870 		else
871 			selection->clear ();
872 	}
873 }
874 
875 //----------------------------------------------------------------------------------------------------
doCopy(bool cut)876 void UIEditController::doCopy (bool cut)
877 {
878 	if (!editTemplateName.empty ())
879 		updateTemplate (editTemplateName.c_str ());
880 	CMemoryStream stream (1024, 1024, false);
881 	selection->store (stream, editDescription);
882 	auto dataSource = CDropSource::create (stream.getBuffer (), static_cast<uint32_t> (stream.tell ()), IDataPackage::kText);
883 	editView->getFrame ()->setClipboard (dataSource);
884 	if (cut)
885 		undoManager->pushAndPerform (new DeleteOperation (selection));
886 }
887 
888 //----------------------------------------------------------------------------------------------------
addSelectionToCurrentView(UISelection * copySelection)889 void UIEditController::addSelectionToCurrentView (UISelection* copySelection)
890 {
891 	if (selection->total () == 0)
892 		return;
893 	CPoint offset;
894 	CViewContainer* container = selection->first ()->asViewContainer ();
895 	if (container == nullptr)
896 	{
897 		container = selection->first ()->getParentView ()->asViewContainer ();
898 		offset = selection->first ()->getViewSize ().getTopLeft ();
899 		offset.offset (gridController->getSize ().x, gridController->getSize ().y);
900 	}
901 	IAction* action = new ViewCopyOperation (copySelection, selection, container, offset, editDescription);
902 	undoManager->pushAndPerform (action);
903 	if (!editTemplateName.empty ())
904 		updateTemplate (editTemplateName.c_str ());
905 }
906 
907 //----------------------------------------------------------------------------------------------------
doPaste()908 void UIEditController::doPaste ()
909 {
910 	if (auto clipboard = editView->getFrame ()->getClipboard ())
911 	{
912 		if (clipboard->getDataType (0) == IDataPackage::kText)
913 		{
914 			const void* data;
915 			IDataPackage::Type type;
916 			uint32_t size = clipboard->getData (0, data, type);
917 			if (size > 0)
918 			{
919 				CMemoryStream stream ((const int8_t*)data, size, false);
920 				auto* copySelection = new UISelection ();
921 				if (copySelection->restore (stream, editDescription))
922 				{
923 					addSelectionToCurrentView (copySelection);
924 				}
925 				copySelection->forget ();
926 			}
927 		}
928 	}
929 }
930 
931 //----------------------------------------------------------------------------------------------------
showTemplateSettings()932 void UIEditController::showTemplateSettings ()
933 {
934 	if (undoManager->canUndo () && !editTemplateName.empty ())
935 	{
936 		updateTemplate (editTemplateName.c_str ());
937 	}
938 	auto* dc = new UIDialogController (this, editView->getFrame ());
939 	auto* tsController = new UITemplateSettingsController (editTemplateName, editDescription, this);
940 	dc->run ("template.settings", "Template Settings", "OK", "Cancel", tsController, editorDesc);
941 }
942 
943 //----------------------------------------------------------------------------------------------------
showFocusSettings()944 void UIEditController::showFocusSettings ()
945 {
946 	auto* dc = new UIDialogController (this, editView->getFrame ());
947 	auto* fsController = new UIFocusSettingsController (editDescription, this);
948 	dc->run ("focus.settings", "Focus Drawing Settings", "OK", "Cancel", fsController, editorDesc);
949 }
950 
951 //----------------------------------------------------------------------------------------------------
toggleBoolAttribute(UIAttributes * attributes,UTF8StringPtr key)952 static void toggleBoolAttribute (UIAttributes* attributes, UTF8StringPtr key)
953 {
954 	if (attributes)
955 	{
956 		bool val = false;
957 		attributes->getBooleanAttribute (key, val);
958 		attributes->setBooleanAttribute (key, !val);
959 	}
960 }
961 
962 //----------------------------------------------------------------------------------------------------
onMenuItemSelection(CCommandMenuItem * item)963 CMessageResult UIEditController::onMenuItemSelection (CCommandMenuItem* item)
964 {
965 	UTF8StringView cmdCategory (item->getCommandCategory ());
966 	UTF8StringView cmdName (item->getCommandName ());
967 
968 	if (cmdCategory == "Edit")
969 	{
970 		if (cmdName == "Copy")
971 		{
972 			doCopy (false);
973 			return kMessageNotified;
974 		}
975 		else if (cmdName == "Cut")
976 		{
977 			doCopy (true);
978 			return kMessageNotified;
979 		}
980 		else if (cmdName == "Paste")
981 		{
982 			doPaste ();
983 			return kMessageNotified;
984 		}
985 		else if (cmdName == "Template Settings...")
986 		{
987 			showTemplateSettings ();
988 			return kMessageNotified;
989 		}
990 		else if (cmdName == "Focus Drawing Settings...")
991 		{
992 			showFocusSettings ();
993 			return kMessageNotified;
994 		}
995 	}
996 	else if (cmdCategory == "File")
997 	{
998 		if (cmdName == "Encode Bitmaps in XML")
999 		{
1000 			toggleBoolAttribute (getSettings (), kEncodeBitmapsSettingsKey);
1001 			return kMessageNotified;
1002 		}
1003 		else if (cmdName == "Write Windows RC File on Save")
1004 		{
1005 			toggleBoolAttribute (getSettings (), kWriteWindowsRCFileSettingsKey);
1006 			return kMessageNotified;
1007 		}
1008 	}
1009 	else if (cmdCategory == "SelectionMoveByGrid")
1010 	{
1011 		if (doSelectionMove (item->getCommandName (), true))
1012 			return kMessageNotified;
1013 	}
1014 	else if (cmdCategory == "SelectionSizeByGrid")
1015 	{
1016 		if (doSelectionSize (item->getCommandName (), true))
1017 			return kMessageNotified;
1018 	}
1019 	else if (cmdCategory == "SelectionMoveByPixel")
1020 	{
1021 		if (doSelectionMove (item->getCommandName (), false))
1022 			return kMessageNotified;
1023 	}
1024 	else if (cmdCategory == "SelectionSizeByPixel")
1025 	{
1026 		if (doSelectionSize (item->getCommandName (), false))
1027 			return kMessageNotified;
1028 	}
1029 	else if (cmdCategory == "SelectionZOrder")
1030 	{
1031 		bool lower = cmdName == "Lower" ? true : false;
1032 		if (doZOrderAction (lower))
1033 			return kMessageNotified;
1034 
1035 	}
1036 	else if (cmdCategory == "Selection")
1037 	{
1038 		if (cmdName == "Select All Children")
1039 		{
1040 			doSelectAllChildren ();
1041 			return kMessageNotified;
1042 		}
1043 	}
1044 	else if (cmdCategory == "Zoom")
1045 	{
1046 		if (cmdName == "Zoom In")
1047 		{
1048 			zoomSettingController->increaseZoom ();
1049 			return kMessageNotified;
1050 		}
1051 		else if (cmdName == "Zoom Out")
1052 		{
1053 			zoomSettingController->decreaseZoom ();
1054 			return kMessageNotified;
1055 		}
1056 		else if (cmdName == "Zoom 100%")
1057 		{
1058 			zoomSettingController->resetZoom ();
1059 			return kMessageNotified;
1060 		}
1061 	}
1062 	return kMessageUnknown;
1063 }
1064 
1065 //----------------------------------------------------------------------------------------------------
validateMenuItem(CCommandMenuItem * item)1066 CMessageResult UIEditController::validateMenuItem (CCommandMenuItem* item)
1067 {
1068 	UTF8StringView cmdCategory (item->getCommandCategory ());
1069 	UTF8StringView cmdName (item->getCommandName ());
1070 
1071 	if (cmdCategory == "Edit")
1072 	{
1073 		if (cmdName == "Template Settings...")
1074 		{
1075 			item->setEnabled (editTemplateName.empty () ? false : true);
1076 			return kMessageNotified;
1077 		}
1078 		else if (cmdName == "Copy" || cmdName == "Cut")
1079 		{
1080 			if (editView && selection->first () && selection->contains (editView->getEditView ()) == false)
1081 				item->setEnabled (true);
1082 			else
1083 				item->setEnabled (false);
1084 			return kMessageNotified;
1085 		}
1086 		else if (cmdName == "Paste")
1087 		{
1088 			item->setEnabled (false);
1089 			if (editView && selection->first ())
1090 			{
1091 				if (auto clipboard = editView->getFrame ()->getClipboard ())
1092 				{
1093 					if (clipboard->getDataType (0) == IDataPackage::kText)
1094 						item->setEnabled (true);
1095 				}
1096 			}
1097 			return kMessageNotified;
1098 		}
1099 	}
1100 	else if (cmdCategory == "File")
1101 	{
1102 		if (cmdName == "Encode Bitmaps in XML")
1103 		{
1104 			auto attr = getSettings ();
1105 			bool encodeBitmaps = false;
1106 			if (attr && attr->getBooleanAttribute (kEncodeBitmapsSettingsKey, encodeBitmaps))
1107 			{
1108 				item->setChecked (encodeBitmaps);
1109 			}
1110 			return kMessageNotified;
1111 		}
1112 		else if (cmdName == "Write Windows RC File on Save")
1113 		{
1114 			auto attr = getSettings ();
1115 			bool encodeBitmaps = false;
1116 			if (attr && attr->getBooleanAttribute (kWriteWindowsRCFileSettingsKey, encodeBitmaps))
1117 			{
1118 				item->setChecked (encodeBitmaps);
1119 			}
1120 			return kMessageNotified;
1121 		}
1122 	}
1123 	else if (cmdCategory == "SelectionMoveByGrid"
1124 			 || cmdCategory == "SelectionSizeByGrid"
1125 			 || cmdCategory == "SelectionMoveByPixel"
1126 			 || cmdCategory == "SelectionSizeByPixel"
1127 		)
1128 	{
1129 		bool enableItem = selection->first () ? true : false;
1130 		if (enableItem && cmdCategory.contains ("Size") == false)
1131 		{
1132 			if (selection->contains (editView->getEditView ()))
1133 				enableItem = false;
1134 		}
1135 		item->setEnabled (enableItem);
1136 		return kMessageNotified;
1137 	}
1138 	else if (cmdCategory == "SelectionZOrder")
1139 	{
1140 		bool enableItem = selection->total () == 1;
1141 		if (enableItem)
1142 		{
1143 			bool lower = cmdName == "Lower" ? true : false;
1144 			CView* view = selection->first ();
1145 			if (auto parent = view->getParentView ()->asViewContainer ())
1146 			{
1147 				if (lower)
1148 				{
1149 					ViewIterator it (parent);
1150 					if (*it == view)
1151 						enableItem = false;
1152 				}
1153 				else
1154 				{
1155 					ReverseViewIterator it (parent);
1156 					if (*it == view)
1157 						enableItem = false;
1158 				}
1159 			}
1160 		}
1161 		item->setEnabled (enableItem);
1162 		return kMessageNotified;
1163 	}
1164 	else if (cmdCategory == "Selection")
1165 	{
1166 		if (cmdName == "Select All Children")
1167 		{
1168 			bool enable = selection->total () == 1 && selection->first () && selection->first ()->asViewContainer ();
1169 			item->setEnabled (enable);
1170 			return kMessageNotified;
1171 		}
1172 	}
1173 	return kMessageUnknown;
1174 }
1175 
1176 //----------------------------------------------------------------------------------------------------
doSelectionMove(const UTF8String & commandName,bool useGrid) const1177 bool UIEditController::doSelectionMove (const UTF8String& commandName, bool useGrid) const
1178 {
1179 	CPoint diff;
1180 	if (commandName == "Move Up")
1181 		diff.y = -(useGrid ? gridController->getSize ().y : 1);
1182 	else if (commandName == "Move Down")
1183 		diff.y = (useGrid ? gridController->getSize ().y : 1);
1184 	else if (commandName == "Move Left")
1185 		diff.x = -(useGrid ? gridController->getSize ().x : 1);
1186 	else if (commandName == "Move Right")
1187 		diff.x = (useGrid ? gridController->getSize ().x : 1);
1188 	if (diff.x != 0 || diff.y != 0)
1189 	{
1190 		editView->doKeyMove (diff);
1191 		return true;
1192 	}
1193 	return false;
1194 }
1195 
1196 //----------------------------------------------------------------------------------------------------
doSelectionSize(const UTF8String & commandName,bool useGrid) const1197 bool UIEditController::doSelectionSize (const UTF8String& commandName, bool useGrid) const
1198 {
1199 	CPoint diff;
1200 	if (commandName == "Increase Size Width")
1201 		diff.x = (useGrid ? gridController->getSize ().x : 1);
1202 	else if (commandName == "Increase Size Height")
1203 		diff.y = (useGrid ? gridController->getSize ().y : 1);
1204 	else if (commandName == "Decrease Size Width")
1205 		diff.x = -(useGrid ? gridController->getSize ().x : 1);
1206 	else if (commandName == "Decrease Size Height")
1207 		diff.y = -(useGrid ? gridController->getSize ().y : 1);
1208 	if (diff.x != 0 || diff.y != 0)
1209 	{
1210 		editView->doKeySize (diff);
1211 		return true;
1212 	}
1213 	return false;
1214 }
1215 
1216 //----------------------------------------------------------------------------------------------------
doZOrderAction(bool lower)1217 bool UIEditController::doZOrderAction (bool lower)
1218 {
1219 	if (selection->total () == 1)
1220 	{
1221 		CView* view = selection->first ();
1222 		undoManager->pushAndPerform (new HierarchyMoveViewOperation (view, selection, lower));
1223 		return true;
1224 	}
1225 	return false;
1226 }
1227 
1228 //----------------------------------------------------------------------------------------------------
doSelectAllChildren()1229 void UIEditController::doSelectAllChildren ()
1230 {
1231 	CViewContainer* container = selection->first ()->asViewContainer ();
1232 	selection->clear ();
1233 	auto factory = static_cast<const UIViewFactory*> (editDescription->getViewFactory ());
1234 	container->forEachChild ([&] (CView* view) {
1235 		if (factory->getViewName (view))
1236 			selection->add (view);
1237 	});
1238 }
1239 
1240 //----------------------------------------------------------------------------------------------------
onUndoManagerChanged()1241 void UIEditController::onUndoManagerChanged ()
1242 {
1243 	if (undoManager->isSavePosition ())
1244 	{
1245 		updateTemplate (editTemplateName.data ());
1246 		setDirty (false);
1247 	}
1248 	else
1249 		setDirty (true);
1250 	CView* view = selection->first ();
1251 	if (view)
1252 	{
1253 		if (auto templateView = editView->getEditView () ? editView->getEditView ()->asViewContainer () : nullptr)
1254 		{
1255 			if (view == templateView || templateView->isChild (view, true))
1256 			{
1257 				return;
1258 			}
1259 		}
1260 		for (auto& it : templates)
1261 		{
1262 			CViewContainer* container = it.view->asViewContainer ();
1263 			if (container && (view == container || container->isChild (view, true)))
1264 			{
1265 				templateController->selectTemplate (it.name.c_str ());
1266 				return;
1267 			}
1268 		}
1269 		selection->clear ();
1270 	}
1271 }
1272 
1273 //----------------------------------------------------------------------------------------------------
resetScrollViewOffsets(CViewContainer * view)1274 void UIEditController::resetScrollViewOffsets (CViewContainer* view)
1275 {
1276 	view->forEachChild ([&] (CView* view) {
1277 		auto* scrollView = dynamic_cast<CScrollView*>(view);
1278 		if (scrollView)
1279 		{
1280 			scrollView->resetScrollOffset ();
1281 		}
1282 		if (auto container = view->asViewContainer ())
1283 			resetScrollViewOffsets (container);
1284 	});
1285 }
1286 
1287 //----------------------------------------------------------------------------------------------------
onKeyDown(const VstKeyCode & code,CFrame * frame)1288 int32_t UIEditController::onKeyDown (const VstKeyCode& code, CFrame* frame)
1289 {
1290 	if (frame->getModalView () == nullptr)
1291 	{
1292 		if (frame->getFocusView ())
1293 		{
1294 			auto* edit = dynamic_cast<CTextEdit*>(frame->getFocusView ());
1295 			if (edit && edit->getPlatformTextEdit ())
1296 				return -1;
1297 		}
1298 		return menuController->processKeyCommand (code);
1299 	}
1300 	return -1;
1301 }
1302 
1303 //----------------------------------------------------------------------------------------------------
onKeyUp(const VstKeyCode & code,CFrame * frame)1304 int32_t UIEditController::onKeyUp (const VstKeyCode& code, CFrame* frame)
1305 {
1306 	return -1;
1307 }
1308 
1309 //----------------------------------------------------------------------------------------------------
getSettings()1310 SharedPointer<UIAttributes> UIEditController::getSettings ()
1311 {
1312 	return editDescription->getCustomAttributes ("UIEditController", true);
1313 }
1314 
1315 //----------------------------------------------------------------------------------------------------
getSaveOptions()1316 int32_t UIEditController::getSaveOptions ()
1317 {
1318 	int32_t flags = 0;
1319 	auto attributes = getSettings ();
1320 	bool val;
1321 	if (attributes->getBooleanAttribute (UIEditController::kEncodeBitmapsSettingsKey, val) && val == true)
1322 	{
1323 		flags |= UIDescription::kWriteImagesIntoXMLFile;
1324 	}
1325 	if (attributes->getBooleanAttribute (UIEditController::kWriteWindowsRCFileSettingsKey, val) && val == true)
1326 	{
1327 		flags |= UIDescription::kWriteWindowsResourceFile;
1328 	}
1329 	return flags;
1330 }
1331 
1332 //----------------------------------------------------------------------------------------------------
getSplitViewIndex(CSplitView * splitView)1333 int32_t UIEditController::getSplitViewIndex (CSplitView* splitView)
1334 {
1335 	int32_t index = 0;
1336 	for (auto& sv : splitViews)
1337 	{
1338 		if (sv == splitView)
1339 			return index;
1340 		index++;
1341 	}
1342 	return -1;
1343 }
1344 
1345 //----------------------------------------------------------------------------------------------------
getSplitViewSizeConstraint(int32_t index,CCoord & minSize,CCoord & maxSize,CSplitView * splitView)1346 bool UIEditController::getSplitViewSizeConstraint (int32_t index, CCoord& minSize, CCoord& maxSize, CSplitView* splitView)
1347 {
1348 	return false;
1349 }
1350 
1351 //----------------------------------------------------------------------------------------------------
getSplitViewSeparatorDrawer(CSplitView * splitView)1352 ISplitViewSeparatorDrawer* UIEditController::getSplitViewSeparatorDrawer (CSplitView* splitView)
1353 {
1354 	int32_t si = getSplitViewIndex (splitView);
1355 	if (si >= 0)
1356 	{
1357 		return this;
1358 	}
1359 	return nullptr;
1360 }
1361 
1362 //----------------------------------------------------------------------------------------------------
storeViewSize(int32_t index,const CCoord & size,CSplitView * splitView)1363 bool UIEditController::storeViewSize (int32_t index, const CCoord& size, CSplitView* splitView)
1364 {
1365 	int32_t si = getSplitViewIndex (splitView);
1366 	if (si >= 0)
1367 	{
1368 		std::stringstream str;
1369 		str << "SplitViewSize_";
1370 		str << si;
1371 		str << "_";
1372 		str << index;
1373 		double value;
1374 		if (splitView->getStyle () == CSplitView::kHorizontal)
1375 			value = size / splitView->getWidth ();
1376 		else
1377 			value = size / splitView->getHeight ();
1378 		getSettings ()->setDoubleAttribute (str.str (), value);
1379 		return true;
1380 	}
1381 	return false;
1382 }
1383 
1384 //----------------------------------------------------------------------------------------------------
restoreViewSize(int32_t index,CCoord & size,CSplitView * splitView)1385 bool UIEditController::restoreViewSize (int32_t index, CCoord& size, CSplitView* splitView)
1386 {
1387 	int32_t version = 0;
1388 	getSettings ()->getIntegerAttribute ("Version", version);
1389 	if (version == 0)
1390 		return false;
1391 	int32_t si = getSplitViewIndex (splitView);
1392 	if (si >= 0)
1393 	{
1394 		std::stringstream str;
1395 		str << "SplitViewSize_";
1396 		str << si;
1397 		str << "_";
1398 		str << index;
1399 		double value;
1400 		if (getSettings ()->getDoubleAttribute (str.str ().c_str (), value))
1401 		{
1402 			if (splitView->getStyle () == CSplitView::kHorizontal)
1403 				value = floor (splitView->getWidth () * value + 0.5);
1404 			else
1405 				value = floor (splitView->getHeight () * value + 0.5);
1406 			size = value;
1407 			return true;
1408 		}
1409 	}
1410 	return false;
1411 }
1412 
1413 //----------------------------------------------------------------------------------------------------
drawSplitViewSeparator(CDrawContext * context,const CRect & size,int32_t flags,int32_t index,CSplitView * splitView)1414 void UIEditController::drawSplitViewSeparator (CDrawContext* context, const CRect& size, int32_t flags, int32_t index, CSplitView* splitView)
1415 {
1416 	if (splitView->getStyle () == CSplitView::kHorizontal)
1417 	{
1418 		UIEditControllerShadingView::drawGradient (context, size, true);
1419 	}
1420 	else
1421 	{
1422 		UIEditControllerShadingView::drawGradient (context, size, false);
1423 	}
1424 }
1425 
1426 //----------------------------------------------------------------------------------------------------
setDirty(bool state)1427 void UIEditController::setDirty (bool state)
1428 {
1429 	if (dirty != state)
1430 	{
1431 		dirty = state;
1432 		if (notSavedControl && notSavedControl->isAttached ())
1433 		{
1434 			notSavedControl->invalid ();
1435 			notSavedControl->addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (dirty ? 1.f : 0.f), new Animation::LinearTimingFunction (80));
1436 		}
1437 	}
1438 }
1439 
1440 //----------------------------------------------------------------------------------------------------
performAction(IAction * action)1441 void UIEditController::performAction (IAction* action)
1442 {
1443 	undoManager->pushAndPerform (action);
1444 }
1445 
1446 //----------------------------------------------------------------------------------------------------
beginGroupAction(UTF8StringPtr name)1447 void UIEditController::beginGroupAction (UTF8StringPtr name)
1448 {
1449 	undoManager->startGroupAction (name);
1450 }
1451 
1452 //----------------------------------------------------------------------------------------------------
finishGroupAction()1453 void UIEditController::finishGroupAction ()
1454 {
1455 	undoManager->endGroupAction ();
1456 }
1457 
1458 //----------------------------------------------------------------------------------------------------
performChangeFocusDrawingSettings(const FocusDrawingSettings & newSettings)1459 void UIEditController::performChangeFocusDrawingSettings (const FocusDrawingSettings& newSettings)
1460 {
1461 	undoManager->pushAndPerform (new ChangeFocusDrawingAction (editDescription, newSettings));
1462 }
1463 
1464 //----------------------------------------------------------------------------------------------------
getTemplateViews(std::list<CView * > & views) const1465 void UIEditController::getTemplateViews (std::list<CView*>& views) const
1466 {
1467 	for (const auto& templateDesc : templates)
1468 		views.emplace_back (templateDesc.view);
1469 }
1470 
1471 //----------------------------------------------------------------------------------------------------
performColorChange(UTF8StringPtr colorName,const CColor & newColor,bool remove)1472 void UIEditController::performColorChange (UTF8StringPtr colorName, const CColor& newColor, bool remove)
1473 {
1474 	std::list<CView*> views;
1475 	getTemplateViews (views);
1476 
1477 	auto* action = new ColorChangeAction (editDescription, colorName, newColor, remove, true);
1478 	undoManager->startGroupAction (remove ? "Delete Color" : action->isAddColor () ? "Add New Color" : "Change Color");
1479 	undoManager->pushAndPerform (action);
1480 	undoManager->pushAndPerform (new MultipleAttributeChangeAction (editDescription, views, IViewCreator::kColorType, colorName, remove ? "" : colorName));
1481 	undoManager->pushAndPerform (new ColorChangeAction (editDescription, colorName, newColor, remove, false));
1482 	undoManager->endGroupAction ();
1483 }
1484 
1485 //----------------------------------------------------------------------------------------------------
performTagChange(UTF8StringPtr tagName,UTF8StringPtr tagStr,bool remove)1486 void UIEditController::performTagChange (UTF8StringPtr tagName, UTF8StringPtr tagStr, bool remove)
1487 {
1488 	std::list<CView*> views;
1489 	getTemplateViews (views);
1490 
1491 	auto* action = new TagChangeAction (editDescription, tagName, tagStr, remove, true);
1492 	undoManager->startGroupAction (remove ? "Delete Tag" : action->isAddTag () ? "Add New Tag" : "Change Tag");
1493 	undoManager->pushAndPerform (action);
1494 	undoManager->pushAndPerform (new MultipleAttributeChangeAction (editDescription, views, IViewCreator::kTagType, tagName, remove ? "" : tagName));
1495 	undoManager->pushAndPerform (new TagChangeAction (editDescription, tagName, tagStr, remove, false));
1496 	undoManager->endGroupAction ();
1497 }
1498 
1499 //----------------------------------------------------------------------------------------------------
performBitmapChange(UTF8StringPtr bitmapName,UTF8StringPtr bitmapPath,bool remove)1500 void UIEditController::performBitmapChange (UTF8StringPtr bitmapName, UTF8StringPtr bitmapPath, bool remove)
1501 {
1502 	std::list<CView*> views;
1503 	getTemplateViews (views);
1504 
1505 	auto* action = new BitmapChangeAction (editDescription, bitmapName, bitmapPath, remove, true);
1506 	undoManager->startGroupAction (remove ? "Delete Bitmap" : action->isAddBitmap () ? "Add New Bitmap" :"Change Bitmap");
1507 	undoManager->pushAndPerform (action);
1508 	undoManager->pushAndPerform (new MultipleAttributeChangeAction (editDescription, views, IViewCreator::kBitmapType, bitmapName, remove ? "" : bitmapName));
1509 	undoManager->pushAndPerform (new BitmapChangeAction (editDescription, bitmapName, bitmapPath, remove, false));
1510 	undoManager->endGroupAction ();
1511 }
1512 
1513 //------------------------------------------------------------------------
performGradientChange(UTF8StringPtr gradientName,CGradient * newGradient,bool remove)1514 void UIEditController::performGradientChange (UTF8StringPtr gradientName, CGradient* newGradient, bool remove)
1515 {
1516 	std::list<CView*> views;
1517 	getTemplateViews (views);
1518 
1519 	auto* action = new GradientChangeAction (editDescription, gradientName, newGradient, remove, true);
1520 	undoManager->startGroupAction (remove ? "Delete Bitmap" : action->isAddGradient () ? "Add New Gradient" :"Change Gradient");
1521 	undoManager->pushAndPerform (action);
1522 	undoManager->pushAndPerform (new MultipleAttributeChangeAction (editDescription, views, IViewCreator::kGradientType, gradientName, remove ? "" : gradientName));
1523 	undoManager->pushAndPerform (new GradientChangeAction (editDescription, gradientName, newGradient, remove, false));
1524 	undoManager->endGroupAction ();
1525 }
1526 
1527 //----------------------------------------------------------------------------------------------------
performFontChange(UTF8StringPtr fontName,CFontRef newFont,bool remove)1528 void UIEditController::performFontChange (UTF8StringPtr fontName, CFontRef newFont, bool remove)
1529 {
1530 	std::list<CView*> views;
1531 	getTemplateViews (views);
1532 
1533 	auto* action = new FontChangeAction (editDescription, fontName, newFont, remove, true);
1534 	undoManager->startGroupAction (remove ? "Delete Font" : action->isAddFont () ? "Add New Font" : "Change Font");
1535 	undoManager->pushAndPerform (action);
1536 	undoManager->pushAndPerform (new MultipleAttributeChangeAction (editDescription, views, IViewCreator::kFontType, fontName, remove ? "" : fontName));
1537 	undoManager->pushAndPerform (new FontChangeAction (editDescription, fontName, newFont, remove, false));
1538 	undoManager->endGroupAction ();
1539 }
1540 
1541 //----------------------------------------------------------------------------------------------------
performNameChange(UTF8StringPtr oldName,UTF8StringPtr newName,IdStringPtr groupActionName)1542 template<typename NameChangeAction, IViewCreator::AttrType attrType> void UIEditController::performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName, IdStringPtr groupActionName)
1543 {
1544 	std::list<CView*> views;
1545 	getTemplateViews (views);
1546 
1547 	undoManager->startGroupAction (groupActionName);
1548 	undoManager->pushAndPerform (new NameChangeAction (editDescription, oldName, newName, true));
1549 	undoManager->pushAndPerform (new MultipleAttributeChangeAction (editDescription, views, attrType, oldName, newName));
1550 	undoManager->pushAndPerform (new NameChangeAction (editDescription, oldName, newName, false));
1551 	undoManager->endGroupAction ();
1552 }
1553 
1554 //----------------------------------------------------------------------------------------------------
performColorNameChange(UTF8StringPtr oldName,UTF8StringPtr newName)1555 void UIEditController::performColorNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
1556 {
1557 	performNameChange<ColorNameChangeAction, IViewCreator::kColorType> (oldName, newName, "Change Color Name");
1558 }
1559 
1560 //----------------------------------------------------------------------------------------------------
performTagNameChange(UTF8StringPtr oldName,UTF8StringPtr newName)1561 void UIEditController::performTagNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
1562 {
1563 	performNameChange<TagNameChangeAction, IViewCreator::kTagType> (oldName, newName, "Change Tag Name");
1564 }
1565 
1566 //----------------------------------------------------------------------------------------------------
performFontNameChange(UTF8StringPtr oldName,UTF8StringPtr newName)1567 void UIEditController::performFontNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
1568 {
1569 	performNameChange<FontNameChangeAction, IViewCreator::kFontType> (oldName, newName, "Change Font Name");
1570 }
1571 
1572 //----------------------------------------------------------------------------------------------------
performGradientNameChange(UTF8StringPtr oldName,UTF8StringPtr newName)1573 void UIEditController::performGradientNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
1574 {
1575 	performNameChange<GradientNameChangeAction, IViewCreator::kGradientType> (oldName, newName, "Change Gradient Name");
1576 }
1577 
1578 //----------------------------------------------------------------------------------------------------
performBitmapNameChange(UTF8StringPtr oldName,UTF8StringPtr newName)1579 void UIEditController::performBitmapNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
1580 {
1581 	performNameChange<BitmapNameChangeAction, IViewCreator::kBitmapType> (oldName, newName, "Change Bitmap Name");
1582 }
1583 
1584 //----------------------------------------------------------------------------------------------------
performBitmapNinePartTiledChange(UTF8StringPtr bitmapName,const CRect * offsets)1585 void UIEditController::performBitmapNinePartTiledChange (UTF8StringPtr bitmapName, const CRect* offsets)
1586 {
1587 	std::list<CView*> views;
1588 	getTemplateViews (views);
1589 
1590 	undoManager->startGroupAction ("Change NinePartTiled Bitmap");
1591 	undoManager->pushAndPerform (new NinePartTiledBitmapChangeAction (editDescription, bitmapName, offsets, true));
1592 	undoManager->pushAndPerform (new MultipleAttributeChangeAction (editDescription, views, IViewCreator::kBitmapType, bitmapName, bitmapName));
1593 	undoManager->pushAndPerform (new NinePartTiledBitmapChangeAction (editDescription, bitmapName, offsets, false));
1594 	undoManager->endGroupAction ();
1595 }
1596 
1597 //----------------------------------------------------------------------------------------------------
performBitmapFiltersChange(UTF8StringPtr bitmapName,const std::list<SharedPointer<UIAttributes>> & filterDescription)1598 void UIEditController::performBitmapFiltersChange (UTF8StringPtr bitmapName, const std::list<SharedPointer<UIAttributes> >& filterDescription)
1599 {
1600 	std::list<CView*> views;
1601 	getTemplateViews (views);
1602 
1603 	undoManager->startGroupAction ("Change Bitmap Filter");
1604 	undoManager->pushAndPerform (new BitmapFilterChangeAction (editDescription, bitmapName, filterDescription, true));
1605 	undoManager->pushAndPerform (new MultipleAttributeChangeAction (editDescription, views, IViewCreator::kBitmapType, bitmapName, bitmapName));
1606 	undoManager->pushAndPerform (new BitmapFilterChangeAction (editDescription, bitmapName, filterDescription, false));
1607 	undoManager->endGroupAction ();
1608 }
1609 
1610 
1611 //----------------------------------------------------------------------------------------------------
performAlternativeFontChange(UTF8StringPtr fontName,UTF8StringPtr newAlternativeFonts)1612 void UIEditController::performAlternativeFontChange (UTF8StringPtr fontName, UTF8StringPtr newAlternativeFonts)
1613 {
1614 	undoManager->pushAndPerform (new AlternateFontChangeAction (editDescription, fontName, newAlternativeFonts));
1615 }
1616 
1617 //----------------------------------------------------------------------------------------------------
beginLiveColorChange(UTF8StringPtr colorName)1618 void UIEditController::beginLiveColorChange (UTF8StringPtr colorName)
1619 {
1620 	undoManager->startGroupAction ("Change Color");
1621 	CColor color;
1622 	editDescription->getColor(colorName, color);
1623 	performColorChange (colorName, color, false);
1624 }
1625 
1626 //----------------------------------------------------------------------------------------------------
performLiveColorChange(UTF8StringPtr _colorName,const CColor & newColor)1627 void UIEditController::performLiveColorChange (UTF8StringPtr _colorName, const CColor& newColor)
1628 {
1629 	std::string colorName (_colorName);
1630 
1631 	IAction* action =
1632 	    new ColorChangeAction (editDescription, colorName.data (), newColor, false, true);
1633 	action->perform ();
1634 	delete action;
1635 
1636 	std::list<CView*> views;
1637 	getTemplateViews (views);
1638 
1639 	action = new MultipleAttributeChangeAction (editDescription, views, IViewCreator::kColorType,
1640 	                                            colorName.data (), colorName.data ());
1641 	action->perform ();
1642 	delete action;
1643 }
1644 
1645 //----------------------------------------------------------------------------------------------------
endLiveColorChange(UTF8StringPtr colorName)1646 void UIEditController::endLiveColorChange (UTF8StringPtr colorName)
1647 {
1648 	UIDescriptionListenerOff lo (this, editDescription);
1649 	CColor color;
1650 	editDescription->getColor (colorName, color);
1651 	performColorChange (colorName, color, false);
1652 	undoManager->endGroupAction ();
1653 }
1654 
1655 //----------------------------------------------------------------------------------------------------
performTemplateNameChange(UTF8StringPtr oldName,UTF8StringPtr newName)1656 void UIEditController::performTemplateNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
1657 {
1658 	undoManager->pushAndPerform (new TemplateNameChangeAction (editDescription, this, oldName, newName));
1659 }
1660 
1661 //----------------------------------------------------------------------------------------------------
performTemplateMinMaxSizeChange(UTF8StringPtr templateName,CPoint minSize,CPoint maxSize)1662 void UIEditController::performTemplateMinMaxSizeChange (UTF8StringPtr templateName, CPoint minSize, CPoint maxSize)
1663 {
1664 	undoManager->pushAndPerform (
1665 	    new ChangeTemplateMinMaxAction (editDescription, templateName, minSize, maxSize));
1666 }
1667 
1668 //----------------------------------------------------------------------------------------------------
performCreateNewTemplate(UTF8StringPtr name,UTF8StringPtr baseViewClassName)1669 void UIEditController::performCreateNewTemplate (UTF8StringPtr name, UTF8StringPtr baseViewClassName)
1670 {
1671 	undoManager->pushAndPerform (new CreateNewTemplateAction (editDescription, this, name, baseViewClassName));
1672 }
1673 
1674 //----------------------------------------------------------------------------------------------------
performDeleteTemplate(UTF8StringPtr name)1675 void UIEditController::performDeleteTemplate (UTF8StringPtr name)
1676 {
1677 	auto it = std::find (templates.begin (), templates.end (), name);
1678 	if (it != templates.end ())
1679 		undoManager->pushAndPerform (new DeleteTemplateAction (editDescription, this, (*it).view, (*it).name.c_str ()));
1680 }
1681 
1682 //----------------------------------------------------------------------------------------------------
performDuplicateTemplate(UTF8StringPtr name,UTF8StringPtr dupName)1683 void UIEditController::performDuplicateTemplate (UTF8StringPtr name, UTF8StringPtr dupName)
1684 {
1685 	updateTemplate (name);
1686 	UIDescriptionListenerOff lo (this, editDescription);
1687 	undoManager->pushAndPerform (new DuplicateTemplateAction (editDescription, this, name, dupName));
1688 }
1689 
1690 //----------------------------------------------------------------------------------------------------
onTemplateCreation(UTF8StringPtr name,CView * view)1691 void UIEditController::onTemplateCreation (UTF8StringPtr name, CView* view)
1692 {
1693 	auto it = std::find (templates.begin (), templates.end (), name);
1694 	if (it == templates.end ())
1695 		templates.emplace_back (name, view);
1696 	templateController->selectTemplate (name);
1697 }
1698 
1699 //----------------------------------------------------------------------------------------------------
onTemplateNameChange(UTF8StringPtr oldName,UTF8StringPtr newName)1700 void UIEditController::onTemplateNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
1701 {
1702 	auto it = std::find (templates.begin (), templates.end (), oldName);
1703 	if (it != templates.end ())
1704 	{
1705 		(*it).name = newName;
1706 	}
1707 }
1708 
1709 //----------------------------------------------------------------------------------------------------
updateTemplate(const std::vector<Template>::const_iterator & it)1710 void UIEditController::updateTemplate (const std::vector<Template>::const_iterator& it)
1711 {
1712 	if (it != templates.end ())
1713 	{
1714 		CView* view = (*it).view;
1715 		if (auto container = view->asViewContainer ())
1716 			resetScrollViewOffsets (container);
1717 		editDescription->updateViewDescription ((*it).name.c_str (), view);
1718 	}
1719 }
1720 
1721 //----------------------------------------------------------------------------------------------------
updateTemplate(UTF8StringPtr name)1722 void UIEditController::updateTemplate (UTF8StringPtr name)
1723 {
1724 	auto it = std::find (templates.begin (), templates.end (), name);
1725 	updateTemplate (it);
1726 }
1727 
1728 //----------------------------------------------------------------------------------------------------
onTemplatesChanged()1729 void UIEditController::onTemplatesChanged ()
1730 {
1731 	std::list<const std::string*> templateNames;
1732 	editDescription->collectTemplateViewNames (templateNames);
1733 	for (auto& it : templateNames)
1734 	{
1735 		if (std::find (templates.begin (), templates.end (), *it) == templates.end ())
1736 		{
1737 			auto view = owned (editDescription->createView (it->c_str (), editDescription->getController ()));
1738 			templates.emplace_back (*it, view);
1739 		}
1740 	}
1741 	for (std::vector<Template>::iterator it = templates.begin (); it != templates.end ();)
1742 	{
1743 		Template& t = (*it);
1744 		bool found = false;
1745 		for (auto& it2 : templateNames)
1746 		{
1747 			if (t.name == *it2)
1748 			{
1749 				found = true;
1750 				it++;
1751 				break;
1752 			}
1753 		}
1754 		if (!found)
1755 		{
1756 			it = templates.erase (it);
1757 		}
1758 	}
1759 }
1760 
1761 //----------------------------------------------------------------------------------------------------
appendContextMenuItems(COptionMenu & contextMenu,CView * view,const CPoint & where)1762 void UIEditController::appendContextMenuItems (COptionMenu& contextMenu, CView* view, const CPoint& where)
1763 {
1764 	auto vc = view->asViewContainer ();
1765 	if (!vc || editView == nullptr)
1766 		return;
1767 	view = vc->getViewAt (where, GetViewOptions ().deep ().includeViewContainer ());
1768 	while (view && view != editView)
1769 	{
1770 		view = view->getParentView ();
1771 	}
1772 	if (view != editView)
1773 		return;
1774 	auto editMenu = getMenuController ()->getEditMenu ();
1775 	for (auto& entry : *editMenu->getItems ())
1776 	{
1777 		if (auto item = entry.cast<CCommandMenuItem> ())
1778 		{
1779 			item->validate ();
1780 		}
1781 		if (!entry->isEnabled ())
1782 			continue;
1783 		entry->remember ();
1784 		contextMenu.addEntry (entry);
1785 	}
1786 }
1787 
1788 } // namespace
1789 
1790 #endif // VSTGUI_LIVE_EDITING
1791