Improve KeyboardNavigation to better handle modal windows

It's no longer possible to cycle to widgets that aren't part of the current modal window.

The window manager will remember the focused widget of a modal window on a limited basis (it'll be discarded when a different modal window opens).
new-script-api
scrawl 7 years ago
parent 41fe16013b
commit 1714271a76

@ -77,7 +77,6 @@ namespace MWGui
void PersuasionDialog::onOpen() void PersuasionDialog::onOpen()
{ {
WindowModal::onOpen();
center(); center();
MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::Ptr player = MWMechanics::getPlayer();
@ -88,6 +87,12 @@ namespace MWGui
mBribe1000Button->setEnabled (playerGold >= 1000); mBribe1000Button->setEnabled (playerGold >= 1000);
mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
WindowModal::onOpen();
}
MyGUI::Widget* PersuasionDialog::getDefaultKeyFocus()
{
return mAdmireButton;
} }
// -------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------

@ -32,6 +32,8 @@ namespace MWGui
virtual void onOpen(); virtual void onOpen();
virtual MyGUI::Widget* getDefaultKeyFocus();
private: private:
MyGUI::Button* mCancelButton; MyGUI::Button* mCancelButton;
MyGUI::Button* mAdmireButton; MyGUI::Button* mAdmireButton;

@ -38,6 +38,7 @@ bool shouldAcceptKeyFocus(MyGUI::Widget* w)
KeyboardNavigation::KeyboardNavigation() KeyboardNavigation::KeyboardNavigation()
: mCurrentFocus(nullptr) : mCurrentFocus(nullptr)
, mModalWindow(nullptr)
{ {
MyGUI::WidgetManager::getInstance().registerUnlinker(this); MyGUI::WidgetManager::getInstance().registerUnlinker(this);
} }
@ -51,9 +52,13 @@ void KeyboardNavigation::saveFocus(int mode)
{ {
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if (shouldAcceptKeyFocus(focus)) if (shouldAcceptKeyFocus(focus))
{
mKeyFocus[mode] = focus; mKeyFocus[mode] = focus;
}
else else
{
mKeyFocus[mode] = mCurrentFocus; mKeyFocus[mode] = mCurrentFocus;
}
} }
void KeyboardNavigation::restoreFocus(int mode) void KeyboardNavigation::restoreFocus(int mode)
@ -87,6 +92,13 @@ void styleFocusedButton(MyGUI::Widget* w)
} }
} }
bool isRootParent(MyGUI::Widget* widget, MyGUI::Widget* root)
{
while (widget && widget->getParent())
widget = widget->getParent();
return widget == root;
}
void KeyboardNavigation::onFrame() void KeyboardNavigation::onFrame()
{ {
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
@ -98,7 +110,7 @@ void KeyboardNavigation::onFrame()
} }
// workaround incorrect key focus resets (fix in MyGUI TBD) // workaround incorrect key focus resets (fix in MyGUI TBD)
if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus)) if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow)))
{ {
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus);
focus = mCurrentFocus; focus = mCurrentFocus;
@ -119,6 +131,25 @@ void KeyboardNavigation::onFrame()
styleFocusedButton(mCurrentFocus); styleFocusedButton(mCurrentFocus);
} }
void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *defaultFocus)
{
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if (!focus || !shouldAcceptKeyFocus(focus))
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus);
}
else
{
if (!isRootParent(focus, window))
MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus);
}
}
void KeyboardNavigation::setModalWindow(MyGUI::Widget *window)
{
mModalWindow = window;
}
enum Direction enum Direction
{ {
D_Left, D_Left,
@ -152,29 +183,15 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text)
} }
} }
bool selectFirstWidget()
{
MyGUI::VectorWidgetPtr keyFocusList;
MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator();
while (enumerator.next())
getKeyFocusWidgets(enumerator.current(), keyFocusList);
if (!keyFocusList.empty())
{
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]);
return true;
}
return false;
}
bool KeyboardNavigation::switchFocus(int direction, bool wrap) bool KeyboardNavigation::switchFocus(int direction, bool wrap)
{ {
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) bool isCycle = (direction == D_Prev || direction == D_Next);
if ((focus && focus->getTypeName().find("Button") == std::string::npos) && !isCycle)
return false; return false;
bool isCycle = (direction == D_Prev || direction == D_Next);
if (focus && isCycle && focus->getUserString("AcceptTab") == "true") if (focus && isCycle && focus->getUserString("AcceptTab") == "true")
return false; return false;
@ -230,6 +247,23 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap)
return true; return true;
} }
bool KeyboardNavigation::selectFirstWidget()
{
MyGUI::VectorWidgetPtr keyFocusList;
MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator();
if (mModalWindow)
enumerator = mModalWindow->getEnumerator();
while (enumerator.next())
getKeyFocusWidgets(enumerator.current(), keyFocusList);
if (!keyFocusList.empty())
{
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]);
return true;
}
return false;
}
bool KeyboardNavigation::accept() bool KeyboardNavigation::accept()
{ {
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();

@ -23,15 +23,23 @@ namespace MWGui
void onFrame(); void onFrame();
/// Set a key focus widget for this window, if one isn't already set.
void setDefaultFocus(MyGUI::Widget* window, MyGUI::Widget* defaultFocus);
void setModalWindow(MyGUI::Widget* window);
private: private:
bool switchFocus(int direction, bool wrap); bool switchFocus(int direction, bool wrap);
bool selectFirstWidget();
/// Send button press event to focused button /// Send button press event to focused button
bool accept(); bool accept();
std::map<int, MyGUI::Widget*> mKeyFocus; std::map<int, MyGUI::Widget*> mKeyFocus;
MyGUI::Widget* mCurrentFocus; MyGUI::Widget* mCurrentFocus;
MyGUI::Widget* mModalWindow;
}; };
} }

@ -67,14 +67,17 @@ WindowModal::WindowModal(const std::string& parLayout)
void WindowModal::onOpen() void WindowModal::onOpen()
{ {
// Order important. We need to save the key focus widget before its unset
MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget);
MyGUI::InputManager::getInstance().setKeyFocusWidget(focus);
} }
void WindowModal::onClose() void WindowModal::onClose()
{ {
MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); MWBase::Environment::get().getWindowManager()->removeCurrentModal(this);
MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget);
} }

@ -23,6 +23,8 @@ namespace MWGui
public: public:
WindowBase(const std::string& parLayout); WindowBase(const std::string& parLayout);
virtual MyGUI::Widget* getDefaultKeyFocus() { return NULL; }
// Events // Events
typedef MyGUI::delegates::CMultiDelegate1<WindowBase*> EventHandle_WindowBase; typedef MyGUI::delegates::CMultiDelegate1<WindowBase*> EventHandle_WindowBase;

@ -1738,6 +1738,10 @@ namespace MWGui
mKeyboardNavigation->saveFocus(getMode()); mKeyboardNavigation->saveFocus(getMode());
mCurrentModals.push(input); mCurrentModals.push(input);
mKeyboardNavigation->restoreFocus(-1);
mKeyboardNavigation->setModalWindow(input->mMainWidget);
mKeyboardNavigation->setDefaultFocus(input->mMainWidget, input->getDefaultKeyFocus());
} }
void WindowManager::removeCurrentModal(WindowModal* input) void WindowManager::removeCurrentModal(WindowModal* input)
@ -1747,12 +1751,20 @@ namespace MWGui
if(!mCurrentModals.empty()) if(!mCurrentModals.empty())
{ {
if(input == mCurrentModals.top()) if(input == mCurrentModals.top())
{
mCurrentModals.pop(); mCurrentModals.pop();
mKeyboardNavigation->saveFocus(-1);
}
else else
std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl;
} }
if (mCurrentModals.empty()) if (mCurrentModals.empty())
{
mKeyboardNavigation->setModalWindow(NULL);
mKeyboardNavigation->restoreFocus(getMode()); mKeyboardNavigation->restoreFocus(getMode());
}
else
mKeyboardNavigation->setModalWindow(mCurrentModals.top()->mMainWidget);
} }
void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char)

@ -81,6 +81,7 @@ color_misc=0,205,205 # ????
<Resource type="ResourceSkin" name="SandTextButton" size="16 16"> <Resource type="ResourceSkin" name="SandTextButton" size="16 16">
<Property key="FontName" value="Default"/> <Property key="FontName" value="Default"/>
<Property key="TextAlign" value="Left Bottom"/> <Property key="TextAlign" value="Left Bottom"/>
<Property key="NeedKey" value="true"/>
<BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"> <BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch">
<State name="disabled" colour="#{fontcolour=disabled}" shift="0"/> <State name="disabled" colour="#{fontcolour=disabled}" shift="0"/>
<State name="normal" colour="#{fontcolour=normal}" shift="0"/> <State name="normal" colour="#{fontcolour=normal}" shift="0"/>

Loading…
Cancel
Save