From 38d1b8471964ebf9d4da576d74a452dc3a12b057 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Tue, 14 Jan 2014 14:46:47 +0100 Subject: [PATCH] Allow hide/show of columns in Engine Output 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 | 1 + backend.c | 5 +++- common.h | 1 + dialogs.c | 1 + engineoutput.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++-------- xboard.conf.in | 1 + xboard.texi | 8 ++++++ 7 files changed, 72 insertions(+), 11 deletions(-) diff --git a/args.h b/args.h index d803e72..2bc0211 100644 --- 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 }, diff --git a/backend.c b/backend.c index ab34737..ec6b5fc 100644 --- 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; diff --git a/common.h b/common.h index f8a521a..96c060e 100644 --- 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; diff --git a/dialogs.c b/dialogs.c index 1c6d1f4..fd68fb2 100644 --- 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") }, diff --git a/engineoutput.c b/engineoutput.c index e22df5e..364b9eb 100644 --- a/engineoutput.c +++ b/engineoutput.c @@ -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