From 02f78d5eb03670bc07f615ad629e1ec03959be14 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 8 Oct 2015 07:30:10 +0200 Subject: Refactored EventHandler and friends. --- plugingui/combobox.cc | 2 +- plugingui/eventhandler.cc | 318 +++++++++++++++++++++------------------- plugingui/eventhandler.h | 37 +++-- plugingui/guievent.h | 132 +++++++++-------- plugingui/nativewindow.h | 61 +++++--- plugingui/nativewindow_win32.cc | 32 ++-- plugingui/nativewindow_x11.cc | 6 +- plugingui/plugingui.cc | 9 +- plugingui/plugingui.h | 1 + 9 files changed, 324 insertions(+), 274 deletions(-) diff --git a/plugingui/combobox.cc b/plugingui/combobox.cc index 4d2637a..c627b05 100644 --- a/plugingui/combobox.cc +++ b/plugingui/combobox.cc @@ -38,7 +38,7 @@ namespace GUI { void ComboBox::listboxSelectHandler() { ButtonEvent e; - e.direction = 1; + e.direction = ButtonEvent::Down; buttonEvent(&e); } diff --git a/plugingui/eventhandler.cc b/plugingui/eventhandler.cc index cec5fab..e47cbf5 100644 --- a/plugingui/eventhandler.cc +++ b/plugingui/eventhandler.cc @@ -29,166 +29,180 @@ #include "window.h" #include "painter.h" -GUI::EventHandler::EventHandler(GUI::NativeWindow *n, GUI::Window *w) -{ - native = n; - window = w; +namespace GUI { - last_click = 0; - last_was_dbl_click = false; -} +EventHandler::EventHandler(NativeWindow *nativeWindow, Window *window) + : window(window) + , nativeWindow(nativeWindow) +// , last_click(0) + , lastWasDoubleClick(false) +{} -bool GUI::EventHandler::hasEvent() +bool EventHandler::hasEvent() { - return native->hasEvent(); + return nativeWindow->hasEvent(); } -GUI::Event *GUI::EventHandler::getNextEvent() +Event *EventHandler::getNextEvent() { - return native->getNextEvent(); + return nativeWindow->getNextEvent(); } -void GUI::EventHandler::registerCloseHandler(void (*handler)(void *), void *ptr) +void EventHandler::processEvents() { - this->closeHandler = handler; - this->closeHandlerPtr = ptr; + while(hasEvent()) + { + Painter p(window); // Make sure we only redraw buffer one time. + + auto event = getNextEvent(); + + if(event == nullptr) + { + continue; + } + + switch(event->type()) { + case Event::Repaint: + window->redraw(); + break; + + case Event::Resize: + { + auto resizeEvent = static_cast(event); + if((resizeEvent->width != window->width()) || + (resizeEvent->height != window->height())) + { + window->resized(resizeEvent->width, resizeEvent->height); + } + } + break; + + case Event::MouseMove: + { + auto moveEvent = static_cast(event); + + auto widget = window->find(moveEvent->x, moveEvent->y); + auto oldwidget = window->mouseFocus(); + if(widget != oldwidget) + { + // Send focus leave to oldwidget + if(oldwidget) + { + oldwidget->mouseLeaveEvent(); + } + + // Send focus enter to widget + if(widget) + { + widget->mouseEnterEvent(); + } + + window->setMouseFocus(widget); + } + + if(window->buttonDownFocus()) + { + auto widget = window->buttonDownFocus(); + moveEvent->x -= widget->windowX(); + moveEvent->y -= widget->windowY(); + + window->buttonDownFocus()->mouseMoveEvent(moveEvent); + break; + } + + if(widget) + { + moveEvent->x -= widget->windowX(); + moveEvent->y -= widget->windowY(); + widget->mouseMoveEvent(moveEvent); + } + } + break; + + case Event::Button: + { + if(lastWasDoubleClick) + { + lastWasDoubleClick = false; + continue; + } + + auto buttonEvent = static_cast(event); + + lastWasDoubleClick = buttonEvent->doubleclick; + + auto widget = window->find(buttonEvent->x, buttonEvent->y); + + if(window->buttonDownFocus()) + { + if(buttonEvent->direction == ButtonEvent::Up) + { + auto widget = window->buttonDownFocus(); + buttonEvent->x -= widget->windowX(); + buttonEvent->y -= widget->windowY(); + + widget->buttonEvent(buttonEvent); + break; + } + else // Event::Button::Down + { + window->setButtonDownFocus(nullptr); + } + } + + if(widget) + { + buttonEvent->x -= widget->windowX(); + buttonEvent->y -= widget->windowY(); + + widget->buttonEvent(buttonEvent); + + if((buttonEvent->direction == ButtonEvent::Down) && + widget->catchMouse()) + { + window->setButtonDownFocus(widget); + } + + if(widget->isFocusable()) + { + window->setKeyboardFocus(widget); + } + } + } + break; + + case Event::Scroll: + { + auto scrollEvent = static_cast(event); + + auto widget = window->find(scrollEvent->x, scrollEvent->y); + if(widget) + { + scrollEvent->x -= widget->windowX(); + scrollEvent->y -= widget->windowY(); + + widget->scrollEvent(scrollEvent); + } + } + break; + + case Event::Key: + { + auto keyEvent = static_cast(event); + if(window->keyboardFocus()) + { + window->keyboardFocus()->keyEvent(keyEvent); + } + } + break; + + case Event::Close: + closeNotifier(); + break; + } + + delete event; + } } -void GUI::EventHandler::processEvents() -{ - while(hasEvent()) { - Painter p(window); // Make sure we only redraw buffer one time. - - Event *event = getNextEvent(); - - if(event == NULL) continue; - - // Widget *widget = gctx->widgets[event->window_id]; - switch(event->type()) { - case Event::Repaint: - // window->repaint((RepaintEvent*)event); - window->redraw(); - break; - case Event::Resize: - { - // window->repaint((RepaintEvent*)event) - ResizeEvent *re = (ResizeEvent*)event; - if(re->width != window->width() || re->height != window->height()) { - window->resized(re->width, re->height); - //window->repaint_r(NULL); - } - } - break; - case Event::MouseMove: - { - MouseMoveEvent *me = (MouseMoveEvent*)event; - - Widget *w = window->find(me->x, me->y); - Widget *oldw = window->mouseFocus(); - if(w != oldw) { - // Send focus leave to oldw - if(oldw) oldw->mouseLeaveEvent(); - // Send focus enter to w - if(w) w->mouseEnterEvent(); - - window->setMouseFocus(w); - } - - if(window->buttonDownFocus()) { - Widget *w = window->buttonDownFocus(); - /* - if(me->x < w->x()) me->x = w->x(); - if(me->x > w->x() + w->width()) me->x = w->x() + w->width(); - if(me->y < w->y()) me->y = w->y(); - if(me->y > w->y() + w->height()) me->y = w->y() + w->height(); - */ - me->x -= w->windowX(); - me->y -= w->windowY(); - - window->buttonDownFocus()->mouseMoveEvent(me); - break; - } - - if(w) { - me->x -= w->windowX(); - me->y -= w->windowY(); - w->mouseMoveEvent(me); - } - } - break; - case Event::Button: - { - if(last_was_dbl_click) { - last_was_dbl_click = false; - continue; - } - ButtonEvent *be = (ButtonEvent *)event; - - last_was_dbl_click = be->doubleclick; - - Widget *w = window->find(be->x, be->y); - - if(window->buttonDownFocus()) { - if(be->direction == -1) { - Widget *w = window->buttonDownFocus(); - /* - if(be->x < w->x()) be->x = w->x(); - if(be->x > w->x() + w->width()) be->x = w->x() + w->width(); - if(be->y < w->y()) be->y = w->y(); - if(be->y > w->y() + w->height()) be->y = w->y() + w->height(); - */ - be->x -= w->windowX(); - be->y -= w->windowY(); - - w->buttonEvent(be); - break; - } else { - window->setButtonDownFocus(NULL); - } - } - - if(w) { - be->x -= w->windowX(); - be->y -= w->windowY(); - - w->buttonEvent(be); - - if(be->direction == 1) { - if(w->catchMouse()) window->setButtonDownFocus(w); - } - - if(w->isFocusable()) window->setKeyboardFocus(w); - } - } - break; - case Event::Scroll: - { - ScrollEvent *se = (ScrollEvent *)event; - - Widget *w = window->find(se->x, se->y); - - //printf("scroller (%d,%d) %p\n", se->x, se->y, w); - - if(w) { - se->x -= w->windowX(); - se->y -= w->windowY(); - - w->scrollEvent(se); - } - } - break; - case Event::Key: - // window->key((KeyEvent*)event); - // lineedit->keyEvent((KeyEvent*)event); - if(window->keyboardFocus()) - window->keyboardFocus()->keyEvent((KeyEvent*)event); - break; - case Event::Close: - if(closeHandler) closeHandler(closeHandlerPtr); - //delete window; - //window = NULL; - break; - } - delete event; - } -} +} // GUI:: diff --git a/plugingui/eventhandler.h b/plugingui/eventhandler.h index 028418d..b865cbb 100644 --- a/plugingui/eventhandler.h +++ b/plugingui/eventhandler.h @@ -24,39 +24,38 @@ * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#ifndef __DRUMGIZMO_EVENTHANDLER_H__ -#define __DRUMGIZMO_EVENTHANDLER_H__ +#pragma once #include "guievent.h" #include "nativewindow.h" -//#include "window.h" +#include "notifier.h" namespace GUI { + class Window; class EventHandler { public: - EventHandler(NativeWindow *native, Window *window); - - void processEvents(); + EventHandler(NativeWindow *nativeWindow, Window *window); - bool hasEvent(); - Event *getNextEvent(); + //! \brief Process all evebts currently in the event queue. + void processEvents(); - void registerCloseHandler(void (*handler)(void *), void *ptr); + //! \brief Query if any events are currently in the event queue. + bool hasEvent(); -private: - Window *window; - int last_click; - void (*closeHandler)(void *); - void *closeHandlerPtr; + //! \brief Get a single event from the event queue. + //! \return A pointer to the event or nullptr if there are none. + Event *getNextEvent(); - // Used to ignore mouse button release after a double click. - bool last_was_dbl_click; + Notifier<> closeNotifier; - NativeWindow *native; -}; +private: + Window *window; + NativeWindow *nativeWindow; + // Used to ignore mouse button release after a double click. + bool lastWasDoubleClick; }; -#endif/*__DRUMGIZMO_EVENTHANDLER_H__*/ +} // GUI:: diff --git a/plugingui/guievent.h b/plugingui/guievent.h index 4732101..221e056 100644 --- a/plugingui/guievent.h +++ b/plugingui/guievent.h @@ -24,8 +24,7 @@ * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#ifndef __DRUMGIZMO_GUI_EVENT_H__ -#define __DRUMGIZMO_GUI_EVENT_H__ +#pragma once #include @@ -40,102 +39,113 @@ namespace GUI { class Event { public: - typedef enum { - MouseMove, - Repaint, - Button, - Scroll, - Key, - Close, - Resize - } Type; - virtual ~Event() {} - - virtual Type type() = 0; + typedef enum { + MouseMove, + Repaint, + Button, + Scroll, + Key, + Close, + Resize + } Type; + virtual ~Event() {} + + virtual Type type() = 0; #ifdef X11 - ::Window window_id; + ::Window window_id; #endif/*X11*/ }; class MouseMoveEvent : public Event { public: - Type type() { return MouseMove; } + Type type() { return MouseMove; } - int x; - int y; + int x; + int y; }; class ButtonEvent : public Event { public: - Type type() { return Button; } + Type type() { return Button; } - int x; - int y; + int x; + int y; - int direction; - int button; - int doubleclick; + enum { + Up, + Down, + } direction; + + enum { + Right, + Middle, + Left, + } button; + + bool doubleclick; }; class ScrollEvent : public Event { public: - Type type() { return Scroll; } + Type type() { return Scroll; } - int x; - int y; + int x; + int y; - int delta; + int delta; }; class RepaintEvent : public Event { public: - Type type() { return Repaint; } + Type type() { return Repaint; } - int x; - int y; - size_t width; - size_t height; + int x; + int y; + size_t width; + size_t height; }; class KeyEvent : public Event { public: - Type type() { return Key; } - - int direction; - int keycode; - std::string text; - - enum { - KEY_UNKNOWN =-1, - KEY_LEFT = 1, - KEY_RIGHT = 2, - KEY_UP = 3, - KEY_DOWN = 4, - KEY_DELETE = 5, - KEY_BACKSPACE = 6, - KEY_HOME = 7, - KEY_END = 8, - KEY_PGDOWN = 9, - KEY_PGUP = 10, - KEY_ENTER = 11, - KEY_CHARACTER = 0xffff // character data is stored in 'text' - }; + Type type() { return Key; } + + enum { + Up, + Down, + } direction; + + int keycode; + std::string text; + + enum { + KEY_UNKNOWN =-1, + KEY_LEFT = 1, + KEY_RIGHT = 2, + KEY_UP = 3, + KEY_DOWN = 4, + KEY_DELETE = 5, + KEY_BACKSPACE = 6, + KEY_HOME = 7, + KEY_END = 8, + KEY_PGDOWN = 9, + KEY_PGUP = 10, + KEY_ENTER = 11, + KEY_CHARACTER = 0xffff // character data is stored in 'text' + }; }; class CloseEvent : public Event { public: - Type type() { return Close; } + Type type() { return Close; } }; class ResizeEvent : public Event { public: - Type type() { return Resize; } - - size_t width; - size_t height; -}; + Type type() { return Resize; } + size_t width; + size_t height; }; -#endif/*__DRUMGIZMO_GUI_EVENT_H__*/ +} // GUI:: diff --git a/plugingui/nativewindow.h b/plugingui/nativewindow.h index d68909d..46891f2 100644 --- a/plugingui/nativewindow.h +++ b/plugingui/nativewindow.h @@ -24,8 +24,7 @@ * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#ifndef __DRUMGIZMO_NATIVEWINDOW_H__ -#define __DRUMGIZMO_NATIVEWINDOW_H__ +#pragma once #include @@ -33,25 +32,49 @@ namespace GUI { +//! \brief Interface class for native window implementations. class NativeWindow { public: - NativeWindow() {} - virtual ~NativeWindow() {} - - virtual void setFixedSize(int width, int height) = 0; - virtual void resize(int width, int height) = 0; - virtual void move(int x, int y) = 0; - virtual void show() = 0; - virtual void setCaption(const std::string &caption) = 0; - virtual void hide() = 0; - virtual void handleBuffer() = 0; - virtual void redraw() = 0; - virtual void grabMouse(bool grab) = 0; - - virtual bool hasEvent() = 0; - virtual Event *getNextEvent() = 0; -}; + NativeWindow() {} + virtual ~NativeWindow() {} + + //! \brief Set a fixed size to the window. + //! It resizes the window and disallows user resizing. + virtual void setFixedSize(int width, int height) = 0; + + // TODO: setScalable(bool) ?? + + //! \brief Set a new size of the window. + virtual void resize(int width, int height) = 0; + + //! \brief Move the window to a new position. + virtual void move(int x, int y) = 0; + + //! \brief Show the window if it is hidden. + virtual void show() = 0; + + //! \brief Hides the window. + virtual void hide() = 0; + + //! \brief Sets the window caption in the title bar (if it has one). + virtual void setCaption(const std::string &caption) = 0; + + //! \brief Recreate a window render buffer based on the internal buffer. + //! This need to be called whenever the internal buffer size has changed. + virtual void handleBuffer() = 0; + + //! \brief Draw the internal rendering buffer to the window buffer. + virtual void redraw() = 0; + + //! \brief Toggle capture mouse mode. + virtual void grabMouse(bool grab) = 0; + + //! \brief Query if the event queue contains any events. + virtual bool hasEvent() = 0; + //! \brief Read a single event from the event queue. + //! \return A pointer to the event or nullptr is none exists. + virtual Event *getNextEvent() = 0; }; -#endif/*__DRUMGIZMO_NATIVEWINDOW_H__*/ +} // GUI:: diff --git a/plugingui/nativewindow_win32.cc b/plugingui/nativewindow_win32.cc index 871bafe..fcee1a6 100644 --- a/plugingui/nativewindow_win32.cc +++ b/plugingui/nativewindow_win32.cc @@ -125,24 +125,28 @@ LRESULT CALLBACK dialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) if(msg == WM_LBUTTONUP || msg == WM_LBUTTONDBLCLK || - msg == WM_LBUTTONDOWN) e->button = 0; - - if(msg == WM_RBUTTONUP || + msg == WM_LBUTTONDOWN) e->button = ButtonEvent::Left; + else if(msg == WM_RBUTTONUP || msg == WM_RBUTTONDBLCLK || - msg == WM_RBUTTONDOWN) e->button = 1; - - if(msg == WM_MBUTTONUP || + msg == WM_RBUTTONDOWN) e->button = ButtonEvent::Middle; + else if(msg == WM_MBUTTONUP || msg == WM_MBUTTONDBLCLK || - msg == WM_MBUTTONDOWN) e->button = 2; + msg == WM_MBUTTONDOWN) e->button = ButtonEvent::Right; + else { + delete e; + break; // unknown button + } - e->direction = 0; if(msg == WM_LBUTTONUP || msg == WM_RBUTTONUP || - msg == WM_MBUTTONUP) e->direction = -1; - - if(msg == WM_LBUTTONDOWN || + msg == WM_MBUTTONUP) e->direction = ButtonEvent::Up; + else if(msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || - msg == WM_MBUTTONDOWN) e->direction = 1; + msg == WM_MBUTTONDOWN) e->direction = ButtonEvent::Down; + else { + delete e; + break; // unknown direction + } e->doubleclick = (msg == WM_LBUTTONDBLCLK || msg == WM_RBUTTONDBLCLK || @@ -171,7 +175,7 @@ LRESULT CALLBACK dialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) default: e->keycode = GUI::KeyEvent::KEY_UNKNOWN; break; } e->text = ""; - e->direction = -1; + e->direction = KeyEvent::Up; native->event = e; } break; @@ -183,7 +187,7 @@ LRESULT CALLBACK dialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) GUI::KeyEvent *e = new GUI::KeyEvent(); e->keycode = GUI::KeyEvent::KEY_CHARACTER; e->text += (char)wp; - e->direction = -1; + e->direction = KeyEvent::Up; native->event = e; } } diff --git a/plugingui/nativewindow_x11.cc b/plugingui/nativewindow_x11.cc index cb6cf73..4d91b32 100644 --- a/plugingui/nativewindow_x11.cc +++ b/plugingui/nativewindow_x11.cc @@ -334,8 +334,8 @@ GUI::Event *GUI::NativeWindowX11::getNextEvent() e->window_id = xe.xbutton.window; e->x = xe.xbutton.x; e->y = xe.xbutton.y; - e->button = 0; - e->direction = xe.type == ButtonPress?1:-1; + e->button = ButtonEvent::Left; + e->direction = (xe.type == ButtonPress) ? ButtonEvent::Down : ButtonEvent::Up; e->doubleclick = xe.type == ButtonPress && (xe.xbutton.time - last_click) < 200; @@ -371,7 +371,7 @@ GUI::Event *GUI::NativeWindowX11::getNextEvent() } e->text.append(buf, sz); - e->direction = xe.type == KeyPress?1:-1; + e->direction = (xe.type == KeyPress) ? KeyEvent::Down : KeyEvent::Up; event = e; } diff --git a/plugingui/plugingui.cc b/plugingui/plugingui.cc index 0a68d72..9bb451d 100644 --- a/plugingui/plugingui.cc +++ b/plugingui/plugingui.cc @@ -224,10 +224,9 @@ void PluginGUI::deinit() if(window) delete window; } -void closeEventHandler(void *ptr) +void PluginGUI::closeEventHandler() { - volatile bool *closing = (volatile bool*)ptr; - *closing = true; + closing = true; } void PluginGUI::init() @@ -238,8 +237,8 @@ void PluginGUI::init() config->load(); window = new Window(); - window->eventHandler()->registerCloseHandler(closeEventHandler, - (void*)&closing); + auto eventHandler = window->eventHandler(); + CONNECT(eventHandler, closeNotifier, this, &PluginGUI::closeEventHandler); window->setFixedSize(370, 330); window->setCaption("DrumGizmo v" VERSION); diff --git a/plugingui/plugingui.h b/plugingui/plugingui.h index b5fd5d0..52cd8d2 100644 --- a/plugingui/plugingui.h +++ b/plugingui/plugingui.h @@ -92,6 +92,7 @@ private: void velocityCheckClick(bool checked); void kitBrowseClick(); void midimapBrowseClick(); + void closeEventHandler(); // Humanized velocity controls: CheckBox *velocityCheck; -- cgit v1.2.3