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; };