4 * Author: Alessandro Scotti (Dec 2005)
6 * Copyright 2005 Alessandro Scotti
8 * Enhancements Copyright 2009 Free Software Foundation, Inc.
10 * ------------------------------------------------------------------------
12 * GNU XBoard is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or (at
15 * your option) any later version.
17 * GNU XBoard is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see http://www.gnu.org/licenses/.
25 * ------------------------------------------------------------------------
26 ** See the file ChangeLog for a revision history. */
33 #include <sys/types.h>
38 #else /* not STDC_HEADERS */
39 extern char *getenv();
42 # else /* not HAVE_STRING_H */
44 # endif /* not HAVE_STRING_H */
45 #endif /* not STDC_HEADERS */
51 #include <X11/Intrinsic.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Shell.h>
54 #include <X11/Xaw/Dialog.h>
55 #include <X11/Xaw/Form.h>
56 #include <X11/Xaw/List.h>
57 #include <X11/Xaw/Label.h>
58 #include <X11/Xaw/SimpleMenu.h>
59 #include <X11/Xaw/SmeBSB.h>
60 #include <X11/Xaw/SmeLine.h>
61 #include <X11/Xaw/Box.h>
62 #include <X11/Xaw/Paned.h>
63 #include <X11/Xaw/MenuButton.h>
64 #include <X11/cursorfont.h>
65 #include <X11/Xaw/Text.h>
66 #include <X11/Xaw/AsciiText.h>
67 #include <X11/Xaw/Viewport.h>
73 // Add xengineo.h later
77 # define _(s) gettext (s)
78 # define N_(s) gettext_noop (s)
86 // [HGM] pixmaps of some ICONS used in the engine-outut window
87 #include "pixmaps/WHITE_14.xpm"
88 #include "pixmaps/BLACK_14.xpm"
89 #include "pixmaps/CLEAR_14.xpm"
90 #include "pixmaps/UNKNOWN_14.xpm"
91 #include "pixmaps/THINKING_14.xpm"
92 #include "pixmaps/PONDER_14.xpm"
93 #include "pixmaps/ANALYZING_14.xpm"
101 // imports from xboard.c
102 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
103 extern Display *xDisplay;
104 extern Window xBoardWindow;
105 extern int squareSize;
106 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
107 extern char *layoutName;
109 // temporary kludge to avoid compile errors untill all Windows code has been replaced
113 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
114 #define nColorBlack 1
115 #define nColorWhite 2
116 #define nColorUnknown 3
122 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
124 // [HGM] same for output fields (note that there are two of each type, one per color)
132 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
134 void EngineOutputPopDown();
135 void engineOutputPopUp();
136 int EngineOutputIsUp();
137 static void SetEngineColorIcon( int which );
139 #define SHOW_PONDERING
141 /* Imports from backend.c */
142 char * SavePart(char *str);
143 extern int opponentKibitzes;
145 /* Imports from winboard.c */
146 //extern HWND engineOutputDialog;
147 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
149 //extern WindowPlacement wpEngineOutput;
151 Position engineOutputX = -1, engineOutputY = -1;
152 Dimension engineOutputW, engineOutputH;
153 Widget engineOutputShell;
154 int engineOutputDialogUp;
156 /* Module variables */
159 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
160 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
164 #define STATE_UNKNOWN -1
165 #define STATE_THINKING 0
167 #define STATE_PONDERING 2
168 #define STATE_ANALYZING 3
170 static int windowMode = 1;
172 static int needInit = TRUE;
174 static int lastDepth[2] = { -1, -1 };
175 static int lastForwardMostMove[2] = { -1, -1 };
176 static int engineState[2] = { -1, -1 };
191 static void VerifyDisplayMode();
192 static void UpdateControls( EngineOutputData * ed );
193 static void SetEngineState( int which, int state, char * state_data );
195 void ReadIcon(char *pixData[], int iconNr)
199 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
202 NULL, NULL /*&attr*/)) != 0) {
203 fprintf(stderr, _("Error %d loading icon image\n"), r);
208 static void InitializeEngineOutput()
211 ReadIcon(WHITE_14, nColorWhite);
212 ReadIcon(BLACK_14, nColorBlack);
213 ReadIcon(UNKNOWN_14, nColorUnknown);
215 ReadIcon(CLEAR_14, nClear);
216 ReadIcon(PONDER_14, nPondering);
217 ReadIcon(THINK_14, nThinking);
218 ReadIcon(ANALYZE_14, nAnalyzing);
221 void DoSetWindowText(int which, int field, char *s_label)
225 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
226 XtSetValues(outputField[which][field], &arg, 1);
229 static void InsertIntoMemo( int which, char * text, int where )
231 Arg arg; XawTextBlock t; Widget edit;
233 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
234 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
235 XawTextReplace(edit, where, where, &t);
236 // XtSetArg(arg, XtNstring, (XtArgVal) text);
237 // XtSetValues(outputField[which][nMemo], &arg, 1);
240 static void SetIcon( int which, int field, int nIcon )
245 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
246 XtSetValues(outputField[which][field], &arg, 1);
250 void DoClearMemo(int which)
256 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
257 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
258 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
261 // The following routines are mutated clones of the commentPopUp routines
263 void PositionControlSet(which, form, bw_width)
269 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
272 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
273 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
274 XtSetArg(args[j], XtNtop, XtChainTop); j++;
275 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
276 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
277 XtSetArg(args[j], XtNright, XtChainLeft); j++;
278 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
279 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
280 outputField[which][nColorIcon] = ColorWidget =
281 XtCreateManagedWidget("Color", labelWidgetClass,
285 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
286 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
287 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
288 XtSetArg(args[j], XtNtop, XtChainTop); j++;
289 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
290 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
291 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
292 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
293 outputField[which][nLabel] = NameWidget =
294 XtCreateManagedWidget("Engine", labelWidgetClass,
298 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
299 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
300 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
301 XtSetArg(args[j], XtNtop, XtChainTop); j++;
302 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
303 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
304 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
305 outputField[which][nStateIcon] = ModeWidget =
306 XtCreateManagedWidget("Mode", labelWidgetClass,
310 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
311 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
312 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
313 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
314 XtSetArg(args[j], XtNtop, XtChainTop); j++;
315 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
316 XtSetArg(args[j], XtNright, XtChainRight); j++;
317 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
318 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
319 outputField[which][nStateData] = MoveWidget =
320 XtCreateManagedWidget("Move", labelWidgetClass,
324 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
325 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
326 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
327 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
328 XtSetArg(args[j], XtNtop, XtChainTop); j++;
329 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
330 XtSetArg(args[j], XtNleft, XtChainRight); j++;
331 XtSetArg(args[j], XtNright, XtChainRight); j++;
332 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
333 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
334 outputField[which][nLabelNPS] = NodesWidget =
335 XtCreateManagedWidget("Nodes", labelWidgetClass,
338 // create "text" within "form"
341 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
342 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
344 XtSetArg(args[j], XtNstring, ""); j++;
345 XtSetArg(args[j], XtNdisplayCaret, False); j++;
346 XtSetArg(args[j], XtNtop, XtChainTop); j++;
347 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
348 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
349 XtSetArg(args[j], XtNright, XtChainRight); j++;
350 XtSetArg(args[j], XtNresizable, True); j++;
351 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
352 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
353 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
354 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
355 // XtSetArg(args[j], XtNautoFill, True); j++;
356 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
357 outputField[which][nMemo] = edit =
358 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
361 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
362 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
363 XtSetValues(edit, args, j);
366 Widget EngineOutputCreate(name, text)
370 Widget shell, layout, form, form2, edit;
371 Dimension bw_width, bw_height;
376 XtSetArg(args[j], XtNwidth, &bw_width); j++;
377 XtSetArg(args[j], XtNheight, &bw_height); j++;
378 XtGetValues(boardWidget, args, j);
380 // define form within layout within shell.
382 XtSetArg(args[j], XtNresizable, True); j++;
385 XtCreatePopupShell(name, topLevelShellWidgetClass,
387 XtCreatePopupShell(name, transientShellWidgetClass,
389 shellWidget, args, j);
391 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
392 layoutArgs, XtNumber(layoutArgs));
393 // divide window vertically into two equal parts, by creating two forms
395 XtCreateManagedWidget("form", formWidgetClass, layout,
396 formArgs, XtNumber(formArgs));
398 XtCreateManagedWidget("form2", formWidgetClass, layout,
399 formArgs, XtNumber(formArgs));
401 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
402 XtSetValues(form2, args, j);
403 // make sure width is known in advance, for better placement of child widgets
405 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
406 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
407 XtSetValues(shell, args, j);
409 // fill up both forms with control elements
410 PositionControlSet(0, form, bw_width);
411 PositionControlSet(1, form2, bw_width);
413 XtRealizeWidget(shell);
415 if (engineOutputX == -1) {
420 engineOutputH = bw_height/2;
421 engineOutputW = bw_width-16;
423 XSync(xDisplay, False);
425 /* This code seems to tickle an X bug if it is executed too soon
426 after xboard starts up. The coordinates get transformed as if
427 the main window was positioned at (0, 0).
429 XtTranslateCoords(shellWidget,
430 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
431 &engineOutputX, &engineOutputY);
433 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
434 RootWindowOfScreen(XtScreen(shellWidget)),
435 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
440 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
443 XtSetArg(args[j], XtNheight, engineOutputH); j++;
444 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
445 XtSetArg(args[j], XtNx, engineOutputX); j++;
446 XtSetArg(args[j], XtNy, engineOutputY); j++;
447 XtSetValues(shell, args, j);
448 // XtSetKeyboardFocus(shell, edit);
453 void ResizeWindowControls(shell, mode)
460 Dimension ew_height, tmp;
462 form1 = XtNameToWidget(shell, "*form");
463 form2 = XtNameToWidget(shell, "*form2");
466 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
467 XtGetValues(form1, args, j);
469 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
470 XtGetValues(form2, args, j);
471 ew_height += tmp; // total height
475 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
476 XtSetValues(form2, args, j);
478 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
479 XtSetValues(form1, args, j);
482 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
483 XtSetValues(form1, args, j);
485 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
486 XtSetValues(form2, args, j);
496 static char *title = _("Engine output"), *text = _("This feature is experimental");
498 if (engineOutputShell == NULL) {
500 EngineOutputCreate(title, text);
501 XtRealizeWidget(engineOutputShell);
502 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
504 InitializeEngineOutput();
507 SetEngineColorIcon( 0 );
508 SetEngineColorIcon( 1 );
509 SetEngineState( 0, STATE_IDLE, "" );
510 SetEngineState( 1, STATE_IDLE, "" );
512 edit = XtNameToWidget(engineOutputShell, "*form.text");
514 XtSetArg(args[j], XtNstring, text); j++;
515 XtSetValues(edit, args, j);
517 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
518 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
519 XtSetValues(engineOutputShell, args, j);
522 XtPopup(engineOutputShell, XtGrabNone);
523 XSync(xDisplay, False);
526 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
527 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
530 engineOutputDialogUp = True;
531 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
534 void EngineOutputPopDown()
539 if (!engineOutputDialogUp) return;
542 XtSetArg(args[j], XtNx, &engineOutputX); j++;
543 XtSetArg(args[j], XtNy, &engineOutputY); j++;
544 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
545 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
546 XtGetValues(engineOutputShell, args, j);
547 XtPopdown(engineOutputShell);
548 XSync(xDisplay, False);
550 XtSetArg(args[j], XtNleftBitmap, None); j++;
551 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
554 engineOutputDialogUp = False;
555 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
558 //------------------------ pure back-end routines -------------------------------
562 static int scores[MAX_VAR], textEnd[MAX_VAR], curDepth[2], nrVariations[2];
564 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
565 static void SetEngineState( int which, int state, char * state_data )
567 int x_which = 1 - which;
569 if( engineState[ which ] != state ) {
570 engineState[ which ] = state;
574 SetIcon( which, nStateIcon, nThinking );
575 if( engineState[ x_which ] == STATE_THINKING ) {
576 SetEngineState( x_which, STATE_IDLE, "" );
579 case STATE_PONDERING:
580 SetIcon( which, nStateIcon, nPondering );
582 case STATE_ANALYZING:
583 SetIcon( which, nStateIcon, nAnalyzing );
586 SetIcon( which, nStateIcon, nClear );
591 if( state_data != 0 ) {
592 DoSetWindowText( which, nStateData, state_data );
596 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
597 void EngineOutputUpdate( FrontEndProgramStats * stats )
600 int clearMemo = FALSE;
605 SetEngineState( 0, STATE_IDLE, "" );
606 SetEngineState( 1, STATE_IDLE, "" );
610 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
611 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
613 which = stats->which;
614 depth = stats->depth;
616 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
620 if( engineOutputShell == NULL ) {
628 ed.nodes = stats->nodes;
629 ed.score = stats->score;
630 ed.time = stats->time;
632 ed.hint = stats->hint;
633 ed.an_move_index = stats->an_move_index;
634 ed.an_move_count = stats->an_move_count;
636 /* Get target control. [HGM] this is moved to front end, which get them from a table */
638 ed.name = first.tidy;
641 ed.name = second.tidy;
644 /* Clear memo if needed */
645 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
649 if( lastForwardMostMove[which] != forwardMostMove ) {
653 if( clearMemo ) DoClearMemo(which);
656 lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge
657 lastForwardMostMove[which] = forwardMostMove;
659 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
660 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
665 UpdateControls( &ed );
668 #define ENGINE_COLOR_WHITE 'w'
669 #define ENGINE_COLOR_BLACK 'b'
670 #define ENGINE_COLOR_UNKNOWN ' '
673 char GetEngineColor( int which )
675 char result = ENGINE_COLOR_UNKNOWN;
677 if( which == 0 || which == 1 ) {
678 ChessProgramState * cps;
681 case MachinePlaysBlack:
682 case IcsPlayingBlack:
683 result = ENGINE_COLOR_BLACK;
685 case MachinePlaysWhite:
686 case IcsPlayingWhite:
687 result = ENGINE_COLOR_WHITE;
691 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
693 case TwoMachinesPlay:
694 cps = (which == 0) ? &first : &second;
695 result = cps->twoMachinesColor[0];
696 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
705 char GetActiveEngineColor()
707 char result = ENGINE_COLOR_UNKNOWN;
709 if( gameMode == TwoMachinesPlay ) {
710 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
717 static int IsEnginePondering( int which )
722 case MachinePlaysBlack:
723 case IcsPlayingBlack:
724 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
726 case MachinePlaysWhite:
727 case IcsPlayingWhite:
728 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
730 case TwoMachinesPlay:
731 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
732 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
741 static void SetDisplayMode( int mode )
743 if( windowMode != mode ) {
746 ResizeWindowControls( engineOutputShell, mode );
751 void VerifyDisplayMode()
755 /* Get proper mode for current game */
757 case IcsObserving: // [HGM] ICS analyze
758 if(!appData.icsEngineAnalyze) return;
761 case MachinePlaysWhite:
762 case MachinePlaysBlack:
765 case IcsPlayingWhite:
766 case IcsPlayingBlack:
767 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
769 case TwoMachinesPlay:
777 SetDisplayMode( mode );
780 // back end. Determine what icon to se in the color-icon field, and print it
781 static void SetEngineColorIcon( int which )
783 char color = GetEngineColor(which);
786 if( color == ENGINE_COLOR_BLACK )
788 else if( color == ENGINE_COLOR_WHITE )
791 nicon = nColorUnknown;
793 SetIcon( which, nColorIcon, nicon );
796 #define MAX_NAME_LENGTH 32
798 // [HGM] multivar: sort Thinking Output within one depth on score
800 static int InsertionPoint( int len, EngineOutputData * ed )
802 int i, offs = 0, newScore = ed->score, n = ed->which;
804 if(ed->nodes == 0 && ed->score == 0 && ed->time == 0)
805 newScore = 1e6; // info lines inserted on top
806 if(ed->depth != curDepth[n]) { // depth has changed
807 curDepth[n] = ed->depth;
808 nrVariations[n] = 0; // throw away everything we had
810 // loop through all lines. Note even / odd used for different panes
811 for(i=nrVariations[n]-2; i>=0; i-=2) {
812 // put new item behind those we haven't looked at
814 textEnd[i+n+2] = offs + len;
815 scores[i+n+2] = newScore;
816 if(newScore < scores[i+n]) break;
817 // if it had higher score as previous, move previous in stead
818 scores[i+n+2] = scores[i+n];
819 textEnd[i+n+2] = textEnd[i+n] + len;
823 textEnd[n] = offs + len;
824 scores[n] = newScore;
826 nrVariations[n] += 2;
830 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
831 static void UpdateControls( EngineOutputData * ed )
833 int isPondering = FALSE;
835 char s_label[MAX_NAME_LENGTH + 32];
837 char * name = ed->name;
840 if( name == 0 || *name == '\0' ) {
844 strncpy( s_label, name, MAX_NAME_LENGTH );
845 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
847 #ifdef SHOW_PONDERING
848 if( IsEnginePondering( ed->which ) ) {
853 if( ed->hint != 0 && *ed->hint != '\0' ) {
854 strncpy( buf, ed->hint, sizeof(buf) );
855 buf[sizeof(buf)-1] = '\0';
857 else if( ed->pv != 0 && *ed->pv != '\0' ) {
858 char * sep = strchr( ed->pv, ' ' );
859 int buflen = sizeof(buf);
862 buflen = sep - ed->pv + 1;
863 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
866 strncpy( buf, ed->pv, buflen );
867 buf[ buflen-1 ] = '\0';
870 SetEngineState( ed->which, STATE_PONDERING, buf );
872 else if( gameMode == TwoMachinesPlay ) {
873 SetEngineState( ed->which, STATE_THINKING, "" );
875 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
876 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
878 int time_secs = ed->time / 100;
879 int time_mins = time_secs / 60;
883 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
886 strncpy( mov, ed->hint, sizeof(mov) );
887 mov[ sizeof(mov)-1 ] = '\0';
889 sprintf( buf, "[%d] %d/%d: %s [%02d:%02d:%02d]", ed->depth, ed->an_move_index,
890 ed->an_move_count, mov, time_mins / 60, time_mins % 60, time_secs % 60 );
893 SetEngineState( ed->which, STATE_ANALYZING, buf );
896 SetEngineState( ed->which, STATE_IDLE, "" );
900 DoSetWindowText( ed->which, nLabel, s_label );
904 if( ed->time > 0 && ed->nodes > 0 ) {
905 unsigned long nps_100 = ed->nodes / ed->time;
907 if( nps_100 < 100000 ) {
908 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
911 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
915 DoSetWindowText( ed->which, nLabelNPS, s_label );
918 if( ed->pv != 0 && *ed->pv != '\0' ) {
924 int time_secs = ed->time / 100;
925 int time_cent = ed->time % 100;
928 if( ed->nodes < 1000000 ) {
929 sprintf( s_nodes, u64Display, ed->nodes );
932 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
936 if( ed->score > 0 ) {
937 sprintf( s_score, "+%.2f", ed->score / 100.0 );
939 sprintf( s_score, "%.2f", ed->score / 100.0 );
942 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
944 /* Put all together... */
945 if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else
946 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
949 buflen = strlen(buf);
951 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
953 buf[ sizeof(buf) - 3 ] = '\0';
955 strcat( buf + buflen, "\n" );
958 InsertIntoMemo( ed->which, buf, InsertionPoint(strlen(buf), ed) );
962 SetEngineColorIcon( ed->which );
966 int EngineOutputIsUp()
968 return engineOutputDialogUp;
972 EngineOutputProc(w, event, prms, nprms)
978 if (engineOutputDialogUp) {
979 EngineOutputPopDown();
983 // ToNrEvent(currentMove);
986 // [HGM] kibitz: write kibitz line; split window for it if necessary
987 void OutputKibitz(int window, char *text)
989 if(!EngineOutputIsUp()) return;
990 if(!opponentKibitzes) { // on first kibitz of game, clear memos
992 if(gameMode == IcsObserving) DoClearMemo(0);
994 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
996 if(gameMode == IcsObserving) {
997 DoSetWindowText(0, nLabel, gameInfo.white);
998 SetIcon( 0, nColorIcon, nColorWhite);
999 SetIcon( 0, nStateIcon, nClear);
1001 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
1002 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
1003 SetIcon( 1, nStateIcon, nClear);
1004 InsertIntoMemo(window-1, text, 0);