4 * Author: Alessandro Scotti (Dec 2005)
\r
6 * ------------------------------------------------------------------------
\r
8 * GNU XBoard is free software: you can redistribute it and/or modify
\r
9 * it under the terms of the GNU General Public License as published by
\r
10 * the Free Software Foundation, either version 3 of the License, or (at
\r
11 * your option) any later version.
\r
13 * GNU XBoard is distributed in the hope that it will be useful, but
\r
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
16 * General Public License for more details.
\r
18 * You should have received a copy of the GNU General Public License
\r
19 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
21 *------------------------------------------------------------------------
\r
22 ** See the file ChangeLog for a revision history. */
\r
26 #include <windows.h> /* required for all Windows applications */
\r
27 #include <richedit.h>
\r
31 #include <commdlg.h>
\r
35 #include "winboard.h"
\r
36 #include "frontend.h"
\r
37 #include "backend.h"
\r
41 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
\r
42 #define nColorBlack 1
\r
43 #define nColorWhite 2
\r
44 #define nColorUnknown 3
\r
46 #define nPondering 5
\r
48 #define nAnalyzing 7
\r
50 HICON icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
\r
52 // [HGM] same for output fields (note that there are two of each type, one per color)
\r
53 #define nColorIcon 1
\r
54 #define nStateIcon 2
\r
56 #define nStateData 4
\r
60 HWND outputField[2][7]; // [HGM] front-end array to translate output field to window handle
\r
62 void EngineOutputPopUp();
\r
63 void EngineOutputPopDown();
\r
64 int EngineOutputIsUp();
\r
66 #define SHOW_PONDERING
\r
68 /* Imports from backend.c */
\r
69 char * SavePart(char *str);
\r
70 extern int opponentKibitzes;
\r
72 /* Imports from winboard.c */
\r
73 extern HWND engineOutputDialog;
\r
74 extern int engineOutputDialogUp;
\r
76 extern HINSTANCE hInst;
\r
77 extern HWND hwndMain;
\r
79 extern WindowPlacement wpEngineOutput;
\r
81 /* Module variables */
\r
84 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
\r
85 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
\r
87 #define ICON_SIZE 14
\r
89 #define STATE_UNKNOWN -1
\r
90 #define STATE_THINKING 0
\r
91 #define STATE_IDLE 1
\r
92 #define STATE_PONDERING 2
\r
93 #define STATE_ANALYZING 3
\r
95 static int windowMode = 1;
\r
97 static int needInit = TRUE;
\r
99 static int lastDepth[2] = { -1, -1 };
\r
100 static int lastForwardMostMove[2] = { -1, -1 };
\r
101 static int engineState[2] = { -1, -1 };
\r
104 // HWND hColorIcon; // [HGM] the output-control handles are no loger passed,
\r
105 // HWND hLabel; // to give better front-end / back-end separation
\r
106 // HWND hStateIcon; // the front-end routines now get them from a (front-end)
\r
107 // HWND hStateData; // table, indexed by output-field indicators.
\r
120 } EngineOutputData;
\r
122 static VerifyDisplayMode();
\r
123 static void UpdateControls( EngineOutputData * ed );
\r
124 static SetEngineState( int which, int state, char * state_data );
\r
127 static HICON LoadIconEx( int id )
\r
129 return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );
\r
132 // [HGM] the platform-dependent way of indicating where output should go is now all
\r
133 // concentrated here, where a table of platform-dependent handles are initialized.
\r
134 // This cleanses most other routines of front-end stuff, so they can go into the back end.
\r
135 static void InitializeEngineOutput()
\r
137 // if( needInit ) { // needInit was already tested before call
\r
138 // [HGM] made this into a table, rather than separate global variables
\r
139 icons[nColorBlack] = LoadIconEx( IDI_BLACK_14 );
\r
140 icons[nColorWhite] = LoadIconEx( IDI_WHITE_14 );
\r
141 icons[nColorUnknown] = LoadIconEx( IDI_UNKNOWN_14 );
\r
142 icons[nClear] = LoadIconEx( IDI_TRANS_14 );
\r
143 icons[nPondering] = LoadIconEx( IDI_PONDER_14 );
\r
144 icons[nThinking] = LoadIconEx( IDI_CLOCK_14 );
\r
145 icons[nAnalyzing] = LoadIconEx( IDI_ANALYZE2_14 );
\r
147 // [HGM] also make a table of handles to output controls
\r
148 // Note that engineOutputDialog must be defined first!
\r
149 outputField[0][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color1 );
\r
150 outputField[0][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );
\r
151 outputField[0][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );
\r
152 outputField[0][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData1 );
\r
153 outputField[0][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );
\r
154 outputField[0][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );
\r
156 outputField[1][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color2 );
\r
157 outputField[1][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );
\r
158 outputField[1][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );
\r
159 outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 );
\r
160 outputField[1][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );
\r
161 outputField[1][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );
\r
162 // needInit = FALSE;
\r
167 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )
\r
169 HWND hControl = GetDlgItem( hDlg, id );
\r
171 SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );
\r
174 #define HIDDEN_X 20000
\r
175 #define HIDDEN_Y 20000
\r
178 static void HideControl( HWND hDlg, int id )
\r
180 HWND hControl = GetDlgItem( hDlg, id );
\r
183 GetWindowRect( hControl, &rc );
\r
186 Avoid hiding an already hidden control, because that causes many
\r
187 unnecessary WM_ERASEBKGND messages!
\r
189 if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {
\r
190 SetControlPos( hDlg, id, 20000, 20000, 100, 100 );
\r
194 // front end, although we might make GetWindowRect front end instead
\r
195 static int GetControlWidth( HWND hDlg, int id )
\r
199 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
201 return rc.right - rc.left;
\r
205 static int GetControlHeight( HWND hDlg, int id )
\r
209 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
211 return rc.bottom - rc.top;
\r
214 static int GetHeaderHeight()
\r
216 int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );
\r
218 if( result < ICON_SIZE ) result = ICON_SIZE;
\r
223 // The size calculations should be backend? If setControlPos is a platform-dependent way of doing things,
\r
224 // a platform-independent wrapper for it should be supplied.
\r
225 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
227 int label_x = x + ICON_SIZE + H_MARGIN;
\r
228 int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
229 int label_y = y + ICON_SIZE - label_h;
\r
230 int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
231 int nps_x = clientWidth - H_MARGIN - nps_w;
\r
232 int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );
\r
233 int state_data_x = nps_x - H_MARGIN - state_data_w;
\r
234 int state_icon_x = state_data_x - ICON_SIZE - 2;
\r
235 int max_w = clientWidth - 2*H_MARGIN;
\r
236 int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;
\r
238 SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );
\r
239 SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );
\r
240 SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );
\r
241 SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );
\r
242 SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );
\r
243 SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );
\r
246 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine
\r
247 static void ResizeWindowControls( HWND hDlg, int mode )
\r
250 int headerHeight = GetHeaderHeight();
\r
251 int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
252 int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;
\r
253 int labelDeltaY = ICON_SIZE - labelHeight;
\r
256 int maxControlWidth;
\r
259 /* Initialize variables */
\r
260 GetClientRect( hDlg, &rc );
\r
262 clientWidth = rc.right - rc.left;
\r
263 clientHeight = rc.bottom - rc.top;
\r
265 maxControlWidth = clientWidth - 2*H_MARGIN;
\r
267 npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
269 /* Resize controls */
\r
272 PositionControlSet( hDlg, H_MARGIN, V_MARGIN,
\r
274 clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,
\r
275 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
277 /* Hide controls for the second engine */
\r
278 HideControl( hDlg, IDC_Color2 );
\r
279 HideControl( hDlg, IDC_EngineLabel2 );
\r
280 HideControl( hDlg, IDC_StateIcon2 );
\r
281 HideControl( hDlg, IDC_StateData2 );
\r
282 HideControl( hDlg, IDC_Engine2_NPS );
\r
283 HideControl( hDlg, IDC_EngineMemo2 );
\r
284 SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );
\r
285 /* TODO: we should also hide/disable them!!! what about tab stops?!?! */
\r
289 int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;
\r
290 int header1_y = V_MARGIN;
\r
291 int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;
\r
293 PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,
\r
294 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
296 PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,
\r
297 IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );
\r
300 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );
\r
301 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );
\r
304 // front end. Actual printing of PV lines into the output field
\r
305 static void InsertIntoMemo( int which, char * text )
\r
307 SendMessage( outputField[which][nMemo], EM_SETSEL, 0, 0 );
\r
309 SendMessage( outputField[which][nMemo], EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );
\r
312 // front end. Associates an icon with an output field ("control" in Windows jargon).
\r
313 // [HGM] let it find out the output field from the 'which' number by itself
\r
314 static void SetIcon( int which, int field, int nIcon )
\r
318 SendMessage( outputField[which][field], STM_SETICON, (WPARAM) icons[nIcon], 0 );
\r
322 // front end wrapper for SetWindowText, taking control number in stead of handle
\r
323 void DoSetWindowText(int which, int field, char *s_label)
\r
325 SetWindowText( outputField[which][field], s_label );
\r
328 // This seems pure front end
\r
329 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
\r
331 static SnapData sd;
\r
334 case WM_INITDIALOG:
\r
335 if( engineOutputDialog == NULL ) {
\r
336 engineOutputDialog = hDlg;
\r
338 RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */
\r
340 ResizeWindowControls( hDlg, windowMode );
\r
342 SetEngineState( 0, STATE_IDLE, "" );
\r
343 SetEngineState( 1, STATE_IDLE, "" );
\r
349 switch (LOWORD(wParam)) {
\r
351 EndDialog(hDlg, TRUE);
\r
355 EndDialog(hDlg, FALSE);
\r
364 case WM_GETMINMAXINFO:
\r
366 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
\r
368 mmi->ptMinTrackSize.x = 100;
\r
369 mmi->ptMinTrackSize.y = 160;
\r
374 EngineOutputPopDown();
\r
378 ResizeWindowControls( hDlg, windowMode );
\r
381 case WM_ENTERSIZEMOVE:
\r
382 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
385 return OnSizing( &sd, hDlg, wParam, lParam );
\r
388 return OnMoving( &sd, hDlg, wParam, lParam );
\r
390 case WM_EXITSIZEMOVE:
\r
391 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
398 void EngineOutputPopUp()
\r
402 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);
\r
404 if( engineOutputDialog ) {
\r
405 SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );
\r
407 if( ! engineOutputDialogUp ) {
\r
408 ShowWindow(engineOutputDialog, SW_SHOW);
\r
412 lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );
\r
414 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
\r
415 CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );
\r
417 FreeProcInstance(lpProc);
\r
420 // [HGM] displaced to after creation of dialog, to allow initialization of output fields
\r
422 InitializeEngineOutput();
\r
426 engineOutputDialogUp = TRUE;
\r
430 void EngineOutputPopDown()
\r
432 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);
\r
434 if( engineOutputDialog ) {
\r
435 ShowWindow(engineOutputDialog, SW_HIDE);
\r
438 engineOutputDialogUp = FALSE;
\r
441 // front end. [HGM] Takes handle of output control from table, so only number is passed
\r
442 void DoClearMemo(int which)
\r
444 SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" );
\r
447 //------------------------ pure back-end routines -------------------------------
\r
450 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
\r
451 static SetEngineState( int which, int state, char * state_data )
\r
453 int x_which = 1 - which;
\r
455 if( engineState[ which ] != state ) {
\r
456 engineState[ which ] = state;
\r
459 case STATE_THINKING:
\r
460 SetIcon( which, nStateIcon, nThinking );
\r
461 if( engineState[ x_which ] == STATE_THINKING ) {
\r
462 SetEngineState( x_which, STATE_IDLE, "" );
\r
465 case STATE_PONDERING:
\r
466 SetIcon( which, nStateIcon, nPondering );
\r
468 case STATE_ANALYZING:
\r
469 SetIcon( which, nStateIcon, nAnalyzing );
\r
472 SetIcon( which, nStateIcon, nClear );
\r
477 if( state_data != 0 ) {
\r
478 DoSetWindowText( which, nStateData, state_data );
\r
482 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
\r
483 void EngineOutputUpdate( FrontEndProgramStats * stats )
\r
485 EngineOutputData ed;
\r
486 int clearMemo = FALSE;
\r
491 SetEngineState( 0, STATE_IDLE, "" );
\r
492 SetEngineState( 1, STATE_IDLE, "" );
\r
496 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
\r
497 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
\r
499 which = stats->which;
\r
500 depth = stats->depth;
\r
502 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
\r
506 if( engineOutputDialog == NULL ) {
\r
510 VerifyDisplayMode();
\r
514 ed.nodes = stats->nodes;
\r
515 ed.score = stats->score;
\r
516 ed.time = stats->time;
\r
518 ed.hint = stats->hint;
\r
519 ed.an_move_index = stats->an_move_index;
\r
520 ed.an_move_count = stats->an_move_count;
\r
522 /* Get target control. [HGM] this is moved to front end, which get them from a table */
\r
524 ed.name = first.tidy;
\r
527 ed.name = second.tidy;
\r
530 /* Clear memo if needed */
\r
531 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
\r
535 if( lastForwardMostMove[which] != forwardMostMove ) {
\r
539 if( clearMemo ) DoClearMemo(which);
\r
542 lastDepth[which] = depth;
\r
543 lastForwardMostMove[which] = forwardMostMove;
\r
545 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
\r
546 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
\r
551 UpdateControls( &ed );
\r
554 #define ENGINE_COLOR_WHITE 'w'
\r
555 #define ENGINE_COLOR_BLACK 'b'
\r
556 #define ENGINE_COLOR_UNKNOWN ' '
\r
559 char GetEngineColor( int which )
\r
561 char result = ENGINE_COLOR_UNKNOWN;
\r
563 if( which == 0 || which == 1 ) {
\r
564 ChessProgramState * cps;
\r
566 switch (gameMode) {
\r
567 case MachinePlaysBlack:
\r
568 case IcsPlayingBlack:
\r
569 result = ENGINE_COLOR_BLACK;
\r
571 case MachinePlaysWhite:
\r
572 case IcsPlayingWhite:
\r
573 result = ENGINE_COLOR_WHITE;
\r
577 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
579 case TwoMachinesPlay:
\r
580 cps = (which == 0) ? &first : &second;
\r
581 result = cps->twoMachinesColor[0];
\r
582 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
591 char GetActiveEngineColor()
\r
593 char result = ENGINE_COLOR_UNKNOWN;
\r
595 if( gameMode == TwoMachinesPlay ) {
\r
596 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
603 static int IsEnginePondering( int which )
\r
605 int result = FALSE;
\r
607 switch (gameMode) {
\r
608 case MachinePlaysBlack:
\r
609 case IcsPlayingBlack:
\r
610 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
612 case MachinePlaysWhite:
\r
613 case IcsPlayingWhite:
\r
614 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
616 case TwoMachinesPlay:
\r
617 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
618 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
627 static void SetDisplayMode( int mode )
\r
629 if( windowMode != mode ) {
\r
632 ResizeWindowControls( engineOutputDialog, mode );
\r
637 static VerifyDisplayMode()
\r
641 /* Get proper mode for current game */
\r
642 switch( gameMode ) {
\r
643 case IcsObserving: // [HGM] ICS analyze
\r
644 if(!appData.icsEngineAnalyze) return;
\r
647 case MachinePlaysWhite:
\r
648 case MachinePlaysBlack:
\r
651 case IcsPlayingWhite:
\r
652 case IcsPlayingBlack:
\r
653 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
655 case TwoMachinesPlay:
\r
659 /* Do not change */
\r
663 SetDisplayMode( mode );
\r
666 // back end. Determine what icon to se in the color-icon field, and print it
\r
667 static void SetEngineColorIcon( int which )
\r
669 char color = GetEngineColor(which);
\r
672 if( color == ENGINE_COLOR_BLACK )
\r
673 nicon = nColorBlack;
\r
674 else if( color == ENGINE_COLOR_WHITE )
\r
675 nicon = nColorWhite;
\r
677 nicon = nColorUnknown;
\r
679 SetIcon( which, nColorIcon, nicon );
\r
682 #define MAX_NAME_LENGTH 32
\r
684 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
685 static void UpdateControls( EngineOutputData * ed )
\r
687 int isPondering = FALSE;
\r
689 char s_label[MAX_NAME_LENGTH + 32];
\r
691 char * name = ed->name;
\r
694 if( name == 0 || *name == '\0' ) {
\r
698 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
699 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
701 #ifdef SHOW_PONDERING
\r
702 if( IsEnginePondering( ed->which ) ) {
\r
707 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
708 strncpy( buf, ed->hint, sizeof(buf) );
\r
709 buf[sizeof(buf)-1] = '\0';
\r
711 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
712 char * sep = strchr( ed->pv, ' ' );
\r
713 int buflen = sizeof(buf);
\r
715 if( sep != NULL ) {
\r
716 buflen = sep - ed->pv + 1;
\r
717 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
720 strncpy( buf, ed->pv, buflen );
\r
721 buf[ buflen-1 ] = '\0';
\r
724 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
726 else if( gameMode == TwoMachinesPlay ) {
\r
727 SetEngineState( ed->which, STATE_THINKING, "" );
\r
729 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
730 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
\r
732 int time_secs = ed->time / 100;
\r
733 int time_mins = time_secs / 60;
\r
737 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
740 strncpy( mov, ed->hint, sizeof(mov) );
\r
741 mov[ sizeof(mov)-1 ] = '\0';
\r
743 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
746 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
749 SetEngineState( ed->which, STATE_IDLE, "" );
\r
753 DoSetWindowText( ed->which, nLabel, s_label );
\r
757 if( ed->time > 0 && ed->nodes > 0 ) {
\r
758 unsigned long nps_100 = ed->nodes / ed->time;
\r
760 if( nps_100 < 100000 ) {
\r
761 sprintf( s_label, "NPS: %lu", nps_100 * 100 );
\r
764 sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );
\r
768 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
771 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
777 int time_secs = ed->time / 100;
\r
778 int time_cent = ed->time % 100;
\r
781 if( ed->nodes < 1000000 ) {
\r
782 sprintf( s_nodes, u64Display, ed->nodes );
\r
785 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
\r
789 if( ed->score > 0 ) {
\r
790 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
793 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
797 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
799 /* Put all together... */
\r
800 sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
803 buflen = strlen(buf);
\r
805 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
807 buf[ sizeof(buf) - 3 ] = '\0';
\r
809 strcat( buf + buflen, "\r\n" );
\r
812 InsertIntoMemo( ed->which, buf );
\r
816 SetEngineColorIcon( ed->which );
\r
820 int EngineOutputIsUp()
\r
822 return engineOutputDialogUp;
\r
825 // [HGM] kibitz: write kibitz line; split window for it if necessary
\r
826 void OutputKibitz(int window, char *text)
\r
828 if(!EngineOutputIsUp()) return;
\r
829 if(!opponentKibitzes) { // on first kibitz of game, clear memos
\r
831 if(gameMode == IcsObserving) DoClearMemo(0);
\r
833 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
\r
834 VerifyDisplayMode();
\r
835 if(gameMode == IcsObserving) {
\r
836 DoSetWindowText(0, nLabel, gameInfo.white);
\r
837 SetIcon( 0, nColorIcon, nColorWhite);
\r
838 SetIcon( 0, nStateIcon, nClear);
\r
840 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
\r
841 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
\r
842 SetIcon( 1, nStateIcon, nClear);
\r
843 InsertIntoMemo(window-1, text);
\r