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()
{
WindowModal::onOpen();
center();
MWWorld::Ptr player = MWMechanics::getPlayer();
@ -88,6 +87,12 @@ namespace MWGui
mBribe1000Button->setEnabled (playerGold >= 1000);
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 MyGUI::Widget* getDefaultKeyFocus();
private:
MyGUI::Button* mCancelButton;
MyGUI::Button* mAdmireButton;

@ -38,6 +38,7 @@ bool shouldAcceptKeyFocus(MyGUI::Widget* w)
KeyboardNavigation::KeyboardNavigation()
: mCurrentFocus(nullptr)
, mModalWindow(nullptr)
{
MyGUI::WidgetManager::getInstance().registerUnlinker(this);
}
@ -51,9 +52,13 @@ void KeyboardNavigation::saveFocus(int mode)
{
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if (shouldAcceptKeyFocus(focus))
{
mKeyFocus[mode] = focus;
}
else
{
mKeyFocus[mode] = mCurrentFocus;
}
}
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()
{
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
@ -98,7 +110,7 @@ void KeyboardNavigation::onFrame()
}
// 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);
focus = mCurrentFocus;
@ -119,6 +131,25 @@ void KeyboardNavigation::onFrame()
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
{
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)
{
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;
bool isCycle = (direction == D_Prev || direction == D_Next);
if (focus && isCycle && focus->getUserString("AcceptTab") == "true")
return false;
@ -230,6 +247,23 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap)
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()
{
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();

@ -23,15 +23,23 @@ namespace MWGui
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:
bool switchFocus(int direction, bool wrap);
bool selectFirstWidget();
/// Send button press event to focused button
bool accept();
std::map<int, MyGUI::Widget*> mKeyFocus;
MyGUI::Widget* mCurrentFocus;
MyGUI::Widget* mModalWindow;
};
}

@ -67,14 +67,17 @@ WindowModal::WindowModal(const std::string& parLayout)
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
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget);
MyGUI::InputManager::getInstance().setKeyFocusWidget(focus);
}
void WindowModal::onClose()
{
MWBase::Environment::get().getWindowManager()->removeCurrentModal(this);
MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget);
}

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

@ -1738,6 +1738,10 @@ namespace MWGui
mKeyboardNavigation->saveFocus(getMode());
mCurrentModals.push(input);
mKeyboardNavigation->restoreFocus(-1);
mKeyboardNavigation->setModalWindow(input->mMainWidget);
mKeyboardNavigation->setDefaultFocus(input->mMainWidget, input->getDefaultKeyFocus());
}
void WindowManager::removeCurrentModal(WindowModal* input)
@ -1747,12 +1751,20 @@ namespace MWGui
if(!mCurrentModals.empty())
{
if(input == mCurrentModals.top())
{
mCurrentModals.pop();
mKeyboardNavigation->saveFocus(-1);
}
else
std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl;
}
if (mCurrentModals.empty())
{
mKeyboardNavigation->setModalWindow(NULL);
mKeyboardNavigation->restoreFocus(getMode());
}
else
mKeyboardNavigation->setModalWindow(mCurrentModals.top()->mMainWidget);
}
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">
<Property key="FontName" value="Default"/>
<Property key="TextAlign" value="Left Bottom"/>
<Property key="NeedKey" value="true"/>
<BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch">
<State name="disabled" colour="#{fontcolour=disabled}" shift="0"/>
<State name="normal" colour="#{fontcolour=normal}" shift="0"/>

Loading…
Cancel
Save