diff --git a/modules/core_widgets/uiitem.lua b/modules/core_widgets/uiitem.lua index 93f520a7..42ee50a3 100644 --- a/modules/core_widgets/uiitem.lua +++ b/modules/core_widgets/uiitem.lua @@ -2,7 +2,7 @@ function UIItem:onDragEnter(mousePos) if self:isVirtual() then return false end local item = self:getItem() - if not item then return true end + if not item then return false end self:setBorderWidth(1) diff --git a/modules/core_widgets/uiminiwindow.lua b/modules/core_widgets/uiminiwindow.lua index d82b6963..d71496d2 100644 --- a/modules/core_widgets/uiminiwindow.lua +++ b/modules/core_widgets/uiminiwindow.lua @@ -24,6 +24,7 @@ function UIMiniWindow:onDragEnter(mousePos) local oldPos = self:getPosition() self.movingReference = { x = mousePos.x - oldPos.x, y = mousePos.y - oldPos.y } self:setPosition(oldPos) + return true end function UIMiniWindow:onDragLeave(droppedWidget, mousePos) diff --git a/modules/core_widgets/uiwindow.lua b/modules/core_widgets/uiwindow.lua index c9810e59..69c8ffe5 100644 --- a/modules/core_widgets/uiwindow.lua +++ b/modules/core_widgets/uiwindow.lua @@ -25,6 +25,7 @@ end function UIWindow:onDragEnter(mousePos) self:breakAnchors() self.movingReference = { x = mousePos.x - self:getX(), y = mousePos.y - self:getY() } + return true end function UIWindow:onDragLeave(droppedWidget, mousePos) diff --git a/src/framework/ui/uimanager.cpp b/src/framework/ui/uimanager.cpp index 9d25b947..168c561c 100644 --- a/src/framework/ui/uimanager.cpp +++ b/src/framework/ui/uimanager.cpp @@ -26,6 +26,7 @@ #include #include #include +#include UIManager g_ui; @@ -78,8 +79,12 @@ void UIManager::inputEvent(const InputEvent& event) break; case Fw::MousePressInputEvent: m_mouseReceiver->propagateOnMousePress(event.mousePos, event.mouseButton); - if(event.mouseButton == Fw::MouseLeftButton) - updatePressedWidget(m_mouseReceiver->recursiveGetChildByPos(event.mousePos), event.mousePos); + if(event.mouseButton == Fw::MouseLeftButton && m_mouseReceiver->isVisible()) { + UIWidgetPtr pressedWidget = m_mouseReceiver->recursiveGetChildByPos(event.mousePos); + if(pressedWidget && !pressedWidget->isEnabled()) + pressedWidget = nullptr; + updatePressedWidget(pressedWidget, event.mousePos); + } break; case Fw::MouseReleaseInputEvent: m_mouseReceiver->propagateOnMouseRelease(event.mousePos, event.mouseButton); @@ -123,74 +128,80 @@ void UIManager::updatePressedWidget(const UIWidgetPtr& newPressedWidget, const P if(oldPressedWidget) { oldPressedWidget->updateState(Fw::PressedState); - // when releasing mouse inside pressed widget area send onClick event - if(!clickedPos.isNull() && oldPressedWidget->containsPoint(clickedPos)) - oldPressedWidget->onClick(clickedPos); - // must send mouse events even if the mouse is outside widget area when releasing a pressed widget - else - oldPressedWidget->onMouseRelease(clickedPos, Fw::MouseLeftButton); + if(oldPressedWidget->isEnabled()) { + // when releasing mouse inside pressed widget area send onClick event + if(!clickedPos.isNull() && oldPressedWidget->containsPoint(clickedPos)) { + // onMouseRelease will be already fired by mouseReceiver + oldPressedWidget->onClick(clickedPos); + // must send mouse events even if the mouse is outside widget area when releasing a pressed widget + } else + oldPressedWidget->onMouseRelease(clickedPos, Fw::MouseLeftButton); + } } } void UIManager::updateHoveredWidget() { - UIWidgetPtr hoveredWidget = m_rootWidget->recursiveGetChildByPos(g_window.getMousePosition()); - if(hoveredWidget != m_hoveredWidget) { - UIWidgetPtr oldHovered = m_hoveredWidget; - m_hoveredWidget = hoveredWidget; - if(oldHovered) - oldHovered->updateState(Fw::HoverState); - if(hoveredWidget) - hoveredWidget->updateState(Fw::HoverState); - } + if(m_hoverUpdateScheduled) + return; + + g_dispatcher.addEvent([this] { + if(!m_rootWidget) + return; + + m_hoverUpdateScheduled = false; + UIWidgetPtr hoveredWidget = m_rootWidget->recursiveGetChildByPos(g_window.getMousePosition()); + if(hoveredWidget && !hoveredWidget->isEnabled()) + hoveredWidget = nullptr; + + if(hoveredWidget != m_hoveredWidget) { + UIWidgetPtr oldHovered = m_hoveredWidget; + m_hoveredWidget = hoveredWidget; + if(oldHovered) + oldHovered->updateState(Fw::HoverState); + if(hoveredWidget) + hoveredWidget->updateState(Fw::HoverState); + } + }); + m_hoverUpdateScheduled = true; } void UIManager::updateDraggingWidget(const UIWidgetPtr& draggingWidget, const Point& clickedPos) { UIWidgetPtr oldDraggingWidget = m_draggingWidget; + m_draggingWidget = nullptr; if(oldDraggingWidget) { - auto clickedChildren = m_rootWidget->recursiveGetChildrenByPos(clickedPos); UIWidgetPtr droppedWidget; - for(const UIWidgetPtr& child : clickedChildren) { - if(child->onDrop(oldDraggingWidget, clickedPos)) { - droppedWidget = child; - break; + if(!clickedPos.isNull()) { + auto clickedChildren = m_rootWidget->recursiveGetChildrenByPos(clickedPos); + for(const UIWidgetPtr& child : clickedChildren) { + if(child->onDrop(oldDraggingWidget, clickedPos)) { + droppedWidget = child; + break; + } } } oldDraggingWidget->onDragLeave(droppedWidget, clickedPos); + oldDraggingWidget->updateState(Fw::DraggingState); } - m_draggingWidget = draggingWidget; - - if(oldDraggingWidget) - oldDraggingWidget->updateState(Fw::DraggingState); - if(draggingWidget) { - draggingWidget->updateState(Fw::DraggingState); - draggingWidget->onDragEnter(clickedPos); + if(draggingWidget->onDragEnter(clickedPos)) { + m_draggingWidget = draggingWidget; + draggingWidget->updateState(Fw::DraggingState); + } } } void UIManager::onWidgetAppear(const UIWidgetPtr& widget) { - if(widget->getRootParent() != m_rootWidget || !widget->isVisible()) - return; - - if(widget->getRect().contains(g_window.getMousePosition())) - updateHoveredWidget(); + updateHoveredWidget(); } void UIManager::onWidgetDisappear(const UIWidgetPtr& widget) { - if(widget->getRootParent() != m_rootWidget || widget->isVisible()) - return; - - if(m_hoveredWidget == widget) - updateHoveredWidget(); - - if(m_pressedWidget == widget) - updatePressedWidget(nullptr); + updateHoveredWidget(); } void UIManager::onWidgetDestroy(const UIWidgetPtr& widget) @@ -207,6 +218,9 @@ void UIManager::onWidgetDestroy(const UIWidgetPtr& widget) if(m_pressedWidget == widget) updatePressedWidget(nullptr); + + if(m_draggingWidget == widget) + updateDraggingWidget(nullptr); } bool UIManager::importStyle(const std::string& file) diff --git a/src/framework/ui/uimanager.h b/src/framework/ui/uimanager.h index bbe04915..09d90789 100644 --- a/src/framework/ui/uimanager.h +++ b/src/framework/ui/uimanager.h @@ -39,7 +39,7 @@ public: void updatePressedWidget(const UIWidgetPtr& newPressedWidget, const Point& clickedPos = Point()); void updateHoveredWidget(); - void updateDraggingWidget(const UIWidgetPtr& draggingWidget, const Point& clickedPos); + void updateDraggingWidget(const UIWidgetPtr& draggingWidget, const Point& clickedPos = Point()); bool importStyle(const std::string& file); void importStyleFromOTML(const OTMLNodePtr& styleNode); @@ -78,6 +78,7 @@ private: UIWidgetPtr m_draggingWidget; UIWidgetPtr m_hoveredWidget; UIWidgetPtr m_pressedWidget; + Boolean m_hoverUpdateScheduled; bool m_isOnInputEvent; Boolean m_drawDebugBoxes; std::map m_styles; diff --git a/src/framework/ui/uiwidget.cpp b/src/framework/ui/uiwidget.cpp index 37ccd44f..76489b9e 100644 --- a/src/framework/ui/uiwidget.cpp +++ b/src/framework/ui/uiwidget.cpp @@ -571,9 +571,6 @@ void UIWidget::grabMouse() void UIWidget::ungrabMouse() { - if(m_destroyed) - return; - if(g_ui.getMouseReceiver() == asUIWidget()) g_ui.resetMouseReceiver(); } @@ -588,9 +585,6 @@ void UIWidget::grabKeyboard() void UIWidget::ungrabKeyboard() { - if(m_destroyed) - return; - if(g_ui.getKeyboardReceiver() == asUIWidget()) g_ui.resetKeyboardReceiver(); } @@ -756,6 +750,7 @@ void UIWidget::setEnabled(bool enabled) updateState(Fw::DisabledState); updateState(Fw::ActiveState); + updateState(Fw::HoverState); } } @@ -764,12 +759,6 @@ void UIWidget::setVisible(bool visible) if(m_visible != visible) { m_visible = visible; - // visibility can change the current hovered widget - if(visible) - g_ui.onWidgetAppear(asUIWidget()); - else - g_ui.onWidgetDisappear(asUIWidget()); - // hiding a widget make it lose focus if(!visible && isFocused()) { if(UIWidgetPtr parent = getParent()) @@ -780,6 +769,12 @@ void UIWidget::setVisible(bool visible) updateParentLayout(); updateState(Fw::ActiveState); + + // visibility can change the current hovered widget + if(visible) + g_ui.onWidgetAppear(asUIWidget()); + else + g_ui.onWidgetDisappear(asUIWidget()); } } @@ -1033,7 +1028,7 @@ void UIWidget::updateState(Fw::WidgetState state) } } while(widget = parent); - updateChildren = true; + updateChildren = newStatus != oldStatus; break; } case Fw::FocusState: { @@ -1041,7 +1036,8 @@ void UIWidget::updateState(Fw::WidgetState state) break; } case Fw::HoverState: { - newStatus = (g_ui.getHoveredWidget() == asUIWidget()); + updateChildren = true; + newStatus = (g_ui.getHoveredWidget() == asUIWidget() && isEnabled()); break; } case Fw::PressedState: { @@ -1054,7 +1050,6 @@ void UIWidget::updateState(Fw::WidgetState state) } case Fw::DisabledState: { bool enabled = true; - updateChildren = true; UIWidgetPtr widget = asUIWidget(); do { if(!widget->isExplicitlyEnabled()) { @@ -1063,6 +1058,7 @@ void UIWidget::updateState(Fw::WidgetState state) } } while(widget = widget->getParent()); newStatus = !enabled; + updateChildren = newStatus != oldStatus; break; } case Fw::FirstState: { @@ -1085,14 +1081,14 @@ void UIWidget::updateState(Fw::WidgetState state) return; } - if(setState(state, newStatus)) { - if(updateChildren) { - // do a backup of children list, because it may change while looping it - UIWidgetList children = m_children; - for(const UIWidgetPtr& child : children) - child->updateState(state); - } + if(updateChildren) { + // do a backup of children list, because it may change while looping it + UIWidgetList children = m_children; + for(const UIWidgetPtr& child : children) + child->updateState(state); + } + if(setState(state, newStatus)) { if(state == Fw::FocusState) { g_dispatcher.addEvent(std::bind(&UIWidget::onFocusChange, asUIWidget(), newStatus, m_lastFocusReason)); } else if(state == Fw::HoverState) @@ -1200,105 +1196,66 @@ void UIWidget::onStyleApply(const std::string& styleName, const OTMLNodePtr& sty void UIWidget::onGeometryChange(const Rect& oldRect, const Rect& newRect) { - if(m_destroyed) - return; - callLuaField("onGeometryChange", oldRect, newRect); } void UIWidget::onFocusChange(bool focused, Fw::FocusReason reason) { - if(m_destroyed) - return; - callLuaField("onFocusChange", focused, reason); } void UIWidget::onChildFocusChange(const UIWidgetPtr& focusedChild, const UIWidgetPtr& unfocusedChild, Fw::FocusReason reason) { - if(m_destroyed) - return; - callLuaField("onChildFocusChange", focusedChild, unfocusedChild, reason); } void UIWidget::onHoverChange(bool hovered) { - if(m_destroyed) - return; - callLuaField("onHoverChange", hovered); } -void UIWidget::onDragEnter(const Point& mousePos) +bool UIWidget::onDragEnter(const Point& mousePos) { - if(m_destroyed) - return; - - callLuaField("onDragEnter", mousePos); + return callLuaField("onDragEnter", mousePos); } void UIWidget::onDragLeave(UIWidgetPtr droppedWidget, const Point& mousePos) { - if(m_destroyed) - return; - callLuaField("onDragLeave", droppedWidget, mousePos); } bool UIWidget::onDragMove(const Point& mousePos, const Point& mouseMoved) { - if(m_destroyed) - return false; - return callLuaField("onDragMove", mousePos, mouseMoved); } bool UIWidget::onDrop(UIWidgetPtr draggedWidget, const Point& mousePos) { - if(m_destroyed) - return false; - return callLuaField("onDrop", draggedWidget, mousePos); } bool UIWidget::onKeyText(const std::string& keyText) { - if(m_destroyed) - return false; - return callLuaField("onKeyText", keyText); } bool UIWidget::onKeyDown(uchar keyCode, int keyboardModifiers) { - if(m_destroyed) - return false; - return callLuaField("onKeyDown", keyCode, keyboardModifiers); } bool UIWidget::onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks) { - if(m_destroyed) - return false; - return callLuaField("onKeyPress", keyCode, keyboardModifiers, autoRepeatTicks); } bool UIWidget::onKeyUp(uchar keyCode, int keyboardModifiers) { - if(m_destroyed) - return false; - return callLuaField("onKeyUp", keyCode, keyboardModifiers); } bool UIWidget::onMousePress(const Point& mousePos, Fw::MouseButton button) { - if(m_destroyed) - return false; - if(button == Fw::MouseLeftButton) { if(m_clickTimer.running() && m_clickTimer.ticksElapsed() <= 500) { if(onDoubleClick(mousePos)) @@ -1315,41 +1272,26 @@ bool UIWidget::onMousePress(const Point& mousePos, Fw::MouseButton button) bool UIWidget::onMouseRelease(const Point& mousePos, Fw::MouseButton button) { - if(m_destroyed) - return false; - return callLuaField("onMouseRelease", mousePos, button); } bool UIWidget::onMouseMove(const Point& mousePos, const Point& mouseMoved) { - if(m_destroyed) - return false; - return callLuaField("onMouseMove", mousePos, mouseMoved); } bool UIWidget::onMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction) { - if(m_destroyed) - return false; - return callLuaField("onMouseWheel", mousePos, direction); } bool UIWidget::onClick(const Point& mousePos) { - if(m_destroyed) - return false; - return callLuaField("onClick", mousePos); } bool UIWidget::onDoubleClick(const Point& mousePos) { - if(m_destroyed) - return false; - return callLuaField("onDoubleClick", mousePos); } diff --git a/src/framework/ui/uiwidget.h b/src/framework/ui/uiwidget.h index 936be965..102a6869 100644 --- a/src/framework/ui/uiwidget.h +++ b/src/framework/ui/uiwidget.h @@ -170,7 +170,7 @@ protected: virtual void onFocusChange(bool focused, Fw::FocusReason reason); virtual void onChildFocusChange(const UIWidgetPtr& focusedChild, const UIWidgetPtr& unfocusedChild, Fw::FocusReason reason); virtual void onHoverChange(bool hovered); - virtual void onDragEnter(const Point& mousePos); + virtual bool onDragEnter(const Point& mousePos); virtual void onDragLeave(UIWidgetPtr droppedWidget, const Point& mousePos); virtual bool onDragMove(const Point& mousePos, const Point& mouseMoved); virtual bool onDrop(UIWidgetPtr draggedWidget, const Point& mousePos);