From: PatR Date: Thu, 5 Nov 2020 23:35:30 +0000 (-0800) Subject: Qt text windows X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e4106bb1613da808ae87780dfeedb4c80e6afc2a;p=nethack Qt text windows Text window search behaved very strangely: at some point after selecting [Search], entering a search string, having the string entry popup go away, and having the search performed, but before the result could be shown, the text window got pushed behind the main window (map+messages+paperdoll+status). Clicking on the main window's minimize button hid the main window and gave access to the text window behind it. That was still functional even after having been inaccessible; another search could be performed and/or it could be dismissed. I still don't know what causes that or how to properly fix it, but using raise() is a workaround to bring it to the front where it belongs. Unfortunately you can see it go away and come back so searching for text is distracting. Allow (when not searching) to dismiss all text windows including RIP. Accept ctrl+[ as ESC. Make text window searching be case-insensitive. Searching wouldn't find a match on the first line of text. Now it will. This also includes an attempt to fix github issue #400 (typing a pickup command while "things that are here" popup text window is displayed seems to hang the program), but since I can't reproduce that, I can't tell whether the fix works. The issue description says that pickup started executing and "things here" couldn't be dismissed which is different from "things here" being behind the map waiting for it to be dismissed. The attempted fix is for text window handling to tell Qt that it wants control of the keyboard, so nethack shouldn't see any attempted pickup command. --- diff --git a/doc/fixes37.0 b/doc/fixes37.0 index b92e07915..4eb6b9062 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.344 $ $NHDT-Date: 1603836614 2020/10/27 22:10:14 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.347 $ $NHDT-Date: 1604619327 2020/11/05 23:35:27 $ General Fixes and Modified Features ----------------------------------- @@ -467,6 +467,10 @@ Qt: don't clobber an existing save file after choosing "new game" in the saved game selection widget Qt: don't get stuck in a loop after choosing "play" while the character name field is empty in the character selection widget +Qt: {maybe just Qt+OSX:} when viewing a text window ('V' to look at 'history' + for instance), clicking on [Search], entering a search target in the + resulting popup and clicking on [Okay] or typing , the text + window got pushed underneath the main window so seemed to go away Qt+OSX: fix control key Qt+OSX: rename menu entry "nethack->Preferences..." for invoking nethack's 'O' command to "Game->Run-time options" and entry "Game->Qt settings" diff --git a/win/Qt/Qt-issues.txt b/win/Qt/Qt-issues.txt index 4ac6fc2e7..b25adff97 100644 --- a/win/Qt/Qt-issues.txt +++ b/win/Qt/Qt-issues.txt @@ -52,4 +52,11 @@ intended to be displayed, is displayed (as blank terrain). 3.6 status conditions (Stone, Slime, Strngl, Deaf, Lev, Fly, Ride) have been implemented but need icon artwork (one 40x40 tile for each). +In a menu window, typing ':' (via shift+something) works to initiate +a search without the need to click on the [Search] button. In a text +window, it does not, despite moving the menu key press interpretation +code into its own routine and calling that for both types of windows. +From the text window code, it sees the initial shift but not the ':' +that should follow. + ----- diff --git a/win/Qt/qt_menu.cpp b/win/Qt/qt_menu.cpp index 3a6062ee1..4a59f4356 100644 --- a/win/Qt/qt_menu.cpp +++ b/win/Qt/qt_menu.cpp @@ -55,6 +55,24 @@ namespace nethack_qt_ { void centerOnMain( QWidget* w ); // end temporary +static uchar keyValue(QKeyEvent *key_event) +{ + // key_event manipulation derived from NetHackQtBind::notify() + const int k = key_event->key(); + Qt::KeyboardModifiers mod = key_event->modifiers(); + QChar ch = !key_event->text().isEmpty() ? key_event->text().at(0) : 0; + if (ch >= 128) + ch = 0; + // on OSX, ascii control codes are not sent, force them + if (ch == 0 && (mod & Qt::ControlModifier) != 0) { + if (k >= Qt::Key_A && k <= Qt::Key_Underscore) + ch = QChar((k - (Qt::Key_A - 1))); + } + uchar result = (uchar) ch.cell(); + //raw_printf("kV: k=%d, ch=%d", k, result); + return result; +} + QSize NetHackQtTextListBox::sizeHint() const { QScrollBar *hscroll = horizontalScrollBar(); @@ -697,18 +715,9 @@ void NetHackQtMenuWindow::ClearCount(void) void NetHackQtMenuWindow::keyPressEvent(QKeyEvent *key_event) { - // key_event manipulation derived from NetHackQtBind::notify() - const int k = key_event->key(); - Qt::KeyboardModifiers mod = key_event->modifiers(); - QChar ch = !key_event->text().isEmpty() ? key_event->text().at(0) : 0; - if (ch > 128) - ch = 0; - // on OSX, ascii control codes are not sent, force them - if (ch == 0 && (mod & Qt::ControlModifier) != 0) { - if (k >= Qt::Key_A && k <= Qt::Key_Underscore) - ch = (QChar) (k - (Qt::Key_A - 1)); - } - uchar key = (char) ch.cell(); + uchar key = keyValue(key_event); + if (!key) + return; // only one possible match for key==ch, and if one occurs it takes // precedence over any other match (for instance, some menus might @@ -837,7 +846,7 @@ void NetHackQtMenuWindow::Search() line[0] = '\0'; /* for EDIT_GETLIN */ if (requestor.Get(line)) { for (int i=0; iaddWidget(&rip); @@ -974,6 +995,10 @@ NetHackQtTextWindow::NetHackQtTextWindow(QWidget *parent) : hb->addWidget(&ok); hb->addWidget(&search); vb->addWidget(lines); + + // we don't want keystrokes being sent to the main window for use as + // commands while this text window is popped up + setFocusPolicy(Qt::StrongFocus); } void NetHackQtTextWindow::doUpdate() @@ -984,7 +1009,6 @@ void NetHackQtTextWindow::doUpdate() NetHackQtTextWindow::~NetHackQtTextWindow() { - } QWidget* NetHackQtTextWindow::Widget() @@ -994,7 +1018,16 @@ QWidget* NetHackQtTextWindow::Widget() bool NetHackQtTextWindow::Destroy() { - return !isVisible(); + return true; /*!isVisible();*/ +} + +void NetHackQtTextWindow::doDismiss() +{ + // [Clear() was needed when the search target string was kept in + // a static buffer but is superfluous now that that's part of + // the TextWindow class and initialized in the constructor.] + Clear(); + accept(); } void NetHackQtTextWindow::UseRIP(int how, time_t when) @@ -1083,12 +1116,18 @@ void NetHackQtTextWindow::UseRIP(int how, time_t when) void NetHackQtTextWindow::Clear() { lines->clear(); - use_rip=false; - str_fixed=false; + target[0] = '\0'; // discard search target string + use_rip = false; + str_fixed = false; + textsearching = false; } void NetHackQtTextWindow::Display(bool block UNUSED) { + // make sure window isn't completely empty + if (!lines->count()) + PutStr(ATR_NONE, ""); + if (str_fixed) { lines->setFont(qt_settings->normalFixedFont()); } else { @@ -1117,7 +1156,11 @@ void NetHackQtTextWindow::Display(bool block UNUSED) centerOnMain(this); show(); } + + lines->clearSelection(); // affects [Search] + exec(); + textsearching = false; } void NetHackQtTextWindow::PutStr(int attr UNUSED, const QString& text) @@ -1126,22 +1169,77 @@ void NetHackQtTextWindow::PutStr(int attr UNUSED, const QString& text) lines->addItem(text); } +// prompt for a target string and search current text window for it; +// if found, highlight the next line target occurs on; +// multiple searches with same or different search string are supported void NetHackQtTextWindow::Search() { - NetHackQtStringRequestor requestor(this, "Search for:"); - static char line[256]=""; - requestor.SetDefault(line); - if (requestor.Get(line)) { - int current=lines->currentRow(); - for (int i=1; icount(); i++) { - int lnum=(i+current)%lines->count(); - QString str=lines->item(lnum)->text(); - if (str.contains(line)) { - lines->setCurrentRow(lnum); - return; - } - } - lines->setCurrentItem(NULL); + textsearching = true; + NetHackQtStringRequestor requestor(this, "Search for:", "Done", "Find"); + requestor.SetDefault(target); + boolean get_a_line = requestor.Get(target, (int) sizeof target); + + // FIXME: + // Force text window to be on top. Without this, it moves behind + // the map after the string requestor completes. Then it can't + // be seen or accessed (unless the game window is minimized or + // possibly dragged out of the way). Unfortunately the window + // noticeably vanishes and then immediately gets redrawn. + if (!this->isActiveWindow()) + this->activateWindow(); + this->raise(); + + if (get_a_line) { + int linecount = lines->count(); + int current = lines->currentRow(); + // when no row is highlighted (selected), start the search + // on the current row, otherwise start on the row after it + // [normally means that the very first row is a candidate + // for containgin the target during the very first search] + int startln = lines->selectedItems().count(); + for (int i = startln; i < linecount; ++i) { + int lnum = (i + current) % linecount; + const QString &str = lines->item(lnum)->text(); + // Check whether target occurs on this line. If it does, + // the line is highlighted and this search finishes. + // When not currently within view, highlighting also + // scrolls the view to make it become the bottom line. + // A subsequent search will remember the target string + // and start searching on the line past the highlighted + // one (even if a new target is specified). + if (str.contains(target, Qt::CaseInsensitive)) { + lines->setCurrentRow(lnum); + return; + } + } + lines->setCurrentItem(NULL); + } else { + target[0] = '\0'; + } + textsearching = false; + return; +} + +void NetHackQtTextWindow::keyPressEvent(QKeyEvent *key_event) +{ + uchar key = keyValue(key_event); + + // + // FIXME: + // Typing ':' doesn't produce ':' so key won't match MENU_SEARCH, + // despite the fact that it does produce ':' for menu input and + // we're calling the exact same code for both types of window...? + // + if (key == MENU_SEARCH) { + if (!use_rip) + Search(); + } else if (key == '\n' || key == '\r') { + if (!textsearching) + accept(); + } else if (key == '\033') { + reject(); + } else { + QDialog::keyPressEvent(key_event); } } diff --git a/win/Qt/qt_menu.h b/win/Qt/qt_menu.h index b61a9305b..e69265a4f 100644 --- a/win/Qt/qt_menu.h +++ b/win/Qt/qt_menu.h @@ -155,15 +155,21 @@ public slots: void Search(); private slots: + void doDismiss(); void doUpdate(); +protected: + virtual void keyPressEvent(QKeyEvent *); + private: bool use_rip; bool str_fixed; + bool textsearching; QPushButton ok; QPushButton search; NetHackQtTextListBox* lines; + char target[BUFSZ]; NetHackQtRIP rip; };