commit 5171f69a2129f87ae3803ce7c2ee2c813a949221
parent 8f99465b717e816cb301548d7d3790de56c9ec28
Author: falkTX <falktx@gmail.com>
Date: Tue, 5 May 2015 01:27:13 +0200
Move Image Widgets implementation into a single file
Diffstat:
8 files changed, 1187 insertions(+), 1286 deletions(-)
diff --git a/dgl/ImageWidgets.hpp b/dgl/ImageWidgets.hpp
@@ -43,7 +43,6 @@ protected:
private:
Image fImgBackground;
- //DISTRHO_DECLARE_NON_COPY_CLASS(ImageAboutWindow)
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageAboutWindow)
};
diff --git a/dgl/Makefile b/dgl/Makefile
@@ -19,11 +19,7 @@ OBJS = \
src/Color.cpp.o \
src/Geometry.cpp.o \
src/Image.cpp.o \
- src/ImageAboutWindow.cpp.o \
- src/ImageButton.cpp.o \
- src/ImageKnob.cpp.o \
- src/ImageSlider.cpp.o \
- src/ImageSwitch.cpp.o \
+ src/ImageWidgets.cpp.o \
src/NanoVG.cpp.o \
src/Widget.cpp.o
diff --git a/dgl/src/ImageAboutWindow.cpp b/dgl/src/ImageAboutWindow.cpp
@@ -1,89 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2015 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"
-
-START_NAMESPACE_DGL
-
-// -----------------------------------------------------------------------
-
-ImageAboutWindow::ImageAboutWindow(Window& parent, const Image& image)
- : Window(parent.getApp(), parent),
- Widget((Window&)*this),
- fImgBackground(image)/*,
- leakDetector_ImageAboutWindow()*/
-{
- Window::setResizable(false);
- Window::setSize(static_cast<uint>(image.getWidth()), static_cast<uint>(image.getHeight()));
- Window::setTitle("About");
-}
-
-ImageAboutWindow::ImageAboutWindow(Widget* widget, const Image& image)
- : Window(widget->getParentApp(), widget->getParentWindow()),
- Widget((Window&)*this),
- fImgBackground(image)/*,
- leakDetector_ImageAboutWindow()*/
-{
- Window::setResizable(false);
- Window::setSize(static_cast<uint>(image.getWidth()), static_cast<uint>(image.getHeight()));
- Window::setTitle("About");
-}
-
-void ImageAboutWindow::setImage(const Image& image)
-{
- if (fImgBackground == image)
- return;
-
- fImgBackground = image;
- Window::setSize(static_cast<uint>(image.getWidth()), static_cast<uint>(image.getHeight()));
-}
-
-void ImageAboutWindow::onDisplay()
-{
- fImgBackground.draw();
-}
-
-bool ImageAboutWindow::onKeyboard(const KeyboardEvent& ev)
-{
- if (ev.press && ev.key == CHAR_ESCAPE)
- {
- Window::close();
- return true;
- }
-
- return false;
-}
-
-bool ImageAboutWindow::onMouse(const MouseEvent& ev)
-{
- if (ev.press)
- {
- Window::close();
- return true;
- }
-
- return false;
-}
-
-void ImageAboutWindow::onReshape(uint width, uint height)
-{
- Widget::setSize(width, height);
- Window::onReshape(width, height);
-}
-
-// -----------------------------------------------------------------------
-
-END_NAMESPACE_DGL
diff --git a/dgl/src/ImageButton.cpp b/dgl/src/ImageButton.cpp
@@ -1,190 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2015 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"
-
-START_NAMESPACE_DGL
-
-// -----------------------------------------------------------------------
-
-ImageButton::ImageButton(Window& parent, const Image& image) noexcept
- : Widget(parent),
- fImageNormal(image),
- fImageHover(image),
- fImageDown(image),
- fCurImage(&fImageNormal),
- fCurButton(-1),
- fCallback(nullptr),
- leakDetector_ImageButton() {}
-
-ImageButton::ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown) noexcept
- : Widget(parent),
- fImageNormal(imageNormal),
- fImageHover(imageHover),
- fImageDown(imageDown),
- fCurImage(&fImageNormal),
- fCurButton(-1),
- fCallback(nullptr),
- leakDetector_ImageButton()
-{
- DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
-
- setSize(fCurImage->getSize());
-}
-
-ImageButton::ImageButton(Widget* widget, const Image& image) noexcept
- : Widget(widget->getParentWindow()),
- fImageNormal(image),
- fImageHover(image),
- fImageDown(image),
- fCurImage(&fImageNormal),
- fCurButton(-1),
- fCallback(nullptr),
- leakDetector_ImageButton() {}
-
-ImageButton::ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown) noexcept
- : Widget(widget->getParentWindow()),
- fImageNormal(imageNormal),
- fImageHover(imageHover),
- fImageDown(imageDown),
- fCurImage(&fImageNormal),
- fCurButton(-1),
- fCallback(nullptr),
- leakDetector_ImageButton()
-{
- DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
-
- setSize(fCurImage->getSize());
-}
-
-ImageButton::ImageButton(const ImageButton& imageButton) noexcept
- : Widget(imageButton.getParentWindow()),
- fImageNormal(imageButton.fImageNormal),
- fImageHover(imageButton.fImageHover),
- fImageDown(imageButton.fImageDown),
- fCurImage(&fImageNormal),
- fCurButton(-1),
- fCallback(imageButton.fCallback),
- leakDetector_ImageButton()
-{
- DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
-
- setSize(fCurImage->getSize());
-}
-
-ImageButton& ImageButton::operator=(const ImageButton& imageButton) noexcept
-{
- fImageNormal = imageButton.fImageNormal;
- fImageHover = imageButton.fImageHover;
- fImageDown = imageButton.fImageDown;
- fCurImage = &fImageNormal;
- fCurButton = -1;
- fCallback = imageButton.fCallback;
-
- DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
-
- setSize(fCurImage->getSize());
-
- return *this;
-}
-
-void ImageButton::setCallback(Callback* callback) noexcept
-{
- fCallback = callback;
-}
-
-void ImageButton::onDisplay()
-{
- fCurImage->draw();
-}
-
-bool ImageButton::onMouse(const MouseEvent& ev)
-{
- if (fCurButton != -1 && ! ev.press)
- {
- if (fCurImage != &fImageNormal)
- {
- fCurImage = &fImageNormal;
- repaint();
- }
-
- if (! contains(ev.pos))
- {
- fCurButton = -1;
- return false;
- }
-
- if (fCallback != nullptr)
- fCallback->imageButtonClicked(this, fCurButton);
-
-#if 0
- if (contains(ev.pos))
- {
- fCurImage = &fImageHover;
- repaint();
- }
-#endif
-
- fCurButton = -1;
-
- return true;
- }
-
- if (ev.press && contains(ev.pos))
- {
- if (fCurImage != &fImageDown)
- {
- fCurImage = &fImageDown;
- repaint();
- }
-
- fCurButton = ev.button;
- return true;
- }
-
- return false;
-}
-
-bool ImageButton::onMotion(const MotionEvent& ev)
-{
- if (fCurButton != -1)
- return true;
-
- if (contains(ev.pos))
- {
- if (fCurImage != &fImageHover)
- {
- fCurImage = &fImageHover;
- repaint();
- }
-
- return true;
- }
- else
- {
- if (fCurImage != &fImageNormal)
- {
- fCurImage = &fImageNormal;
- repaint();
- }
-
- return false;
- }
-}
-
-// -----------------------------------------------------------------------
-
-END_NAMESPACE_DGL
diff --git a/dgl/src/ImageKnob.cpp b/dgl/src/ImageKnob.cpp
@@ -1,480 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2015 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 <cmath>
-
-START_NAMESPACE_DGL
-
-// -----------------------------------------------------------------------
-
-ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation) noexcept
- : Widget(parent),
- 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),
- leakDetector_ImageKnob()
-{
- glGenTextures(1, &fTextureId);
- setSize(fImgLayerWidth, fImgLayerHeight);
-}
-
-ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation) noexcept
- : Widget(widget->getParentWindow()),
- 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),
- leakDetector_ImageKnob()
-{
- glGenTextures(1, &fTextureId);
- setSize(fImgLayerWidth, fImgLayerHeight);
-}
-
-ImageKnob::ImageKnob(const ImageKnob& imageKnob)
- : Widget(imageKnob.getParentWindow()),
- 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),
- leakDetector_ImageKnob()
-{
- 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() == GL_BGRA || fImage.getFormat() == GL_RGBA) ? 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,
- fImage.getFormat(), fImage.getType(), 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 & MODIFIER_SHIFT) != 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 & MODIFIER_CTRL) ? 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 & MODIFIER_CTRL) ? 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 & MODIFIER_CTRL) ? 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;
-}
-
-// -----------------------------------------------------------------------
-
-END_NAMESPACE_DGL
diff --git a/dgl/src/ImageSlider.cpp b/dgl/src/ImageSlider.cpp
@@ -1,399 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2015 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 <cmath>
-
-START_NAMESPACE_DGL
-
-// -----------------------------------------------------------------------
-
-ImageSlider::ImageSlider(Window& parent, const Image& image) noexcept
- : Widget(parent),
- fImage(image),
- fMinimum(0.0f),
- fMaximum(1.0f),
- fStep(0.0f),
- fValue(0.5f),
- fValueTmp(fValue),
- fDragging(false),
- fInverted(false),
- fStartedX(0),
- fStartedY(0),
- fCallback(nullptr),
- fStartPos(),
- fEndPos(),
- fSliderArea(),
- leakDetector_ImageSlider()
-{
- fNeedsFullViewport = true;
-}
-
-ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept
- : Widget(widget->getParentWindow()),
- fImage(image),
- fMinimum(0.0f),
- fMaximum(1.0f),
- fStep(0.0f),
- fValue(0.5f),
- fValueTmp(fValue),
- fDragging(false),
- fInverted(false),
- fStartedX(0),
- fStartedY(0),
- fCallback(nullptr),
- fStartPos(),
- fEndPos(),
- fSliderArea(),
- leakDetector_ImageSlider()
-{
- fNeedsFullViewport = true;
-}
-
-ImageSlider::ImageSlider(const ImageSlider& imageSlider) noexcept
- : Widget(imageSlider.getParentWindow()),
- fImage(imageSlider.fImage),
- fMinimum(imageSlider.fMinimum),
- fMaximum(imageSlider.fMaximum),
- fStep(imageSlider.fStep),
- fValue(imageSlider.fValue),
- fValueTmp(fValue),
- fDragging(false),
- fInverted(imageSlider.fInverted),
- fStartedX(0),
- fStartedY(0),
- fCallback(imageSlider.fCallback),
- fStartPos(imageSlider.fStartPos),
- fEndPos(imageSlider.fEndPos),
- fSliderArea(imageSlider.fSliderArea),
- leakDetector_ImageSlider()
-{
- fNeedsFullViewport = true;
-}
-
-ImageSlider& ImageSlider::operator=(const ImageSlider& imageSlider) noexcept
-{
- fImage = imageSlider.fImage;
- fMinimum = imageSlider.fMinimum;
- fMaximum = imageSlider.fMaximum;
- fStep = imageSlider.fStep;
- fValue = imageSlider.fValue;
- fValueTmp = fValue;
- fDragging = false;
- fInverted = imageSlider.fInverted;
- fStartedX = 0;
- fStartedY = 0;
- fCallback = imageSlider.fCallback;
- fStartPos = imageSlider.fStartPos;
- fEndPos = imageSlider.fEndPos;
- fSliderArea = imageSlider.fSliderArea;
-
- return *this;
-}
-
-float ImageSlider::getValue() const noexcept
-{
- return fValue;
-}
-
-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::setRange(float min, float max) noexcept
-{
- if (fValue < min)
- {
- fValue = min;
- repaint();
-
- if (fCallback != nullptr)
- {
- try {
- fCallback->imageSliderValueChanged(this, fValue);
- } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange < min");
- }
- }
- else if (fValue > max)
- {
- fValue = max;
- repaint();
-
- if (fCallback != nullptr)
- {
- try {
- fCallback->imageSliderValueChanged(this, fValue);
- } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange > max");
- }
- }
-
- fMinimum = min;
- fMaximum = max;
-}
-
-void ImageSlider::setStep(float step) noexcept
-{
- fStep = step;
-}
-
-void ImageSlider::setValue(float value, bool sendCallback) noexcept
-{
- 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::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;
-
- 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<int>(fStartPos.getX(),
- fStartPos.getY(),
- fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(),
- static_cast<int>(fImage.getHeight()));
- }
- else
- {
- // vertical
- fSliderArea = Rectangle<int>(fStartPos.getX(),
- fStartPos.getY(),
- static_cast<int>(fImage.getWidth()),
- fEndPos.getY() + static_cast<int>(fImage.getHeight()) - fStartPos.getY());
- }
-}
-
-// -----------------------------------------------------------------------
-
-END_NAMESPACE_DGL
diff --git a/dgl/src/ImageSwitch.cpp b/dgl/src/ImageSwitch.cpp
@@ -1,122 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2015 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"
-
-START_NAMESPACE_DGL
-
-// -----------------------------------------------------------------------
-
-ImageSwitch::ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept
- : Widget(parent),
- fImageNormal(imageNormal),
- fImageDown(imageDown),
- fIsDown(false),
- fCallback(nullptr),
- leakDetector_ImageSwitch()
-{
- DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize());
-
- setSize(fImageNormal.getSize());
-}
-
-ImageSwitch::ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept
- : Widget(widget->getParentWindow()),
- fImageNormal(imageNormal),
- fImageDown(imageDown),
- fIsDown(false),
- fCallback(nullptr),
- leakDetector_ImageSwitch()
-{
- DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize());
-
- setSize(fImageNormal.getSize());
-}
-
-ImageSwitch::ImageSwitch(const ImageSwitch& imageSwitch) noexcept
- : Widget(imageSwitch.getParentWindow()),
- fImageNormal(imageSwitch.fImageNormal),
- fImageDown(imageSwitch.fImageDown),
- fIsDown(imageSwitch.fIsDown),
- fCallback(imageSwitch.fCallback),
- leakDetector_ImageSwitch()
-{
- 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
diff --git a/dgl/src/ImageWidgets.cpp b/dgl/src/ImageWidgets.cpp
@@ -0,0 +1,1186 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2015 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 <cmath>
+
+START_NAMESPACE_DGL
+
+// -----------------------------------------------------------------------
+
+ImageAboutWindow::ImageAboutWindow(Window& parent, const Image& image)
+ : Window(parent.getApp(), parent),
+ Widget((Window&)*this),
+ fImgBackground(image),
+ leakDetector_ImageAboutWindow()
+{
+ Window::setResizable(false);
+ Window::setSize(image.getSize());
+ Window::setTitle("About");
+}
+
+ImageAboutWindow::ImageAboutWindow(Widget* widget, const Image& image)
+ : Window(widget->getParentApp(), widget->getParentWindow()),
+ Widget((Window&)*this),
+ fImgBackground(image),
+ leakDetector_ImageAboutWindow()
+{
+ Window::setResizable(false);
+ Window::setSize(image.getSize());
+ Window::setTitle("About");
+}
+
+void ImageAboutWindow::setImage(const Image& image)
+{
+ if (fImgBackground == image)
+ return;
+
+ fImgBackground = image;
+ Window::setSize(image.getSize());
+}
+
+void ImageAboutWindow::onDisplay()
+{
+ fImgBackground.draw();
+}
+
+bool ImageAboutWindow::onKeyboard(const KeyboardEvent& ev)
+{
+ if (ev.press && ev.key == CHAR_ESCAPE)
+ {
+ Window::close();
+ return true;
+ }
+
+ return false;
+}
+
+bool ImageAboutWindow::onMouse(const MouseEvent& ev)
+{
+ if (ev.press)
+ {
+ Window::close();
+ return true;
+ }
+
+ return false;
+}
+
+void ImageAboutWindow::onReshape(uint width, uint height)
+{
+ Widget::setSize(width, height);
+ Window::onReshape(width, height);
+}
+
+// -----------------------------------------------------------------------
+
+ImageButton::ImageButton(Window& parent, const Image& image) noexcept
+ : Widget(parent),
+ fImageNormal(image),
+ fImageHover(image),
+ fImageDown(image),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(nullptr),
+ leakDetector_ImageButton() {}
+
+ImageButton::ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown) noexcept
+ : Widget(parent),
+ fImageNormal(imageNormal),
+ fImageHover(imageHover),
+ fImageDown(imageDown),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(nullptr),
+ leakDetector_ImageButton()
+{
+ DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
+
+ setSize(fCurImage->getSize());
+}
+
+ImageButton::ImageButton(Widget* widget, const Image& image) noexcept
+ : Widget(widget->getParentWindow()),
+ fImageNormal(image),
+ fImageHover(image),
+ fImageDown(image),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(nullptr),
+ leakDetector_ImageButton() {}
+
+ImageButton::ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown) noexcept
+ : Widget(widget->getParentWindow()),
+ fImageNormal(imageNormal),
+ fImageHover(imageHover),
+ fImageDown(imageDown),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(nullptr),
+ leakDetector_ImageButton()
+{
+ DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
+
+ setSize(fCurImage->getSize());
+}
+
+ImageButton::ImageButton(const ImageButton& imageButton) noexcept
+ : Widget(imageButton.getParentWindow()),
+ fImageNormal(imageButton.fImageNormal),
+ fImageHover(imageButton.fImageHover),
+ fImageDown(imageButton.fImageDown),
+ fCurImage(&fImageNormal),
+ fCurButton(-1),
+ fCallback(imageButton.fCallback),
+ leakDetector_ImageButton()
+{
+ DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
+
+ setSize(fCurImage->getSize());
+}
+
+ImageButton& ImageButton::operator=(const ImageButton& imageButton) noexcept
+{
+ fImageNormal = imageButton.fImageNormal;
+ fImageHover = imageButton.fImageHover;
+ fImageDown = imageButton.fImageDown;
+ fCurImage = &fImageNormal;
+ fCurButton = -1;
+ fCallback = imageButton.fCallback;
+
+ DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize());
+
+ setSize(fCurImage->getSize());
+
+ return *this;
+}
+
+void ImageButton::setCallback(Callback* callback) noexcept
+{
+ fCallback = callback;
+}
+
+void ImageButton::onDisplay()
+{
+ fCurImage->draw();
+}
+
+bool ImageButton::onMouse(const MouseEvent& ev)
+{
+ if (fCurButton != -1 && ! ev.press)
+ {
+ if (fCurImage != &fImageNormal)
+ {
+ fCurImage = &fImageNormal;
+ repaint();
+ }
+
+ if (! contains(ev.pos))
+ {
+ fCurButton = -1;
+ return false;
+ }
+
+ if (fCallback != nullptr)
+ fCallback->imageButtonClicked(this, fCurButton);
+
+#if 0
+ if (contains(ev.pos))
+ {
+ fCurImage = &fImageHover;
+ repaint();
+ }
+#endif
+
+ fCurButton = -1;
+
+ return true;
+ }
+
+ if (ev.press && contains(ev.pos))
+ {
+ if (fCurImage != &fImageDown)
+ {
+ fCurImage = &fImageDown;
+ repaint();
+ }
+
+ fCurButton = ev.button;
+ return true;
+ }
+
+ return false;
+}
+
+bool ImageButton::onMotion(const MotionEvent& ev)
+{
+ if (fCurButton != -1)
+ return true;
+
+ if (contains(ev.pos))
+ {
+ if (fCurImage != &fImageHover)
+ {
+ fCurImage = &fImageHover;
+ repaint();
+ }
+
+ return true;
+ }
+ else
+ {
+ if (fCurImage != &fImageNormal)
+ {
+ fCurImage = &fImageNormal;
+ repaint();
+ }
+
+ return false;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation) noexcept
+ : Widget(parent),
+ 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),
+ leakDetector_ImageKnob()
+{
+ glGenTextures(1, &fTextureId);
+ setSize(fImgLayerWidth, fImgLayerHeight);
+}
+
+ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation) noexcept
+ : Widget(widget->getParentWindow()),
+ 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),
+ leakDetector_ImageKnob()
+{
+ glGenTextures(1, &fTextureId);
+ setSize(fImgLayerWidth, fImgLayerHeight);
+}
+
+ImageKnob::ImageKnob(const ImageKnob& imageKnob)
+ : Widget(imageKnob.getParentWindow()),
+ 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),
+ leakDetector_ImageKnob()
+{
+ 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() == GL_BGRA || fImage.getFormat() == GL_RGBA) ? 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,
+ fImage.getFormat(), fImage.getType(), 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 & MODIFIER_SHIFT) != 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 & MODIFIER_CTRL) ? 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 & MODIFIER_CTRL) ? 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 & MODIFIER_CTRL) ? 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(Window& parent, const Image& image) noexcept
+ : Widget(parent),
+ fImage(image),
+ fMinimum(0.0f),
+ fMaximum(1.0f),
+ fStep(0.0f),
+ fValue(0.5f),
+ fValueTmp(fValue),
+ fDragging(false),
+ fInverted(false),
+ fStartedX(0),
+ fStartedY(0),
+ fCallback(nullptr),
+ fStartPos(),
+ fEndPos(),
+ fSliderArea(),
+ leakDetector_ImageSlider()
+{
+ fNeedsFullViewport = true;
+}
+
+ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept
+ : Widget(widget->getParentWindow()),
+ fImage(image),
+ fMinimum(0.0f),
+ fMaximum(1.0f),
+ fStep(0.0f),
+ fValue(0.5f),
+ fValueTmp(fValue),
+ fDragging(false),
+ fInverted(false),
+ fStartedX(0),
+ fStartedY(0),
+ fCallback(nullptr),
+ fStartPos(),
+ fEndPos(),
+ fSliderArea(),
+ leakDetector_ImageSlider()
+{
+ fNeedsFullViewport = true;
+}
+
+ImageSlider::ImageSlider(const ImageSlider& imageSlider) noexcept
+ : Widget(imageSlider.getParentWindow()),
+ fImage(imageSlider.fImage),
+ fMinimum(imageSlider.fMinimum),
+ fMaximum(imageSlider.fMaximum),
+ fStep(imageSlider.fStep),
+ fValue(imageSlider.fValue),
+ fValueTmp(fValue),
+ fDragging(false),
+ fInverted(imageSlider.fInverted),
+ fStartedX(0),
+ fStartedY(0),
+ fCallback(imageSlider.fCallback),
+ fStartPos(imageSlider.fStartPos),
+ fEndPos(imageSlider.fEndPos),
+ fSliderArea(imageSlider.fSliderArea),
+ leakDetector_ImageSlider()
+{
+ fNeedsFullViewport = true;
+}
+
+ImageSlider& ImageSlider::operator=(const ImageSlider& imageSlider) noexcept
+{
+ fImage = imageSlider.fImage;
+ fMinimum = imageSlider.fMinimum;
+ fMaximum = imageSlider.fMaximum;
+ fStep = imageSlider.fStep;
+ fValue = imageSlider.fValue;
+ fValueTmp = fValue;
+ fDragging = false;
+ fInverted = imageSlider.fInverted;
+ fStartedX = 0;
+ fStartedY = 0;
+ fCallback = imageSlider.fCallback;
+ fStartPos = imageSlider.fStartPos;
+ fEndPos = imageSlider.fEndPos;
+ fSliderArea = imageSlider.fSliderArea;
+
+ return *this;
+}
+
+float ImageSlider::getValue() const noexcept
+{
+ return fValue;
+}
+
+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::setRange(float min, float max) noexcept
+{
+ if (fValue < min)
+ {
+ fValue = min;
+ repaint();
+
+ if (fCallback != nullptr)
+ {
+ try {
+ fCallback->imageSliderValueChanged(this, fValue);
+ } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange < min");
+ }
+ }
+ else if (fValue > max)
+ {
+ fValue = max;
+ repaint();
+
+ if (fCallback != nullptr)
+ {
+ try {
+ fCallback->imageSliderValueChanged(this, fValue);
+ } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange > max");
+ }
+ }
+
+ fMinimum = min;
+ fMaximum = max;
+}
+
+void ImageSlider::setStep(float step) noexcept
+{
+ fStep = step;
+}
+
+void ImageSlider::setValue(float value, bool sendCallback) noexcept
+{
+ 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::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;
+
+ 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<int>(fStartPos.getX(),
+ fStartPos.getY(),
+ fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(),
+ static_cast<int>(fImage.getHeight()));
+ }
+ else
+ {
+ // vertical
+ fSliderArea = Rectangle<int>(fStartPos.getX(),
+ fStartPos.getY(),
+ static_cast<int>(fImage.getWidth()),
+ fEndPos.getY() + static_cast<int>(fImage.getHeight()) - fStartPos.getY());
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImageSwitch::ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept
+ : Widget(parent),
+ fImageNormal(imageNormal),
+ fImageDown(imageDown),
+ fIsDown(false),
+ fCallback(nullptr),
+ leakDetector_ImageSwitch()
+{
+ DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize());
+
+ setSize(fImageNormal.getSize());
+}
+
+ImageSwitch::ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept
+ : Widget(widget->getParentWindow()),
+ fImageNormal(imageNormal),
+ fImageDown(imageDown),
+ fIsDown(false),
+ fCallback(nullptr),
+ leakDetector_ImageSwitch()
+{
+ DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize());
+
+ setSize(fImageNormal.getSize());
+}
+
+ImageSwitch::ImageSwitch(const ImageSwitch& imageSwitch) noexcept
+ : Widget(imageSwitch.getParentWindow()),
+ fImageNormal(imageSwitch.fImageNormal),
+ fImageDown(imageSwitch.fImageDown),
+ fIsDown(imageSwitch.fIsDown),
+ fCallback(imageSwitch.fCallback),
+ leakDetector_ImageSwitch()
+{
+ 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