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 <return> (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.
This commit is contained in:
@@ -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; i<itemcount; i++) {
|
||||
if (itemlist[i].str.contains(line))
|
||||
if (itemlist[i].str.contains(line, Qt::CaseInsensitive))
|
||||
ToggleSelect(i, false);
|
||||
}
|
||||
}
|
||||
@@ -953,19 +962,31 @@ long NetHackQtMenuWindow::count(int row)
|
||||
return cstr.isEmpty() ? -1L : cstr.toLong();
|
||||
}
|
||||
|
||||
// initialize a text window
|
||||
NetHackQtTextWindow::NetHackQtTextWindow(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
use_rip(false),
|
||||
str_fixed(false),
|
||||
ok("Dismiss",this),
|
||||
search("Search",this),
|
||||
textsearching(false),
|
||||
ok("&Dismiss", this),
|
||||
search("&Search", this),
|
||||
lines(new NetHackQtTextListBox(this)),
|
||||
target(""),
|
||||
rip(this)
|
||||
{
|
||||
//
|
||||
// TODO?
|
||||
// Searching would be far more convenient if the window contained
|
||||
// the search string requestor widget instead of just a [Search]
|
||||
// button to request a popup for that.
|
||||
// Also, searching should probably be disabled if the entire text
|
||||
// fits within the window so there's nothing to scroll through.
|
||||
//
|
||||
|
||||
ok.setDefault(true);
|
||||
connect(&ok,SIGNAL(clicked()),this,SLOT(accept()));
|
||||
connect(&search,SIGNAL(clicked()),this,SLOT(Search()));
|
||||
connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate()));
|
||||
connect(&ok,SIGNAL(clicked()), this, SLOT(doDismiss()));
|
||||
connect(&search, SIGNAL(clicked()), this, SLOT(Search()));
|
||||
connect(qt_settings, SIGNAL(fontChanged()), this, SLOT(doUpdate()));
|
||||
|
||||
QVBoxLayout* vb = new QVBoxLayout(this);
|
||||
vb->addWidget(&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; i<lines->count(); 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user