4 * Author: Alessandro Scotti (Dec 2005)
\r
6 * ------------------------------------------------------------------------
\r
7 * This program is free software; you can redistribute it and/or modify
\r
8 * it under the terms of the GNU General Public License as published by
\r
9 * the Free Software Foundation; either version 2 of the License, or
\r
10 * (at your option) any later version.
\r
12 * This program is distributed in the hope that it will be useful,
\r
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 * GNU General Public License for more details.
\r
17 * You should have received a copy of the GNU General Public License
\r
18 * along with this program; if not, write to the Free Software
\r
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
20 * ------------------------------------------------------------------------
\r
24 #include <windows.h> /* required for all Windows applications */
\r
25 #include <richedit.h>
\r
29 #include <commdlg.h>
\r
33 #include "winboard.h"
\r
34 #include "frontend.h"
\r
35 #include "backend.h"
\r
39 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
\r
40 #define nColorBlack 1
\r
41 #define nColorWhite 2
\r
42 #define nColorUnknown 3
\r
44 #define nPondering 5
\r
46 #define nAnalyzing 7
\r
48 HICON icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
\r
50 // [HGM] same for output fields (note that there are two of each type, one per color)
\r
51 #define nColorIcon 1
\r
52 #define nStateIcon 2
\r
54 #define nStateData 4
\r
58 HWND outputField[2][7]; // [HGM] front-end array to translate output field to window handle
\r
60 void EngineOutputPopUp();
\r
61 void EngineOutputPopDown();
\r
62 int EngineOutputIsUp();
\r
64 #define SHOW_PONDERING
\r
66 /* Imports from backend.c */
\r
67 char * SavePart(char *str);
\r
68 extern int opponentKibitzes;
\r
70 /* Imports from winboard.c */
\r
71 extern HWND engineOutputDialog;
\r
72 extern int engineOutputDialogUp;
\r
74 extern HINSTANCE hInst;
\r
75 extern HWND hwndMain;
\r
77 extern WindowPlacement wpEngineOutput;
\r
79 /* Module variables */
\r
82 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
\r
83 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
\r
85 #define ICON_SIZE 14
\r
87 #define STATE_UNKNOWN -1
\r
88 #define STATE_THINKING 0
\r
89 #define STATE_IDLE 1
\r
90 #define STATE_PONDERING 2
\r
91 #define STATE_ANALYZING 3
\r
93 static int windowMode = 1;
\r
95 static int needInit = TRUE;
\r
97 static int lastDepth[2] = { -1, -1 };
\r
98 static int lastForwardMostMove[2] = { -1, -1 };
\r
99 static int engineState[2] = { -1, -1 };
\r
102 // HWND hColorIcon; // [HGM] the output-control handles are no loger passed,
\r
103 // HWND hLabel; // to give better front-end / back-end separation
\r
104 // HWND hStateIcon; // the front-end routines now get them from a (front-end)
\r
105 // HWND hStateData; // table, indexed by output-field indicators.
\r
118 } EngineOutputData;
\r
120 static VerifyDisplayMode();
\r
121 static void UpdateControls( EngineOutputData * ed );
\r
122 static SetEngineState( int which, int state, char * state_data );
\r
125 static HICON LoadIconEx( int id )
\r
127 return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );
\r
130 // [HGM] the platform-dependent way of indicating where output should go is now all
\r
131 // concentrated here, where a table of platform-dependent handles are initialized.
\r
132 // This cleanses most other routines of front-end stuff, so they can go into the back end.
\r
133 static void InitializeEngineOutput()
\r
135 // if( needInit ) { // needInit was already tested before call
\r
136 // [HGM] made this into a table, rather than separate global variables
\r
137 icons[nColorBlack] = LoadIconEx( IDI_BLACK_14 );
\r
138 icons[nColorWhite] = LoadIconEx( IDI_WHITE_14 );
\r
139 icons[nColorUnknown] = LoadIconEx( IDI_UNKNOWN_14 );
\r
140 icons[nClear] = LoadIconEx( IDI_TRANS_14 );
\r
141 icons[nPondering] = LoadIconEx( IDI_PONDER_14 );
\r
142 icons[nThinking] = LoadIconEx( IDI_CLOCK_14 );
\r
143 icons[nAnalyzing] = LoadIconEx( IDI_ANALYZE2_14 );
\r
145 // [HGM] also make a table of handles to output controls
\r
146 // Note that engineOutputDialog must be defined first!
\r
147 outputField[0][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color1 );
\r
148 outputField[0][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );
\r
149 outputField[0][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );
\r
150 outputField[0][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData1 );
\r
151 outputField[0][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );
\r
152 outputField[0][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );
\r
154 outputField[1][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color2 );
\r
155 outputField[1][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );
\r
156 outputField[1][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );
\r
157 outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 );
\r
158 outputField[1][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );
\r
159 outputField[1][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );
\r
160 // needInit = FALSE;
\r
165 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )
\r
167 HWND hControl = GetDlgItem( hDlg, id );
\r
169 SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );
\r
172 #define HIDDEN_X 20000
\r
173 #define HIDDEN_Y 20000
\r
176 static void HideControl( HWND hDlg, int id )
\r
178 HWND hControl = GetDlgItem( hDlg, id );
\r
181 GetWindowRect( hControl, &rc );
\r
184 Avoid hiding an already hidden control, because that causes many
\r
185 unnecessary WM_ERASEBKGND messages!
\r
187 if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {
\r
188 SetControlPos( hDlg, id, 20000, 20000, 100, 100 );
\r
192 // front end, although we might make GetWindowRect front end instead
\r
193 static int GetControlWidth( HWND hDlg, int id )
\r
197 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
199 return rc.right - rc.left;
\r
203 static int GetControlHeight( HWND hDlg, int id )
\r
207 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
209 return rc.bottom - rc.top;
\r
212 static int GetHeaderHeight()
\r
214 int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );
\r
216 if( result < ICON_SIZE ) result = ICON_SIZE;
\r
221 // The size calculations should be backend? If setControlPos is a platform-dependent way of doing things,
\r
222 // a platform-independent wrapper for it should be supplied.
\r
223 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 )
\r
225 int label_x = x + ICON_SIZE + H_MARGIN;
\r
226 int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
227 int label_y = y + ICON_SIZE - label_h;
\r
228 int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
229 int nps_x = clientWidth - H_MARGIN - nps_w;
\r
230 int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );
\r
231 int state_data_x = nps_x - H_MARGIN - state_data_w;
\r
232 int state_icon_x = state_data_x - ICON_SIZE - 2;
\r
233 int max_w = clientWidth - 2*H_MARGIN;
\r
234 int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;
\r
236 SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );
\r
237 SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );
\r
238 SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );
\r
239 SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );
\r
240 SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );
\r
241 SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );
\r
244 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine
\r
245 static void ResizeWindowControls( HWND hDlg, int mode )
\r
248 int headerHeight = GetHeaderHeight();
\r
249 int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
250 int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;
\r
251 int labelDeltaY = ICON_SIZE - labelHeight;
\r
254 int maxControlWidth;
\r
257 /* Initialize variables */
\r
258 GetClientRect( hDlg, &rc );
\r
260 clientWidth = rc.right - rc.left;
\r
261 clientHeight = rc.bottom - rc.top;
\r
263 maxControlWidth = clientWidth - 2*H_MARGIN;
\r
265 npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
267 /* Resize controls */
\r
270 PositionControlSet( hDlg, H_MARGIN, V_MARGIN,
\r
272 clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,
\r
273 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
275 /* Hide controls for the second engine */
\r
276 HideControl( hDlg, IDC_Color2 );
\r
277 HideControl( hDlg, IDC_EngineLabel2 );
\r
278 HideControl( hDlg, IDC_StateIcon2 );
\r
279 HideControl( hDlg, IDC_StateData2 );
\r
280 HideControl( hDlg, IDC_Engine2_NPS );
\r
281 HideControl( hDlg, IDC_EngineMemo2 );
\r
282 SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );
\r
283 /* TODO: we should also hide/disable them!!! what about tab stops?!?! */
\r
287 int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;
\r
288 int header1_y = V_MARGIN;
\r
289 int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;
\r
291 PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,
\r
292 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
294 PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,
\r
295 IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );
\r
298 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );
\r
299 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );
\r
302 // front end. Actual printing of PV lines into the output field
\r
303 static void InsertIntoMemo( int which, char * text )
\r
305 SendMessage( outputField[which][nMemo], EM_SETSEL, 0, 0 );
\r
307 SendMessage( outputField[which][nMemo], EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );
\r
310 // front end. Associates an icon with an output field ("control" in Windows jargon).
\r
311 // [HGM] let it find out the output field from the 'which' number by itself
\r
312 static void SetIcon( int which, int field, int nIcon )
\r
316 SendMessage( outputField[which][field], STM_SETICON, (WPARAM) icons[nIcon], 0 );
\r
320 // front end wrapper for SetWindowText, taking control number in stead of handle
\r
321 void DoSetWindowText(int which, int field, char *s_label)
\r
323 SetWindowText( outputField[which][field], s_label );
\r
326 // This seems pure front end
\r
327 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
\r
329 static SnapData sd;
\r
332 case WM_INITDIALOG:
\r
333 if( engineOutputDialog == NULL ) {
\r
334 engineOutputDialog = hDlg;
\r
336 RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */
\r
338 ResizeWindowControls( hDlg, windowMode );
\r
340 SetEngineState( 0, STATE_IDLE, "" );
\r
341 SetEngineState( 1, STATE_IDLE, "" );
\r
347 switch (LOWORD(wParam)) {
\r
349 EndDialog(hDlg, TRUE);
\r
353 EndDialog(hDlg, FALSE);
\r
362 case WM_GETMINMAXINFO:
\r
364 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
\r
366 mmi->ptMinTrackSize.x = 100;
\r
367 mmi->ptMinTrackSize.y = 160;
\r
372 EngineOutputPopDown();
\r
376 ResizeWindowControls( hDlg, windowMode );
\r
379 case WM_ENTERSIZEMOVE:
\r
380 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
383 return OnSizing( &sd, hDlg, wParam, lParam );
\r
386 return OnMoving( &sd, hDlg, wParam, lParam );
\r
388 case WM_EXITSIZEMOVE:
\r
389 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
396 void EngineOutputPopUp()
\r
400 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);
\r
402 if( engineOutputDialog ) {
\r
403 SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );
\r
405 if( ! engineOutputDialogUp ) {
\r
406 ShowWindow(engineOutputDialog, SW_SHOW);
\r
410 lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );
\r
412 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
\r
413 CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );
\r
415 FreeProcInstance(lpProc);
\r
418 // [HGM] displaced to after creation of dialog, to allow initialization of output fields
\r
420 InitializeEngineOutput();
\r
424 engineOutputDialogUp = TRUE;
\r
428 void EngineOutputPopDown()
\r
430 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);
\r
432 if( engineOutputDialog ) {
\r
433 ShowWindow(engineOutputDialog, SW_HIDE);
\r
436 engineOutputDialogUp = FALSE;
\r
439 // front end. [HGM] Takes handle of output control from table, so only number is passed
\r
440 void DoClearMemo(int which)
\r
442 SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" );
\r
445 //------------------------ pure back-end routines -------------------------------
\r
448 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
\r
449 static SetEngineState( int which, int state, char * state_data )
\r
451 int x_which = 1 - which;
\r
453 if( engineState[ which ] != state ) {
\r
454 engineState[ which ] = state;
\r
457 case STATE_THINKING:
\r
458 SetIcon( which, nStateIcon, nThinking );
\r
459 if( engineState[ x_which ] == STATE_THINKING ) {
\r
460 SetEngineState( x_which, STATE_IDLE, "" );
\r
463 case STATE_PONDERING:
\r
464 SetIcon( which, nStateIcon, nPondering );
\r
466 case STATE_ANALYZING:
\r
467 SetIcon( which, nStateIcon, nAnalyzing );
\r
470 SetIcon( which, nStateIcon, nClear );
\r
475 if( state_data != 0 ) {
\r
476 DoSetWindowText( which, nStateData, state_data );
\r
480 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
\r
481 void EngineOutputUpdate( FrontEndProgramStats * stats )
\r
483 EngineOutputData ed;
\r
484 int clearMemo = FALSE;
\r
489 SetEngineState( 0, STATE_IDLE, "" );
\r
490 SetEngineState( 1, STATE_IDLE, "" );
\r
494 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
\r
495 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
\r
497 which = stats->which;
\r
498 depth = stats->depth;
\r
500 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
\r
504 if( engineOutputDialog == NULL ) {
\r
508 VerifyDisplayMode();
\r
512 ed.nodes = stats->nodes;
\r
513 ed.score = stats->score;
\r
514 ed.time = stats->time;
\r
516 ed.hint = stats->hint;
\r
517 ed.an_move_index = stats->an_move_index;
\r
518 ed.an_move_count = stats->an_move_count;
\r
520 /* Get target control. [HGM] this is moved to front end, which get them from a table */
\r
522 ed.name = first.tidy;
\r
525 ed.name = second.tidy;
\r
528 /* Clear memo if needed */
\r
529 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
\r
533 if( lastForwardMostMove[which] != forwardMostMove ) {
\r
537 if( clearMemo ) DoClearMemo(which);
\r
540 lastDepth[which] = depth;
\r
541 lastForwardMostMove[which] = forwardMostMove;
\r
543 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
\r
544 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
\r
549 UpdateControls( &ed );
\r
552 #define ENGINE_COLOR_WHITE 'w'
\r
553 #define ENGINE_COLOR_BLACK 'b'
\r
554 #define ENGINE_COLOR_UNKNOWN ' '
\r
557 char GetEngineColor( int which )
\r
559 char result = ENGINE_COLOR_UNKNOWN;
\r
561 if( which == 0 || which == 1 ) {
\r
562 ChessProgramState * cps;
\r
564 switch (gameMode) {
\r
565 case MachinePlaysBlack:
\r
566 case IcsPlayingBlack:
\r
567 result = ENGINE_COLOR_BLACK;
\r
569 case MachinePlaysWhite:
\r
570 case IcsPlayingWhite:
\r
571 result = ENGINE_COLOR_WHITE;
\r
575 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
577 case TwoMachinesPlay:
\r
578 cps = (which == 0) ? &first : &second;
\r
579 result = cps->twoMachinesColor[0];
\r
580 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
589 char GetActiveEngineColor()
\r
591 char result = ENGINE_COLOR_UNKNOWN;
\r
593 if( gameMode == TwoMachinesPlay ) {
\r
594 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
601 static int IsEnginePondering( int which )
\r
603 int result = FALSE;
\r
605 switch (gameMode) {
\r
606 case MachinePlaysBlack:
\r
607 case IcsPlayingBlack:
\r
608 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
610 case MachinePlaysWhite:
\r
611 case IcsPlayingWhite:
\r
612 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
614 case TwoMachinesPlay:
\r
615 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
616 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
625 static void SetDisplayMode( int mode )
\r
627 if( windowMode != mode ) {
\r
630 ResizeWindowControls( engineOutputDialog, mode );
\r
635 static VerifyDisplayMode()
\r
639 /* Get proper mode for current game */
\r
640 switch( gameMode ) {
\r
641 case IcsObserving: // [HGM] ICS analyze
\r
642 if(!appData.icsEngineAnalyze) return;
\r
645 case MachinePlaysWhite:
\r
646 case MachinePlaysBlack:
\r
649 case IcsPlayingWhite:
\r
650 case IcsPlayingBlack:
\r
651 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
653 case TwoMachinesPlay:
\r
657 /* Do not change */
\r
661 SetDisplayMode( mode );
\r
664 // back end. Determine what icon to se in the color-icon field, and print it
\r
665 static void SetEngineColorIcon( int which )
\r
667 char color = GetEngineColor(which);
\r
670 if( color == ENGINE_COLOR_BLACK )
\r
671 nicon = nColorBlack;
\r
672 else if( color == ENGINE_COLOR_WHITE )
\r
673 nicon = nColorWhite;
\r
675 nicon = nColorUnknown;
\r
677 SetIcon( which, nColorIcon, nicon );
\r
680 #define MAX_NAME_LENGTH 32
\r
682 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
683 static void UpdateControls( EngineOutputData * ed )
\r
685 int isPondering = FALSE;
\r
687 char s_label[MAX_NAME_LENGTH + 32];
\r
689 char * name = ed->name;
\r
692 if( name == 0 || *name == '\0' ) {
\r
696 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
697 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
699 #ifdef SHOW_PONDERING
\r
700 if( IsEnginePondering( ed->which ) ) {
\r
705 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
706 strncpy( buf, ed->hint, sizeof(buf) );
\r
707 buf[sizeof(buf)-1] = '\0';
\r
709 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
710 char * sep = strchr( ed->pv, ' ' );
\r
711 int buflen = sizeof(buf);
\r
713 if( sep != NULL ) {
\r
714 buflen = sep - ed->pv + 1;
\r
715 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
718 strncpy( buf, ed->pv, buflen );
\r
719 buf[ buflen-1 ] = '\0';
\r
722 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
724 else if( gameMode == TwoMachinesPlay ) {
\r
725 SetEngineState( ed->which, STATE_THINKING, "" );
\r
727 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
728 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
\r
730 int time_secs = ed->time / 100;
\r
731 int time_mins = time_secs / 60;
\r
735 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
738 strncpy( mov, ed->hint, sizeof(mov) );
\r
739 mov[ sizeof(mov)-1 ] = '\0';
\r
741 sprintf( buf, "%d/%d: %s [%02d:%02d:%02d]", ed->an_move_index, ed->an_move_count, mov, time_mins / 60, time_mins % 60, time_secs % 60 );
\r
744 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
747 SetEngineState( ed->which, STATE_IDLE, "" );
\r
751 DoSetWindowText( ed->which, nLabel, s_label );
\r
755 if( ed->time > 0 && ed->nodes > 0 ) {
\r
756 unsigned long nps_100 = ed->nodes / ed->time;
\r
758 if( nps_100 < 100000 ) {
\r
759 sprintf( s_label, "NPS: %lu", nps_100 * 100 );
\r
762 sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );
\r
766 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
769 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
775 int time_secs = ed->time / 100;
\r
776 int time_cent = ed->time % 100;
\r
779 if( ed->nodes < 1000000 ) {
\r
780 sprintf( s_nodes, u64Display, ed->nodes );
\r
783 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
\r
787 if( ed->score > 0 ) {
\r
788 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
791 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
795 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
797 /* Put all together... */
\r
798 sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
801 buflen = strlen(buf);
\r
803 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
805 buf[ sizeof(buf) - 3 ] = '\0';
\r
807 strcat( buf + buflen, "\r\n" );
\r
810 InsertIntoMemo( ed->which, buf );
\r
814 SetEngineColorIcon( ed->which );
\r
818 int EngineOutputIsUp()
\r
820 return engineOutputDialogUp;
\r
823 // [HGM] kibitz: write kibitz line; split window for it if necessary
\r
824 void OutputKibitz(int window, char *text)
\r
826 if(!EngineOutputIsUp()) return;
\r
827 if(!opponentKibitzes) { // on first kibitz of game, clear memos
\r
829 if(gameMode == IcsObserving) DoClearMemo(0);
\r
831 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
\r
832 VerifyDisplayMode();
\r
833 if(gameMode == IcsObserving) {
\r
834 DoSetWindowText(0, nLabel, gameInfo.white);
\r
835 SetIcon( 0, nColorIcon, nColorWhite);
\r
836 SetIcon( 0, nStateIcon, nClear);
\r
838 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
\r
839 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
\r
840 SetIcon( 1, nStateIcon, nClear);
\r
841 InsertIntoMemo(window-1, text);
\r