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