X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=winboard%2Fwengineoutput.c;h=cac474470a8cf8dc939a47947478383cbd8b861e;hb=29df666d997ad990de5376c962b154b26eb73f2f;hp=64865088152a3b58c4809c2391bb9367790f94db;hpb=2380bd9a886c088ba6040d99932c20cdf080fbbb;p=xboard.git diff --git a/winboard/wengineoutput.c b/winboard/wengineoutput.c index 6486508..cac4744 100644 --- a/winboard/wengineoutput.c +++ b/winboard/wengineoutput.c @@ -1,7 +1,7 @@ /* * Engine output (PV) * - * Author: Alessandro Scotti + * Author: Alessandro Scotti (Dec 2005) * * ------------------------------------------------------------------------ * This program is free software; you can redistribute it and/or modify @@ -40,6 +40,8 @@ VOID EngineOutputPopUp(); VOID EngineOutputPopDown(); BOOL EngineOutputIsUp(); +#define SHOW_PONDERING + /* Imports from backend.c */ char * SavePart(char *str); @@ -58,9 +60,62 @@ extern WindowPlacement wpEngineOutput; #define LABEL_V_DISTANCE 1 /* Distance between label and memo */ #define SPLITTER_SIZE 4 /* Distance between first memo and second label */ +#define ICON_SIZE 14 + +#define STATE_UNKNOWN -1 +#define STATE_THINKING 0 +#define STATE_IDLE 1 +#define STATE_PONDERING 2 + static int windowMode = 1; +static BOOL needInit = TRUE; + +static HICON hiColorBlack = NULL; +static HICON hiColorWhite = NULL; +static HICON hiColorUnknown = NULL; +static HICON hiClear = NULL; +static HICON hiPondering = NULL; +static HICON hiThinking = NULL; + static int lastDepth[2] = { -1, -1 }; +static int lastForwardMostMove[2] = { -1, -1 }; +static int engineState[2] = { -1, -1 }; + +typedef struct { + int which; + HWND hColorIcon; + HWND hLabel; + HWND hStateIcon; + HWND hStateData; + HWND hLabelNPS; + HWND hMemo; + char * name; + int depth; + unsigned long nodes; + int score; + int time; + char * pv; + char * hint; +} EngineOutputData; + +static HICON LoadIconEx( int id ) +{ + return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 ); +} + +static VOID InitializeEngineOutput() +{ + if( needInit ) { + hiColorBlack = LoadIconEx( IDI_BLACK_14 ); + hiColorWhite = LoadIconEx( IDI_WHITE_14 ); + hiColorUnknown = LoadIconEx( IDI_UNKNOWN_14 ); + hiClear = LoadIconEx( IDI_TRANS_14 ); + hiPondering = LoadIconEx( IDI_PONDER_14 ); + hiThinking = LoadIconEx( IDI_CLOCK_14 ); + needInit = FALSE; + } +} static VOID SetControlPos( HWND hDlg, int id, int x, int y, int width, int height ) { @@ -69,35 +124,132 @@ static VOID SetControlPos( HWND hDlg, int id, int x, int y, int width, int heigh SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER ); } +#define HIDDEN_X 20000 +#define HIDDEN_Y 20000 + static VOID HideControl( HWND hDlg, int id ) { - /* TODO: we should also hide/disable it!!! what about tab stops?!?! */ + HWND hControl = GetDlgItem( hDlg, id ); + RECT rc; + + GetWindowRect( hControl, &rc ); + + /* + Avoid hiding an already hidden control, because that causes many + unnecessary WM_ERASEBKGND messages! + */ + if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) { SetControlPos( hDlg, id, 20000, 20000, 100, 100 ); + } } static int GetControlWidth( HWND hDlg, int id ) { RECT rc; - GetWindowRect( GetDlgItem( hDlg, IDC_EngineLabel1 ), &rc ); + GetWindowRect( GetDlgItem( hDlg, id ), &rc ); return rc.right - rc.left; } +static int GetControlHeight( HWND hDlg, int id ) +{ + RECT rc; + + GetWindowRect( GetDlgItem( hDlg, id ), &rc ); + + return rc.bottom - rc.top; +} + +static int GetHeaderHeight() +{ + int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 ); + + if( result < ICON_SIZE ) result = ICON_SIZE; + + return result; +} + +#define ENGINE_COLOR_WHITE 'w' +#define ENGINE_COLOR_BLACK 'b' +#define ENGINE_COLOR_UNKNOWN ' ' + +char GetEngineColor( int which ) +{ + char result = ENGINE_COLOR_UNKNOWN; + + if( which == 0 || which == 1 ) { + ChessProgramState * cps; + + switch (gameMode) { + case MachinePlaysBlack: + case IcsPlayingBlack: + result = ENGINE_COLOR_BLACK; + break; + case MachinePlaysWhite: + case IcsPlayingWhite: + result = ENGINE_COLOR_WHITE; + break; + case AnalyzeMode: + case AnalyzeFile: + result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; + break; + case TwoMachinesPlay: + cps = (which == 0) ? &first : &second; + result = cps->twoMachinesColor[0]; + result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; + break; + } + } + + return result; +} + +char GetActiveEngineColor() +{ + char result = ENGINE_COLOR_UNKNOWN; + + if( gameMode == TwoMachinesPlay ) { + result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; + } + + return result; +} + +static VOID PositionControlSet( HWND hDlg, int x, int y, int clientWidth, int memoHeight, int idColor, int idEngineLabel, int idNPS, int idMemo, int idStateIcon, int idStateData ) +{ + int label_x = x + ICON_SIZE + H_MARGIN; + int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 ); + int label_y = y + ICON_SIZE - label_h; + int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS ); + int nps_x = clientWidth - H_MARGIN - nps_w; + int state_data_w = GetControlWidth( hDlg, IDC_StateData1 ); + int state_data_x = nps_x - H_MARGIN - state_data_w; + int state_icon_x = state_data_x - ICON_SIZE - 2; + int max_w = clientWidth - 2*H_MARGIN; + int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE; + + SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE ); + SetControlPos( hDlg, idEngineLabel, label_x, label_y, max_w / 2, label_h ); + SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE ); + SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h ); + SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h ); + SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight ); +} + static VOID ResizeWindowControls( HWND hDlg, int mode ) { RECT rc; - int labelHeight; + int headerHeight = GetHeaderHeight(); + int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 ); + int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN; + int labelDeltaY = ICON_SIZE - labelHeight; int clientWidth; int clientHeight; int maxControlWidth; int npsWidth; /* Initialize variables */ - GetWindowRect( GetDlgItem( hDlg, IDC_EngineLabel1 ), &rc ); - - labelHeight = rc.bottom - rc.top; - GetClientRect( hDlg, &rc ); clientWidth = rc.right - rc.left; @@ -110,33 +262,32 @@ static VOID ResizeWindowControls( HWND hDlg, int mode ) /* Resize controls */ if( mode == 0 ) { /* One engine */ - int memo_y = V_MARGIN + labelHeight + LABEL_V_DISTANCE; - int memo_h = clientHeight - memo_y - V_MARGIN; - - SetControlPos( hDlg, IDC_EngineLabel1, H_MARGIN, V_MARGIN, maxControlWidth / 2, labelHeight ); - SetControlPos( hDlg, IDC_EngineMemo1, H_MARGIN, memo_y, maxControlWidth, memo_h ); + PositionControlSet( hDlg, H_MARGIN, V_MARGIN, + clientWidth, + clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN, + IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 ); /* Hide controls for the second engine */ + HideControl( hDlg, IDC_Color2 ); HideControl( hDlg, IDC_EngineLabel2 ); + HideControl( hDlg, IDC_StateIcon2 ); + HideControl( hDlg, IDC_StateData2 ); HideControl( hDlg, IDC_Engine2_NPS ); HideControl( hDlg, IDC_EngineMemo2 ); + SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" ); /* TODO: we should also hide/disable them!!! what about tab stops?!?! */ } else { /* Two engines */ - int memo1_y = V_MARGIN + labelHeight + LABEL_V_DISTANCE; - int memo_h = (clientHeight - memo1_y - V_MARGIN - labelHeight - LABEL_V_DISTANCE - SPLITTER_SIZE) / 2; - int label2_y = memo1_y + memo_h + SPLITTER_SIZE; - int memo2_y = label2_y + labelHeight + LABEL_V_DISTANCE; - int nps_x = clientWidth - H_MARGIN - npsWidth; - - SetControlPos( hDlg, IDC_EngineLabel1, H_MARGIN, V_MARGIN, maxControlWidth / 2, labelHeight ); - SetControlPos( hDlg, IDC_Engine1_NPS, nps_x, V_MARGIN, npsWidth, labelHeight ); - SetControlPos( hDlg, IDC_EngineMemo1, H_MARGIN, memo1_y, maxControlWidth, memo_h ); - - SetControlPos( hDlg, IDC_EngineLabel2, H_MARGIN, label2_y, maxControlWidth / 2, labelHeight ); - SetControlPos( hDlg, IDC_Engine2_NPS, nps_x, label2_y, npsWidth, labelHeight ); - SetControlPos( hDlg, IDC_EngineMemo2, H_MARGIN, memo2_y, maxControlWidth, memo_h ); + int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2; + int header1_y = V_MARGIN; + int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE; + + PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h, + IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 ); + + PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h, + IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 ); } InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE ); @@ -162,6 +313,8 @@ static VOID VerifyDisplayMode() case AnalyzeFile: case MachinePlaysWhite: case MachinePlaysBlack: + case IcsPlayingWhite: + case IcsPlayingBlack: mode = 0; break; case TwoMachinesPlay: @@ -182,11 +335,65 @@ static VOID InsertIntoMemo( HWND hMemo, char * text ) SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text ); } +static VOID SetIcon( HWND hControl, HICON hIcon ) +{ + if( hIcon != NULL ) { + SendMessage( hControl, STM_SETICON, (WPARAM) hIcon, 0 ); + } +} + +static VOID SetEngineColorIcon( HWND hControl, int which ) +{ + char color = GetEngineColor(which); + HICON hicon = NULL; + + if( color == ENGINE_COLOR_BLACK ) + hicon = hiColorBlack; + else if( color == ENGINE_COLOR_WHITE ) + hicon = hiColorWhite; + else + hicon = hiColorUnknown; + + SetIcon( hControl, hicon ); +} + +static SetEngineState( int which, int state, char * state_data ) +{ + int x_which = 1 - which; + HWND hStateIcon = GetDlgItem( engineOutputDialog, which == 0 ? IDC_StateIcon1 : IDC_StateIcon2 ); + HWND hStateData = GetDlgItem( engineOutputDialog, which == 0 ? IDC_StateData1 : IDC_StateData2 ); + + if( engineState[ which ] != state ) { + engineState[ which ] = state; + + switch( state ) { + case STATE_THINKING: + SetIcon( hStateIcon, hiThinking ); + if( engineState[ x_which ] == STATE_THINKING ) { + SetEngineState( x_which, STATE_IDLE, "" ); + } + break; + case STATE_PONDERING: + SetIcon( hStateIcon, hiPondering ); + break; + default: + SetIcon( hStateIcon, hiClear ); + break; + } + } + + if( state_data != 0 ) { + SetWindowText( hStateData, state_data ); + } +} + #define MAX_NAME_LENGTH 32 -static VOID UpdateControls( HWND hLabel, HWND hLabelNPS, HWND hMemo, char * name, int depth, unsigned long nodes, int score, int time, char * pv ) +static VOID UpdateControls( EngineOutputData * ed ) { - char s_label[MAX_NAME_LENGTH + 64]; + char s_label[MAX_NAME_LENGTH + 32]; + + char * name = ed->name; /* Label */ if( name == 0 || *name == '\0' ) { @@ -196,12 +403,47 @@ static VOID UpdateControls( HWND hLabel, HWND hLabelNPS, HWND hMemo, char * name strncpy( s_label, name, MAX_NAME_LENGTH ); s_label[ MAX_NAME_LENGTH-1 ] = '\0'; - SetWindowText( hLabel, s_label ); +#ifdef SHOW_PONDERING + if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) { + if( GetEngineColor(ed->which) != GetActiveEngineColor() ) { + char buf[8]; + + buf[0] = '\0'; + + if( ed->hint != 0 && *ed->hint != '\0' ) { + strncpy( buf, ed->hint, sizeof(buf) ); + buf[sizeof(buf)-1] = '\0'; + } + else if( ed->pv != 0 && *ed->pv != '\0' ) { + char * sep = strchr( ed->pv, ' ' ); + int buflen = sizeof(buf); + + if( sep != NULL ) { + buflen = sep - ed->pv + 1; + if( buflen > sizeof(buf) ) buflen = sizeof(buf); + } + + strncpy( buf, ed->pv, buflen ); + buf[ buflen-1 ] = '\0'; + } + + SetEngineState( ed->which, STATE_PONDERING, buf ); + } + else { + SetEngineState( ed->which, STATE_THINKING, "" ); + } + } + else { + SetEngineState( ed->which, STATE_IDLE, "" ); + } +#endif + + SetWindowText( ed->hLabel, s_label ); s_label[0] = '\0'; - if( time > 0 && nodes > 0 ) { - unsigned long nps_100 = nodes / time; + if( ed->time > 0 && ed->nodes > 0 ) { + unsigned long nps_100 = ed->nodes / ed->time; if( nps_100 < 100000 ) { sprintf( s_label, "NPS: %lu", nps_100 * 100 ); @@ -211,52 +453,55 @@ static VOID UpdateControls( HWND hLabel, HWND hLabelNPS, HWND hMemo, char * name } } - SetWindowText( hLabelNPS, s_label ); + SetWindowText( ed->hLabelNPS, s_label ); /* Memo */ - if( pv != 0 && *pv != '\0' ) { + if( ed->pv != 0 && *ed->pv != '\0' ) { char s_nodes[24]; char s_score[16]; char s_time[24]; char buf[256]; int buflen; - int time_secs = time / 100; - int time_cent = time % 100; + int time_secs = ed->time / 100; + int time_cent = ed->time % 100; /* Nodes */ - if( nodes < 1000000 ) { - sprintf( s_nodes, "%lu", nodes ); + if( ed->nodes < 1000000 ) { + sprintf( s_nodes, "%lu", ed->nodes ); } else { - sprintf( s_nodes, "%.1fM", nodes / 1000000.0 ); + sprintf( s_nodes, "%.1fM", ed->nodes / 1000000.0 ); } /* Score */ - if( score > 0 ) { - sprintf( s_score, "+%.2f", score / 100.0 ); + if( ed->score > 0 ) { + sprintf( s_score, "+%.2f", ed->score / 100.0 ); } else { - sprintf( s_score, "%.2f", score / 100.0 ); + sprintf( s_score, "%.2f", ed->score / 100.0 ); } /* Time */ sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent ); /* Put all together... */ - sprintf( buf, "%3d\t%s\t%s\t%s\t", depth, s_score, s_nodes, s_time ); + sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time ); /* Add PV */ buflen = strlen(buf); - strncpy( buf + buflen, pv, sizeof(buf) - buflen ); + strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen ); buf[ sizeof(buf) - 3 ] = '\0'; strcat( buf + buflen, "\r\n" ); /* Update memo */ - InsertIntoMemo( hMemo, buf ); + InsertIntoMemo( ed->hMemo, buf ); } + + /* Colors */ + SetEngineColorIcon( ed->hColorIcon, ed->which ); } LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) @@ -271,6 +516,9 @@ LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARA RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */ ResizeWindowControls( hDlg, windowMode ); + + SetEngineState( 0, STATE_IDLE, "" ); + SetEngineState( 1, STATE_IDLE, "" ); } return FALSE; @@ -328,6 +576,10 @@ VOID EngineOutputPopUp() { FARPROC lpProc; + if( needInit ) { + InitializeEngineOutput(); + } + CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED); if( engineOutputDialog ) { @@ -365,12 +617,10 @@ BOOL EngineOutputIsUp() return engineOutputDialogUp; } -VOID EngineOutputUpdate( int which, int depth, unsigned long nodes, int score, int time, char * pv ) +VOID EngineOutputUpdate( int which, int depth, unsigned long nodes, int score, int time, char * pv, char * hint ) { - HWND hLabel; - HWND hLabelNPS; - HWND hMemo; - char * name; + EngineOutputData ed; + BOOL clearMemo = FALSE; if( which < 0 || which > 1 || depth < 0 || time < 0 || pv == 0 || *pv == '\0' ) { return; @@ -382,33 +632,56 @@ VOID EngineOutputUpdate( int which, int depth, unsigned long nodes, int score, i VerifyDisplayMode(); + ed.which = which; + ed.depth = depth; + ed.nodes = nodes; + ed.score = score; + ed.time = time; + ed.pv = pv; + ed.hint = hint; + /* Get target control */ if( which == 0 ) { - hLabel = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 ); - hLabelNPS = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS ); - hMemo = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 ); - name = first.tidy; + ed.hColorIcon = GetDlgItem( engineOutputDialog, IDC_Color1 ); + ed.hLabel = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 ); + ed.hStateIcon = GetDlgItem( engineOutputDialog, IDC_StateIcon1 ); + ed.hStateData = GetDlgItem( engineOutputDialog, IDC_StateData1 ); + ed.hLabelNPS = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS ); + ed.hMemo = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 ); + ed.name = first.tidy; } else { - hLabel = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 ); - hLabelNPS = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS ); - hMemo = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 ); - name = second.tidy; + ed.hColorIcon = GetDlgItem( engineOutputDialog, IDC_Color2 ); + ed.hLabel = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 ); + ed.hStateIcon = GetDlgItem( engineOutputDialog, IDC_StateIcon2 ); + ed.hStateData = GetDlgItem( engineOutputDialog, IDC_StateData2 ); + ed.hLabelNPS = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS ); + ed.hMemo = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 ); + ed.name = second.tidy; } /* Clear memo if needed */ if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) { - SendMessage( hMemo, WM_SETTEXT, 0, (LPARAM) "" ); + clearMemo = TRUE; + } + + if( lastForwardMostMove[which] != forwardMostMove ) { + clearMemo = TRUE; + } + + if( clearMemo ) { + SendMessage( ed.hMemo, WM_SETTEXT, 0, (LPARAM) "" ); } /* Update */ lastDepth[which] = depth; + lastForwardMostMove[which] = forwardMostMove; if( pv[0] == ' ' ) { if( strncmp( pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */ - pv = ""; + ed.pv = ""; } } - UpdateControls( hLabel, hLabelNPS, hMemo, name, depth, nodes, score, time, pv ); + UpdateControls( &ed ); }