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/Application.cpp" | ||||
"${DPF_ROOT_DIR}/dgl/src/ApplicationPrivateData.cpp" | "${DPF_ROOT_DIR}/dgl/src/ApplicationPrivateData.cpp" | ||||
"${DPF_ROOT_DIR}/dgl/src/Color.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/Geometry.cpp" | ||||
"${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp" | "${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp" | ||||
"${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.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 | #ifndef DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | ||||
#define DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | #define DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | ||||
#include "EventHandlers.hpp" | |||||
#include "StandaloneWindow.hpp" | #include "StandaloneWindow.hpp" | ||||
#include "SubWidget.hpp" | #include "SubWidget.hpp" | ||||
@@ -47,7 +48,8 @@ private: | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
template <class ImageType> | template <class ImageType> | ||||
class ImageBaseButton : public SubWidget | |||||
class ImageBaseButton : public SubWidget, | |||||
public ButtonEventHandler | |||||
{ | { | ||||
public: | public: | ||||
class Callback | class Callback | ||||
@@ -27,6 +27,7 @@ OBJS_common = \ | |||||
../build/dgl/Application.cpp.o \ | ../build/dgl/Application.cpp.o \ | ||||
../build/dgl/ApplicationPrivateData.cpp.o \ | ../build/dgl/ApplicationPrivateData.cpp.o \ | ||||
../build/dgl/Color.cpp.o \ | ../build/dgl/Color.cpp.o \ | ||||
../build/dgl/EventHandlers.cpp.o \ | |||||
../build/dgl/Geometry.cpp.o \ | ../build/dgl/Geometry.cpp.o \ | ||||
../build/dgl/ImageBase.cpp.o \ | ../build/dgl/ImageBase.cpp.o \ | ||||
../build/dgl/ImageBaseWidgets.cpp.o \ | ../build/dgl/ImageBaseWidgets.cpp.o \ | ||||
@@ -39,7 +40,6 @@ OBJS_common = \ | |||||
../build/dgl/WidgetPrivateData.cpp.o \ | ../build/dgl/WidgetPrivateData.cpp.o \ | ||||
../build/dgl/Window.cpp.o \ | ../build/dgl/Window.cpp.o \ | ||||
../build/dgl/WindowPrivateData.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> | template <class ImageType> | ||||
struct ImageBaseKnob<ImageType>::PrivateData { | struct ImageBaseKnob<ImageType>::PrivateData { | ||||
ImageType image; | 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> | template <class ImageType> | ||||
struct ImageBaseButton<ImageType>::PrivateData { | |||||
ButtonImpl<ImageType> impl; | |||||
struct ImageBaseButton<ImageType>::PrivateData : public ButtonEventHandler::Callback { | |||||
ImageBaseButton<ImageType>::Callback* callback; | |||||
ImageType imageNormal; | ImageType imageNormal; | ||||
ImageType imageHover; | ImageType imageHover; | ||||
ImageType imageDown; | 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), | imageNormal(normal), | ||||
imageHover(hover), | imageHover(hover), | ||||
imageDown(down) {} | 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) | DISTRHO_DECLARE_NON_COPYABLE(PrivateData) | ||||
}; | }; | ||||
@@ -109,28 +116,34 @@ struct ImageBaseButton<ImageType>::PrivateData { | |||||
template <class ImageType> | template <class ImageType> | ||||
ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& image) | ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& image) | ||||
: SubWidget(parentWidget), | : SubWidget(parentWidget), | ||||
pData(new PrivateData(this, image, image, image)) | |||||
ButtonEventHandler(this), | |||||
pData(new PrivateData(image, image, image)) | |||||
{ | { | ||||
ButtonEventHandler::setCallback(pData); | |||||
setSize(image.getSize()); | setSize(image.getSize()); | ||||
} | } | ||||
template <class ImageType> | template <class ImageType> | ||||
ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& imageNormal, const ImageType& imageDown) | ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& imageNormal, const ImageType& imageDown) | ||||
: SubWidget(parentWidget), | : SubWidget(parentWidget), | ||||
pData(new PrivateData(this, imageNormal, imageNormal, imageDown)) | |||||
ButtonEventHandler(this), | |||||
pData(new PrivateData(imageNormal, imageNormal, imageDown)) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageDown.getSize()); | DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageDown.getSize()); | ||||
ButtonEventHandler::setCallback(pData); | |||||
setSize(imageNormal.getSize()); | setSize(imageNormal.getSize()); | ||||
} | } | ||||
template <class ImageType> | template <class ImageType> | ||||
ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& imageNormal, const ImageType& imageHover, const ImageType& imageDown) | ImageBaseButton<ImageType>::ImageBaseButton(Widget* const parentWidget, const ImageType& imageNormal, const ImageType& imageHover, const ImageType& imageDown) | ||||
: SubWidget(parentWidget), | : 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()); | DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageHover.getSize() && imageHover.getSize() == imageDown.getSize()); | ||||
ButtonEventHandler::setCallback(pData); | |||||
setSize(imageNormal.getSize()); | setSize(imageNormal.getSize()); | ||||
} | } | ||||
@@ -143,7 +156,7 @@ ImageBaseButton<ImageType>::~ImageBaseButton() | |||||
template <class ImageType> | template <class ImageType> | ||||
void ImageBaseButton<ImageType>::setCallback(Callback* callback) noexcept | void ImageBaseButton<ImageType>::setCallback(Callback* callback) noexcept | ||||
{ | { | ||||
pData->impl.callback_img = callback; | |||||
pData->callback = callback; | |||||
} | } | ||||
template <class ImageType> | template <class ImageType> | ||||
@@ -151,30 +164,30 @@ void ImageBaseButton<ImageType>::onDisplay() | |||||
{ | { | ||||
const GraphicsContext& context(getGraphicsContext()); | const GraphicsContext& context(getGraphicsContext()); | ||||
switch (pData->impl.state) | |||||
{ | |||||
case ButtonImpl<ImageType>::kStateDown: | |||||
const State state = ButtonEventHandler::getState(); | |||||
if (state & kButtonStateActive) | |||||
pData->imageDown.draw(context); | pData->imageDown.draw(context); | ||||
break; | |||||
case ButtonImpl<ImageType>::kStateHover: | |||||
else if (state & kButtonStateHover) | |||||
pData->imageHover.draw(context); | pData->imageHover.draw(context); | ||||
break; | |||||
default: | |||||
else | |||||
pData->imageNormal.draw(context); | pData->imageNormal.draw(context); | ||||
break; | |||||
} | |||||
} | } | ||||
template <class ImageType> | template <class ImageType> | ||||
bool ImageBaseButton<ImageType>::onMouse(const MouseEvent& ev) | 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> | template <class ImageType> | ||||
bool ImageBaseButton<ImageType>::onMotion(const MotionEvent& ev) | bool ImageBaseButton<ImageType>::onMotion(const MotionEvent& ev) | ||||
{ | { | ||||
return pData->impl.onMotion(ev); | |||||
if (SubWidget::onMotion(ev)) | |||||
return true; | |||||
return ButtonEventHandler::motionEvent(ev); | |||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||