Rework auto focus behavior, closes #222

master
Eduardo Bart 11 years ago
parent 7e01306fc6
commit 4f8f02acad

@ -1,8 +1,10 @@
Panel < UIWidget Panel < UIWidget
phantom: true phantom: true
auto-focus: first
ScrollablePanel < UIScrollArea ScrollablePanel < UIScrollArea
phantom: true phantom: true
auto-focus: first
FlatPanel < Panel FlatPanel < Panel
image-source: /images/ui/panel_flat image-source: /images/ui/panel_flat

@ -13,21 +13,21 @@ CharacterWidget < UIWidget
Label Label
id: name id: name
color: #ffffff color: #aaaaaa
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
font: verdana-11px-monochrome font: verdana-11px-monochrome
text-auto-resize: true text-auto-resize: true
background-color: alpha background-color: alpha
text-offset: 2 0 text-offset: 2 0
on: true
$!on: $on:
color: #aaaaaa color: #ffffff
Label Label
id: worldName id: worldName
color: #ffffff color: #ffffff
color: #aaaaaa
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
margin-right: 5 margin-right: 5
@ -35,10 +35,9 @@ CharacterWidget < UIWidget
text-auto-resize: true text-auto-resize: true
background-color: alpha background-color: alpha
&baseText: '(%s)' &baseText: '(%s)'
on: true
$!on: $on:
color: #aaaaaa color: #ffffff
MainWindow MainWindow
id: charactersWindow id: charactersWindow

@ -97,7 +97,6 @@ function EnterGame.init()
enterGame:getChildById('serverPortTextEdit'):setText(port) enterGame:getChildById('serverPortTextEdit'):setText(port)
enterGame:getChildById('autoLoginBox'):setChecked(autologin) enterGame:getChildById('autoLoginBox'):setChecked(autologin)
enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0) enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0)
enterGame:getChildById('accountNameTextEdit'):focus()
protocolBox = enterGame:getChildById('protocolComboBox') protocolBox = enterGame:getChildById('protocolComboBox')
protocolBox.onOptionChange = onChangeProtocol protocolBox.onOptionChange = onChangeProtocol

@ -19,6 +19,10 @@ KeyboardFocusReason = 1
ActiveFocusReason = 2 ActiveFocusReason = 2
OtherFocusReason = 3 OtherFocusReason = 3
AutoFocusNone = 0
AutoFocusFirst = 1
AutoFocusLast = 2
KeyboardNoModifier = 0 KeyboardNoModifier = 0
KeyboardCtrlModifier = 1 KeyboardCtrlModifier = 1
KeyboardAltModifier = 2 KeyboardAltModifier = 2

@ -5,6 +5,7 @@ function UIWindow.create()
local window = UIWindow.internalCreate() local window = UIWindow.internalCreate()
window:setTextAlign(AlignTopCenter) window:setTextAlign(AlignTopCenter)
window:setDraggable(true) window:setDraggable(true)
window:setAutoFocusPolicy(AutoFocusFirst)
return window return window
end end

@ -226,6 +226,12 @@ namespace Fw
OtherFocusReason OtherFocusReason
}; };
enum AutoFocusPolicy {
AutoFocusNone = 0,
AutoFocusFirst,
AutoFocusLast
};
enum InputEventType { enum InputEventType {
NoInputEvent = 0, NoInputEvent = 0,
KeyTextInputEvent, KeyTextInputEvent,

@ -377,6 +377,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIWidget>("setFixedSize", &UIWidget::setFixedSize); g_lua.bindClassMemberFunction<UIWidget>("setFixedSize", &UIWidget::setFixedSize);
g_lua.bindClassMemberFunction<UIWidget>("setClipping", &UIWidget::setClipping); g_lua.bindClassMemberFunction<UIWidget>("setClipping", &UIWidget::setClipping);
g_lua.bindClassMemberFunction<UIWidget>("setLastFocusReason", &UIWidget::setLastFocusReason); 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>("setAutoRepeatDelay", &UIWidget::setAutoRepeatDelay);
g_lua.bindClassMemberFunction<UIWidget>("setVirtualOffset", &UIWidget::setVirtualOffset); g_lua.bindClassMemberFunction<UIWidget>("setVirtualOffset", &UIWidget::setVirtualOffset);
g_lua.bindClassMemberFunction<UIWidget>("isVisible", &UIWidget::isVisible); 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>("getStyle", &UIWidget::getStyle);
g_lua.bindClassMemberFunction<UIWidget>("getChildCount", &UIWidget::getChildCount); g_lua.bindClassMemberFunction<UIWidget>("getChildCount", &UIWidget::getChildCount);
g_lua.bindClassMemberFunction<UIWidget>("getLastFocusReason", &UIWidget::getLastFocusReason); 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>("getAutoRepeatDelay", &UIWidget::getAutoRepeatDelay);
g_lua.bindClassMemberFunction<UIWidget>("getVirtualOffset", &UIWidget::getVirtualOffset); g_lua.bindClassMemberFunction<UIWidget>("getVirtualOffset", &UIWidget::getVirtualOffset);
g_lua.bindClassMemberFunction<UIWidget>("getStyleName", &UIWidget::getStyleName); 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) { } else if(keyCode == Fw::KeyTab && !m_shiftNavigation) {
clearSelection(); clearSelection();
if(UIWidgetPtr parent = getParent()) if(UIWidgetPtr parent = getParent())
parent->focusNextChild(Fw::KeyboardFocusReason); parent->focusNextChild(Fw::KeyboardFocusReason, true);
return true; return true;
} else if(keyCode == Fw::KeyEnter && m_multiline && m_editable) { } else if(keyCode == Fw::KeyEnter && m_multiline && m_editable) {
appendCharacter('\n'); appendCharacter('\n');
@ -724,7 +724,7 @@ bool UITextEdit::onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeat
} else if(keyboardModifiers == Fw::KeyboardShiftModifier) { } else if(keyboardModifiers == Fw::KeyboardShiftModifier) {
if(keyCode == Fw::KeyTab && !m_shiftNavigation) { if(keyCode == Fw::KeyTab && !m_shiftNavigation) {
if(UIWidgetPtr parent = getParent()) if(UIWidgetPtr parent = getParent())
parent->focusPreviousChild(Fw::KeyboardFocusReason); parent->focusPreviousChild(Fw::KeyboardFocusReason, true);
return true; return true;
} else if(keyCode == Fw::KeyRight || keyCode == Fw::KeyLeft) { } else if(keyCode == Fw::KeyRight || keyCode == Fw::KeyLeft) {

@ -98,6 +98,16 @@ Fw::WidgetState Fw::translateState(std::string state)
return Fw::DraggingState; return Fw::DraggingState;
else if(state == "hidden") else if(state == "hidden")
return Fw::HiddenState; return Fw::HiddenState;
else return Fw::InvalidState;
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); AlignmentFlag translateAlignment(std::string aligment);
AnchorEdge translateAnchorEdge(std::string anchorEdge); AnchorEdge translateAnchorEdge(std::string anchorEdge);
WidgetState translateState(std::string state); WidgetState translateState(std::string state);
AutoFocusPolicy translateAutoFocusPolicy(std::string policy);
}; };

@ -36,6 +36,7 @@ UIWidget::UIWidget()
{ {
m_lastFocusReason = Fw::ActiveFocusReason; m_lastFocusReason = Fw::ActiveFocusReason;
m_states = Fw::DefaultState; m_states = Fw::DefaultState;
m_autoFocusPolicy = Fw::AutoFocusLast;
m_clickTimer.stop(); m_clickTimer.stop();
m_autoRepeatDelay = 500; m_autoRepeatDelay = 500;
@ -239,8 +240,8 @@ void UIWidget::removeChild(UIWidgetPtr child)
child->updateStates(); child->updateStates();
updateChildrenIndexStates(); updateChildrenIndexStates();
if(focusAnother && !m_focusedChild) if(m_autoFocusPolicy != Fw::AutoFocusNone && focusAnother && !m_focusedChild)
focusPreviousChild(Fw::ActiveFocusReason); focusPreviousChild(Fw::ActiveFocusReason, true);
g_ui.onWidgetDisappear(child); g_ui.onWidgetDisappear(child);
} else } else
@ -283,60 +284,89 @@ void UIWidget::focusChild(const UIWidgetPtr& child, Fw::FocusReason reason)
onChildFocusChange(child, oldFocused, reason); onChildFocusChange(child, oldFocused, reason);
} }
void UIWidget::focusNextChild(Fw::FocusReason reason) void UIWidget::focusNextChild(Fw::FocusReason reason, bool rotate)
{ {
if(m_destroyed) if(m_destroyed)
return; return;
UIWidgetPtr toFocus; UIWidgetPtr toFocus;
UIWidgetList rotatedChildren(m_children);
if(m_focusedChild) { if(rotate) {
auto focusedIt = std::find(rotatedChildren.begin(), rotatedChildren.end(), m_focusedChild); UIWidgetList rotatedChildren(m_children);
if(focusedIt != rotatedChildren.end()) {
std::rotate(rotatedChildren.begin(), focusedIt, rotatedChildren.end()); if(m_focusedChild) {
rotatedChildren.pop_front(); auto focusedIt = std::find(rotatedChildren.begin(), rotatedChildren.end(), m_focusedChild);
if(focusedIt != rotatedChildren.end()) {
std::rotate(rotatedChildren.begin(), focusedIt, rotatedChildren.end());
rotatedChildren.pop_front();
}
} }
}
// finds next child to focus // finds next child to focus
for(const UIWidgetPtr& child : rotatedChildren) { for(const UIWidgetPtr& child : rotatedChildren) {
if(child->isFocusable() && child->isExplicitlyEnabled() && child->isVisible()) { if(child->isFocusable() && child->isExplicitlyEnabled() && child->isVisible()) {
toFocus = child; toFocus = child;
break; break;
}
}
} else {
auto it = m_children.begin();
if(m_focusedChild)
it = std::find(m_children.begin(), m_children.end(), m_focusedChild);
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) if(toFocus && toFocus != m_focusedChild)
focusChild(toFocus, reason); focusChild(toFocus, reason);
} }
void UIWidget::focusPreviousChild(Fw::FocusReason reason) void UIWidget::focusPreviousChild(Fw::FocusReason reason, bool rotate)
{ {
if(m_destroyed) if(m_destroyed)
return; return;
UIWidgetPtr toFocus; UIWidgetPtr toFocus;
UIWidgetList rotatedChildren(m_children); if(rotate) {
std::reverse(rotatedChildren.begin(), rotatedChildren.end()); UIWidgetList rotatedChildren(m_children);
std::reverse(rotatedChildren.begin(), rotatedChildren.end());
if(m_focusedChild) {
auto focusedIt = std::find(rotatedChildren.begin(), rotatedChildren.end(), m_focusedChild); if(m_focusedChild) {
if(focusedIt != rotatedChildren.end()) { auto focusedIt = std::find(rotatedChildren.begin(), rotatedChildren.end(), m_focusedChild);
std::rotate(rotatedChildren.begin(), focusedIt, rotatedChildren.end()); if(focusedIt != rotatedChildren.end()) {
rotatedChildren.pop_front(); std::rotate(rotatedChildren.begin(), focusedIt, rotatedChildren.end());
rotatedChildren.pop_front();
}
} }
}
// finds next child to focus // finds next child to focus
for(const UIWidgetPtr& child : rotatedChildren) { for(const UIWidgetPtr& child : rotatedChildren) {
if(child->isFocusable() && child->isExplicitlyEnabled() && child->isVisible()) { if(child->isFocusable() && child->isExplicitlyEnabled() && child->isVisible()) {
toFocus = child; toFocus = child;
break; break;
}
}
} else {
auto it = m_children.rbegin();
if(m_focusedChild)
it = std::find(m_children.rbegin(), m_children.rend(), m_focusedChild);
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) if(toFocus && toFocus != m_focusedChild)
focusChild(toFocus, reason); focusChild(toFocus, reason);
} }
@ -520,10 +550,14 @@ void UIWidget::applyStyle(const OTMLNodePtr& styleNode)
callLuaField("onStyleApply", styleNode->tag(), styleNode); callLuaField("onStyleApply", styleNode->tag(), styleNode);
if(m_firstOnStyle) { if(m_firstOnStyle) {
// always focus new child UIWidgetPtr parent = getParent();
if(isFocusable() && isExplicitlyVisible() && isExplicitlyEnabled()) if(isFocusable() && isExplicitlyVisible() && isExplicitlyEnabled() &&
parent && ((!parent->getFocusedChild() && parent->getAutoFocusPolicy() == Fw::AutoFocusFirst) ||
parent->getAutoFocusPolicy() == Fw::AutoFocusLast)) {
focus(); focus();
}
} }
m_firstOnStyle = false; m_firstOnStyle = false;
} catch(stdext::exception& e) { } catch(stdext::exception& e) {
g_logger.traceError(stdext::format("failed to apply style to widget '%s': %s", m_id, e.what())); 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 // hiding a widget make it lose focus
if(!visible && isFocused()) { if(!visible && isFocused()) {
if(UIWidgetPtr parent = getParent()) if(UIWidgetPtr parent = getParent())
parent->focusPreviousChild(Fw::ActiveFocusReason); parent->focusPreviousChild(Fw::ActiveFocusReason, true);
} }
// visibility can change change parent layout // visibility can change change parent layout
@ -940,9 +974,12 @@ void UIWidget::setFocusable(bool focusable)
m_focusable = focusable; m_focusable = focusable;
// make parent focus another child // make parent focus another child
if(!focusable && isFocused()) { if(UIWidgetPtr parent = getParent()) {
if(UIWidgetPtr parent = getParent()) if(!focusable && isFocused()) {
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; m_lastFocusReason = reason;
} }
void UIWidget::setAutoFocusPolicy(Fw::AutoFocusPolicy policy)
{
m_autoFocusPolicy = policy;
}
void UIWidget::setVirtualOffset(const Point& offset) void UIWidget::setVirtualOffset(const Point& offset)
{ {
m_virtualOffset = offset; m_virtualOffset = offset;

@ -77,14 +77,15 @@ protected:
OTMLNodePtr m_style; OTMLNodePtr m_style;
Timer m_clickTimer; Timer m_clickTimer;
Fw::FocusReason m_lastFocusReason; Fw::FocusReason m_lastFocusReason;
Fw::AutoFocusPolicy m_autoFocusPolicy;
public: public:
void addChild(const UIWidgetPtr& child); void addChild(const UIWidgetPtr& child);
void insertChild(int index, const UIWidgetPtr& child); void insertChild(int index, const UIWidgetPtr& child);
void removeChild(UIWidgetPtr child); void removeChild(UIWidgetPtr child);
void focusChild(const UIWidgetPtr& child, Fw::FocusReason reason); void focusChild(const UIWidgetPtr& child, Fw::FocusReason reason);
void focusNextChild(Fw::FocusReason reason); void focusNextChild(Fw::FocusReason reason, bool rotate = false);
void focusPreviousChild(Fw::FocusReason reason); void focusPreviousChild(Fw::FocusReason reason, bool rotate = false);
void lowerChild(UIWidgetPtr child); void lowerChild(UIWidgetPtr child);
void raiseChild(UIWidgetPtr child); void raiseChild(UIWidgetPtr child);
void moveChildToIndex(const UIWidgetPtr& child, int index); void moveChildToIndex(const UIWidgetPtr& child, int index);
@ -129,6 +130,7 @@ public:
void setFixedSize(bool fixed); void setFixedSize(bool fixed);
void setClipping(bool clipping) { m_clipping = clipping; } void setClipping(bool clipping) { m_clipping = clipping; }
void setLastFocusReason(Fw::FocusReason reason); void setLastFocusReason(Fw::FocusReason reason);
void setAutoFocusPolicy(Fw::AutoFocusPolicy policy);
void setAutoRepeatDelay(int delay) { m_autoRepeatDelay = delay; } void setAutoRepeatDelay(int delay) { m_autoRepeatDelay = delay; }
void setVirtualOffset(const Point& offset); void setVirtualOffset(const Point& offset);
@ -259,6 +261,7 @@ public:
OTMLNodePtr getStyle() { return m_style; } OTMLNodePtr getStyle() { return m_style; }
int getChildCount() { return m_children.size(); } int getChildCount() { return m_children.size(); }
Fw::FocusReason getLastFocusReason() { return m_lastFocusReason; } Fw::FocusReason getLastFocusReason() { return m_lastFocusReason; }
Fw::AutoFocusPolicy getAutoFocusPolicy() { return m_autoFocusPolicy; }
int getAutoRepeatDelay() { return m_autoRepeatDelay; } int getAutoRepeatDelay() { return m_autoRepeatDelay; }
Point getVirtualOffset() { return m_virtualOffset; } Point getVirtualOffset() { return m_virtualOffset; }
std::string getStyleName() { return m_style->tag(); } std::string getStyleName() { return m_style->tag(); }

@ -122,6 +122,8 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode)
setOn(node->value<bool>()); setOn(node->value<bool>());
else if(node->tag() == "focusable") else if(node->tag() == "focusable")
setFocusable(node->value<bool>()); setFocusable(node->value<bool>());
else if(node->tag() == "auto-focus")
setAutoFocusPolicy(Fw::translateAutoFocusPolicy(node->value()));
else if(node->tag() == "phantom") else if(node->tag() == "phantom")
setPhantom(node->value<bool>()); setPhantom(node->value<bool>());
else if(node->tag() == "size") else if(node->tag() == "size")

Loading…
Cancel
Save