commit 1bf94ee615e6224fca46b6f09848ad6a71c7fa8e
parent 92f0f978a15109c7df3eb729bc645ba4a38ed0bd
Author: falkTX <falktx@falktx.com>
Date: Thu, 17 Jun 2021 22:19:48 +0100
Move ImageKnob logic into reusable KnobEventHandler
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
7 files changed, 592 insertions(+), 422 deletions(-)
diff --git a/dgl/EventHandlers.hpp b/dgl/EventHandlers.hpp
@@ -54,8 +54,8 @@ public:
void setCallback(Callback* callback) noexcept;
- bool mouseEvent(const Widget::MouseEvent& ev);
- bool motionEvent(const Widget::MotionEvent& ev);
+ bool mouseEvent(const Widget::MouseEvent& ev);
+ bool motionEvent(const Widget::MotionEvent& ev);
protected:
State getState() const noexcept;
@@ -63,6 +63,9 @@ protected:
virtual void stateChanged(State state, State oldState);
+ void setInternalCallback(Callback* callback) noexcept;
+ void triggerUserCallback(SubWidget* widget, int button);
+
private:
struct PrivateData;
PrivateData* const pData;
@@ -72,6 +75,76 @@ private:
// --------------------------------------------------------------------------------------------------------------------
+class KnobEventHandler
+{
+public:
+ enum Orientation {
+ Horizontal,
+ Vertical
+ };
+
+ // NOTE hover not implemented yet
+ enum State {
+ kKnobStateDefault = 0x0,
+ kKnobStateHover = 0x1,
+ kKnobStateDragging = 0x2,
+ kKnobStateDraggingHover = kKnobStateDragging|kKnobStateHover
+ };
+
+ class Callback
+ {
+ public:
+ virtual ~Callback() {}
+ virtual void knobDragStarted(SubWidget* widget) = 0;
+ virtual void knobDragFinished(SubWidget* widget) = 0;
+ virtual void knobValueChanged(SubWidget* widget, float value) = 0;
+ };
+
+ explicit KnobEventHandler(SubWidget* self);
+ explicit KnobEventHandler(SubWidget* self, const KnobEventHandler& other);
+ KnobEventHandler& operator=(const KnobEventHandler& other);
+ ~KnobEventHandler();
+
+ // returns raw value, is assumed to be scaled if using log
+ float getValue() const noexcept;
+
+ // NOTE: value is assumed to be scaled if using log
+ void setValue(float value, bool sendCallback = false) noexcept;
+
+ // returns 0-1 ranged value, already with log scale as needed
+ float getNormalizedValue() const noexcept;
+
+ // NOTE: value is assumed to be scaled if using log
+ void setDefault(float def) noexcept;
+
+ // NOTE: value is assumed to be scaled if using log
+ void setRange(float min, float max) noexcept;
+
+ void setStep(float step) noexcept;
+
+ void setUsingLogScale(bool yesNo) noexcept;
+
+ Orientation getOrientation() const noexcept;
+ void setOrientation(const Orientation orientation) noexcept;
+
+ void setCallback(Callback* callback) noexcept;
+
+ bool mouseEvent(const Widget::MouseEvent& ev);
+ bool motionEvent(const Widget::MotionEvent& ev);
+ bool scrollEvent(const Widget::ScrollEvent& ev);
+
+protected:
+ State getState() const noexcept;
+
+private:
+ struct PrivateData;
+ PrivateData* const pData;
+
+ DISTRHO_LEAK_DETECTOR(KnobEventHandler)
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+
END_NAMESPACE_DGL
#endif // DGL_EVENT_HANDLERS_HPP_INCLUDED
diff --git a/dgl/ImageBaseWidgets.hpp b/dgl/ImageBaseWidgets.hpp
@@ -82,14 +82,10 @@ private:
// --------------------------------------------------------------------------------------------------------------------
template <class ImageType>
-class ImageBaseKnob : public SubWidget
+class ImageBaseKnob : public SubWidget,
+ public KnobEventHandler
{
public:
- enum Orientation {
- Horizontal,
- Vertical
- };
-
class Callback
{
public:
@@ -104,19 +100,9 @@ public:
ImageBaseKnob& operator=(const ImageBaseKnob& imageKnob);
~ImageBaseKnob() override;
- float getValue() const noexcept;
-
- void setDefault(float def) noexcept;
- void setRange(float min, float max) noexcept;
- void setStep(float step) noexcept;
- void setValue(float value, bool sendCallback = false) noexcept;
- void setUsingLogScale(bool yesNo) noexcept;
-
void setCallback(Callback* callback) noexcept;
- void setOrientation(Orientation orientation) noexcept;
- void setRotationAngle(int angle);
-
void setImageLayerCount(uint count) noexcept;
+ void setRotationAngle(int angle);
protected:
void onDisplay() override;
diff --git a/dgl/src/Cairo.cpp b/dgl/src/Cairo.cpp
@@ -24,7 +24,6 @@
#include "../Color.hpp"
#include "../ImageBaseWidgets.hpp"
-#include "Common.hpp"
#include "SubWidgetPrivateData.hpp"
#include "TopLevelWidgetPrivateData.hpp"
#include "WidgetPrivateData.hpp"
@@ -657,8 +656,7 @@ void ImageBaseKnob<CairoImage>::onDisplay()
{
const GraphicsContext& context(getGraphicsContext());
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
- const double normValue = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum)
- / (pData->maximum - pData->minimum);
+ const double normValue = getNormalizedValue();
cairo_surface_t* surface = (cairo_surface_t*)pData->cairoSurface;
diff --git a/dgl/src/Common.hpp b/dgl/src/Common.hpp
@@ -1,91 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any purpose with
- * or without fee is hereby granted, provided that the above copyright notice and this
- * permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
- * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef DGL_COMMON_HPP_INCLUDED
-#define DGL_COMMON_HPP_INCLUDED
-
-#include "../ImageBaseWidgets.hpp"
-
-START_NAMESPACE_DGL
-
-// -----------------------------------------------------------------------
-
-template <class ImageType>
-struct ImageBaseKnob<ImageType>::PrivateData {
- ImageType image;
- float minimum;
- float maximum;
- float step;
- float value;
- float valueDef;
- float valueTmp;
- bool usingDefault;
- bool usingLog;
- Orientation orientation;
-
- int rotationAngle;
- bool dragging;
- double lastX;
- double lastY;
-
- Callback* callback;
-
- bool alwaysRepaint;
- bool isImgVertical;
- uint imgLayerWidth;
- uint imgLayerHeight;
- uint imgLayerCount;
- bool isReady;
-
- union {
- uint glTextureId;
- void* cairoSurface;
- };
-
- explicit PrivateData(const ImageType& img, const Orientation o);
- explicit PrivateData(PrivateData* const other);
- void assignFrom(PrivateData* const other);
-
- ~PrivateData()
- {
- cleanup();
- }
-
- void init();
- void cleanup();
-
- inline float logscale(const float v) const
- {
- const float b = std::log(maximum/minimum)/(maximum-minimum);
- const float a = maximum/std::exp(maximum*b);
- return a * std::exp(b*v);
- }
-
- inline float invlogscale(const float v) const
- {
- const float b = std::log(maximum/minimum)/(maximum-minimum);
- const float a = maximum/std::exp(maximum*b);
- return std::log(v/a)/b;
- }
-
- DISTRHO_DECLARE_NON_COPYABLE(PrivateData)
-};
-
-// -----------------------------------------------------------------------
-
-END_NAMESPACE_DGL
-
-#endif // DGL_APP_PRIVATE_DATA_HPP_INCLUDED
diff --git a/dgl/src/EventHandlers.cpp b/dgl/src/EventHandlers.cpp
@@ -24,7 +24,8 @@ START_NAMESPACE_DGL
struct ButtonEventHandler::PrivateData {
ButtonEventHandler* const self;
SubWidget* const widget;
- ButtonEventHandler::Callback* callback;
+ ButtonEventHandler::Callback* internalCallback;
+ ButtonEventHandler::Callback* userCallback;
int button;
int state;
@@ -36,7 +37,8 @@ struct ButtonEventHandler::PrivateData {
PrivateData(ButtonEventHandler* const s, SubWidget* const w)
: self(s),
widget(w),
- callback(nullptr),
+ internalCallback(nullptr),
+ userCallback(nullptr),
button(-1),
state(kButtonStateDefault),
checkable(false),
@@ -72,8 +74,10 @@ struct ButtonEventHandler::PrivateData {
if (checkable)
checked = !checked;
- if (callback != nullptr)
- callback->buttonClicked(widget, button2);
+ if (internalCallback != nullptr)
+ internalCallback->buttonClicked(widget, button2);
+ else if (userCallback != nullptr)
+ userCallback->buttonClicked(widget, button2);
return true;
}
@@ -141,8 +145,13 @@ struct ButtonEventHandler::PrivateData {
state |= kButtonStateActive;
widget->repaint();
- if (sendCallback && callback != nullptr)
- callback->buttonClicked(widget, -1);
+ if (sendCallback)
+ {
+ if (internalCallback != nullptr)
+ internalCallback->buttonClicked(widget, -1);
+ else if (userCallback != nullptr)
+ userCallback->buttonClicked(widget, -1);
+ }
}
void setChecked(const bool checked2, const bool sendCallback) noexcept
@@ -153,8 +162,13 @@ struct ButtonEventHandler::PrivateData {
checked = checked2;
widget->repaint();
- if (sendCallback && callback != nullptr)
- callback->buttonClicked(widget, -1);
+ if (sendCallback)
+ {
+ if (internalCallback != nullptr)
+ internalCallback->buttonClicked(widget, -1);
+ else if (userCallback != nullptr)
+ userCallback->buttonClicked(widget, -1);
+ }
}
DISTRHO_DECLARE_NON_COPYABLE(PrivateData)
@@ -205,7 +219,7 @@ void ButtonEventHandler::setCheckable(const bool checkable) noexcept
void ButtonEventHandler::setCallback(Callback* const callback) noexcept
{
- pData->callback = callback;
+ pData->userCallback = callback;
}
bool ButtonEventHandler::mouseEvent(const Widget::MouseEvent& ev)
@@ -232,6 +246,375 @@ void ButtonEventHandler::stateChanged(State, State)
{
}
+void ButtonEventHandler::setInternalCallback(Callback* const callback) noexcept
+{
+ pData->internalCallback = callback;
+}
+
+void ButtonEventHandler::triggerUserCallback(SubWidget* const widget, const int button)
+{
+ if (pData->userCallback != nullptr)
+ pData->userCallback->buttonClicked(widget, button);
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+
+struct KnobEventHandler::PrivateData {
+ KnobEventHandler* const self;
+ SubWidget* const widget;
+ KnobEventHandler::Callback* callback;
+
+ float minimum;
+ float maximum;
+ float step;
+ float value;
+ float valueDef;
+ float valueTmp;
+ bool usingDefault;
+ bool usingLog;
+ Orientation orientation;
+ int state;
+
+ double lastX;
+ double lastY;
+
+ PrivateData(KnobEventHandler* const s, SubWidget* const w)
+ : self(s),
+ widget(w),
+ callback(nullptr),
+ minimum(0.0f),
+ maximum(1.0f),
+ step(0.0f),
+ value(0.5f),
+ valueDef(value),
+ valueTmp(value),
+ usingDefault(false),
+ usingLog(false),
+ orientation(Horizontal),
+ state(kKnobStateDefault),
+ lastX(0.0),
+ lastY(0.0) {}
+
+ PrivateData(KnobEventHandler* const s, SubWidget* const w, PrivateData* const other)
+ : self(s),
+ widget(w),
+ callback(other->callback),
+ minimum(other->minimum),
+ maximum(other->maximum),
+ step(other->step),
+ value(other->value),
+ valueDef(other->valueDef),
+ valueTmp(value),
+ usingDefault(other->usingDefault),
+ usingLog(other->usingLog),
+ orientation(other->orientation),
+ state(kKnobStateDefault),
+ lastX(0.0),
+ lastY(0.0) {}
+
+ void assignFrom(PrivateData* const other)
+ {
+ callback = other->callback;
+ minimum = other->minimum;
+ maximum = other->maximum;
+ step = other->step;
+ value = other->value;
+ valueDef = other->valueDef;
+ valueTmp = value;
+ usingDefault = other->usingDefault;
+ usingLog = other->usingLog;
+ orientation = other->orientation;
+ state = kKnobStateDefault;
+ lastX = 0.0;
+ lastY = 0.0;
+ }
+
+ inline float logscale(const float v) const
+ {
+ const float b = std::log(maximum/minimum)/(maximum-minimum);
+ const float a = maximum/std::exp(maximum*b);
+ return a * std::exp(b*v);
+ }
+
+ inline float invlogscale(const float v) const
+ {
+ const float b = std::log(maximum/minimum)/(maximum-minimum);
+ const float a = maximum/std::exp(maximum*b);
+ return std::log(v/a)/b;
+ }
+
+ bool mouseEvent(const Widget::MouseEvent& ev)
+ {
+ if (ev.button != 1)
+ return false;
+
+ if (ev.press)
+ {
+ if (! widget->contains(ev.pos))
+ return false;
+
+ if ((ev.mod & kModifierShift) != 0 && usingDefault)
+ {
+ setValue(valueDef, true);
+ valueTmp = value;
+ return true;
+ }
+
+ state |= kKnobStateDragging;
+ lastX = ev.pos.getX();
+ lastY = ev.pos.getY();
+ widget->repaint();
+
+ if (callback != nullptr)
+ callback->knobDragStarted(widget);
+
+ return true;
+ }
+ else if (state & kKnobStateDragging)
+ {
+ state &= ~kKnobStateDragging;
+ widget->repaint();
+
+ if (callback != nullptr)
+ callback->knobDragFinished(widget);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ bool motionEvent(const Widget::MotionEvent& ev)
+ {
+ if ((state & kKnobStateDragging) == 0x0)
+ return false;
+
+ bool doVal = false;
+ float d, value2 = 0.0f;
+
+ if (orientation == Horizontal)
+ {
+ if (const double movX = ev.pos.getX() - lastX)
+ {
+ d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
+ value2 = (usingLog ? invlogscale(valueTmp) : valueTmp) + (float(maximum - minimum) / d * float(movX));
+ doVal = true;
+ }
+ }
+ else if (orientation == Vertical)
+ {
+ if (const double movY = lastY - ev.pos.getY())
+ {
+ d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
+ value2 = (usingLog ? invlogscale(valueTmp) : valueTmp) + (float(maximum - minimum) / d * float(movY));
+ doVal = true;
+ }
+ }
+
+ if (! doVal)
+ return false;
+
+ if (usingLog)
+ value2 = logscale(value2);
+
+ if (value2 < minimum)
+ {
+ valueTmp = value2 = minimum;
+ }
+ else if (value2 > maximum)
+ {
+ valueTmp = value2 = maximum;
+ }
+ else
+ {
+ valueTmp = value2;
+
+ if (d_isNotZero(step))
+ {
+ const float rest = std::fmod(value2, step);
+ value2 -= rest + (rest > step/2.0f ? step : 0.0f);
+ }
+ }
+
+ setValue(value2, true);
+
+ lastX = ev.pos.getX();
+ lastY = ev.pos.getY();
+
+ return true;
+ }
+
+ bool scrollEvent(const Widget::ScrollEvent& ev)
+ {
+ if (! widget->contains(ev.pos))
+ return false;
+
+ const float dir = (ev.delta.getY() > 0.f) ? 1.f : -1.f;
+ const float d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
+ float value2 = (usingLog ? invlogscale(valueTmp) : valueTmp)
+ + ((maximum - minimum) / d * 10.f * dir);
+
+ if (usingLog)
+ value2 = logscale(value2);
+
+ if (value2 < minimum)
+ {
+ valueTmp = value2 = minimum;
+ }
+ else if (value2 > maximum)
+ {
+ valueTmp = value2 = maximum;
+ }
+ else
+ {
+ valueTmp = value2;
+
+ if (d_isNotZero(step))
+ {
+ const float rest = std::fmod(value2, step);
+ value2 = value2 - rest + (rest > step/2.0f ? step : 0.0f);
+ }
+ }
+
+ setValue(value2, true);
+ return true;
+ }
+
+ float getNormalizedValue() const noexcept
+ {
+ const float diff = maximum - minimum;
+ return ((usingLog ? invlogscale(value) : value) - minimum) / diff;
+ }
+
+ void setRange(const float min, const float max) noexcept
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(max > min,);
+
+ if (value < min)
+ {
+ valueTmp = value = min;
+ widget->repaint();
+ }
+ else if (value > max)
+ {
+ valueTmp = value = max;
+ widget->repaint();
+ }
+
+ minimum = min;
+ maximum = max;
+ }
+
+ void setValue(const float value2, const bool sendCallback)
+ {
+ if (d_isEqual(value, value2))
+ return;
+
+ valueTmp = value = value2;
+ widget->repaint();
+
+ if (sendCallback && callback != nullptr)
+ {
+ try {
+ callback->knobValueChanged(widget, value);
+ } DISTRHO_SAFE_EXCEPTION("KnobEventHandler::setValue");
+ }
+ }
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+
+KnobEventHandler::KnobEventHandler(SubWidget* const self)
+ : pData(new PrivateData(this, self)) {}
+
+KnobEventHandler::KnobEventHandler(SubWidget* const self, const KnobEventHandler& other)
+ : pData(new PrivateData(this, self, other.pData)) {}
+
+KnobEventHandler& KnobEventHandler::operator=(const KnobEventHandler& other)
+{
+ pData->assignFrom(other.pData);
+ return *this;
+}
+
+KnobEventHandler::~KnobEventHandler()
+{
+ delete pData;
+}
+
+float KnobEventHandler::getValue() const noexcept
+{
+ return pData->value;
+}
+
+void KnobEventHandler::setValue(const float value, const bool sendCallback) noexcept
+{
+ pData->setValue(value, sendCallback);
+}
+
+float KnobEventHandler::getNormalizedValue() const noexcept
+{
+ return pData->getNormalizedValue();
+}
+
+void KnobEventHandler::setDefault(const float def) noexcept
+{
+ pData->valueDef = def;
+ pData->usingDefault = true;
+}
+
+void KnobEventHandler::setRange(const float min, const float max) noexcept
+{
+ pData->setRange(min, max);
+}
+
+void KnobEventHandler::setStep(const float step) noexcept
+{
+ pData->step = step;
+}
+
+void KnobEventHandler::setUsingLogScale(const bool yesNo) noexcept
+{
+ pData->usingLog = yesNo;
+}
+
+KnobEventHandler::Orientation KnobEventHandler::getOrientation() const noexcept
+{
+ return pData->orientation;
+}
+
+void KnobEventHandler::setOrientation(const Orientation orientation) noexcept
+{
+ if (pData->orientation == orientation)
+ return;
+
+ pData->orientation = orientation;
+}
+
+void KnobEventHandler::setCallback(Callback* const callback) noexcept
+{
+ pData->callback = callback;
+}
+
+bool KnobEventHandler::mouseEvent(const Widget::MouseEvent& ev)
+{
+ return pData->mouseEvent(ev);
+}
+
+bool KnobEventHandler::motionEvent(const Widget::MotionEvent& ev)
+{
+ return pData->motionEvent(ev);
+}
+
+bool KnobEventHandler::scrollEvent(const Widget::ScrollEvent& ev)
+{
+ return pData->scrollEvent(ev);
+}
+
+KnobEventHandler::State KnobEventHandler::getState() const noexcept
+{
+ return static_cast<State>(pData->state);
+}
+
// --------------------------------------------------------------------------------------------------------------------
END_NAMESPACE_DGL
diff --git a/dgl/src/ImageBaseWidgets.cpp b/dgl/src/ImageBaseWidgets.cpp
@@ -16,7 +16,6 @@
#include "../ImageBaseWidgets.hpp"
#include "../Color.hpp"
-#include "Common.hpp"
START_NAMESPACE_DGL
@@ -193,108 +192,131 @@ bool ImageBaseButton<ImageType>::onMotion(const MotionEvent& ev)
// --------------------------------------------------------------------------------------------------------------------
template <class ImageType>
-ImageBaseKnob<ImageType>::PrivateData::PrivateData(const ImageType& img, const Orientation o)
- : image(img),
- minimum(0.0f),
- maximum(1.0f),
- step(0.0f),
- value(0.5f),
- valueDef(value),
- valueTmp(value),
- usingDefault(false),
- usingLog(false),
- orientation(o),
- rotationAngle(0),
- dragging(false),
- lastX(0.0),
- lastY(0.0),
- callback(nullptr),
- alwaysRepaint(false),
- isImgVertical(img.getHeight() > img.getWidth()),
- imgLayerWidth(isImgVertical ? img.getWidth() : img.getHeight()),
- imgLayerHeight(imgLayerWidth),
- imgLayerCount(isImgVertical ? img.getHeight()/imgLayerHeight : img.getWidth()/imgLayerWidth),
- isReady(false)
-{
- init();
-}
+struct ImageBaseKnob<ImageType>::PrivateData : public KnobEventHandler::Callback {
+ ImageBaseKnob<ImageType>::Callback* callback;
+ ImageType image;
-template <class ImageType>
-ImageBaseKnob<ImageType>::PrivateData::PrivateData(PrivateData* const other)
- : image(other->image),
- minimum(other->minimum),
- maximum(other->maximum),
- step(other->step),
- value(other->value),
- valueDef(other->valueDef),
- valueTmp(value),
- usingDefault(other->usingDefault),
- usingLog(other->usingLog),
- orientation(other->orientation),
- rotationAngle(other->rotationAngle),
- dragging(false),
- lastX(0.0),
- lastY(0.0),
- callback(other->callback),
- alwaysRepaint(other->alwaysRepaint),
- isImgVertical(other->isImgVertical),
- imgLayerWidth(other->imgLayerWidth),
- imgLayerHeight(other->imgLayerHeight),
- imgLayerCount(other->imgLayerCount),
- isReady(false)
-{
- init();
-}
+ int rotationAngle;
-template <class ImageType>
-void ImageBaseKnob<ImageType>::PrivateData::assignFrom(PrivateData* const other)
-{
- cleanup();
- image = other->image;
- minimum = other->minimum;
- maximum = other->maximum;
- step = other->step;
- value = other->value;
- valueDef = other->valueDef;
- valueTmp = value;
- usingDefault = other->usingDefault;
- usingLog = other->usingLog;
- orientation = other->orientation;
- rotationAngle = other->rotationAngle;
- dragging = false;
- lastX = 0.0;
- lastY = 0.0;
- callback = other->callback;
- alwaysRepaint = other->alwaysRepaint;
- isImgVertical = other->isImgVertical;
- imgLayerWidth = other->imgLayerWidth;
- imgLayerHeight = other->imgLayerHeight;
- imgLayerCount = other->imgLayerCount;
- isReady = false;
- init();
-}
+ bool alwaysRepaint;
+ bool isImgVertical;
+ uint imgLayerWidth;
+ uint imgLayerHeight;
+ uint imgLayerCount;
+ bool isReady;
+
+ union {
+ uint glTextureId;
+ void* cairoSurface;
+ };
+
+ explicit PrivateData(const ImageType& img)
+ : callback(nullptr),
+ image(img),
+ rotationAngle(0),
+ alwaysRepaint(false),
+ isImgVertical(img.getHeight() > img.getWidth()),
+ imgLayerWidth(isImgVertical ? img.getWidth() : img.getHeight()),
+ imgLayerHeight(imgLayerWidth),
+ imgLayerCount(isImgVertical ? img.getHeight()/imgLayerHeight : img.getWidth()/imgLayerWidth),
+ isReady(false)
+ {
+ init();
+ }
+
+ explicit PrivateData(PrivateData* const other)
+ : callback(other->callback),
+ image(other->image),
+ rotationAngle(other->rotationAngle),
+ alwaysRepaint(other->alwaysRepaint),
+ isImgVertical(other->isImgVertical),
+ imgLayerWidth(other->imgLayerWidth),
+ imgLayerHeight(other->imgLayerHeight),
+ imgLayerCount(other->imgLayerCount),
+ isReady(false)
+ {
+ init();
+ }
+
+ void assignFrom(PrivateData* const other)
+ {
+ cleanup();
+ image = other->image;
+ rotationAngle = other->rotationAngle;
+ callback = other->callback;
+ alwaysRepaint = other->alwaysRepaint;
+ isImgVertical = other->isImgVertical;
+ imgLayerWidth = other->imgLayerWidth;
+ imgLayerHeight = other->imgLayerHeight;
+ imgLayerCount = other->imgLayerCount;
+ isReady = false;
+ init();
+ }
+
+ ~PrivateData()
+ {
+ cleanup();
+ }
+
+ void knobDragStarted(SubWidget* const widget) override
+ {
+ if (callback != nullptr)
+ if (ImageBaseKnob* const imageKnob = dynamic_cast<ImageBaseKnob*>(widget))
+ callback->imageKnobDragStarted(imageKnob);
+ }
+
+ void knobDragFinished(SubWidget* const widget) override
+ {
+ if (callback != nullptr)
+ if (ImageBaseKnob* const imageKnob = dynamic_cast<ImageBaseKnob*>(widget))
+ callback->imageKnobDragFinished(imageKnob);
+ }
+
+ void knobValueChanged(SubWidget* const widget, const float value) override
+ {
+ if (rotationAngle == 0 || alwaysRepaint)
+ isReady = false;
+
+ if (callback != nullptr)
+ if (ImageBaseKnob* const imageKnob = dynamic_cast<ImageBaseKnob*>(widget))
+ callback->imageKnobValueChanged(imageKnob, value);
+ }
+
+ // implemented independently per graphics backend
+ void init();
+ void cleanup();
+
+ DISTRHO_DECLARE_NON_COPYABLE(PrivateData)
+};
// --------------------------------------------------------------------------------------------------------------------
template <class ImageType>
-ImageBaseKnob<ImageType>::ImageBaseKnob(Widget* const parentWidget, const ImageType& image, const Orientation orientation) noexcept
+ImageBaseKnob<ImageType>::ImageBaseKnob(Widget* const parentWidget,
+ const ImageType& image,
+ const Orientation orientation) noexcept
: SubWidget(parentWidget),
- pData(new PrivateData(image, orientation))
+ KnobEventHandler(this),
+ pData(new PrivateData(image))
{
+ setOrientation(orientation);
setSize(pData->imgLayerWidth, pData->imgLayerHeight);
}
template <class ImageType>
ImageBaseKnob<ImageType>::ImageBaseKnob(const ImageBaseKnob<ImageType>& imageKnob)
: SubWidget(imageKnob.getParentWidget()),
+ KnobEventHandler(this, imageKnob),
pData(new PrivateData(imageKnob.pData))
{
+ setOrientation(imageKnob.getOrientation());
setSize(pData->imgLayerWidth, pData->imgLayerHeight);
}
template <class ImageType>
ImageBaseKnob<ImageType>& ImageBaseKnob<ImageType>::operator=(const ImageBaseKnob<ImageType>& imageKnob)
{
+ KnobEventHandler::operator=(imageKnob);
pData->assignFrom(imageKnob.pData);
setSize(pData->imgLayerWidth, pData->imgLayerHeight);
return *this;
@@ -307,116 +329,12 @@ ImageBaseKnob<ImageType>::~ImageBaseKnob()
}
template <class ImageType>
-float ImageBaseKnob<ImageType>::getValue() const noexcept
-{
- return pData->value;
-}
-
-// NOTE: value is assumed to be scaled if using log
-template <class ImageType>
-void ImageBaseKnob<ImageType>::setDefault(float value) noexcept
-{
- pData->valueDef = value;
- pData->usingDefault = true;
-}
-
-template <class ImageType>
-void ImageBaseKnob<ImageType>::setRange(float min, float max) noexcept
-{
- DISTRHO_SAFE_ASSERT_RETURN(max > min,);
-
- if (pData->value < min)
- {
- pData->value = min;
- repaint();
-
- if (pData->callback != nullptr)
- {
- try {
- pData->callback->imageKnobValueChanged(this, pData->value);
- } DISTRHO_SAFE_EXCEPTION("ImageBaseKnob<ImageType>::setRange < min");
- }
- }
- else if (pData->value > max)
- {
- pData->value = max;
- repaint();
-
- if (pData->callback != nullptr)
- {
- try {
- pData->callback->imageKnobValueChanged(this, pData->value);
- } DISTRHO_SAFE_EXCEPTION("ImageBaseKnob<ImageType>::setRange > max");
- }
- }
-
- pData->minimum = min;
- pData->maximum = max;
-}
-
-template <class ImageType>
-void ImageBaseKnob<ImageType>::setStep(float step) noexcept
-{
- pData->step = step;
-}
-
-// NOTE: value is assumed to be scaled if using log
-template <class ImageType>
-void ImageBaseKnob<ImageType>::setValue(float value, bool sendCallback) noexcept
-{
- if (d_isEqual(pData->value, value))
- return;
-
- pData->value = value;
-
- if (d_isZero(pData->step))
- pData->valueTmp = value;
-
- if (pData->rotationAngle == 0 || pData->alwaysRepaint)
- pData->isReady = false;
-
- repaint();
-
- if (sendCallback && pData->callback != nullptr)
- {
- try {
- pData->callback->imageKnobValueChanged(this, pData->value);
- } DISTRHO_SAFE_EXCEPTION("ImageBaseKnob<ImageType>::setValue");
- }
-}
-
-template <class ImageType>
-void ImageBaseKnob<ImageType>::setUsingLogScale(bool yesNo) noexcept
-{
- pData->usingLog = yesNo;
-}
-
-template <class ImageType>
void ImageBaseKnob<ImageType>::setCallback(Callback* callback) noexcept
{
pData->callback = callback;
}
template <class ImageType>
-void ImageBaseKnob<ImageType>::setOrientation(Orientation orientation) noexcept
-{
- if (pData->orientation == orientation)
- return;
-
- pData->orientation = orientation;
-}
-
-template <class ImageType>
-void ImageBaseKnob<ImageType>::setRotationAngle(int angle)
-{
- if (pData->rotationAngle == angle)
- return;
-
- pData->rotationAngle = angle;
- pData->isReady = false;
-}
-
-template <class ImageType>
void ImageBaseKnob<ImageType>::setImageLayerCount(uint count) noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(count > 1,);
@@ -432,132 +350,37 @@ void ImageBaseKnob<ImageType>::setImageLayerCount(uint count) noexcept
}
template <class ImageType>
-bool ImageBaseKnob<ImageType>::onMouse(const MouseEvent& ev)
+void ImageBaseKnob<ImageType>::setRotationAngle(int angle)
{
- if (ev.button != 1)
- return false;
-
- if (ev.press)
- {
- if (! contains(ev.pos))
- return false;
-
- if ((ev.mod & kModifierShift) != 0 && pData->usingDefault)
- {
- setValue(pData->valueDef, true);
- pData->valueTmp = pData->value;
- return true;
- }
-
- pData->dragging = true;
- pData->lastX = ev.pos.getX();
- pData->lastY = ev.pos.getY();
-
- if (pData->callback != nullptr)
- pData->callback->imageKnobDragStarted(this);
+ if (pData->rotationAngle == angle)
+ return;
- return true;
- }
- else if (pData->dragging)
- {
- if (pData->callback != nullptr)
- pData->callback->imageKnobDragFinished(this);
+ pData->rotationAngle = angle;
+ pData->isReady = false;
+}
- pData->dragging = false;
+template <class ImageType>
+bool ImageBaseKnob<ImageType>::onMouse(const MouseEvent& ev)
+{
+ if (SubWidget::onMouse(ev))
return true;
- }
-
- return false;
+ return KnobEventHandler::mouseEvent(ev);
}
template <class ImageType>
bool ImageBaseKnob<ImageType>::onMotion(const MotionEvent& ev)
{
- if (! pData->dragging)
- return false;
-
- bool doVal = false;
- float d, value = 0.0f;
-
- if (pData->orientation == ImageBaseKnob<ImageType>::Horizontal)
- {
- if (const double movX = ev.pos.getX() - pData->lastX)
- {
- d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
- value = (pData->usingLog ? pData->invlogscale(pData->valueTmp) : pData->valueTmp) + (float(pData->maximum - pData->minimum) / d * float(movX));
- doVal = true;
- }
- }
- else if (pData->orientation == ImageBaseKnob<ImageType>::Vertical)
- {
- if (const double movY = pData->lastY - ev.pos.getY())
- {
- d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
- value = (pData->usingLog ? pData->invlogscale(pData->valueTmp) : pData->valueTmp) + (float(pData->maximum - pData->minimum) / d * float(movY));
- doVal = true;
- }
- }
-
- if (! doVal)
- return false;
-
- if (pData->usingLog)
- value = pData->logscale(value);
-
- if (value < pData->minimum)
- {
- pData->valueTmp = value = pData->minimum;
- }
- else if (value > pData->maximum)
- {
- pData->valueTmp = value = pData->maximum;
- }
- else if (d_isNotZero(pData->step))
- {
- pData->valueTmp = value;
- const float rest = std::fmod(value, pData->step);
- value = value - rest + (rest > pData->step/2.0f ? pData->step : 0.0f);
- }
-
- setValue(value, true);
-
- pData->lastX = ev.pos.getX();
- pData->lastY = ev.pos.getY();
-
- return true;
+ if (SubWidget::onMotion(ev))
+ return true;
+ return KnobEventHandler::motionEvent(ev);
}
template <class ImageType>
bool ImageBaseKnob<ImageType>::onScroll(const ScrollEvent& ev)
{
- if (! contains(ev.pos))
- return false;
-
- const float dir = (ev.delta.getY() > 0.f) ? 1.f : -1.f;
- const float d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f;
- float value = (pData->usingLog ? pData->invlogscale(pData->valueTmp) : pData->valueTmp)
- + ((pData->maximum - pData->minimum) / d * 10.f * dir);
-
- if (pData->usingLog)
- value = pData->logscale(value);
-
- if (value < pData->minimum)
- {
- pData->valueTmp = value = pData->minimum;
- }
- else if (value > pData->maximum)
- {
- pData->valueTmp = value = pData->maximum;
- }
- else if (d_isNotZero(pData->step))
- {
- pData->valueTmp = value;
- const float rest = std::fmod(value, pData->step);
- value = value - rest + (rest > pData->step/2.0f ? pData->step : 0.0f);
- }
-
- setValue(value, true);
- return true;
+ if (SubWidget::onScroll(ev))
+ return true;
+ return KnobEventHandler::scrollEvent(ev);
}
// --------------------------------------------------------------------------------------------------------------------
diff --git a/dgl/src/OpenGL.cpp b/dgl/src/OpenGL.cpp
@@ -23,7 +23,6 @@
#include "../Color.hpp"
#include "../ImageWidgets.hpp"
-#include "Common.hpp"
#include "SubWidgetPrivateData.hpp"
#include "TopLevelWidgetPrivateData.hpp"
#include "WidgetPrivateData.hpp"
@@ -486,8 +485,7 @@ template <>
void ImageBaseKnob<OpenGLImage>::onDisplay()
{
const GraphicsContext& context(getGraphicsContext());
- const float normValue = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum)
- / (pData->maximum - pData->minimum);
+ const float normValue = getNormalizedValue();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pData->glTextureId);