@@ -19,7 +19,6 @@ | |||
#include "ImageBase.hpp" | |||
#include "ImageBaseWidgets.hpp" | |||
#include "SubWidget.hpp" | |||
#include <cairo/cairo.h> | |||
@@ -115,25 +114,21 @@ class CairoBaseWidget : public BaseWidget | |||
public: | |||
/** | |||
Constructor for a CairoSubWidget. | |||
@see CreateFlags | |||
*/ | |||
explicit CairoBaseWidget(Widget* const parentGroupWidget); | |||
/** | |||
Constructor for a CairoTopLevelWidget. | |||
@see CreateFlags | |||
*/ | |||
explicit CairoBaseWidget(Window& windowToMapTo); | |||
/** | |||
Constructor for a CairoStandaloneWindow without parent window. | |||
@see CreateFlags | |||
*/ | |||
explicit CairoBaseWidget(Application& app); | |||
/** | |||
Constructor for a CairoStandaloneWindow with parent window. | |||
@see CreateFlags | |||
*/ | |||
explicit CairoBaseWidget(Application& app, Window& parentWindow); | |||
@@ -171,6 +166,9 @@ typedef CairoBaseWidget<StandaloneWindow> CairoStandaloneWindow; | |||
typedef ImageBaseAboutWindow<CairoImage> CairoImageAboutWindow; | |||
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 | |||
#endif // DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED |
@@ -17,206 +17,25 @@ | |||
#ifndef DGL_IMAGE_WIDGETS_HPP_INCLUDED | |||
#define DGL_IMAGE_WIDGETS_HPP_INCLUDED | |||
#include "Image.hpp" | |||
#include "ImageBaseWidgets.hpp" | |||
#include "SubWidget.hpp" | |||
// TODO switch to use templated image type after merging widget-related PRs | |||
#if defined(__GNUC__) && (__GNUC__ >= 6) | |||
# pragma GCC diagnostic push | |||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |||
#endif | |||
#include "OpenGL.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class ImageKnob : public SubWidget | |||
{ | |||
public: | |||
enum Orientation { | |||
Horizontal, | |||
Vertical | |||
}; | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageKnobDragStarted(ImageKnob* imageKnob) = 0; | |||
virtual void imageKnobDragFinished(ImageKnob* imageKnob) = 0; | |||
virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0; | |||
}; | |||
explicit ImageKnob(Widget* parentWidget, const Image& image, Orientation orientation = Vertical) noexcept; | |||
explicit ImageKnob(const ImageKnob& imageKnob); | |||
ImageKnob& operator=(const ImageKnob& imageKnob); | |||
~ImageKnob() override; | |||
float getValue() const noexcept; | |||
void setDefault(float def) noexcept; | |||
void setRange(float min, float max) noexcept; | |||
void setStep(float step) noexcept; | |||
void setValue(float value, bool sendCallback = false) noexcept; | |||
void setUsingLogScale(bool yesNo) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
void setOrientation(Orientation orientation) noexcept; | |||
void setRotationAngle(int angle); | |||
void setImageLayerCount(uint count) noexcept; | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
bool onScroll(const ScrollEvent&) override; | |||
private: | |||
Image fImage; | |||
float fMinimum; | |||
float fMaximum; | |||
float fStep; | |||
float fValue; | |||
float fValueDef; | |||
float fValueTmp; | |||
bool fUsingDefault; | |||
bool fUsingLog; | |||
Orientation fOrientation; | |||
int fRotationAngle; | |||
bool fDragging; | |||
int fLastX; | |||
int fLastY; | |||
Callback* fCallback; | |||
bool fIsImgVertical; | |||
uint fImgLayerWidth; | |||
uint fImgLayerHeight; | |||
uint fImgLayerCount; | |||
bool fIsReady; | |||
GLuint fTextureId; | |||
float _logscale(float value) const; | |||
float _invlogscale(float value) const; | |||
DISTRHO_LEAK_DETECTOR(ImageKnob) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// note set range and step before setting the value | |||
class ImageSlider : public SubWidget | |||
{ | |||
public: | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageSliderDragStarted(ImageSlider* imageSlider) = 0; | |||
virtual void imageSliderDragFinished(ImageSlider* imageSlider) = 0; | |||
virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0; | |||
}; | |||
explicit ImageSlider(Widget* parentWidget, const Image& image) noexcept; | |||
DISTRHO_DEPRECATED_BY("OpenGLImageAboutWindow") | |||
typedef OpenGLImageAboutWindow ImageAboutWindow; | |||
float getValue() const noexcept; | |||
void setValue(float value, bool sendCallback = false) noexcept; | |||
void setDefault(float def) noexcept; | |||
DISTRHO_DEPRECATED_BY("OpenGLImageButton") | |||
typedef OpenGLImageButton ImageButton; | |||
void setStartPos(const Point<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 | |||
#if defined(__GNUC__) && (__GNUC__ >= 6) | |||
# pragma GCC diagnostic pop | |||
#endif | |||
#endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED |
@@ -56,7 +56,6 @@ endif | |||
OBJS_opengl = $(OBJS_common) \ | |||
../build/dgl/OpenGL.cpp.opengl.o \ | |||
../build/dgl/ImageWidgets.cpp.o \ | |||
../build/dgl/NanoVG.cpp.opengl.o | |||
ifeq ($(MACOS),true) | |||
@@ -282,12 +282,9 @@ private: | |||
typedef ImageBaseAboutWindow<OpenGLImage> OpenGLImageAboutWindow; | |||
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 |
@@ -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 |