Rework auto focus behavior, closes #222
This commit is contained in:
parent
7e01306fc6
commit
4f8f02acad
|
@ -1,8 +1,10 @@
|
|||
Panel < UIWidget
|
||||
phantom: true
|
||||
auto-focus: first
|
||||
|
||||
ScrollablePanel < UIScrollArea
|
||||
phantom: true
|
||||
auto-focus: first
|
||||
|
||||
FlatPanel < Panel
|
||||
image-source: /images/ui/panel_flat
|
||||
|
|
|
@ -13,21 +13,21 @@ CharacterWidget < UIWidget
|
|||
|
||||
Label
|
||||
id: name
|
||||
color: #ffffff
|
||||
color: #aaaaaa
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
font: verdana-11px-monochrome
|
||||
text-auto-resize: true
|
||||
background-color: alpha
|
||||
text-offset: 2 0
|
||||
on: true
|
||||
|
||||
$!on:
|
||||
color: #aaaaaa
|
||||
$on:
|
||||
color: #ffffff
|
||||
|
||||
Label
|
||||
id: worldName
|
||||
color: #ffffff
|
||||
color: #aaaaaa
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
margin-right: 5
|
||||
|
@ -35,10 +35,9 @@ CharacterWidget < UIWidget
|
|||
text-auto-resize: true
|
||||
background-color: alpha
|
||||
&baseText: '(%s)'
|
||||
on: true
|
||||
|
||||
$!on:
|
||||
color: #aaaaaa
|
||||
$on:
|
||||
color: #ffffff
|
||||
|
||||
MainWindow
|
||||
id: charactersWindow
|
||||
|
|
|
@ -97,7 +97,6 @@ function EnterGame.init()
|
|||
enterGame:getChildById('serverPortTextEdit'):setText(port)
|
||||
enterGame:getChildById('autoLoginBox'):setChecked(autologin)
|
||||
enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0)
|
||||
enterGame:getChildById('accountNameTextEdit'):focus()
|
||||
|
||||
protocolBox = enterGame:getChildById('protocolComboBox')
|
||||
protocolBox.onOptionChange = onChangeProtocol
|
||||
|
|
|
@ -19,6 +19,10 @@ KeyboardFocusReason = 1
|
|||
ActiveFocusReason = 2
|
||||
OtherFocusReason = 3
|
||||
|
||||
AutoFocusNone = 0
|
||||
AutoFocusFirst = 1
|
||||
AutoFocusLast = 2
|
||||
|
||||
KeyboardNoModifier = 0
|
||||
KeyboardCtrlModifier = 1
|
||||
KeyboardAltModifier = 2
|
||||
|
|
|
@ -5,6 +5,7 @@ function UIWindow.create()
|
|||
local window = UIWindow.internalCreate()
|
||||
window:setTextAlign(AlignTopCenter)
|
||||
window:setDraggable(true)
|
||||
window:setAutoFocusPolicy(AutoFocusFirst)
|
||||
return window
|
||||
end
|
||||
|
||||
|
|
|
@ -226,6 +226,12 @@ namespace Fw
|
|||
OtherFocusReason
|
||||
};
|
||||
|
||||
enum AutoFocusPolicy {
|
||||
AutoFocusNone = 0,
|
||||
AutoFocusFirst,
|
||||
AutoFocusLast
|
||||
};
|
||||
|
||||
enum InputEventType {
|
||||
NoInputEvent = 0,
|
||||
KeyTextInputEvent,
|
||||
|
|
|
@ -377,6 +377,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<UIWidget>("setFixedSize", &UIWidget::setFixedSize);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setClipping", &UIWidget::setClipping);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setLastFocusReason", &UIWidget::setLastFocusReason);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setAutoFocusPolicy", &UIWidget::setAutoFocusPolicy);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setAutoRepeatDelay", &UIWidget::setAutoRepeatDelay);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setVirtualOffset", &UIWidget::setVirtualOffset);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("isVisible", &UIWidget::isVisible);
|
||||
|
@ -442,6 +443,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<UIWidget>("getStyle", &UIWidget::getStyle);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getChildCount", &UIWidget::getChildCount);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getLastFocusReason", &UIWidget::getLastFocusReason);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getAutoFocusPolicy", &UIWidget::getAutoFocusPolicy);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getAutoRepeatDelay", &UIWidget::getAutoRepeatDelay);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getVirtualOffset", &UIWidget::getVirtualOffset);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getStyleName", &UIWidget::getStyleName);
|
||||
|
|
|
@ -689,7 +689,7 @@ bool UITextEdit::onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeat
|
|||
} else if(keyCode == Fw::KeyTab && !m_shiftNavigation) {
|
||||
clearSelection();
|
||||
if(UIWidgetPtr parent = getParent())
|
||||
parent->focusNextChild(Fw::KeyboardFocusReason);
|
||||
parent->focusNextChild(Fw::KeyboardFocusReason, true);
|
||||
return true;
|
||||
} else if(keyCode == Fw::KeyEnter && m_multiline && m_editable) {
|
||||
appendCharacter('\n');
|
||||
|
@ -724,7 +724,7 @@ bool UITextEdit::onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeat
|
|||
} else if(keyboardModifiers == Fw::KeyboardShiftModifier) {
|
||||
if(keyCode == Fw::KeyTab && !m_shiftNavigation) {
|
||||
if(UIWidgetPtr parent = getParent())
|
||||
parent->focusPreviousChild(Fw::KeyboardFocusReason);
|
||||
parent->focusPreviousChild(Fw::KeyboardFocusReason, true);
|
||||
return true;
|
||||
} else if(keyCode == Fw::KeyRight || keyCode == Fw::KeyLeft) {
|
||||
|
||||
|
|
|
@ -98,6 +98,16 @@ Fw::WidgetState Fw::translateState(std::string state)
|
|||
return Fw::DraggingState;
|
||||
else if(state == "hidden")
|
||||
return Fw::HiddenState;
|
||||
else
|
||||
return Fw::InvalidState;
|
||||
}
|
||||
|
||||
Fw::AutoFocusPolicy Fw::translateAutoFocusPolicy(std::string policy)
|
||||
{
|
||||
boost::to_lower(policy);
|
||||
boost::trim(policy);
|
||||
if(policy == "first")
|
||||
return Fw::AutoFocusFirst;
|
||||
else if(policy == "last")
|
||||
return Fw::AutoFocusLast;
|
||||
return Fw::AutoFocusNone;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace Fw {
|
|||
AlignmentFlag translateAlignment(std::string aligment);
|
||||
AnchorEdge translateAnchorEdge(std::string anchorEdge);
|
||||
WidgetState translateState(std::string state);
|
||||
AutoFocusPolicy translateAutoFocusPolicy(std::string policy);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ UIWidget::UIWidget()
|
|||
{
|
||||
m_lastFocusReason = Fw::ActiveFocusReason;
|
||||
m_states = Fw::DefaultState;
|
||||
m_autoFocusPolicy = Fw::AutoFocusLast;
|
||||
m_clickTimer.stop();
|
||||
m_autoRepeatDelay = 500;
|
||||
|
||||
|
@ -239,8 +240,8 @@ void UIWidget::removeChild(UIWidgetPtr child)
|
|||
child->updateStates();
|
||||
updateChildrenIndexStates();
|
||||
|
||||
if(focusAnother && !m_focusedChild)
|
||||
focusPreviousChild(Fw::ActiveFocusReason);
|
||||
if(m_autoFocusPolicy != Fw::AutoFocusNone && focusAnother && !m_focusedChild)
|
||||
focusPreviousChild(Fw::ActiveFocusReason, true);
|
||||
|
||||
g_ui.onWidgetDisappear(child);
|
||||
} else
|
||||
|
@ -283,12 +284,14 @@ void UIWidget::focusChild(const UIWidgetPtr& child, Fw::FocusReason reason)
|
|||
onChildFocusChange(child, oldFocused, reason);
|
||||
}
|
||||
|
||||
void UIWidget::focusNextChild(Fw::FocusReason reason)
|
||||
void UIWidget::focusNextChild(Fw::FocusReason reason, bool rotate)
|
||||
{
|
||||
if(m_destroyed)
|
||||
return;
|
||||
|
||||
UIWidgetPtr toFocus;
|
||||
|
||||
if(rotate) {
|
||||
UIWidgetList rotatedChildren(m_children);
|
||||
|
||||
if(m_focusedChild) {
|
||||
|
@ -306,17 +309,31 @@ void UIWidget::focusNextChild(Fw::FocusReason reason)
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto it = m_children.begin();
|
||||
if(m_focusedChild)
|
||||
it = std::find(m_children.begin(), m_children.end(), m_focusedChild);
|
||||
|
||||
if(toFocus)
|
||||
for(; it != m_children.end(); ++it) {
|
||||
const UIWidgetPtr& child = *it;
|
||||
if(child != m_focusedChild && child->isFocusable() && child->isExplicitlyEnabled() && child->isVisible()) {
|
||||
toFocus = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(toFocus && toFocus != m_focusedChild)
|
||||
focusChild(toFocus, reason);
|
||||
}
|
||||
|
||||
void UIWidget::focusPreviousChild(Fw::FocusReason reason)
|
||||
void UIWidget::focusPreviousChild(Fw::FocusReason reason, bool rotate)
|
||||
{
|
||||
if(m_destroyed)
|
||||
return;
|
||||
|
||||
UIWidgetPtr toFocus;
|
||||
if(rotate) {
|
||||
UIWidgetList rotatedChildren(m_children);
|
||||
std::reverse(rotatedChildren.begin(), rotatedChildren.end());
|
||||
|
||||
|
@ -335,8 +352,21 @@ void UIWidget::focusPreviousChild(Fw::FocusReason reason)
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto it = m_children.rbegin();
|
||||
if(m_focusedChild)
|
||||
it = std::find(m_children.rbegin(), m_children.rend(), m_focusedChild);
|
||||
|
||||
if(toFocus)
|
||||
for(; it != m_children.rend(); ++it) {
|
||||
const UIWidgetPtr& child = *it;
|
||||
if(child != m_focusedChild && child->isFocusable() && child->isExplicitlyEnabled() && child->isVisible()) {
|
||||
toFocus = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(toFocus && toFocus != m_focusedChild)
|
||||
focusChild(toFocus, reason);
|
||||
}
|
||||
|
||||
|
@ -520,10 +550,14 @@ void UIWidget::applyStyle(const OTMLNodePtr& styleNode)
|
|||
callLuaField("onStyleApply", styleNode->tag(), styleNode);
|
||||
|
||||
if(m_firstOnStyle) {
|
||||
// always focus new child
|
||||
if(isFocusable() && isExplicitlyVisible() && isExplicitlyEnabled())
|
||||
UIWidgetPtr parent = getParent();
|
||||
if(isFocusable() && isExplicitlyVisible() && isExplicitlyEnabled() &&
|
||||
parent && ((!parent->getFocusedChild() && parent->getAutoFocusPolicy() == Fw::AutoFocusFirst) ||
|
||||
parent->getAutoFocusPolicy() == Fw::AutoFocusLast)) {
|
||||
focus();
|
||||
}
|
||||
}
|
||||
|
||||
m_firstOnStyle = false;
|
||||
} catch(stdext::exception& e) {
|
||||
g_logger.traceError(stdext::format("failed to apply style to widget '%s': %s", m_id, e.what()));
|
||||
|
@ -906,7 +940,7 @@ void UIWidget::setVisible(bool visible)
|
|||
// hiding a widget make it lose focus
|
||||
if(!visible && isFocused()) {
|
||||
if(UIWidgetPtr parent = getParent())
|
||||
parent->focusPreviousChild(Fw::ActiveFocusReason);
|
||||
parent->focusPreviousChild(Fw::ActiveFocusReason, true);
|
||||
}
|
||||
|
||||
// visibility can change change parent layout
|
||||
|
@ -940,9 +974,12 @@ void UIWidget::setFocusable(bool focusable)
|
|||
m_focusable = focusable;
|
||||
|
||||
// make parent focus another child
|
||||
if(UIWidgetPtr parent = getParent()) {
|
||||
if(!focusable && isFocused()) {
|
||||
if(UIWidgetPtr parent = getParent())
|
||||
parent->focusPreviousChild(Fw::ActiveFocusReason);
|
||||
parent->focusPreviousChild(Fw::ActiveFocusReason, true);
|
||||
} else if(focusable && (!parent->getFocusedChild() && parent->getAutoFocusPolicy() != Fw::AutoFocusNone)) {
|
||||
focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -968,6 +1005,11 @@ void UIWidget::setLastFocusReason(Fw::FocusReason reason)
|
|||
m_lastFocusReason = reason;
|
||||
}
|
||||
|
||||
void UIWidget::setAutoFocusPolicy(Fw::AutoFocusPolicy policy)
|
||||
{
|
||||
m_autoFocusPolicy = policy;
|
||||
}
|
||||
|
||||
void UIWidget::setVirtualOffset(const Point& offset)
|
||||
{
|
||||
m_virtualOffset = offset;
|
||||
|
|
|
@ -77,14 +77,15 @@ protected:
|
|||
OTMLNodePtr m_style;
|
||||
Timer m_clickTimer;
|
||||
Fw::FocusReason m_lastFocusReason;
|
||||
Fw::AutoFocusPolicy m_autoFocusPolicy;
|
||||
|
||||
public:
|
||||
void addChild(const UIWidgetPtr& child);
|
||||
void insertChild(int index, const UIWidgetPtr& child);
|
||||
void removeChild(UIWidgetPtr child);
|
||||
void focusChild(const UIWidgetPtr& child, Fw::FocusReason reason);
|
||||
void focusNextChild(Fw::FocusReason reason);
|
||||
void focusPreviousChild(Fw::FocusReason reason);
|
||||
void focusNextChild(Fw::FocusReason reason, bool rotate = false);
|
||||
void focusPreviousChild(Fw::FocusReason reason, bool rotate = false);
|
||||
void lowerChild(UIWidgetPtr child);
|
||||
void raiseChild(UIWidgetPtr child);
|
||||
void moveChildToIndex(const UIWidgetPtr& child, int index);
|
||||
|
@ -129,6 +130,7 @@ public:
|
|||
void setFixedSize(bool fixed);
|
||||
void setClipping(bool clipping) { m_clipping = clipping; }
|
||||
void setLastFocusReason(Fw::FocusReason reason);
|
||||
void setAutoFocusPolicy(Fw::AutoFocusPolicy policy);
|
||||
void setAutoRepeatDelay(int delay) { m_autoRepeatDelay = delay; }
|
||||
void setVirtualOffset(const Point& offset);
|
||||
|
||||
|
@ -259,6 +261,7 @@ public:
|
|||
OTMLNodePtr getStyle() { return m_style; }
|
||||
int getChildCount() { return m_children.size(); }
|
||||
Fw::FocusReason getLastFocusReason() { return m_lastFocusReason; }
|
||||
Fw::AutoFocusPolicy getAutoFocusPolicy() { return m_autoFocusPolicy; }
|
||||
int getAutoRepeatDelay() { return m_autoRepeatDelay; }
|
||||
Point getVirtualOffset() { return m_virtualOffset; }
|
||||
std::string getStyleName() { return m_style->tag(); }
|
||||
|
|
|
@ -122,6 +122,8 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode)
|
|||
setOn(node->value<bool>());
|
||||
else if(node->tag() == "focusable")
|
||||
setFocusable(node->value<bool>());
|
||||
else if(node->tag() == "auto-focus")
|
||||
setAutoFocusPolicy(Fw::translateAutoFocusPolicy(node->value()));
|
||||
else if(node->tag() == "phantom")
|
||||
setPhantom(node->value<bool>());
|
||||
else if(node->tag() == "size")
|
||||
|
|
Loading…
Reference in New Issue