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 "winboard.h"
\r
38 #include "frontend.h"
\r
39 #include "backend.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 void EngineOutputPopUp();
\r
65 void EngineOutputPopDown();
\r
66 int EngineOutputIsUp();
\r
68 #define SHOW_PONDERING
\r
70 /* Imports from backend.c */
\r
71 char * SavePart(char *str);
\r
72 extern int opponentKibitzes;
\r
74 /* Imports from winboard.c */
\r
75 extern HWND engineOutputDialog;
\r
76 extern int engineOutputDialogUp;
\r
78 extern HINSTANCE hInst;
\r
79 extern HWND hwndMain;
\r
81 extern WindowPlacement wpEngineOutput;
\r
83 extern BoardSize boardSize;
\r
85 /* Module variables */
\r
88 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
\r
89 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
\r
91 #define ICON_SIZE 14
\r
93 #define STATE_UNKNOWN -1
\r
94 #define STATE_THINKING 0
\r
95 #define STATE_IDLE 1
\r
96 #define STATE_PONDERING 2
\r
97 #define STATE_ANALYZING 3
\r
99 static int windowMode = 1;
\r
101 static int needInit = TRUE;
\r
103 static int lastDepth[2] = { -1, -1 };
\r
104 static int lastForwardMostMove[2] = { -1, -1 };
\r
105 static int engineState[2] = { -1, -1 };
\r
108 // HWND hColorIcon; // [HGM] the output-control handles are no loger passed,
\r
109 // HWND hLabel; // to give better front-end / back-end separation
\r
110 // HWND hStateIcon; // the front-end routines now get them from a (front-end)
\r
111 // HWND hStateData; // table, indexed by output-field indicators.
\r
124 } EngineOutputData;
\r
126 static void VerifyDisplayMode();
\r
127 static void UpdateControls( EngineOutputData * ed );
\r
128 static void SetEngineState( int which, int state, char * state_data );
\r
131 static HICON LoadIconEx( int id )
\r
133 return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );
\r
136 // [HGM] the platform-dependent way of indicating where output should go is now all
\r
137 // concentrated here, where a table of platform-dependent handles are initialized.
\r
138 // This cleanses most other routines of front-end stuff, so they can go into the back end.
\r
139 static void InitializeEngineOutput()
\r
141 // if( needInit ) { // needInit was already tested before call
\r
142 // [HGM] made this into a table, rather than separate global variables
\r
143 icons[nColorBlack] = LoadIconEx( IDI_BLACK_14 );
\r
144 icons[nColorWhite] = LoadIconEx( IDI_WHITE_14 );
\r
145 icons[nColorUnknown] = LoadIconEx( IDI_UNKNOWN_14 );
\r
146 icons[nClear] = LoadIconEx( IDI_TRANS_14 );
\r
147 icons[nPondering] = LoadIconEx( IDI_PONDER_14 );
\r
148 icons[nThinking] = LoadIconEx( IDI_CLOCK_14 );
\r
149 icons[nAnalyzing] = LoadIconEx( IDI_ANALYZE2_14 );
\r
151 // [HGM] also make a table of handles to output controls
\r
152 // Note that engineOutputDialog must be defined first!
\r
153 outputField[0][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color1 );
\r
154 outputField[0][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );
\r
155 outputField[0][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );
\r
156 outputField[0][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData1 );
\r
157 outputField[0][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );
\r
158 outputField[0][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );
\r
160 outputField[1][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color2 );
\r
161 outputField[1][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );
\r
162 outputField[1][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );
\r
163 outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 );
\r
164 outputField[1][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );
\r
165 outputField[1][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );
\r
166 // needInit = FALSE;
\r
171 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )
\r
173 HWND hControl = GetDlgItem( hDlg, id );
\r
175 SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );
\r
178 #define HIDDEN_X 20000
\r
179 #define HIDDEN_Y 20000
\r
182 static void HideControl( HWND hDlg, int id )
\r
184 HWND hControl = GetDlgItem( hDlg, id );
\r
187 GetWindowRect( hControl, &rc );
\r
190 Avoid hiding an already hidden control, because that causes many
\r
191 unnecessary WM_ERASEBKGND messages!
\r
193 if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {
\r
194 SetControlPos( hDlg, id, 20000, 20000, 100, 100 );
\r
198 // front end, although we might make GetWindowRect front end instead
\r
199 static int GetControlWidth( HWND hDlg, int id )
\r
203 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
205 return rc.right - rc.left;
\r
209 static int GetControlHeight( HWND hDlg, int id )
\r
213 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
215 return rc.bottom - rc.top;
\r
218 static int GetHeaderHeight()
\r
220 int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );
\r
222 if( result < ICON_SIZE ) result = ICON_SIZE;
\r
227 // The size calculations should be backend? If setControlPos is a platform-dependent way of doing things,
\r
228 // a platform-independent wrapper for it should be supplied.
\r
229 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
231 int label_x = x + ICON_SIZE + H_MARGIN;
\r
232 int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
233 int label_y = y + ICON_SIZE - label_h;
\r
234 int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
235 int nps_x = clientWidth - H_MARGIN - nps_w;
\r
236 int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );
\r
237 int state_data_x = nps_x - H_MARGIN - state_data_w;
\r
238 int state_icon_x = state_data_x - ICON_SIZE - 2;
\r
239 int max_w = clientWidth - 2*H_MARGIN;
\r
240 int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;
\r
242 SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );
\r
243 SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );
\r
244 SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );
\r
245 SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );
\r
246 SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );
\r
247 SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );
\r
250 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine
\r
251 static void ResizeWindowControls( HWND hDlg, int mode )
\r
254 int headerHeight = GetHeaderHeight();
\r
255 // int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
256 // int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;
\r
257 // int labelDeltaY = ICON_SIZE - labelHeight;
\r
260 int maxControlWidth;
\r
263 /* Initialize variables */
\r
264 GetClientRect( hDlg, &rc );
\r
266 clientWidth = rc.right - rc.left;
\r
267 clientHeight = rc.bottom - rc.top;
\r
269 maxControlWidth = clientWidth - 2*H_MARGIN;
\r
271 npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
273 /* Resize controls */
\r
276 PositionControlSet( hDlg, H_MARGIN, V_MARGIN,
\r
278 clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,
\r
279 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
281 /* Hide controls for the second engine */
\r
282 HideControl( hDlg, IDC_Color2 );
\r
283 HideControl( hDlg, IDC_EngineLabel2 );
\r
284 HideControl( hDlg, IDC_StateIcon2 );
\r
285 HideControl( hDlg, IDC_StateData2 );
\r
286 HideControl( hDlg, IDC_Engine2_NPS );
\r
287 HideControl( hDlg, IDC_EngineMemo2 );
\r
288 SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );
\r
289 /* TODO: we should also hide/disable them!!! what about tab stops?!?! */
\r
293 int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;
\r
294 int header1_y = V_MARGIN;
\r
295 int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;
\r
297 PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,
\r
298 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
300 PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,
\r
301 IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );
\r
304 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );
\r
305 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );
\r
308 // front end. Actual printing of PV lines into the output field
\r
309 static void InsertIntoMemo( int which, char * text )
\r
311 SendMessage( outputField[which][nMemo], EM_SETSEL, 0, 0 );
\r
313 SendMessage( outputField[which][nMemo], EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );
\r
316 // front end. Associates an icon with an output field ("control" in Windows jargon).
\r
317 // [HGM] let it find out the output field from the 'which' number by itself
\r
318 static void SetIcon( int which, int field, int nIcon )
\r
322 SendMessage( outputField[which][field], STM_SETICON, (WPARAM) icons[nIcon], 0 );
\r
326 // front end wrapper for SetWindowText, taking control number in stead of handle
\r
327 void DoSetWindowText(int which, int field, char *s_label)
\r
329 SetWindowText( outputField[which][field], s_label );
\r
332 // This seems pure front end
\r
333 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
\r
335 static SnapData sd;
\r
338 case WM_INITDIALOG:
\r
339 if( engineOutputDialog == NULL ) {
\r
340 engineOutputDialog = hDlg;
\r
342 RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */
\r
344 ResizeWindowControls( hDlg, windowMode );
\r
347 SendDlgItemMessage( engineOutputDialog, IDC_EngineMemo1, WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, MAKELPARAM(TRUE, 0 ));
\r
348 SendDlgItemMessage( engineOutputDialog, IDC_EngineMemo2, WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, MAKELPARAM(TRUE, 0 ));
\r
350 SetEngineState( 0, STATE_IDLE, "" );
\r
351 SetEngineState( 1, STATE_IDLE, "" );
\r
357 switch (LOWORD(wParam)) {
\r
359 EndDialog(hDlg, TRUE);
\r
363 EndDialog(hDlg, FALSE);
\r
372 case WM_GETMINMAXINFO:
\r
374 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
\r
376 mmi->ptMinTrackSize.x = 100;
\r
377 mmi->ptMinTrackSize.y = 160;
\r
382 EngineOutputPopDown();
\r
386 ResizeWindowControls( hDlg, windowMode );
\r
389 case WM_ENTERSIZEMOVE:
\r
390 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
393 return OnSizing( &sd, hDlg, wParam, lParam );
\r
396 return OnMoving( &sd, hDlg, wParam, lParam );
\r
398 case WM_EXITSIZEMOVE:
\r
399 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
406 void EngineOutputPopUp()
\r
410 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);
\r
412 if( engineOutputDialog ) {
\r
413 SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );
\r
415 if( ! engineOutputDialogUp ) {
\r
416 ShowWindow(engineOutputDialog, SW_SHOW);
\r
420 lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );
\r
422 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
\r
423 CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );
\r
425 FreeProcInstance(lpProc);
\r
428 // [HGM] displaced to after creation of dialog, to allow initialization of output fields
\r
430 InitializeEngineOutput();
\r
434 engineOutputDialogUp = TRUE;
\r
438 void EngineOutputPopDown()
\r
440 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);
\r
442 if( engineOutputDialog ) {
\r
443 ShowWindow(engineOutputDialog, SW_HIDE);
\r
446 engineOutputDialogUp = FALSE;
\r
449 // front end. [HGM] Takes handle of output control from table, so only number is passed
\r
450 void DoClearMemo(int which)
\r
452 SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" );
\r
455 //------------------------ pure back-end routines -------------------------------
\r
458 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
\r
459 static void SetEngineState( int which, int state, char * state_data )
\r
461 int x_which = 1 - which;
\r
463 if( engineState[ which ] != state ) {
\r
464 engineState[ which ] = state;
\r
467 case STATE_THINKING:
\r
468 SetIcon( which, nStateIcon, nThinking );
\r
469 if( engineState[ x_which ] == STATE_THINKING ) {
\r
470 SetEngineState( x_which, STATE_IDLE, "" );
\r
473 case STATE_PONDERING:
\r
474 SetIcon( which, nStateIcon, nPondering );
\r
476 case STATE_ANALYZING:
\r
477 SetIcon( which, nStateIcon, nAnalyzing );
\r
480 SetIcon( which, nStateIcon, nClear );
\r
485 if( state_data != 0 ) {
\r
486 DoSetWindowText( which, nStateData, state_data );
\r
490 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
\r
491 void EngineOutputUpdate( FrontEndProgramStats * stats )
\r
493 EngineOutputData ed;
\r
494 int clearMemo = FALSE;
\r
499 SetEngineState( 0, STATE_IDLE, "" );
\r
500 SetEngineState( 1, STATE_IDLE, "" );
\r
504 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
\r
505 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
\r
507 which = stats->which;
\r
508 depth = stats->depth;
\r
510 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
\r
514 if( engineOutputDialog == NULL ) {
\r
518 VerifyDisplayMode();
\r
522 ed.nodes = stats->nodes;
\r
523 ed.score = stats->score;
\r
524 ed.time = stats->time;
\r
526 ed.hint = stats->hint;
\r
527 ed.an_move_index = stats->an_move_index;
\r
528 ed.an_move_count = stats->an_move_count;
\r
530 /* Get target control. [HGM] this is moved to front end, which get them from a table */
\r
532 ed.name = first.tidy;
\r
535 ed.name = second.tidy;
\r
538 /* Clear memo if needed */
\r
539 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
\r
543 if( lastForwardMostMove[which] != forwardMostMove ) {
\r
547 if( clearMemo ) DoClearMemo(which);
\r
550 lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge
\r
551 lastForwardMostMove[which] = forwardMostMove;
\r
553 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
\r
554 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
\r
559 UpdateControls( &ed );
\r
562 #define ENGINE_COLOR_WHITE 'w'
\r
563 #define ENGINE_COLOR_BLACK 'b'
\r
564 #define ENGINE_COLOR_UNKNOWN ' '
\r
567 char GetEngineColor( int which )
\r
569 char result = ENGINE_COLOR_UNKNOWN;
\r
571 if( which == 0 || which == 1 ) {
\r
572 ChessProgramState * cps;
\r
574 switch (gameMode) {
\r
575 case MachinePlaysBlack:
\r
576 case IcsPlayingBlack:
\r
577 result = ENGINE_COLOR_BLACK;
\r
579 case MachinePlaysWhite:
\r
580 case IcsPlayingWhite:
\r
581 result = ENGINE_COLOR_WHITE;
\r
585 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
587 case TwoMachinesPlay:
\r
588 cps = (which == 0) ? &first : &second;
\r
589 result = cps->twoMachinesColor[0];
\r
590 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
592 default: ; // does not happen, but suppresses pedantic warnings
\r
600 char GetActiveEngineColor()
\r
602 char result = ENGINE_COLOR_UNKNOWN;
\r
604 if( gameMode == TwoMachinesPlay ) {
\r
605 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
612 static int IsEnginePondering( int which )
\r
614 int result = FALSE;
\r
616 switch (gameMode) {
\r
617 case MachinePlaysBlack:
\r
618 case IcsPlayingBlack:
\r
619 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
621 case MachinePlaysWhite:
\r
622 case IcsPlayingWhite:
\r
623 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
625 case TwoMachinesPlay:
\r
626 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
627 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
630 default: ; // does not happen, but suppresses pedantic warnings
\r
637 static void SetDisplayMode( int mode )
\r
639 if( windowMode != mode ) {
\r
642 ResizeWindowControls( engineOutputDialog, mode );
\r
647 static void VerifyDisplayMode()
\r
651 /* Get proper mode for current game */
\r
652 switch( gameMode ) {
\r
653 case IcsObserving: // [HGM] ICS analyze
\r
654 if(!appData.icsEngineAnalyze) return;
\r
657 case MachinePlaysWhite:
\r
658 case MachinePlaysBlack:
\r
661 case IcsPlayingWhite:
\r
662 case IcsPlayingBlack:
\r
663 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
665 case TwoMachinesPlay:
\r
669 /* Do not change */
\r
673 SetDisplayMode( mode );
\r
676 // back end. Determine what icon to se in the color-icon field, and print it
\r
677 static void SetEngineColorIcon( int which )
\r
679 char color = GetEngineColor(which);
\r
682 if( color == ENGINE_COLOR_BLACK )
\r
683 nicon = nColorBlack;
\r
684 else if( color == ENGINE_COLOR_WHITE )
\r
685 nicon = nColorWhite;
\r
687 nicon = nColorUnknown;
\r
689 SetIcon( which, nColorIcon, nicon );
\r
692 #define MAX_NAME_LENGTH 32
\r
694 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
695 static void UpdateControls( EngineOutputData * ed )
\r
697 // int isPondering = FALSE;
\r
699 char s_label[MAX_NAME_LENGTH + 32];
\r
701 char * name = ed->name;
\r
704 if( name == 0 || *name == '\0' ) {
\r
708 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
709 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
711 #ifdef SHOW_PONDERING
\r
712 if( IsEnginePondering( ed->which ) ) {
\r
717 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
718 strncpy( buf, ed->hint, sizeof(buf) );
\r
719 buf[sizeof(buf)-1] = '\0';
\r
721 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
722 char * sep = strchr( ed->pv, ' ' );
\r
723 int buflen = sizeof(buf);
\r
725 if( sep != NULL ) {
\r
726 buflen = sep - ed->pv + 1;
\r
727 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
730 strncpy( buf, ed->pv, buflen );
\r
731 buf[ buflen-1 ] = '\0';
\r
734 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
736 else if( gameMode == TwoMachinesPlay ) {
\r
737 SetEngineState( ed->which, STATE_THINKING, "" );
\r
739 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
740 || (gameMode == IcsObserving && appData.icsEngineAnalyze)) { // [HGM] ICS-analyze
\r
742 int time_secs = ed->time / 100;
\r
743 int time_mins = time_secs / 60;
\r
747 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
750 strncpy( mov, ed->hint, sizeof(mov) );
\r
751 mov[ sizeof(mov)-1 ] = '\0';
\r
753 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
756 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
759 SetEngineState( ed->which, STATE_IDLE, "" );
\r
763 DoSetWindowText( ed->which, nLabel, s_label );
\r
767 if( ed->time > 0 && ed->nodes > 0 ) {
\r
768 unsigned long nps_100 = ed->nodes / ed->time;
\r
770 if( nps_100 < 100000 ) {
\r
771 sprintf( s_label, "NPS: %lu", nps_100 * 100 );
\r
774 sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );
\r
778 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
781 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
787 int time_secs = ed->time / 100;
\r
788 int time_cent = ed->time % 100;
\r
791 if( ed->nodes < 1000000 ) {
\r
792 sprintf( s_nodes, u64Display, ed->nodes );
\r
795 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
\r
799 if( ed->score > 0 ) {
\r
800 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
803 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
807 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
809 /* Put all together... */
\r
810 if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else
\r
811 sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
814 buflen = strlen(buf);
\r
816 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
818 buf[ sizeof(buf) - 3 ] = '\0';
\r
820 strcat( buf + buflen, "\r\n" );
\r
823 InsertIntoMemo( ed->which, buf );
\r
827 SetEngineColorIcon( ed->which );
\r
831 int EngineOutputIsUp()
\r
833 return engineOutputDialogUp;
\r
836 // [HGM] kibitz: write kibitz line; split window for it if necessary
\r
837 void OutputKibitz(int window, char *text)
\r
839 if(!EngineOutputIsUp()) return;
\r
840 if(!opponentKibitzes) { // on first kibitz of game, clear memos
\r
842 if(gameMode == IcsObserving) DoClearMemo(0);
\r
844 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
\r
845 VerifyDisplayMode();
\r
846 if(gameMode == IcsObserving) {
\r
847 DoSetWindowText(0, nLabel, gameInfo.white);
\r
848 SetIcon( 0, nColorIcon, nColorWhite);
\r
849 SetIcon( 0, nStateIcon, nClear);
\r
851 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
\r
852 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
\r
853 SetIcon( 1, nStateIcon, nClear);
\r
854 InsertIntoMemo(window-1, text);
\r