4 * Author: Alessandro Scotti (Dec 2005)
\r
6 * ------------------------------------------------------------------------
\r
8 * GNU XBoard is free software: you can redistribute it and/or modify
\r
9 * it under the terms of the GNU General Public License as published by
\r
10 * the Free Software Foundation, either version 3 of the License, or (at
\r
11 * your option) any later version.
\r
13 * GNU XBoard is distributed in the hope that it will be useful, but
\r
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
16 * General Public License for more details.
\r
18 * You should have received a copy of the GNU General Public License
\r
19 * along with this program. If not, see http://www.gnu.org/licenses/.
\r
21 * ------------------------------------------------------------------------
\r
22 ** See the file ChangeLog for a revision history. */
\r
29 #include <sys/types.h>
\r
32 # include <stdlib.h>
\r
33 # include <string.h>
\r
34 #else /* not STDC_HEADERS */
\r
35 extern char *getenv();
\r
37 # include <string.h>
\r
38 # else /* not HAVE_STRING_H */
\r
39 # include <strings.h>
\r
40 # endif /* not HAVE_STRING_H */
\r
41 #endif /* not STDC_HEADERS */
\r
44 # include <unistd.h>
\r
47 #include <X11/Intrinsic.h>
\r
48 #include <X11/StringDefs.h>
\r
49 #include <X11/Shell.h>
\r
50 #include <X11/Xaw/Dialog.h>
\r
51 #include <X11/Xaw/Form.h>
\r
52 #include <X11/Xaw/List.h>
\r
53 #include <X11/Xaw/Label.h>
\r
54 #include <X11/Xaw/SimpleMenu.h>
\r
55 #include <X11/Xaw/SmeBSB.h>
\r
56 #include <X11/Xaw/SmeLine.h>
\r
57 #include <X11/Xaw/Box.h>
\r
58 #include <X11/Xaw/Paned.h>
\r
59 #include <X11/Xaw/MenuButton.h>
\r
60 #include <X11/cursorfont.h>
\r
61 #include <X11/Xaw/Text.h>
\r
62 #include <X11/Xaw/AsciiText.h>
\r
63 #include <X11/Xaw/Viewport.h>
\r
66 #include "frontend.h"
\r
67 #include "backend.h"
\r
69 // Add xengineo.h later
\r
70 #include "gettext.h"
\r
73 # define _(s) gettext (s)
\r
74 # define N_(s) gettext_noop (s)
\r
80 #include <X11/xpm.h>
\r
82 // [HGM] pixmaps of some ICONS used in the engine-outut window
\r
83 #include "pixmaps/WHITE_14.xpm"
\r
84 #include "pixmaps/BLACK_14.xpm"
\r
85 #include "pixmaps/CLEAR_14.xpm"
\r
86 #include "pixmaps/UNKNOWN_14.xpm"
\r
87 #include "pixmaps/THINKING_14.xpm"
\r
88 #include "pixmaps/PONDER_14.xpm"
\r
89 #include "pixmaps/ANALYZING_14.xpm"
\r
97 // imports from xboard.c
\r
98 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
\r
99 extern Display *xDisplay;
\r
100 extern Window xBoardWindow;
\r
101 extern int squareSize;
\r
102 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
\r
103 extern char *layoutName;
\r
105 // temporary kludge to avoid compile errors untill all Windows code has been replaced
\r
106 #define HICON int *
\r
109 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
\r
110 #define nColorBlack 1
\r
111 #define nColorWhite 2
\r
112 #define nColorUnknown 3
\r
114 #define nPondering 5
\r
115 #define nThinking 6
\r
116 #define nAnalyzing 7
\r
118 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
\r
120 // [HGM] same for output fields (note that there are two of each type, one per color)
\r
121 #define nColorIcon 1
\r
122 #define nStateIcon 2
\r
124 #define nStateData 4
\r
125 #define nLabelNPS 5
\r
128 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
\r
130 void EngineOutputPopDown();
\r
131 void engineOutputPopUp(char *title, char *text);
\r
132 int EngineOutputIsUp();
\r
133 static void SetEngineColorIcon( int which );
\r
135 #define SHOW_PONDERING
\r
137 /* Imports from backend.c */
\r
138 char * SavePart(char *str);
\r
139 extern int opponentKibitzes;
\r
141 /* Imports from winboard.c */
\r
142 //extern HWND engineOutputDialog;
\r
143 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
\r
145 //extern WindowPlacement wpEngineOutput;
\r
147 Position engineOutputX = -1, engineOutputY = -1;
\r
148 Dimension engineOutputW, engineOutputH;
\r
149 Widget engineOutputShell;
\r
150 int engineOutputDialogUp;
\r
152 /* Module variables */
\r
155 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
\r
156 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
\r
158 #define ICON_SIZE 14
\r
160 #define STATE_UNKNOWN -1
\r
161 #define STATE_THINKING 0
\r
162 #define STATE_IDLE 1
\r
163 #define STATE_PONDERING 2
\r
164 #define STATE_ANALYZING 3
\r
166 static int windowMode = 1;
\r
168 static int needInit = TRUE;
\r
170 static int lastDepth[2] = { -1, -1 };
\r
171 static int lastForwardMostMove[2] = { -1, -1 };
\r
172 static int engineState[2] = { -1, -1 };
\r
185 } EngineOutputData;
\r
187 static int VerifyDisplayMode();
\r
188 static void UpdateControls( EngineOutputData * ed );
\r
189 static SetEngineState( int which, int state, char * state_data );
\r
191 void ReadIcon(char *pixData[], int iconNr)
\r
195 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
\r
198 NULL, NULL /*&attr*/)) != 0) {
\r
199 fprintf(stderr, _("Error %d loading icon image\n"), r);
\r
204 static void InitializeEngineOutput()
\r
207 ReadIcon(WHITE_14, nColorWhite);
\r
208 ReadIcon(BLACK_14, nColorBlack);
\r
209 ReadIcon(UNKNOWN_14, nColorUnknown);
\r
211 ReadIcon(CLEAR_14, nClear);
\r
212 ReadIcon(PONDER_14, nPondering);
\r
213 ReadIcon(THINK_14, nThinking);
\r
214 ReadIcon(ANALYZE_14, nAnalyzing);
\r
217 void DoSetWindowText(int which, int field, char *s_label)
\r
221 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
\r
222 XtSetValues(outputField[which][field], &arg, 1);
\r
225 static void InsertIntoMemo( int which, char * text )
\r
227 Arg arg; XawTextBlock t; Widget edit;
\r
229 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
\r
230 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
\r
231 XawTextReplace(edit, 0, 0, &t);
\r
232 // XtSetArg(arg, XtNstring, (XtArgVal) text);
\r
233 // XtSetValues(outputField[which][nMemo], &arg, 1);
\r
236 static void SetIcon( int which, int field, int nIcon )
\r
241 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
\r
242 XtSetValues(outputField[which][field], &arg, 1);
\r
246 void DoClearMemo(int which)
\r
252 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
\r
253 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
\r
254 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
\r
257 // The following routines are mutated clones of the commentPopUp routines
\r
259 void PositionControlSet(which, form, bw_width)
\r
262 Dimension bw_width;
\r
265 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
\r
268 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
269 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
270 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
271 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
272 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
273 XtSetArg(args[j], XtNright, XtChainLeft); j++;
\r
274 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
275 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
\r
276 outputField[which][nColorIcon] = ColorWidget =
\r
277 XtCreateManagedWidget("Color", labelWidgetClass,
\r
281 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
282 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
\r
283 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
\r
284 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
285 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
286 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
287 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
288 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
\r
289 outputField[which][nLabel] = NameWidget =
\r
290 XtCreateManagedWidget("Engine", labelWidgetClass,
\r
294 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
295 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
296 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
\r
297 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
298 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
299 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
300 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
\r
301 outputField[which][nStateIcon] = ModeWidget =
\r
302 XtCreateManagedWidget("Mode", labelWidgetClass,
\r
306 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
307 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
\r
308 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
309 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
\r
310 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
311 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
312 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
313 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
314 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
\r
315 outputField[which][nStateData] = MoveWidget =
\r
316 XtCreateManagedWidget("Move", labelWidgetClass,
\r
320 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
321 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
\r
322 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
\r
323 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
\r
324 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
325 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
326 XtSetArg(args[j], XtNleft, XtChainRight); j++;
\r
327 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
328 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
329 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
\r
330 outputField[which][nLabelNPS] = NodesWidget =
\r
331 XtCreateManagedWidget("Nodes", labelWidgetClass,
\r
334 // create "text" within "form"
\r
337 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
\r
338 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
\r
340 XtSetArg(args[j], XtNstring, ""); j++;
\r
341 XtSetArg(args[j], XtNdisplayCaret, False); j++;
\r
342 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
343 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
\r
344 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
345 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
346 XtSetArg(args[j], XtNresizable, True); j++;
\r
347 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
\r
349 XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded); j++;
\r
351 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
\r
352 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
\r
353 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
\r
355 // XtSetArg(args[j], XtNautoFill, True); j++;
\r
356 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
\r
357 outputField[which][nMemo] = edit =
\r
358 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
\r
361 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
\r
362 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
\r
363 XtSetValues(edit, args, j);
\r
366 Widget EngineOutputCreate(name, text)
\r
370 Widget shell, layout, form, form2, edit;
\r
371 Dimension bw_width, bw_height;
\r
376 XtSetArg(args[j], XtNwidth, &bw_width); j++;
\r
377 XtSetArg(args[j], XtNheight, &bw_height); j++;
\r
378 XtGetValues(boardWidget, args, j);
\r
380 // define form within layout within shell.
\r
382 XtSetArg(args[j], XtNresizable, True); j++;
\r
384 XtCreatePopupShell(name, transientShellWidgetClass,
\r
385 shellWidget, args, j);
\r
387 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
\r
388 layoutArgs, XtNumber(layoutArgs));
\r
389 // divide window vertically into two equal parts, by creating two forms
\r
391 XtCreateManagedWidget("form", formWidgetClass, layout,
\r
392 formArgs, XtNumber(formArgs));
\r
394 XtCreateManagedWidget("form2", formWidgetClass, layout,
\r
395 formArgs, XtNumber(formArgs));
\r
397 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
\r
398 XtSetValues(form2, args, j);
\r
399 // make sure width is known in advance, for better placement of child widgets
\r
401 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
\r
402 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
\r
403 XtSetValues(shell, args, j);
\r
405 // fill up both forms with control elements
\r
406 PositionControlSet(0, form, bw_width);
\r
407 PositionControlSet(1, form2, bw_width);
\r
409 XtRealizeWidget(shell);
\r
411 if (engineOutputX == -1) {
\r
414 Dimension pw_height;
\r
415 Dimension ew_height;
\r
418 XtSetArg(args[j], XtNheight, &ew_height); j++;
\r
419 XtGetValues(edit, args, j);
\r
422 XtSetArg(args[j], XtNheight, &pw_height); j++;
\r
423 XtGetValues(shell, args, j);
\r
424 engineOutputH = pw_height + (lines - 1) * ew_height;
\r
425 engineOutputW = bw_width - 16;
\r
427 engineOutputH = bw_height/2;
\r
428 engineOutputW = bw_width-16;
\r
431 XSync(xDisplay, False);
\r
433 /* This code seems to tickle an X bug if it is executed too soon
\r
434 after xboard starts up. The coordinates get transformed as if
\r
435 the main window was positioned at (0, 0).
\r
437 XtTranslateCoords(shellWidget,
\r
438 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
\r
439 &engineOutputX, &engineOutputY);
\r
441 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
\r
442 RootWindowOfScreen(XtScreen(shellWidget)),
\r
443 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
\r
445 engineOutputX = xx;
\r
446 engineOutputY = yy;
\r
448 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
\r
451 XtSetArg(args[j], XtNheight, engineOutputH); j++;
\r
452 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
\r
453 XtSetArg(args[j], XtNx, engineOutputX); j++;
\r
454 XtSetArg(args[j], XtNy, engineOutputY); j++;
\r
455 XtSetValues(shell, args, j);
\r
456 // XtSetKeyboardFocus(shell, edit);
\r
461 void ResizeWindowControls(shell, mode)
\r
465 Widget form1, form2;
\r
468 Dimension ew_height, tmp;
\r
470 form1 = XtNameToWidget(shell, "*form");
\r
471 form2 = XtNameToWidget(shell, "*form2");
\r
474 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
\r
475 XtGetValues(form1, args, j);
\r
477 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
\r
478 XtGetValues(form2, args, j);
\r
479 ew_height += tmp; // total height
\r
483 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
\r
484 XtSetValues(form2, args, j);
\r
486 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
\r
487 XtSetValues(form1, args, j);
\r
490 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
\r
491 XtSetValues(form1, args, j);
\r
493 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
\r
494 XtSetValues(form2, args, j);
\r
498 void EngineOutputPopUp(title, text)
\r
499 char *title, *text;
\r
505 if (engineOutputShell == NULL) {
\r
506 engineOutputShell =
\r
507 EngineOutputCreate(title, text);
\r
508 XtRealizeWidget(engineOutputShell);
\r
509 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
\r
511 InitializeEngineOutput();
\r
514 SetEngineColorIcon( 0 );
\r
515 SetEngineColorIcon( 1 );
\r
516 SetEngineState( 0, STATE_IDLE, "" );
\r
517 SetEngineState( 1, STATE_IDLE, "" );
\r
519 edit = XtNameToWidget(engineOutputShell, "*form.text");
\r
521 XtSetArg(args[j], XtNstring, text); j++;
\r
522 XtSetValues(edit, args, j);
\r
524 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
\r
525 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
\r
526 XtSetValues(engineOutputShell, args, j);
\r
529 XtPopup(engineOutputShell, XtGrabNone);
\r
530 XSync(xDisplay, False);
\r
533 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
\r
534 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
\r
537 engineOutputDialogUp = True;
\r
538 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
\r
541 void EngineOutputPopDown()
\r
546 if (!engineOutputDialogUp) return;
\r
549 XtSetArg(args[j], XtNx, &engineOutputX); j++;
\r
550 XtSetArg(args[j], XtNy, &engineOutputY); j++;
\r
551 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
\r
552 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
\r
553 XtGetValues(engineOutputShell, args, j);
\r
554 XtPopdown(engineOutputShell);
\r
555 XSync(xDisplay, False);
\r
557 XtSetArg(args[j], XtNleftBitmap, None); j++;
\r
558 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
\r
561 engineOutputDialogUp = False;
\r
562 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
\r
565 //------------------------ pure back-end routines -------------------------------
\r
568 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
\r
569 static SetEngineState( int which, int state, char * state_data )
\r
571 int x_which = 1 - which;
\r
573 if( engineState[ which ] != state ) {
\r
574 engineState[ which ] = state;
\r
577 case STATE_THINKING:
\r
578 SetIcon( which, nStateIcon, nThinking );
\r
579 if( engineState[ x_which ] == STATE_THINKING ) {
\r
580 SetEngineState( x_which, STATE_IDLE, "" );
\r
583 case STATE_PONDERING:
\r
584 SetIcon( which, nStateIcon, nPondering );
\r
586 case STATE_ANALYZING:
\r
587 SetIcon( which, nStateIcon, nAnalyzing );
\r
590 SetIcon( which, nStateIcon, nClear );
\r
595 if( state_data != 0 ) {
\r
596 DoSetWindowText( which, nStateData, state_data );
\r
600 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
\r
601 void EngineOutputUpdate( FrontEndProgramStats * stats )
\r
603 EngineOutputData ed;
\r
604 int clearMemo = FALSE;
\r
609 SetEngineState( 0, STATE_IDLE, "" );
\r
610 SetEngineState( 1, STATE_IDLE, "" );
\r
614 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
\r
615 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
\r
617 which = stats->which;
\r
618 depth = stats->depth;
\r
620 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
\r
624 if( engineOutputShell == NULL ) {
\r
628 VerifyDisplayMode();
\r
632 ed.nodes = stats->nodes;
\r
633 ed.score = stats->score;
\r
634 ed.time = stats->time;
\r
636 ed.hint = stats->hint;
\r
637 ed.an_move_index = stats->an_move_index;
\r
638 ed.an_move_count = stats->an_move_count;
\r
640 /* Get target control. [HGM] this is moved to front end, which get them from a table */
\r
642 ed.name = first.tidy;
\r
645 ed.name = second.tidy;
\r
648 /* Clear memo if needed */
\r
649 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
\r
653 if( lastForwardMostMove[which] != forwardMostMove ) {
\r
657 if( clearMemo ) DoClearMemo(which);
\r
660 lastDepth[which] = depth;
\r
661 lastForwardMostMove[which] = forwardMostMove;
\r
663 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
\r
664 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
\r
669 UpdateControls( &ed );
\r
672 #define ENGINE_COLOR_WHITE 'w'
\r
673 #define ENGINE_COLOR_BLACK 'b'
\r
674 #define ENGINE_COLOR_UNKNOWN ' '
\r
677 char GetEngineColor( int which )
\r
679 char result = ENGINE_COLOR_UNKNOWN;
\r
681 if( which == 0 || which == 1 ) {
\r
682 ChessProgramState * cps;
\r
684 switch (gameMode) {
\r
685 case MachinePlaysBlack:
\r
686 case IcsPlayingBlack:
\r
687 result = ENGINE_COLOR_BLACK;
\r
689 case MachinePlaysWhite:
\r
690 case IcsPlayingWhite:
\r
691 result = ENGINE_COLOR_WHITE;
\r
695 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
697 case TwoMachinesPlay:
\r
698 cps = (which == 0) ? &first : &second;
\r
699 result = cps->twoMachinesColor[0];
\r
700 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
709 char GetActiveEngineColor()
\r
711 char result = ENGINE_COLOR_UNKNOWN;
\r
713 if( gameMode == TwoMachinesPlay ) {
\r
714 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
721 static int IsEnginePondering( int which )
\r
723 int result = FALSE;
\r
725 switch (gameMode) {
\r
726 case MachinePlaysBlack:
\r
727 case IcsPlayingBlack:
\r
728 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
730 case MachinePlaysWhite:
\r
731 case IcsPlayingWhite:
\r
732 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
734 case TwoMachinesPlay:
\r
735 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
736 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
745 static void SetDisplayMode( int mode )
\r
747 if( windowMode != mode ) {
\r
750 ResizeWindowControls( engineOutputShell, mode );
\r
755 int VerifyDisplayMode()
\r
759 /* Get proper mode for current game */
\r
760 switch( gameMode ) {
\r
761 case IcsObserving: // [HGM] ICS analyze
\r
762 if(!appData.icsEngineAnalyze) return;
\r
765 case MachinePlaysWhite:
\r
766 case MachinePlaysBlack:
\r
769 case IcsPlayingWhite:
\r
770 case IcsPlayingBlack:
\r
771 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
773 case TwoMachinesPlay:
\r
777 /* Do not change */
\r
781 SetDisplayMode( mode );
\r
784 // back end. Determine what icon to se in the color-icon field, and print it
\r
785 static void SetEngineColorIcon( int which )
\r
787 char color = GetEngineColor(which);
\r
790 if( color == ENGINE_COLOR_BLACK )
\r
791 nicon = nColorBlack;
\r
792 else if( color == ENGINE_COLOR_WHITE )
\r
793 nicon = nColorWhite;
\r
795 nicon = nColorUnknown;
\r
797 SetIcon( which, nColorIcon, nicon );
\r
800 #define MAX_NAME_LENGTH 32
\r
802 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
803 static void UpdateControls( EngineOutputData * ed )
\r
805 int isPondering = FALSE;
\r
807 char s_label[MAX_NAME_LENGTH + 32];
\r
809 char * name = ed->name;
\r
812 if( name == 0 || *name == '\0' ) {
\r
816 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
817 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
819 #ifdef SHOW_PONDERING
\r
820 if( IsEnginePondering( ed->which ) ) {
\r
825 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
826 strncpy( buf, ed->hint, sizeof(buf) );
\r
827 buf[sizeof(buf)-1] = '\0';
\r
829 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
830 char * sep = strchr( ed->pv, ' ' );
\r
831 int buflen = sizeof(buf);
\r
833 if( sep != NULL ) {
\r
834 buflen = sep - ed->pv + 1;
\r
835 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
838 strncpy( buf, ed->pv, buflen );
\r
839 buf[ buflen-1 ] = '\0';
\r
842 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
844 else if( gameMode == TwoMachinesPlay ) {
\r
845 SetEngineState( ed->which, STATE_THINKING, "" );
\r
847 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
848 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
\r
850 int time_secs = ed->time / 100;
\r
851 int time_mins = time_secs / 60;
\r
855 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
858 strncpy( mov, ed->hint, sizeof(mov) );
\r
859 mov[ sizeof(mov)-1 ] = '\0';
\r
861 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
864 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
867 SetEngineState( ed->which, STATE_IDLE, "" );
\r
871 DoSetWindowText( ed->which, nLabel, s_label );
\r
875 if( ed->time > 0 && ed->nodes > 0 ) {
\r
876 unsigned long nps_100 = ed->nodes / ed->time;
\r
878 if( nps_100 < 100000 ) {
\r
879 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
\r
882 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
\r
886 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
889 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
895 int time_secs = ed->time / 100;
\r
896 int time_cent = ed->time % 100;
\r
899 if( ed->nodes < 1000000 ) {
\r
900 sprintf( s_nodes, u64Display, ed->nodes );
\r
903 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
\r
907 if( ed->score > 0 ) {
\r
908 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
910 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
913 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
915 /* Put all together... */
\r
916 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
919 buflen = strlen(buf);
\r
921 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
923 buf[ sizeof(buf) - 3 ] = '\0';
\r
925 strcat( buf + buflen, "\n" );
\r
928 InsertIntoMemo( ed->which, buf );
\r
932 SetEngineColorIcon( ed->which );
\r
936 int EngineOutputIsUp()
\r
938 return engineOutputDialogUp;
\r
942 EngineOutputProc(w, event, prms, nprms)
\r
948 if (engineOutputDialogUp) {
\r
949 EngineOutputPopDown();
\r
951 EngineOutputPopUp(_("engine output"),_("This feature is experimental"));
\r
953 // ToNrEvent(currentMove);
\r
956 // [HGM] kibitz: write kibitz line; split window for it if necessary
\r
957 void OutputKibitz(int window, char *text)
\r
959 if(!EngineOutputIsUp()) return;
\r
960 if(!opponentKibitzes) { // on first kibitz of game, clear memos
\r
962 if(gameMode == IcsObserving) DoClearMemo(0);
\r
964 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
\r
965 VerifyDisplayMode();
\r
966 if(gameMode == IcsObserving) {
\r
967 DoSetWindowText(0, nLabel, gameInfo.white);
\r
968 SetIcon( 0, nColorIcon, nColorWhite);
\r
969 SetIcon( 0, nStateIcon, nClear);
\r
971 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
\r
972 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
\r
973 SetIcon( 1, nStateIcon, nClear);
\r
974 InsertIntoMemo(window-1, text);
\r