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 void VerifyDisplayMode();
\r
123 static void UpdateControls( EngineOutputData * ed );
\r
124 static void 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 void 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
584 default: ; // does not happen, but suppresses pedantic warnings
\r
592 char GetActiveEngineColor()
\r
594 char result = ENGINE_COLOR_UNKNOWN;
\r
596 if( gameMode == TwoMachinesPlay ) {
\r
597 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
604 static int IsEnginePondering( int which )
\r
606 int result = FALSE;
\r
608 switch (gameMode) {
\r
609 case MachinePlaysBlack:
\r
610 case IcsPlayingBlack:
\r
611 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
613 case MachinePlaysWhite:
\r
614 case IcsPlayingWhite:
\r
615 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
617 case TwoMachinesPlay:
\r
618 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
619 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
622 default: ; // does not happen, but suppresses pedantic warnings
\r
629 static void SetDisplayMode( int mode )
\r
631 if( windowMode != mode ) {
\r
634 ResizeWindowControls( engineOutputDialog, mode );
\r
639 static void VerifyDisplayMode()
\r
643 /* Get proper mode for current game */
\r
644 switch( gameMode ) {
\r
645 case IcsObserving: // [HGM] ICS analyze
\r
646 if(!appData.icsEngineAnalyze) return;
\r
649 case MachinePlaysWhite:
\r
650 case MachinePlaysBlack:
\r
653 case IcsPlayingWhite:
\r
654 case IcsPlayingBlack:
\r
655 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
657 case TwoMachinesPlay:
\r
661 /* Do not change */
\r
665 SetDisplayMode( mode );
\r
668 // back end. Determine what icon to se in the color-icon field, and print it
\r
669 static void SetEngineColorIcon( int which )
\r
671 char color = GetEngineColor(which);
\r
674 if( color == ENGINE_COLOR_BLACK )
\r
675 nicon = nColorBlack;
\r
676 else if( color == ENGINE_COLOR_WHITE )
\r
677 nicon = nColorWhite;
\r
679 nicon = nColorUnknown;
\r
681 SetIcon( which, nColorIcon, nicon );
\r
684 #define MAX_NAME_LENGTH 32
\r
686 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
687 static void UpdateControls( EngineOutputData * ed )
\r
689 // int isPondering = FALSE;
\r
691 char s_label[MAX_NAME_LENGTH + 32];
\r
693 char * name = ed->name;
\r
696 if( name == 0 || *name == '\0' ) {
\r
700 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
701 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
703 #ifdef SHOW_PONDERING
\r
704 if( IsEnginePondering( ed->which ) ) {
\r
709 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
710 strncpy( buf, ed->hint, sizeof(buf) );
\r
711 buf[sizeof(buf)-1] = '\0';
\r
713 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
714 char * sep = strchr( ed->pv, ' ' );
\r
715 int buflen = sizeof(buf);
\r
717 if( sep != NULL ) {
\r
718 buflen = sep - ed->pv + 1;
\r
719 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
722 strncpy( buf, ed->pv, buflen );
\r
723 buf[ buflen-1 ] = '\0';
\r
726 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
728 else if( gameMode == TwoMachinesPlay ) {
\r
729 SetEngineState( ed->which, STATE_THINKING, "" );
\r
731 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
732 || (gameMode == IcsObserving && appData.icsEngineAnalyze)) { // [HGM] ICS-analyze
\r
734 int time_secs = ed->time / 100;
\r
735 int time_mins = time_secs / 60;
\r
739 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
742 strncpy( mov, ed->hint, sizeof(mov) );
\r
743 mov[ sizeof(mov)-1 ] = '\0';
\r
745 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
748 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
751 SetEngineState( ed->which, STATE_IDLE, "" );
\r
755 DoSetWindowText( ed->which, nLabel, s_label );
\r
759 if( ed->time > 0 && ed->nodes > 0 ) {
\r
760 unsigned long nps_100 = ed->nodes / ed->time;
\r
762 if( nps_100 < 100000 ) {
\r
763 sprintf( s_label, "NPS: %lu", nps_100 * 100 );
\r
766 sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );
\r
770 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
773 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
779 int time_secs = ed->time / 100;
\r
780 int time_cent = ed->time % 100;
\r
783 if( ed->nodes < 1000000 ) {
\r
784 sprintf( s_nodes, u64Display, ed->nodes );
\r
787 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
\r
791 if( ed->score > 0 ) {
\r
792 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
795 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
799 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
801 /* Put all together... */
\r
802 sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
805 buflen = strlen(buf);
\r
807 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
809 buf[ sizeof(buf) - 3 ] = '\0';
\r
811 strcat( buf + buflen, "\r\n" );
\r
814 InsertIntoMemo( ed->which, buf );
\r
818 SetEngineColorIcon( ed->which );
\r
822 int EngineOutputIsUp()
\r
824 return engineOutputDialogUp;
\r
827 // [HGM] kibitz: write kibitz line; split window for it if necessary
\r
828 void OutputKibitz(int window, char *text)
\r
830 if(!EngineOutputIsUp()) return;
\r
831 if(!opponentKibitzes) { // on first kibitz of game, clear memos
\r
833 if(gameMode == IcsObserving) DoClearMemo(0);
\r
835 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
\r
836 VerifyDisplayMode();
\r
837 if(gameMode == IcsObserving) {
\r
838 DoSetWindowText(0, nLabel, gameInfo.white);
\r
839 SetIcon( 0, nColorIcon, nColorWhite);
\r
840 SetIcon( 0, nStateIcon, nClear);
\r
842 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
\r
843 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
\r
844 SetIcon( 1, nStateIcon, nClear);
\r
845 InsertIntoMemo(window-1, text);
\r