fix focus bugs in UI
This commit is contained in:
parent
d0f47f47a4
commit
b410921e32
|
@ -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})
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,3 +5,9 @@ function print(...)
|
|||
end
|
||||
Logger.log(LogInfo, msg)
|
||||
end
|
||||
|
||||
function createEnvironment()
|
||||
local env = { }
|
||||
setmetatable(env, { __index = _G} )
|
||||
return env
|
||||
end
|
|
@ -14,7 +14,7 @@ void LuaInterface::registerFunctions()
|
|||
g_lua.bindClassMemberFunction<UIWidget>("setId", &UIWidget::setId);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setEnabled", &UIWidget::setEnabled);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("isVisible", &UIWidget::isVisible);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("isExplicitlyVisible", &UIWidget::isExplicitlyVisible);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setVisible", &UIWidget::setVisible);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getWidth", &UIWidget::getWidth);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setWidth", &UIWidget::setWidth);
|
||||
|
|
|
@ -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"); };
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
UILabel::UILabel() : UIWidget(UITypeLabel)
|
||||
{
|
||||
m_align = AlignLeft;
|
||||
m_focusable = false;
|
||||
}
|
||||
|
||||
UILabelPtr UILabel::create()
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue