diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 0aff91687..905af1491 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.329 $ $NHDT-Date: 1602669770 2020/10/14 10:02:50 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.330 $ $NHDT-Date: 1602716771 2020/10/14 23:06:11 $ General Fixes and Modified Features ----------------------------------- @@ -575,6 +575,8 @@ Qt: the "paper doll" inventory subset can be controlled via the "Qt Settings" dialog box ("Preferences..." on OSX) Qt: draw a border around each tile in the paper doll inventory; when BUC is known for a doll item, change the border's color and thicken it +Qt: letting the mouse hover over the paper doll shows a tool tip describing + the object--or lack of same--in the slot under the pointer Qt: clicking on the paper doll runs the #seeall command (inventory of wielded and worn items plus tools [lamps, leashes] actively in use; in other words, same set of things whose tiles are used to populate the doll) diff --git a/win/Qt/qt_glyph.cpp b/win/Qt/qt_glyph.cpp index 1585d9ca9..7edbefa99 100644 --- a/win/Qt/qt_glyph.cpp +++ b/win/Qt/qt_glyph.cpp @@ -101,8 +101,9 @@ void NetHackQtGlyphs::drawBorderedCell(QPainter& painter, int glyph, { int wd = width(), ht = height(), + yoffset = 1, // tiny extra margin at top lox = cellx * (wd + 2), - loy = celly * (ht + 2); + loy = celly * (ht + 2) + yoffset; drawGlyph(painter, glyph, lox + 1, loy + 1); diff --git a/win/Qt/qt_inv.cpp b/win/Qt/qt_inv.cpp index 5379a33fa..0139a56f1 100644 --- a/win/Qt/qt_inv.cpp +++ b/win/Qt/qt_inv.cpp @@ -43,10 +43,25 @@ NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) : QWidget(parent) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + // needed to enable tool tips + setMouseTracking(true); + + for (int x = 0; x <= 2; ++x) + for (int y = 0; y <= 5; ++y) + tips[x][y] = NULL; } -void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, - int x, int y, bool canbe) +NetHackQtInvUsageWindow::~NetHackQtInvUsageWindow() +{ + for (int x = 0; x <= 2; ++x) + for (int y = 0; y <= 5; ++y) + if (tips[x][y]) + free((void *) tips[x][y]), tips[x][y] = NULL; +} + +void NetHackQtInvUsageWindow::drawWorn(QPainter &painter, obj *nhobj, + int x, int y, // cell index, not pixels + const char *alttip, bool canbe) { short int glyph; int border; @@ -54,16 +69,39 @@ void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, if (nhobj) { border = BORDER_DEFAULT; #ifdef ENHANCED_PAPERDOLL + // color margin around cell containing item whose BUC state is known if (Role_if('P') && !Blind) nhobj->bknown = 1; if (nhobj->bknown) border = nhobj->cursed ? BORDER_CURSED : !nhobj->blessed ? BORDER_UNCURSED : BORDER_BLESSED; + + // set up a tool tip describing the item that will be displayed here + char *itmnam = xprname(nhobj, (char *) 0, nhobj->invlet, TRUE, 0L, 0L); + if (tips[x][y] && strlen(itmnam) > strlen(tips[x][y])) + free((void *) tips[x][y]), tips[x][y] = NULL; + + if (tips[x][y]) + Strcpy(tips[x][y], itmnam); + else + tips[x][y] = dupstr(itmnam); #endif glyph = obj_to_glyph(nhobj, rn2_on_display_rng); } else { border = NO_BORDER; +#ifdef ENHANCED_PAPERDOLL + // caller passes an alternative tool tip for empty cells + if (tips[x][y] && (!alttip || strlen(alttip) > strlen(tips[x][y]))) + free((void *) tips[x][y]), tips[x][y] = NULL; + + if (tips[x][y]) // above guarantees that test fails if alttip is Null + Strcpy(tips[x][y], alttip); + else if (alttip) + tips[x][y] = dupstr(alttip); +#else + nhUse(alttip); +#endif glyph = canbe ? cmap_to_glyph(S_room) : GLYPH_UNEXPLORED; } qt_settings->glyphs().drawBorderedCell(painter, glyph, x, y, border); @@ -92,51 +130,66 @@ void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) qt_settings->doll_is_shown = false; if (!qt_settings->doll_is_shown) return; + // set glyphs() for the paperdoll; might be different size than map's qt_settings->glyphs().setSize(qt_settings->dollWidth, qt_settings->dollHeight); + + /* for drawWorn()'s use of obj->invlet */ + if (!flags.invlet_constant) + reassign(); #endif QPainter painter; painter.begin(this); - // Blanks - drawWorn(painter, 0, 0, 5, false); - drawWorn(painter, 0, 2, 5, false); - if (u.twoweap) // empty alt weapon slot, show uswapwep in shield slot - drawWorn(painter, 0, 0, 0, false); - - // TODO: render differently if known to be non-removable (known cursed) - drawWorn(painter, uarm, 1, 3); // Armour - drawWorn(painter, uarmc, 1, 2); // Cloak - drawWorn(painter, uarmh, 1, 0); // Helmet - // shield slot varies depending upon weapon usage - if (u.twoweap) - drawWorn(painter, uswapwep, 0, 1); // Secondary weapon, in use - else if (uwep && bimanual(uwep)) - drawWorn(painter, uwep, 0, 1); // Two-handed weapon shown twice + // String argument is for a tool tip when the object in question is Null. + // + // left column + /* uswapwep slot varies depending upon dual-wielding state; + shown in shield slot when actively wielded, so uswapwep slot is empty + then and an alternate tool tip is used to explain that emptiness */ + if (!u.twoweap) + drawWorn(painter, uswapwep, 0, 0, "no alternate weapon"); else - drawWorn(painter, uarms, 0, 1); // Shield (might be blank) - drawWorn(painter, uarmg, 0, 2); // Gloves - drawWorn(painter, uarmf, 1, 5); // Shoes (feet) - drawWorn(painter, uarmu, 1, 4); // Undershirt - drawWorn(painter, uleft, 0, 3); // RingL - drawWorn(painter, uright, 2, 3); // RingR + drawWorn(painter, NULL, 0, 0, "secondary weapon is wielded"); + /* shield slot varies depending upon weapon usage; + no alt tool tip is needed for first two cases because object will + never be Null when the corresponding tests pass */ + if (u.twoweap) + drawWorn(painter, uswapwep, 0, 1, NULL); // secondary weapon, in use + else if (uwep && bimanual(uwep)) + drawWorn(painter, uwep, 0, 1, NULL); // two-handed uwep shown twice + else + drawWorn(painter, uarms, 0, 1, "no shield"); + drawWorn(painter, uarmg, 0, 2, "no gloves"); + drawWorn(painter, uleft, 0, 3, "no left ring"); + /* light source and leash aren't unique and don't have pointers defined */ + drawWorn(painter, find_tool(LEASH), 0, 4, "no leashes in use"); + drawWorn(painter, NULL, 0, 5, NULL, false); // always blank - drawWorn(painter, uwep, 2, 1); // Weapon - drawWorn(painter, !u.twoweap ? uswapwep : NULL, 0, 0); // Alternate weapon - drawWorn(painter, uquiver, 2, 2); // Quiver - drawWorn(painter, uamul, 1, 1); // Amulet - drawWorn(painter, ublindf, 2, 0); // Blindfold/Towel/Lenses + // middle column; no unused slots + drawWorn(painter, uarmh, 1, 0, "no helmet"); + drawWorn(painter, uamul, 1, 1, "no amulet"); + drawWorn(painter, uarmc, 1, 2, "no cloak"); + drawWorn(painter, uarm, 1, 3, "no suit"); + drawWorn(painter, uarmu, 1, 4, "no shirt"); + drawWorn(painter, uarmf, 1, 5, "no boots"); - // light source and leash aren't unique and don't have pointers defined - drawWorn(painter, find_tool(LEASH), 0, 4); - // OIL_LAMP matches lit candles, lamps, lantern, and candelabrum (and will - // also duplicate Sunsword when it is wielded and shown in the uwep slot) - drawWorn(painter, find_tool(OIL_LAMP), 2, 4); + // right column + drawWorn(painter, ublindf, 2, 0, "no eyewear"); // blindfold/towel/lenses + drawWorn(painter, uwep, 2, 1, "no weapon"); + drawWorn(painter, uquiver, 2, 2, "nothing readied for firing"); // quiver + drawWorn(painter, uright, 2, 3, "no right ring"); + /* OIL_LAMP matches lit candles, lamps, lantern, and candelabrum + (and might also duplicate Sunsword when it is wielded--hence lit-- + depending upon whether another light source precedes it in invent) */ + drawWorn(painter, find_tool(OIL_LAMP), 2, 4, "no active light sources"); + drawWorn(painter, NULL, 2, 5, NULL, false); // always blank painter.end(); #ifdef ENHANCED_PAPERDOLL + // reset glyphs() to the ones being used for the map qt_settings->glyphs().setSize(qt_settings->tileWidth, qt_settings->tileHeight); #endif @@ -145,7 +198,7 @@ void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) QSize NetHackQtInvUsageWindow::sizeHint(void) const { if (qt_settings) { - int w = 0, h = 0; + int w = 0, h = 1; // one pixel margin at top // 1+X+1: one pixel border surrounding each tile in the paper doll, // so +1 left and +1 right, also +1 above and +1 below #ifdef ENHANCED_PAPERDOLL @@ -167,6 +220,56 @@ QSize NetHackQtInvUsageWindow::sizeHint(void) const } } +// ENHANCED_PAPERDOLL - called when a tool tip is triggered by hovering mouse +bool NetHackQtInvUsageWindow::tooltip_event(QHelpEvent *tipevent) +{ +#ifdef ENHANCED_PAPERDOLL + if (iflags.wc_ascii_map) + qt_settings->doll_is_shown = false; + if (!qt_settings->doll_is_shown) { + tipevent->ignore(); + return false; + } + int wd = qt_settings->dollWidth, + ht = qt_settings->dollHeight; + + // inverse of drawBorderedCell(); + int yoffset = 1, // tiny extra margin at top + ex = tipevent->pos().x(), + ey = tipevent->pos().y() - yoffset, + // KISS: treat 1-pixel margin around cells as part of enclosed cell + cellx = ex / (wd + 2), + celly = ey / (ht + 2); + + const char *tip = (cellx >= 0 && cellx <= 2 && celly >= 0 && celly <= 5) + ? tips[cellx][celly] : NULL; + if (tip && *tip) { + QToolTip::showText(tipevent->globalPos(), QString(tip)); + } else { + QToolTip::hideText(); + tipevent->ignore(); + } +#else + nhUse(tipevent); +#endif /* ENHANCED_PAPERDOLL */ + return true; +} + +// ENHANCED_PAPERDOLL - event handler is necessary to support tool tips +bool NetHackQtInvUsageWindow::event(QEvent *event) +{ +#ifdef ENHANCED_PAPERDOLL + if (event->type() == QEvent::ToolTip) { + QHelpEvent *tipevent = static_cast (event); + return tooltip_event(tipevent); + } +#endif + // with this routine intercepting events, we need to pass along + // paint and mouse-press events to have them handled + return QWidget::event(event); + +} + // ENHANCED_PAPERDOLL - clicking on the PaperDoll runs #seeall ('*') void NetHackQtInvUsageWindow::mousePressEvent(QMouseEvent *event UNUSED) { diff --git a/win/Qt/qt_inv.h b/win/Qt/qt_inv.h index 9c38128c5..2566c8f79 100644 --- a/win/Qt/qt_inv.h +++ b/win/Qt/qt_inv.h @@ -13,14 +13,20 @@ namespace nethack_qt_ { class NetHackQtInvUsageWindow : public QWidget { public: NetHackQtInvUsageWindow(QWidget* parent); + virtual ~NetHackQtInvUsageWindow(); virtual void paintEvent(QPaintEvent*); virtual QSize sizeHint(void) const; protected: + virtual bool event(QEvent *event); virtual void mousePressEvent(QMouseEvent *event); private: - void drawWorn(QPainter& painter, obj*, int x, int y, bool canbe=true); + void drawWorn(QPainter &painter, obj *nhobj, int x, int y, + const char *alttip, bool canbe=true); + bool tooltip_event(QHelpEvent *tipevent); + + char *tips[3][6]; // PAPERDOLL is a grid of 3x6 cells for tiles }; } // namespace nethack_qt_