4 * Author: Alessandro Scotti (Dec 2005)
\r
6 * Copyright 2005 Alessandro Scotti
\r
8 * Enhancements Copyright 2009 Free Software Foundation, Inc.
\r
10 * ------------------------------------------------------------------------
\r
12 * GNU XBoard is free software: you can redistribute it and/or modify
\r
13 * it under the terms of the GNU General Public License as published by
\r
14 * the Free Software Foundation, either version 3 of the License, or (at
\r
15 * your option) any later version.
\r
17 * GNU XBoard is distributed in the hope that it will be useful, but
\r
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
20 * General Public License for more details.
\r
22 * You should have received a copy of the GNU General Public License
\r
23 * along with this program. If not, see http://www.gnu.org/licenses/.
\r
25 * ------------------------------------------------------------------------
\r
26 ** See the file ChangeLog for a revision history. */
\r
33 #include <sys/types.h>
\r
36 # include <stdlib.h>
\r
37 # include <string.h>
\r
38 #else /* not STDC_HEADERS */
\r
39 extern char *getenv();
\r
41 # include <string.h>
\r
42 # else /* not HAVE_STRING_H */
\r
43 # include <strings.h>
\r
44 # endif /* not HAVE_STRING_H */
\r
45 #endif /* not STDC_HEADERS */
\r
48 # include <unistd.h>
\r
51 #include <X11/Intrinsic.h>
\r
52 #include <X11/StringDefs.h>
\r
53 #include <X11/Shell.h>
\r
54 #include <X11/Xaw/Dialog.h>
\r
55 #include <X11/Xaw/Form.h>
\r
56 #include <X11/Xaw/List.h>
\r
57 #include <X11/Xaw/Label.h>
\r
58 #include <X11/Xaw/SimpleMenu.h>
\r
59 #include <X11/Xaw/SmeBSB.h>
\r
60 #include <X11/Xaw/SmeLine.h>
\r
61 #include <X11/Xaw/Box.h>
\r
62 #include <X11/Xaw/Paned.h>
\r
63 #include <X11/Xaw/MenuButton.h>
\r
64 #include <X11/cursorfont.h>
\r
65 #include <X11/Xaw/Text.h>
\r
66 #include <X11/Xaw/AsciiText.h>
\r
67 #include <X11/Xaw/Viewport.h>
\r
70 #include "frontend.h"
\r
71 #include "backend.h"
\r
73 // Add xengineo.h later
\r
74 #include "gettext.h"
\r
77 # define _(s) gettext (s)
\r
78 # define N_(s) gettext_noop (s)
\r
84 #include <X11/xpm.h>
\r
86 // [HGM] pixmaps of some ICONS used in the engine-outut window
\r
87 #include "pixmaps/WHITE_14.xpm"
\r
88 #include "pixmaps/BLACK_14.xpm"
\r
89 #include "pixmaps/CLEAR_14.xpm"
\r
90 #include "pixmaps/UNKNOWN_14.xpm"
\r
91 #include "pixmaps/THINKING_14.xpm"
\r
92 #include "pixmaps/PONDER_14.xpm"
\r
93 #include "pixmaps/ANALYZING_14.xpm"
\r
101 // imports from xboard.c
\r
102 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
\r
103 extern Display *xDisplay;
\r
104 extern Window xBoardWindow;
\r
105 extern int squareSize;
\r
106 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
\r
107 extern char *layoutName;
\r
109 // temporary kludge to avoid compile errors untill all Windows code has been replaced
\r
110 #define HICON int *
\r
113 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
\r
114 #define nColorBlack 1
\r
115 #define nColorWhite 2
\r
116 #define nColorUnknown 3
\r
118 #define nPondering 5
\r
119 #define nThinking 6
\r
120 #define nAnalyzing 7
\r
122 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
\r
124 // [HGM] same for output fields (note that there are two of each type, one per color)
\r
125 #define nColorIcon 1
\r
126 #define nStateIcon 2
\r
128 #define nStateData 4
\r
129 #define nLabelNPS 5
\r
132 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
\r
134 void EngineOutputPopDown();
\r
135 void engineOutputPopUp(char *title, char *text);
\r
136 int EngineOutputIsUp();
\r
137 static void SetEngineColorIcon( int which );
\r
139 #define SHOW_PONDERING
\r
141 /* Imports from backend.c */
\r
142 char * SavePart(char *str);
\r
143 extern int opponentKibitzes;
\r
145 /* Imports from winboard.c */
\r
146 //extern HWND engineOutputDialog;
\r
147 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
\r
149 //extern WindowPlacement wpEngineOutput;
\r
151 Position engineOutputX = -1, engineOutputY = -1;
\r
152 Dimension engineOutputW, engineOutputH;
\r
153 Widget engineOutputShell;
\r
154 int engineOutputDialogUp;
\r
156 /* Module variables */
\r
159 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
\r
160 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
\r
162 #define ICON_SIZE 14
\r
164 #define STATE_UNKNOWN -1
\r
165 #define STATE_THINKING 0
\r
166 #define STATE_IDLE 1
\r
167 #define STATE_PONDERING 2
\r
168 #define STATE_ANALYZING 3
\r
170 static int windowMode = 1;
\r
172 static int needInit = TRUE;
\r
174 static int lastDepth[2] = { -1, -1 };
\r
175 static int lastForwardMostMove[2] = { -1, -1 };
\r
176 static int engineState[2] = { -1, -1 };
\r
189 } EngineOutputData;
\r
191 static int VerifyDisplayMode();
\r
192 static void UpdateControls( EngineOutputData * ed );
\r
193 static SetEngineState( int which, int state, char * state_data );
\r
195 void ReadIcon(char *pixData[], int iconNr)
\r
199 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
\r
202 NULL, NULL /*&attr*/)) != 0) {
\r
203 fprintf(stderr, _("Error %d loading icon image\n"), r);
\r
208 static void InitializeEngineOutput()
\r
211 ReadIcon(WHITE_14, nColorWhite);
\r
212 ReadIcon(BLACK_14, nColorBlack);
\r
213 ReadIcon(UNKNOWN_14, nColorUnknown);
\r
215 ReadIcon(CLEAR_14, nClear);
\r
216 ReadIcon(PONDER_14, nPondering);
\r
217 ReadIcon(THINK_14, nThinking);
\r
218 ReadIcon(ANALYZE_14, nAnalyzing);
\r
221 void DoSetWindowText(int which, int field, char *s_label)
\r
225 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
\r
226 XtSetValues(outputField[which][field], &arg, 1);
\r
229 static void InsertIntoMemo( int which, char * text )
\r
231 Arg arg; XawTextBlock t; Widget edit;
\r
233 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
\r
234 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
\r
235 XawTextReplace(edit, 0, 0, &t);
\r
236 // XtSetArg(arg, XtNstring, (XtArgVal) text);
\r
237 // XtSetValues(outputField[which][nMemo], &arg, 1);
\r
240 static void SetIcon( int which, int field, int nIcon )
\r
245 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
\r
246 XtSetValues(outputField[which][field], &arg, 1);
\r
250 void DoClearMemo(int which)
\r
256 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
\r
257 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
\r
258 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
\r
261 // The following routines are mutated clones of the commentPopUp routines
\r
263 void PositionControlSet(which, form, bw_width)
\r
266 Dimension bw_width;
\r
269 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
\r
272 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
273 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
274 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
275 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
276 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
277 XtSetArg(args[j], XtNright, XtChainLeft); j++;
\r
278 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
279 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
\r
280 outputField[which][nColorIcon] = ColorWidget =
\r
281 XtCreateManagedWidget("Color", labelWidgetClass,
\r
285 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
286 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
\r
287 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
\r
288 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
289 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
290 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
291 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
292 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
\r
293 outputField[which][nLabel] = NameWidget =
\r
294 XtCreateManagedWidget("Engine", labelWidgetClass,
\r
298 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
299 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
300 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
\r
301 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
302 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
303 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
304 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
\r
305 outputField[which][nStateIcon] = ModeWidget =
\r
306 XtCreateManagedWidget("Mode", labelWidgetClass,
\r
310 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
311 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
\r
312 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
313 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
\r
314 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
315 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
316 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
317 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
318 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
\r
319 outputField[which][nStateData] = MoveWidget =
\r
320 XtCreateManagedWidget("Move", labelWidgetClass,
\r
324 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
325 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
\r
326 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
\r
327 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
\r
328 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
329 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
330 XtSetArg(args[j], XtNleft, XtChainRight); j++;
\r
331 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
332 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
333 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
\r
334 outputField[which][nLabelNPS] = NodesWidget =
\r
335 XtCreateManagedWidget("Nodes", labelWidgetClass,
\r
338 // create "text" within "form"
\r
341 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
\r
342 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
\r
344 XtSetArg(args[j], XtNstring, ""); j++;
\r
345 XtSetArg(args[j], XtNdisplayCaret, False); j++;
\r
346 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
347 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
\r
348 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
349 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
350 XtSetArg(args[j], XtNresizable, True); j++;
\r
351 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
\r
353 XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded); j++;
\r
355 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
\r
356 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
\r
357 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
\r
359 // XtSetArg(args[j], XtNautoFill, True); j++;
\r
360 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
\r
361 outputField[which][nMemo] = edit =
\r
362 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
\r
365 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
\r
366 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
\r
367 XtSetValues(edit, args, j);
\r
370 Widget EngineOutputCreate(name, text)
\r
374 Widget shell, layout, form, form2, edit;
\r
375 Dimension bw_width, bw_height;
\r
380 XtSetArg(args[j], XtNwidth, &bw_width); j++;
\r
381 XtSetArg(args[j], XtNheight, &bw_height); j++;
\r
382 XtGetValues(boardWidget, args, j);
\r
384 // define form within layout within shell.
\r
386 XtSetArg(args[j], XtNresizable, True); j++;
\r
388 XtCreatePopupShell(name, transientShellWidgetClass,
\r
389 shellWidget, args, j);
\r
391 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
\r
392 layoutArgs, XtNumber(layoutArgs));
\r
393 // divide window vertically into two equal parts, by creating two forms
\r
395 XtCreateManagedWidget("form", formWidgetClass, layout,
\r
396 formArgs, XtNumber(formArgs));
\r
398 XtCreateManagedWidget("form2", formWidgetClass, layout,
\r
399 formArgs, XtNumber(formArgs));
\r
401 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
\r
402 XtSetValues(form2, args, j);
\r
403 // make sure width is known in advance, for better placement of child widgets
\r
405 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
\r
406 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
\r
407 XtSetValues(shell, args, j);
\r
409 // fill up both forms with control elements
\r
410 PositionControlSet(0, form, bw_width);
\r
411 PositionControlSet(1, form2, bw_width);
\r
413 XtRealizeWidget(shell);
\r
415 if (engineOutputX == -1) {
\r
418 Dimension pw_height;
\r
419 Dimension ew_height;
\r
422 XtSetArg(args[j], XtNheight, &ew_height); j++;
\r
423 XtGetValues(edit, args, j);
\r
426 XtSetArg(args[j], XtNheight, &pw_height); j++;
\r
427 XtGetValues(shell, args, j);
\r
428 engineOutputH = pw_height + (lines - 1) * ew_height;
\r
429 engineOutputW = bw_width - 16;
\r
431 engineOutputH = bw_height/2;
\r
432 engineOutputW = bw_width-16;
\r
435 XSync(xDisplay, False);
\r
437 /* This code seems to tickle an X bug if it is executed too soon
\r
438 after xboard starts up. The coordinates get transformed as if
\r
439 the main window was positioned at (0, 0).
\r
441 XtTranslateCoords(shellWidget,
\r
442 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
\r
443 &engineOutputX, &engineOutputY);
\r
445 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
\r
446 RootWindowOfScreen(XtScreen(shellWidget)),
\r
447 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
\r
449 engineOutputX = xx;
\r
450 engineOutputY = yy;
\r
452 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
\r
455 XtSetArg(args[j], XtNheight, engineOutputH); j++;
\r
456 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
\r
457 XtSetArg(args[j], XtNx, engineOutputX); j++;
\r
458 XtSetArg(args[j], XtNy, engineOutputY); j++;
\r
459 XtSetValues(shell, args, j);
\r
460 // XtSetKeyboardFocus(shell, edit);
\r
465 void ResizeWindowControls(shell, mode)
\r
469 Widget form1, form2;
\r
472 Dimension ew_height, tmp;
\r
474 form1 = XtNameToWidget(shell, "*form");
\r
475 form2 = XtNameToWidget(shell, "*form2");
\r
478 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
\r
479 XtGetValues(form1, args, j);
\r
481 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
\r
482 XtGetValues(form2, args, j);
\r
483 ew_height += tmp; // total height
\r
487 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
\r
488 XtSetValues(form2, args, j);
\r
490 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
\r
491 XtSetValues(form1, args, j);
\r
494 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
\r
495 XtSetValues(form1, args, j);
\r
497 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
\r
498 XtSetValues(form2, args, j);
\r
502 void EngineOutputPopUp(title, text)
\r
503 char *title, *text;
\r
509 if (engineOutputShell == NULL) {
\r
510 engineOutputShell =
\r
511 EngineOutputCreate(title, text);
\r
512 XtRealizeWidget(engineOutputShell);
\r
513 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
\r
515 InitializeEngineOutput();
\r
518 SetEngineColorIcon( 0 );
\r
519 SetEngineColorIcon( 1 );
\r
520 SetEngineState( 0, STATE_IDLE, "" );
\r
521 SetEngineState( 1, STATE_IDLE, "" );
\r
523 edit = XtNameToWidget(engineOutputShell, "*form.text");
\r
525 XtSetArg(args[j], XtNstring, text); j++;
\r
526 XtSetValues(edit, args, j);
\r
528 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
\r
529 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
\r
530 XtSetValues(engineOutputShell, args, j);
\r
533 XtPopup(engineOutputShell, XtGrabNone);
\r
534 XSync(xDisplay, False);
\r
537 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
\r
538 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
\r
541 engineOutputDialogUp = True;
\r
542 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
\r
545 void EngineOutputPopDown()
\r
550 if (!engineOutputDialogUp) return;
\r
553 XtSetArg(args[j], XtNx, &engineOutputX); j++;
\r
554 XtSetArg(args[j], XtNy, &engineOutputY); j++;
\r
555 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
\r
556 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
\r
557 XtGetValues(engineOutputShell, args, j);
\r
558 XtPopdown(engineOutputShell);
\r
559 XSync(xDisplay, False);
\r
561 XtSetArg(args[j], XtNleftBitmap, None); j++;
\r
562 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
\r
565 engineOutputDialogUp = False;
\r
566 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
\r
569 //------------------------ pure back-end routines -------------------------------
\r
572 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
\r
573 static SetEngineState( int which, int state, char * state_data )
\r
575 int x_which = 1 - which;
\r
577 if( engineState[ which ] != state ) {
\r
578 engineState[ which ] = state;
\r
581 case STATE_THINKING:
\r
582 SetIcon( which, nStateIcon, nThinking );
\r
583 if( engineState[ x_which ] == STATE_THINKING ) {
\r
584 SetEngineState( x_which, STATE_IDLE, "" );
\r
587 case STATE_PONDERING:
\r
588 SetIcon( which, nStateIcon, nPondering );
\r
590 case STATE_ANALYZING:
\r
591 SetIcon( which, nStateIcon, nAnalyzing );
\r
594 SetIcon( which, nStateIcon, nClear );
\r
599 if( state_data != 0 ) {
\r
600 DoSetWindowText( which, nStateData, state_data );
\r
604 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
\r
605 void EngineOutputUpdate( FrontEndProgramStats * stats )
\r
607 EngineOutputData ed;
\r
608 int clearMemo = FALSE;
\r
613 SetEngineState( 0, STATE_IDLE, "" );
\r
614 SetEngineState( 1, STATE_IDLE, "" );
\r
618 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
\r
619 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
\r
621 which = stats->which;
\r
622 depth = stats->depth;
\r
624 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
\r
628 if( engineOutputShell == NULL ) {
\r
632 VerifyDisplayMode();
\r
636 ed.nodes = stats->nodes;
\r
637 ed.score = stats->score;
\r
638 ed.time = stats->time;
\r
640 ed.hint = stats->hint;
\r
641 ed.an_move_index = stats->an_move_index;
\r
642 ed.an_move_count = stats->an_move_count;
\r
644 /* Get target control. [HGM] this is moved to front end, which get them from a table */
\r
646 ed.name = first.tidy;
\r
649 ed.name = second.tidy;
\r
652 /* Clear memo if needed */
\r
653 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
\r
657 if( lastForwardMostMove[which] != forwardMostMove ) {
\r
661 if( clearMemo ) DoClearMemo(which);
\r
664 lastDepth[which] = depth;
\r
665 lastForwardMostMove[which] = forwardMostMove;
\r
667 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
\r
668 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
\r
673 UpdateControls( &ed );
\r
676 #define ENGINE_COLOR_WHITE 'w'
\r
677 #define ENGINE_COLOR_BLACK 'b'
\r
678 #define ENGINE_COLOR_UNKNOWN ' '
\r
681 char GetEngineColor( int which )
\r
683 char result = ENGINE_COLOR_UNKNOWN;
\r
685 if( which == 0 || which == 1 ) {
\r
686 ChessProgramState * cps;
\r
688 switch (gameMode) {
\r
689 case MachinePlaysBlack:
\r
690 case IcsPlayingBlack:
\r
691 result = ENGINE_COLOR_BLACK;
\r
693 case MachinePlaysWhite:
\r
694 case IcsPlayingWhite:
\r
695 result = ENGINE_COLOR_WHITE;
\r
699 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
701 case TwoMachinesPlay:
\r
702 cps = (which == 0) ? &first : &second;
\r
703 result = cps->twoMachinesColor[0];
\r
704 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
713 char GetActiveEngineColor()
\r
715 char result = ENGINE_COLOR_UNKNOWN;
\r
717 if( gameMode == TwoMachinesPlay ) {
\r
718 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
725 static int IsEnginePondering( int which )
\r
727 int result = FALSE;
\r
729 switch (gameMode) {
\r
730 case MachinePlaysBlack:
\r
731 case IcsPlayingBlack:
\r
732 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
734 case MachinePlaysWhite:
\r
735 case IcsPlayingWhite:
\r
736 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
738 case TwoMachinesPlay:
\r
739 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
740 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
749 static void SetDisplayMode( int mode )
\r
751 if( windowMode != mode ) {
\r
754 ResizeWindowControls( engineOutputShell, mode );
\r
759 int VerifyDisplayMode()
\r
763 /* Get proper mode for current game */
\r
764 switch( gameMode ) {
\r
765 case IcsObserving: // [HGM] ICS analyze
\r
766 if(!appData.icsEngineAnalyze) return;
\r
769 case MachinePlaysWhite:
\r
770 case MachinePlaysBlack:
\r
773 case IcsPlayingWhite:
\r
774 case IcsPlayingBlack:
\r
775 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
777 case TwoMachinesPlay:
\r
781 /* Do not change */
\r
785 SetDisplayMode( mode );
\r
788 // back end. Determine what icon to se in the color-icon field, and print it
\r
789 static void SetEngineColorIcon( int which )
\r
791 char color = GetEngineColor(which);
\r
794 if( color == ENGINE_COLOR_BLACK )
\r
795 nicon = nColorBlack;
\r
796 else if( color == ENGINE_COLOR_WHITE )
\r
797 nicon = nColorWhite;
\r
799 nicon = nColorUnknown;
\r
801 SetIcon( which, nColorIcon, nicon );
\r
804 #define MAX_NAME_LENGTH 32
\r
806 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
807 static void UpdateControls( EngineOutputData * ed )
\r
809 int isPondering = FALSE;
\r
811 char s_label[MAX_NAME_LENGTH + 32];
\r
813 char * name = ed->name;
\r
816 if( name == 0 || *name == '\0' ) {
\r
820 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
821 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
823 #ifdef SHOW_PONDERING
\r
824 if( IsEnginePondering( ed->which ) ) {
\r
829 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
830 strncpy( buf, ed->hint, sizeof(buf) );
\r
831 buf[sizeof(buf)-1] = '\0';
\r
833 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
834 char * sep = strchr( ed->pv, ' ' );
\r
835 int buflen = sizeof(buf);
\r
837 if( sep != NULL ) {
\r
838 buflen = sep - ed->pv + 1;
\r
839 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
842 strncpy( buf, ed->pv, buflen );
\r
843 buf[ buflen-1 ] = '\0';
\r
846 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
848 else if( gameMode == TwoMachinesPlay ) {
\r
849 SetEngineState( ed->which, STATE_THINKING, "" );
\r
851 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
852 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
\r
854 int time_secs = ed->time / 100;
\r
855 int time_mins = time_secs / 60;
\r
859 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
862 strncpy( mov, ed->hint, sizeof(mov) );
\r
863 mov[ sizeof(mov)-1 ] = '\0';
\r
865 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
868 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
871 SetEngineState( ed->which, STATE_IDLE, "" );
\r
875 DoSetWindowText( ed->which, nLabel, s_label );
\r
879 if( ed->time > 0 && ed->nodes > 0 ) {
\r
880 unsigned long nps_100 = ed->nodes / ed->time;
\r
882 if( nps_100 < 100000 ) {
\r
883 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
\r
886 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
\r
890 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
893 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
899 int time_secs = ed->time / 100;
\r
900 int time_cent = ed->time % 100;
\r
903 if( ed->nodes < 1000000 ) {
\r
904 sprintf( s_nodes, u64Display, ed->nodes );
\r
907 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
\r
911 if( ed->score > 0 ) {
\r
912 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
914 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
917 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
919 /* Put all together... */
\r
920 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
923 buflen = strlen(buf);
\r
925 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
927 buf[ sizeof(buf) - 3 ] = '\0';
\r
929 strcat( buf + buflen, "\n" );
\r
932 InsertIntoMemo( ed->which, buf );
\r
936 SetEngineColorIcon( ed->which );
\r
940 int EngineOutputIsUp()
\r
942 return engineOutputDialogUp;
\r
946 EngineOutputProc(w, event, prms, nprms)
\r
952 if (engineOutputDialogUp) {
\r
953 EngineOutputPopDown();
\r
955 EngineOutputPopUp(_("engine output"),_("This feature is experimental"));
\r
957 // ToNrEvent(currentMove);
\r
960 // [HGM] kibitz: write kibitz line; split window for it if necessary
\r
961 void OutputKibitz(int window, char *text)
\r
963 if(!EngineOutputIsUp()) return;
\r
964 if(!opponentKibitzes) { // on first kibitz of game, clear memos
\r
966 if(gameMode == IcsObserving) DoClearMemo(0);
\r
968 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
\r
969 VerifyDisplayMode();
\r
970 if(gameMode == IcsObserving) {
\r
971 DoSetWindowText(0, nLabel, gameInfo.white);
\r
972 SetIcon( 0, nColorIcon, nColorWhite);
\r
973 SetIcon( 0, nStateIcon, nClear);
\r
975 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
\r
976 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
\r
977 SetIcon( 1, nStateIcon, nClear);
\r
978 InsertIntoMemo(window-1, text);
\r