put the caret in the name prompt's line edit
The layer asked the modal's focusWidget() what to focus, but hosting a modal reparents it into a scroll area and a reparent clears the focus its constructor set, so the answer was always nothing and the dialog itself took the keyboard. Modals now name their initial focus widget outright, which survives the hosting. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
This commit is contained in:
@@ -52,6 +52,11 @@ bool ModalDialog::isDismissible() const
|
||||
return false;
|
||||
}
|
||||
|
||||
QWidget* ModalDialog::getInitialFocusWidget() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ModalDialog::requestDismiss()
|
||||
{
|
||||
reject();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
|
||||
QString getName() const;
|
||||
|
||||
QWidget* getInitialFocusWidget() const override;
|
||||
|
||||
private:
|
||||
QLineEdit* m_nameEdit;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user