// Qt4 conversion copyright (c) Ray Chason, 2012-2014.
// NetHack may be freely redistributed. See license for details.
-// qt_icon.cpp -- a labelled icon
+// qt_icon.cpp -- a labelled icon for display in the status window
+//
+// TODO?
+// When the label specifies two values separated by a slash (curHP/maxHP,
+// curEn/maxEn, XpLevel/ExpPoints when 'showexp' is On), highlighting
+// for changes is all or nothing. curHP and curEn go up and down
+// without any change to the corresponding maximum all the time. Much
+// rarer, but when maxHP and maxEn go up with level gain, the hero
+// could be injured by a passive counterattack or collateral damage
+// from an area effect--or much simpler, the casting cost of a spell
+// that killed a monster and produced the level gain--so the current
+// value could stay the same or even go down at same time max goes up.
+// Likewise, Exp goes up a lot but Xp relatively rarely. (On the very
+// rare occasions where either goes down, they'll both do so.)
+// Highlighting two slash-separated values independently would be
+// worthwhile but with the 'single label using a style sheet for color'
+// approach it isn't going to happen.
+//
extern "C" {
#include "hack.h"
namespace nethack_qt_ {
-NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) :
+NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l) :
QWidget(parent),
+ label(new QLabel(l,this)),
+ icon(NULL),
low_is_good(false),
prev_value(-123),
- turn_count(-1),
- label(new QLabel(l,this)),
- icon(0)
+ turn_count(-1)
{
initHighlight();
}
-NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) :
+NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l,
+ const QPixmap &i) :
QWidget(parent),
+ label(new QLabel(l,this)),
+ icon(new QLabel(this)),
low_is_good(false),
prev_value(-123),
- turn_count(-1),
- label(new QLabel(l,this)),
- icon(new QLabel(this))
+ turn_count(-1)
{
setIcon(i);
initHighlight();
void NetHackQtLabelledIcon::initHighlight()
{
+ // note: named 'green' is much darker than Qt::green
hl_good = "QLabel { background-color : green; color : white }";
hl_bad = "QLabel { background-color : red ; color : white }";
}
class NetHackQtLabelledIcon : public QWidget {
public:
- NetHackQtLabelledIcon(QWidget* parent, const char* label);
- NetHackQtLabelledIcon(QWidget* parent, const char* label, const QPixmap& icon);
+ NetHackQtLabelledIcon(QWidget *parent, const char *label);
+ NetHackQtLabelledIcon(QWidget *parent, const char *label,
+ const QPixmap &icon);
enum { NoNum=-99999 };
- void setLabel(const QString&, bool lower=true); // a string
- void setLabel(const QString&, long, const QString& tail=""); // a number
- void setLabel(const QString&, long show_value, long comparative_value, const QString& tail="");
- void setIcon(const QPixmap&);
- virtual void setFont(const QFont&);
+ void setLabel(const QString &, bool lower=true); // string
+ void setLabel(const QString &, long, const QString &tail=""); // number
+ void setLabel(const QString &, long show_value,
+ long comparative_value, const QString &tail="");
+ void setIcon(const QPixmap &);
+ virtual void setFont(const QFont &);
+ //QString labelText() { return QString(this->label->text()); }
void highlightWhenChanging();
void lowIsGood();
virtual QSize sizeHint() const;
virtual QSize minimumSizeHint() const;
+ QLabel *label;
+ QLabel *icon;
+
protected:
void resizeEvent(QResizeEvent*);
int turn_count; /* last time the value changed */
QString hl_good;
QString hl_bad;
-
- QLabel* label;
- QLabel* icon;
};
} // namespace nethack_qt_
buf.sprintf("/%d", u.uhpmax);
hp.setLabel("HP:", std::max((long) u.uhp, 0L), buf);
// if Exp points are to be displayed, append them to Xp level;
- // up/down highlighting becomes tricky--don't try very hard
- if (::flags.showexp) {
- buf.sprintf("%ld/%ld", (long) u.ulevel, (long) u.uexp);
- // at levels above 20, "Level:NN/nnnnnnnn" doesn't fit so
- // shorten "Level" to "Lvl" at that stage;
- // at level 30, a few pixels are truncated from the start
- // and end of "Lvl:30/nnnnnnnnn" but the result is ledgible
- level.setLabel(((u.ulevel <= 20) ? "Level:" : "Lvl:") + buf,
- NetHackQtLabelledIcon::NoNum, (long) u.uexp);
- } else {
- level.setLabel("Level:", (long) u.ulevel);
+ // up/down highlighting becomes tricky--don't try very hard;
+ // depending upon font size and status layout, "Level:NN/nnnnnnnn"
+ // might be too wide to fit
+ static const char *const lvllbl[3] = { "Level:", "Lvl:", "L:" };
+ QFontMetrics fm(level.label->font());
+ int startingpass = ::flags.showexp ? 0 : 3;
+ for (int i = startingpass; i < 6; ++i) {
+ // passes 0,1,2 are with Exp, 3,4,5 without (3 should always fit)
+ if (i < 3) {
+ buf.sprintf("%s%ld/%ld", lvllbl[i],
+ (long) u.ulevel, (long) u.uexp);
+ level.setLabel(buf, NetHackQtLabelledIcon::NoNum,
+ (long) u.uexp);
+ } else {
+ buf.sprintf("%s%ld", lvllbl[i - 3], (long) u.ulevel);
+ level.setLabel(buf, NetHackQtLabelledIcon::NoNum,
+ (long) u.ulevel);
+ }
+ // 2: allow a couple of pixels at either end to be clipped off
+ if (fm.size(0, buf).width() <= (2 + level.width() + 2))
+ break;
}
}
buf.sprintf("/%d", u.uenmax);
} else
blank2.hide();
- if (::flags.time)
+ if (::flags.time) {
+ // hypothetically Time could grow to enough digits to have trouble
+ // fitting, but it's not worth worrying about
time.setLabel("Time:", (long) g.moves);
- else
+ } else {
time.setLabel("");
+ }
#ifdef SCORE_ON_BOTL
if (::flags.showscore) {
- score.setLabel("Score:", (long) botl_score());
+ long pts = botl_score();
+ if (spreadout) {
+ // plenty of room; Time and Score both have the width of 3 fields
+ score.setLabel("Score:", pts);
+ } else {
+ // depending upon font size and status layout, "Score:nnnnnnnn"
+ // might be too wide to fit (simpler version of Level:NN/nnnnnnnn)
+ static const char *const scrlbl[3] = { "Score:", "Scr:", "S:" };
+ QFontMetrics fm(score.label->font());
+ for (int i = 0; i < 3; ++i) {
+ buf.sprintf("%s%ld", scrlbl[i], pts);
+ score.setLabel(buf, NetHackQtLabelledIcon::NoNum, pts);
+ // 2: allow a couple of pixels at either end to be clipped off
+ if (fm.size(0, buf).width() <= (2 + score.width() + 2))
+ break;
+ }
+ // with Xp/Exp, we fallback to Xp if the shortest label prefix
+ // is still too long; here we just show a clipped value and
+ // let user either live with it or turn 'showscore' off (or
+ // set statuslines:3 to take advantage of the extra room that
+ // the spread out status layout provides)
+ }
} else
#endif
{