Qt paperdoll - tool tips used to describe items

New for Qt, moving the mouse over one of the slots in the paperdoll
inventory subset and letting it pause there will use Qt's tool tip
mechanism to give a description of the item under the pointer, if
there is one, or of what the slot would contain when there isn't.

So "e - uncursed leather gloves (being worn)" or "no gloves" when
the pointer is over the glove slot.  If you do something with the
keyboard to make the paperdoll change while the mouse is still
hovering, you'll need to move the pointer slightly to have Qt
recheck for tool tip at that spot.  It may be feasible to force
an immediate update, but I'm satisfied with how it's working.

Interestingly, you can move pointer and hover while yn_function()
has asked you to pick an inventory item and is waiting for an
answer.  Mostly useful for Take-off/Remove or #adjust.
This commit is contained in:
PatR
2020-10-14 16:06:25 -07:00
parent 42b466e87b
commit a0c6118c97
4 changed files with 149 additions and 37 deletions

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 <QHelpEvent *> (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)
{

View File

@@ -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_