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