Updated all files to GPL version 3.
[xboard.git] / winboard / wengineoutput.c
1 /*\r
2  * Engine output (PV)\r
3  *\r
4  * Author: Alessandro Scotti (Dec 2005)\r
5  *\r
6  * ------------------------------------------------------------------------\r
7  *
8  * GNU XBoard is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or (at
11  * your option) any later version.
12  *
13  * GNU XBoard is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see http://www.gnu.org/licenses/.
20  *
21  *------------------------------------------------------------------------
22  ** See the file ChangeLog for a revision history.  */
23
24 #include "config.h"\r
25 \r
26 #include <windows.h> /* required for all Windows applications */\r
27 #include <richedit.h>\r
28 #include <stdio.h>\r
29 #include <stdlib.h>\r
30 #include <malloc.h>\r
31 #include <commdlg.h>\r
32 #include <dlgs.h>\r
33 \r
34 #include "common.h"\r
35 #include "winboard.h"\r
36 #include "frontend.h"\r
37 #include "backend.h"\r
38 \r
39 #include "wsnap.h"\r
40 \r
41 VOID EngineOutputPopUp();\r
42 VOID EngineOutputPopDown();\r
43 BOOL EngineOutputIsUp();\r
44 \r
45 #define SHOW_PONDERING\r
46 \r
47 /* Imports from backend.c */\r
48 char * SavePart(char *str);\r
49 \r
50 /* Imports from winboard.c */\r
51 extern HWND engineOutputDialog;\r
52 extern BOOLEAN engineOutputDialogUp;\r
53 \r
54 extern HINSTANCE hInst;\r
55 extern HWND hwndMain;\r
56 \r
57 extern WindowPlacement wpEngineOutput;\r
58 \r
59 /* Module variables */\r
60 #define H_MARGIN            2\r
61 #define V_MARGIN            2\r
62 #define LABEL_V_DISTANCE    1   /* Distance between label and memo */\r
63 #define SPLITTER_SIZE       4   /* Distance between first memo and second label */\r
64 \r
65 #define ICON_SIZE           14\r
66 \r
67 #define STATE_UNKNOWN   -1\r
68 #define STATE_THINKING   0\r
69 #define STATE_IDLE       1\r
70 #define STATE_PONDERING  2\r
71 #define STATE_ANALYZING  3\r
72 \r
73 static int  windowMode = 1;\r
74 \r
75 static BOOL needInit = TRUE;\r
76 \r
77 static HICON hiColorBlack = NULL;\r
78 static HICON hiColorWhite = NULL;\r
79 static HICON hiColorUnknown = NULL;\r
80 static HICON hiClear = NULL;\r
81 static HICON hiPondering = NULL;\r
82 static HICON hiThinking = NULL;\r
83 static HICON hiAnalyzing = NULL;\r
84 \r
85 static int  lastDepth[2] = { -1, -1 };\r
86 static int  lastForwardMostMove[2] = { -1, -1 };\r
87 static int  engineState[2] = { -1, -1 };\r
88 \r
89 typedef struct {\r
90     HWND hColorIcon;\r
91     HWND hLabel;\r
92     HWND hStateIcon;\r
93     HWND hStateData;\r
94     HWND hLabelNPS;\r
95     HWND hMemo;\r
96     char * name;\r
97     int which;\r
98     int depth;\r
99     unsigned long nodes;\r
100     int score;\r
101     int time;\r
102     char * pv;\r
103     char * hint;\r
104     int an_move_index;\r
105     int an_move_count;\r
106 } EngineOutputData;\r
107 \r
108 static HICON LoadIconEx( int id )\r
109 {\r
110     return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );\r
111 }\r
112 \r
113 static VOID InitializeEngineOutput()\r
114 {\r
115     if( needInit ) {\r
116         hiColorBlack = LoadIconEx( IDI_BLACK_14 );\r
117         hiColorWhite = LoadIconEx( IDI_WHITE_14 );\r
118         hiColorUnknown = LoadIconEx( IDI_UNKNOWN_14 );\r
119         hiClear = LoadIconEx( IDI_TRANS_14 );\r
120         hiPondering = LoadIconEx( IDI_PONDER_14 );\r
121         hiThinking = LoadIconEx( IDI_CLOCK_14 );\r
122         hiAnalyzing = LoadIconEx( IDI_ANALYZE2_14 );\r
123         needInit = FALSE;\r
124     }\r
125 }\r
126 \r
127 static VOID SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )\r
128 {\r
129     HWND hControl = GetDlgItem( hDlg, id );\r
130 \r
131     SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );\r
132 }\r
133 \r
134 #define HIDDEN_X    20000\r
135 #define HIDDEN_Y    20000\r
136 \r
137 static VOID HideControl( HWND hDlg, int id )\r
138 {\r
139     HWND hControl = GetDlgItem( hDlg, id );\r
140     RECT rc;\r
141 \r
142     GetWindowRect( hControl, &rc );\r
143 \r
144     /* \r
145         Avoid hiding an already hidden control, because that causes many\r
146         unnecessary WM_ERASEBKGND messages!\r
147     */\r
148     if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {\r
149         SetControlPos( hDlg, id, 20000, 20000, 100, 100 );\r
150     }\r
151 }\r
152 \r
153 static int GetControlWidth( HWND hDlg, int id )\r
154 {\r
155     RECT rc;\r
156 \r
157     GetWindowRect( GetDlgItem( hDlg, id ), &rc );\r
158 \r
159     return rc.right - rc.left;\r
160 }\r
161 \r
162 static int GetControlHeight( HWND hDlg, int id )\r
163 {\r
164     RECT rc;\r
165 \r
166     GetWindowRect( GetDlgItem( hDlg, id ), &rc );\r
167 \r
168     return rc.bottom - rc.top;\r
169 }\r
170 \r
171 static int GetHeaderHeight()\r
172 {\r
173     int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );\r
174 \r
175     if( result < ICON_SIZE ) result = ICON_SIZE;\r
176 \r
177     return result;\r
178 }\r
179 \r
180 #define ENGINE_COLOR_WHITE      'w'\r
181 #define ENGINE_COLOR_BLACK      'b'\r
182 #define ENGINE_COLOR_UNKNOWN    ' '\r
183 \r
184 char GetEngineColor( int which )\r
185 {\r
186     char result = ENGINE_COLOR_UNKNOWN;\r
187 \r
188     if( which == 0 || which == 1 ) {\r
189         ChessProgramState * cps;\r
190 \r
191         switch (gameMode) {\r
192         case MachinePlaysBlack:\r
193         case IcsPlayingBlack:\r
194             result = ENGINE_COLOR_BLACK;\r
195             break;\r
196         case MachinePlaysWhite:\r
197         case IcsPlayingWhite:\r
198             result = ENGINE_COLOR_WHITE;\r
199             break;\r
200         case AnalyzeMode:\r
201         case AnalyzeFile:\r
202             result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
203             break;\r
204         case TwoMachinesPlay:\r
205             cps = (which == 0) ? &first : &second;\r
206             result = cps->twoMachinesColor[0];\r
207             result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
208             break;\r
209         }\r
210     }\r
211 \r
212     return result;\r
213 }\r
214 \r
215 char GetActiveEngineColor()\r
216 {\r
217     char result = ENGINE_COLOR_UNKNOWN;\r
218 \r
219     if( gameMode == TwoMachinesPlay ) {\r
220         result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
221     }\r
222 \r
223     return result;\r
224 }\r
225 \r
226 static int IsEnginePondering( int which )\r
227 {\r
228     int result = FALSE;\r
229 \r
230     switch (gameMode) {\r
231     case MachinePlaysBlack:\r
232     case IcsPlayingBlack:\r
233         if( WhiteOnMove(forwardMostMove) ) result = TRUE;\r
234         break;\r
235     case MachinePlaysWhite:\r
236     case IcsPlayingWhite:\r
237         if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;\r
238         break;\r
239     case TwoMachinesPlay:\r
240         if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {\r
241             if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;\r
242         }\r
243         break;\r
244     }\r
245 \r
246     return result;\r
247 }\r
248 \r
249 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
250 {\r
251     int label_x = x + ICON_SIZE + H_MARGIN;\r
252     int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );\r
253     int label_y = y + ICON_SIZE - label_h;\r
254     int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );\r
255     int nps_x = clientWidth - H_MARGIN - nps_w;\r
256     int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );\r
257     int state_data_x = nps_x - H_MARGIN - state_data_w;\r
258     int state_icon_x = state_data_x - ICON_SIZE - 2;\r
259     int max_w = clientWidth - 2*H_MARGIN;\r
260     int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;\r
261 \r
262     SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );\r
263     SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );\r
264     SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );\r
265     SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );\r
266     SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );\r
267     SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );\r
268 }\r
269 \r
270 static VOID ResizeWindowControls( HWND hDlg, int mode )\r
271 {\r
272     RECT rc;\r
273     int headerHeight = GetHeaderHeight();\r
274     int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );\r
275     int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;\r
276     int labelDeltaY = ICON_SIZE - labelHeight;\r
277     int clientWidth;\r
278     int clientHeight;\r
279     int maxControlWidth;\r
280     int npsWidth;\r
281 \r
282     /* Initialize variables */\r
283     GetClientRect( hDlg, &rc );\r
284 \r
285     clientWidth = rc.right - rc.left;\r
286     clientHeight = rc.bottom - rc.top;\r
287 \r
288     maxControlWidth = clientWidth - 2*H_MARGIN;\r
289 \r
290     npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );\r
291 \r
292     /* Resize controls */\r
293     if( mode == 0 ) {\r
294         /* One engine */\r
295         PositionControlSet( hDlg, H_MARGIN, V_MARGIN, \r
296             clientWidth, \r
297             clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,\r
298             IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );\r
299 \r
300         /* Hide controls for the second engine */\r
301         HideControl( hDlg, IDC_Color2 );\r
302         HideControl( hDlg, IDC_EngineLabel2 );\r
303         HideControl( hDlg, IDC_StateIcon2 );\r
304         HideControl( hDlg, IDC_StateData2 );\r
305         HideControl( hDlg, IDC_Engine2_NPS );\r
306         HideControl( hDlg, IDC_EngineMemo2 );\r
307         SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );\r
308         /* TODO: we should also hide/disable them!!! what about tab stops?!?! */\r
309     }\r
310     else {\r
311         /* Two engines */\r
312         int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;\r
313         int header1_y = V_MARGIN;\r
314         int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;\r
315 \r
316         PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,\r
317             IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );\r
318 \r
319         PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,\r
320             IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );\r
321     }\r
322 \r
323     InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );\r
324     InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );\r
325 }\r
326 \r
327 static VOID SetDisplayMode( int mode )\r
328 {\r
329     if( windowMode != mode ) {\r
330         windowMode = mode;\r
331 \r
332         ResizeWindowControls( engineOutputDialog, mode );\r
333     }\r
334 }\r
335 \r
336 static VOID VerifyDisplayMode()\r
337 {\r
338     int mode;\r
339 \r
340     /* Get proper mode for current game */\r
341     switch( gameMode ) {\r
342     case AnalyzeMode:\r
343     case AnalyzeFile:\r
344     case MachinePlaysWhite:\r
345     case MachinePlaysBlack:\r
346     case IcsPlayingWhite:\r
347     case IcsPlayingBlack:\r
348         mode = 0;\r
349         break;\r
350     case TwoMachinesPlay:\r
351         mode = 1;\r
352         break;\r
353     default:\r
354         /* Do not change */\r
355         return;\r
356     }\r
357 \r
358     SetDisplayMode( mode );\r
359 }\r
360 \r
361 static VOID InsertIntoMemo( HWND hMemo, char * text )\r
362 {\r
363     SendMessage( hMemo, EM_SETSEL, 0, 0 );\r
364 \r
365     SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );\r
366 }\r
367 \r
368 static VOID SetIcon( HWND hControl, HICON hIcon )\r
369 {\r
370     if( hIcon != NULL ) {\r
371         SendMessage( hControl, STM_SETICON, (WPARAM) hIcon, 0 );\r
372     }\r
373 }\r
374 \r
375 static VOID SetEngineColorIcon( HWND hControl, int which )\r
376 {\r
377     char color = GetEngineColor(which);\r
378     HICON hicon = NULL;\r
379 \r
380     if( color == ENGINE_COLOR_BLACK )\r
381         hicon = hiColorBlack;\r
382     else if( color == ENGINE_COLOR_WHITE )\r
383         hicon = hiColorWhite;\r
384     else\r
385         hicon = hiColorUnknown;\r
386 \r
387     SetIcon( hControl, hicon );\r
388 }\r
389 \r
390 static SetEngineState( int which, int state, char * state_data )\r
391 {\r
392     int x_which = 1 - which;\r
393     HWND hStateIcon = GetDlgItem( engineOutputDialog, which == 0 ? IDC_StateIcon1 : IDC_StateIcon2 );\r
394     HWND hStateData = GetDlgItem( engineOutputDialog, which == 0 ? IDC_StateData1 : IDC_StateData2 );\r
395 \r
396     if( engineState[ which ] != state ) {\r
397         engineState[ which ] = state;\r
398 \r
399         switch( state ) {\r
400         case STATE_THINKING:\r
401             SetIcon( hStateIcon, hiThinking );\r
402             if( engineState[ x_which ] == STATE_THINKING ) {\r
403                 SetEngineState( x_which, STATE_IDLE, "" );\r
404             }\r
405             break;\r
406         case STATE_PONDERING:\r
407             SetIcon( hStateIcon, hiPondering );\r
408             break;\r
409         case STATE_ANALYZING:\r
410             SetIcon( hStateIcon, hiAnalyzing );\r
411             break;\r
412         default:\r
413             SetIcon( hStateIcon, hiClear );\r
414             break;\r
415         }\r
416     }\r
417 \r
418     if( state_data != 0 ) {\r
419         SetWindowText( hStateData, state_data );\r
420     }\r
421 }\r
422 \r
423 #define MAX_NAME_LENGTH 32\r
424 \r
425 static VOID UpdateControls( EngineOutputData * ed )\r
426 {\r
427     BOOL isPondering = FALSE;\r
428 \r
429     char s_label[MAX_NAME_LENGTH + 32];\r
430     \r
431     char * name = ed->name;\r
432 \r
433     /* Label */\r
434     if( name == 0 || *name == '\0' ) {\r
435         name = "?";\r
436     }\r
437 \r
438     strncpy( s_label, name, MAX_NAME_LENGTH );\r
439     s_label[ MAX_NAME_LENGTH-1 ] = '\0';\r
440 \r
441 #ifdef SHOW_PONDERING\r
442     if( IsEnginePondering( ed->which ) ) {\r
443         char buf[8];\r
444 \r
445         buf[0] = '\0';\r
446 \r
447         if( ed->hint != 0 && *ed->hint != '\0' ) {\r
448             strncpy( buf, ed->hint, sizeof(buf) );\r
449             buf[sizeof(buf)-1] = '\0';\r
450         }\r
451         else if( ed->pv != 0 && *ed->pv != '\0' ) {\r
452             char * sep = strchr( ed->pv, ' ' );\r
453             int buflen = sizeof(buf);\r
454 \r
455             if( sep != NULL ) {\r
456                 buflen = sep - ed->pv + 1;\r
457                 if( buflen > sizeof(buf) ) buflen = sizeof(buf);\r
458             }\r
459 \r
460             strncpy( buf, ed->pv, buflen );\r
461             buf[ buflen-1 ] = '\0';\r
462         }\r
463 \r
464         SetEngineState( ed->which, STATE_PONDERING, buf );\r
465     }\r
466     else if( gameMode == TwoMachinesPlay ) {\r
467         SetEngineState( ed->which, STATE_THINKING, "" );\r
468     }\r
469     else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile ) {\r
470         char buf[64];\r
471         int time_secs = ed->time / 100;\r
472         int time_mins = time_secs / 60;\r
473 \r
474         buf[0] = '\0';\r
475 \r
476         if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {\r
477             char mov[16];\r
478 \r
479             strncpy( mov, ed->hint, sizeof(mov) );\r
480             mov[ sizeof(mov)-1 ] = '\0';\r
481 \r
482             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
483         }\r
484 \r
485         SetEngineState( ed->which, STATE_ANALYZING, buf );\r
486     }\r
487     else {\r
488         SetEngineState( ed->which, STATE_IDLE, "" );\r
489     }\r
490 #endif\r
491 \r
492     SetWindowText( ed->hLabel, s_label );\r
493 \r
494     s_label[0] = '\0';\r
495 \r
496     if( ed->time > 0 && ed->nodes > 0 ) {\r
497         unsigned long nps_100 = ed->nodes / ed->time;\r
498 \r
499         if( nps_100 < 100000 ) {\r
500             sprintf( s_label, "NPS: %lu", nps_100 * 100 );\r
501         }\r
502         else {\r
503             sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );\r
504         }\r
505     }\r
506 \r
507     SetWindowText( ed->hLabelNPS, s_label );\r
508 \r
509     /* Memo */\r
510     if( ed->pv != 0 && *ed->pv != '\0' ) {\r
511         char s_nodes[24];\r
512         char s_score[16];\r
513         char s_time[24];\r
514         char buf[256];\r
515         int buflen;\r
516         int time_secs = ed->time / 100;\r
517         int time_cent = ed->time % 100;\r
518 \r
519         /* Nodes */\r
520         if( ed->nodes < 1000000 ) {\r
521             sprintf( s_nodes, "%lu", ed->nodes );\r
522         }\r
523         else {\r
524             sprintf( s_nodes, "%.1fM", ed->nodes / 1000000.0 );\r
525         }\r
526 \r
527         /* Score */\r
528         if( ed->score > 0 ) {\r
529             sprintf( s_score, "+%.2f", ed->score / 100.0 );\r
530         }\r
531         else {\r
532             sprintf( s_score, "%.2f", ed->score / 100.0 );\r
533         }\r
534 \r
535         /* Time */\r
536         sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );\r
537 \r
538         /* Put all together... */\r
539         sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time );\r
540 \r
541         /* Add PV */\r
542         buflen = strlen(buf);\r
543 \r
544         strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );\r
545 \r
546         buf[ sizeof(buf) - 3 ] = '\0';\r
547 \r
548         strcat( buf + buflen, "\r\n" );\r
549 \r
550         /* Update memo */\r
551         InsertIntoMemo( ed->hMemo, buf );\r
552     }\r
553 \r
554     /* Colors */\r
555     SetEngineColorIcon( ed->hColorIcon, ed->which );\r
556 }\r
557 \r
558 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
559 {\r
560     static SnapData sd;\r
561 \r
562     switch (message) {\r
563     case WM_INITDIALOG:\r
564         if( engineOutputDialog == NULL ) {\r
565             engineOutputDialog = hDlg;\r
566 \r
567             RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */\r
568 \r
569             ResizeWindowControls( hDlg, windowMode );\r
570 \r
571             SetEngineState( 0, STATE_IDLE, "" );\r
572             SetEngineState( 1, STATE_IDLE, "" );\r
573         }\r
574 \r
575         return FALSE;\r
576 \r
577     case WM_COMMAND:\r
578         switch (LOWORD(wParam)) {\r
579         case IDOK:\r
580           EndDialog(hDlg, TRUE);\r
581           return TRUE;\r
582 \r
583         case IDCANCEL:\r
584           EndDialog(hDlg, FALSE);\r
585           return TRUE;\r
586 \r
587         default:\r
588           break;\r
589         }\r
590 \r
591         break;\r
592 \r
593     case WM_GETMINMAXINFO:\r
594         {\r
595             MINMAXINFO * mmi = (MINMAXINFO *) lParam;\r
596         \r
597             mmi->ptMinTrackSize.x = 100;\r
598             mmi->ptMinTrackSize.y = 160;\r
599         }\r
600         break;\r
601 \r
602     case WM_CLOSE:\r
603         EngineOutputPopDown();\r
604         break;\r
605 \r
606     case WM_SIZE:\r
607         ResizeWindowControls( hDlg, windowMode );\r
608         break;\r
609 \r
610     case WM_ENTERSIZEMOVE:\r
611         return OnEnterSizeMove( &sd, hDlg, wParam, lParam );\r
612 \r
613     case WM_SIZING:\r
614         return OnSizing( &sd, hDlg, wParam, lParam );\r
615 \r
616     case WM_MOVING:\r
617         return OnMoving( &sd, hDlg, wParam, lParam );\r
618 \r
619     case WM_EXITSIZEMOVE:\r
620         return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
621     }\r
622 \r
623     return FALSE;\r
624 }\r
625 \r
626 VOID EngineOutputPopUp()\r
627 {\r
628   FARPROC lpProc;\r
629 \r
630   if( needInit ) {\r
631       InitializeEngineOutput();\r
632   }\r
633   \r
634   CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);\r
635 \r
636   if( engineOutputDialog ) {\r
637     SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );\r
638 \r
639     if( ! engineOutputDialogUp ) {\r
640         ShowWindow(engineOutputDialog, SW_SHOW);\r
641     }\r
642   }\r
643   else {\r
644     lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );\r
645 \r
646     /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */\r
647     CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );\r
648 \r
649     FreeProcInstance(lpProc);\r
650   }\r
651 \r
652   engineOutputDialogUp = TRUE;\r
653   ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
654 }\r
655 \r
656 VOID EngineOutputPopDown()\r
657 {\r
658   CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);\r
659 \r
660   if( engineOutputDialog ) {\r
661       ShowWindow(engineOutputDialog, SW_HIDE);\r
662   }\r
663 \r
664   engineOutputDialogUp = FALSE;\r
665   ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
666 }\r
667 \r
668 BOOL EngineOutputIsUp()\r
669 {\r
670     return engineOutputDialogUp;\r
671 }\r
672 \r
673 VOID EngineOutputUpdate( FrontEndProgramStats * stats )\r
674 {\r
675     EngineOutputData ed;\r
676     BOOL clearMemo = FALSE;\r
677     int which;\r
678     int depth;\r
679 \r
680     if( stats == 0 ) {\r
681         SetEngineState( 0, STATE_IDLE, "" );\r
682         SetEngineState( 1, STATE_IDLE, "" );\r
683         return;\r
684     }\r
685 \r
686     which = stats->which;\r
687     depth = stats->depth;\r
688 \r
689     if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {\r
690         return;\r
691     }\r
692 \r
693     if( engineOutputDialog == NULL ) {\r
694         return;\r
695     }\r
696 \r
697     VerifyDisplayMode();\r
698 \r
699     ed.which = which;\r
700     ed.depth = depth;\r
701     ed.nodes = stats->nodes;\r
702     ed.score = stats->score;\r
703     ed.time = stats->time;\r
704     ed.pv = stats->pv;\r
705     ed.hint = stats->hint;\r
706     ed.an_move_index = stats->an_move_index;\r
707     ed.an_move_count = stats->an_move_count;\r
708 \r
709     /* Get target control */\r
710     if( which == 0 ) {\r
711         ed.hColorIcon = GetDlgItem( engineOutputDialog, IDC_Color1 );\r
712         ed.hLabel = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );\r
713         ed.hStateIcon = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );\r
714         ed.hStateData = GetDlgItem( engineOutputDialog, IDC_StateData1 );\r
715         ed.hLabelNPS = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );\r
716         ed.hMemo  = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );\r
717         ed.name = first.tidy;\r
718     }\r
719     else {\r
720         ed.hColorIcon = GetDlgItem( engineOutputDialog, IDC_Color2 );\r
721         ed.hLabel = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );\r
722         ed.hStateIcon = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );\r
723         ed.hStateData = GetDlgItem( engineOutputDialog, IDC_StateData2 );\r
724         ed.hLabelNPS = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );\r
725         ed.hMemo  = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );\r
726         ed.name = second.tidy;\r
727     }\r
728 \r
729     /* Clear memo if needed */\r
730     if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {\r
731         clearMemo = TRUE;\r
732     }\r
733 \r
734     if( lastForwardMostMove[which] != forwardMostMove ) {\r
735         clearMemo = TRUE;\r
736     }\r
737 \r
738     if( clearMemo ) {\r
739         SendMessage( ed.hMemo, WM_SETTEXT, 0, (LPARAM) "" );\r
740     }\r
741 \r
742     /* Update */\r
743     lastDepth[which] = depth;\r
744     lastForwardMostMove[which] = forwardMostMove;\r
745 \r
746     if( ed.pv != 0 && ed.pv[0] == ' ' ) {\r
747         if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */\r
748             ed.pv = "";\r
749         }\r
750     }\r
751 \r
752     UpdateControls( &ed );\r
753 }\r