4 * Author: Alessandro Scotti (Dec 2005)
\r
6 * Copyright 2005 Alessandro Scotti
\r
8 * ------------------------------------------------------------------------
\r
10 * GNU XBoard is free software: you can redistribute it and/or modify
\r
11 * it under the terms of the GNU General Public License as published by
\r
12 * the Free Software Foundation, either version 3 of the License, or (at
\r
13 * your option) any later version.
\r
15 * GNU XBoard is distributed in the hope that it will be useful, but
\r
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
18 * General Public License for more details.
\r
20 * You should have received a copy of the GNU General Public License
\r
21 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
23 *------------------------------------------------------------------------
\r
24 ** See the file ChangeLog for a revision history. */
\r
28 #include <windows.h> /* required for all Windows applications */
\r
29 #include <richedit.h>
\r
33 #include <commdlg.h>
\r
37 #include "frontend.h"
\r
38 #include "backend.h"
\r
39 #include "winboard.h"
\r
43 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
\r
44 #define nColorBlack 1
\r
45 #define nColorWhite 2
\r
46 #define nColorUnknown 3
\r
48 #define nPondering 5
\r
50 #define nAnalyzing 7
\r
52 HICON icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
\r
54 // [HGM] same for output fields (note that there are two of each type, one per color)
\r
55 #define nColorIcon 1
\r
56 #define nStateIcon 2
\r
58 #define nStateData 4
\r
62 HWND outputField[2][7]; // [HGM] front-end array to translate output field to window handle
\r
64 #define SHOW_PONDERING
\r
66 /* Module variables */
\r
69 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
\r
70 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
\r
72 #define ICON_SIZE 14
\r
74 #define STATE_UNKNOWN -1
\r
75 #define STATE_THINKING 0
\r
76 #define STATE_IDLE 1
\r
77 #define STATE_PONDERING 2
\r
78 #define STATE_ANALYZING 3
\r
80 static int windowMode = 1;
\r
81 static int needInit = TRUE;
\r
82 static int lastDepth[2] = { -1, -1 };
\r
83 static int lastForwardMostMove[2] = { -1, -1 };
\r
84 static int engineState[2] = { -1, -1 };
\r
85 static BOOLEAN engineOutputDialogUp = FALSE;
\r
88 // HWND hColorIcon; // [HGM] the output-control handles are no loger passed,
\r
89 // HWND hLabel; // to give better front-end / back-end separation
\r
90 // HWND hStateIcon; // the front-end routines now get them from a (front-end)
\r
91 // HWND hStateData; // table, indexed by output-field indicators.
\r
104 } EngineOutputData;
\r
106 static void VerifyDisplayMode();
\r
107 static void UpdateControls( EngineOutputData * ed );
\r
108 static void SetEngineState( int which, int state, char * state_data );
\r
111 static HICON LoadIconEx( int id )
\r
113 return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );
\r
116 // [HGM] the platform-dependent way of indicating where output should go is now all
\r
117 // concentrated here, where a table of platform-dependent handles are initialized.
\r
118 // This cleanses most other routines of front-end stuff, so they can go into the back end.
\r
119 static void InitializeEngineOutput()
\r
121 // if( needInit ) { // needInit was already tested before call
\r
122 // [HGM] made this into a table, rather than separate global variables
\r
123 icons[nColorBlack] = LoadIconEx( IDI_BLACK_14 );
\r
124 icons[nColorWhite] = LoadIconEx( IDI_WHITE_14 );
\r
125 icons[nColorUnknown] = LoadIconEx( IDI_UNKNOWN_14 );
\r
126 icons[nClear] = LoadIconEx( IDI_TRANS_14 );
\r
127 icons[nPondering] = LoadIconEx( IDI_PONDER_14 );
\r
128 icons[nThinking] = LoadIconEx( IDI_CLOCK_14 );
\r
129 icons[nAnalyzing] = LoadIconEx( IDI_ANALYZE2_14 );
\r
131 // [HGM] also make a table of handles to output controls
\r
132 // Note that engineOutputDialog must be defined first!
\r
133 outputField[0][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color1 );
\r
134 outputField[0][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );
\r
135 outputField[0][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );
\r
136 outputField[0][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData1 );
\r
137 outputField[0][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );
\r
138 outputField[0][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );
\r
140 outputField[1][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color2 );
\r
141 outputField[1][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );
\r
142 outputField[1][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );
\r
143 outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 );
\r
144 outputField[1][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );
\r
145 outputField[1][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );
\r
146 // needInit = FALSE;
\r
151 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )
\r
153 HWND hControl = GetDlgItem( hDlg, id );
\r
155 SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );
\r
158 #define HIDDEN_X 20000
\r
159 #define HIDDEN_Y 20000
\r
162 static void HideControl( HWND hDlg, int id )
\r
164 HWND hControl = GetDlgItem( hDlg, id );
\r
167 GetWindowRect( hControl, &rc );
\r
170 Avoid hiding an already hidden control, because that causes many
\r
171 unnecessary WM_ERASEBKGND messages!
\r
173 if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {
\r
174 SetControlPos( hDlg, id, 20000, 20000, 100, 100 );
\r
178 // front end, although we might make GetWindowRect front end instead
\r
179 static int GetControlWidth( HWND hDlg, int id )
\r
183 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
185 return rc.right - rc.left;
\r
189 static int GetControlHeight( HWND hDlg, int id )
\r
193 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
195 return rc.bottom - rc.top;
\r
198 static int GetHeaderHeight()
\r
200 int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );
\r
202 if( result < ICON_SIZE ) result = ICON_SIZE;
\r
207 // The size calculations should be backend? If setControlPos is a platform-dependent way of doing things,
\r
208 // a platform-independent wrapper for it should be supplied.
\r
209 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
211 int label_x = x + ICON_SIZE + H_MARGIN;
\r
212 int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
213 int label_y = y + ICON_SIZE - label_h;
\r
214 int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
215 int nps_x = clientWidth - H_MARGIN - nps_w;
\r
216 int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );
\r
217 int state_data_x = nps_x - H_MARGIN - state_data_w;
\r
218 int state_icon_x = state_data_x - ICON_SIZE - 2;
\r
219 int max_w = clientWidth - 2*H_MARGIN;
\r
220 int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;
\r
222 SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );
\r
223 SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );
\r
224 SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );
\r
225 SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );
\r
226 SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );
\r
227 SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );
\r
230 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine
\r
231 static void ResizeWindowControls( HWND hDlg, int mode )
\r
234 int headerHeight = GetHeaderHeight();
\r
235 // int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
236 // int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;
\r
237 // int labelDeltaY = ICON_SIZE - labelHeight;
\r
240 int maxControlWidth;
\r
243 /* Initialize variables */
\r
244 GetClientRect( hDlg, &rc );
\r
246 clientWidth = rc.right - rc.left;
\r
247 clientHeight = rc.bottom - rc.top;
\r
249 maxControlWidth = clientWidth - 2*H_MARGIN;
\r
251 npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
253 /* Resize controls */
\r
256 PositionControlSet( hDlg, H_MARGIN, V_MARGIN,
\r
258 clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,
\r
259 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
261 /* Hide controls for the second engine */
\r
262 HideControl( hDlg, IDC_Color2 );
\r
263 HideControl( hDlg, IDC_EngineLabel2 );
\r
264 HideControl( hDlg, IDC_StateIcon2 );
\r
265 HideControl( hDlg, IDC_StateData2 );
\r
266 HideControl( hDlg, IDC_Engine2_NPS );
\r
267 HideControl( hDlg, IDC_EngineMemo2 );
\r
268 SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );
\r
269 /* TODO: we should also hide/disable them!!! what about tab stops?!?! */
\r
273 int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;
\r
274 int header1_y = V_MARGIN;
\r
275 int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;
\r
277 PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,
\r
278 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
280 PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,
\r
281 IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );
\r
284 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );
\r
285 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );
\r
288 // front end. Actual printing of PV lines into the output field
\r
289 static void InsertIntoMemo( int which, char * text )
\r
291 SendMessage( outputField[which][nMemo], EM_SETSEL, 0, 0 );
\r
293 SendMessage( outputField[which][nMemo], EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );
\r
296 // front end. Associates an icon with an output field ("control" in Windows jargon).
\r
297 // [HGM] let it find out the output field from the 'which' number by itself
\r
298 static void SetIcon( int which, int field, int nIcon )
\r
302 SendMessage( outputField[which][field], STM_SETICON, (WPARAM) icons[nIcon], 0 );
\r
306 // front end wrapper for SetWindowText, taking control number in stead of handle
\r
307 void DoSetWindowText(int which, int field, char *s_label)
\r
309 SetWindowText( outputField[which][field], s_label );
\r
312 // This seems pure front end
\r
313 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
\r
315 static SnapData sd;
\r
318 case WM_INITDIALOG:
\r
319 if( engineOutputDialog == NULL ) {
\r
320 engineOutputDialog = hDlg;
\r
322 RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */
\r
324 ResizeWindowControls( hDlg, windowMode );
\r
327 SendDlgItemMessage( engineOutputDialog, IDC_EngineMemo1, WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, MAKELPARAM(TRUE, 0 ));
\r
328 SendDlgItemMessage( engineOutputDialog, IDC_EngineMemo2, WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, MAKELPARAM(TRUE, 0 ));
\r
330 SetEngineState( 0, STATE_IDLE, "" );
\r
331 SetEngineState( 1, STATE_IDLE, "" );
\r
337 switch (LOWORD(wParam)) {
\r
339 EndDialog(hDlg, TRUE);
\r
343 EndDialog(hDlg, FALSE);
\r
352 case WM_GETMINMAXINFO:
\r
354 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
\r
356 mmi->ptMinTrackSize.x = 100;
\r
357 mmi->ptMinTrackSize.y = 160;
\r
362 EngineOutputPopDown();
\r
366 ResizeWindowControls( hDlg, windowMode );
\r
369 case WM_ENTERSIZEMOVE:
\r
370 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
373 return OnSizing( &sd, hDlg, wParam, lParam );
\r
376 return OnMoving( &sd, hDlg, wParam, lParam );
\r
378 case WM_EXITSIZEMOVE:
\r
379 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
386 void EngineOutputPopUp()
\r
390 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);
\r
392 if( engineOutputDialog ) {
\r
393 SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );
\r
395 if( ! engineOutputDialogUp ) {
\r
396 ShowWindow(engineOutputDialog, SW_SHOW);
\r
400 lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );
\r
402 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
\r
403 CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );
\r
405 FreeProcInstance(lpProc);
\r
408 // [HGM] displaced to after creation of dialog, to allow initialization of output fields
\r
410 InitializeEngineOutput();
\r
414 engineOutputDialogUp = TRUE;
\r
418 void EngineOutputPopDown()
\r
420 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);
\r
422 if( engineOutputDialog ) {
\r
423 ShowWindow(engineOutputDialog, SW_HIDE);
\r
426 engineOutputDialogUp = FALSE;
\r
429 // front end. [HGM] Takes handle of output control from table, so only number is passed
\r
430 void DoClearMemo(int which)
\r
432 SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" );
\r
435 //------------------------ pure back-end routines -------------------------------
\r
438 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
\r
439 static void SetEngineState( int which, int state, char * state_data )
\r
441 int x_which = 1 - which;
\r
443 if( engineState[ which ] != state ) {
\r
444 engineState[ which ] = state;
\r
447 case STATE_THINKING:
\r
448 SetIcon( which, nStateIcon, nThinking );
\r
449 if( engineState[ x_which ] == STATE_THINKING ) {
\r
450 SetEngineState( x_which, STATE_IDLE, "" );
\r
453 case STATE_PONDERING:
\r
454 SetIcon( which, nStateIcon, nPondering );
\r
456 case STATE_ANALYZING:
\r
457 SetIcon( which, nStateIcon, nAnalyzing );
\r
460 SetIcon( which, nStateIcon, nClear );
\r
465 if( state_data != 0 ) {
\r
466 DoSetWindowText( which, nStateData, state_data );
\r
470 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
\r
471 void EngineOutputUpdate( FrontEndProgramStats * stats )
\r
473 EngineOutputData ed;
\r
474 int clearMemo = FALSE;
\r
479 SetEngineState( 0, STATE_IDLE, "" );
\r
480 SetEngineState( 1, STATE_IDLE, "" );
\r
484 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
\r
485 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
\r
487 which = stats->which;
\r
488 depth = stats->depth;
\r
490 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
\r
494 if( engineOutputDialog == NULL ) {
\r
498 VerifyDisplayMode();
\r
502 ed.nodes = stats->nodes;
\r
503 ed.score = stats->score;
\r
504 ed.time = stats->time;
\r
506 ed.hint = stats->hint;
\r
507 ed.an_move_index = stats->an_move_index;
\r
508 ed.an_move_count = stats->an_move_count;
\r
510 /* Get target control. [HGM] this is moved to front end, which get them from a table */
\r
512 ed.name = first.tidy;
\r
515 ed.name = second.tidy;
\r
518 /* Clear memo if needed */
\r
519 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
\r
523 if( lastForwardMostMove[which] != forwardMostMove ) {
\r
527 if( clearMemo ) DoClearMemo(which);
\r
530 lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge
\r
531 lastForwardMostMove[which] = forwardMostMove;
\r
533 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
\r
534 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
\r
539 UpdateControls( &ed );
\r
542 #define ENGINE_COLOR_WHITE 'w'
\r
543 #define ENGINE_COLOR_BLACK 'b'
\r
544 #define ENGINE_COLOR_UNKNOWN ' '
\r
547 char GetEngineColor( int which )
\r
549 char result = ENGINE_COLOR_UNKNOWN;
\r
551 if( which == 0 || which == 1 ) {
\r
552 ChessProgramState * cps;
\r
554 switch (gameMode) {
\r
555 case MachinePlaysBlack:
\r
556 case IcsPlayingBlack:
\r
557 result = ENGINE_COLOR_BLACK;
\r
559 case MachinePlaysWhite:
\r
560 case IcsPlayingWhite:
\r
561 result = ENGINE_COLOR_WHITE;
\r
565 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
567 case TwoMachinesPlay:
\r
568 cps = (which == 0) ? &first : &second;
\r
569 result = cps->twoMachinesColor[0];
\r
570 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
572 default: ; // does not happen, but suppresses pedantic warnings
\r
580 char GetActiveEngineColor()
\r
582 char result = ENGINE_COLOR_UNKNOWN;
\r
584 if( gameMode == TwoMachinesPlay ) {
\r
585 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
592 static int IsEnginePondering( int which )
\r
594 int result = FALSE;
\r
596 switch (gameMode) {
\r
597 case MachinePlaysBlack:
\r
598 case IcsPlayingBlack:
\r
599 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
601 case MachinePlaysWhite:
\r
602 case IcsPlayingWhite:
\r
603 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
605 case TwoMachinesPlay:
\r
606 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
607 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
610 default: ; // does not happen, but suppresses pedantic warnings
\r
617 static void SetDisplayMode( int mode )
\r
619 if( windowMode != mode ) {
\r
622 ResizeWindowControls( engineOutputDialog, mode );
\r
627 static void VerifyDisplayMode()
\r
631 /* Get proper mode for current game */
\r
632 switch( gameMode ) {
\r
633 case IcsObserving: // [HGM] ICS analyze
\r
634 if(!appData.icsEngineAnalyze) return;
\r
637 case MachinePlaysWhite:
\r
638 case MachinePlaysBlack:
\r
641 case IcsPlayingWhite:
\r
642 case IcsPlayingBlack:
\r
643 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
645 case TwoMachinesPlay:
\r
649 /* Do not change */
\r
653 SetDisplayMode( mode );
\r
656 // back end. Determine what icon to se in the color-icon field, and print it
\r
657 static void SetEngineColorIcon( int which )
\r
659 char color = GetEngineColor(which);
\r
662 if( color == ENGINE_COLOR_BLACK )
\r
663 nicon = nColorBlack;
\r
664 else if( color == ENGINE_COLOR_WHITE )
\r
665 nicon = nColorWhite;
\r
667 nicon = nColorUnknown;
\r
669 SetIcon( which, nColorIcon, nicon );
\r
672 #define MAX_NAME_LENGTH 32
\r
674 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
675 static void UpdateControls( EngineOutputData * ed )
\r
677 // int isPondering = FALSE;
\r
679 char s_label[MAX_NAME_LENGTH + 32];
\r
681 char * name = ed->name;
\r
684 if( name == 0 || *name == '\0' ) {
\r
688 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
689 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
691 #ifdef SHOW_PONDERING
\r
692 if( IsEnginePondering( ed->which ) ) {
\r
697 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
698 strncpy( buf, ed->hint, sizeof(buf) );
\r
699 buf[sizeof(buf)-1] = '\0';
\r
701 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
702 char * sep = strchr( ed->pv, ' ' );
\r
703 int buflen = sizeof(buf);
\r
705 if( sep != NULL ) {
\r
706 buflen = sep - ed->pv + 1;
\r
707 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
710 strncpy( buf, ed->pv, buflen );
\r
711 buf[ buflen-1 ] = '\0';
\r
714 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
716 else if( gameMode == TwoMachinesPlay ) {
\r
717 SetEngineState( ed->which, STATE_THINKING, "" );
\r
719 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
720 || (gameMode == IcsObserving && appData.icsEngineAnalyze)) { // [HGM] ICS-analyze
\r
722 int time_secs = ed->time / 100;
\r
723 int time_mins = time_secs / 60;
\r
727 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
730 strncpy( mov, ed->hint, sizeof(mov) );
\r
731 mov[ sizeof(mov)-1 ] = '\0';
\r
733 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
736 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
739 SetEngineState( ed->which, STATE_IDLE, "" );
\r
743 DoSetWindowText( ed->which, nLabel, s_label );
\r
747 if( ed->time > 0 && ed->nodes > 0 ) {
\r
748 unsigned long nps_100 = ed->nodes / ed->time;
\r
750 if( nps_100 < 100000 ) {
\r
751 sprintf( s_label, "NPS: %lu", nps_100 * 100 );
\r
754 sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );
\r
758 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
761 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
767 int time_secs = ed->time / 100;
\r
768 int time_cent = ed->time % 100;
\r
771 if( ed->nodes < 1000000 ) {
\r
772 sprintf( s_nodes, u64Display, ed->nodes );
\r
775 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
\r
779 if( ed->score > 0 ) {
\r
780 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
783 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
787 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
789 /* Put all together... */
\r
790 if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else
\r
791 sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
794 buflen = strlen(buf);
\r
796 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
798 buf[ sizeof(buf) - 3 ] = '\0';
\r
800 strcat( buf + buflen, "\r\n" );
\r
803 InsertIntoMemo( ed->which, buf );
\r
807 SetEngineColorIcon( ed->which );
\r
811 int EngineOutputIsUp()
\r
813 return engineOutputDialogUp;
\r
816 // [HGM] kibitz: write kibitz line; split window for it if necessary
\r
817 void OutputKibitz(int window, char *text)
\r
819 if(!EngineOutputIsUp()) return;
\r
820 if(!opponentKibitzes) { // on first kibitz of game, clear memos
\r
822 if(gameMode == IcsObserving) DoClearMemo(0);
\r
824 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
\r
825 VerifyDisplayMode();
\r
826 if(gameMode == IcsObserving) {
\r
827 DoSetWindowText(0, nLabel, gameInfo.white);
\r
828 SetIcon( 0, nColorIcon, nColorWhite);
\r
829 SetIcon( 0, nStateIcon, nClear);
\r
831 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
\r
832 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
\r
833 SetIcon( 1, nStateIcon, nClear);
\r
834 InsertIntoMemo(window-1, text);
\r