Allow hide/show of columns in Engine Output
authorH.G. Muller <h.g.muller@hccnet.nl>
Tue, 14 Jan 2014 13:46:47 +0000 (14:46 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Sat, 18 Jan 2014 23:00:04 +0000 (00:00 +0100)
A new persistent Boolean option -memoHeaders enables a new feature:
text headers are shown above the depth, score, nodes, time columns in the
engine output. Right-clicking them will subsequently hide the corresponding
data, and move the column header to above the PV in a 'not shown' list,
where it can be clicked again to re-open the column.
Configure maseter settings to switch -memoHeaders on by default.

args.h
backend.c
common.h
dialogs.c
engineoutput.c
xboard.conf.in
xboard.texi

diff --git a/args.h b/args.h
index d803e72..2bc0211 100644 (file)
--- a/args.h
+++ b/args.h
@@ -699,6 +699,7 @@ ArgDescriptor argDescriptors[] = {
   { "buttonColor", ArgString, (void *) &appData.buttonColor, XBOARD, (ArgIniType) "" },
   { "firstDrawDepth", ArgInt, (void *) &appData.drawDepth[0], FALSE, (ArgIniType) 0 },
   { "secondDrawDepth", ArgInt, (void *) &appData.drawDepth[1], FALSE, (ArgIniType) 0 },
+  { "memoHeaders", ArgBoolean, (void *) &appData.headers, TRUE, (ArgIniType) FALSE },
 
 #if ZIPPY
   { "zippyTalk", ArgBoolean, (void *) &appData.zippyTalk, FALSE, (ArgIniType) ZIPPY_TALK },
index ab34737..ec6b5fc 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -148,6 +148,7 @@ extern int gettimeofday(struct timeval *, struct timezone *);
 #endif
 #include "backendz.h"
 #include "evalgraph.h"
+#include "engineoutput.h"
 #include "gettext.h"
 
 #ifdef ENABLE_NLS
@@ -250,7 +251,6 @@ static int NonStandardBoardSize P((VariantClass v, int w, int h, int s));
 #endif
 
 ChessProgramState *WhitePlayer();
-void InsertIntoMemo P((int which, char *text)); // [HGM] kibitz: in engineo.c
 int VerifyDisplayMode P(());
 
 char *GetInfoFromComment( int, char * ); // [HGM] PV time: returns stripped comment
@@ -5647,6 +5647,9 @@ LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end, int pane)
        } else if(strstr(buf+lineStart, "exclude:") == buf+lineStart) { // exclude moves clicked
                ExcludeClick(origIndex - lineStart);
                return FALSE;
+       } else if(!strncmp(buf+lineStart, "dep\t", 4)) {                // column headers clicked
+               Collapse(origIndex - lineStart);
+               return FALSE;
        }
        ParsePV(buf+startPV, FALSE, gameMode != AnalyzeMode);
        *start = startPV; *end = index-1;
index f8a521a..96c060e 100644 (file)
--- a/common.h
+++ b/common.h
@@ -536,6 +536,7 @@ typedef struct {
     Boolean flipView;
     Boolean autoFlipView;
     char *cmailGameName; /* xboard only */
+    Boolean headers;
     Boolean alwaysPromoteToQueen;
     Boolean oldSaveStyle;
     Boolean oneClick;
index 1c6d1f4..fd68fb2 100644 (file)
--- a/dialogs.c
+++ b/dialogs.c
@@ -409,6 +409,7 @@ static Option generalOptions[] = {
 /* TRANSLATORS: the drop menu is used to drop a piece, e.g. during bughouse or editing a position */
 { 0,  0, 0, NULL, (void*) &appData.dropMenu, "", NULL, CheckBox, N_("Drop Menu") },
 { 0,  0, 0, NULL, (void*) &appData.variations, "", NULL, CheckBox, N_("Enable Variation Trees") },
+{ 0,  0, 0, NULL, (void*) &appData.headers, "", NULL, CheckBox, N_("Headers in Engine Output Window") },
 { 0,  0, 0, NULL, (void*) &appData.hideThinkingFromHuman, "", NULL, CheckBox, N_("Hide Thinking from Human") },
 { 0,  0, 0, NULL, (void*) &appData.highlightLastMove, "", NULL, CheckBox, N_("Highlight Last Move") },
 { 0,  0, 0, NULL, (void*) &appData.highlightMoveWithArrow, "", NULL, CheckBox, N_("Highlight with Arrow") },
index e22df5e..364b9eb 100644 (file)
@@ -90,6 +90,8 @@ static int  lastForwardMostMove[2] = { -1, -1 };
 static int  engineState[2] = { -1, -1 };
 static char lastLine[2][MSG_SIZ];
 static char header[2][MSG_SIZ];
+static char columnHeader[MSG_SIZ] = "dep\tscore\tnodes\ttime\n";
+static int  columnMask;
 
 #define MAX_VAR 400
 static int scores[MAX_VAR], textEnd[MAX_VAR], keys[MAX_VAR], curDepth[2], nrVariations[2];
@@ -222,6 +224,7 @@ SetProgramStats (FrontEndProgramStats * stats) // now directly called by back-en
     }
 
     if( clearMemo ) {
+        if(!appData.headers) columnHeader[0] = NULLCHAR;
         DoClearMemo(which); nrVariations[which] = 0;
         header[which][0] = NULLCHAR;
         if(gameMode == AnalyzeMode) {
@@ -230,12 +233,15 @@ SetProgramStats (FrontEndProgramStats * stats) // now directly called by back-en
             snprintf(header[which], MSG_SIZ, "\t%s viewpoint\t\tfewer / Multi-PV setting = %d / more\n",
                                        appData.whitePOV || appData.scoreWhite ? "white" : "mover", cps->option[multi].value);
          }
-          if(!which) snprintf(header[which]+strlen(header[which]), MSG_SIZ-strlen(header[which]), "%s", exclusionHeader);
+          if(!which) snprintf(header[which]+strlen(header[which]), MSG_SIZ-strlen(header[which]), "%s%s", exclusionHeader, columnHeader);
           InsertIntoMemo( which, header[which], 0);
-        } else
-        if(appData.ponderNextMove && lastLine[which][0]) {
+        } else {
+          snprintf(header[which], MSG_SIZ, "%s", columnHeader);
+          if(appData.ponderNextMove && lastLine[which][0]) {
             InsertIntoMemo( which, lastLine[which], 0 );
             InsertIntoMemo( which, "\n", 0 );
+          }
+          InsertIntoMemo( which, header[which], 0);
         }
     }
 
@@ -423,7 +429,7 @@ InsertionPoint (int len, EngineOutputData *ed)
                scores[n] = newScore;
        }
        nrVariations[n] += 2;
-      return offs + (gameMode == AnalyzeMode)*strlen(header[ed->which]);
+      return offs + strlen(header[ed->which]);
 }
 
 
@@ -517,6 +523,7 @@ UpdateControls (EngineOutputData *ed)
 
     /* Memo */
     if( ed->pv != 0 && *ed->pv != '\0' ) {
+        static char spaces[] = "            "; // [HGM] align: spaces for padding
         char s_nodes[24];
         char s_score[16];
         char s_time[24];
@@ -527,29 +534,39 @@ UpdateControls (EngineOutputData *ed)
 
         /* Nodes */
         if( ed->nodes < 1000000 ) {
-            snprintf( s_nodes, sizeof(s_nodes)/sizeof(s_nodes[0]), u64Display, ed->nodes );
+            int h = ed->nodes, i=0;
+            while(h > 0) h /= 10, i++; // [HGM] align: count digits; pad with 2 spaces for every missing digit
+            snprintf( s_nodes, sizeof(s_nodes)/sizeof(s_nodes[0]), u64Display "%s\t", ed->nodes, spaces + 2*i);
         }
         else {
-            snprintf( s_nodes, sizeof(s_nodes)/sizeof(s_nodes[0]), "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
+            snprintf( s_nodes, sizeof(s_nodes)/sizeof(s_nodes[0]), "%.1fM%s\t", u64ToDouble(ed->nodes) / 1000000.0,
+                      spaces + 8 + 2*(ed->nodes > 1e7));
         }
 
         /* Score */
         h = ((gameMode == AnalyzeMode && appData.whitePOV || appData.scoreWhite) && !WhiteOnMove(currentMove) ? -1 : 1) * ed->score;
+        if( h == 0 ) {
+         snprintf( s_score, sizeof(s_score)/sizeof(s_score[0]), "  0.00\t" );
+        } else
         if( h > 0 ) {
-         snprintf( s_score, sizeof(s_score)/sizeof(s_score[0]), "+%.2f", h / 100.0 );
+         snprintf( s_score, sizeof(s_score)/sizeof(s_score[0]), "+%.2f\t", h / 100.0 );
         }
         else {
-         snprintf( s_score, sizeof(s_score)/sizeof(s_score[0]), "%.2f", h / 100.0 );
+         snprintf( s_score, sizeof(s_score)/sizeof(s_score[0]), " %.2f\t", h / 100.0 );
         }
 
         /* Time */
-        snprintf( s_time, sizeof(s_time)/sizeof(s_time[0]), "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
+        snprintf( s_time, sizeof(s_time)/sizeof(s_time[0]), "%d:%02d.%02d\t", time_secs / 60, time_secs % 60, time_cent );
+
+        if(columnMask & 2) s_score[0] = NULLCHAR; // [HGM] hide: erase columns the user has hidden
+        if(columnMask & 4) s_nodes[0] = NULLCHAR;
+        if(columnMask & 8) s_time[0]  = NULLCHAR;
 
         /* Put all together... */
        if(ed->nodes == 0 && ed->score == 0 && ed->time == 0)
          snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%3d\t", ed->depth );
        else
-         snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time );
+         snprintf( buf, sizeof(buf)/sizeof(buf[0]), "%3d\t%s%s%s", ed->depth, s_score, s_nodes, s_time );
 
         /* Add PV */
         buflen = strlen(buf);
@@ -569,6 +586,35 @@ UpdateControls (EngineOutputData *ed)
     SetEngineColorIcon( ed->which );
 }
 
+static char *titles[] = { "score\t", "nodes\t", "time\t" };
+
+void
+Collapse(int n)
+{   // handle click on column headers, to hide / show them
+    int i, j, nr=0, m=~columnMask, Ncol=4;
+    for(i=0; columnHeader[i] && i<n; i++) nr += (columnHeader[i] == '\t');
+    if(!nr) return; // depth always shown, so clicks on it ignored
+    for(i=j=0; i<Ncol; i++) if(m & 1<<i) j++; // count hidden columns
+    if(nr < j) { // shown column clicked: hide it
+       for(i=j=0; i<Ncol; i++) if(m & 1<<i && j++ == nr) break;
+       columnMask |= 1<<i;
+    } else { // hidden column clicked: show it
+       m = ~m; nr -= j;
+       for(i=j=0; i<Ncol; i++) if(m & 1<<i && j++ == nr) break;
+       columnMask &= ~(1<<i);
+    }
+    // create new header line
+    strcpy(columnHeader, "dep\t");
+    m = ~columnMask;
+    for(i=j=1; i<Ncol; i++) if(m & 1<<i) strcat(columnHeader, titles[i-1]), j++;
+    if(j != Ncol) { // list hidden columns, so user ca click them
+       m = ~m; strcat(columnHeader, "(not shown:  ");
+       for(i=1; i<Ncol; i++) if(m & 1<<i) strcat(columnHeader, titles[i-1]);
+       strcat(columnHeader, ")");
+    }
+    strcat(columnHeader, "\n");
+}
+
 // [HGM] kibitz: write kibitz line; split window for it if necessary
 void
 OutputKibitz (int window, char *text)
index 4d312f4..7771371 100644 (file)
@@ -59,6 +59,7 @@
 -defaultTourneyName "Tourney_%y%M%d_%h%m.trn"
 -variations true
 -appendPV true
+-memoHeaders true
 ;
 ; PGN format & Game List
 ;
index 9e61977..3e4e002 100644 (file)
@@ -3289,6 +3289,14 @@ Default: False.
 When true, scores will always be printed from the white point-of-view, 
 rather than the side-to-move point-of-view.
 Default: False.
+@item -memoHeaders true|false
+@cindex memoHeaders, option
+When true, column headers will be displayed in the Engine Output window
+for the depth, score, time and nodes data.
+Right-clicking on these headers will hide or show the corresponding data.
+(Not intended for dynamic use, as already printed data of the current search
+will not be affected!)
+Defaul: False.
 @end table
 
 @node Adjudication Options