diff --git a/src/ui/ModalDialog.cpp b/src/ui/ModalDialog.cpp index fae07f9..074eed3 100644 --- a/src/ui/ModalDialog.cpp +++ b/src/ui/ModalDialog.cpp @@ -52,6 +52,11 @@ bool ModalDialog::isDismissible() const return false; } +QWidget* ModalDialog::getInitialFocusWidget() const +{ + return nullptr; +} + void ModalDialog::requestDismiss() { reject(); diff --git a/src/ui/ModalDialog.h b/src/ui/ModalDialog.h index 3c981ab..b229a0d 100644 --- a/src/ui/ModalDialog.h +++ b/src/ui/ModalDialog.h @@ -30,6 +30,12 @@ public: // has no way out but choosing (REQ-DEF-SCHEMATIC-DROP). virtual bool isDismissible() const; + // The widget that should hold the keyboard once the modal is open -- a name prompt's + // line edit -- or nullptr to leave the focus on the modal itself. Asked for by + // ModalLayer rather than read off focusWidget(), because hosting the modal reparents + // it and a reparent clears the focus its constructor set. + virtual QWidget* getInitialFocusWidget() const; + public slots: // What a dismissal does, whichever gesture asked for it. Cancelling is the default; // a dialog with modes of its own overrides this to back out of them one at a time diff --git a/src/ui/ModalLayer.cpp b/src/ui/ModalLayer.cpp index c5a526b..ed5fe93 100644 --- a/src/ui/ModalLayer.cpp +++ b/src/ui/ModalLayer.cpp @@ -66,17 +66,15 @@ int ModalLayer::execute(ModalDialog& content, const QRect& anchorRect) content.show(); updateVisibility(); - // The modal's own focus widget where it has one -- a name dialog puts the caret in + // The widget the modal names where it names one -- a name dialog puts the caret in // its line edit -- and the modal itself otherwise, so keys reach it and not the game // world behind (REQ-UI-MODAL-CHROME). - if (content.focusWidget() != nullptr) + QWidget* focusTarget = content.getInitialFocusWidget(); + if (focusTarget == nullptr) { - content.focusWidget()->setFocus(); - } - else - { - content.setFocus(); + focusTarget = &content; } + focusTarget->setFocus(); // The dialog's own loop, run here rather than by QDialog::exec(), so the layer knows // what is open and can place it, dim behind it, and take the clicks beside it. diff --git a/src/ui/NameInputDialog.cpp b/src/ui/NameInputDialog.cpp index cccce27..9c0082d 100644 --- a/src/ui/NameInputDialog.cpp +++ b/src/ui/NameInputDialog.cpp @@ -46,10 +46,17 @@ NameInputDialog::NameInputDialog(const QString& title, const QString& prompt, addHeader(mainLayout, title, false); // The line edit is what the player came here to use, and it takes Q as a character - // because it holds the focus (REQ-UI-DIALOG-DISMISS). + // because it holds the focus (REQ-UI-DIALOG-DISMISS). Set here for a dialog shown on + // its own, and named again through getInitialFocusWidget() for the usual case: being + // hosted on the modal layer reparents this dialog, which clears the focus set here. m_nameEdit->setFocus(); } +QWidget* NameInputDialog::getInitialFocusWidget() const +{ + return m_nameEdit; +} + QString NameInputDialog::getName() const { return m_nameEdit->text().trimmed(); diff --git a/src/ui/NameInputDialog.h b/src/ui/NameInputDialog.h index 77f1ba2..658c267 100644 --- a/src/ui/NameInputDialog.h +++ b/src/ui/NameInputDialog.h @@ -25,6 +25,8 @@ public: QString getName() const; + QWidget* getInitialFocusWidget() const override; + private: QLineEdit* m_nameEdit; };