commit 2fe6b274d15f1c73e7a6505a968eb91d077bc6ac
parent 66aa0ee878ba4ca6feb85c29d3fcdad09e595f26
Author: falkTX <falktx@falktx.com>
Date: Mon, 14 Jun 2021 18:38:09 +0100
Start of common event handlers, split off button as a start
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
7 files changed, 346 insertions(+), 118 deletions(-)
diff --git a/cmake/DPF-plugin.cmake b/cmake/DPF-plugin.cmake
@@ -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"
diff --git a/dgl/EventHandlers.hpp b/dgl/EventHandlers.hpp
@@ -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
+
diff --git a/dgl/ImageBaseWidgets.hpp b/dgl/ImageBaseWidgets.hpp
@@ -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
diff --git a/dgl/Makefile b/dgl/Makefile
@@ -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
# ---------------------------------------------------------------------------------------------------------------------
diff --git a/dgl/src/Common.hpp b/dgl/src/Common.hpp
@@ -24,103 +24,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;
float minimum;
diff --git a/dgl/src/EventHandlers.cpp b/dgl/src/EventHandlers.cpp
@@ -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
diff --git a/dgl/src/ImageBaseWidgets.cpp b/dgl/src/ImageBaseWidgets.cpp
@@ -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);
}
// --------------------------------------------------------------------------------------------------------------------