| @@ -19,7 +19,6 @@ | |||||
| #include "ImageBase.hpp" | #include "ImageBase.hpp" | ||||
| #include "ImageBaseWidgets.hpp" | #include "ImageBaseWidgets.hpp" | ||||
| #include "SubWidget.hpp" | |||||
| #include <cairo/cairo.h> | #include <cairo/cairo.h> | ||||
| @@ -115,25 +114,21 @@ class CairoBaseWidget : public BaseWidget | |||||
| public: | public: | ||||
| /** | /** | ||||
| Constructor for a CairoSubWidget. | Constructor for a CairoSubWidget. | ||||
| @see CreateFlags | |||||
| */ | */ | ||||
| explicit CairoBaseWidget(Widget* const parentGroupWidget); | explicit CairoBaseWidget(Widget* const parentGroupWidget); | ||||
| /** | /** | ||||
| Constructor for a CairoTopLevelWidget. | Constructor for a CairoTopLevelWidget. | ||||
| @see CreateFlags | |||||
| */ | */ | ||||
| explicit CairoBaseWidget(Window& windowToMapTo); | explicit CairoBaseWidget(Window& windowToMapTo); | ||||
| /** | /** | ||||
| Constructor for a CairoStandaloneWindow without parent window. | Constructor for a CairoStandaloneWindow without parent window. | ||||
| @see CreateFlags | |||||
| */ | */ | ||||
| explicit CairoBaseWidget(Application& app); | explicit CairoBaseWidget(Application& app); | ||||
| /** | /** | ||||
| Constructor for a CairoStandaloneWindow with parent window. | Constructor for a CairoStandaloneWindow with parent window. | ||||
| @see CreateFlags | |||||
| */ | */ | ||||
| explicit CairoBaseWidget(Application& app, Window& parentWindow); | explicit CairoBaseWidget(Application& app, Window& parentWindow); | ||||
| @@ -171,6 +166,9 @@ typedef CairoBaseWidget<StandaloneWindow> CairoStandaloneWindow; | |||||
| typedef ImageBaseAboutWindow<CairoImage> CairoImageAboutWindow; | typedef ImageBaseAboutWindow<CairoImage> CairoImageAboutWindow; | ||||
| typedef ImageBaseButton<CairoImage> CairoImageButton; | typedef ImageBaseButton<CairoImage> CairoImageButton; | ||||
| typedef ImageBaseKnob<CairoImage> CairoImageKnob; | |||||
| typedef ImageBaseSlider<CairoImage> CairoImageSlider; | |||||
| typedef ImageBaseSwitch<CairoImage> CairoImageSwitch; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -82,6 +82,205 @@ private: | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| template <class ImageType> | |||||
| 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 ImageType> | |||||
| 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<int>& startPos) noexcept; | |||||
| void setStartPos(int x, int y) noexcept; | |||||
| void setEndPos(const Point<int>& 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<int> fStartPos; | |||||
| Point<int> fEndPos; | |||||
| Rectangle<double> 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<int>&) const noexcept {} | |||||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageBaseSlider) | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| template <class ImageType> | |||||
| 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 | END_NAMESPACE_DGL | ||||
| #endif // DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | #endif // DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | ||||
| @@ -17,206 +17,25 @@ | |||||
| #ifndef DGL_IMAGE_WIDGETS_HPP_INCLUDED | #ifndef DGL_IMAGE_WIDGETS_HPP_INCLUDED | ||||
| #define 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 | 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<int>& startPos) noexcept; | |||||
| void setStartPos(int x, int y) noexcept; | |||||
| void setEndPos(const Point<int>& 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<int> fStartPos; | |||||
| Point<int> fEndPos; | |||||
| Rectangle<double> 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<int>&) 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 | END_NAMESPACE_DGL | ||||
| #if defined(__GNUC__) && (__GNUC__ >= 6) | |||||
| # pragma GCC diagnostic pop | |||||
| #endif | |||||
| #endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED | #endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED | ||||
| @@ -56,7 +56,6 @@ endif | |||||
| OBJS_opengl = $(OBJS_common) \ | OBJS_opengl = $(OBJS_common) \ | ||||
| ../build/dgl/OpenGL.cpp.opengl.o \ | ../build/dgl/OpenGL.cpp.opengl.o \ | ||||
| ../build/dgl/ImageWidgets.cpp.o \ | |||||
| ../build/dgl/NanoVG.cpp.opengl.o | ../build/dgl/NanoVG.cpp.opengl.o | ||||
| ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
| @@ -282,12 +282,9 @@ private: | |||||
| typedef ImageBaseAboutWindow<OpenGLImage> OpenGLImageAboutWindow; | typedef ImageBaseAboutWindow<OpenGLImage> OpenGLImageAboutWindow; | ||||
| typedef ImageBaseButton<OpenGLImage> OpenGLImageButton; | typedef ImageBaseButton<OpenGLImage> OpenGLImageButton; | ||||
| DISTRHO_DEPRECATED_BY("OpenGLImageAboutWindow") | |||||
| typedef OpenGLImageAboutWindow ImageAboutWindow; | |||||
| DISTRHO_DEPRECATED_BY("OpenGLImageButton") | |||||
| typedef OpenGLImageButton ImageButton; | |||||
| typedef ImageBaseKnob<OpenGLImage> OpenGLImageKnob; | |||||
| typedef ImageBaseSlider<OpenGLImage> OpenGLImageSlider; | |||||
| typedef ImageBaseSwitch<OpenGLImage> OpenGLImageSwitch; | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -180,4 +180,857 @@ bool ImageBaseButton<ImageType>::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<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0, | |||||
| asOpenGLImageFormat(fImage.getFormat()), GL_UNSIGNED_BYTE, fImage.getRawData() + imageDataOffset); | |||||
| fIsReady = true; | |||||
| } | |||||
| const int w = static_cast<int>(getWidth()); | |||||
| const int h = static_cast<int>(getHeight()); | |||||
| if (fRotationAngle != 0) | |||||
| { | |||||
| glPushMatrix(); | |||||
| const int w2 = w/2; | |||||
| const int h2 = h/2; | |||||
| glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f); | |||||
| glRotatef(normValue*static_cast<float>(fRotationAngle), 0.0f, 0.0f, 1.0f); | |||||
| Rectangle<int>(-w2, -h2, w, h).draw(); | |||||
| glPopMatrix(); | |||||
| } | |||||
| else | |||||
| { | |||||
| Rectangle<int>(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<int>& startPos) noexcept | |||||
| { | |||||
| fStartPos = startPos; | |||||
| _recheckArea(); | |||||
| } | |||||
| void ImageSlider::setStartPos(int x, int y) noexcept | |||||
| { | |||||
| setStartPos(Point<int>(x, y)); | |||||
| } | |||||
| void ImageSlider::setEndPos(const Point<int>& endPos) noexcept | |||||
| { | |||||
| fEndPos = endPos; | |||||
| _recheckArea(); | |||||
| } | |||||
| void ImageSlider::setEndPos(int x, int y) noexcept | |||||
| { | |||||
| setEndPos(Point<int>(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<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX())); | |||||
| else | |||||
| x = fStartPos.getX() + static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX())); | |||||
| y = fStartPos.getY(); | |||||
| } | |||||
| else | |||||
| { | |||||
| // vertical | |||||
| x = fStartPos.getX(); | |||||
| if (fInverted) | |||||
| y = fEndPos.getY() - static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY())); | |||||
| else | |||||
| y = fStartPos.getY() + static_cast<int>(normValue*static_cast<float>(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<double>(fStartPos.getX(), | |||||
| fStartPos.getY(), | |||||
| fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(), | |||||
| static_cast<int>(fImage.getHeight())); | |||||
| } | |||||
| else | |||||
| { | |||||
| // vertical | |||||
| fSliderArea = Rectangle<double>(fStartPos.getX(), | |||||
| fStartPos.getY(), | |||||
| static_cast<int>(fImage.getWidth()), | |||||
| fEndPos.getY() + static_cast<int>(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 | END_NAMESPACE_DGL | ||||
| @@ -1,876 +0,0 @@ | |||||
| /* | |||||
| * DISTRHO Plugin Framework (DPF) | |||||
| * Copyright (C) 2012-2019 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. | |||||
| */ | |||||
| #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<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0, | |||||
| asOpenGLImageFormat(fImage.getFormat()), GL_UNSIGNED_BYTE, fImage.getRawData() + imageDataOffset); | |||||
| fIsReady = true; | |||||
| } | |||||
| const int w = static_cast<int>(getWidth()); | |||||
| const int h = static_cast<int>(getHeight()); | |||||
| if (fRotationAngle != 0) | |||||
| { | |||||
| glPushMatrix(); | |||||
| const int w2 = w/2; | |||||
| const int h2 = h/2; | |||||
| glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f); | |||||
| glRotatef(normValue*static_cast<float>(fRotationAngle), 0.0f, 0.0f, 1.0f); | |||||
| Rectangle<int>(-w2, -h2, w, h).draw(); | |||||
| glPopMatrix(); | |||||
| } | |||||
| else | |||||
| { | |||||
| Rectangle<int>(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<int>& startPos) noexcept | |||||
| { | |||||
| fStartPos = startPos; | |||||
| _recheckArea(); | |||||
| } | |||||
| void ImageSlider::setStartPos(int x, int y) noexcept | |||||
| { | |||||
| setStartPos(Point<int>(x, y)); | |||||
| } | |||||
| void ImageSlider::setEndPos(const Point<int>& endPos) noexcept | |||||
| { | |||||
| fEndPos = endPos; | |||||
| _recheckArea(); | |||||
| } | |||||
| void ImageSlider::setEndPos(int x, int y) noexcept | |||||
| { | |||||
| setEndPos(Point<int>(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<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX())); | |||||
| else | |||||
| x = fStartPos.getX() + static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX())); | |||||
| y = fStartPos.getY(); | |||||
| } | |||||
| else | |||||
| { | |||||
| // vertical | |||||
| x = fStartPos.getX(); | |||||
| if (fInverted) | |||||
| y = fEndPos.getY() - static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY())); | |||||
| else | |||||
| y = fStartPos.getY() + static_cast<int>(normValue*static_cast<float>(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<double>(fStartPos.getX(), | |||||
| fStartPos.getY(), | |||||
| fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(), | |||||
| static_cast<int>(fImage.getHeight())); | |||||
| } | |||||
| else | |||||
| { | |||||
| // vertical | |||||
| fSliderArea = Rectangle<double>(fStartPos.getX(), | |||||
| fStartPos.getY(), | |||||
| static_cast<int>(fImage.getWidth()), | |||||
| fEndPos.getY() + static_cast<int>(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 | |||||