From 9309d6e7f337a92714c194d3f16e3d8499e402b1 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Mon, 26 Mar 2012 10:34:43 -0300 Subject: [PATCH] some rework in UIWidget input --- modules/client_entergame/characterlist.otui | 5 +- modules/core_lib/mouse.lua | 2 +- modules/core_lib/widgets/uiscrollarea.lua | 15 +- modules/core_lib/widgets/uiscrollbar.lua | 11 +- modules/core_lib/widgets/uisplitter.lua | 1 - modules/game_console/console.lua | 4 - modules/game_console/console.otui | 1 - src/framework/ui/uihorizontallayout.cpp | 2 +- src/framework/ui/uimanager.cpp | 150 +++++++++++--------- src/framework/ui/uimanager.h | 5 +- src/framework/ui/uiverticallayout.cpp | 2 +- src/framework/ui/uiwidget.cpp | 69 +++------ src/framework/ui/uiwidget.h | 6 +- 13 files changed, 140 insertions(+), 133 deletions(-) diff --git a/modules/client_entergame/characterlist.otui b/modules/client_entergame/characterlist.otui index 4088c485..764dd8c4 100644 --- a/modules/client_entergame/characterlist.otui +++ b/modules/client_entergame/characterlist.otui @@ -22,13 +22,14 @@ MainWindow margin-bottom: 5 padding: 1 focusable: false + vertical-scrollbar: characterListScrollBar VerticalScrollBar - attached-to: characterList + id: characterListScrollBar anchors.top: characterList.top anchors.bottom: characterList.bottom anchors.right: characterList.right - maximum: 0 + step: 14 Label id: accountStatusLabel diff --git a/modules/core_lib/mouse.lua b/modules/core_lib/mouse.lua index ccefbc28..3f079fd1 100644 --- a/modules/core_lib/mouse.lua +++ b/modules/core_lib/mouse.lua @@ -17,7 +17,7 @@ function Mouse.restoreCursor() end function Mouse.isPressed() - return g_ui.getPressedWidget() == nil + return g_ui.getPressedWidget() ~= nil end function Mouse.bindAutoPress(widget, callback) diff --git a/modules/core_lib/widgets/uiscrollarea.lua b/modules/core_lib/widgets/uiscrollarea.lua index e7e47737..5dd8e254 100644 --- a/modules/core_lib/widgets/uiscrollarea.lua +++ b/modules/core_lib/widgets/uiscrollarea.lua @@ -33,7 +33,9 @@ function UIScrollArea:updateScrollBars() if scrollbar then if self.inverted then scrollbar:setMinimum(-scrollheight) + scrollbar:setMaximum(0) else + scrollbar:setMinimum(0) scrollbar:setMaximum(scrollheight) end end @@ -50,10 +52,8 @@ end function UIScrollArea:setVerticalScrollBar(scrollbar) self.verticalScrollBar = scrollbar - scrollbar:setMaximum(0) self.verticalScrollBar.onValueChange = function(scrollbar, value) local virtualOffset = self:getVirtualOffset() - if self.inverted then value = -value end virtualOffset.y = value self:setVirtualOffset(virtualOffset) end @@ -72,3 +72,14 @@ end function UIScrollArea:onLayoutUpdate() self:updateScrollBars() end + +function UIScrollArea:onMouseWheel(mousePos, mouseWheel) + if self.verticalScrollBar then + if mouseWheel == MouseWheelUp then + self.verticalScrollBar:decrement() + else + self.verticalScrollBar:increment() + end + end + return true +end diff --git a/modules/core_lib/widgets/uiscrollbar.lua b/modules/core_lib/widgets/uiscrollbar.lua index a9470466..a0504ff8 100644 --- a/modules/core_lib/widgets/uiscrollbar.lua +++ b/modules/core_lib/widgets/uiscrollbar.lua @@ -22,7 +22,7 @@ local function calcValues(self) local px = math.max(math.floor(proportion * pxrange), 10) local offset = 0 if range > 1 then - offset = (((self.value - self.minimum) / (range - 1)) - 0.5) * (pxrange - px) + offset = math.ceil((((self.value - self.minimum) / (range - 1)) - 0.5) * (pxrange - px)) end return range, pxrange, px, offset, center @@ -153,6 +153,15 @@ function UIScrollBar:onGeometryChange() updateSlider(self) end +function UIScrollBar:onMouseWheel(mousePos, mouseWheel) + if mouseWheel == MouseWheelUp then + self:decrement() + else + self:increment() + end + return true +end + function UIScrollBar:getMaximum() return self.maximum end function UIScrollBar:getMinimum() return self.minimum end function UIScrollBar:getValue() return self.value end diff --git a/modules/core_lib/widgets/uisplitter.lua b/modules/core_lib/widgets/uisplitter.lua index 4c6e257f..96b3136e 100644 --- a/modules/core_lib/widgets/uisplitter.lua +++ b/modules/core_lib/widgets/uisplitter.lua @@ -46,7 +46,6 @@ function UISplitter:onMouseRelease(mousePos, mouseButton) if not self:isHovered() then Mouse.restoreCursor() end - self:ungrabMouse() end function UISplitter:onStyleApply(styleName, styleNode) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index 653dbd97..384d0e08 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -215,10 +215,6 @@ function Console.terminate() Console = nil end -function Console.debug() - print(#channels) -end - function Console.clear() for channelid, channelname in pairs(channels) do if channelid ~= 0 then diff --git a/modules/game_console/console.otui b/modules/game_console/console.otui index c3e50d94..dbdddf60 100644 --- a/modules/game_console/console.otui +++ b/modules/game_console/console.otui @@ -12,7 +12,6 @@ ConsoleTabBarPanel < TabBarPanel ScrollablePanel id: consoleBuffer - // height = max lines * 14 anchors.fill: parent margin-right: 12 vertical-scrollbar: consoleScrollBar diff --git a/src/framework/ui/uihorizontallayout.cpp b/src/framework/ui/uihorizontallayout.cpp index b1780a1a..3462758b 100644 --- a/src/framework/ui/uihorizontallayout.cpp +++ b/src/framework/ui/uihorizontallayout.cpp @@ -70,7 +70,7 @@ void UIHorizontalLayout::internalUpdate() pos.y = clippingRect.top() + (clippingRect.height() - size.height())/2; } - widget->setRect(Rect(pos + parentWidget->getVirtualOffset(), size)); + widget->setRect(Rect(pos - parentWidget->getVirtualOffset(), size)); gap = (m_alignRight) ? -widget->getMarginLeft() : (widget->getWidth() + widget->getMarginRight()); gap += m_spacing; diff --git a/src/framework/ui/uimanager.cpp b/src/framework/ui/uimanager.cpp index 73352c65..ea667c64 100644 --- a/src/framework/ui/uimanager.cpp +++ b/src/framework/ui/uimanager.cpp @@ -64,6 +64,7 @@ void UIManager::resize(const Size& size) void UIManager::inputEvent(const InputEvent& event) { m_isOnInputEvent = true; + UIWidgetList widgetList; switch(event.type) { case Fw::KeyTextInputEvent: m_keyboardReceiver->propagateOnKeyText(event.keyText); @@ -78,41 +79,68 @@ void UIManager::inputEvent(const InputEvent& event) m_keyboardReceiver->propagateOnKeyUp(event.keyCode, event.keyboardModifiers); break; case Fw::MousePressInputEvent: - m_mouseReceiver->propagateOnMousePress(event.mousePos, event.mouseButton); 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); } + m_mouseReceiver->propagateOnMousePress(event.mousePos, event.mouseButton); break; case Fw::MouseReleaseInputEvent: { - m_mouseReceiver->propagateOnMouseRelease(event.mousePos, event.mouseButton); - if(event.mouseButton == Fw::MouseLeftButton) { - // release pressed widget - if(m_pressedWidget) - updatePressedWidget(nullptr, event.mousePos); - - // release dragging widget - if(m_draggingWidget) - updateDraggingWidget(nullptr, event.mousePos); + // release dragging widget + bool accepted = false; + if(m_draggingWidget && event.mouseButton == Fw::MouseLeftButton) + accepted = updateDraggingWidget(nullptr, event.mousePos); + + if(!accepted) { + m_mouseReceiver->propagateOnMouseRelease(event.mousePos, event.mouseButton, widgetList); + + // mouse release is always fired first on the pressed widget + if(m_pressedWidget) { + auto it = std::find(widgetList.begin(), widgetList.end(), m_pressedWidget); + if(it != widgetList.end()) + widgetList.erase(it); + widgetList.push_front(m_pressedWidget); + } + + for(const UIWidgetPtr& widget : widgetList) { + if(widget->onMouseRelease(event.mousePos, event.mouseButton)) + break; + } } + + if(m_pressedWidget && event.mouseButton == Fw::MouseLeftButton) + updatePressedWidget(nullptr, event.mousePos); break; } case Fw::MouseMoveInputEvent: { - // start dragging when moves a pressed widget + // start dragging when moving a pressed widget if(m_pressedWidget && m_pressedWidget->isDragable() && m_draggingWidget != m_pressedWidget) updateDraggingWidget(m_pressedWidget, event.mousePos - event.mouseMoved); - if(m_draggingWidget) - m_draggingWidget->onDragMove(event.mousePos, event.mouseMoved); - + // mouse move can change hovered widgets updateHoveredWidget(); - m_mouseReceiver->propagateOnMouseMove(event.mousePos, event.mouseMoved); + + // first fire dragging move + if(m_draggingWidget) { + if(m_draggingWidget->onDragMove(event.mousePos, event.mouseMoved)) + break; + } + + m_mouseReceiver->propagateOnMouseMove(event.mousePos, event.mouseMoved, widgetList); + for(const UIWidgetPtr& widget : widgetList) { + if(widget->onMouseMove(event.mousePos, event.mouseMoved)) + break; + } break; } case Fw::MouseWheelInputEvent: - m_mouseReceiver->propagateOnMouseWheel(event.mousePos, event.wheelDirection); + m_mouseReceiver->propagateOnMouseWheel(event.mousePos, event.wheelDirection, widgetList); + for(const UIWidgetPtr& widget : widgetList) { + if(widget->onMouseWheel(event.mousePos, event.wheelDirection)) + break; + } break; default: break; @@ -120,58 +148,20 @@ void UIManager::inputEvent(const InputEvent& event) m_isOnInputEvent = false; } -bool UIManager::updatePressedWidget(const UIWidgetPtr& newPressedWidget, const Point& clickedPos) +void UIManager::updatePressedWidget(const UIWidgetPtr& newPressedWidget, const Point& clickedPos) { - bool accepted = false; - UIWidgetPtr oldPressedWidget = m_pressedWidget; - if(oldPressedWidget) { - 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 - accepted = oldPressedWidget->onClick(clickedPos); - // must send mouse events even if the mouse is outside widget area when releasing a pressed widget - } else - accepted = oldPressedWidget->onMouseRelease(clickedPos, Fw::MouseLeftButton); - } - } - m_pressedWidget = newPressedWidget; + // when releasing mouse inside pressed widget area send onClick event + if(oldPressedWidget && oldPressedWidget->isEnabled() && oldPressedWidget->containsPoint(clickedPos)) + oldPressedWidget->onClick(clickedPos); + if(newPressedWidget) newPressedWidget->updateState(Fw::PressedState); if(oldPressedWidget) oldPressedWidget->updateState(Fw::PressedState); - - return accepted; -} - -void UIManager::updateHoveredWidget() -{ - if(m_hoverUpdateScheduled) - return; - - g_eventDispatcher.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; } bool UIManager::updateDraggingWidget(const UIWidgetPtr& draggingWidget, const Point& clickedPos) @@ -200,20 +190,53 @@ bool UIManager::updateDraggingWidget(const UIWidgetPtr& draggingWidget, const Po if(draggingWidget->onDragEnter(clickedPos)) { m_draggingWidget = draggingWidget; draggingWidget->updateState(Fw::DraggingState); + accepted = true; } } return accepted; } +void UIManager::updateHoveredWidget() +{ + if(m_hoverUpdateScheduled) + return; + + g_eventDispatcher.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); + oldHovered->onHoverChange(false); + } + if(hoveredWidget) { + hoveredWidget->updateState(Fw::HoverState); + hoveredWidget->onHoverChange(true); + } + } + }); + m_hoverUpdateScheduled = true; +} + void UIManager::onWidgetAppear(const UIWidgetPtr& widget) { - updateHoveredWidget(); + if(widget->containsPoint(g_window.getMousePosition())) + updateHoveredWidget(); } void UIManager::onWidgetDisappear(const UIWidgetPtr& widget) { - updateHoveredWidget(); + if(widget->containsPoint(g_window.getMousePosition())) + updateHoveredWidget(); } void UIManager::onWidgetDestroy(const UIWidgetPtr& widget) @@ -233,10 +256,8 @@ void UIManager::onWidgetDestroy(const UIWidgetPtr& widget) if(m_draggingWidget == widget) updateDraggingWidget(nullptr); -} -void UIManager::addDestroyedWidget(const UIWidgetPtr& widget) -{ +#ifdef DEBUG static UIWidgetList destroyedWidgets; static ScheduledEventPtr checkEvent; @@ -258,6 +279,7 @@ void UIManager::addDestroyedWidget(const UIWidgetPtr& widget) } }); }, 1000); +#endif } bool UIManager::importStyle(const std::string& file) diff --git a/src/framework/ui/uimanager.h b/src/framework/ui/uimanager.h index 4f912df8..65e37e18 100644 --- a/src/framework/ui/uimanager.h +++ b/src/framework/ui/uimanager.h @@ -37,9 +37,9 @@ public: void resize(const Size& size); void inputEvent(const InputEvent& event); - bool updatePressedWidget(const UIWidgetPtr& newPressedWidget, const Point& clickedPos = Point()); - void updateHoveredWidget(); + void updatePressedWidget(const UIWidgetPtr& newPressedWidget, const Point& clickedPos = Point()); bool updateDraggingWidget(const UIWidgetPtr& draggingWidget, const Point& clickedPos = Point()); + void updateHoveredWidget(); bool importStyle(const std::string& file); void importStyleFromOTML(const OTMLNodePtr& styleNode); @@ -69,7 +69,6 @@ protected: void onWidgetAppear(const UIWidgetPtr& widget); void onWidgetDisappear(const UIWidgetPtr& widget); void onWidgetDestroy(const UIWidgetPtr& widget); - void addDestroyedWidget(const UIWidgetPtr& widget); friend class UIWidget; diff --git a/src/framework/ui/uiverticallayout.cpp b/src/framework/ui/uiverticallayout.cpp index d34ef789..3cec4460 100644 --- a/src/framework/ui/uiverticallayout.cpp +++ b/src/framework/ui/uiverticallayout.cpp @@ -70,7 +70,7 @@ void UIVerticalLayout::internalUpdate() pos.x = clippingRect.left() + (clippingRect.width() - size.width())/2; } - widget->setRect(Rect(pos + parentWidget->getVirtualOffset(), size)); + widget->setRect(Rect(pos - parentWidget->getVirtualOffset(), size)); gap = (m_alignBottom) ? -widget->getMarginTop() : (widget->getHeight() + widget->getMarginBottom()); gap += m_spacing; diff --git a/src/framework/ui/uiwidget.cpp b/src/framework/ui/uiwidget.cpp index c853b0b3..9f2c2cc7 100644 --- a/src/framework/ui/uiwidget.cpp +++ b/src/framework/ui/uiwidget.cpp @@ -244,12 +244,16 @@ void UIWidget::focusChild(const UIWidgetPtr& child, Fw::FocusReason reason) child->setLastFocusReason(reason); child->updateState(Fw::FocusState); child->updateState(Fw::ActiveState); + + g_eventDispatcher.addEvent(std::bind(&UIWidget::onFocusChange, child, true, reason)); } if(oldFocused) { oldFocused->setLastFocusReason(reason); oldFocused->updateState(Fw::FocusState); oldFocused->updateState(Fw::ActiveState); + + g_eventDispatcher.addEvent(std::bind(&UIWidget::onFocusChange, oldFocused, false, reason)); } onChildFocusChange(child, oldFocused, reason); @@ -647,8 +651,6 @@ void UIWidget::destroy() setVisible(false); setEnabled(false); - g_ui.onWidgetDestroy(asUIWidget()); - // remove itself from parent if(UIWidgetPtr parent = getParent()) parent->removeChild(asUIWidget()); @@ -660,9 +662,7 @@ void UIWidget::destroy() releaseLuaFieldsTable(); -#ifdef DEBUG - g_ui.addDestroyedWidget(asUIWidget()); -#endif + g_ui.onWidgetDestroy(asUIWidget()); } void UIWidget::destroyChildren() @@ -781,7 +781,6 @@ void UIWidget::setEnabled(bool enabled) updateState(Fw::DisabledState); updateState(Fw::ActiveState); - updateState(Fw::HoverState); } } @@ -1090,7 +1089,6 @@ void UIWidget::updateState(Fw::WidgetState state) break; } case Fw::HoverState: { - updateChildren = true; newStatus = (g_ui.getHoveredWidget() == asUIWidget() && isEnabled()); break; } @@ -1143,10 +1141,10 @@ void UIWidget::updateState(Fw::WidgetState state) } if(setState(state, newStatus)) { - if(state == Fw::FocusState) { - g_eventDispatcher.addEvent(std::bind(&UIWidget::onFocusChange, asUIWidget(), newStatus, m_lastFocusReason)); - } else if(state == Fw::HoverState) - g_eventDispatcher.addEvent(std::bind(&UIWidget::onHoverChange, asUIWidget(), newStatus)); + // disabled widgets cannot have hover state + if(state == Fw::DisabledState && !newStatus && isHovered()) { + g_ui.updateHoveredWidget(); + } } } @@ -1288,7 +1286,7 @@ bool UIWidget::onDragLeave(UIWidgetPtr droppedWidget, const Point& mousePos) bool UIWidget::onDragMove(const Point& mousePos, const Point& mouseMoved) { - return callLuaField("onDragMove", mousePos, mouseMoved); + return callLuaField("onDragMove", mousePos, mouseMoved); } bool UIWidget::onDrop(UIWidgetPtr draggedWidget, const Point& mousePos) @@ -1489,10 +1487,9 @@ bool UIWidget::propagateOnMousePress(const Point& mousePos, Fw::MouseButton butt return false; } -bool UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button) +void UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button, UIWidgetList& widgetList) { // do a backup of children list, because it may change while looping it - UIWidgetPtr clickedChild; for(const UIWidgetPtr& child : m_children) { // events on hidden or disabled widgets are discarded if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) @@ -1500,48 +1497,31 @@ bool UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton bu // mouse press events only go to children that contains the mouse position if(child->containsPoint(mousePos) && child == getChildByPos(mousePos)) { - clickedChild = child; + child->propagateOnMouseRelease(mousePos, button, widgetList); break; } } - if(clickedChild) { - if(clickedChild->propagateOnMouseRelease(mousePos, button)) - return true; - } - - // only non phatom widgets receives mouse events + // only non phatom widgets receives mouse release events if(!isPhantom()) - return onMouseRelease(mousePos, button); - - return false; + widgetList.push_back(asUIWidget()); } -bool UIWidget::propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved) +void UIWidget::propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved, UIWidgetList& widgetList) { - // do a backup of children list, because it may change while looping it - UIWidgetList children; for(const UIWidgetPtr& child : m_children) { // events on hidden or disabled widgets are discarded if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) continue; // mouse move events go to all children - children.push_back(child); - } - - for(const UIWidgetPtr& child : children) { - if(child->propagateOnMouseMove(mousePos, mouseMoved)) - return true; + child->propagateOnMouseMove(mousePos, mouseMoved, widgetList); } - - return onMouseMove(mousePos, mouseMoved); + widgetList.push_back(asUIWidget()); } -bool UIWidget::propagateOnMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction) +void UIWidget::propagateOnMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction, UIWidgetList& widgetList) { - // do a backup of children list, because it may change while looping it - UIWidgetList children; for(const UIWidgetPtr& child : m_children) { // events on hidden or disabled widgets are discarded if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) @@ -1549,17 +1529,8 @@ bool UIWidget::propagateOnMouseWheel(const Point& mousePos, Fw::MouseWheelDirect // mouse wheel events only go to children that contains the mouse position if(child->containsPoint(mousePos) && child == getChildByPos(mousePos)) - children.push_back(child); + child->propagateOnMouseWheel(mousePos, direction, widgetList); } - for(const UIWidgetPtr& child : children) { - if(child->propagateOnMouseWheel(mousePos, direction)) - return true; - } - - // only non phatom widgets receives mouse events - if(!isPhantom()) - return onMouseWheel(mousePos, direction); - else - return false; + widgetList.push_back(asUIWidget()); } diff --git a/src/framework/ui/uiwidget.h b/src/framework/ui/uiwidget.h index 1aec856f..33ceec2f 100644 --- a/src/framework/ui/uiwidget.h +++ b/src/framework/ui/uiwidget.h @@ -200,9 +200,9 @@ protected: bool propagateOnKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks); bool propagateOnKeyUp(uchar keyCode, int keyboardModifiers); bool propagateOnMousePress(const Point& mousePos, Fw::MouseButton button); - bool propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button); - bool propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved); - bool propagateOnMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction); + void propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button, UIWidgetList& widgetList); + void propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved, UIWidgetList& widgetList); + void propagateOnMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction, UIWidgetList& widgetList); // function shortcuts