From b410921e322d503f16a0363cf5746d731e67b190 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 20 Aug 2011 22:01:46 -0300 Subject: [PATCH] fix focus bugs in UI --- CMakeLists.txt | 1 - modules/console/console.lua | 9 ++- modules/core/util.lua | 6 ++ src/framework/luascript/luafunctions.cpp | 2 +- src/framework/ui/uibutton.cpp | 1 + src/framework/ui/uilabel.cpp | 1 + src/framework/ui/uilineedit.cpp | 11 ++-- src/framework/ui/uiwidget.cpp | 79 +++++++++--------------- src/framework/ui/uiwidget.h | 5 +- src/framework/ui/uiwindow.cpp | 8 ++- src/framework/ui/uiwindow.h | 1 + src/otclient/core/tile.cpp | 8 +-- src/otclient/otclient.cpp | 6 +- 13 files changed, 68 insertions(+), 70 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2ef94c6..e713723b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,4 +168,3 @@ ENDIF(USE_PCH) SET(DATA_INSTALL_DIR share/otclient) INSTALL(TARGETS otclient RUNTIME DESTINATION bin) INSTALL(DIRECTORY modules DESTINATION ${DATA_INSTALL_DIR}) - diff --git a/modules/console/console.lua b/modules/console/console.lua index 5555f19c..75c142b4 100644 --- a/modules/console/console.lua +++ b/modules/console/console.lua @@ -1,6 +1,8 @@ Console = { } + local console local logLocked = false +local commandEnv = createEnvironment() function Console.onLog(level, message, time) -- avoid logging while reporting logs (would cause a infinite loop) @@ -61,11 +63,14 @@ end function Console.executeCommand(command) Console.addLine(">> " .. command, "#ffffff") - local func, err = loadstring("return (" .. command .. ")", "@") + local func, err = loadstring(command, "@") if func then + setfenv(func, commandEnv) local ok, ret = pcall(func) if ok then - Logger.log(LogDebug, "=> " .. tostring(ret)) + if ret then + print(ret) + end else Logger.log(LogError, 'command failed: ' .. ret) end diff --git a/modules/core/util.lua b/modules/core/util.lua index 394c7bdc..58d75fb2 100644 --- a/modules/core/util.lua +++ b/modules/core/util.lua @@ -4,4 +4,10 @@ function print(...) msg = msg .. tostring(v) .. "\t" end Logger.log(LogInfo, msg) +end + +function createEnvironment() + local env = { } + setmetatable(env, { __index = _G} ) + return env end \ No newline at end of file diff --git a/src/framework/luascript/luafunctions.cpp b/src/framework/luascript/luafunctions.cpp index 7accc5eb..328c3e00 100644 --- a/src/framework/luascript/luafunctions.cpp +++ b/src/framework/luascript/luafunctions.cpp @@ -14,7 +14,7 @@ void LuaInterface::registerFunctions() g_lua.bindClassMemberFunction("setId", &UIWidget::setId); g_lua.bindClassMemberFunction("isEnabled", &UIWidget::isEnabled); g_lua.bindClassMemberFunction("setEnabled", &UIWidget::setEnabled); - g_lua.bindClassMemberFunction("isVisible", &UIWidget::isVisible); + g_lua.bindClassMemberFunction("isExplicitlyVisible", &UIWidget::isExplicitlyVisible); g_lua.bindClassMemberFunction("setVisible", &UIWidget::setVisible); g_lua.bindClassMemberFunction("getWidth", &UIWidget::getWidth); g_lua.bindClassMemberFunction("setWidth", &UIWidget::setWidth); diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index fcceafd5..6c959267 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -8,6 +8,7 @@ UIButton::UIButton(): UIWidget(UITypeButton) { m_state = ButtonUp; + m_focusable = false; // by default, all callbacks call lua fields m_onClick = [this]() { this->callLuaField("onClick"); }; diff --git a/src/framework/ui/uilabel.cpp b/src/framework/ui/uilabel.cpp index c7cd8c09..3818977f 100644 --- a/src/framework/ui/uilabel.cpp +++ b/src/framework/ui/uilabel.cpp @@ -5,6 +5,7 @@ UILabel::UILabel() : UIWidget(UITypeLabel) { m_align = AlignLeft; + m_focusable = false; } UILabelPtr UILabel::create() diff --git a/src/framework/ui/uilineedit.cpp b/src/framework/ui/uilineedit.cpp index ce21da8e..9a09d09e 100644 --- a/src/framework/ui/uilineedit.cpp +++ b/src/framework/ui/uilineedit.cpp @@ -10,7 +10,6 @@ UILineEdit::UILineEdit() : UIWidget(UITypeLabel) m_cursorPos = 0; m_startRenderPos = 0; m_textHorizontalMargin = 3; - m_focusable = true; blinkCursor(); m_onAction = [this]() { this->callLuaField("onAction"); }; @@ -364,14 +363,14 @@ void UILineEdit::onKeyPress(UIKeyEvent& event) setCursorPos(0); else if(event.keyCode() == KC_END) // move cursor to last character setCursorPos(m_text.length()); - else if(event.keyCode() == KC_RETURN) { + else if(event.keyCode() == KC_TAB) { + if(UIWidgetPtr parent = getParent()) + parent->focusNextChild(TabFocusReason); + } else if(event.keyCode() == KC_RETURN) { if(m_onAction) m_onAction(); } else if(event.keyChar() != 0) { - if(event.keyCode() != KC_TAB && event.keyCode() != KC_RETURN) - appendCharacter(event.keyChar()); - else - event.ignore(); + appendCharacter(event.keyChar()); } else event.ignore(); diff --git a/src/framework/ui/uiwidget.cpp b/src/framework/ui/uiwidget.cpp index c9c4cd15..432653d0 100644 --- a/src/framework/ui/uiwidget.cpp +++ b/src/framework/ui/uiwidget.cpp @@ -16,7 +16,7 @@ UIWidget::UIWidget(UIWidgetType type) m_visible = true; m_enabled = true; m_hovered = false; - m_focusable = false; + m_focusable = true; m_destroyed = false; m_updateScheduled = false; m_opacity = 255; @@ -193,7 +193,7 @@ void UIWidget::render() m_image->draw(getGeometry()); for(const UIWidgetPtr& child : m_children) { - if(child->isVisible()) { + if(child->isExplicitlyVisible()) { int oldOpacity = g_graphics.getOpacity(); if(child->getOpacity() < oldOpacity) g_graphics.setOpacity(child->getOpacity()); @@ -290,8 +290,10 @@ bool UIWidget::hasFocus() { assert(!m_destroyed); - if(UIWidgetPtr parent = m_parent.lock()) - return (parent->getFocusedChild() == shared_from_this()); + if(UIWidgetPtr parent = getParent()) { + if(parent->hasFocus() && parent->getFocusedChild() == shared_from_this()) + return true; + } // root widget always has focus else if(asUIWidget() == g_ui.getRootWidget()) return true; @@ -381,7 +383,7 @@ UIWidgetPtr UIWidget::getChildByPos(const Point& childPos) for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) { const UIWidgetPtr& widget = (*it); - if(widget->isVisible() && widget->getGeometry().contains(childPos)) + if(widget->isExplicitlyVisible() && widget->getGeometry().contains(childPos)) return widget; } @@ -480,25 +482,13 @@ void UIWidget::focusChild(const UIWidgetPtr& focusedChild, FocusReason reason) m_focusedChild = focusedChild; if(oldFocused) { - g_dispatcher.addEvent([oldFocused,reason]() { - // the widget can be destroyed before the event happens - UIFocusEvent e(reason, false); - if(!oldFocused->isDestroyed()) - oldFocused->onFocusChange(e); - }); + UIFocusEvent e(reason, false); + oldFocused->onFocusChange(e); } if(focusedChild) { - g_dispatcher.addEvent([focusedChild,reason]() { - // the widget can be destroyed before the event happens - UIFocusEvent e(reason, true); - if(!focusedChild->isDestroyed()) - focusedChild->onFocusChange(e); - }); + UIFocusEvent e(reason, focusedChild->hasFocus()); + focusedChild->onFocusChange(e); } - - // when containers are focused they go to the top - if(focusedChild && focusedChild->hasChildren()) - moveChildToTop(focusedChild); } } @@ -516,8 +506,8 @@ void UIWidget::addChild(const UIWidgetPtr& childToAdd) // updates geometry updateGeometry(); - // focus it if there is no focused child yet - if(!m_focusedChild && childToAdd->isFocusable()) + // always focus new children + if(childToAdd->isFocusable()) focusChild(childToAdd, ActiveFocusReason); } @@ -541,10 +531,6 @@ void UIWidget::insertChild(const UIWidgetPtr& childToInsert, int index) // updates geometry updateGeometry(); - - // focus it if there is no focused child yet - if(!m_focusedChild && childToInsert->isFocusable()) - focusChild(childToInsert, ActiveFocusReason); } void UIWidget::removeChild(const UIWidgetPtr& childToRemove) @@ -619,8 +605,9 @@ void UIWidget::lockChild(const UIWidgetPtr& childToLock) m_lockedWidgets.push_front(childToLock); - // move locked child to top - moveChildToTop(childToLock); + // lock child focus + if(childToLock->isFocusable()) + focusChild(childToLock, ActiveFocusReason); } void UIWidget::unlockChild(const UIWidgetPtr& childToUnlock) @@ -674,32 +661,26 @@ void UIWidget::fill(const std::string& targetId) addAnchor(AnchorBottom, targetId, AnchorBottom); } +void UIWidget::onFocusChange(UIFocusEvent& event) +{ + if(m_focusedChild) + m_focusedChild->onFocusChange(event); +} + void UIWidget::onKeyPress(UIKeyEvent& event) { assert(!m_destroyed); event.ignore(); - // focus next child when pressing tab - if(isFocusable() && hasFocus() && !hasChildren() && event.keyCode() == KC_TAB) { - if(UIWidgetPtr parent = getParent()) { - g_dispatcher.addEvent([parent]{ - if(!parent->isDestroyed()) - parent->focusNextChild(TabFocusReason); - }); - } - event.accept(); - return; - } - // do a backup of children list, because it may change while looping it UIWidgetList children = m_children; for(const UIWidgetPtr& child : children) { - if(!child->isExplicitlyEnabled() || !child->isVisible()) + if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) continue; // key events go only to containers or focused child - if(child->hasChildren() || child->hasFocus()) { + if(child->hasChildren() || (child->isFocusable() && child->hasFocus())) { event.accept(); child->onKeyPress(event); } @@ -718,11 +699,11 @@ void UIWidget::onKeyRelease(UIKeyEvent& event) // do a backup of children list, because it may change while looping it UIWidgetList children = m_children; for(const UIWidgetPtr& child : children) { - if(!child->isExplicitlyEnabled() || !child->isVisible()) + if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) continue; // key events go only to containers or focused child - if(child->hasChildren() || child->hasFocus()) { + if(child->hasChildren() || (child->isFocusable() && child->hasFocus())) { event.accept(); child->onKeyRelease(event); } @@ -741,7 +722,7 @@ void UIWidget::onMousePress(UIMouseEvent& event) // do a backup of children list, because it may change while looping it UIWidgetList children = m_children; for(const UIWidgetPtr& child : children) { - if(!child->isExplicitlyEnabled() || !child->isVisible()) + if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) continue; // mouse press events only go to children that contains the mouse position @@ -768,7 +749,7 @@ void UIWidget::onMouseRelease(UIMouseEvent& event) // do a backup of children list, because it may change while looping it UIWidgetList children = m_children; for(const UIWidgetPtr& child : children) { - if(!child->isExplicitlyEnabled() || !child->isVisible()) + if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) continue; // mouse release events go to all children @@ -789,7 +770,7 @@ void UIWidget::onMouseMove(UIMouseEvent& event) // do a backup of children list, because it may change while looping it UIWidgetList children = m_children; for(const UIWidgetPtr& child : children) { - if(!child->isExplicitlyEnabled() || !child->isVisible()) + if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) continue; // check if the mouse is relally over this child @@ -821,7 +802,7 @@ void UIWidget::onMouseWheel(UIMouseEvent& event) // do a backup of children list, because it may change while looping it UIWidgetList children = m_children; for(const UIWidgetPtr& child : children) { - if(!child->isExplicitlyEnabled() || !child->isVisible()) + if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible()) continue; // mouse wheel events only go to children that contains the mouse position diff --git a/src/framework/ui/uiwidget.h b/src/framework/ui/uiwidget.h index bce697a9..e6548d53 100644 --- a/src/framework/ui/uiwidget.h +++ b/src/framework/ui/uiwidget.h @@ -39,7 +39,6 @@ public: void setParent(const UIWidgetPtr& parent); void setStyle(const std::string& styleName); void setGeometry(const Rect& rect); - void setLocked(bool locked); void setX(int x) { move(Point(x, getY())); } void setY(int y) { move(Point(getX(), y)); } void setWidth(int width) { resize(Size(width, getHeight())); } @@ -64,7 +63,7 @@ public: bool isEnabled(); bool isExplicitlyEnabled() const { return m_enabled; } - bool isVisible() const { return m_visible; } + bool isExplicitlyVisible() const { return m_visible; } bool isHovered() const { return m_hovered; } bool isFocusable() const { return m_focusable; } bool isDestroyed() const { return m_destroyed; } @@ -128,7 +127,7 @@ protected: // Triggered when widget change visibility/enabled/style/children/parent/layout/... //virtual void onChange(const UIEvent& event); /// Triggered when widget gets or loses focus - virtual void onFocusChange(UIFocusEvent& event) { } + virtual void onFocusChange(UIFocusEvent& event); /// Triggered when the mouse enters or leaves widget area virtual void onHoverChange(UIHoverEvent& event) { } /// Triggered when user presses key while widget has focus diff --git a/src/framework/ui/uiwindow.cpp b/src/framework/ui/uiwindow.cpp index 3b18cd3c..dfc19379 100644 --- a/src/framework/ui/uiwindow.cpp +++ b/src/framework/ui/uiwindow.cpp @@ -6,7 +6,6 @@ UIWindow::UIWindow(): UIWidget(UITypeWindow) { m_moving = false; - setFocusable(true); } UIWindowPtr UIWindow::create() @@ -89,6 +88,13 @@ void UIWindow::onGeometryUpdate(UIGeometryUpdateEvent& event) setGeometry(boundRect); } +void UIWindow::onFocusChange(UIFocusEvent& event) +{ + // when a window is focused it goes to the top + if(UIWidgetPtr parent = getParent()) + parent->moveChildToTop(asUIWidget()); +} + void UIWindow::onMousePress(UIMouseEvent& event) { Rect headRect = getGeometry(); diff --git a/src/framework/ui/uiwindow.h b/src/framework/ui/uiwindow.h index 1ecba62f..b7c06a73 100644 --- a/src/framework/ui/uiwindow.h +++ b/src/framework/ui/uiwindow.h @@ -18,6 +18,7 @@ public: protected: virtual void onGeometryUpdate(UIGeometryUpdateEvent& event); + virtual void onFocusChange(UIFocusEvent& event); virtual void onMousePress(UIMouseEvent& event); virtual void onMouseRelease(UIMouseEvent& event); virtual void onMouseMove(UIMouseEvent& event); diff --git a/src/otclient/core/tile.cpp b/src/otclient/core/tile.cpp index 625bc060..784ddbba 100644 --- a/src/otclient/core/tile.cpp +++ b/src/otclient/core/tile.cpp @@ -34,7 +34,7 @@ void Tile::draw(int x, int y, int step) if(thingAttributes.alwaysOnTopOrder == 1) { thing->draw(x - m_drawNextOffset, y - m_drawNextOffset); - //font->renderText("T1", Rect(x + 5, y+5, 100, 100)); + font->renderText("T1", Rect(x + 5, y+5, 100, 100)); m_drawNextOffset += thingAttributes.drawNextOffset; } @@ -45,7 +45,7 @@ void Tile::draw(int x, int y, int step) if(thingAttributes.alwaysOnTopOrder == 2) { thing->draw(x - m_drawNextOffset, y - m_drawNextOffset); - //font->renderText("T2", Rect(x + 5, y+5, 100, 100)); + font->renderText("T2", Rect(x + 5, y+5, 100, 100)); m_drawNextOffset += thingAttributes.drawNextOffset; } } @@ -53,7 +53,7 @@ void Tile::draw(int x, int y, int step) for(const ThingPtr& thing : m_itemsBottom) { const ThingAttributes& thingAttributes = thing->getAttributes(); thing->draw(x - m_drawNextOffset, y - m_drawNextOffset); - //font->renderText("B0", Rect(x + 5, y+5, 100, 100)); + font->renderText("B0", Rect(x + 5, y+5, 100, 100)); m_drawNextOffset += thingAttributes.drawNextOffset; } @@ -69,7 +69,7 @@ void Tile::draw(int x, int y, int step) if(thingAttributes.alwaysOnTopOrder == 3) { thing->draw(x - m_drawNextOffset, y - m_drawNextOffset); - //font->renderText("T3", Rect(x + 5, y+5, 100, 100)); + font->renderText("T3", Rect(x + 5, y+5, 100, 100)); m_drawNextOffset += thingAttributes.drawNextOffset; } } diff --git a/src/otclient/otclient.cpp b/src/otclient/otclient.cpp index 7f5c5d19..66e996d0 100644 --- a/src/otclient/otclient.cpp +++ b/src/otclient/otclient.cpp @@ -295,11 +295,11 @@ void OTClient::onPlatformEvent(const PlatformEvent& event) else if(event.keycode == KC_APOSTROPHE) { // TODO: move these events to lua UIWidgetPtr console = g_ui.getRootWidget()->getChildById("consolePanel"); - if(!console->isVisible()) { - g_ui.getRootWidget()->lockChild(console); + if(!console->isExplicitlyVisible()) { + g_ui.getRootWidget()->focusChild(console, ActiveFocusReason); + g_ui.getRootWidget()->moveChildToTop(console); console->setVisible(true); } else { - g_ui.getRootWidget()->unlockChild(console); console->setVisible(false); } fireUi = false;