diff --git a/dgl/Cairo.hpp b/dgl/Cairo.hpp index 525c1496..e7dfaa93 100644 --- a/dgl/Cairo.hpp +++ b/dgl/Cairo.hpp @@ -19,7 +19,6 @@ #include "ImageBase.hpp" #include "ImageBaseWidgets.hpp" -#include "SubWidget.hpp" #include @@ -115,25 +114,21 @@ class CairoBaseWidget : public BaseWidget public: /** Constructor for a CairoSubWidget. - @see CreateFlags */ explicit CairoBaseWidget(Widget* const parentGroupWidget); /** Constructor for a CairoTopLevelWidget. - @see CreateFlags */ explicit CairoBaseWidget(Window& windowToMapTo); /** Constructor for a CairoStandaloneWindow without parent window. - @see CreateFlags */ explicit CairoBaseWidget(Application& app); /** Constructor for a CairoStandaloneWindow with parent window. - @see CreateFlags */ explicit CairoBaseWidget(Application& app, Window& parentWindow); @@ -171,6 +166,9 @@ typedef CairoBaseWidget CairoStandaloneWindow; typedef ImageBaseAboutWindow CairoImageAboutWindow; typedef ImageBaseButton CairoImageButton; +typedef ImageBaseKnob CairoImageKnob; +typedef ImageBaseSlider CairoImageSlider; +typedef ImageBaseSwitch CairoImageSwitch; // -------------------------------------------------------------------------------------------------------------------- diff --git a/dgl/ImageBaseWidgets.hpp b/dgl/ImageBaseWidgets.hpp index 6ae520db..33a72639 100644 --- a/dgl/ImageBaseWidgets.hpp +++ b/dgl/ImageBaseWidgets.hpp @@ -82,6 +82,205 @@ private: // -------------------------------------------------------------------------------------------------------------------- +template +class ImageBaseKnob : public SubWidget +{ +public: + enum Orientation { + Horizontal, + Vertical + }; + + class Callback + { + public: + virtual ~Callback() {} + virtual void imageKnobDragStarted(ImageBaseKnob* imageKnob) = 0; + virtual void imageKnobDragFinished(ImageBaseKnob* imageKnob) = 0; + virtual void imageKnobValueChanged(ImageBaseKnob* imageKnob, float value) = 0; + }; + + explicit ImageBaseKnob(Widget* parentWidget, const ImageType& image, Orientation orientation = Vertical) noexcept; + explicit ImageBaseKnob(const ImageBaseKnob& imageKnob); + 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; + +protected: + void onDisplay() override; + bool onMouse(const MouseEvent&) override; + bool onMotion(const MotionEvent&) override; + bool onScroll(const ScrollEvent&) override; + +private: + struct PrivateData; + PrivateData* const pData; + + /* + Image fImage; + float fMinimum; + float fMaximum; + float fStep; + float fValue; + float fValueDef; + float fValueTmp; + bool fUsingDefault; + bool fUsingLog; + Orientation fOrientation; + + int fRotationAngle; + bool fDragging; + int fLastX; + int fLastY; + + Callback* fCallback; + + bool fIsImgVertical; + uint fImgLayerWidth; + uint fImgLayerHeight; + uint fImgLayerCount; + bool fIsReady; + GLuint fTextureId; + + float _logscale(float value) const; + float _invlogscale(float value) const; + */ + + DISTRHO_LEAK_DETECTOR(ImageBaseKnob) +}; + +// -------------------------------------------------------------------------------------------------------------------- + +// note set range and step before setting the value + +template +class ImageBaseSlider : public SubWidget +{ +public: + class Callback + { + public: + virtual ~Callback() {} + virtual void imageSliderDragStarted(ImageBaseSlider* imageSlider) = 0; + virtual void imageSliderDragFinished(ImageBaseSlider* imageSlider) = 0; + virtual void imageSliderValueChanged(ImageBaseSlider* imageSlider, float value) = 0; + }; + + explicit ImageBaseSlider(Widget* parentWidget, const ImageType& image) noexcept; + + float getValue() const noexcept; + void setValue(float value, bool sendCallback = false) noexcept; + void setDefault(float def) noexcept; + + void setStartPos(const Point& startPos) noexcept; + void setStartPos(int x, int y) noexcept; + void setEndPos(const Point& endPos) noexcept; + void setEndPos(int x, int y) noexcept; + + void setInverted(bool inverted) noexcept; + void setRange(float min, float max) noexcept; + void setStep(float step) noexcept; + + void setCallback(Callback* callback) noexcept; + +protected: + void onDisplay() override; + bool onMouse(const MouseEvent&) override; + bool onMotion(const MotionEvent&) override; + +private: + struct PrivateData; + PrivateData* const pData; + + /* + Image fImage; + float fMinimum; + float fMaximum; + float fStep; + float fValue; + float fValueDef; + float fValueTmp; + bool fUsingDefault; + + bool fDragging; + bool fInverted; + bool fValueIsSet; + int fStartedX; + int fStartedY; + + Callback* fCallback; + + Point fStartPos; + Point fEndPos; + Rectangle fSliderArea; + + void _recheckArea() noexcept; + */ + + // these should not be used + void setAbsoluteX(int) const noexcept {} + void setAbsoluteY(int) const noexcept {} + void setAbsolutePos(int, int) const noexcept {} + void setAbsolutePos(const Point&) const noexcept {} + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageBaseSlider) +}; + +// -------------------------------------------------------------------------------------------------------------------- + +template +class ImageBaseSwitch : public SubWidget +{ +public: + class Callback + { + public: + virtual ~Callback() {} + virtual void imageSwitchClicked(ImageBaseSwitch* imageSwitch, bool down) = 0; + }; + + explicit ImageBaseSwitch(Widget* parentWidget, const ImageType& imageNormal, const ImageType& imageDown) noexcept; + explicit ImageBaseSwitch(const ImageBaseSwitch& imageSwitch) noexcept; + ImageBaseSwitch& operator=(const ImageBaseSwitch& imageSwitch) noexcept; + + bool isDown() const noexcept; + void setDown(bool down) noexcept; + + void setCallback(Callback* callback) noexcept; + +protected: + void onDisplay() override; + bool onMouse(const MouseEvent&) override; + +private: + struct PrivateData; + PrivateData* const pData; + + /* + Image fImageNormal; + Image fImageDown; + bool fIsDown; + Callback* fCallback; + */ + + DISTRHO_LEAK_DETECTOR(ImageBaseSwitch) +}; + +// -------------------------------------------------------------------------------------------------------------------- + END_NAMESPACE_DGL #endif // DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED diff --git a/dgl/ImageWidgets.hpp b/dgl/ImageWidgets.hpp index 3571d8da..aa85fe6f 100644 --- a/dgl/ImageWidgets.hpp +++ b/dgl/ImageWidgets.hpp @@ -17,206 +17,25 @@ #ifndef DGL_IMAGE_WIDGETS_HPP_INCLUDED #define DGL_IMAGE_WIDGETS_HPP_INCLUDED -#include "Image.hpp" -#include "ImageBaseWidgets.hpp" -#include "SubWidget.hpp" - -// TODO switch to use templated image type after merging widget-related PRs -#if defined(__GNUC__) && (__GNUC__ >= 6) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif +#include "OpenGL.hpp" START_NAMESPACE_DGL -// ----------------------------------------------------------------------- - -class ImageKnob : public SubWidget -{ -public: - enum Orientation { - Horizontal, - Vertical - }; - - class Callback - { - public: - virtual ~Callback() {} - virtual void imageKnobDragStarted(ImageKnob* imageKnob) = 0; - virtual void imageKnobDragFinished(ImageKnob* imageKnob) = 0; - virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0; - }; - - explicit ImageKnob(Widget* parentWidget, const Image& image, Orientation orientation = Vertical) noexcept; - explicit ImageKnob(const ImageKnob& imageKnob); - ImageKnob& operator=(const ImageKnob& imageKnob); - ~ImageKnob() 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; - -protected: - void onDisplay() override; - bool onMouse(const MouseEvent&) override; - bool onMotion(const MotionEvent&) override; - bool onScroll(const ScrollEvent&) override; - -private: - Image fImage; - float fMinimum; - float fMaximum; - float fStep; - float fValue; - float fValueDef; - float fValueTmp; - bool fUsingDefault; - bool fUsingLog; - Orientation fOrientation; - - int fRotationAngle; - bool fDragging; - int fLastX; - int fLastY; - - Callback* fCallback; - - bool fIsImgVertical; - uint fImgLayerWidth; - uint fImgLayerHeight; - uint fImgLayerCount; - bool fIsReady; - GLuint fTextureId; - - float _logscale(float value) const; - float _invlogscale(float value) const; - - DISTRHO_LEAK_DETECTOR(ImageKnob) -}; - -// ----------------------------------------------------------------------- - -// note set range and step before setting the value - -class ImageSlider : public SubWidget -{ -public: - class Callback - { - public: - virtual ~Callback() {} - virtual void imageSliderDragStarted(ImageSlider* imageSlider) = 0; - virtual void imageSliderDragFinished(ImageSlider* imageSlider) = 0; - virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0; - }; - - explicit ImageSlider(Widget* parentWidget, const Image& image) noexcept; +DISTRHO_DEPRECATED_BY("OpenGLImageAboutWindow") +typedef OpenGLImageAboutWindow ImageAboutWindow; - float getValue() const noexcept; - void setValue(float value, bool sendCallback = false) noexcept; - void setDefault(float def) noexcept; +DISTRHO_DEPRECATED_BY("OpenGLImageButton") +typedef OpenGLImageButton ImageButton; - void setStartPos(const Point& startPos) noexcept; - void setStartPos(int x, int y) noexcept; - void setEndPos(const Point& endPos) noexcept; - void setEndPos(int x, int y) noexcept; +DISTRHO_DEPRECATED_BY("OpenGLImageKnob") +typedef OpenGLImageKnob ImageKnob; - void setInverted(bool inverted) noexcept; - void setRange(float min, float max) noexcept; - void setStep(float step) noexcept; +DISTRHO_DEPRECATED_BY("OpenGLImageSlider") +typedef OpenGLImageSlider ImageSlider; - void setCallback(Callback* callback) noexcept; - -protected: - void onDisplay() override; - bool onMouse(const MouseEvent&) override; - bool onMotion(const MotionEvent&) override; - -private: - Image fImage; - float fMinimum; - float fMaximum; - float fStep; - float fValue; - float fValueDef; - float fValueTmp; - bool fUsingDefault; - - bool fDragging; - bool fInverted; - bool fValueIsSet; - int fStartedX; - int fStartedY; - - Callback* fCallback; - - Point fStartPos; - Point fEndPos; - Rectangle fSliderArea; - - void _recheckArea() noexcept; - - // these should not be used - void setAbsoluteX(int) const noexcept {} - void setAbsoluteY(int) const noexcept {} - void setAbsolutePos(int, int) const noexcept {} - void setAbsolutePos(const Point&) const noexcept {} - - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageSlider) -}; - -// ----------------------------------------------------------------------- - -class ImageSwitch : public SubWidget -{ -public: - class Callback - { - public: - virtual ~Callback() {} - virtual void imageSwitchClicked(ImageSwitch* imageSwitch, bool down) = 0; - }; - - explicit ImageSwitch(Widget* parentWidget, const Image& imageNormal, const Image& imageDown) noexcept; - explicit ImageSwitch(const ImageSwitch& imageSwitch) noexcept; - ImageSwitch& operator=(const ImageSwitch& imageSwitch) noexcept; - - bool isDown() const noexcept; - void setDown(bool down) noexcept; - - void setCallback(Callback* callback) noexcept; - -protected: - void onDisplay() override; - bool onMouse(const MouseEvent&) override; - -private: - Image fImageNormal; - Image fImageDown; - bool fIsDown; - - Callback* fCallback; - - DISTRHO_LEAK_DETECTOR(ImageSwitch) -}; - -// ----------------------------------------------------------------------- +DISTRHO_DEPRECATED_BY("OpenGLImageSwitch") +typedef OpenGLImageSwitch ImageSwitch; END_NAMESPACE_DGL -#if defined(__GNUC__) && (__GNUC__ >= 6) -# pragma GCC diagnostic pop -#endif - #endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED diff --git a/dgl/Makefile b/dgl/Makefile index 35068125..041e1d03 100644 --- a/dgl/Makefile +++ b/dgl/Makefile @@ -56,7 +56,6 @@ endif OBJS_opengl = $(OBJS_common) \ ../build/dgl/OpenGL.cpp.opengl.o \ - ../build/dgl/ImageWidgets.cpp.o \ ../build/dgl/NanoVG.cpp.opengl.o ifeq ($(MACOS),true) diff --git a/dgl/OpenGL.hpp b/dgl/OpenGL.hpp index e3fa37e1..f28f2277 100644 --- a/dgl/OpenGL.hpp +++ b/dgl/OpenGL.hpp @@ -282,12 +282,9 @@ private: typedef ImageBaseAboutWindow OpenGLImageAboutWindow; typedef ImageBaseButton OpenGLImageButton; - -DISTRHO_DEPRECATED_BY("OpenGLImageAboutWindow") -typedef OpenGLImageAboutWindow ImageAboutWindow; - -DISTRHO_DEPRECATED_BY("OpenGLImageButton") -typedef OpenGLImageButton ImageButton; +typedef ImageBaseKnob OpenGLImageKnob; +typedef ImageBaseSlider OpenGLImageSlider; +typedef ImageBaseSwitch OpenGLImageSwitch; // ----------------------------------------------------------------------- diff --git a/dgl/src/ImageBaseWidgets.cpp b/dgl/src/ImageBaseWidgets.cpp index 1eb8bbd1..b9e46896 100644 --- a/dgl/src/ImageBaseWidgets.cpp +++ b/dgl/src/ImageBaseWidgets.cpp @@ -180,4 +180,857 @@ bool ImageBaseButton::onMotion(const MotionEvent& ev) // -------------------------------------------------------------------------------------------------------------------- +#if 0 +ImageKnob::ImageKnob(Widget* const parentWidget, const Image& image, Orientation orientation) noexcept + : SubWidget(parentWidget), + fImage(image), + fMinimum(0.0f), + fMaximum(1.0f), + fStep(0.0f), + fValue(0.5f), + fValueDef(fValue), + fValueTmp(fValue), + fUsingDefault(false), + fUsingLog(false), + fOrientation(orientation), + fRotationAngle(0), + fDragging(false), + fLastX(0), + fLastY(0), + fCallback(nullptr), + fIsImgVertical(image.getHeight() > image.getWidth()), + fImgLayerWidth(fIsImgVertical ? image.getWidth() : image.getHeight()), + fImgLayerHeight(fImgLayerWidth), + fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerHeight : image.getWidth()/fImgLayerWidth), + fIsReady(false), + fTextureId(0) +{ + glGenTextures(1, &fTextureId); + setSize(fImgLayerWidth, fImgLayerHeight); +} + +ImageKnob::ImageKnob(const ImageKnob& imageKnob) + : SubWidget(imageKnob.getParentWidget()), + fImage(imageKnob.fImage), + fMinimum(imageKnob.fMinimum), + fMaximum(imageKnob.fMaximum), + fStep(imageKnob.fStep), + fValue(imageKnob.fValue), + fValueDef(imageKnob.fValueDef), + fValueTmp(fValue), + fUsingDefault(imageKnob.fUsingDefault), + fUsingLog(imageKnob.fUsingLog), + fOrientation(imageKnob.fOrientation), + fRotationAngle(imageKnob.fRotationAngle), + fDragging(false), + fLastX(0), + fLastY(0), + fCallback(imageKnob.fCallback), + fIsImgVertical(imageKnob.fIsImgVertical), + fImgLayerWidth(imageKnob.fImgLayerWidth), + fImgLayerHeight(imageKnob.fImgLayerHeight), + fImgLayerCount(imageKnob.fImgLayerCount), + fIsReady(false), + fTextureId(0) +{ + glGenTextures(1, &fTextureId); + setSize(fImgLayerWidth, fImgLayerHeight); +} + +ImageKnob& ImageKnob::operator=(const ImageKnob& imageKnob) +{ + fImage = imageKnob.fImage; + fMinimum = imageKnob.fMinimum; + fMaximum = imageKnob.fMaximum; + fStep = imageKnob.fStep; + fValue = imageKnob.fValue; + fValueDef = imageKnob.fValueDef; + fValueTmp = fValue; + fUsingDefault = imageKnob.fUsingDefault; + fUsingLog = imageKnob.fUsingLog; + fOrientation = imageKnob.fOrientation; + fRotationAngle = imageKnob.fRotationAngle; + fDragging = false; + fLastX = 0; + fLastY = 0; + fCallback = imageKnob.fCallback; + fIsImgVertical = imageKnob.fIsImgVertical; + fImgLayerWidth = imageKnob.fImgLayerWidth; + fImgLayerHeight = imageKnob.fImgLayerHeight; + fImgLayerCount = imageKnob.fImgLayerCount; + fIsReady = false; + + if (fTextureId != 0) + { + glDeleteTextures(1, &fTextureId); + fTextureId = 0; + } + + glGenTextures(1, &fTextureId); + setSize(fImgLayerWidth, fImgLayerHeight); + + return *this; +} + +ImageKnob::~ImageKnob() +{ + if (fTextureId != 0) + { + glDeleteTextures(1, &fTextureId); + fTextureId = 0; + } +} + +float ImageKnob::getValue() const noexcept +{ + return fValue; +} + +// NOTE: value is assumed to be scaled if using log +void ImageKnob::setDefault(float value) noexcept +{ + fValueDef = value; + fUsingDefault = true; +} + +void ImageKnob::setRange(float min, float max) noexcept +{ + DISTRHO_SAFE_ASSERT_RETURN(max > min,); + + if (fValue < min) + { + fValue = min; + repaint(); + + if (fCallback != nullptr) + { + try { + fCallback->imageKnobValueChanged(this, fValue); + } DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange < min"); + } + } + else if (fValue > max) + { + fValue = max; + repaint(); + + if (fCallback != nullptr) + { + try { + fCallback->imageKnobValueChanged(this, fValue); + } DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange > max"); + } + } + + fMinimum = min; + fMaximum = max; +} + +void ImageKnob::setStep(float step) noexcept +{ + fStep = step; +} + +// NOTE: value is assumed to be scaled if using log +void ImageKnob::setValue(float value, bool sendCallback) noexcept +{ + if (d_isEqual(fValue, value)) + return; + + fValue = value; + + if (d_isZero(fStep)) + fValueTmp = value; + + if (fRotationAngle == 0) + fIsReady = false; + + repaint(); + + if (sendCallback && fCallback != nullptr) + { + try { + fCallback->imageKnobValueChanged(this, fValue); + } DISTRHO_SAFE_EXCEPTION("ImageKnob::setValue"); + } +} + +void ImageKnob::setUsingLogScale(bool yesNo) noexcept +{ + fUsingLog = yesNo; +} + +void ImageKnob::setCallback(Callback* callback) noexcept +{ + fCallback = callback; +} + +void ImageKnob::setOrientation(Orientation orientation) noexcept +{ + if (fOrientation == orientation) + return; + + fOrientation = orientation; +} + +void ImageKnob::setRotationAngle(int angle) +{ + if (fRotationAngle == angle) + return; + + fRotationAngle = angle; + fIsReady = false; +} + +void ImageKnob::setImageLayerCount(uint count) noexcept +{ + DISTRHO_SAFE_ASSERT_RETURN(count > 1,); + + fImgLayerCount = count; + + if (fIsImgVertical) + fImgLayerHeight = fImage.getHeight()/count; + else + fImgLayerWidth = fImage.getWidth()/count; + + setSize(fImgLayerWidth, fImgLayerHeight); +} + +void ImageKnob::onDisplay() +{ + const float normValue = ((fUsingLog ? _invlogscale(fValue) : fValue) - fMinimum) / (fMaximum - fMinimum); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, fTextureId); + + if (! fIsReady) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + uint imageDataOffset = 0; + + if (fRotationAngle == 0) + { + DISTRHO_SAFE_ASSERT_RETURN(fImgLayerCount > 0,); + DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); + + const uint& v1(fIsImgVertical ? fImgLayerWidth : fImgLayerHeight); + const uint& v2(fIsImgVertical ? fImgLayerHeight : fImgLayerWidth); + + const uint layerDataSize = v1 * v2 * ((fImage.getFormat() == kImageFormatBGRA || + fImage.getFormat() == kImageFormatRGBA) ? 4 : 3); + /* */ imageDataOffset = layerDataSize * uint(normValue * float(fImgLayerCount-1)); + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + static_cast(getWidth()), static_cast(getHeight()), 0, + asOpenGLImageFormat(fImage.getFormat()), GL_UNSIGNED_BYTE, fImage.getRawData() + imageDataOffset); + + fIsReady = true; + } + + const int w = static_cast(getWidth()); + const int h = static_cast(getHeight()); + + if (fRotationAngle != 0) + { + glPushMatrix(); + + const int w2 = w/2; + const int h2 = h/2; + + glTranslatef(static_cast(w2), static_cast(h2), 0.0f); + glRotatef(normValue*static_cast(fRotationAngle), 0.0f, 0.0f, 1.0f); + + Rectangle(-w2, -h2, w, h).draw(); + + glPopMatrix(); + } + else + { + Rectangle(0, 0, w, h).draw(); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); +} + +bool ImageKnob::onMouse(const MouseEvent& ev) +{ + if (ev.button != 1) + return false; + + if (ev.press) + { + if (! contains(ev.pos)) + return false; + + if ((ev.mod & kModifierShift) != 0 && fUsingDefault) + { + setValue(fValueDef, true); + fValueTmp = fValue; + return true; + } + + fDragging = true; + fLastX = ev.pos.getX(); + fLastY = ev.pos.getY(); + + if (fCallback != nullptr) + fCallback->imageKnobDragStarted(this); + + return true; + } + else if (fDragging) + { + if (fCallback != nullptr) + fCallback->imageKnobDragFinished(this); + + fDragging = false; + return true; + } + + return false; +} + +bool ImageKnob::onMotion(const MotionEvent& ev) +{ + if (! fDragging) + return false; + + bool doVal = false; + float d, value = 0.0f; + + if (fOrientation == ImageKnob::Horizontal) + { + if (const int movX = ev.pos.getX() - fLastX) + { + d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; + value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movX)); + doVal = true; + } + } + else if (fOrientation == ImageKnob::Vertical) + { + if (const int movY = fLastY - ev.pos.getY()) + { + d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; + value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movY)); + doVal = true; + } + } + + if (! doVal) + return false; + + if (fUsingLog) + value = _logscale(value); + + if (value < fMinimum) + { + fValueTmp = value = fMinimum; + } + else if (value > fMaximum) + { + fValueTmp = value = fMaximum; + } + else if (d_isNotZero(fStep)) + { + fValueTmp = value; + const float rest = std::fmod(value, fStep); + value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); + } + + setValue(value, true); + + fLastX = ev.pos.getX(); + fLastY = ev.pos.getY(); + + return true; +} + +bool ImageKnob::onScroll(const ScrollEvent& ev) +{ + if (! contains(ev.pos)) + return false; + + const float d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; + float value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * 10.f * ev.delta.getY()); + + if (fUsingLog) + value = _logscale(value); + + if (value < fMinimum) + { + fValueTmp = value = fMinimum; + } + else if (value > fMaximum) + { + fValueTmp = value = fMaximum; + } + else if (d_isNotZero(fStep)) + { + fValueTmp = value; + const float rest = std::fmod(value, fStep); + value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); + } + + setValue(value, true); + return true; +} + +// ----------------------------------------------------------------------- + +float ImageKnob::_logscale(float value) const +{ + const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum); + const float a = fMaximum/std::exp(fMaximum*b); + return a * std::exp(b*value); +} + +float ImageKnob::_invlogscale(float value) const +{ + const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum); + const float a = fMaximum/std::exp(fMaximum*b); + return std::log(value/a)/b; +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +#if 0 +ImageSlider::ImageSlider(Widget* const parentWidget, const Image& image) noexcept + : SubWidget(parentWidget), + fImage(image), + fMinimum(0.0f), + fMaximum(1.0f), + fStep(0.0f), + fValue(0.5f), + fValueDef(fValue), + fValueTmp(fValue), + fUsingDefault(false), + fDragging(false), + fInverted(false), + fValueIsSet(false), + fStartedX(0), + fStartedY(0), + fCallback(nullptr), + fStartPos(), + fEndPos(), + fSliderArea() +{ + setNeedsFullViewportDrawing(); +} + +float ImageSlider::getValue() const noexcept +{ + return fValue; +} + +void ImageSlider::setValue(float value, bool sendCallback) noexcept +{ + if (! fValueIsSet) + fValueIsSet = true; + + if (d_isEqual(fValue, value)) + return; + + fValue = value; + + if (d_isZero(fStep)) + fValueTmp = value; + + repaint(); + + if (sendCallback && fCallback != nullptr) + { + try { + fCallback->imageSliderValueChanged(this, fValue); + } DISTRHO_SAFE_EXCEPTION("ImageSlider::setValue"); + } +} + +void ImageSlider::setStartPos(const Point& startPos) noexcept +{ + fStartPos = startPos; + _recheckArea(); +} + +void ImageSlider::setStartPos(int x, int y) noexcept +{ + setStartPos(Point(x, y)); +} + +void ImageSlider::setEndPos(const Point& endPos) noexcept +{ + fEndPos = endPos; + _recheckArea(); +} + +void ImageSlider::setEndPos(int x, int y) noexcept +{ + setEndPos(Point(x, y)); +} + +void ImageSlider::setInverted(bool inverted) noexcept +{ + if (fInverted == inverted) + return; + + fInverted = inverted; + repaint(); +} + +void ImageSlider::setDefault(float value) noexcept +{ + fValueDef = value; + fUsingDefault = true; +} + +void ImageSlider::setRange(float min, float max) noexcept +{ + fMinimum = min; + fMaximum = max; + + if (fValue < min) + { + fValue = min; + repaint(); + + if (fCallback != nullptr && fValueIsSet) + { + try { + fCallback->imageSliderValueChanged(this, fValue); + } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange < min"); + } + } + else if (fValue > max) + { + fValue = max; + repaint(); + + if (fCallback != nullptr && fValueIsSet) + { + try { + fCallback->imageSliderValueChanged(this, fValue); + } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange > max"); + } + } +} + +void ImageSlider::setStep(float step) noexcept +{ + fStep = step; +} + +void ImageSlider::setCallback(Callback* callback) noexcept +{ + fCallback = callback; +} + +void ImageSlider::onDisplay() +{ +#if 0 // DEBUG, paints slider area + glColor3f(0.4f, 0.5f, 0.1f); + glRecti(fSliderArea.getX(), fSliderArea.getY(), fSliderArea.getX()+fSliderArea.getWidth(), fSliderArea.getY()+fSliderArea.getHeight()); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +#endif + + const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum); + + int x, y; + + if (fStartPos.getY() == fEndPos.getY()) + { + // horizontal + if (fInverted) + x = fEndPos.getX() - static_cast(normValue*static_cast(fEndPos.getX()-fStartPos.getX())); + else + x = fStartPos.getX() + static_cast(normValue*static_cast(fEndPos.getX()-fStartPos.getX())); + + y = fStartPos.getY(); + } + else + { + // vertical + x = fStartPos.getX(); + + if (fInverted) + y = fEndPos.getY() - static_cast(normValue*static_cast(fEndPos.getY()-fStartPos.getY())); + else + y = fStartPos.getY() + static_cast(normValue*static_cast(fEndPos.getY()-fStartPos.getY())); + } + + fImage.drawAt(x, y); +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +#if 0 +bool ImageSlider::onMouse(const MouseEvent& ev) +{ + if (ev.button != 1) + return false; + + if (ev.press) + { + if (! fSliderArea.contains(ev.pos)) + return false; + + if ((ev.mod & kModifierShift) != 0 && fUsingDefault) + { + setValue(fValueDef, true); + fValueTmp = fValue; + return true; + } + + float vper; + const int x = ev.pos.getX(); + const int y = ev.pos.getY(); + + if (fStartPos.getY() == fEndPos.getY()) + { + // horizontal + vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth()); + } + else + { + // vertical + vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); + } + + float value; + + if (fInverted) + value = fMaximum - vper * (fMaximum - fMinimum); + else + value = fMinimum + vper * (fMaximum - fMinimum); + + if (value < fMinimum) + { + fValueTmp = value = fMinimum; + } + else if (value > fMaximum) + { + fValueTmp = value = fMaximum; + } + else if (d_isNotZero(fStep)) + { + fValueTmp = value; + const float rest = std::fmod(value, fStep); + value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); + } + + fDragging = true; + fStartedX = x; + fStartedY = y; + + if (fCallback != nullptr) + fCallback->imageSliderDragStarted(this); + + setValue(value, true); + + return true; + } + else if (fDragging) + { + if (fCallback != nullptr) + fCallback->imageSliderDragFinished(this); + + fDragging = false; + return true; + } + + return false; +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +#if 0 +bool ImageSlider::onMotion(const MotionEvent& ev) +{ + if (! fDragging) + return false; + + const bool horizontal = fStartPos.getY() == fEndPos.getY(); + const int x = ev.pos.getX(); + const int y = ev.pos.getY(); + + if ((horizontal && fSliderArea.containsX(x)) || (fSliderArea.containsY(y) && ! horizontal)) + { + float vper; + + if (horizontal) + { + // horizontal + vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth()); + } + else + { + // vertical + vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); + } + + float value; + + if (fInverted) + value = fMaximum - vper * (fMaximum - fMinimum); + else + value = fMinimum + vper * (fMaximum - fMinimum); + + if (value < fMinimum) + { + fValueTmp = value = fMinimum; + } + else if (value > fMaximum) + { + fValueTmp = value = fMaximum; + } + else if (d_isNotZero(fStep)) + { + fValueTmp = value; + const float rest = std::fmod(value, fStep); + value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); + } + + setValue(value, true); + } + else if (horizontal) + { + if (x < fSliderArea.getX()) + setValue(fInverted ? fMaximum : fMinimum, true); + else + setValue(fInverted ? fMinimum : fMaximum, true); + } + else + { + if (y < fSliderArea.getY()) + setValue(fInverted ? fMaximum : fMinimum, true); + else + setValue(fInverted ? fMinimum : fMaximum, true); + } + + return true; +} + +void ImageSlider::_recheckArea() noexcept +{ + if (fStartPos.getY() == fEndPos.getY()) + { + // horizontal + fSliderArea = Rectangle(fStartPos.getX(), + fStartPos.getY(), + fEndPos.getX() + static_cast(fImage.getWidth()) - fStartPos.getX(), + static_cast(fImage.getHeight())); + } + else + { + // vertical + fSliderArea = Rectangle(fStartPos.getX(), + fStartPos.getY(), + static_cast(fImage.getWidth()), + fEndPos.getY() + static_cast(fImage.getHeight()) - fStartPos.getY()); + } +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +#if 0 +ImageSwitch::ImageSwitch(Widget* parentWidget, const Image& imageNormal, const Image& imageDown) noexcept + : SubWidget(parentWidget), + fImageNormal(imageNormal), + fImageDown(imageDown), + fIsDown(false), + fCallback(nullptr) +{ + DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); + + setSize(fImageNormal.getSize()); +} + +ImageSwitch::ImageSwitch(const ImageSwitch& imageSwitch) noexcept + : SubWidget(imageSwitch.getParentWidget()), + fImageNormal(imageSwitch.fImageNormal), + fImageDown(imageSwitch.fImageDown), + fIsDown(imageSwitch.fIsDown), + fCallback(imageSwitch.fCallback) +{ + DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); + + setSize(fImageNormal.getSize()); +} + +ImageSwitch& ImageSwitch::operator=(const ImageSwitch& imageSwitch) noexcept +{ + fImageNormal = imageSwitch.fImageNormal; + fImageDown = imageSwitch.fImageDown; + fIsDown = imageSwitch.fIsDown; + fCallback = imageSwitch.fCallback; + + DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); + + setSize(fImageNormal.getSize()); + + return *this; +} + +bool ImageSwitch::isDown() const noexcept +{ + return fIsDown; +} + +void ImageSwitch::setDown(bool down) noexcept +{ + if (fIsDown == down) + return; + + fIsDown = down; + repaint(); +} + +void ImageSwitch::setCallback(Callback* callback) noexcept +{ + fCallback = callback; +} + +void ImageSwitch::onDisplay() +{ + if (fIsDown) + fImageDown.draw(); + else + fImageNormal.draw(); +} + +bool ImageSwitch::onMouse(const MouseEvent& ev) +{ + if (ev.press && contains(ev.pos)) + { + fIsDown = !fIsDown; + + repaint(); + + if (fCallback != nullptr) + fCallback->imageSwitchClicked(this, fIsDown); + + return true; + } + + return false; +} +#endif + +// -------------------------------------------------------------------------------------------------------------------- + END_NAMESPACE_DGL diff --git a/dgl/src/ImageWidgets.cpp b/dgl/src/ImageWidgets.cpp deleted file mode 100644 index 41d4f1a7..00000000 --- a/dgl/src/ImageWidgets.cpp +++ /dev/null @@ -1,876 +0,0 @@ -/* - * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho - * - * 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. - */ - -#include "../ImageWidgets.hpp" -#include "WidgetPrivateData.hpp" - -// TODO make this code more generic and move GL specific bits to OpenGL.cpp -#include "../OpenGL.hpp" - -// TODO switch to use templated image type after merging widget-related PRs -#if defined(__GNUC__) && (__GNUC__ >= 6) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - -START_NAMESPACE_DGL - -// ----------------------------------------------------------------------- - -ImageKnob::ImageKnob(Widget* const parentWidget, const Image& image, Orientation orientation) noexcept - : SubWidget(parentWidget), - fImage(image), - fMinimum(0.0f), - fMaximum(1.0f), - fStep(0.0f), - fValue(0.5f), - fValueDef(fValue), - fValueTmp(fValue), - fUsingDefault(false), - fUsingLog(false), - fOrientation(orientation), - fRotationAngle(0), - fDragging(false), - fLastX(0), - fLastY(0), - fCallback(nullptr), - fIsImgVertical(image.getHeight() > image.getWidth()), - fImgLayerWidth(fIsImgVertical ? image.getWidth() : image.getHeight()), - fImgLayerHeight(fImgLayerWidth), - fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerHeight : image.getWidth()/fImgLayerWidth), - fIsReady(false), - fTextureId(0) -{ - glGenTextures(1, &fTextureId); - setSize(fImgLayerWidth, fImgLayerHeight); -} - -ImageKnob::ImageKnob(const ImageKnob& imageKnob) - : SubWidget(imageKnob.getParentWidget()), - fImage(imageKnob.fImage), - fMinimum(imageKnob.fMinimum), - fMaximum(imageKnob.fMaximum), - fStep(imageKnob.fStep), - fValue(imageKnob.fValue), - fValueDef(imageKnob.fValueDef), - fValueTmp(fValue), - fUsingDefault(imageKnob.fUsingDefault), - fUsingLog(imageKnob.fUsingLog), - fOrientation(imageKnob.fOrientation), - fRotationAngle(imageKnob.fRotationAngle), - fDragging(false), - fLastX(0), - fLastY(0), - fCallback(imageKnob.fCallback), - fIsImgVertical(imageKnob.fIsImgVertical), - fImgLayerWidth(imageKnob.fImgLayerWidth), - fImgLayerHeight(imageKnob.fImgLayerHeight), - fImgLayerCount(imageKnob.fImgLayerCount), - fIsReady(false), - fTextureId(0) -{ - glGenTextures(1, &fTextureId); - setSize(fImgLayerWidth, fImgLayerHeight); -} - -ImageKnob& ImageKnob::operator=(const ImageKnob& imageKnob) -{ - fImage = imageKnob.fImage; - fMinimum = imageKnob.fMinimum; - fMaximum = imageKnob.fMaximum; - fStep = imageKnob.fStep; - fValue = imageKnob.fValue; - fValueDef = imageKnob.fValueDef; - fValueTmp = fValue; - fUsingDefault = imageKnob.fUsingDefault; - fUsingLog = imageKnob.fUsingLog; - fOrientation = imageKnob.fOrientation; - fRotationAngle = imageKnob.fRotationAngle; - fDragging = false; - fLastX = 0; - fLastY = 0; - fCallback = imageKnob.fCallback; - fIsImgVertical = imageKnob.fIsImgVertical; - fImgLayerWidth = imageKnob.fImgLayerWidth; - fImgLayerHeight = imageKnob.fImgLayerHeight; - fImgLayerCount = imageKnob.fImgLayerCount; - fIsReady = false; - - if (fTextureId != 0) - { - glDeleteTextures(1, &fTextureId); - fTextureId = 0; - } - - glGenTextures(1, &fTextureId); - setSize(fImgLayerWidth, fImgLayerHeight); - - return *this; -} - -ImageKnob::~ImageKnob() -{ - if (fTextureId != 0) - { - glDeleteTextures(1, &fTextureId); - fTextureId = 0; - } -} - -float ImageKnob::getValue() const noexcept -{ - return fValue; -} - -// NOTE: value is assumed to be scaled if using log -void ImageKnob::setDefault(float value) noexcept -{ - fValueDef = value; - fUsingDefault = true; -} - -void ImageKnob::setRange(float min, float max) noexcept -{ - DISTRHO_SAFE_ASSERT_RETURN(max > min,); - - if (fValue < min) - { - fValue = min; - repaint(); - - if (fCallback != nullptr) - { - try { - fCallback->imageKnobValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange < min"); - } - } - else if (fValue > max) - { - fValue = max; - repaint(); - - if (fCallback != nullptr) - { - try { - fCallback->imageKnobValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange > max"); - } - } - - fMinimum = min; - fMaximum = max; -} - -void ImageKnob::setStep(float step) noexcept -{ - fStep = step; -} - -// NOTE: value is assumed to be scaled if using log -void ImageKnob::setValue(float value, bool sendCallback) noexcept -{ - if (d_isEqual(fValue, value)) - return; - - fValue = value; - - if (d_isZero(fStep)) - fValueTmp = value; - - if (fRotationAngle == 0) - fIsReady = false; - - repaint(); - - if (sendCallback && fCallback != nullptr) - { - try { - fCallback->imageKnobValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageKnob::setValue"); - } -} - -void ImageKnob::setUsingLogScale(bool yesNo) noexcept -{ - fUsingLog = yesNo; -} - -void ImageKnob::setCallback(Callback* callback) noexcept -{ - fCallback = callback; -} - -void ImageKnob::setOrientation(Orientation orientation) noexcept -{ - if (fOrientation == orientation) - return; - - fOrientation = orientation; -} - -void ImageKnob::setRotationAngle(int angle) -{ - if (fRotationAngle == angle) - return; - - fRotationAngle = angle; - fIsReady = false; -} - -void ImageKnob::setImageLayerCount(uint count) noexcept -{ - DISTRHO_SAFE_ASSERT_RETURN(count > 1,); - - fImgLayerCount = count; - - if (fIsImgVertical) - fImgLayerHeight = fImage.getHeight()/count; - else - fImgLayerWidth = fImage.getWidth()/count; - - setSize(fImgLayerWidth, fImgLayerHeight); -} - -void ImageKnob::onDisplay() -{ - const float normValue = ((fUsingLog ? _invlogscale(fValue) : fValue) - fMinimum) / (fMaximum - fMinimum); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, fTextureId); - - if (! fIsReady) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - uint imageDataOffset = 0; - - if (fRotationAngle == 0) - { - DISTRHO_SAFE_ASSERT_RETURN(fImgLayerCount > 0,); - DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); - - const uint& v1(fIsImgVertical ? fImgLayerWidth : fImgLayerHeight); - const uint& v2(fIsImgVertical ? fImgLayerHeight : fImgLayerWidth); - - const uint layerDataSize = v1 * v2 * ((fImage.getFormat() == kImageFormatBGRA || - fImage.getFormat() == kImageFormatRGBA) ? 4 : 3); - /* */ imageDataOffset = layerDataSize * uint(normValue * float(fImgLayerCount-1)); - } - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - static_cast(getWidth()), static_cast(getHeight()), 0, - asOpenGLImageFormat(fImage.getFormat()), GL_UNSIGNED_BYTE, fImage.getRawData() + imageDataOffset); - - fIsReady = true; - } - - const int w = static_cast(getWidth()); - const int h = static_cast(getHeight()); - - if (fRotationAngle != 0) - { - glPushMatrix(); - - const int w2 = w/2; - const int h2 = h/2; - - glTranslatef(static_cast(w2), static_cast(h2), 0.0f); - glRotatef(normValue*static_cast(fRotationAngle), 0.0f, 0.0f, 1.0f); - - Rectangle(-w2, -h2, w, h).draw(); - - glPopMatrix(); - } - else - { - Rectangle(0, 0, w, h).draw(); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); -} - -bool ImageKnob::onMouse(const MouseEvent& ev) -{ - if (ev.button != 1) - return false; - - if (ev.press) - { - if (! contains(ev.pos)) - return false; - - if ((ev.mod & kModifierShift) != 0 && fUsingDefault) - { - setValue(fValueDef, true); - fValueTmp = fValue; - return true; - } - - fDragging = true; - fLastX = ev.pos.getX(); - fLastY = ev.pos.getY(); - - if (fCallback != nullptr) - fCallback->imageKnobDragStarted(this); - - return true; - } - else if (fDragging) - { - if (fCallback != nullptr) - fCallback->imageKnobDragFinished(this); - - fDragging = false; - return true; - } - - return false; -} - -bool ImageKnob::onMotion(const MotionEvent& ev) -{ - if (! fDragging) - return false; - - bool doVal = false; - float d, value = 0.0f; - - if (fOrientation == ImageKnob::Horizontal) - { - if (const int movX = ev.pos.getX() - fLastX) - { - d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; - value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movX)); - doVal = true; - } - } - else if (fOrientation == ImageKnob::Vertical) - { - if (const int movY = fLastY - ev.pos.getY()) - { - d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; - value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movY)); - doVal = true; - } - } - - if (! doVal) - return false; - - if (fUsingLog) - value = _logscale(value); - - if (value < fMinimum) - { - fValueTmp = value = fMinimum; - } - else if (value > fMaximum) - { - fValueTmp = value = fMaximum; - } - else if (d_isNotZero(fStep)) - { - fValueTmp = value; - const float rest = std::fmod(value, fStep); - value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); - } - - setValue(value, true); - - fLastX = ev.pos.getX(); - fLastY = ev.pos.getY(); - - return true; -} - -bool ImageKnob::onScroll(const ScrollEvent& ev) -{ - if (! contains(ev.pos)) - return false; - - const float d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; - float value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * 10.f * ev.delta.getY()); - - if (fUsingLog) - value = _logscale(value); - - if (value < fMinimum) - { - fValueTmp = value = fMinimum; - } - else if (value > fMaximum) - { - fValueTmp = value = fMaximum; - } - else if (d_isNotZero(fStep)) - { - fValueTmp = value; - const float rest = std::fmod(value, fStep); - value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); - } - - setValue(value, true); - return true; -} - -// ----------------------------------------------------------------------- - -float ImageKnob::_logscale(float value) const -{ - const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum); - const float a = fMaximum/std::exp(fMaximum*b); - return a * std::exp(b*value); -} - -float ImageKnob::_invlogscale(float value) const -{ - const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum); - const float a = fMaximum/std::exp(fMaximum*b); - return std::log(value/a)/b; -} - -// ----------------------------------------------------------------------- - -ImageSlider::ImageSlider(Widget* const parentWidget, const Image& image) noexcept - : SubWidget(parentWidget), - fImage(image), - fMinimum(0.0f), - fMaximum(1.0f), - fStep(0.0f), - fValue(0.5f), - fValueDef(fValue), - fValueTmp(fValue), - fUsingDefault(false), - fDragging(false), - fInverted(false), - fValueIsSet(false), - fStartedX(0), - fStartedY(0), - fCallback(nullptr), - fStartPos(), - fEndPos(), - fSliderArea() -{ - setNeedsFullViewportDrawing(); -} - -float ImageSlider::getValue() const noexcept -{ - return fValue; -} - -void ImageSlider::setValue(float value, bool sendCallback) noexcept -{ - if (! fValueIsSet) - fValueIsSet = true; - - if (d_isEqual(fValue, value)) - return; - - fValue = value; - - if (d_isZero(fStep)) - fValueTmp = value; - - repaint(); - - if (sendCallback && fCallback != nullptr) - { - try { - fCallback->imageSliderValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageSlider::setValue"); - } -} - -void ImageSlider::setStartPos(const Point& startPos) noexcept -{ - fStartPos = startPos; - _recheckArea(); -} - -void ImageSlider::setStartPos(int x, int y) noexcept -{ - setStartPos(Point(x, y)); -} - -void ImageSlider::setEndPos(const Point& endPos) noexcept -{ - fEndPos = endPos; - _recheckArea(); -} - -void ImageSlider::setEndPos(int x, int y) noexcept -{ - setEndPos(Point(x, y)); -} - -void ImageSlider::setInverted(bool inverted) noexcept -{ - if (fInverted == inverted) - return; - - fInverted = inverted; - repaint(); -} - -void ImageSlider::setDefault(float value) noexcept -{ - fValueDef = value; - fUsingDefault = true; -} - -void ImageSlider::setRange(float min, float max) noexcept -{ - fMinimum = min; - fMaximum = max; - - if (fValue < min) - { - fValue = min; - repaint(); - - if (fCallback != nullptr && fValueIsSet) - { - try { - fCallback->imageSliderValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange < min"); - } - } - else if (fValue > max) - { - fValue = max; - repaint(); - - if (fCallback != nullptr && fValueIsSet) - { - try { - fCallback->imageSliderValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange > max"); - } - } -} - -void ImageSlider::setStep(float step) noexcept -{ - fStep = step; -} - -void ImageSlider::setCallback(Callback* callback) noexcept -{ - fCallback = callback; -} - -void ImageSlider::onDisplay() -{ -#if 0 // DEBUG, paints slider area - glColor3f(0.4f, 0.5f, 0.1f); - glRecti(fSliderArea.getX(), fSliderArea.getY(), fSliderArea.getX()+fSliderArea.getWidth(), fSliderArea.getY()+fSliderArea.getHeight()); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); -#endif - - const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum); - - int x, y; - - if (fStartPos.getY() == fEndPos.getY()) - { - // horizontal - if (fInverted) - x = fEndPos.getX() - static_cast(normValue*static_cast(fEndPos.getX()-fStartPos.getX())); - else - x = fStartPos.getX() + static_cast(normValue*static_cast(fEndPos.getX()-fStartPos.getX())); - - y = fStartPos.getY(); - } - else - { - // vertical - x = fStartPos.getX(); - - if (fInverted) - y = fEndPos.getY() - static_cast(normValue*static_cast(fEndPos.getY()-fStartPos.getY())); - else - y = fStartPos.getY() + static_cast(normValue*static_cast(fEndPos.getY()-fStartPos.getY())); - } - - fImage.drawAt(x, y); -} - -bool ImageSlider::onMouse(const MouseEvent& ev) -{ - if (ev.button != 1) - return false; - - if (ev.press) - { - if (! fSliderArea.contains(ev.pos)) - return false; - - if ((ev.mod & kModifierShift) != 0 && fUsingDefault) - { - setValue(fValueDef, true); - fValueTmp = fValue; - return true; - } - - float vper; - const int x = ev.pos.getX(); - const int y = ev.pos.getY(); - - if (fStartPos.getY() == fEndPos.getY()) - { - // horizontal - vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth()); - } - else - { - // vertical - vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); - } - - float value; - - if (fInverted) - value = fMaximum - vper * (fMaximum - fMinimum); - else - value = fMinimum + vper * (fMaximum - fMinimum); - - if (value < fMinimum) - { - fValueTmp = value = fMinimum; - } - else if (value > fMaximum) - { - fValueTmp = value = fMaximum; - } - else if (d_isNotZero(fStep)) - { - fValueTmp = value; - const float rest = std::fmod(value, fStep); - value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); - } - - fDragging = true; - fStartedX = x; - fStartedY = y; - - if (fCallback != nullptr) - fCallback->imageSliderDragStarted(this); - - setValue(value, true); - - return true; - } - else if (fDragging) - { - if (fCallback != nullptr) - fCallback->imageSliderDragFinished(this); - - fDragging = false; - return true; - } - - return false; -} - -bool ImageSlider::onMotion(const MotionEvent& ev) -{ - if (! fDragging) - return false; - - const bool horizontal = fStartPos.getY() == fEndPos.getY(); - const int x = ev.pos.getX(); - const int y = ev.pos.getY(); - - if ((horizontal && fSliderArea.containsX(x)) || (fSliderArea.containsY(y) && ! horizontal)) - { - float vper; - - if (horizontal) - { - // horizontal - vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth()); - } - else - { - // vertical - vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); - } - - float value; - - if (fInverted) - value = fMaximum - vper * (fMaximum - fMinimum); - else - value = fMinimum + vper * (fMaximum - fMinimum); - - if (value < fMinimum) - { - fValueTmp = value = fMinimum; - } - else if (value > fMaximum) - { - fValueTmp = value = fMaximum; - } - else if (d_isNotZero(fStep)) - { - fValueTmp = value; - const float rest = std::fmod(value, fStep); - value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); - } - - setValue(value, true); - } - else if (horizontal) - { - if (x < fSliderArea.getX()) - setValue(fInverted ? fMaximum : fMinimum, true); - else - setValue(fInverted ? fMinimum : fMaximum, true); - } - else - { - if (y < fSliderArea.getY()) - setValue(fInverted ? fMaximum : fMinimum, true); - else - setValue(fInverted ? fMinimum : fMaximum, true); - } - - return true; -} - -void ImageSlider::_recheckArea() noexcept -{ - if (fStartPos.getY() == fEndPos.getY()) - { - // horizontal - fSliderArea = Rectangle(fStartPos.getX(), - fStartPos.getY(), - fEndPos.getX() + static_cast(fImage.getWidth()) - fStartPos.getX(), - static_cast(fImage.getHeight())); - } - else - { - // vertical - fSliderArea = Rectangle(fStartPos.getX(), - fStartPos.getY(), - static_cast(fImage.getWidth()), - fEndPos.getY() + static_cast(fImage.getHeight()) - fStartPos.getY()); - } -} - -// ----------------------------------------------------------------------- - -ImageSwitch::ImageSwitch(Widget* parentWidget, const Image& imageNormal, const Image& imageDown) noexcept - : SubWidget(parentWidget), - fImageNormal(imageNormal), - fImageDown(imageDown), - fIsDown(false), - fCallback(nullptr) -{ - DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); - - setSize(fImageNormal.getSize()); -} - -ImageSwitch::ImageSwitch(const ImageSwitch& imageSwitch) noexcept - : SubWidget(imageSwitch.getParentWidget()), - fImageNormal(imageSwitch.fImageNormal), - fImageDown(imageSwitch.fImageDown), - fIsDown(imageSwitch.fIsDown), - fCallback(imageSwitch.fCallback) -{ - DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); - - setSize(fImageNormal.getSize()); -} - -ImageSwitch& ImageSwitch::operator=(const ImageSwitch& imageSwitch) noexcept -{ - fImageNormal = imageSwitch.fImageNormal; - fImageDown = imageSwitch.fImageDown; - fIsDown = imageSwitch.fIsDown; - fCallback = imageSwitch.fCallback; - - DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); - - setSize(fImageNormal.getSize()); - - return *this; -} - -bool ImageSwitch::isDown() const noexcept -{ - return fIsDown; -} - -void ImageSwitch::setDown(bool down) noexcept -{ - if (fIsDown == down) - return; - - fIsDown = down; - repaint(); -} - -void ImageSwitch::setCallback(Callback* callback) noexcept -{ - fCallback = callback; -} - -void ImageSwitch::onDisplay() -{ - if (fIsDown) - fImageDown.draw(); - else - fImageNormal.draw(); -} - -bool ImageSwitch::onMouse(const MouseEvent& ev) -{ - if (ev.press && contains(ev.pos)) - { - fIsDown = !fIsDown; - - repaint(); - - if (fCallback != nullptr) - fCallback->imageSwitchClicked(this, fIsDown); - - return true; - } - - return false; -} - -// ----------------------------------------------------------------------- - -END_NAMESPACE_DGL - -#if defined(__GNUC__) && (__GNUC__ >= 6) -# pragma GCC diagnostic pop -#endif