Skip to content

Commit

Permalink
Widgets|libappfw: Basic focus switching with Tab/Shift-Tab; button ac…
Browse files Browse the repository at this point in the history
…tivation

IssueID #2131
  • Loading branch information
skyjake committed Jul 23, 2016
1 parent 3d5b767 commit 3b8dc24
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 22 deletions.
46 changes: 42 additions & 4 deletions doomsday/sdk/libappfw/src/guiwidget.cpp
Expand Up @@ -351,9 +351,33 @@ DENG2_PIMPL(GuiWidget)
}
}

static float toDevicePixels(float logicalPixels)
GuiWidget *findNextWidgetToFocus(WalkDirection dir)
{
return logicalPixels * DENG2_BASE_GUI_APP->dpiFactor();
Rectanglei const viewRect = self.root().viewRule().recti();
auto *widget = self.walkInOrder(dir, [this, &viewRect] (Widget &widget)
{
if (widget.behavior().testFlag(Focusable) && widget.isEnabled() &&
widget.isVisible() && widget.is<GuiWidget>())
{
// The widget's center must be in view.
if (viewRect.contains(widget.as<GuiWidget>().rule().recti().middle()))
{
// This is good.
return LoopAbort;
}
}
return LoopContinue;
});
if (widget)
{
return widget->asPtr<GuiWidget>();
}
return nullptr;
}

static float toDevicePixels(double logicalPixels)
{
return float(logicalPixels * DENG2_BASE_GUI_APP->dpiFactor());
}
};

Expand Down Expand Up @@ -729,6 +753,20 @@ bool GuiWidget::handleEvent(Event const &event)
}
}

if (hasFocus() && event.isKey())
{
KeyEvent const &key = event.as<KeyEvent>();
if (key.isKeyDown() && key.ddKey() == DDKEY_TAB)
{
if (auto *focus = d->findNextWidgetToFocus(
key.modifiers().testFlag(KeyEvent::Shift)? Backward : Forward))
{
root().setFocus(focus);
return true;
}
}
}

if (Widget::handleEvent(event))
{
return true;
Expand All @@ -737,8 +775,8 @@ bool GuiWidget::handleEvent(Event const &event)
if (d->attribs.testFlag(EatAllMouseEvents))
{
if ((event.type() == Event::MouseButton ||
event.type() == Event::MousePosition ||
event.type() == Event::MouseWheel) && hitTest(event))
event.type() == Event::MousePosition ||
event.type() == Event::MouseWheel) && hitTest(event))
{
return true;
}
Expand Down
17 changes: 17 additions & 0 deletions doomsday/sdk/libappfw/src/widgets/buttonwidget.cpp
Expand Up @@ -311,6 +311,23 @@ bool ButtonWidget::handleEvent(Event const &event)
{
if (isDisabled()) return false;

if (event.isKey() && hasFocus())
{
KeyEvent const &key = event.as<KeyEvent>();
if (key.ddKey() == DDKEY_RETURN ||
key.ddKey() == DDKEY_ENTER ||
key.ddKey() == ' ')
{
if (key.isKeyDown())
{
d->setState(Down);
trigger();
d->setState(Up);
}
return true;
}
}

if (event.isMouse())
{
MouseEvent const &mouse = event.as<MouseEvent>();
Expand Down
37 changes: 22 additions & 15 deletions doomsday/sdk/libappfw/src/widgets/dialogwidget.cpp
Expand Up @@ -391,6 +391,15 @@ DENG_GUI_PIMPL(DialogWidget)
return 0;
}

ButtonWidget *findDefaultButton() const
{
if (ui::ActionItem const *defaultAction = findDefaultAction())
{
return &buttonWidget(*defaultAction);
}
return nullptr;
}

ButtonWidget &buttonWidget(ui::Item const &item) const
{
GuiWidget *w = extraButtons->organizer().itemWidget(item);
Expand Down Expand Up @@ -587,23 +596,21 @@ void DialogWidget::update()

bool DialogWidget::handleEvent(Event const &event)
{
if (!isOpen()) return false;

if (event.isKeyDown())
{
KeyEvent const &key = event.as<KeyEvent>();

if (key.ddKey() == DDKEY_ENTER ||
key.ddKey() == DDKEY_RETURN ||
key.ddKey() == ' ')
if (key.ddKey() == DDKEY_ENTER ||
key.ddKey() == DDKEY_RETURN ||
key.ddKey() == ' ')
{
if (ui::ActionItem const *defaultAction = d->findDefaultAction())
if (ButtonWidget *but = d->findDefaultButton())
{
ButtonWidget const &but = d->buttonWidget(*defaultAction);
if (but.action())
{
const_cast<de::Action *>(but.action())->trigger();
}
but->trigger();
return true;
}
return true;
}

if (key.ddKey() == DDKEY_ESCAPE)
Expand All @@ -618,9 +625,9 @@ bool DialogWidget::handleEvent(Event const &event)
{
// The event should already have been handled by the children.
if ((event.isKeyDown() && !event.as<KeyEvent>().isModifier()) ||
(event.type() == Event::MouseButton &&
event.as<MouseEvent>().state() == MouseEvent::Pressed &&
!hitTest(event)))
(event.type() == Event::MouseButton &&
event.as<MouseEvent>().state() == MouseEvent::Pressed &&
!hitTest(event)))
{
d->startBorderFlash();
}
Expand All @@ -629,7 +636,7 @@ bool DialogWidget::handleEvent(Event const &event)
else
{
if ((event.type() == Event::MouseButton || event.type() == Event::MousePosition ||
event.type() == Event::MouseWheel) &&
event.type() == Event::MouseWheel) &&
hitTest(event))
{
// Non-modal dialogs eat mouse clicks/position inside the dialog.
Expand Down Expand Up @@ -675,7 +682,7 @@ void DialogWidget::prepare()
// Mouse needs to be untrapped for the user to be access the dialog.
d->untrapper.reset(new Untrapper(root().window()));

root().setFocus(0);
root().setFocus(d->findDefaultButton());

if (openingDirection() == ui::NoDirection)
{
Expand Down
11 changes: 8 additions & 3 deletions doomsday/sdk/libappfw/src/widgets/popupwidget.cpp
Expand Up @@ -375,10 +375,15 @@ bool PopupWidget::handleEvent(Event const &event)
}

if (event.type() == Event::KeyPress ||
event.type() == Event::KeyRepeat ||
event.type() == Event::KeyRelease)
event.type() == Event::KeyRepeat ||
event.type() == Event::KeyRelease)
{
if (event.isKeyDown() && event.as<KeyEvent>().ddKey() == DDKEY_ESCAPE)
KeyEvent const &key = event.as<KeyEvent>();
if (event.isKeyDown() &&
(key.ddKey() == DDKEY_ESCAPE ||
key.ddKey() == DDKEY_ENTER ||
key.ddKey() == DDKEY_RETURN ||
key.ddKey() == ' '))
{
close();
return true;
Expand Down

0 comments on commit 3b8dc24

Please sign in to comment.