]> granicus.if.org Git - nethack/commitdiff
daily Qt status window update...
authorPatR <rankin@nethack.org>
Thu, 19 Nov 2020 12:48:15 +0000 (04:48 -0800)
committerPatR <rankin@nethack.org>
Thu, 19 Nov 2020 12:48:15 +0000 (04:48 -0800)
Highlight changes to dungeon location or alignment in blue instead
of green or red since neither the old value nor the new can be
classified as better than the other.  Likewise when changing
between regular Hp and Xp (or Xp/Exp) to or from you-as-mon Hp and
HD when polymorph or rehumanization takes place.

When toggling Score On, start out highlighted in blue instead of
green.  When toggling it Off, don't highlight the blank space
where it had been in red.  At the moment there's a quirk here;
if it is highlighted in green (from recent change) or blue (from
having just been toggled on) at the time it gets toggled off, the
space stays green or blue until that highlight times out.  (It has
occurred to me that the bogus red highlight might have been added
to deliberately overwrite stale green highlights.  If so, a better
fix should be achievable.)

For the title (plname and rank or plname and monster-species),
capitalize the player name since core's botl() and at least some
other interfaces do that.

TODO:  toggling Exp needs work.  The field used for deciding
up/down changes gets swapped and the update in progress compares
apples and oranges.  [This wasn't an issue in the original Qt
implementation where Xp and Exp were two separate fields.]

win/Qt/qt_icon.cpp
win/Qt/qt_icon.h
win/Qt/qt_stat.cpp
win/Qt/qt_stat.h

index 388a1e500a38f770e56e9f90cb2151926b12d79f..19763cffb705a397405dcd0019dca30301df4f40 100644 (file)
@@ -7,7 +7,8 @@
 // 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
+//    for changes is all or nothing based on which field caller passes
+//    as the value to use for comparison.  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
@@ -19,6 +20,8 @@
 //    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.
+// FIXME:
+//  Every LabelledIcon duplicates hl_better, hl_worse, hl_changd.
 //
 
 extern "C" {
@@ -39,9 +42,9 @@ 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)
+    comp_mode(BiggerIsBetter),
+    prev_value(NoNum),
+    turn_count(-1L)
 {
     initHighlight();
 }
@@ -51,9 +54,9 @@ NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l,
     QWidget(parent),
     label(new QLabel(l,this)),
     icon(new QLabel(this)),
-    low_is_good(false),
-    prev_value(-123),
-    turn_count(-1)
+    comp_mode(BiggerIsBetter),
+    prev_value(NoNum),
+    turn_count(-1L)
 {
     setIcon(i);
     initHighlight();
@@ -61,12 +64,13 @@ NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l,
 
 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 }";
+    // note: string "green" is much darker than Qt::green
+    hl_better = "QLabel { background-color : green ; color : white }";
+    hl_worse  = "QLabel { background-color : red   ; color : white }";
+    hl_changd = "QLabel { background-color : blue  ; color : white }";
 }
 
-void NetHackQtLabelledIcon::setLabel(const QStringt, bool lower)
+void NetHackQtLabelledIcon::setLabel(const QString &t, bool lower)
 {
     if (!label) {
        label=new QLabel(this);
@@ -75,7 +79,12 @@ void NetHackQtLabelledIcon::setLabel(const QString& t, bool lower)
     if (label->text() != t) {
        label->setText(t);
         ForceResize();
-       highlight((lower == low_is_good) ? hl_good : hl_bad);
+        if (comp_mode != NoCompare) {
+            highlight((comp_mode == NeitherIsBetter) ? hl_changd
+                      : (comp_mode == (lower ? SmallerIsBetter
+                                             : BiggerIsBetter)) ? hl_better
+                        : hl_worse);
+        }
     }
 }
 
@@ -113,14 +122,19 @@ void NetHackQtLabelledIcon::setFont(const QFont& f)
     if (label) label->setFont(f);
 }
 
+// [pr] this might no longer be needed; it seems to have been responsible
+// for highlighting the blank space where an optional field like Score
+// was just toggled off; we don't need or want that anymore...
 void NetHackQtLabelledIcon::show()
 {
+    if (
 #if QT_VERSION >= 300
-    if (isHidden())
+        isHidden()
 #else
-    if (!isVisible())
+        !isVisible()
 #endif
-       highlight(hl_bad);
+        && comp_mode != NoCompare)
+       highlight(hl_worse);
     QWidget::show();
 }
 
@@ -156,41 +170,42 @@ QSize NetHackQtLabelledIcon::minimumSizeHint() const
 
 void NetHackQtLabelledIcon::highlightWhenChanging()
 {
-    turn_count=0;
+    turn_count = 0; // turn_count starts negative (as flag to not highlight)
 }
 
-void NetHackQtLabelledIcon::lowIsGood()
+// set comp_mode to one of NoCompare or {Bigger,Smaller,Neither}IsBetter
+void NetHackQtLabelledIcon::setCompareMode(int newmode)
 {
-    low_is_good=true;
+    comp_mode = newmode;
 }
 
-void NetHackQtLabelledIcon::dissipateHighlight()
+void NetHackQtLabelledIcon::unhighlight()
 {
-    if (turn_count>0) {
-       turn_count--;
-       if (!turn_count)
-           unhighlight();
+    if (label) { // Surely it is?!
+        label->setStyleSheet("");
     }
+    if (turn_count > 0)
+        turn_count = 0;
 }
 
 void NetHackQtLabelledIcon::highlight(const QString& hl)
 {
     if (label) { // Surely it is?!
-       if (turn_count>=0) {
-           label->setStyleSheet(hl);
-           turn_count=4;
-           // `4' includes this turn, so dissipates after
-           // 3 more keypresses.
-       } else {
-           label->setStyleSheet("");
-       }
+        if (turn_count >= 0) {
+            label->setStyleSheet(hl);
+            turn_count = 4;
+            // 4 includes this turn, so dissipates after 3 more keypresses.
+        } else {
+            unhighlight();
+        }
     }
 }
 
-void NetHackQtLabelledIcon::unhighlight()
+void NetHackQtLabelledIcon::dissipateHighlight()
 {
-    if (label) { // Surely it is?!
-       label->setStyleSheet("");
+    if (turn_count > 0) {
+        if (!--turn_count)
+            unhighlight();
     }
 }
 
index 56a24f0e1155bc7ecc4abaa76d1439207819f867..4542368968d890b425967c484f073686cefa437e 100644 (file)
@@ -9,13 +9,18 @@
 
 namespace nethack_qt_ {
 
+enum CompareMode {
+    NoCompare = -1, BiggerIsBetter = 0,
+    SmallerIsBetter = 1, NeitherIsBetter = 2
+};
+
 class NetHackQtLabelledIcon : public QWidget {
 public:
         NetHackQtLabelledIcon(QWidget *parent, const char *label);
         NetHackQtLabelledIcon(QWidget *parent, const char *label,
                               const QPixmap &icon);
 
-       enum { NoNum=-99999 };
+        enum { NoNum = -99999L };
         void setLabel(const QString &, bool lower=true); // string
         void setLabel(const QString &, long, const QString &tail=""); // number
         void setLabel(const QString &, long show_value,
@@ -25,7 +30,7 @@ public:
         //QString labelText() { return QString(this->label->text()); }
 
        void highlightWhenChanging();
-       void lowIsGood();
+        void setCompareMode(int newmode);
        void dissipateHighlight();
         void ForceResize();
 
@@ -45,11 +50,13 @@ private:
        void highlight(const QString& highlight);
        void unhighlight();
 
-       bool low_is_good;
-       int prev_value;
-       int turn_count;         /* last time the value changed */
-       QString hl_good;
-       QString hl_bad;
+        int comp_mode;          /* compareMode; default is BiggerIsBetter */
+        long prev_value;
+        long turn_count;        /* last time the value changed */
+
+        QString hl_better;
+        QString hl_worse;
+        QString hl_changd;
 };
 
 } // namespace nethack_qt_
index 133655e863a251e920f129826ee0736247fa0915..f76612b2290ef9582be3d5f97ab539670c40639a 100644 (file)
 //      five status fields without icons (some containing two values:
 //        HP/HPmax, Energy/Enmax, AC, XpLevel/ExpPoints or HD, [blank], Gold)
 //      separator line
-//      optional line with two text fields (Time:1234, Score:89)
+//      line with two optional text fields (Time:1234, Score:89), maybe blank
 //      varying number of icons (one or more, each paired with...)
 //      corresponding text (Alignment plus zero or more status conditions
 //        including Hunger if not "normal" and encumbrance if not "normal")
 //
 // The hitpoint bar spans the width of the status window when enabled.
 // Title and location are centered.
-// The icons and text for the size characteristics are evenly spaced.
-// The five main stats are padded with an empty sixth and spaced to
-//   match the characteristics.
-// Time and Score are spaced as if each were three fields wide.
+// The icons and text for the six characteristics are evenly spaced;
+//   this pair of lines is sometimes referred to as "row 1" below.
+// The five main stats or slash-separated stat pairs are padded with an
+//   empty slot between Xp and Gold; adding the sixth makes that row
+//   line up with the characteristics; this line is sometimes referred
+//   to as "row 2".
+// Time and Score are spaced as if each were three fields wide; their
+//   line is "row 3" relative to statuslines:2 vs statuslines:3.
 // Icons and texts for alignment and conditions are left justified.
 // The separator lines are thin and don't take up much vertical space.
 // When enabled, the hitpoint bar bisects the margin above Title,
 //   increasing the overall status height by 9 pixels; when disabled,
 //   the status shifts up by those 9 pixels.
-// When Time+Score line is empty, it still takes up the vertical space
-//   that would be used to show those values.
+// When row 3 (Time, Score) is blank, it still takes up the vertical
+//   space that would be used to show those values.
+//
+// The above is for statuslines:3, which used to be the default.  For
+//   statuslines:2, rows 1 and 2 are extended from six to seven fields
+//   and row 3 (optional Time, Score) is eliminated.  Alignment is
+//   moved from the beginning of the Conditions pair (icon over text)
+//   of lines up to the end of row 1, the Characteristics pair of lines,
+//   with a separator between Cha:NN and it.  Time, when active, is
+//   placed after Gold.  Score, if enabled and active, is shown in the
+//   filler slot before Gold.  When there are no Conditions to display,
+//   there is an an invisible fake one (blank icon over blank text)
+//   rendered in order to preserve the vertical space they need.
 //
 // FIXME:
 //  When hitpoint bar is shown, attempting to resize horizontally won't
 //    style sheets used to control color, but removing those constraints
 //    causes the bar display to get screwed up.)
 //  There are separate icons for Satiated and Hungry, but Weak, Fainting,
-//    and Fainted all share the Hungry one when they should be different.
+//    and Fainted all share the Hungry one.  Weak should have its own,
+//    Fainting+Fainted should have another.  The current two depict
+//    plates with cutlery which is a bit of an anachronism.  Statiated
+//    could be replaced by a figure in profile with a bulging belly,
+//    Hungry similar but with a slightly concave belly, Weak either a
+//    collapsing figure or a much larger concavity or both, Fainting/
+//    Fainted a fully collapsed figure.
 //
 // TODO:
 //  If/when status conditions become too wide for the status window, scale
 //    the rest of status.  That takes up more space, which is ok, but it
 //    also increases the vertical margin in between them by more than is
 //    necessary.  Should squeeze some of that excess blank space out.
-//  Changed values are highlighted as "gone Up" (green) or "gone Down" (red)
-//    with NetHackQtLabelledIcon::setLabel() taking an optional boolean
-//    argument indicating "lower is better" (for AC).  That flag should
-//    have other choices:  "changed" (third color with no better or worse
-//    judgement, for alignment and dungeon location) and "ignore" (don't
-//    highlight, to suppress the bogus highlighting that currently happens
-//    when toggling 'showexp' or 'showscore').
+//  Highlighting of Xp/Exp needs work when 'showexp' is toggled On or Off.
+//    The field passed to xp.setLabel() for its better vs worse comparison
+//    gets swapped from Xp to Exp or vice versa, yielding a nonsensical
+//    comparison for the first status update after the 'showexp' toggle.
+//  Toggling 'showscore' while Score is highlighted leaves the highlight
+//    on blank space until it times out.  (Time isn't highlighted and Exp
+//    is combined with Xp so always updated; only Score is affected.)
 //
 
 extern "C" {
@@ -132,7 +153,10 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() :
     /* miscellaneous; not display fields */
     cursy(0),
     first_set(true),
-    alreadyfullhp(false)
+    alreadyfullhp(false),
+    was_polyd(false),
+    had_exp(false),
+    had_score(false)
 {
     if (!qt_compact_mode) {
         int w = NetHackQtBind::mainWidget()->width();
@@ -502,7 +526,7 @@ void NetHackQtStatusWindow::fadeHighlighting()
     level.dissipateHighlight();
     align.dissipateHighlight();
 
-    time.dissipateHighlight();
+    //time.dissipateHighlight();
     score.dissipateHighlight();
 
     hunger.dissipateHighlight();
@@ -665,12 +689,19 @@ void NetHackQtStatusWindow::HitpointBar()
 void NetHackQtStatusWindow::updateStats()
 {
     if (!parentWidget()) return;
+    if (cursy != 0) return; /* do a complete update when line 0 is done */
 
     QString buf;
-    const char *text;
-
-    if (cursy != 0) return;    /* do a complete update when line 0 is done */
 
+    if (first_set) {
+        was_polyd = Upolyd ? true : false;
+        had_exp = ::flags.showexp ? true : false;
+        // not '#ifndef SCORE_ON_BOTL' here; use the variable and the widget
+        had_score = ::flags.showscore ? true : false; // false when disabled
+        score.setLabel(""); // init if enabled, one-time set if disabled
+    }
+    // display hitpoint bar if it is active; it isn't subject to field
+    // highlighting so we don't track whether it has just been toggled On|Off
     HitpointBar();
 
     int st = ACURR(A_STR);
@@ -747,18 +778,23 @@ void NetHackQtStatusWindow::updateStats()
        buf = rank_of(u.ulevel, g.pl_character[0], ::flags.female);
     }
     QString buf2;
-    buf2.sprintf("%s the %s", g.plname, buf.toLatin1().constData());
+    char buf3[BUFSZ];
+    buf2.sprintf("%s the %s", upstart(strcpy(buf3, g.plname)),
+                 buf.toLatin1().constData());
     name.setLabel(buf2, NetHackQtLabelledIcon::NoNum, u.ulevel);
 
-    char buf3[BUFSZ];
     if (!describe_level(buf3)) {
        Sprintf(buf3, "%s, level %d",
                 g.dungeons[u.uz.dnum].dname, ::depth(&u.uz));
     }
-    // false: always highlight as 'change for the better' regardless of
-    // new depth compared to old
-    dlevel.setLabel(buf3, false);
+    dlevel.setLabel(buf3);
 
+    int poly_toggled = !was_polyd ^ !Upolyd;
+    if (poly_toggled) {
+        // for this update, changed values aren't better|worse, just different
+        hp.setCompareMode(NeitherIsBetter);
+        level.setCompareMode(NeitherIsBetter);
+    }
     if (Upolyd) {
         // You're a monster!
         buf.sprintf("/%d", u.mhmax);
@@ -773,6 +809,9 @@ void NetHackQtStatusWindow::updateStats()
         // 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
+#if 0   /* not yet */
+        int exp_toggled = !had_exp ^ !::flags.showexp;
+#endif
         static const char *const lvllbl[3] = { "Level:", "Lvl:", "L:" };
         QFontMetrics fm(level.label->font());
         for (int i = ::flags.showexp ? 0 : 3; i < 4; ++i) {
@@ -792,6 +831,14 @@ void NetHackQtStatusWindow::updateStats()
                        // Exp for setLabel()'s Up|Down highlighting
                        ::flags.showexp ? u.uexp : (long) u.ulevel);
     }
+    if (poly_toggled) {
+        // for next update, changed values will be better|worse as usual
+        hp.setCompareMode(BiggerIsBetter);
+        level.setCompareMode(BiggerIsBetter);
+    }
+    was_polyd = Upolyd ? true : false;
+    had_exp = (::flags.showexp && !was_polyd) ? true : false;
+
     buf.sprintf("/%d", u.uenmax);
     power.setLabel("Pow:", (long) u.uen, buf);
     ac.setLabel("AC:", (long) u.uac);
@@ -802,7 +849,7 @@ void NetHackQtStatusWindow::updateStats()
     goldamt = std::min(goldamt, 99999999L); // ditto
     gold.setLabel("Gold:", goldamt);
 
-    text = NULL;
+    const char *text = NULL;
     if (u.ualign.type == A_LAWFUL) {
         align.setIcon(p_lawful);
         text = "Lawful";
@@ -816,14 +863,10 @@ void NetHackQtStatusWindow::updateStats()
                : (u.ualign.type == A_NONE) ? "unaligned"
                  : "other?";
     }
-    if (text) {
-        // false: don't highlight as 'became lower' even if the internal
-        // numeric value is becoming lower (N -> C, L -> N || C)
-        align.setLabel(text, false);
-        // without this, the ankh pixmap shifts from centered to left
-        // justified relative to the label text for some unknown reason...
-        align.ForceResize();
-    }
+    align.setLabel(QString(text));
+    // without this, the ankh pixmap shifts from centered to left
+    // justified relative to the label text for some unknown reason...
+    align.ForceResize();
     if (spreadout)
         ++k; // when not condensed, Alignment is shown on the Conditions row
 
@@ -832,6 +875,8 @@ void NetHackQtStatusWindow::updateStats()
     } else
         blank2.hide();
 
+    // Time isn't highlighted (due to constantly changing) so we don't keep
+    // track of whether it has just been toggled On or Off
     if (::flags.time) {
         // hypothetically Time could grow to enough digits to have trouble
         // fitting, but it's not worth worrying about
@@ -840,7 +885,10 @@ void NetHackQtStatusWindow::updateStats()
         time.setLabel("");
     }
 #ifdef SCORE_ON_BOTL
+    int score_toggled = !had_score ^ !::flags.showscore;
     if (::flags.showscore) {
+        if (score_toggled) // toggled On
+            score.setCompareMode(NeitherIsBetter);
         long pts = botl_score();
         if (spreadout) {
             // plenty of room; Time and Score both have the width of 3 fields
@@ -863,17 +911,26 @@ void NetHackQtStatusWindow::updateStats()
             // set statuslines:3 to take advantage of the extra room that
             // the spread out status layout provides)
         }
-    } else
-#endif
-    {
-       score.setLabel("");
+    } else {
+        if (score_toggled) { // toggled Off; if already Off, no need to set ""
+            score.setCompareMode(NoCompare);
+            score.setLabel(""); // blank when not active
+        }
     }
+    if (score_toggled)
+        score.setCompareMode(BiggerIsBetter);
+    had_score = ::flags.showscore ? true : false;
+#endif /* SCORE_ON_BOTL */
 
     if (first_set) {
        first_set=false;
 
+        was_polyd = Upolyd ? true : false;
+        had_exp = ::flags.showexp ? true : false;
+        had_score = ::flags.showscore ? true : false;
+
        name.highlightWhenChanging();
-       dlevel.highlightWhenChanging();
+       dlevel.highlightWhenChanging(); dlevel.setCompareMode(NeitherIsBetter);
 
        str.highlightWhenChanging();
        dex.highlightWhenChanging();
@@ -884,15 +941,16 @@ void NetHackQtStatusWindow::updateStats()
 
        hp.highlightWhenChanging();
        power.highlightWhenChanging();
-       ac.highlightWhenChanging(); ac.lowIsGood();
+       ac.highlightWhenChanging(); ac.setCompareMode(SmallerIsBetter);
        level.highlightWhenChanging();
        gold.highlightWhenChanging();
 
         // don't highlight 'time' because it changes almost continuously
-        //time.highlightWhenChanging();
+        // [if we did highlight it, we wouldn't show increase as 'Better']
+        //time.highlightWhenChanging(); time.setCompareMode(NeitherIsBetter);
        score.highlightWhenChanging();
 
-       align.highlightWhenChanging();
+       align.highlightWhenChanging(); align.setCompareMode(NeitherIsBetter);
 
        hunger.highlightWhenChanging();
        encumber.highlightWhenChanging();
index 4f24c70278a69a33881fec69cfa06978df065846..a24028569ce18b1cd3ae76eb4bb2746f79fd668d 100644 (file)
@@ -138,6 +138,12 @@ private:
 
        bool first_set;
         bool alreadyfullhp;
+        bool was_polyd;
+        bool had_exp;
+        // Time isn't highlighted (due to constantly changing) so we don't
+        // keep track of whether it was On and is now Off or vice versa
+        //bool had_time;
+        bool had_score;
 
         QHBoxLayout *InitHitpointBar();
         void HitpointBar();