From f45a53d6c3748d3150f0054d15326fac32e2c048 Mon Sep 17 00:00:00 2001 From: scheffle Date: Fri, 28 Apr 2023 12:54:40 +0200 Subject: [PATCH 01/11] add leak detector for macos standalone applications --- .../source/platform/mac/macapplication.mm | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/vstgui/standalone/source/platform/mac/macapplication.mm b/vstgui/standalone/source/platform/mac/macapplication.mm index acbc2ec3a..0548f0829 100644 --- a/vstgui/standalone/source/platform/mac/macapplication.mm +++ b/vstgui/standalone/source/platform/mac/macapplication.mm @@ -704,6 +704,24 @@ - (void)application:(nonnull NSApplication*)sender openFiles:(nonnull NSArray Date: Fri, 28 Apr 2023 12:54:48 +0200 Subject: [PATCH 02/11] fix leaks --- vstgui/contrib/datepicker.mm | 3 ++ .../mac/cocoa/nsviewdraggingsession.mm | 2 +- .../editing/uieditmenucontroller.cpp | 30 +++++++++++++++++++ .../editing/uieditmenucontroller.h | 9 ++++-- vstgui/uidescription/uidescription.cpp | 4 +-- vstgui/uidescription/uidescription.h | 3 +- 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/vstgui/contrib/datepicker.mm b/vstgui/contrib/datepicker.mm index aa1a4a245..9aa020149 100644 --- a/vstgui/contrib/datepicker.mm +++ b/vstgui/contrib/datepicker.mm @@ -141,6 +141,9 @@ static void validate (id self, SEL cmd, NSDatePickerCell* datePickerCell, dateComponents.month = date.month; dateComponents.year = date.year; impl->view.dateValue = [calendar dateFromComponents:dateComponents]; +#if !__has_feature(objc_arc) + [dateComponents release]; +#endif } //------------------------------------------------------------------------ diff --git a/vstgui/lib/platform/mac/cocoa/nsviewdraggingsession.mm b/vstgui/lib/platform/mac/cocoa/nsviewdraggingsession.mm index 6ab7ab439..3aa4fff2a 100644 --- a/vstgui/lib/platform/mac/cocoa/nsviewdraggingsession.mm +++ b/vstgui/lib/platform/mac/cocoa/nsviewdraggingsession.mm @@ -252,7 +252,7 @@ static Class CreateClass () //----------------------------------------------------------------------------- NSImage* NSViewDraggingSession::nsImageForDragOperation (CBitmap* bitmap) { - return bitmapToNSImage (bitmap); + return [bitmapToNSImage (bitmap) autorelease]; } //------------------------------------------------------------------------ diff --git a/vstgui/uidescription/editing/uieditmenucontroller.cpp b/vstgui/uidescription/editing/uieditmenucontroller.cpp index d8dbadc18..59bb6f569 100644 --- a/vstgui/uidescription/editing/uieditmenucontroller.cpp +++ b/vstgui/uidescription/editing/uieditmenucontroller.cpp @@ -30,6 +30,15 @@ UIEditMenuController::UIEditMenuController (IController* baseController, UISelec { } +//------------------------------------------------------------------------ +UIEditMenuController::~UIEditMenuController () noexcept +{ + if (editMenu) + editMenu->unregisterViewListener (this); + if (fileMenu) + fileMenu->unregisterViewListener (this); +} + //---------------------------------------------------------------------------------------------------- static void addEntriesToMenu (const UIEditing::MenuEntry* entries, COptionMenu* menu, ICommandMenuItemTarget* menuItemTarget, int32_t& index) { @@ -615,6 +624,21 @@ static void copyMenuItems (COptionMenu* src, COptionMenu* dst) } } +//------------------------------------------------------------------------ +void UIEditMenuController::viewRemoved (CView* view) +{ + if (view == editMenu) + { + view->unregisterViewListener (this); + editMenu = nullptr; + } + else if (view == fileMenu) + { + view->unregisterViewListener (this); + fileMenu = nullptr; + } +} + //---------------------------------------------------------------------------------------------------- CView* UIEditMenuController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription*) { @@ -628,7 +652,10 @@ CView* UIEditMenuController::verifyView (CView* view, const UIAttributes& attrib if (editMenu) copyMenuItems (editMenu, menu); else + { createEditMenu (menu); + menu->registerViewListener (this); + } editMenu = menu; break; } @@ -637,7 +664,10 @@ CView* UIEditMenuController::verifyView (CView* view, const UIAttributes& attrib if (fileMenu) copyMenuItems (fileMenu, menu); else + { createFileMenu (menu); + menu->registerViewListener (this); + } fileMenu = menu; break; } diff --git a/vstgui/uidescription/editing/uieditmenucontroller.h b/vstgui/uidescription/editing/uieditmenucontroller.h index e54ac86d8..f9cc94e95 100644 --- a/vstgui/uidescription/editing/uieditmenucontroller.h +++ b/vstgui/uidescription/editing/uieditmenucontroller.h @@ -13,6 +13,7 @@ #include "../delegationcontroller.h" #include "../../lib/controls/icommandmenuitemtarget.h" #include "../../lib/events.h" +#include "../../lib/iviewlistener.h" namespace VSTGUI { class IActionPerformer; @@ -144,11 +145,14 @@ static const MenuEntry fileMenu[] = { } // UIEditing //---------------------------------------------------------------------------------------------------- -class UIEditMenuController : public CBaseObject, public DelegationController, public CommandMenuItemTargetAdapter +class UIEditMenuController : public CBaseObject, + public DelegationController, + public CommandMenuItemTargetAdapter, + public ViewListenerAdapter { public: UIEditMenuController (IController* baseController, UISelection* selection, UIUndoManager* undoManager, UIDescription* description, IActionPerformer* actionPerformer); - ~UIEditMenuController () noexcept override = default; + ~UIEditMenuController () noexcept override; COptionMenu* getFileMenu () const { return fileMenu; } COptionMenu* getEditMenu () const { return editMenu; } @@ -170,6 +174,7 @@ class UIEditMenuController : public CBaseObject, public DelegationController, pu void createEditMenu (COptionMenu* menu); void createFileMenu (COptionMenu* menu); + void viewRemoved (CView* view) override; CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override; IControlListener* getControlListener (UTF8StringPtr name) override { return this; } void controlBeginEdit (CControl* pControl) override; diff --git a/vstgui/uidescription/uidescription.cpp b/vstgui/uidescription/uidescription.cpp index 7adf10bcb..adec79c5e 100644 --- a/vstgui/uidescription/uidescription.cpp +++ b/vstgui/uidescription/uidescription.cpp @@ -567,7 +567,8 @@ Detail::UINode* UIDescription::findNodeForView (CView* view) const } //----------------------------------------------------------------------------- -bool UIDescription::storeViews (const std::list& views, OutputStream& stream, UIAttributes* customData) const +bool UIDescription::storeViews (const std::list& views, OutputStream& stream, + SharedPointer customData) const { auto nodeList = makeOwned (false); for (auto& view : views) @@ -599,7 +600,6 @@ bool UIDescription::storeViews (const std::list& views, OutputStream& st UINode* customNode = new UINode (Detail::MainNodeNames::kCustom, customData); nodeList->add (customNode); customNode->forget (); - customData->remember (); } UINode baseNode ("vstgui-ui-description-view-list", nodeList); return Detail::UIJsonDescWriter::write (stream, &baseNode, false); diff --git a/vstgui/uidescription/uidescription.h b/vstgui/uidescription/uidescription.h index afcb2f665..5ad547dc3 100644 --- a/vstgui/uidescription/uidescription.h +++ b/vstgui/uidescription/uidescription.h @@ -52,7 +52,8 @@ class UIDescription : public NonAtomicReferenceCounted, public IUIDescription AttributeSaveFilterFunc func = nullptr); virtual bool saveWindowsRCFile (UTF8StringPtr filename); - bool storeViews (const std::list& views, OutputStream& stream, UIAttributes* customData = nullptr) const; + bool storeViews (const std::list& views, OutputStream& stream, + SharedPointer customData = {}) const; bool restoreViews (InputStream& stream, std::list >& views, UIAttributes** customData = nullptr); UTF8StringPtr getFilePath () const; From c62640865ba31eb326bd97e3dc0388e6681062cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Hansen?= Date: Fri, 18 Aug 2023 18:46:09 +0200 Subject: [PATCH 03/11] Implement radial gradient with cairo --- vstgui/lib/platform/linux/cairogradient.cpp | 15 ++++++---- vstgui/lib/platform/linux/cairogradient.h | 3 +- .../platform/linux/cairographicscontext.cpp | 29 +++++++++++++++++-- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/vstgui/lib/platform/linux/cairogradient.cpp b/vstgui/lib/platform/linux/cairogradient.cpp index 9488d9916..0338909cc 100644 --- a/vstgui/lib/platform/linux/cairogradient.cpp +++ b/vstgui/lib/platform/linux/cairogradient.cpp @@ -44,22 +44,25 @@ const PatternHandle& Gradient::getLinearGradient (CPoint start, CPoint end) cons } //------------------------------------------------------------------------ -const PatternHandle& Gradient::getRadialGradient () +const PatternHandle& Gradient::getRadialGradient (CPoint center, CCoord radius, + CPoint originOffset) const { if (!radialGradient) { - radialGradient = PatternHandle (cairo_pattern_create_radial (0, 0, 1, 0, 0, 1)); + auto end = center + originOffset; + radialGradient = PatternHandle ( + cairo_pattern_create_radial (center.x, center.y, 0., center.x, center.y, radius)); + for (auto& it : getColorStops ()) { cairo_pattern_add_color_stop_rgba ( - radialGradient, it.first, it.second.normRed (), - it.second.normGreen (), it.second.normBlue (), - it.second.normAlpha ()); + radialGradient, it.first, it.second.normRed (), + it.second.normGreen (), it.second.normBlue (), + it.second.normAlpha ()); } } return radialGradient; } - //------------------------------------------------------------------------ } // Cairo } // VSTGUI diff --git a/vstgui/lib/platform/linux/cairogradient.h b/vstgui/lib/platform/linux/cairogradient.h index 785247db9..e0eb8453c 100644 --- a/vstgui/lib/platform/linux/cairogradient.h +++ b/vstgui/lib/platform/linux/cairogradient.h @@ -20,7 +20,8 @@ class Gradient : public PlatformGradientBase ~Gradient () noexcept override; const PatternHandle& getLinearGradient (CPoint start, CPoint end) const; - const PatternHandle& getRadialGradient (); + const PatternHandle& getRadialGradient (CPoint center, CCoord radius, + CPoint originOffset) const; private: void changed () override; diff --git a/vstgui/lib/platform/linux/cairographicscontext.cpp b/vstgui/lib/platform/linux/cairographicscontext.cpp index ab620cc91..ed7e493fd 100644 --- a/vstgui/lib/platform/linux/cairographicscontext.cpp +++ b/vstgui/lib/platform/linux/cairographicscontext.cpp @@ -624,8 +624,33 @@ bool CairoGraphicsDeviceContext::fillRadialGradient (IPlatformGraphicsPath& path auto cairoPath = dynamic_cast (&path); if (!cairoPath) return false; - // TODO: Implementation - return false; + + auto cairoGradient = dynamic_cast (&gradient); + if (!cairoGradient) + return false; + impl->doInContext ([&] () { + std::unique_ptr alignedPath; + if (impl->state.drawMode.integralMode ()) + { + alignedPath = cairoPath->copyPixelAlign ([&] (CPoint p) { + p = pixelAlign (impl->state.tm, p); + return p; + }); + } + auto p = alignedPath ? alignedPath->getCairoPath () : cairoPath->getCairoPath (); + cairo_append_path (impl->context, p); + + const auto& radialGradient = + cairoGradient->getRadialGradient (center, radius, originOffset); + cairo_set_source (impl->context, radialGradient); + if (evenOdd) + cairo_set_fill_rule (impl->context, CAIRO_FILL_RULE_EVEN_ODD); + + cairo_arc (impl->context, 0, 0, 0, 0., M_PI * 2.); + cairo_fill (impl->context); + }); + + return true; } //------------------------------------------------------------------------ From b64c305f69f0ab4de573821c12de2b3a76cc95cb Mon Sep 17 00:00:00 2001 From: rehans Date: Fri, 18 Aug 2023 18:58:23 +0200 Subject: [PATCH 04/11] Remove debug line --- vstgui/lib/platform/linux/cairogradient.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/vstgui/lib/platform/linux/cairogradient.cpp b/vstgui/lib/platform/linux/cairogradient.cpp index 0338909cc..296141690 100644 --- a/vstgui/lib/platform/linux/cairogradient.cpp +++ b/vstgui/lib/platform/linux/cairogradient.cpp @@ -49,7 +49,6 @@ const PatternHandle& Gradient::getRadialGradient (CPoint center, CCoord radius, { if (!radialGradient) { - auto end = center + originOffset; radialGradient = PatternHandle ( cairo_pattern_create_radial (center.x, center.y, 0., center.x, center.y, radius)); From 56862d75b1a6205c8343dad7fc3cc73287c4606a Mon Sep 17 00:00:00 2001 From: scheffle Date: Sat, 7 Oct 2023 17:58:32 +0200 Subject: [PATCH 05/11] filter out some attributes The attributes like `min-value`, `max-value`, `default-value`, `mouse-enabled` and the `title` attribute for text labels/edit fields are now filtered for controls which are managed by parameters, which will always override these values. --- vstgui/plugin-bindings/vst3editor.cpp | 25 +++- .../examples/standalone/resource/test.uidesc | 111 +----------------- .../source/uidescriptionwindowcontroller.cpp | 25 +++- 3 files changed, 54 insertions(+), 107 deletions(-) diff --git a/vstgui/plugin-bindings/vst3editor.cpp b/vstgui/plugin-bindings/vst3editor.cpp index 0f9de0cdf..9ac05d1d0 100644 --- a/vstgui/plugin-bindings/vst3editor.cpp +++ b/vstgui/plugin-bindings/vst3editor.cpp @@ -1534,7 +1534,30 @@ void VST3Editor::save (bool saveAs) } if (savePath.empty ()) return; - if (description->save (savePath.c_str (), VST3EditorInternal::getUIDescriptionSaveOptions (frame))) + + // filter out attributes we will always override with the values from the parameters + auto filter = [] (CView* view, const std::string& name) -> bool { + if (auto control = dynamic_cast (view)) + { + if (control->getTag () != -1) + { + if (name == UIViewCreator::kAttrMinValue) + return false; + if (name == UIViewCreator::kAttrMaxValue) + return false; + if (name == UIViewCreator::kAttrDefaultValue) + return false; + if (name == UIViewCreator::kAttrMouseEnabled) + return false; + if (name == UIViewCreator::kAttrTitle && dynamic_cast (control)) + return false; + } + } + return true; + }; + + if (description->save (savePath.c_str (), + VST3EditorInternal::getUIDescriptionSaveOptions (frame), filter)) description->setFilePath (savePath.c_str ()); } diff --git a/vstgui/standalone/examples/standalone/resource/test.uidesc b/vstgui/standalone/examples/standalone/resource/test.uidesc index e31b0a38c..fe3b7cd71 100644 --- a/vstgui/standalone/examples/standalone/resource/test.uidesc +++ b/vstgui/standalone/examples/standalone/resource/test.uidesc @@ -41,7 +41,7 @@ "SelectedRow": "4" }, "UIDescFilePath": { - "path": "/Users/scheffle/git/vstgui/vstgui/standalone/examples/standalone/resource/test.uidesc" + "path": "/Users/scheffle/Source/vstgui/vstgui/standalone/examples/standalone/resource/test.uidesc" }, "UITagsDataSource": { "SelectedRow": "-1" @@ -139,14 +139,10 @@ "checkmark-color": "~ WhiteCColor", "class": "CCheckBox", "control-tag": "Activate", - "default-value": "0.5", "draw-crossbox": "true", "font": "~ SystemFont", "font-color": "~ WhiteCColor", "frame-width": "1", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "20, 10", "round-rect-radius": "2", @@ -163,7 +159,6 @@ "bitmap-offset": "0, 0", "class": "CSlider", "control-tag": "Test", - "default-value": "0.5", "draw-back": "true", "draw-back-color": "~ WhiteCColor", "draw-frame": "true", @@ -174,10 +169,7 @@ "draw-value-inverted": "true", "frame-width": "1", "handle-offset": "0, 0", - "max-value": "1", - "min-value": "0", "mode": "free click", - "mouse-enabled": "true", "opacity": "1", "orientation": "vertical", "origin": "10, 50", @@ -196,16 +188,12 @@ "back-color-selected": "TextShadow", "class": "CStringListControl", "control-tag": "Weekdays", - "default-value": "0.5", "font": "~ NormalFont", "font-color": "~ BlackCColor", "font-color-selected": "~ BlackCColor", "hover-color": "Hover", "line-color": "~ BlackCColor", "line-width": "-1", - "max-value": "7", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "15, 200", "row-height": "16", @@ -227,16 +215,12 @@ "background-offset": "0, 0", "class": "CTextEdit", "control-tag": "MutableString", - "default-value": "0.5", "font": "~ NormalFont", "font-antialias": "true", "font-color": "~ WhiteCColor", "frame-color": "~ WhiteCColor", "frame-width": "1", "immediate-text-change": "true", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "40, 50", "round-rect-radius": "3", @@ -255,7 +239,6 @@ "text-inset": "0, 0", "text-rotation": "0", "text-shadow-offset": "1, 1", - "title": "This is a string value", "tooltip": "Text Edit", "transparent": "false", "value-precision": "2", @@ -269,7 +252,6 @@ "bitmap-offset": "0, 0", "class": "CSlider", "control-tag": "Test", - "default-value": "0.5", "draw-back": "true", "draw-back-color": "~ WhiteCColor", "draw-frame": "true", @@ -280,10 +262,7 @@ "draw-value-inverted": "false", "frame-width": "1", "handle-offset": "0, 0", - "max-value": "1", - "min-value": "0", "mode": "free click", - "mouse-enabled": "true", "opacity": "1", "orientation": "horizontal", "origin": "40, 80", @@ -301,7 +280,6 @@ "autosize": "right top ", "class": "CTextButton", "control-tag": "ShowPopup", - "default-value": "0.5", "font": "~ SystemFont", "frame-color": "~ BlackCColor", "frame-color-highlighted": "~ BlackCColor", @@ -311,9 +289,6 @@ "icon-position": "left", "icon-text-margin": "0", "kick-style": "false", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "280, 80", "round-radius": "10", @@ -333,16 +308,12 @@ "autosize": "left right top ", "class": "CSegmentButton", "control-tag": "StepTest", - "default-value": "0.5", "font": "~ NormalFont", "frame-color": "~ BlackCColor", "frame-width": "1", "gradient": "Default TextButton Gradient", "gradient-highlighted": "Default TextButton Gradient Highlighted", "icon-text-margin": "0", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "40, 110", "round-radius": "3", @@ -365,7 +336,6 @@ "bitmap-offset": "0, 0", "class": "CSlider", "control-tag": "StepTest", - "default-value": "0.5", "draw-back": "true", "draw-back-color": "~ WhiteCColor", "draw-frame": "true", @@ -376,10 +346,7 @@ "draw-value-inverted": "false", "frame-width": "1", "handle-offset": "0, 0", - "max-value": "1", - "min-value": "0", "mode": "free click", - "mouse-enabled": "true", "opacity": "1", "orientation": "horizontal", "origin": "40, 140", @@ -397,16 +364,12 @@ "autosize": "left right top ", "class": "CSegmentButton", "control-tag": "StringList", - "default-value": "0.5", "font": "~ NormalFont", "frame-color": "~ BlackCColor", "frame-width": "1", "gradient": "Default TextButton Gradient", "gradient-highlighted": "Default TextButton Gradient Highlighted", "icon-text-margin": "0", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "40, 170", "round-radius": "3", @@ -427,7 +390,6 @@ "attributes": { "class": "CTextButton", "control-tag": "ShowAlert", - "default-value": "0.5", "font": "~ SystemFont", "frame-color": "~ BlackCColor", "frame-color-highlighted": "~ BlackCColor", @@ -437,9 +399,6 @@ "icon-position": "left", "icon-text-margin": "0", "kick-style": "false", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "170, 210", "round-radius": "3", @@ -461,15 +420,11 @@ "background-offset": "0, 0", "class": "CParamDisplay", "control-tag": "Test", - "default-value": "0.5", "font": "~ NormalFont", "font-antialias": "true", "font-color": "~ WhiteCColor", "frame-color": "~ WhiteCColor", "frame-width": "1", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "310, 50", "round-rect-radius": "3", @@ -500,16 +455,12 @@ "background-offset": "0, 0", "class": "CTextEdit", "control-tag": "Test", - "default-value": "0.5", "font": "~ NormalFont", "font-antialias": "true", "font-color": "~ WhiteCColor", "frame-color": "~ WhiteCColor", "frame-width": "1", "immediate-text-change": "false", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "310, 80", "round-rect-radius": "3", @@ -528,7 +479,6 @@ "text-inset": "0, 0", "text-rotation": "0", "text-shadow-offset": "1, 1", - "title": "0.00", "tooltip": "Text Edit", "transparent": "false", "value-precision": "2", @@ -543,16 +493,12 @@ "background-offset": "0, 0", "class": "CTextEdit", "control-tag": "StepTest", - "default-value": "0.5", "font": "~ NormalFont", "font-antialias": "true", "font-color": "~ WhiteCColor", "frame-color": "~ WhiteCColor", "frame-width": "1", "immediate-text-change": "false", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "310, 110", "round-rect-radius": "6", @@ -571,7 +517,6 @@ "text-inset": "0, 0", "text-rotation": "0", "text-shadow-offset": "1, 1", - "title": "0", "tooltip": "Text Edit", "transparent": "false", "value-precision": "2", @@ -586,17 +531,13 @@ "background-offset": "0, 0", "class": "COptionMenu", "control-tag": "StepTest", - "default-value": "0.5", "font": "~ NormalFont", "font-antialias": "true", "font-color": "~ WhiteCColor", "frame-color": "~ WhiteCColor", "frame-width": "1", - "max-value": "4", "menu-check-style": "true", "menu-popup-style": "true", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "310, 140", "round-rect-radius": "6", @@ -627,17 +568,13 @@ "background-offset": "0, 0", "class": "COptionMenu", "control-tag": "StringList", - "default-value": "0.5", "font": "~ NormalFont", "font-antialias": "true", "font-color": "~ WhiteCColor", "frame-color": "~ WhiteCColor", "frame-width": "1", - "max-value": "4", "menu-check-style": "true", "menu-popup-style": "true", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "310, 170", "round-rect-radius": "6", @@ -668,16 +605,12 @@ "background-offset": "0, 0", "class": "CTextEdit", "control-tag": "StringList", - "default-value": "0.5", "font": "~ NormalFont", "font-antialias": "true", "font-color": "~ WhiteCColor", "frame-color": "~ WhiteCColor", "frame-width": "1", "immediate-text-change": "false", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "310, 200", "round-rect-radius": "6", @@ -696,7 +629,6 @@ "text-inset": "0, 0", "text-rotation": "0", "text-shadow-offset": "1, 1", - "title": "one", "tooltip": "Text Edit", "transparent": "false", "value-precision": "2", @@ -781,7 +713,6 @@ "attributes": { "class": "CTextButton", "control-tag": "ShowAlert2", - "default-value": "0.5", "font": "~ SystemFont", "frame-color": "~ BlackCColor", "frame-color-highlighted": "~ BlackCColor", @@ -791,9 +722,6 @@ "icon-position": "left", "icon-text-margin": "0", "kick-style": "false", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "170, 235", "round-radius": "3", @@ -812,7 +740,6 @@ "attributes": { "class": "CTextButton", "control-tag": "ShowAlert3", - "default-value": "0.5", "font": "~ SystemFont", "frame-color": "~ BlackCColor", "frame-color-highlighted": "~ BlackCColor", @@ -822,9 +749,6 @@ "icon-position": "left", "icon-text-margin": "0", "kick-style": "false", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "170, 260", "round-radius": "3", @@ -847,14 +771,12 @@ "bitmap": "knob", "class": "CAnimKnob", "control-tag": "Test", - "default-value": "0.5", + "height-of-one-image": "50", "inverse-bitmap": "false", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "340, 235", "size": "50, 50", + "sub-pixmaps": "6", "tooltip": "Knob", "transparent": "false", "value-inset": "5", @@ -881,13 +803,9 @@ "corona-line-cap-butt": "true", "corona-outline": "true", "corona-outline-width-add": "2", - "default-value": "0.5", "handle-color": "~ WhiteCColor", "handle-line-width": "8", "handle-shadow-color": "~ BlackCColor", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "270, 225", "size": "70, 70", @@ -907,15 +825,11 @@ "background-offset": "0, 0", "class": "CParamDisplay", "control-tag": "MutableString", - "default-value": "0.5", "font": "~ NormalFont", "font-antialias": "true", "font-color": "~ BlackCColor", "frame-color": "~ BlackCColor", "frame-width": "-1", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "120, 10", "round-rect-radius": "3", @@ -984,10 +898,6 @@ "class": "CControl", "control-tag": "Activate", "custom-view-name": "Native Checkbox", - "default-value": "0.5", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "5, 40", "size": "110, 20", @@ -1000,11 +910,8 @@ "CControl": { "attributes": { "class": "CControl", + "control-tag": "Activate", "custom-view-name": "Native Push Button", - "default-value": "0.5", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "0, 65", "size": "100, 24", @@ -1017,11 +924,8 @@ "CControl": { "attributes": { "class": "CControl", + "control-tag": "Activate", "custom-view-name": "Native OnOff Button", - "default-value": "0.5", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "0, 90", "size": "100, 25", @@ -1034,11 +938,8 @@ "CControl": { "attributes": { "class": "CControl", + "control-tag": "Activate", "custom-view-name": "Native Radio Button", - "default-value": "0.5", - "max-value": "1", - "min-value": "0", - "mouse-enabled": "true", "opacity": "1", "origin": "5, 120", "size": "100, 20", diff --git a/vstgui/standalone/source/uidescriptionwindowcontroller.cpp b/vstgui/standalone/source/uidescriptionwindowcontroller.cpp index def26b93e..e22354ef1 100644 --- a/vstgui/standalone/source/uidescriptionwindowcontroller.cpp +++ b/vstgui/standalone/source/uidescriptionwindowcontroller.cpp @@ -792,7 +792,30 @@ struct WindowController::EditImpl : WindowController::Impl Detail::saveSharedUIDescription (); int32_t flags = UIDescription::kWriteImagesIntoUIDescFile | CompressedUIDescription::kForceWriteCompressedDesc; - if (!uiDesc->save (uiDesc->getFilePath (), flags)) + + // filter out attributes we will always override with the values from the parameters + auto filter = [] (CView* view, const std::string& name) -> bool { + if (auto control = dynamic_cast (view)) + { + if (control->getTag () >= 0) + { + if (name == UIViewCreator::kAttrMinValue) + return false; + if (name == UIViewCreator::kAttrMaxValue) + return false; + if (name == UIViewCreator::kAttrDefaultValue) + return false; + if (name == UIViewCreator::kAttrMouseEnabled) + return false; + if (name == UIViewCreator::kAttrTitle && + dynamic_cast (control)) + return false; + } + } + return true; + }; + + if (!uiDesc->save (uiDesc->getFilePath (), flags, filter)) { AlertBoxConfig config; config.headline = "Saving the uidesc file failed."; From 4e2c80bbb84def25d389e292d58f0399dc0d2b2f Mon Sep 17 00:00:00 2001 From: scheffle Date: Sun, 15 Oct 2023 10:37:08 +0200 Subject: [PATCH 06/11] fix #308 Change the clip to be always axis aligned as the layer approach doesn't work any more. --- .../win32/direct2d/d2dgraphicscontext.cpp | 46 ++++--------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp b/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp index d16758672..9a9e77426 100644 --- a/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp +++ b/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp @@ -166,49 +166,19 @@ struct D2DGraphicsDeviceContext::Impl auto transform = convert (tmGuard.matrix) * globalTM * state.tm; transform.scale (scaleFactor, scaleFactor); transform.translate (transformOffset); - bool useLayer = transform.m12 != 0. || transform.m21 != 0.; - if (useLayer) - { // we have a rotated matrix, we need to use a layer - COM::Ptr factory {}; - deviceContext->GetFactory (factory.adoptPtr ()); - COM::Ptr geometry; - if (SUCCEEDED ( - factory->CreateRectangleGeometry (convert (state.clip), geometry.adoptPtr ()))) - { - if (applyClip.isEmpty () == false) - deviceContext->PopAxisAlignedClip (); - deviceContext->PushLayer (D2D1::LayerParameters (D2D1::InfiniteRect (), - geometry.get (), - D2D1_ANTIALIAS_MODE_ALIASED), - nullptr); - geometry->Release (); - applyClip = state.clip; - } - else - { - useLayer = false; - } - } - if (!useLayer) + auto newClip = state.clip; + globalTM.transform (newClip); + if (applyClip != newClip) { - auto newClip = state.clip; - globalTM.transform (newClip); - if (applyClip != newClip) - { - if (applyClip.isEmpty () == false) - deviceContext->PopAxisAlignedClip (); - if (newClip.isEmpty () == false) - deviceContext->PushAxisAlignedClip (convert (newClip), - D2D1_ANTIALIAS_MODE_ALIASED); - applyClip = newClip; - } + if (applyClip.isEmpty () == false) + deviceContext->PopAxisAlignedClip (); + if (newClip.isEmpty () == false) + deviceContext->PushAxisAlignedClip (convert (newClip), D2D1_ANTIALIAS_MODE_ALIASED); + applyClip = newClip; } deviceContext->SetTransform (convert (transform)); p (deviceContext.get ()); - - if (useLayer) - deviceContext->PopLayer (); } //----------------------------------------------------------------------------- From 61a95ebc66d67705574a0d84a4b8313e73a9c66c Mon Sep 17 00:00:00 2001 From: Reimund Dratwa Date: Wed, 18 Oct 2023 16:01:29 +0200 Subject: [PATCH 07/11] Allow for knob specific mouse sensitivity via CKnobBase::setKnobRange() --- vstgui/lib/controls/cknob.cpp | 9 +++++---- vstgui/lib/controls/cknob.h | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/vstgui/lib/controls/cknob.cpp b/vstgui/lib/controls/cknob.cpp index 53f247a5f..074fe5953 100644 --- a/vstgui/lib/controls/cknob.cpp +++ b/vstgui/lib/controls/cknob.cpp @@ -13,9 +13,9 @@ namespace VSTGUI { #if TARGET_OS_IPHONE -static const float kCKnobRange = 300.f; +static const float kCKnobRangeDefault = 300.f; #else -static const float kCKnobRange = 200.f; +static const float kCKnobRangeDefault = 200.f; #endif static constexpr CViewAttributeID kCKnobMouseStateAttribute = 'knms'; @@ -40,6 +40,7 @@ CKnobBase::CKnobBase (const CRect& size, IControlListener* listener, int32_t tag setStartAngle ((float)(3.f * Constants::quarter_pi)); setRangeAngle ((float)(3.f * Constants::half_pi)); zoomFactor = 1.5f; + knobRange = kCKnobRangeDefault; } //------------------------------------------------------------------------ @@ -112,7 +113,7 @@ CMouseEventResult CKnobBase::onMouseDown (CPoint& where, const CButtonState& but mouseState.modeLinear = false; mouseState.entryState = value; - mouseState.range = kCKnobRange; + mouseState.range = knobRange; mouseState.coef = (getMax () - getMin ()) / mouseState.range; mouseState.oldButton = buttons; @@ -193,7 +194,7 @@ CMouseEventResult CKnobBase::onMouseMoved (CPoint& where, const CButtonState& bu CCoord diff = (mouseState.firstPoint.y - where.y) + (where.x - mouseState.firstPoint.x); if (buttons != mouseState.oldButton) { - mouseState.range = kCKnobRange; + mouseState.range = knobRange; if (buttons & kZoomModifier) mouseState.range *= zoomFactor; diff --git a/vstgui/lib/controls/cknob.h b/vstgui/lib/controls/cknob.h index 0f5eb538a..11a0fb9eb 100644 --- a/vstgui/lib/controls/cknob.h +++ b/vstgui/lib/controls/cknob.h @@ -33,6 +33,8 @@ class CKnobBase : public CControl, protected CMouseWheelEditingSupport virtual CCoord getInsetValue () const { return inset; } virtual void setInsetValue (CCoord val) { inset = val; } + + virtual void setKnobRange (float val) { if(val > 0.f) range = val; } //@} // overrides @@ -56,6 +58,7 @@ class CKnobBase : public CControl, protected CMouseWheelEditingSupport float startAngle, rangeAngle; float zoomFactor; + float knobRange; CCoord inset; private: From 5f813ff901a8ace4dc6e946d7b4386fe239b33ee Mon Sep 17 00:00:00 2001 From: Reimund Dratwa Date: Wed, 18 Oct 2023 16:04:23 +0200 Subject: [PATCH 08/11] Fix previous commit --- vstgui/lib/controls/cknob.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vstgui/lib/controls/cknob.h b/vstgui/lib/controls/cknob.h index 11a0fb9eb..a616525fe 100644 --- a/vstgui/lib/controls/cknob.h +++ b/vstgui/lib/controls/cknob.h @@ -34,7 +34,7 @@ class CKnobBase : public CControl, protected CMouseWheelEditingSupport virtual CCoord getInsetValue () const { return inset; } virtual void setInsetValue (CCoord val) { inset = val; } - virtual void setKnobRange (float val) { if(val > 0.f) range = val; } + virtual void setKnobRange (float val) { if(val > 0.f) knobRange = val; } //@} // overrides From a964da817841e7cde7e44c539e7aa75c2d485cb1 Mon Sep 17 00:00:00 2001 From: Reimund Dratwa Date: Wed, 18 Oct 2023 18:42:46 +0200 Subject: [PATCH 09/11] Add CKnobBase::getKnobRange() --- vstgui/lib/controls/cknob.h | 1 + 1 file changed, 1 insertion(+) diff --git a/vstgui/lib/controls/cknob.h b/vstgui/lib/controls/cknob.h index a616525fe..722216429 100644 --- a/vstgui/lib/controls/cknob.h +++ b/vstgui/lib/controls/cknob.h @@ -35,6 +35,7 @@ class CKnobBase : public CControl, protected CMouseWheelEditingSupport virtual void setInsetValue (CCoord val) { inset = val; } virtual void setKnobRange (float val) { if(val > 0.f) knobRange = val; } + virtual float getKnobRange () const { return knobRange; } //@} // overrides From 46e9cbf7287fd6717355592a438619aae21986e5 Mon Sep 17 00:00:00 2001 From: scheffle Date: Thu, 19 Oct 2023 09:17:57 +0200 Subject: [PATCH 10/11] adapt code style Co-authored-by: Nick Dowell --- vstgui/lib/controls/cknob.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vstgui/lib/controls/cknob.h b/vstgui/lib/controls/cknob.h index 722216429..08e5bdf3c 100644 --- a/vstgui/lib/controls/cknob.h +++ b/vstgui/lib/controls/cknob.h @@ -34,7 +34,7 @@ class CKnobBase : public CControl, protected CMouseWheelEditingSupport virtual CCoord getInsetValue () const { return inset; } virtual void setInsetValue (CCoord val) { inset = val; } - virtual void setKnobRange (float val) { if(val > 0.f) knobRange = val; } + virtual void setKnobRange (float val) { if (val > 0.f) knobRange = val; } virtual float getKnobRange () const { return knobRange; } //@} From 47288841a03379b3ad25b6a72a9416d19cfa6b00 Mon Sep 17 00:00:00 2001 From: scheffle Date: Sun, 22 Oct 2023 16:53:21 +0200 Subject: [PATCH 11/11] add new knob range attribute to uidesc editor --- .../examples/standalone/source/testappdelegate.cpp | 1 + .../uidescription/uiviewcreator/cknobcreator_test.cpp | 7 +++++++ vstgui/uidescription/detail/uiviewcreatorattributes.h | 1 + vstgui/uidescription/viewcreator/knobcreator.cpp | 10 ++++++++++ 4 files changed, 19 insertions(+) diff --git a/vstgui/standalone/examples/standalone/source/testappdelegate.cpp b/vstgui/standalone/examples/standalone/source/testappdelegate.cpp index 82db77376..93e61d2ba 100644 --- a/vstgui/standalone/examples/standalone/source/testappdelegate.cpp +++ b/vstgui/standalone/examples/standalone/source/testappdelegate.cpp @@ -222,6 +222,7 @@ class DatePickerController : public DelegationController Delegate::Delegate () : Application::DelegateAdapter ({"VSTGUI Standalone", "1.0.0", VSTGUI_STANDALONE_APP_URI}) { + CFrame::kDefaultKnobMode = CKnobMode::kLinearMode; } //------------------------------------------------------------------------ diff --git a/vstgui/tests/unittest/uidescription/uiviewcreator/cknobcreator_test.cpp b/vstgui/tests/unittest/uidescription/uiviewcreator/cknobcreator_test.cpp index 3f761eae5..0d47e6224 100644 --- a/vstgui/tests/unittest/uidescription/uiviewcreator/cknobcreator_test.cpp +++ b/vstgui/tests/unittest/uidescription/uiviewcreator/cknobcreator_test.cpp @@ -31,6 +31,13 @@ TEST_CASE (CKnobCreatorTest, AngleRange) }); } +TEST_CASE (CKnobCreatorTest, KnobRange) +{ + DummyUIDescription uidesc; + testAttribute (kCKnob, kAttrKnobRange, 200., &uidesc, + [&] (CKnob* v) { return v->getKnobRange () == 200.; }); +} + TEST_CASE (CKnobCreatorTest, ValueInset) { DummyUIDescription uidesc; diff --git a/vstgui/uidescription/detail/uiviewcreatorattributes.h b/vstgui/uidescription/detail/uiviewcreatorattributes.h index 2516394dc..01efff7d6 100644 --- a/vstgui/uidescription/detail/uiviewcreatorattributes.h +++ b/vstgui/uidescription/detail/uiviewcreatorattributes.h @@ -216,6 +216,7 @@ static const std::string kAttrSegmentNames = "segment-names"; //----------------------------------------------------------------------------- static const std::string kAttrAngleStart = "angle-start"; static const std::string kAttrAngleRange = "angle-range"; +static const std::string kAttrKnobRange = "knob-range"; static const std::string kAttrValueInset = "value-inset"; static const std::string kAttrCoronaInset = "corona-inset"; static const std::string kAttrCoronaColor = "corona-color"; diff --git a/vstgui/uidescription/viewcreator/knobcreator.cpp b/vstgui/uidescription/viewcreator/knobcreator.cpp index fbe78dc6d..5ba6f4187 100644 --- a/vstgui/uidescription/viewcreator/knobcreator.cpp +++ b/vstgui/uidescription/viewcreator/knobcreator.cpp @@ -35,6 +35,8 @@ bool KnobBaseCreator::apply (CView* view, const UIAttributes& attributes, d = d / 180.f * static_cast (Constants::pi); knob->setRangeAngle (static_cast (d)); } + if (attributes.getDoubleAttribute (kAttrKnobRange, d)) + knob->setKnobRange (static_cast (d)); if (attributes.getDoubleAttribute (kAttrValueInset, d)) knob->setInsetValue (d); if (attributes.getDoubleAttribute (kAttrZoomFactor, d)) @@ -48,6 +50,7 @@ bool KnobBaseCreator::getAttributeNames (StringList& attributeNames) const { attributeNames.emplace_back (kAttrAngleStart); attributeNames.emplace_back (kAttrAngleRange); + attributeNames.emplace_back (kAttrKnobRange); attributeNames.emplace_back (kAttrValueInset); attributeNames.emplace_back (kAttrZoomFactor); return true; @@ -60,6 +63,8 @@ auto KnobBaseCreator::getAttributeType (const string& attributeName) const -> At return kFloatType; if (attributeName == kAttrAngleRange) return kFloatType; + if (attributeName == kAttrKnobRange) + return kFloatType; if (attributeName == kAttrValueInset) return kFloatType; if (attributeName == kAttrZoomFactor) @@ -87,6 +92,11 @@ bool KnobBaseCreator::getAttributeValue (CView* view, const string& attributeNam UIAttributes::doubleToString ((knob->getRangeAngle () / Constants::pi * 180.), 5); return true; } + if (attributeName == kAttrKnobRange) + { + stringValue = UIAttributes::doubleToString (knob->getKnobRange (), 5); + return true; + } if (attributeName == kAttrValueInset) { stringValue = UIAttributes::doubleToString (knob->getInsetValue ());