changes from H.G. Muller; version 4.3.15
[xboard.git] / xengineoutput.c
1 /*\r
2  * Engine output (PV)\r
3  *\r
4  * Author: Alessandro Scotti (Dec 2005)\r
5  *\r
6  * ------------------------------------------------------------------------\r
7  * This program is free software; you can redistribute it and/or modify\r
8  * it under the terms of the GNU General Public License as published by\r
9  * the Free Software Foundation; either version 2 of the License, or\r
10  * (at your option) any later version.\r
11  *\r
12  * This program is distributed in the hope that it will be useful,\r
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15  * GNU General Public License for more details.\r
16  *\r
17  * You should have received a copy of the GNU General Public License\r
18  * along with this program; if not, write to the Free Software\r
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
20  * ------------------------------------------------------------------------\r
21  */\r
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <sys/types.h>
28
29 #if STDC_HEADERS
30 # include <stdlib.h>
31 # include <string.h>
32 #else /* not STDC_HEADERS */
33 extern char *getenv();
34 # if HAVE_STRING_H
35 #  include <string.h>
36 # else /* not HAVE_STRING_H */
37 #  include <strings.h>
38 # endif /* not HAVE_STRING_H */
39 #endif /* not STDC_HEADERS */
40
41 #if HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44
45 #include <X11/Intrinsic.h>
46 #include <X11/StringDefs.h>
47 #include <X11/Shell.h>
48 #include <X11/Xaw/Dialog.h>
49 #include <X11/Xaw/Form.h>
50 #include <X11/Xaw/List.h>
51 #include <X11/Xaw/Label.h>
52 #include <X11/Xaw/SimpleMenu.h>
53 #include <X11/Xaw/SmeBSB.h>
54 #include <X11/Xaw/SmeLine.h>
55 #include <X11/Xaw/Box.h>
56 #include <X11/Xaw/Paned.h>
57 #include <X11/Xaw/MenuButton.h>
58 #include <X11/cursorfont.h>
59 #include <X11/Xaw/Text.h>
60 #include <X11/Xaw/AsciiText.h>
61 #include <X11/Xaw/Viewport.h>
62
63 #include "common.h"
64 #include "frontend.h"
65 #include "backend.h"
66 #include "xboard.h"
67 // Add xengineo.h later
68
69 #include <X11/xpm.h>\r
70
71 // [HGM] pixmaps of some ICONS used in the engine-outut window
72 #include "pixmaps/WHITE_14.xpm"
73 #include "pixmaps/BLACK_14.xpm"
74 #include "pixmaps/CLEAR_14.xpm"
75 #include "pixmaps/UNKNOWN_14.xpm"
76 #include "pixmaps/THINKING_14.xpm"
77 #include "pixmaps/PONDER_14.xpm"
78 #include "pixmaps/ANALYZING_14.xpm"
79
80 #ifdef SNAP\r
81 #include "wsnap.h"\r
82 #endif
83
84 #define _LL_ 100
85
86 // imports from xboard.c
87 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
88 extern Display *xDisplay;
89 extern Window xBoardWindow;
90 extern int squareSize;
91 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
92 extern char *layoutName;
93
94 // temporary kludge to avoid compile errors untill all Windows code has been replaced
95 #define HICON int *
96 #define HWND  int *
97 \r
98 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way\r
99 #define nColorBlack   1\r
100 #define nColorWhite   2\r
101 #define nColorUnknown 3\r
102 #define nClear        4\r
103 #define nPondering    5\r
104 #define nThinking     6\r
105 #define nAnalyzing    7\r
106 \r
107 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle\r
108 \r
109 // [HGM] same for output fields (note that there are two of each type, one per color)\r
110 #define nColorIcon 1\r
111 #define nStateIcon 2\r
112 #define nLabel     3\r
113 #define nStateData 4\r
114 #define nLabelNPS  5\r
115 #define nMemo      6\r
116 \r
117 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle\r
118 \r
119 void EngineOutputPopDown();\r
120 void engineOutputPopUp(char *title, char *text);\r
121 int  EngineOutputIsUp();\r
122 static void SetEngineColorIcon( int which );\r
123 \r
124 #define SHOW_PONDERING\r
125 \r
126 /* Imports from backend.c */\r
127 char * SavePart(char *str);\r
128 \r
129 /* Imports from winboard.c */\r
130 //extern HWND engineOutputDialog;\r
131 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];\r
132 \r
133 //extern WindowPlacement wpEngineOutput;\r
134
135 Position engineOutputX = -1, engineOutputY = -1;
136 Dimension engineOutputW, engineOutputH;
137 Widget engineOutputShell;
138 int engineOutputDialogUp;
139
140 /* Module variables */\r
141 #define H_MARGIN            2\r
142 #define V_MARGIN            2\r
143 #define LABEL_V_DISTANCE    1   /* Distance between label and memo */\r
144 #define SPLITTER_SIZE       4   /* Distance between first memo and second label */\r
145 \r
146 #define ICON_SIZE           14\r
147 \r
148 #define STATE_UNKNOWN   -1\r
149 #define STATE_THINKING   0\r
150 #define STATE_IDLE       1\r
151 #define STATE_PONDERING  2\r
152 #define STATE_ANALYZING  3\r
153 \r
154 static int  windowMode = 1;\r
155 \r
156 static int  needInit = TRUE;\r
157 \r
158 static int  lastDepth[2] = { -1, -1 };\r
159 static int  lastForwardMostMove[2] = { -1, -1 };\r
160 static int  engineState[2] = { -1, -1 };\r
161 \r
162 typedef struct {\r
163     char * name;\r
164     int which;\r
165     int depth;\r
166     unsigned long nodes;\r
167     int score;\r
168     int time;\r
169     char * pv;\r
170     char * hint;\r
171     int an_move_index;\r
172     int an_move_count;\r
173 } EngineOutputData;\r
174 \r
175 static VerifyDisplayMode();\r
176 static void UpdateControls( EngineOutputData * ed );\r
177 static SetEngineState( int which, int state, char * state_data );\r
178
179 void ReadIcon(char *pixData[], int iconNr)
180 {
181     int r;
182
183         if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),\r
184                                        pixData,\r
185                                        &(icons[iconNr]),\r
186                                        NULL, NULL /*&attr*/)) != 0) {\r
187           fprintf(stderr, "Error %d loading icon image\n", r);\r
188           exit(1); \r
189         }       \r
190 }
191
192 static void InitializeEngineOutput()\r
193 { int i;
194
195         ReadIcon(WHITE_14,   nColorWhite);\r
196         ReadIcon(BLACK_14,   nColorBlack);\r
197         ReadIcon(UNKNOWN_14, nColorUnknown);\r
198
199         ReadIcon(CLEAR_14,   nClear);\r
200         ReadIcon(PONDER_14,  nPondering);\r
201         ReadIcon(THINK_14,   nThinking);\r
202         ReadIcon(ANALYZE_14, nAnalyzing);\r
203 //        icons[nClear]       = wIconPixmap;\r
204 //        icons[nPondering]   = bIconPixmap;\r//        icons[nThinking]    = wIconPixmap;\r
205 //        icons[nAnalyzing]   = bIconPixmap;\r}
206
207 #if 0
208 // Windows routines commented out
209 \r
210 // front end\r
211 static HICON LoadIconEx( int id )\r
212 {\r
213     return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );\r
214 }\r
215 \r
216 // [HGM] the platform-dependent way of indicating where output should go is now all\r
217 // concentrated here, where a table of platform-dependent handles are initialized.\r
218 // This cleanses most other routines of front-end stuff, so they can go into the back end.\r
219 static void InitializeEngineOutput()\r
220 {\r
221  //   if( needInit ) { // needInit was already tested before call\r
222         // [HGM] made this into a table, rather than separate global variables\r
223         icons[nColorBlack]   = LoadIconEx( IDI_BLACK_14 );\r
224         icons[nColorWhite]   = LoadIconEx( IDI_WHITE_14 );\r
225         icons[nColorUnknown] = LoadIconEx( IDI_UNKNOWN_14 );\r
226         icons[nClear]        = LoadIconEx( IDI_TRANS_14 );\r
227         icons[nPondering]    = LoadIconEx( IDI_PONDER_14 );\r
228         icons[nThinking]     = LoadIconEx( IDI_CLOCK_14 );\r
229         icons[nAnalyzing]    = LoadIconEx( IDI_ANALYZE2_14 );\r
230 \r
231         // [HGM] also make a table of handles to output controls\r
232         // Note that engineOutputDialog must be defined first!\r
233         outputField[0][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color1 );\r
234         outputField[0][nLabel]     = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );\r
235         outputField[0][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );\r
236         outputField[0][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData1 );\r
237         outputField[0][nLabelNPS]  = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );\r
238         outputField[0][nMemo]      = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );\r
239 \r
240         outputField[1][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color2 );\r
241         outputField[1][nLabel]     = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );\r
242         outputField[1][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );\r
243         outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 );\r
244         outputField[1][nLabelNPS]  = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );\r
245         outputField[1][nMemo]      = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );\r
246 //        needInit = FALSE;\r
247 //    }\r
248 }\r
249 \r
250 // front end\r
251 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )\r
252 {\r
253     HWND hControl = GetDlgItem( hDlg, id );\r
254 \r
255     SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );\r
256 }\r
257 \r
258 #define HIDDEN_X    20000\r
259 #define HIDDEN_Y    20000\r
260 \r
261 // front end\r
262 static void HideControl( HWND hDlg, int id )\r
263 {\r
264     HWND hControl = GetDlgItem( hDlg, id );\r
265     RECT rc;\r
266 \r
267     GetWindowRect( hControl, &rc );\r
268 \r
269     /* \r
270         Avoid hiding an already hidden control, because that causes many\r
271         unnecessary WM_ERASEBKGND messages!\r
272     */\r
273     if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {\r
274         SetControlPos( hDlg, id, 20000, 20000, 100, 100 );\r
275     }\r
276 }\r
277 \r
278 // front end, although we might make GetWindowRect front end instead\r
279 static int GetControlWidth( HWND hDlg, int id )\r
280 {\r
281     RECT rc;\r
282 \r
283     GetWindowRect( GetDlgItem( hDlg, id ), &rc );\r
284 \r
285     return rc.right - rc.left;\r
286 }\r
287 \r
288 // front end?\r
289 static int GetControlHeight( HWND hDlg, int id )\r
290 {\r
291     RECT rc;\r
292 \r
293     GetWindowRect( GetDlgItem( hDlg, id ), &rc );\r
294 \r
295     return rc.bottom - rc.top;\r
296 }\r
297 \r
298 static int GetHeaderHeight()\r
299 {\r
300     int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );\r
301 \r
302     if( result < ICON_SIZE ) result = ICON_SIZE;\r
303 \r
304     return result;\r
305 }\r
306 \r
307 // The size calculations should be backend? If setControlPos is a platform-dependent way of doing things,\r
308 // a platform-independent wrapper for it should be supplied.\r
309 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
310 {\r
311     int label_x = x + ICON_SIZE + H_MARGIN;\r
312     int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );\r
313     int label_y = y + ICON_SIZE - label_h;\r
314     int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );\r
315     int nps_x = clientWidth - H_MARGIN - nps_w;\r
316     int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );\r
317     int state_data_x = nps_x - H_MARGIN - state_data_w;\r
318     int state_icon_x = state_data_x - ICON_SIZE - 2;\r
319     int max_w = clientWidth - 2*H_MARGIN;\r
320     int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;\r
321 \r
322     SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );\r
323     SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );\r
324     SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );\r
325     SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );\r
326     SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );\r
327     SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );\r
328 }\r
329 \r
330 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine\r
331 static void ResizeWindowControls( HWND hDlg, int mode )\r
332 {\r
333     RECT rc;\r
334     int headerHeight = GetHeaderHeight();\r
335     int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );\r
336     int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;\r
337     int labelDeltaY = ICON_SIZE - labelHeight;\r
338     int clientWidth;\r
339     int clientHeight;\r
340     int maxControlWidth;\r
341     int npsWidth;\r
342 \r
343     /* Initialize variables */\r
344     GetClientRect( hDlg, &rc );\r
345 \r
346     clientWidth = rc.right - rc.left;\r
347     clientHeight = rc.bottom - rc.top;\r
348 \r
349     maxControlWidth = clientWidth - 2*H_MARGIN;\r
350 \r
351     npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );\r
352 \r
353     /* Resize controls */\r
354     if( mode == 0 ) {\r
355         /* One engine */\r
356         PositionControlSet( hDlg, H_MARGIN, V_MARGIN, \r
357             clientWidth, \r
358             clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,\r
359             IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );\r
360 \r
361         /* Hide controls for the second engine */\r
362         HideControl( hDlg, IDC_Color2 );\r
363         HideControl( hDlg, IDC_EngineLabel2 );\r
364         HideControl( hDlg, IDC_StateIcon2 );\r
365         HideControl( hDlg, IDC_StateData2 );\r
366         HideControl( hDlg, IDC_Engine2_NPS );\r
367         HideControl( hDlg, IDC_EngineMemo2 );\r
368         SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );\r
369         /* TODO: we should also hide/disable them!!! what about tab stops?!?! */\r
370     }\r
371     else {\r
372         /* Two engines */\r
373         int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;\r
374         int header1_y = V_MARGIN;\r
375         int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;\r
376 \r
377         PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,\r
378             IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );\r
379 \r
380         PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,\r
381             IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );\r
382     }\r
383 \r
384     InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );\r
385     InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );\r
386 }\r
387 \r
388 // front end. Actual printing of PV lines into the output field\r
389 static void InsertIntoMemo( int which, char * text )\r
390 {\r
391     SendMessage( outputField[which][nMemo], EM_SETSEL, 0, 0 );\r
392 \r
393     SendMessage( outputField[which][nMemo], EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );\r
394 }\r
395 \r
396 // front end. Associates an icon with an output field ("control" in Windows jargon).\r
397 // [HGM] let it find out the output field from the 'which' number by itself\r
398 static void SetIcon( int which, int field, int nIcon )\r
399 {\r
400 \r
401     if( nIcon != 0 ) {\r
402         SendMessage( outputField[which][field], STM_SETICON, (WPARAM) icons[nIcon], 0 );\r
403     }\r
404 }\r
405 \r
406 // front end wrapper for SetWindowText, taking control number in stead of handle\r
407 void DoSetWindowText(int which, int field, char *s_label)\r
408 {\r
409     SetWindowText( outputField[which][field], s_label );\r
410 }\r
411 #endif
412
413 void DoSetWindowText(int which, int field, char *s_label)\r
414\r
415         Arg arg;\r
416 \r
417         XtSetArg(arg, XtNlabel, (XtArgVal) s_label);\r
418         XtSetValues(outputField[which][field], &arg, 1);\r
419 }\r
420
421 static void InsertIntoMemo( int which, char * text )\r
422 {
423         Arg arg; XawTextBlock t; Widget edit;
424
425         t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;\r
426         edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");\r
427         XawTextReplace(edit, 0, 0, &t);
428 //      XtSetArg(arg, XtNstring, (XtArgVal) text);\r
429 //      XtSetValues(outputField[which][nMemo], &arg, 1);\r
430 }\r
431
432 static void SetIcon( int which, int field, int nIcon )
433 {
434     Arg arg;
435 \r
436     if( nIcon != 0 ) {\r
437         XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);\r
438         XtSetValues(outputField[which][field], &arg, 1);\r
439     }\r
440 }
441
442 void DoClearMemo(int which)\r\r    Arg args[16];\r
443     int j;\r
444     Widget edit;\r
445
446         edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");\r
447         XtCallActionProc(edit, "select-all", NULL, NULL, 0);\r
448         XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);\r
449 }
450 \r
451 // The following routines are mutated clones of the commentPopUp routines\r
452 \r
453 void PositionControlSet(which, form, bw_width)\r
454      int which;\r
455      Widget form;\r
456      Dimension bw_width;\r{\r
457     Arg args[16];\r
458     Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;\r
459     int j, mutable=1;\r
460     j = 0;\r
461     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
462     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;\r
463     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
464     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
465     XtSetArg(args[j], XtNleft,      XtChainLeft); j++;\r    XtSetArg(args[j], XtNright,     XtChainLeft); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
466     XtSetArg(args[j], XtNwidth,     (XtArgVal) 17); j++;\r
467     outputField[which][nColorIcon] = ColorWidget =
468       XtCreateManagedWidget("Color", labelWidgetClass,\r
469                      form, args, j);\r
470
471     j = 0;\r
472     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
473     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyLeft); j++;
474     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;\r
475     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
476     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
477     XtSetArg(args[j], XtNleft,      XtChainLeft); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
478     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width/2 - 57); j++;\r
479     outputField[which][nLabel] = NameWidget =
480       XtCreateManagedWidget("Engine", labelWidgetClass,\r
481                      form, args, j);\r
482
483     j = 0;\r
484     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
485     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;\r
486     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;\r
487     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
488     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
489     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
490     XtSetArg(args[j], XtNwidth,     (XtArgVal) 20); j++;\r
491     outputField[which][nStateIcon] = ModeWidget =
492       XtCreateManagedWidget("Mode", labelWidgetClass,\r
493                      form, args, j);\r
494
495     j = 0;\r
496     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
497     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyLeft); j++;
498     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;\r
499     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;\r
500     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
501     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
502     XtSetArg(args[j], XtNright,     XtChainRight); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
503     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width/2 - 102); j++;\r
504     outputField[which][nStateData] = MoveWidget =
505       XtCreateManagedWidget("Move", labelWidgetClass,\r
506                      form, args, j);\r
507
508     j = 0;\r
509     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
510     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyRight); j++;\r
511     XtSetArg(args[j], XtNlabel,     (XtArgVal) "NPS"); j++;\r
512     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;\r
513     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
514     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
515     XtSetArg(args[j], XtNleft,      XtChainRight); j++;\r    XtSetArg(args[j], XtNright,     XtChainRight); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
516     XtSetArg(args[j], XtNwidth,     (XtArgVal) 100); j++;\r
517     outputField[which][nLabelNPS] = NodesWidget =
518       XtCreateManagedWidget("Nodes", labelWidgetClass,\r
519                      form, args, j);\r
520
521     // create "text" within "form"
522     j = 0;\r
523     if (mutable) {\r
524         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;\r
525         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;\r
526     }\r
527     XtSetArg(args[j], XtNstring, "");  j++;\r
528     XtSetArg(args[j], XtNdisplayCaret, False);  j++;\r
529     XtSetArg(args[j], XtNtop, XtChainTop);  j++;\r
530     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;\r
531     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;\r
532     XtSetArg(args[j], XtNright, XtChainRight);  j++;\r
533     XtSetArg(args[j], XtNresizable, True);  j++;\r
534     XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/\r
535 #if 0\r
536     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;\r
537 #else\r
538     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */\r
539     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;\r
540     XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded);  j++;\r#endif\r
541 //    XtSetArg(args[j], XtNautoFill, True);  j++;\r
542 //    XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;\r
543     outputField[which][nMemo] = edit =\r
544       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);\r
545 \r
546     j = 0;\r
547     XtSetArg(args[j], XtNfromVert, ColorWidget); j++;\r
548 //    XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;\r
549     XtSetValues(edit, args, j);\r
550 }\r
551 \r
552 Widget EngineOutputCreate(name, text)\r
553      char *name, *text;\r
554 {\r
555     Arg args[16];\r
556     Widget shell, layout, form, form2, edit;
557     Dimension bw_width, bw_height;\r
558     int j;\r
559 \r
560     // get board width
561     j = 0;\r
562     XtSetArg(args[j], XtNwidth,  &bw_width);  j++;\r    XtSetArg(args[j], XtNheight, &bw_height);  j++;\r    XtGetValues(boardWidget, args, j);\r
563 \r
564     // define form within layout within shell.
565     j = 0;\r
566     XtSetArg(args[j], XtNresizable, True);  j++;\r
567     shell =\r
568       XtCreatePopupShell(name, transientShellWidgetClass,\r
569                          shellWidget, args, j);\r
570     layout =\r
571       XtCreateManagedWidget(layoutName, formWidgetClass, shell,\r
572                             layoutArgs, XtNumber(layoutArgs));\r
573     // divide window vertically into two equal parts, by creating two forms
574     form =\r
575       XtCreateManagedWidget("form", formWidgetClass, layout,\r
576                             formArgs, XtNumber(formArgs));\r
577     form2 =\r
578       XtCreateManagedWidget("form2", formWidgetClass, layout,\r
579                             formArgs, XtNumber(formArgs));\r
580     j = 0;\r    XtSetArg(args[j], XtNfromVert,  (XtArgVal) form); j++;\r    XtSetValues(form2, args, j);\r
581     // make sure width is known in advance, for better placement of child widgets
582     j = 0;\r    XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width-16); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) bw_height/2); j++;\r    XtSetValues(shell, args, j);\r
583
584     // fill up both forms with control elements
585     PositionControlSet(0, form,  bw_width);
586     PositionControlSet(1, form2, bw_width);
587 \r
588     XtRealizeWidget(shell);\r
589
590     if (engineOutputX == -1) {\r
591         int xx, yy;\r
592         Window junk;\r
593         Dimension pw_height;\r
594         Dimension ew_height;\r
595 #if 0\r
596         j = 0;\r
597         XtSetArg(args[j], XtNheight, &ew_height);  j++;\r
598         XtGetValues(edit, args, j);\r
599 \r
600         j = 0;\r
601         XtSetArg(args[j], XtNheight, &pw_height);  j++;\r
602         XtGetValues(shell, args, j);\r
603         engineOutputH = pw_height + (lines - 1) * ew_height;\r
604         engineOutputW = bw_width - 16;
605 #else
606         engineOutputH = bw_height/2;\r   engineOutputW = bw_width-16;\r#endif
607 \r
608         XSync(xDisplay, False);\r
609 #ifdef NOTDEF\r
610         /* This code seems to tickle an X bug if it is executed too soon\r
611            after xboard starts up.  The coordinates get transformed as if\r
612            the main window was positioned at (0, 0).\r
613            */\r
614         XtTranslateCoords(shellWidget,\r
615                           (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,\r
616                           &engineOutputX, &engineOutputY);\r
617 #else  /*!NOTDEF*/\r
618         XTranslateCoordinates(xDisplay, XtWindow(shellWidget),\r
619                               RootWindowOfScreen(XtScreen(shellWidget)),\r
620                               (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,\r
621                               &xx, &yy, &junk);\r
622         engineOutputX = xx;\r
623         engineOutputY = yy;\r
624 #endif /*!NOTDEF*/\r
625         if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/\r
626     }\r
627     j = 0;\r
628     XtSetArg(args[j], XtNheight, engineOutputH);  j++;\r    XtSetArg(args[j], XtNwidth, engineOutputW);  j++;\r
629     XtSetArg(args[j], XtNx, engineOutputX);  j++;\r
630     XtSetArg(args[j], XtNy, engineOutputY);  j++;\r
631     XtSetValues(shell, args, j);\r
632 //    XtSetKeyboardFocus(shell, edit);\r
633 \r
634     return shell;\r
635 }\r
636 \r
637 void ResizeWindowControls(shell, mode)
638         Widget shell;
639         int mode;
640 {
641     Widget form1, form2;
642     Arg args[16];
643     int j;
644     Dimension ew_height, tmp;
645
646     form1 = XtNameToWidget(shell, "*form");\r
647     form2 = XtNameToWidget(shell, "*form2");
648
649     j = 0;
650     XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;\r    XtGetValues(form1, args, j);
651     j = 0;
652     XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;\r    XtGetValues(form2, args, j);
653     ew_height += tmp; // total height
654 \r
655     if(mode==0) {\r
656         j = 0;
657         XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;\r
658         XtSetValues(form2, args, j);
659         j = 0;
660         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;\r
661         XtSetValues(form1, args, j);
662     } else {
663         j = 0;
664         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;\r
665         XtSetValues(form1, args, j);
666         j = 0;
667         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;\r
668         XtSetValues(form2, args, j);
669     }\r
670 }
671
672 #if 0\r
673 void EngineOutputCallback(w, client_data, call_data)\r
674      Widget w;\r
675      XtPointer client_data, call_data;\r
676 {\r
677     String name;\r
678     Arg args[16];\r
679     int j;\r
680 \r
681     j = 0;\r
682     XtSetArg(args[j], XtNlabel, &name);  j++;\r
683     XtGetValues(w, args, j);\r
684 \r
685     if (strcmp(name, "close") == 0) {\r
686         EngineOutputPopDown();\r
687     } else if (strcmp(name, "edit") == 0) {\r
688         EngineOutputPopDown();\r
689         EditCommentEvent();\r
690     }\r
691 }\r
692 #endif
693 \r
694 #if 0\r
695 // This seems pure front end\r
696 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
697 {\r
698     static SnapData sd;\r
699 \r
700     switch (message) {\r
701     case WM_INITDIALOG:\r
702         if( engineOutputDialog == NULL ) {\r
703             engineOutputDialog = hDlg;\r
704 \r
705             RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */\r
706 \r
707             ResizeWindowControls( hDlg, windowMode );\r
708 \r
709             SetEngineState( 0, STATE_IDLE, "" );\r
710             SetEngineState( 1, STATE_IDLE, "" );\r
711         }\r
712 \r
713         return FALSE;\r
714 \r
715     case WM_COMMAND:\r
716         switch (LOWORD(wParam)) {\r
717         case IDOK:\r
718           EndDialog(hDlg, TRUE);\r
719           return TRUE;\r
720 \r
721         case IDCANCEL:\r
722           EndDialog(hDlg, FALSE);\r
723           return TRUE;\r
724 \r
725         default:\r
726           break;\r
727         }\r
728 \r
729         break;\r
730 \r
731     case WM_GETMINMAXINFO:\r
732         {\r
733             MINMAXINFO * mmi = (MINMAXINFO *) lParam;\r
734         \r
735             mmi->ptMinTrackSize.x = 100;\r
736             mmi->ptMinTrackSize.y = 160;\r
737         }\r
738         break;\r
739 \r
740     case WM_CLOSE:\r
741         EngineOutputPopDown();\r
742         break;\r
743 \r
744     case WM_SIZE:\r
745         ResizeWindowControls( hDlg, windowMode );\r
746         break;\r
747 \r
748     case WM_ENTERSIZEMOVE:\r
749         return OnEnterSizeMove( &sd, hDlg, wParam, lParam );\r
750 \r
751     case WM_SIZING:\r
752         return OnSizing( &sd, hDlg, wParam, lParam );\r
753 \r
754     case WM_MOVING:\r
755         return OnMoving( &sd, hDlg, wParam, lParam );\r
756 \r
757     case WM_EXITSIZEMOVE:\r
758         return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
759     }\r
760 \r
761     return FALSE;\r
762 }\r
763 #endif
764 \r
765 void EngineOutputPopUp(title, text)\r
766      char *title, *text;\r
767 {\r
768     Arg args[16];\r
769     int j;\r
770     Widget edit;\r
771 \r
772     if (engineOutputShell == NULL) {\r
773         engineOutputShell =\r
774           EngineOutputCreate(title, text);\r
775         XtRealizeWidget(engineOutputShell);\r
776         CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");\r
777         if( needInit ) {\r
778             InitializeEngineOutput();\r
779             needInit = FALSE;\r  }\r
780         SetEngineColorIcon( 0 );\r
781         SetEngineColorIcon( 1 );\r
782         SetEngineState( 0, STATE_IDLE, "" );\r
783         SetEngineState( 1, STATE_IDLE, "" );\r
784     } else {
785         edit = XtNameToWidget(engineOutputShell, "*form.text");\r
786         j = 0;\r
787         XtSetArg(args[j], XtNstring, text); j++;\r
788         XtSetValues(edit, args, j);\r
789         j = 0;\r
790         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;\r
791         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;\r
792         XtSetValues(engineOutputShell, args, j);\r
793     }\r
794 \r
795     XtPopup(engineOutputShell, XtGrabNone);\r
796     XSync(xDisplay, False);\r
797 \r
798     j=0;
799     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
800     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
801                 args, j);
802
803     engineOutputDialogUp = True;\r
804     ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
805 }\r
806
807 #if 0\r
808 // front end\r
809 void EngineOutputPopUp()\r
810 {\r
811   FARPROC lpProc;\r
812   \r
813   CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);\r
814 \r
815   if( engineOutputDialog ) {\r
816     SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );\r
817 \r
818     if( ! engineOutputDialogUp ) {\r
819         ShowWindow(engineOutputDialog, SW_SHOW);\r
820     }\r
821   }\r
822   else {\r
823     lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );\r
824 \r
825     /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */\r
826     CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );\r
827 \r
828     FreeProcInstance(lpProc);\r
829   }\r
830 \r
831   // [HGM] displaced to after creation of dialog, to allow initialization of output fields\r
832   if( needInit ) {\r
833       InitializeEngineOutput();\r
834       needInit = FALSE;\r
835   }\r
836 \r
837   engineOutputDialogUp = TRUE;\r
838 }\r
839 #endif
840 \r
841 void EngineOutputPopDown()\r
842 {\r
843     Arg args[16];\r
844     int j;\r
845 \r
846     if (!engineOutputDialogUp) return;\r
847     j = 0;\r
848     XtSetArg(args[j], XtNx, &engineOutputX); j++;\r
849     XtSetArg(args[j], XtNy, &engineOutputY); j++;\r
850     XtSetArg(args[j], XtNwidth, &engineOutputW); j++;\r
851     XtSetArg(args[j], XtNheight, &engineOutputH); j++;\r
852     XtGetValues(engineOutputShell, args, j);\r
853     XtPopdown(engineOutputShell);\r
854     XSync(xDisplay, False);
855     j=0;
856     XtSetArg(args[j], XtNleftBitmap, None); j++;
857     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
858                 args, j);
859 \r
860     engineOutputDialogUp = False;\r
861     ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
862 }\r
863 \r
864 #if 0
865 // front end\r
866 void EngineOutputPopDown()\r
867 {\r
868   CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);\r
869 \r
870   if( engineOutputDialog ) {\r
871       ShowWindow(engineOutputDialog, SW_HIDE);\r
872   }\r
873 \r
874   engineOutputDialogUp = FALSE;\r
875 }\r
876 \r
877 // front end. [HGM] Takes handle of output control from table, so only number is passed\r
878 void DoClearMemo(int which)\r
879 {\r
880         SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" );\r
881 }\r
882 #endif
883
884 //------------------------ pure back-end routines -------------------------------\r
885 \r
886 \r
887 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments\r
888 static SetEngineState( int which, int state, char * state_data )\r
889 {\r
890     int x_which = 1 - which;\r
891 \r
892     if( engineState[ which ] != state ) {\r
893         engineState[ which ] = state;\r
894 \r
895         switch( state ) {\r
896         case STATE_THINKING:\r
897             SetIcon( which, nStateIcon, nThinking );\r
898             if( engineState[ x_which ] == STATE_THINKING ) {\r
899                 SetEngineState( x_which, STATE_IDLE, "" );\r
900             }\r
901             break;\r
902         case STATE_PONDERING:\r
903             SetIcon( which, nStateIcon, nPondering );\r
904             break;\r
905         case STATE_ANALYZING:\r
906             SetIcon( which, nStateIcon, nAnalyzing );\r
907             break;\r
908         default:\r
909             SetIcon( which, nStateIcon, nClear );\r
910             break;\r
911         }\r
912     }\r
913 \r
914     if( state_data != 0 ) {\r
915         DoSetWindowText( which, nStateData, state_data );\r
916     }\r
917 }\r
918 \r
919 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.\r
920 void EngineOutputUpdate( FrontEndProgramStats * stats )\r
921 {\r
922     EngineOutputData ed;\r
923     int clearMemo = FALSE;\r
924     int which;\r
925     int depth;\r
926 \r
927     if( stats == 0 ) {\r
928         SetEngineState( 0, STATE_IDLE, "" );\r
929         SetEngineState( 1, STATE_IDLE, "" );\r
930         return;\r
931     }\r
932 \r
933     which = stats->which;\r
934     depth = stats->depth;\r
935 \r
936     if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {\r
937         return;\r
938     }\r
939 \r
940     if( engineOutputShell == NULL ) {\r
941         return;\r
942     }\r
943 \r
944     VerifyDisplayMode();\r
945 \r
946     ed.which = which;\r
947     ed.depth = depth;\r
948     ed.nodes = stats->nodes;\r
949     ed.score = stats->score;\r
950     ed.time = stats->time;\r
951     ed.pv = stats->pv;\r
952     ed.hint = stats->hint;\r
953     ed.an_move_index = stats->an_move_index;\r
954     ed.an_move_count = stats->an_move_count;\r
955 \r
956     /* Get target control. [HGM] this is moved to front end, which get them from a table */\r
957     if( which == 0 ) {\r
958         ed.name = first.tidy;\r
959     }\r
960     else {\r
961         ed.name = second.tidy;\r
962     }\r
963 \r
964     /* Clear memo if needed */\r
965     if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {\r
966         clearMemo = TRUE;\r
967     }\r
968 \r
969     if( lastForwardMostMove[which] != forwardMostMove ) {\r
970         clearMemo = TRUE;\r
971     }\r
972 \r
973     if( clearMemo ) DoClearMemo(which);\r
974 \r
975     /* Update */\r
976     lastDepth[which] = depth;\r
977     lastForwardMostMove[which] = forwardMostMove;\r
978 \r
979     if( ed.pv != 0 && ed.pv[0] == ' ' ) {\r
980         if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */\r
981             ed.pv = "";\r
982         }\r
983     }\r
984 \r
985     UpdateControls( &ed );\r
986 }\r
987 \r
988 #define ENGINE_COLOR_WHITE      'w'\r
989 #define ENGINE_COLOR_BLACK      'b'\r
990 #define ENGINE_COLOR_UNKNOWN    ' '\r
991 \r
992 // pure back end\r
993 char GetEngineColor( int which )\r
994 {\r
995     char result = ENGINE_COLOR_UNKNOWN;\r
996 \r
997     if( which == 0 || which == 1 ) {\r
998         ChessProgramState * cps;\r
999 \r
1000         switch (gameMode) {\r
1001         case MachinePlaysBlack:\r
1002         case IcsPlayingBlack:\r
1003             result = ENGINE_COLOR_BLACK;\r
1004             break;\r
1005         case MachinePlaysWhite:\r
1006         case IcsPlayingWhite:\r
1007             result = ENGINE_COLOR_WHITE;\r
1008             break;\r
1009         case AnalyzeMode:\r
1010         case AnalyzeFile:\r
1011             result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
1012             break;\r
1013         case TwoMachinesPlay:\r
1014             cps = (which == 0) ? &first : &second;\r
1015             result = cps->twoMachinesColor[0];\r
1016             result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
1017             break;\r
1018         }\r
1019     }\r
1020 \r
1021     return result;\r
1022 }\r
1023 \r
1024 // pure back end\r
1025 char GetActiveEngineColor()\r
1026 {\r
1027     char result = ENGINE_COLOR_UNKNOWN;\r
1028 \r
1029     if( gameMode == TwoMachinesPlay ) {\r
1030         result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
1031     }\r
1032 \r
1033     return result;\r
1034 }\r
1035 \r
1036 // pure back end\r
1037 static int IsEnginePondering( int which )\r
1038 {\r
1039     int result = FALSE;\r
1040 \r
1041     switch (gameMode) {\r
1042     case MachinePlaysBlack:\r
1043     case IcsPlayingBlack:\r
1044         if( WhiteOnMove(forwardMostMove) ) result = TRUE;\r
1045         break;\r
1046     case MachinePlaysWhite:\r
1047     case IcsPlayingWhite:\r
1048         if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;\r
1049         break;\r
1050     case TwoMachinesPlay:\r
1051         if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {\r
1052             if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;\r
1053         }\r
1054         break;\r
1055     }\r
1056 \r
1057     return result;\r
1058 }\r
1059 \r
1060 // back end\r
1061 static void SetDisplayMode( int mode )\r
1062 {\r
1063     if( windowMode != mode ) {\r
1064         windowMode = mode;\r
1065 \r
1066         ResizeWindowControls( engineOutputShell, mode );\r
1067     }\r
1068 }\r
1069 \r
1070 // pure back end\r
1071 static VerifyDisplayMode()\r
1072 {\r
1073     int mode;\r
1074 \r
1075     /* Get proper mode for current game */\r
1076     switch( gameMode ) {\r
1077     case AnalyzeMode:\r
1078     case AnalyzeFile:\r
1079     case MachinePlaysWhite:\r
1080     case MachinePlaysBlack:\r
1081     case IcsPlayingWhite:\r
1082     case IcsPlayingBlack:\r
1083         mode = 0;\r
1084         break;\r
1085     case TwoMachinesPlay:\r
1086         mode = 1;\r
1087         break;\r
1088     default:\r
1089         /* Do not change */\r
1090         return;\r
1091     }\r
1092 \r
1093     SetDisplayMode( mode );\r
1094 }\r
1095 \r
1096 // back end. Determine what icon to se in the color-icon field, and print it\r
1097 static void SetEngineColorIcon( int which )\r
1098 {\r
1099     char color = GetEngineColor(which);\r
1100     int nicon = 0;\r
1101 \r
1102     if( color == ENGINE_COLOR_BLACK )\r
1103         nicon = nColorBlack;\r
1104     else if( color == ENGINE_COLOR_WHITE )\r
1105         nicon = nColorWhite;\r
1106     else\r
1107         nicon = nColorUnknown;\r
1108 \r
1109     SetIcon( which, nColorIcon, nicon );\r
1110 }\r
1111 \r
1112 #define MAX_NAME_LENGTH 32\r
1113 \r
1114 // pure back end, now SetWindowText is called via wrapper DoSetWindowText\r
1115 static void UpdateControls( EngineOutputData * ed )\r
1116 {\r
1117     int isPondering = FALSE;\r
1118 \r
1119     char s_label[MAX_NAME_LENGTH + 32];\r
1120     \r
1121     char * name = ed->name;\r
1122 \r
1123     /* Label */\r
1124     if( name == 0 || *name == '\0' ) {\r
1125         name = "?";\r
1126     }\r
1127 \r
1128     strncpy( s_label, name, MAX_NAME_LENGTH );\r
1129     s_label[ MAX_NAME_LENGTH-1 ] = '\0';\r
1130 \r
1131 #ifdef SHOW_PONDERING\r
1132     if( IsEnginePondering( ed->which ) ) {\r
1133         char buf[8];\r
1134 \r
1135         buf[0] = '\0';\r
1136 \r
1137         if( ed->hint != 0 && *ed->hint != '\0' ) {\r
1138             strncpy( buf, ed->hint, sizeof(buf) );\r
1139             buf[sizeof(buf)-1] = '\0';\r
1140         }\r
1141         else if( ed->pv != 0 && *ed->pv != '\0' ) {\r
1142             char * sep = strchr( ed->pv, ' ' );\r
1143             int buflen = sizeof(buf);\r
1144 \r
1145             if( sep != NULL ) {\r
1146                 buflen = sep - ed->pv + 1;\r
1147                 if( buflen > sizeof(buf) ) buflen = sizeof(buf);\r
1148             }\r
1149 \r
1150             strncpy( buf, ed->pv, buflen );\r
1151             buf[ buflen-1 ] = '\0';\r
1152         }\r
1153 \r
1154         SetEngineState( ed->which, STATE_PONDERING, buf );\r
1155     }\r
1156     else if( gameMode == TwoMachinesPlay ) {\r
1157         SetEngineState( ed->which, STATE_THINKING, "" );\r
1158     }\r
1159     else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile ) {\r
1160         char buf[64];\r
1161         int time_secs = ed->time / 100;\r
1162         int time_mins = time_secs / 60;\r
1163 \r
1164         buf[0] = '\0';\r
1165 \r
1166         if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {\r
1167             char mov[16];\r
1168 \r
1169             strncpy( mov, ed->hint, sizeof(mov) );\r
1170             mov[ sizeof(mov)-1 ] = '\0';\r
1171 \r
1172             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
1173         }\r
1174 \r
1175         SetEngineState( ed->which, STATE_ANALYZING, buf );\r
1176     }\r
1177     else {\r
1178         SetEngineState( ed->which, STATE_IDLE, "" );\r
1179     }\r
1180 #endif\r
1181 \r
1182     DoSetWindowText( ed->which, nLabel, s_label );\r
1183 \r
1184     s_label[0] = '\0';\r
1185 \r
1186     if( ed->time > 0 && ed->nodes > 0 ) {\r
1187         unsigned long nps_100 = ed->nodes / ed->time;\r
1188 \r
1189         if( nps_100 < 100000 ) {\r
1190             sprintf( s_label, "NPS: %lu", nps_100 * 100 );\r
1191         }\r
1192         else {\r
1193             sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );\r
1194         }\r
1195     }\r
1196 \r
1197     DoSetWindowText( ed->which, nLabelNPS, s_label );\r
1198 \r
1199     /* Memo */\r
1200     if( ed->pv != 0 && *ed->pv != '\0' ) {\r
1201         char s_nodes[24];\r
1202         char s_score[16];\r
1203         char s_time[24];\r
1204         char buf[256];\r
1205         int buflen;\r
1206         int time_secs = ed->time / 100;\r
1207         int time_cent = ed->time % 100;\r
1208 \r
1209         /* Nodes */\r
1210         if( ed->nodes < 1000000 ) {\r
1211             sprintf( s_nodes, "%lu", ed->nodes );\r
1212         }\r
1213         else {\r
1214             sprintf( s_nodes, "%.1fM", ed->nodes / 1000000.0 );\r
1215         }\r
1216 \r
1217         /* Score */\r
1218         if( ed->score > 0 ) {\r
1219             sprintf( s_score, "+%.2f", ed->score / 100.0 );\r
1220         } else\r
1221             sprintf( s_score, "%.2f", ed->score / 100.0 );\r
1222 \r
1223         /* Time */\r
1224         sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );\r
1225 \r
1226         /* Put all together... */\r
1227         sprintf( buf, "%3d  %s  %s\t%s\t", ed->depth, s_score, s_nodes, s_time );\r
1228 \r
1229         /* Add PV */\r
1230         buflen = strlen(buf);\r
1231 \r
1232         strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );\r
1233 \r
1234         buf[ sizeof(buf) - 3 ] = '\0';\r
1235 \r
1236         strcat( buf + buflen, "\n" );\r
1237 \r
1238         /* Update memo */\r
1239         InsertIntoMemo( ed->which, buf );\r
1240     }\r
1241 \r
1242     /* Colors */\r
1243     SetEngineColorIcon( ed->which );\r
1244 }\r
1245 \r
1246 // back end\r
1247 int EngineOutputIsUp()\r
1248 {\r
1249     return engineOutputDialogUp;\r
1250 }\r
1251
1252 void
1253 EngineOutputProc(w, event, prms, nprms)
1254      Widget w;
1255      XEvent *event;
1256      String *prms;
1257      Cardinal *nprms;
1258 {
1259   if (engineOutputDialogUp) {
1260     EngineOutputPopDown();
1261   } else {
1262     EngineOutputPopUp("engine output","This feature is experimental");
1263   }
1264 //  ToNrEvent(currentMove);
1265 }
1266 \r