4 * Author: Alessandro Scotti (Dec 2005)
\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
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
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
27 #include <sys/types.h>
\r
30 # include <stdlib.h>
\r
31 # include <string.h>
\r
32 #else /* not STDC_HEADERS */
\r
33 extern char *getenv();
\r
35 # include <string.h>
\r
36 # else /* not HAVE_STRING_H */
\r
37 # include <strings.h>
\r
38 # endif /* not HAVE_STRING_H */
\r
39 #endif /* not STDC_HEADERS */
\r
42 # include <unistd.h>
\r
45 #include <X11/Intrinsic.h>
\r
46 #include <X11/StringDefs.h>
\r
47 #include <X11/Shell.h>
\r
48 #include <X11/Xaw/Dialog.h>
\r
49 #include <X11/Xaw/Form.h>
\r
50 #include <X11/Xaw/List.h>
\r
51 #include <X11/Xaw/Label.h>
\r
52 #include <X11/Xaw/SimpleMenu.h>
\r
53 #include <X11/Xaw/SmeBSB.h>
\r
54 #include <X11/Xaw/SmeLine.h>
\r
55 #include <X11/Xaw/Box.h>
\r
56 #include <X11/Xaw/Paned.h>
\r
57 #include <X11/Xaw/MenuButton.h>
\r
58 #include <X11/cursorfont.h>
\r
59 #include <X11/Xaw/Text.h>
\r
60 #include <X11/Xaw/AsciiText.h>
\r
61 #include <X11/Xaw/Viewport.h>
\r
64 #include "frontend.h"
\r
65 #include "backend.h"
\r
67 // Add xengineo.h later
\r
68 #include "gettext.h"
\r
71 # define _(s) gettext (s)
\r
72 # define N_(s) gettext_noop (s)
\r
78 #include <X11/xpm.h>
\r
80 // [HGM] pixmaps of some ICONS used in the engine-outut window
\r
81 #include "pixmaps/WHITE_14.xpm"
\r
82 #include "pixmaps/BLACK_14.xpm"
\r
83 #include "pixmaps/CLEAR_14.xpm"
\r
84 #include "pixmaps/UNKNOWN_14.xpm"
\r
85 #include "pixmaps/THINKING_14.xpm"
\r
86 #include "pixmaps/PONDER_14.xpm"
\r
87 #include "pixmaps/ANALYZING_14.xpm"
\r
95 // imports from xboard.c
\r
96 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
\r
97 extern Display *xDisplay;
\r
98 extern Window xBoardWindow;
\r
99 extern int squareSize;
\r
100 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
\r
101 extern char *layoutName;
\r
103 // temporary kludge to avoid compile errors untill all Windows code has been replaced
\r
104 #define HICON int *
\r
107 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
\r
108 #define nColorBlack 1
\r
109 #define nColorWhite 2
\r
110 #define nColorUnknown 3
\r
112 #define nPondering 5
\r
113 #define nThinking 6
\r
114 #define nAnalyzing 7
\r
116 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
\r
118 // [HGM] same for output fields (note that there are two of each type, one per color)
\r
119 #define nColorIcon 1
\r
120 #define nStateIcon 2
\r
122 #define nStateData 4
\r
123 #define nLabelNPS 5
\r
126 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
\r
128 void EngineOutputPopDown();
\r
129 void engineOutputPopUp(char *title, char *text);
\r
130 int EngineOutputIsUp();
\r
131 static void SetEngineColorIcon( int which );
\r
133 #define SHOW_PONDERING
\r
135 /* Imports from backend.c */
\r
136 char * SavePart(char *str);
\r
137 extern int opponentKibitzes;
\r
139 /* Imports from winboard.c */
\r
140 //extern HWND engineOutputDialog;
\r
141 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
\r
143 //extern WindowPlacement wpEngineOutput;
\r
145 Position engineOutputX = -1, engineOutputY = -1;
\r
146 Dimension engineOutputW, engineOutputH;
\r
147 Widget engineOutputShell;
\r
148 int engineOutputDialogUp;
\r
150 /* Module variables */
\r
153 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
\r
154 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
\r
156 #define ICON_SIZE 14
\r
158 #define STATE_UNKNOWN -1
\r
159 #define STATE_THINKING 0
\r
160 #define STATE_IDLE 1
\r
161 #define STATE_PONDERING 2
\r
162 #define STATE_ANALYZING 3
\r
164 static int windowMode = 1;
\r
166 static int needInit = TRUE;
\r
168 static int lastDepth[2] = { -1, -1 };
\r
169 static int lastForwardMostMove[2] = { -1, -1 };
\r
170 static int engineState[2] = { -1, -1 };
\r
183 } EngineOutputData;
\r
185 static int VerifyDisplayMode();
\r
186 static void UpdateControls( EngineOutputData * ed );
\r
187 static SetEngineState( int which, int state, char * state_data );
\r
189 void ReadIcon(char *pixData[], int iconNr)
\r
193 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
\r
196 NULL, NULL /*&attr*/)) != 0) {
\r
197 fprintf(stderr, _("Error %d loading icon image\n"), r);
\r
202 static void InitializeEngineOutput()
\r
205 ReadIcon(WHITE_14, nColorWhite);
\r
206 ReadIcon(BLACK_14, nColorBlack);
\r
207 ReadIcon(UNKNOWN_14, nColorUnknown);
\r
209 ReadIcon(CLEAR_14, nClear);
\r
210 ReadIcon(PONDER_14, nPondering);
\r
211 ReadIcon(THINK_14, nThinking);
\r
212 ReadIcon(ANALYZE_14, nAnalyzing);
\r
215 void DoSetWindowText(int which, int field, char *s_label)
\r
219 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
\r
220 XtSetValues(outputField[which][field], &arg, 1);
\r
223 static void InsertIntoMemo( int which, char * text )
\r
225 Arg arg; XawTextBlock t; Widget edit;
\r
227 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
\r
228 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
\r
229 XawTextReplace(edit, 0, 0, &t);
\r
230 // XtSetArg(arg, XtNstring, (XtArgVal) text);
\r
231 // XtSetValues(outputField[which][nMemo], &arg, 1);
\r
234 static void SetIcon( int which, int field, int nIcon )
\r
239 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
\r
240 XtSetValues(outputField[which][field], &arg, 1);
\r
244 void DoClearMemo(int which)
\r
250 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
\r
251 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
\r
252 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
\r
255 // The following routines are mutated clones of the commentPopUp routines
\r
257 void PositionControlSet(which, form, bw_width)
\r
260 Dimension bw_width;
\r
263 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
\r
266 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
267 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
268 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
269 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
270 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
271 XtSetArg(args[j], XtNright, XtChainLeft); j++;
\r
272 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
273 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
\r
274 outputField[which][nColorIcon] = ColorWidget =
\r
275 XtCreateManagedWidget("Color", labelWidgetClass,
\r
279 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
280 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
\r
281 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
\r
282 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
283 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
284 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
285 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
286 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
\r
287 outputField[which][nLabel] = NameWidget =
\r
288 XtCreateManagedWidget("Engine", labelWidgetClass,
\r
292 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
293 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
294 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
\r
295 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
296 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
297 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
298 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
\r
299 outputField[which][nStateIcon] = ModeWidget =
\r
300 XtCreateManagedWidget("Mode", labelWidgetClass,
\r
304 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
305 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
\r
306 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
307 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
\r
308 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
309 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
310 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
311 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
312 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
\r
313 outputField[which][nStateData] = MoveWidget =
\r
314 XtCreateManagedWidget("Move", labelWidgetClass,
\r
318 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
\r
319 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
\r
320 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
\r
321 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
\r
322 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
323 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
324 XtSetArg(args[j], XtNleft, XtChainRight); j++;
\r
325 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
326 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
327 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
\r
328 outputField[which][nLabelNPS] = NodesWidget =
\r
329 XtCreateManagedWidget("Nodes", labelWidgetClass,
\r
332 // create "text" within "form"
\r
335 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
\r
336 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
\r
338 XtSetArg(args[j], XtNstring, ""); j++;
\r
339 XtSetArg(args[j], XtNdisplayCaret, False); j++;
\r
340 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
341 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
\r
342 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
343 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
344 XtSetArg(args[j], XtNresizable, True); j++;
\r
345 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
\r
347 XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded); j++;
\r
349 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
\r
350 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
\r
351 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
\r
353 // XtSetArg(args[j], XtNautoFill, True); j++;
\r
354 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
\r
355 outputField[which][nMemo] = edit =
\r
356 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
\r
359 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
\r
360 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
\r
361 XtSetValues(edit, args, j);
\r
364 Widget EngineOutputCreate(name, text)
\r
368 Widget shell, layout, form, form2, edit;
\r
369 Dimension bw_width, bw_height;
\r
374 XtSetArg(args[j], XtNwidth, &bw_width); j++;
\r
375 XtSetArg(args[j], XtNheight, &bw_height); j++;
\r
376 XtGetValues(boardWidget, args, j);
\r
378 // define form within layout within shell.
\r
380 XtSetArg(args[j], XtNresizable, True); j++;
\r
382 XtCreatePopupShell(name, transientShellWidgetClass,
\r
383 shellWidget, args, j);
\r
385 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
\r
386 layoutArgs, XtNumber(layoutArgs));
\r
387 // divide window vertically into two equal parts, by creating two forms
\r
389 XtCreateManagedWidget("form", formWidgetClass, layout,
\r
390 formArgs, XtNumber(formArgs));
\r
392 XtCreateManagedWidget("form2", formWidgetClass, layout,
\r
393 formArgs, XtNumber(formArgs));
\r
395 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
\r
396 XtSetValues(form2, args, j);
\r
397 // make sure width is known in advance, for better placement of child widgets
\r
399 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
\r
400 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
\r
401 XtSetValues(shell, args, j);
\r
403 // fill up both forms with control elements
\r
404 PositionControlSet(0, form, bw_width);
\r
405 PositionControlSet(1, form2, bw_width);
\r
407 XtRealizeWidget(shell);
\r
409 if (engineOutputX == -1) {
\r
412 Dimension pw_height;
\r
413 Dimension ew_height;
\r
416 XtSetArg(args[j], XtNheight, &ew_height); j++;
\r
417 XtGetValues(edit, args, j);
\r
420 XtSetArg(args[j], XtNheight, &pw_height); j++;
\r
421 XtGetValues(shell, args, j);
\r
422 engineOutputH = pw_height + (lines - 1) * ew_height;
\r
423 engineOutputW = bw_width - 16;
\r
425 engineOutputH = bw_height/2;
\r
426 engineOutputW = bw_width-16;
\r
429 XSync(xDisplay, False);
\r
431 /* This code seems to tickle an X bug if it is executed too soon
\r
432 after xboard starts up. The coordinates get transformed as if
\r
433 the main window was positioned at (0, 0).
\r
435 XtTranslateCoords(shellWidget,
\r
436 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
\r
437 &engineOutputX, &engineOutputY);
\r
439 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
\r
440 RootWindowOfScreen(XtScreen(shellWidget)),
\r
441 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
\r
443 engineOutputX = xx;
\r
444 engineOutputY = yy;
\r
446 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
\r
449 XtSetArg(args[j], XtNheight, engineOutputH); j++;
\r
450 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
\r
451 XtSetArg(args[j], XtNx, engineOutputX); j++;
\r
452 XtSetArg(args[j], XtNy, engineOutputY); j++;
\r
453 XtSetValues(shell, args, j);
\r
454 // XtSetKeyboardFocus(shell, edit);
\r
459 void ResizeWindowControls(shell, mode)
\r
463 Widget form1, form2;
\r
466 Dimension ew_height, tmp;
\r
468 form1 = XtNameToWidget(shell, "*form");
\r
469 form2 = XtNameToWidget(shell, "*form2");
\r
472 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
\r
473 XtGetValues(form1, args, j);
\r
475 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
\r
476 XtGetValues(form2, args, j);
\r
477 ew_height += tmp; // total height
\r
481 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
\r
482 XtSetValues(form2, args, j);
\r
484 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
\r
485 XtSetValues(form1, args, j);
\r
488 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
\r
489 XtSetValues(form1, args, j);
\r
491 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
\r
492 XtSetValues(form2, args, j);
\r
496 void EngineOutputPopUp(title, text)
\r
497 char *title, *text;
\r
503 if (engineOutputShell == NULL) {
\r
504 engineOutputShell =
\r
505 EngineOutputCreate(title, text);
\r
506 XtRealizeWidget(engineOutputShell);
\r
507 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
\r
509 InitializeEngineOutput();
\r
512 SetEngineColorIcon( 0 );
\r
513 SetEngineColorIcon( 1 );
\r
514 SetEngineState( 0, STATE_IDLE, "" );
\r
515 SetEngineState( 1, STATE_IDLE, "" );
\r
517 edit = XtNameToWidget(engineOutputShell, "*form.text");
\r
519 XtSetArg(args[j], XtNstring, text); j++;
\r
520 XtSetValues(edit, args, j);
\r
522 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
\r
523 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
\r
524 XtSetValues(engineOutputShell, args, j);
\r
527 XtPopup(engineOutputShell, XtGrabNone);
\r
528 XSync(xDisplay, False);
\r
531 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
\r
532 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
\r
535 engineOutputDialogUp = True;
\r
536 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
\r
539 void EngineOutputPopDown()
\r
544 if (!engineOutputDialogUp) return;
\r
547 XtSetArg(args[j], XtNx, &engineOutputX); j++;
\r
548 XtSetArg(args[j], XtNy, &engineOutputY); j++;
\r
549 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
\r
550 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
\r
551 XtGetValues(engineOutputShell, args, j);
\r
552 XtPopdown(engineOutputShell);
\r
553 XSync(xDisplay, False);
\r
555 XtSetArg(args[j], XtNleftBitmap, None); j++;
\r
556 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
\r
559 engineOutputDialogUp = False;
\r
560 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
\r
563 //------------------------ pure back-end routines -------------------------------
\r
566 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
\r
567 static SetEngineState( int which, int state, char * state_data )
\r
569 int x_which = 1 - which;
\r
571 if( engineState[ which ] != state ) {
\r
572 engineState[ which ] = state;
\r
575 case STATE_THINKING:
\r
576 SetIcon( which, nStateIcon, nThinking );
\r
577 if( engineState[ x_which ] == STATE_THINKING ) {
\r
578 SetEngineState( x_which, STATE_IDLE, "" );
\r
581 case STATE_PONDERING:
\r
582 SetIcon( which, nStateIcon, nPondering );
\r
584 case STATE_ANALYZING:
\r
585 SetIcon( which, nStateIcon, nAnalyzing );
\r
588 SetIcon( which, nStateIcon, nClear );
\r
593 if( state_data != 0 ) {
\r
594 DoSetWindowText( which, nStateData, state_data );
\r
598 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
\r
599 void EngineOutputUpdate( FrontEndProgramStats * stats )
\r
601 EngineOutputData ed;
\r
602 int clearMemo = FALSE;
\r
607 SetEngineState( 0, STATE_IDLE, "" );
\r
608 SetEngineState( 1, STATE_IDLE, "" );
\r
612 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
\r
613 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
\r
615 which = stats->which;
\r
616 depth = stats->depth;
\r
618 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
\r
622 if( engineOutputShell == NULL ) {
\r
626 VerifyDisplayMode();
\r
630 ed.nodes = stats->nodes;
\r
631 ed.score = stats->score;
\r
632 ed.time = stats->time;
\r
634 ed.hint = stats->hint;
\r
635 ed.an_move_index = stats->an_move_index;
\r
636 ed.an_move_count = stats->an_move_count;
\r
638 /* Get target control. [HGM] this is moved to front end, which get them from a table */
\r
640 ed.name = first.tidy;
\r
643 ed.name = second.tidy;
\r
646 /* Clear memo if needed */
\r
647 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
\r
651 if( lastForwardMostMove[which] != forwardMostMove ) {
\r
655 if( clearMemo ) DoClearMemo(which);
\r
658 lastDepth[which] = depth;
\r
659 lastForwardMostMove[which] = forwardMostMove;
\r
661 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
\r
662 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
\r
667 UpdateControls( &ed );
\r
670 #define ENGINE_COLOR_WHITE 'w'
\r
671 #define ENGINE_COLOR_BLACK 'b'
\r
672 #define ENGINE_COLOR_UNKNOWN ' '
\r
675 char GetEngineColor( int which )
\r
677 char result = ENGINE_COLOR_UNKNOWN;
\r
679 if( which == 0 || which == 1 ) {
\r
680 ChessProgramState * cps;
\r
682 switch (gameMode) {
\r
683 case MachinePlaysBlack:
\r
684 case IcsPlayingBlack:
\r
685 result = ENGINE_COLOR_BLACK;
\r
687 case MachinePlaysWhite:
\r
688 case IcsPlayingWhite:
\r
689 result = ENGINE_COLOR_WHITE;
\r
693 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
695 case TwoMachinesPlay:
\r
696 cps = (which == 0) ? &first : &second;
\r
697 result = cps->twoMachinesColor[0];
\r
698 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
707 char GetActiveEngineColor()
\r
709 char result = ENGINE_COLOR_UNKNOWN;
\r
711 if( gameMode == TwoMachinesPlay ) {
\r
712 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
719 static int IsEnginePondering( int which )
\r
721 int result = FALSE;
\r
723 switch (gameMode) {
\r
724 case MachinePlaysBlack:
\r
725 case IcsPlayingBlack:
\r
726 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
728 case MachinePlaysWhite:
\r
729 case IcsPlayingWhite:
\r
730 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
732 case TwoMachinesPlay:
\r
733 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
734 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
743 static void SetDisplayMode( int mode )
\r
745 if( windowMode != mode ) {
\r
748 ResizeWindowControls( engineOutputShell, mode );
\r
753 int VerifyDisplayMode()
\r
757 /* Get proper mode for current game */
\r
758 switch( gameMode ) {
\r
759 case IcsObserving: // [HGM] ICS analyze
\r
760 if(!appData.icsEngineAnalyze) return;
\r
763 case MachinePlaysWhite:
\r
764 case MachinePlaysBlack:
\r
767 case IcsPlayingWhite:
\r
768 case IcsPlayingBlack:
\r
769 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
771 case TwoMachinesPlay:
\r
775 /* Do not change */
\r
779 SetDisplayMode( mode );
\r
782 // back end. Determine what icon to se in the color-icon field, and print it
\r
783 static void SetEngineColorIcon( int which )
\r
785 char color = GetEngineColor(which);
\r
788 if( color == ENGINE_COLOR_BLACK )
\r
789 nicon = nColorBlack;
\r
790 else if( color == ENGINE_COLOR_WHITE )
\r
791 nicon = nColorWhite;
\r
793 nicon = nColorUnknown;
\r
795 SetIcon( which, nColorIcon, nicon );
\r
798 #define MAX_NAME_LENGTH 32
\r
800 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
801 static void UpdateControls( EngineOutputData * ed )
\r
803 int isPondering = FALSE;
\r
805 char s_label[MAX_NAME_LENGTH + 32];
\r
807 char * name = ed->name;
\r
810 if( name == 0 || *name == '\0' ) {
\r
814 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
815 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
817 #ifdef SHOW_PONDERING
\r
818 if( IsEnginePondering( ed->which ) ) {
\r
823 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
824 strncpy( buf, ed->hint, sizeof(buf) );
\r
825 buf[sizeof(buf)-1] = '\0';
\r
827 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
828 char * sep = strchr( ed->pv, ' ' );
\r
829 int buflen = sizeof(buf);
\r
831 if( sep != NULL ) {
\r
832 buflen = sep - ed->pv + 1;
\r
833 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
836 strncpy( buf, ed->pv, buflen );
\r
837 buf[ buflen-1 ] = '\0';
\r
840 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
842 else if( gameMode == TwoMachinesPlay ) {
\r
843 SetEngineState( ed->which, STATE_THINKING, "" );
\r
845 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
846 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
\r
848 int time_secs = ed->time / 100;
\r
849 int time_mins = time_secs / 60;
\r
853 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
856 strncpy( mov, ed->hint, sizeof(mov) );
\r
857 mov[ sizeof(mov)-1 ] = '\0';
\r
859 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
862 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
865 SetEngineState( ed->which, STATE_IDLE, "" );
\r
869 DoSetWindowText( ed->which, nLabel, s_label );
\r
873 if( ed->time > 0 && ed->nodes > 0 ) {
\r
874 unsigned long nps_100 = ed->nodes / ed->time;
\r
876 if( nps_100 < 100000 ) {
\r
877 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
\r
880 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
\r
884 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
887 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
893 int time_secs = ed->time / 100;
\r
894 int time_cent = ed->time % 100;
\r
897 if( ed->nodes < 1000000 ) {
\r
898 sprintf( s_nodes, u64Display, ed->nodes );
\r
901 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
\r
905 if( ed->score > 0 ) {
\r
906 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
908 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
911 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
913 /* Put all together... */
\r
914 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
917 buflen = strlen(buf);
\r
919 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
921 buf[ sizeof(buf) - 3 ] = '\0';
\r
923 strcat( buf + buflen, "\n" );
\r
926 InsertIntoMemo( ed->which, buf );
\r
930 SetEngineColorIcon( ed->which );
\r
934 int EngineOutputIsUp()
\r
936 return engineOutputDialogUp;
\r
940 EngineOutputProc(w, event, prms, nprms)
\r
946 if (engineOutputDialogUp) {
\r
947 EngineOutputPopDown();
\r
949 EngineOutputPopUp(_("engine output"),_("This feature is experimental"));
\r
951 // ToNrEvent(currentMove);
\r
954 // [HGM] kibitz: write kibitz line; split window for it if necessary
\r
955 void OutputKibitz(char *text)
\r
957 if(!EngineOutputIsUp()) return;
\r
958 if(!opponentKibitzes) DoClearMemo(1);
\r
959 opponentKibitzes = TRUE; // thas causes split window DisplayMode in ICS modes.
\r
960 VerifyDisplayMode();
\r
961 DoSetWindowText(1, nLabel, gameMode == IcsPlayingWhite ? gameInfo.black : gameInfo.white); // opponent name
\r
962 SetIcon( 1, nColorIcon, gameMode == IcsPlayingWhite ? nColorBlack : nColorWhite);
\r
963 InsertIntoMemo(1, text);
\r