Signed-off-by: falkTX <falktx@falktx.com>pull/292/head
@@ -326,6 +326,7 @@ function(dpf__add_dgl_cairo) | |||
"${DPF_ROOT_DIR}/dgl/src/Application.cpp" | |||
"${DPF_ROOT_DIR}/dgl/src/ApplicationPrivateData.cpp" | |||
"${DPF_ROOT_DIR}/dgl/src/Color.cpp" | |||
"${DPF_ROOT_DIR}/dgl/src/EventHandlers.cpp" | |||
"${DPF_ROOT_DIR}/dgl/src/Geometry.cpp" | |||
"${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp" | |||
"${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.cpp" | |||
@@ -0,0 +1,77 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#ifndef DGL_EVENT_HANDLERS_HPP_INCLUDED | |||
#define DGL_EVENT_HANDLERS_HPP_INCLUDED | |||
#include "Widget.hpp" | |||
START_NAMESPACE_DGL | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
class ButtonEventHandler | |||
{ | |||
public: | |||
enum State { | |||
kButtonStateDefault = 0x0, | |||
kButtonStateHover = 0x1, | |||
kButtonStateActive = 0x2, | |||
kButtonStateActiveHover = kButtonStateActive|kButtonStateHover | |||
}; | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void buttonClicked(SubWidget* widget, int button) = 0; | |||
}; | |||
explicit ButtonEventHandler(SubWidget* self); | |||
~ButtonEventHandler(); | |||
bool isActive() noexcept; | |||
void setActive(bool active, bool sendCallback) noexcept; | |||
bool isChecked() const noexcept; | |||
void setChecked(bool checked, bool sendCallback) noexcept; | |||
bool isCheckable() const noexcept; | |||
void setCheckable(bool checkable) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
protected: | |||
State getState() const noexcept; | |||
virtual void stateChanged(State state, State oldState); | |||
bool mouseEvent(const Widget::MouseEvent& ev); | |||
bool motionEvent(const Widget::MotionEvent& ev); | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ButtonEventHandler) | |||
}; | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#endif // DGL_EVENT_HANDLERS_HPP_INCLUDED | |||
@@ -17,6 +17,7 @@ | |||
#ifndef DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | |||
#define DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | |||
#include "EventHandlers.hpp" | |||
#include "StandaloneWindow.hpp" | |||
#include "SubWidget.hpp" | |||
@@ -47,7 +48,8 @@ private: | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
template <class ImageType> | |||
class ImageBaseButton : public SubWidget | |||
class ImageBaseButton : public SubWidget, | |||
public ButtonEventHandler | |||
{ | |||
public: | |||
class Callback | |||
@@ -27,6 +27,7 @@ OBJS_common = \ | |||
../build/dgl/Application.cpp.o \ | |||
../build/dgl/ApplicationPrivateData.cpp.o \ | |||
../build/dgl/Color.cpp.o \ | |||
../build/dgl/EventHandlers.cpp.o \ | |||
../build/dgl/Geometry.cpp.o \ | |||
../build/dgl/ImageBase.cpp.o \ | |||
../build/dgl/ImageBaseWidgets.cpp.o \ | |||
@@ -39,7 +40,6 @@ OBJS_common = \ | |||
../build/dgl/WidgetPrivateData.cpp.o \ | |||
../build/dgl/Window.cpp.o \ | |||
../build/dgl/WindowPrivateData.cpp.o | |||
# ../build/dgl/WindowFileBrowser.cpp.o | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -23,103 +23,6 @@ START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
template <class ImageType> | |||
struct ButtonImpl { | |||
enum State { | |||
kStateNormal = 0, | |||
kStateHover, | |||
kStateDown | |||
}; | |||
int button; | |||
int state; | |||
ImageBaseButton<ImageType>* const self; | |||
typename ImageBaseButton<ImageType>::Callback* callback_img; | |||
explicit ButtonImpl(ImageBaseButton<ImageType>* const s) noexcept | |||
: button(-1), | |||
state(kStateNormal), | |||
self(s), | |||
callback_img(nullptr) {} | |||
bool onMouse(const Widget::MouseEvent& ev) | |||
{ | |||
// button was released, handle it now | |||
if (button != -1 && ! ev.press) | |||
{ | |||
DISTRHO_SAFE_ASSERT(state == kStateDown); | |||
// release button | |||
const int button2 = button; | |||
button = -1; | |||
// cursor was moved outside the button bounds, ignore click | |||
if (! self->contains(ev.pos)) | |||
{ | |||
state = kStateNormal; | |||
self->repaint(); | |||
return true; | |||
} | |||
// still on bounds, register click | |||
state = kStateHover; | |||
self->repaint(); | |||
if (callback_img != nullptr) | |||
callback_img->imageButtonClicked(self, button2); | |||
return true; | |||
} | |||
// button was pressed, wait for release | |||
if (ev.press && self->contains(ev.pos)) | |||
{ | |||
button = static_cast<int>(ev.button); | |||
state = kStateDown; | |||
self->repaint(); | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool onMotion(const Widget::MotionEvent& ev) | |||
{ | |||
// keep pressed | |||
if (button != -1) | |||
return true; | |||
if (self->contains(ev.pos)) | |||
{ | |||
// check if entering hover | |||
if (state == kStateNormal) | |||
{ | |||
state = kStateHover; | |||
self->repaint(); | |||
return true; | |||
} | |||
} | |||
else | |||
{ | |||
// check if exiting hover | |||
if (state == kStateHover) | |||
{ | |||
state = kStateNormal; | |||
self->repaint(); | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||
DISTRHO_DECLARE_NON_COPYABLE(ButtonImpl) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
template <class ImageType> | |||
struct ImageBaseKnob<ImageType>::PrivateData { | |||
ImageType image; | |||
@@ -0,0 +1,232 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "../EventHandlers.hpp" | |||
#include "../SubWidget.hpp" | |||
START_NAMESPACE_DGL | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
struct ButtonEventHandler::PrivateData { | |||
ButtonEventHandler* const self; | |||
SubWidget* const widget; | |||
ButtonEventHandler::Callback* callback; | |||
int button; | |||
int state; | |||
bool checkable; | |||
bool checked; | |||
Point<double> oldMotionPos; | |||
PrivateData(ButtonEventHandler* const s, SubWidget* const w) | |||
: self(s), | |||
widget(w), | |||
callback(nullptr), | |||
button(-1), | |||
state(kButtonStateDefault), | |||
checkable(false), | |||
checked(false), | |||
oldMotionPos(0, 0) {} | |||
bool mouseEvent(const Widget::MouseEvent& ev) | |||
{ | |||
// button was released, handle it now | |||
if (button != -1 && ! ev.press) | |||
{ | |||
DISTRHO_SAFE_ASSERT(state & kButtonStateActive); | |||
// release button | |||
const int button2 = button; | |||
button = -1; | |||
const int state2 = state; | |||
state &= ~kButtonStateActive; | |||
// cursor was moved outside the button bounds, ignore click | |||
if (! widget->contains(ev.pos)) | |||
{ | |||
self->stateChanged(static_cast<State>(state2), static_cast<State>(state)); | |||
widget->repaint(); | |||
return true; | |||
} | |||
// still on bounds, register click | |||
self->stateChanged(static_cast<State>(state2), static_cast<State>(state)); | |||
widget->repaint(); | |||
if (checkable) | |||
checked = !checked; | |||
if (callback != nullptr) | |||
callback->buttonClicked(widget, button2); | |||
return true; | |||
} | |||
// button was pressed, wait for release | |||
if (ev.press && widget->contains(ev.pos)) | |||
{ | |||
const int state2 = state; | |||
button = static_cast<int>(ev.button); | |||
state |= kButtonStateActive; | |||
self->stateChanged(static_cast<State>(state2), static_cast<State>(state)); | |||
widget->repaint(); | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool motionEvent(const Widget::MotionEvent& ev) | |||
{ | |||
// keep pressed | |||
if (button != -1) | |||
{ | |||
oldMotionPos = ev.pos; | |||
return true; | |||
} | |||
bool ret = false; | |||
if (widget->contains(ev.pos)) | |||
{ | |||
// check if entering hover | |||
if ((state & kButtonStateHover) == 0x0) | |||
{ | |||
const int state2 = state; | |||
state |= kButtonStateHover; | |||
ret = widget->contains(oldMotionPos); | |||
self->stateChanged(static_cast<State>(state2), static_cast<State>(state)); | |||
widget->repaint(); | |||
} | |||
} | |||
else | |||
{ | |||
// check if exiting hover | |||
if (state & kButtonStateHover) | |||
{ | |||
const int state2 = state; | |||
state &= ~kButtonStateHover; | |||
ret = widget->contains(oldMotionPos); | |||
self->stateChanged(static_cast<State>(state2), static_cast<State>(state)); | |||
widget->repaint(); | |||
} | |||
} | |||
oldMotionPos = ev.pos; | |||
return ret; | |||
} | |||
void setActive(const bool active2, const bool sendCallback) noexcept | |||
{ | |||
const bool active = state & kButtonStateActive; | |||
if (active == active2) | |||
return; | |||
state |= kButtonStateActive; | |||
widget->repaint(); | |||
if (sendCallback && callback != nullptr) | |||
callback->buttonClicked(widget, -1); | |||
} | |||
void setChecked(const bool checked2, const bool sendCallback) noexcept | |||
{ | |||
if (checked == checked2) | |||
return; | |||
checked = checked2; | |||
widget->repaint(); | |||
if (sendCallback && callback != nullptr) | |||
callback->buttonClicked(widget, -1); | |||
} | |||
DISTRHO_DECLARE_NON_COPYABLE(PrivateData) | |||
}; | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
ButtonEventHandler::ButtonEventHandler(SubWidget* const self) | |||
: pData(new PrivateData(this, self)) {} | |||
ButtonEventHandler::~ButtonEventHandler() | |||
{ | |||
delete pData; | |||
} | |||
bool ButtonEventHandler::isActive() noexcept | |||
{ | |||
return pData->state & kButtonStateActive; | |||
} | |||
void ButtonEventHandler::setActive(const bool active, const bool sendCallback) noexcept | |||
{ | |||
pData->setActive(active, sendCallback); | |||
} | |||
bool ButtonEventHandler::isChecked() const noexcept | |||
{ | |||
return pData->checked; | |||
} | |||
void ButtonEventHandler::setChecked(const bool checked, const bool sendCallback) noexcept | |||
{ | |||
pData->setChecked(checked, sendCallback); | |||
} | |||
bool ButtonEventHandler::isCheckable() const noexcept | |||
{ | |||
return pData->checkable; | |||
} | |||
void ButtonEventHandler::setCheckable(const bool checkable) noexcept | |||
{ | |||
if (pData->checkable == checkable) | |||
return; | |||
pData->checkable = checkable; | |||
} | |||
void ButtonEventHandler::setCallback(Callback* const callback) noexcept | |||
{ | |||
pData->callback = callback; | |||
} | |||
ButtonEventHandler::State ButtonEventHandler::getState() const noexcept | |||
{ | |||
return static_cast<State>(pData->state); | |||
} | |||
void ButtonEventHandler::stateChanged(State, State) | |||
{ | |||
} | |||
bool ButtonEventHandler::mouseEvent(const Widget::MouseEvent& ev) | |||
{ | |||
return pData->mouseEvent(ev); | |||
} | |||
bool ButtonEventHandler::motionEvent(const Widget::MotionEvent& ev) | |||
{ | |||
return pData->motionEvent(ev); | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
END_NAMESPACE_DGL |
@@ -89,18 +89,25 @@ bool ImageBaseAboutWindow<ImageType>::onMouse(const MouseEvent& ev) | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
template <class ImageType> | |||
struct ImageBaseButton<ImageType>::PrivateData { | |||
ButtonImpl<ImageType> impl; | |||
struct ImageBaseButton<ImageType>::PrivateData : public ButtonEventHandler::Callback { | |||
ImageBaseButton<ImageType>::Callback* callback; | |||
ImageType imageNormal; | |||
ImageType imageHover; | |||
ImageType imageDown; | |||
PrivateData(ImageBaseButton<ImageType>* const s, const ImageType& normal, const ImageType& hover, const ImageType& down) | |||
: impl(s), | |||
PrivateData(const ImageType& normal, const ImageType& hover, const ImageType& down) | |||
: callback(nullptr), | |||
imageNormal(normal), | |||
imageHover(hover), | |||
imageDown(down) {} | |||
void buttonClicked(SubWidget* widget, int button) override | |||
{ | |||
if (callback != nullptr) | |||
if (ImageBaseButton* const imageButton = dynamic_cast<ImageBaseButton*>(widget)) | |||
callback->imageButtonClicked(imageButton, button); | |||
} | |||
DISTRHO_DECLARE_NON_COPYABLE(PrivateData) | |||
}; | |||
@@ -109,28 +116,34 @@ struct ImageBaseButton<ImageType>::PrivateData { | |||
template <class ImageType> | |||
ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& image) | |||
: SubWidget(parentWidget), | |||
pData(new PrivateData(this, image, image, image)) | |||
ButtonEventHandler(this), | |||
pData(new PrivateData(image, image, image)) | |||
{ | |||
ButtonEventHandler::setCallback(pData); | |||
setSize(image.getSize()); | |||
} | |||
template <class ImageType> | |||
ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& imageNormal, const ImageType& imageDown) | |||
: SubWidget(parentWidget), | |||
pData(new PrivateData(this, imageNormal, imageNormal, imageDown)) | |||
ButtonEventHandler(this), | |||
pData(new PrivateData(imageNormal, imageNormal, imageDown)) | |||
{ | |||
DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageDown.getSize()); | |||
ButtonEventHandler::setCallback(pData); | |||
setSize(imageNormal.getSize()); | |||
} | |||
template <class ImageType> | |||
ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& imageNormal, const ImageType& imageHover, const ImageType& imageDown) | |||
: SubWidget(parentWidget), | |||
pData(new PrivateData(this, imageNormal, imageHover, imageDown)) | |||
ButtonEventHandler(this), | |||
pData(new PrivateData(imageNormal, imageHover, imageDown)) | |||
{ | |||
DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageHover.getSize() && imageHover.getSize() == imageDown.getSize()); | |||
ButtonEventHandler::setCallback(pData); | |||
setSize(imageNormal.getSize()); | |||
} | |||
@@ -143,7 +156,7 @@ ImageBaseButton<ImageType>::~ImageBaseButton() | |||
template <class ImageType> | |||
void ImageBaseButton<ImageType>::setCallback(Callback* callback) noexcept | |||
{ | |||
pData->impl.callback_img = callback; | |||
pData->callback = callback; | |||
} | |||
template <class ImageType> | |||
@@ -151,30 +164,30 @@ void ImageBaseButton<ImageType>::onDisplay() | |||
{ | |||
const GraphicsContext& context(getGraphicsContext()); | |||
switch (pData->impl.state) | |||
{ | |||
case ButtonImpl<ImageType>::kStateDown: | |||
const State state = ButtonEventHandler::getState(); | |||
if (state & kButtonStateActive) | |||
pData->imageDown.draw(context); | |||
break; | |||
case ButtonImpl<ImageType>::kStateHover: | |||
else if (state & kButtonStateHover) | |||
pData->imageHover.draw(context); | |||
break; | |||
default: | |||
else | |||
pData->imageNormal.draw(context); | |||
break; | |||
} | |||
} | |||
template <class ImageType> | |||
bool ImageBaseButton<ImageType>::onMouse(const MouseEvent& ev) | |||
{ | |||
return pData->impl.onMouse(ev); | |||
if (SubWidget::onMouse(ev)) | |||
return true; | |||
return ButtonEventHandler::mouseEvent(ev); | |||
} | |||
template <class ImageType> | |||
bool ImageBaseButton<ImageType>::onMotion(const MotionEvent& ev) | |||
{ | |||
return pData->impl.onMotion(ev); | |||
if (SubWidget::onMotion(ev)) | |||
return true; | |||
return ButtonEventHandler::motionEvent(ev); | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||