diff --git a/dgl/Base.hpp b/dgl/Base.hpp index 0229512c..e64a28cf 100644 --- a/dgl/Base.hpp +++ b/dgl/Base.hpp @@ -130,6 +130,21 @@ enum CrossingMode { kCrossingUngrab ///< Crossing due to a grab release }; +/** + Scroll direction. + + Describes the direction of a scroll event along with whether the scroll is a "smooth" scroll. + The discrete directions are for devices like mouse wheels with constrained axes, + while a smooth scroll is for those with arbitrary scroll direction freedom, like some touchpads. +*/ +enum ScrollDirection { + kScrollUp, ///< Scroll up + kScrollDown, ///< Scroll down + kScrollLeft, ///< Scroll left + kScrollRight, ///< Scroll right + kScrollSmooth ///< Smooth scroll in any direction +}; + // -------------------------------------------------------------------------------------------------------------------- // Base DGL classes diff --git a/dgl/Events.hpp b/dgl/Events.hpp index b34b5807..dcb468c8 100644 --- a/dgl/Events.hpp +++ b/dgl/Events.hpp @@ -170,19 +170,22 @@ namespace Events Some systems and devices support finer resolution and/or higher values for fast scrolls, so programs should handle any value gracefully. - @a pos The widget-relative coordinates of the pointer. - @a delta The scroll distance. + @a pos The widget-relative coordinates of the pointer. + @a delta The scroll distance. + @a direction The direction of the scroll or "smooth". @see onScroll */ struct ScrollEvent : BaseEvent { Point pos; Point delta; + ScrollDirection direction; /** Constuctor */ ScrollEvent() noexcept : BaseEvent(), pos(0.0, 0.0), - delta(0.0, 0.0) {} + delta(0.0, 0.0), + direction(kScrollSmooth) {} }; /** diff --git a/dgl/src/TopLevelWidgetPrivateData.cpp b/dgl/src/TopLevelWidgetPrivateData.cpp index 9edc6646..433dcaa9 100644 --- a/dgl/src/TopLevelWidgetPrivateData.cpp +++ b/dgl/src/TopLevelWidgetPrivateData.cpp @@ -37,7 +37,37 @@ TopLevelWidget::PrivateData::~PrivateData() window.pData->topLevelWidget = nullptr; } -void TopLevelWidget::PrivateData::mouseEvent(const Events::MouseEvent& ev) +bool TopLevelWidget::PrivateData::keyboardEvent(const Events::KeyboardEvent& ev) +{ + // give top-level widget chance to catch this event first + if (self->onKeyboard(ev)) + return true; + + // propagate event to all subwidgets recursively + return selfw->pData->giveKeyboardEventForSubWidgets(ev); +} + +bool TopLevelWidget::PrivateData::specialEvent(const Events::SpecialEvent& ev) +{ + // give top-level widget chance to catch this event first + if (self->onSpecial(ev)) + return true; + + // propagate event to all subwidgets recursively + return selfw->pData->giveSpecialEventForSubWidgets(ev); +} + +bool TopLevelWidget::PrivateData::characterInputEvent(const Events::CharacterInputEvent& ev) +{ + // give top-level widget chance to catch this event first + if (self->onCharacterInput(ev)) + return true; + + // propagate event to all subwidgets recursively + return selfw->pData->giveCharacterInputEventForSubWidgets(ev); +} + +bool TopLevelWidget::PrivateData::mouseEvent(const Events::MouseEvent& ev) { Events::MouseEvent rev = ev; @@ -51,10 +81,52 @@ void TopLevelWidget::PrivateData::mouseEvent(const Events::MouseEvent& ev) // give top-level widget chance to catch this event first if (self->onMouse(ev)) - return; + return true; + + // propagate event to all subwidgets recursively + return selfw->pData->giveMouseEventForSubWidgets(rev); +} + +bool TopLevelWidget::PrivateData::motionEvent(const Events::MotionEvent& ev) +{ + Events::MotionEvent rev = ev; + + if (window.pData->autoScaling) + { + const double autoScaleFactor = window.pData->autoScaleFactor; + + rev.pos.setX(ev.pos.getX() / autoScaleFactor); + rev.pos.setY(ev.pos.getY() / autoScaleFactor); + } + + // give top-level widget chance to catch this event first + if (self->onMotion(ev)) + return true; + + // propagate event to all subwidgets recursively + return selfw->pData->giveMotionEventForSubWidgets(rev); +} + +bool TopLevelWidget::PrivateData::scrollEvent(const Events::ScrollEvent& ev) +{ + Events::ScrollEvent rev = ev; + + if (window.pData->autoScaling) + { + const double autoScaleFactor = window.pData->autoScaleFactor; + + rev.pos.setX(ev.pos.getX() / autoScaleFactor); + rev.pos.setY(ev.pos.getY() / autoScaleFactor); + rev.delta.setX(ev.delta.getX() / autoScaleFactor); + rev.delta.setY(ev.delta.getY() / autoScaleFactor); + } + + // give top-level widget chance to catch this event first + if (self->onScroll(ev)) + return true; // propagate event to all subwidgets recursively - selfw->pData->giveMouseEventForSubWidgets(rev); + return selfw->pData->giveScrollEventForSubWidgets(rev); } void TopLevelWidget::PrivateData::fallbackOnResize() diff --git a/dgl/src/TopLevelWidgetPrivateData.hpp b/dgl/src/TopLevelWidgetPrivateData.hpp index bc4338eb..b3225c32 100644 --- a/dgl/src/TopLevelWidgetPrivateData.hpp +++ b/dgl/src/TopLevelWidgetPrivateData.hpp @@ -33,7 +33,12 @@ struct TopLevelWidget::PrivateData { explicit PrivateData(TopLevelWidget* const s, Window& w); ~PrivateData(); void display(); - void mouseEvent(const Events::MouseEvent& ev); + bool keyboardEvent(const Events::KeyboardEvent& ev); + bool specialEvent(const Events::SpecialEvent& ev); + bool characterInputEvent(const Events::CharacterInputEvent& ev); + bool mouseEvent(const Events::MouseEvent& ev); + bool motionEvent(const Events::MotionEvent& ev); + bool scrollEvent(const Events::ScrollEvent& ev); void fallbackOnResize(); DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) diff --git a/dgl/src/WidgetPrivateData.cpp b/dgl/src/WidgetPrivateData.cpp index 8ee47b22..b641dca9 100644 --- a/dgl/src/WidgetPrivateData.cpp +++ b/dgl/src/WidgetPrivateData.cpp @@ -67,12 +67,68 @@ void Widget::PrivateData::displaySubWidgets(const uint width, const uint height, } } -void Widget::PrivateData::giveMouseEventForSubWidgets(Events::MouseEvent& ev) +// ----------------------------------------------------------------------- + +bool Widget::PrivateData::giveKeyboardEventForSubWidgets(const Events::KeyboardEvent& ev) { if (! visible) - return; + return false; if (subWidgets.size() == 0) - return; + return false; + + FOR_EACH_SUBWIDGET_INV(rit) + { + SubWidget* const widget(*rit); + + if (widget->isVisible() && widget->onKeyboard(ev)) + return true; + } + + return false; +} + +bool Widget::PrivateData::giveSpecialEventForSubWidgets(const Events::SpecialEvent& ev) +{ + if (! visible) + return false; + if (subWidgets.size() == 0) + return false; + + FOR_EACH_SUBWIDGET_INV(rit) + { + SubWidget* const widget(*rit); + + if (widget->isVisible() && widget->onSpecial(ev)) + return true; + } + + return false; +} + +bool Widget::PrivateData::giveCharacterInputEventForSubWidgets(const Events::CharacterInputEvent& ev) +{ + if (! visible) + return false; + if (subWidgets.size() == 0) + return false; + + FOR_EACH_SUBWIDGET_INV(rit) + { + SubWidget* const widget(*rit); + + if (widget->isVisible() && widget->onCharacterInput(ev)) + return true; + } + + return false; +} + +bool Widget::PrivateData::giveMouseEventForSubWidgets(Events::MouseEvent& ev) +{ + if (! visible) + return false; + if (subWidgets.size() == 0) + return false; const double x = ev.pos.getX(); const double y = ev.pos.getY(); @@ -88,8 +144,64 @@ void Widget::PrivateData::giveMouseEventForSubWidgets(Events::MouseEvent& ev) y - widget->getAbsoluteY()); if (widget->onMouse(ev)) - return; + return true; } + + return false; +} + +bool Widget::PrivateData::giveMotionEventForSubWidgets(Events::MotionEvent& ev) +{ + if (! visible) + return false; + if (subWidgets.size() == 0) + return false; + + const double x = ev.pos.getX(); + const double y = ev.pos.getY(); + + FOR_EACH_SUBWIDGET_INV(rit) + { + SubWidget* const widget(*rit); + + if (! widget->isVisible()) + continue; + + ev.pos = Point(x - widget->getAbsoluteX(), + y - widget->getAbsoluteY()); + + if (widget->onMotion(ev)) + return true; + } + + return false; +} + +bool Widget::PrivateData::giveScrollEventForSubWidgets(Events::ScrollEvent& ev) +{ + if (! visible) + return false; + if (subWidgets.size() == 0) + return false; + + const double x = ev.pos.getX(); + const double y = ev.pos.getY(); + + FOR_EACH_SUBWIDGET_INV(rit) + { + SubWidget* const widget(*rit); + + if (! widget->isVisible()) + continue; + + ev.pos = Point(x - widget->getAbsoluteX(), + y - widget->getAbsoluteY()); + + if (widget->onScroll(ev)) + return true; + } + + return false; } // ----------------------------------------------------------------------- diff --git a/dgl/src/WidgetPrivateData.hpp b/dgl/src/WidgetPrivateData.hpp index 2fcf64e7..81471f47 100644 --- a/dgl/src/WidgetPrivateData.hpp +++ b/dgl/src/WidgetPrivateData.hpp @@ -42,7 +42,13 @@ struct Widget::PrivateData { ~PrivateData(); void displaySubWidgets(uint width, uint height, double autoScaleFactor); - void giveMouseEventForSubWidgets(Events::MouseEvent& ev); + + bool giveKeyboardEventForSubWidgets(const Events::KeyboardEvent& ev); + bool giveSpecialEventForSubWidgets(const Events::SpecialEvent& ev); + bool giveCharacterInputEventForSubWidgets(const Events::CharacterInputEvent& ev); + bool giveMouseEventForSubWidgets(Events::MouseEvent& ev); + bool giveMotionEventForSubWidgets(Events::MotionEvent& ev); + bool giveScrollEventForSubWidgets(Events::ScrollEvent& ev); static TopLevelWidget* findTopLevelWidget(Widget* const w); diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp index a6848881..e8f3cad0 100644 --- a/dgl/src/WindowPrivateData.cpp +++ b/dgl/src/WindowPrivateData.cpp @@ -384,9 +384,48 @@ void Window::PrivateData::onPuglClose() close(); } +void Window::PrivateData::onPuglKey(const Events::KeyboardEvent& ev) +{ + DGL_DBGp("onPuglKey : %i %u %u\n", ev.press, ev.key, ev.keycode); + +// if (fModal.childFocus != nullptr) +// return fModal.childFocus->focus(); + +#ifndef DPF_TEST_WINDOW_CPP + if (topLevelWidget != nullptr) + topLevelWidget->pData->keyboardEvent(ev); +#endif +} + +void Window::PrivateData::onPuglSpecial(const Events::SpecialEvent& ev) +{ + DGL_DBGp("onPuglSpecial : %i %u\n", ev.press, ev.key); + +// if (fModal.childFocus != nullptr) +// return fModal.childFocus->focus(); + +#ifndef DPF_TEST_WINDOW_CPP + if (topLevelWidget != nullptr) + topLevelWidget->pData->specialEvent(ev); +#endif +} + +void Window::PrivateData::onPuglText(const Events::CharacterInputEvent& ev) +{ + DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string); + +// if (fModal.childFocus != nullptr) +// return fModal.childFocus->focus(); + +#ifndef DPF_TEST_WINDOW_CPP + if (topLevelWidget != nullptr) + topLevelWidget->pData->characterInputEvent(ev); +#endif +} + void Window::PrivateData::onPuglMouse(const Events::MouseEvent& ev) { - DGL_DBGp("PUGL: onMouse : %i %i %f %f\n", ev.button, ev.press, ev.pos.getX(), ev.pos.getY()); + DGL_DBGp("onPuglMouse : %i %i %f %f\n", ev.button, ev.press, ev.pos.getX(), ev.pos.getY()); // if (fModal.childFocus != nullptr) // return fModal.childFocus->focus(); @@ -397,6 +436,32 @@ void Window::PrivateData::onPuglMouse(const Events::MouseEvent& ev) #endif } +void Window::PrivateData::onPuglMotion(const Events::MotionEvent& ev) +{ + DGL_DBGp("onPuglMotion : %f %f\n", ev.button, ev.pos.getX(), ev.pos.getY()); + +// if (fModal.childFocus != nullptr) +// return fModal.childFocus->focus(); + +#ifndef DPF_TEST_WINDOW_CPP + if (topLevelWidget != nullptr) + topLevelWidget->pData->motionEvent(ev); +#endif +} + +void Window::PrivateData::onPuglScroll(const Events::ScrollEvent& ev) +{ + DGL_DBGp("onPuglScroll : %f %f %f %f\n", ev.pos.getX(), ev.pos.getY(), ev.delta.getX(), ev.delta.getY()); + +// if (fModal.childFocus != nullptr) +// return fModal.childFocus->focus(); + +#ifndef DPF_TEST_WINDOW_CPP + if (topLevelWidget != nullptr) + topLevelWidget->pData->scrollEvent(ev); +#endif +} + static int printEvent(const PuglEvent* event, const char* prefix, const bool verbose); PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const PuglEvent* const event) @@ -424,6 +489,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< View moved/resized, a #PuglEventConfigure case PUGL_CONFIGURE: + // unused x, y (double) pData->onPuglConfigure(event->configure.width, event->configure.height); break; @@ -441,6 +507,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< View must be drawn, a #PuglEventExpose case PUGL_EXPOSE: + // unused x, y, width, height (double) pData->onPuglExpose(); break; @@ -459,14 +526,38 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Key pressed, a #PuglEventKey case PUGL_KEY_PRESS: - break; ///< Key released, a #PuglEventKey case PUGL_KEY_RELEASE: + { + // unused x, y, xRoot, yRoot (double) + // TODO special keys? + Events::KeyboardEvent ev; + ev.mod = event->key.state; + ev.flags = event->key.flags; + ev.time = static_cast(event->key.time * 1000.0 + 0.5); + ev.press = event->type == PUGL_KEY_PRESS; + ev.key = event->key.key; + ev.keycode = event->key.keycode; + if ((ev.mod & kModifierShift) != 0 && ev.key >= 'a' && ev.key <= 'z') + ev.key -= 'a' - 'A'; // a-z -> A-Z + pData->onPuglKey(ev); break; + } ///< Character entered, a #PuglEventText case PUGL_TEXT: + { + // unused x, y, xRoot, yRoot (double) + Events::CharacterInputEvent ev; + ev.mod = event->text.state; + ev.flags = event->text.flags; + ev.time = static_cast(event->text.time * 1000.0 + 0.5); + ev.keycode = event->text.keycode; + ev.character = event->text.character; + std::strncpy(ev.string, event->text.string, sizeof(ev.string)); + pData->onPuglText(ev); break; + } ///< Pointer entered view, a #PuglEventCrossing case PUGL_POINTER_IN: @@ -493,11 +584,29 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Pointer moved, a #PuglEventMotion case PUGL_MOTION: + { + Events::MotionEvent ev; + ev.mod = event->motion.state; + ev.flags = event->motion.flags; + ev.time = static_cast(event->motion.time * 1000.0 + 0.5); + ev.pos = Point(event->motion.x, event->motion.y); + pData->onPuglMotion(ev); break; + } ///< Scrolled, a #PuglEventScroll case PUGL_SCROLL: + { + Events::ScrollEvent ev; + ev.mod = event->scroll.state; + ev.flags = event->scroll.flags; + ev.time = static_cast(event->scroll.time * 1000.0 + 0.5); + ev.pos = Point(event->scroll.x, event->scroll.y); + ev.delta = Point(event->scroll.dx, event->scroll.dy); + ev.direction = static_cast(event->scroll.direction); + pData->onPuglScroll(ev); break; + } ///< Custom client message, a #PuglEventClient case PUGL_CLIENT: @@ -646,6 +755,9 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver return 0; } +#undef DGL_DBG +#undef DGL_DBGF + // ----------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp index da6066fa..4af83ee0 100644 --- a/dgl/src/WindowPrivateData.hpp +++ b/dgl/src/WindowPrivateData.hpp @@ -109,20 +109,16 @@ struct Window::PrivateData : IdleCallback { void onPuglConfigure(int width, int height); void onPuglExpose(); void onPuglClose(); + void onPuglKey(const Events::KeyboardEvent& ev); + void onPuglSpecial(const Events::SpecialEvent& ev); + void onPuglText(const Events::CharacterInputEvent& ev); void onPuglMouse(const Events::MouseEvent& ev); + void onPuglMotion(const Events::MotionEvent& ev); + void onPuglScroll(const Events::ScrollEvent& ev); // Pugl event handling entry point static PuglStatus puglEventCallback(PuglView* view, const PuglEvent* event); -#if 0 - // Fallback build-specific Window functions - struct Fallback { - static void onDisplayBefore(const GraphicsContext& context); - static void onDisplayAfter(const GraphicsContext& context); - static void onReshape(const GraphicsContext& context, uint width, uint height); - }; -#endif - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) }; @@ -185,33 +181,6 @@ END_NAMESPACE_DGL #endif #endif -#if 0 // ndef DPF_TEST_WINDOW_CPP - // ------------------------------------------------------------------- - // stuff that uses pugl internals or build-specific things - - void init(const bool resizable = false); - void setVisible(const bool visible); - void windowSpecificIdle(); - - // ------------------------------------------------------------------- - - // ------------------------------------------------------------------- - - void addWidget(Widget* const widget); - void removeWidget(Widget* const widget); - - // ------------------------------------------------------------------- - - void onPuglClose(); - void onPuglMouse(const Widget::MouseEvent& ev); - - // ------------------------------------------------------------------- -#endif - -// #ifdef DISTRHO_DEFINES_H_INCLUDED -// friend class DISTRHO_NAMESPACE::UI; -// #endif - #if 0 // ----------------------------------------------------------------------- // Window Private @@ -287,147 +256,6 @@ struct Window::PrivateData { // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - - int onPuglKeyboard(const bool press, const uint key) - { - DBGp("PUGL: onKeyboard : %i %i\n", press, key); - - if (fModal.childFocus != nullptr) - { - fModal.childFocus->focus(); - return 0; - } - - Widget::KeyboardEvent ev; - ev.press = press; - ev.key = key; - ev.mod = static_cast(puglGetModifiers(fView)); - ev.time = puglGetEventTimestamp(fView); - - FOR_EACH_WIDGET_INV(rit) - { - Widget* const widget(*rit); - - if (widget->isVisible() && widget->onKeyboard(ev)) - return 0; - } - - return 1; - } - - int onPuglSpecial(const bool press, const Key key) - { - DBGp("PUGL: onSpecial : %i %i\n", press, key); - - if (fModal.childFocus != nullptr) - { - fModal.childFocus->focus(); - return 0; - } - - Widget::SpecialEvent ev; - ev.press = press; - ev.key = key; - ev.mod = static_cast(puglGetModifiers(fView)); - ev.time = puglGetEventTimestamp(fView); - - FOR_EACH_WIDGET_INV(rit) - { - Widget* const widget(*rit); - - if (widget->isVisible() && widget->onSpecial(ev)) - return 0; - } - - return 1; - } - - void onPuglMotion(int x, int y) - { - // DBGp("PUGL: onMotion : %i %i\n", x, y); - - if (fModal.childFocus != nullptr) - return; - - x /= fAutoScaling; - y /= fAutoScaling; - - Widget::MotionEvent ev; - ev.mod = static_cast(puglGetModifiers(fView)); - ev.time = puglGetEventTimestamp(fView); - - FOR_EACH_WIDGET_INV(rit) - { - Widget* const widget(*rit); - - ev.pos = Point(x-widget->getAbsoluteX(), y-widget->getAbsoluteY()); - - if (widget->isVisible() && widget->onMotion(ev)) - break; - } - } - - void onPuglScroll(int x, int y, float dx, float dy) - { - DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy); - - if (fModal.childFocus != nullptr) - return; - - x /= fAutoScaling; - y /= fAutoScaling; - dx /= fAutoScaling; - dy /= fAutoScaling; - - Widget::ScrollEvent ev; - ev.delta = Point(dx, dy); - ev.mod = static_cast(puglGetModifiers(fView)); - ev.time = puglGetEventTimestamp(fView); - - FOR_EACH_WIDGET_INV(rit) - { - Widget* const widget(*rit); - - ev.pos = Point(x-widget->getAbsoluteX(), y-widget->getAbsoluteY()); - - if (widget->isVisible() && widget->onScroll(ev)) - break; - } - } - - // ------------------------------------------------------------------- - - bool handlePluginKeyboard(const bool press, const uint key) - { - DBGp("PUGL: handlePluginKeyboard : %i %i\n", press, key); - - if (fModal.childFocus != nullptr) - { - fModal.childFocus->focus(); - return true; - } - - Widget::KeyboardEvent ev; - ev.press = press; - ev.key = key; - ev.mod = static_cast(fView->mods); - ev.time = 0; - - if ((ev.mod & kModifierShift) != 0 && ev.key >= 'a' && ev.key <= 'z') - ev.key -= 'a' - 'A'; // a-z -> A-Z - - FOR_EACH_WIDGET_INV(rit) - { - Widget* const widget(*rit); - - if (widget->isVisible() && widget->onKeyboard(ev)) - return true; - } - - return false; - } - bool handlePluginSpecial(const bool press, const Key key) { DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key); @@ -519,7 +347,4 @@ struct Window::PrivateData { }; #endif -// #undef DGL_DBG -// #undef DGL_DBGF - #endif // DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED