diff --git a/doc/fixes37.0 b/doc/fixes37.0 index a0cf984d3..cf1725ed4 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1123,6 +1123,8 @@ Qt: if player's run-time options specified a tiles file and it couldn't be Qt: force the 'toptenwin' option On so that high scores display at end of game is shown in a text window instead of being written to stdout where it might not be seen (note: doesn't apply to 'nethack -s') +Qt: during role/race/&c selection, update role titles with their icons, and + also Valk eligibility, when gender is toggled 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 diff --git a/win/Qt/qt_plsel.cpp b/win/Qt/qt_plsel.cpp index f3ca26933..9b76de8b0 100644 --- a/win/Qt/qt_plsel.cpp +++ b/win/Qt/qt_plsel.cpp @@ -8,7 +8,6 @@ // TODO: // increase height so that no scrolling is needed for role list [needs // to be done properly instead of forcing logo string to be taller] -// the [Random] button doesn't do anything; // make race first vs role first dynamically selectable (tty allows // gender first and alignment first too); // maybe add a set of radio buttons for normal mode vs explore mode @@ -75,6 +74,13 @@ void centerOnMain( QWidget* w ); static const char nh_attribution[] = "
NetHack %1" "
by the NetHack DevTeam

"; +// +// None of these extra classes seem to be used except for NhPSListView. [pr] +// If NhPSListViewRole and NhPSListViewRace ever start being used, +// they'll need access to NetHackQtPlayerSelector::chosen_gend to use +// the correct tile for the icon. +// + class NhPSListViewItem : public QTableWidgetItem { public: NhPSListViewItem( QTableWidget* parent UNUSED, const QString& name ) : @@ -179,11 +185,15 @@ public: } }; -NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks UNUSED) : +// constructor for player's name+role/race/gender/alignment selection +NetHackQtPlayerSelector::NetHackQtPlayerSelector( + NetHackQtKeyBuffer& ks UNUSED) : QDialog(NetHackQtBind::mainWidget()), fully_specified_role(true), chosen_gend(ROLE_NONE), chosen_align(ROLE_NONE), + cleric_role_row(0), + human_race_row(0), rand_btn(new QPushButton("Random")), play_btn(new QPushButton("Play")), quit_btn(new QPushButton("Quit")) @@ -258,48 +268,48 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks UNUSED) l->addWidget( logo, 3, 2, Qt::AlignCenter ); l->setRowStretch( 3, 6 ); - int i; - int nrole; + QTableWidgetItem *item; + int i, nrole, nrace; chosen_gend = flags.initgend; chosen_align = flags.initalign; - bool fem = (chosen_gend > ROLE_NONE); // XXX QListView unsorted goes in rev. for (nrole=0; roles[nrole].name.m; nrole++) ; role->setRowCount(nrole); - for (i=0; roles[i].name.m; i++) { - glyph_info gi; - int glyph = monnum_to_glyph(roles[i].malenum, fem); - map_glyphinfo(0, 0, glyph, 0, &gi); - - QTableWidgetItem *item = new QTableWidgetItem( - QIcon(qt_settings->glyphs().glyph(glyph, gi.gm.tileidx)), - (fem && roles[i].name.f) ? roles[i].name.f : roles[i].name.m); - item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + for (i = 0; i < nrole; ++i) { + item = new QTableWidgetItem(); role->setItem(i, 0, item); + + if (roles[i].malenum == PM_CLERIC) + cleric_role_row = i; // for populate_races() } + + for (nrace=0; races[nrace].noun; nrace++) + ; + race->setRowCount(nrace); + for (i = 0; i < nrace; ++i) { + item = new QTableWidgetItem(); + race->setItem(i, 0, item); + + if (races[i].malenum == PM_HUMAN) + human_race_row = i; // (always i==0) for populate_roles() + } + +#ifdef QT_CHOOSE_RACE_FIRST + populate_races(); + populate_roles(); +#else + populate_roles(); + populate_races(); +#endif + connect(role, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(selectRole(int, int, int, int))); role->setHorizontalHeaderLabels(QStringList("Role")); role->resizeColumnToContents(0); - int nrace; - for (nrace=0; races[nrace].noun; nrace++) - ; - race->setRowCount(nrace); - for (i=0; races[i].noun; i++) { - glyph_info gi; - int glyph = monnum_to_glyph(races[i].malenum, fem); - map_glyphinfo(0, 0, glyph, 0, &gi); - - QTableWidgetItem *item = new QTableWidgetItem( - QIcon(qt_settings->glyphs().glyph(glyph, gi.gm.tileidx)), - races[i].noun); - item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); - race->setItem(i, 0, item); - } connect(race, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(selectRace(int, int, int, int))); race->setHorizontalHeaderLabels(QStringList("Race")); @@ -307,11 +317,8 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks UNUSED) // TODO: // Render the alignment and gender labels smaller to match the - // horizontal header labels for role and race; getting the font from - // race table above and setting it for labels below made no difference. - // - // Maybe, if the order of choosing becomes more dynamic: - // Replace the role and race glyphs when gender gets set. + // horizontal header labels for role and race. (Getting the font from + // race table above and setting it for labels below made no difference.) QLabel *gendlabel = new QLabel("Gender"); genderbox->layout()->addWidget(gendlabel); @@ -321,7 +328,7 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks UNUSED) genderbox->layout()->addWidget(gender[i]); gendergroup->addButton(gender[i], i); } - connect(gendergroup, SIGNAL(buttonPressed(int)), + connect(gendergroup, SIGNAL(buttonClicked(int)), this, SLOT(selectGender(int))); QLabel *alignlabel = new QLabel("Alignment"); @@ -332,7 +339,7 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks UNUSED) alignbox->layout()->addWidget(alignment[i]); aligngroup->addButton(alignment[i], i); } - connect(aligngroup, SIGNAL(buttonPressed(int)), + connect(aligngroup, SIGNAL(buttonClicked(int)), this, SLOT(selectAlignment(int))); l->addWidget(rand_btn, 4, 2); @@ -348,6 +355,68 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks UNUSED) Randomize(); } +// update the role column in the PlayerSelector widget +void +NetHackQtPlayerSelector::populate_roles() +{ + // + // each row in the role column shows a player-character tile + // and the role's name + // + QTableWidgetItem *item; + const char *rolename; + glyph_info gi; + int v, gf, gn = chosen_gend; + // if no race yet, we use human for gender check (gender doesn't affect + // race but we need a valid race when filtering Valkyrie out or back in) + int ra = race->currentRow(), hu = human_race_row; + bool is_f = (gn == 1); + NetHackQtGlyphs& glyphs = qt_settings->glyphs(); + for (int i = 0; roles[i].name.m; ++i) { + rolename = (is_f && roles[i].name.f) ? roles[i].name.f + : roles[i].name.m; + gf = monnum_to_glyph(roles[i].malenum, is_f ? FEMALE : MALE); + map_glyphinfo(0, 0, gf, 0, &gi); + v = ((ra < 0 || validrace(i, ra)) + && (gn < 0 || validgend(i, (ra >= 0) ? ra : hu, gn))); + item = role->item(i, 0); + item->setText(rolename); + item->setIcon(QIcon(glyphs.glyph(gf, gi.gm.tileidx))); + item->setFlags(v ? Qt::ItemIsEnabled | Qt::ItemIsSelectable + : Qt::NoItemFlags); + } + role->repaint(); // role->update() seems to be inadequate +} + +// update the race column in the PlayerSelector widget +void +NetHackQtPlayerSelector::populate_races() +{ + // + // each row in the race column shows race's generic monster tile + // and the race's name + // + QTableWidgetItem *item; + glyph_info gi; + int v, gf, gn = chosen_gend, al = chosen_align; + // if no role yet, use cleric so that alignment won't rule anything out + int ro = role->currentRow(), cl = cleric_role_row; + bool is_f = (gn == 1); + NetHackQtGlyphs& glyphs = qt_settings->glyphs(); + for (int j = 0; races[j].noun; ++j) { + gf = monnum_to_glyph(races[j].malenum, is_f ? FEMALE : MALE); + map_glyphinfo(0, 0, gf, 0, &gi); + v = ((ro < 0 || validrace(ro, j)) + && (al < 0 || validalign((ro >= 0) ? ro : cl, j, al))); + item = race->item(j, 0); + item->setText(races[j].noun); + item->setIcon(QIcon(glyphs.glyph(gf, gi.gm.tileidx))); + item->setFlags(v ? Qt::ItemIsEnabled | Qt::ItemIsSelectable + : Qt::NoItemFlags); + } + race->repaint(); +} + void NetHackQtPlayerSelector::Randomize() { int nrole = role->rowCount(); @@ -416,7 +485,7 @@ void NetHackQtPlayerSelector::Randomize() } int g = flags.initgend; - if (g == -1) { + if (g < 0) { g = rn2(ROLE_GENDERS); fully_specified_role = false; } @@ -427,7 +496,7 @@ void NetHackQtPlayerSelector::Randomize() selectGender(g); int a = flags.initalign; - if (a == -1) { + if (a < 0) { a = rn2(ROLE_ALIGNS); fully_specified_role = false; } @@ -474,33 +543,31 @@ void NetHackQtPlayerSelector::selectRole(int crow, int ccol, { int ra = race->currentRow(); int ro = role->currentRow(); - if (ra == -1 || ro == -1) return; - QTableWidgetItem* item; - item = role->item(prow, 0); + if (ra == -1 || ro == -1) + return; + QTableWidgetItem *item = role->item(prow, 0); if (item != NULL) item->setSelected(false); #ifdef QT_CHOOSE_RACE_FIRST selectRace(crow, ccol, prow, pcol); #else - QTableWidgetItem* i=role->currentItem(); - QTableWidgetItem* valid=0; - int j; - for (j=0; roles[j].name.m; j++) { - bool v = validrace(j,ra); - item = role->item(j, 0); - item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); - if ( !valid && v ) valid = item; + QTableWidgetItem *i = role->currentItem(); + QTableWidgetItem *valid = 0; + for (int j = 0; roles[j].name.m; ++j) { + if (!valid && (ra < 0 || validrace(j, ra))) { + valid = role->item(j, 0); + break; + } } - if ( !validrace(role->currentRow(),ra) ) + if (!validrace(role->currentRow(), ra)) i = valid; role->setCurrentItem(i, 0); - for (j=0; roles[j].name.m; j++) { + for (int j = 0; roles[j].name.m; ++j) { item = role->item(j, 0); item->setSelected(item == i); - bool v = validrace(j,ra); - item->setFlags(v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable - : Qt::NoItemFlags); + /* used to call setFlags here, but setupOthers() -> selectGender() + (and selectAlignment()) -> populate_roles() takes care of that */ } nhUse(crow); nhUse(ccol); @@ -516,32 +583,30 @@ void NetHackQtPlayerSelector::selectRace(int crow, int ccol, { int ra = race->currentRow(); int ro = role->currentRow(); - if (ra == -1 || ro == -1) return; - QTableWidgetItem* item; - item = race->item(prow, 0); + if (ra == -1 || ro == -1) + return; + QTableWidgetItem *item = race->item(prow, 0); if (item != NULL) item->setSelected(false); #ifndef QT_CHOOSE_RACE_FIRST selectRole(crow, ccol, prow, pcol); #else - QTableWidgetItem* i=race->currentItem(); - QTableWidgetItem* valid=0; - int j; - for (j=0; races[j].noun; j++) { - bool v = validrace(ro,j); - item = race->item(j, 0); - item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); - if ( !valid && v ) valid = item; + QTableWidgetItem *i = race->currentItem(); + QTableWidgetItem *valid = 0; + for (int j = 0; races[j].noun; ++j) { + if (!valid && (ro < 0 || validrace(ro, j))) { + valid = race->item(j, 0); + break; + } } - if ( !validrace(ro,race->currentRow()) ) + if (!validrace(ro, race->currentRow())) i = valid; - for (j=0; races[j].noun; j++) { + for (int j = 0; races[j].noun; ++j) { item = race->item(j, 0); item->setSelected(item == i); - bool v = validrace(ro,j); - item->setFlags(v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable - : Qt::NoItemFlags); + /* used to call setFlags here, but setupOthers() -> selectGender() + (and selectAlignment()) -> populate_races() takes care of that */ } nhUse(crow); nhUse(ccol); @@ -593,11 +658,18 @@ void NetHackQtPlayerSelector::setupOthers() void NetHackQtPlayerSelector::selectGender(int i) { chosen_gend = i; + // if gender has changed, tiles and some role titles will change + populate_roles(); + populate_races(); } void NetHackQtPlayerSelector::selectAlignment(int i) { chosen_align = i; + // if alignment has changed, some roles or races may no longer be + // available and some previously excluded ones might become available + populate_roles(); + populate_races(); } void NetHackQtPlayerSelector::Quit() @@ -612,7 +684,8 @@ void NetHackQtPlayerSelector::Random() bool NetHackQtPlayerSelector::Choose() { - if (fully_specified_role) return true; + if (fully_specified_role) + return true; #if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). if ( qt_compact_mode ) { diff --git a/win/Qt/qt_plsel.h b/win/Qt/qt_plsel.h index 985b544dc..a30133711 100644 --- a/win/Qt/qt_plsel.h +++ b/win/Qt/qt_plsel.h @@ -24,6 +24,9 @@ public slots: void Randomize(); void plnamePlayVsQuit(); + void populate_roles(); + void populate_races(); + void selectName(const QString& n); void selectRole(int current, int, int previous, int); void selectRace(int current, int, int previous, int); @@ -43,6 +46,8 @@ private: bool fully_specified_role; int chosen_gend; int chosen_align; + int cleric_role_row; + int human_race_row; QPushButton *rand_btn; QPushButton *play_btn;