From: PatR Date: Sun, 4 Oct 2020 14:36:12 +0000 (-0700) Subject: Qt ynaq/yn#aq dialogs X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9bad6840f467c3b20757b313249b24ae924d6338;p=nethack Qt ynaq/yn#aq dialogs When 'popup_dialog' is set, the Qt interface uses a popup window for yn_function() calls and the dialog has a list of buttons, one per potential choice. It has been handling "yn?" and "ynq?" questions differently from general request-one-char prompts, using buttons "Yes", "No, and "Cancel" instead of showing individual letters. This extends that to "ynaq" and "yn#aq" questions and labels 'q' reply as "Stop" instead of "Cancel" for those. Also, when player uses keyboard instead of mouse to answer, allow 'c' as well as 'q' for cancel ones, 's' as well as 'q' for stop ones. Prompt Buttons yn [Yes ][ No ] ynq [ Yes ][ No ][Cancel] ynaq [Yes ][ No ][All ][Stop] yn#aq [Yes ]Count:______[ No ][All ][Stop] rl [ Left ][Right ] //unchanged; included for completeness (For contrast, when something specifies "ny" as the acceptable choices, the buttons will just be [n][y]. Prompts for choosing from a list of inventory letters can't accidentally match these special cases as long as they're specified in alphabetical order.) --- diff --git a/win/Qt/qt_yndlg.cpp b/win/Qt/qt_yndlg.cpp index 7ae167da2..d7b370a32 100644 --- a/win/Qt/qt_yndlg.cpp +++ b/win/Qt/qt_yndlg.cpp @@ -69,6 +69,7 @@ NetHackQtYnDialog::NetHackQtYnDialog(QWidget *parent, const QString &q, } } } + alt_answer[0] = alt_result[0] = '\0'; } char NetHackQtYnDialog::Exec() @@ -152,7 +153,10 @@ char NetHackQtYnDialog::Exec() QButtonGroup *bgroup = new QButtonGroup(group); int nchoices=ch.length(); - bool is_ynq = (ch == QString("ynq")), // [ Yes ][ No ][Cancel] + bool is_ynaq = (ch == QString("ynaq") // [Yes ][ No ][All ][Stop] + || ch == QString("yn#aq") + || ch == altchoices), // alternate "yn#aq" + is_ynq = (ch == QString("ynq")), // [ Yes ][ No ][Cancel] is_yn = (ch == QString("yn")), // [Yes ][ No ] is_lr = (ch == QString(lrq)); // [ Left ][Right ] @@ -161,8 +165,8 @@ char NetHackQtYnDialog::Exec() const int extra=fontMetrics().height(); // Extra for group int x=margin, y=extra+margin; int butheight = fontMetrics().height() * 2 + 5, - butwidth = (butheight - 5) - * ((is_ynq || is_lr) ? 3 : is_yn ? 2 : 1) + 5; + butwidth = (butheight - 5) * ((is_ynq || is_lr) ? 3 + : (is_ynaq || is_yn) ? 2 : 1) + 5; if (butwidth == butheight) { // square, enough room for C or ^C // some characters will be labelled by name rather than by // keystroke so will need wider buttons @@ -183,7 +187,9 @@ char NetHackQtYnDialog::Exec() if (ch[i] == '#' && allow_count) continue; // don't show a button for '#'; has Count box instead QString button_name = QString(visctrl((char) ch[i].cell())); - if (is_yn || is_ynq || is_lr) { + if (is_yn || is_ynq || is_ynaq || is_lr) { + // FIXME: a better way to recognize which labels should + // use alterate text is needed switch (ch[i].cell()) { case 'y': button_name = "Yes"; @@ -191,13 +197,28 @@ char NetHackQtYnDialog::Exec() case 'n': button_name = "No"; break; + case 'a': + // the display of vanquished monsters uses "ynaq" for + // convenience, where 'a' requests a sort-by menu; + // show "sort" instead of "all" and allow player to + // type either 'a' or 's' when not clicking on button + if (question.contains(QString("vanquished?"))) + button_name = "Sort", AltChoice('s', 'a'); + else + button_name = "All"; + break; case 'q': - // FIXME: sometimes the 'q' choice is ''cancel current - // action'' but other times it is actually 'quit'. - if (question.left(10) == QString("Dump core?")) + // most 'q' replies are actually for "cancel" but + // for "ynaq" (where "all" is a choice) it's "stop" + // and for end of game disclosure it really is "quit" + if (question.left(10) == QString("Dump core?") + || (::g.program_state.gameover + && question.left(11) == QString("Do you want"))) button_name = "Quit"; + else if (is_ynaq) + button_name = "Stop", AltChoice('s', 'q'); else - button_name = "Cancel"; + button_name = "Cancel", AltChoice('c', 'q'); break; case 'l': button_name = "Left"; @@ -286,7 +307,10 @@ char NetHackQtYnDialog::Exec() if (res == 0) { choice = is_lr ? '\033' : ch_esc ? ch_esc : def ? def : ' '; } else if (res == 1) { - choice = def ? def : ch_esc ? ch_esc : ' '; + if (keypress) + choice = keypress; + else + choice = def ? def : ch_esc ? ch_esc : ' '; } else if (res >= 1000) { choice = (char) ch[res - 1000].cell(); } @@ -319,23 +343,33 @@ char NetHackQtYnDialog::Exec() return keypress; } +void NetHackQtYnDialog::AltChoice(char ans, char res) +{ + if (ans && !strchr(alt_answer, ans)) { + (void) strkitten(alt_answer, ans); + (void) strkitten(alt_result, res); + } +} + void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) { + keypress = '\0'; QString text(event->text()); - if (text.isEmpty() && event->modifiers()) + if (text.isEmpty()) /* && event->modifiers()) */ return; - if (!choices || !*choices) { - if (!text.isEmpty()) { - keypress = text.toUcs4()[0]; - this->done(1); - } + keypress = text.at(0).cell(); + char *p = NULL; + if (*alt_answer && (p = strchr(alt_answer, keypress)) != 0) + keypress = alt_result[p - alt_answer]; + + if (!choices || !*choices || !keypress) { + this->done(1); } else { - int where = QString::fromLatin1(choices).indexOf(text); + int where = QString::fromLatin1(choices).indexOf(QChar(keypress)); - if (where != -1 && allow_count - && strchr("#0123456789", text[0].cell())) { + if (allow_count && strchr("#0123456789", keypress)) { if (text == "#") { // 0 will be preselected; typing anything replaces it le->setText(QString("0")); @@ -347,7 +381,18 @@ void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) } // (don't know whether this actually does anything useful) le->setAttribute(Qt::WA_KeyboardFocusChange, true); + // this is definitely useful... le->setFocus(Qt::ActiveWindowFocusReason); + // + // TODO: 'No' is highlighted as default for result if player + // types , but once count entry starts that should + // be changed because this LineEdit dialog has now become + // the defacto default. We can't just turn off the default + // setting for the 'No' button because only works + // if there is a default explicitly set. Unfortunately the + // LineEdit widget isn't a viable candidate for that because + // it isn't a button. [Maybe just highlight 'Yes' instead?] + // } else if (where != -1) { this->done(where + 1000); diff --git a/win/Qt/qt_yndlg.h b/win/Qt/qt_yndlg.h index 049886355..cdbdc0710 100644 --- a/win/Qt/qt_yndlg.h +++ b/win/Qt/qt_yndlg.h @@ -19,8 +19,12 @@ private: bool allow_count; QLineEdit *le; + // abritrary size; might need to be more sophisicated someday + char alt_answer[26 + 1], alt_result[26 + 1]; + protected: virtual void keyPressEvent(QKeyEvent*); + void AltChoice(char answer, char result); private slots: void doneItem(int);