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>
32 #else /* not STDC_HEADERS */
33 extern char *getenv();
36 # else /* not HAVE_STRING_H */
38 # endif /* not HAVE_STRING_H */
39 #endif /* not STDC_HEADERS */
45 #include <X11/Intrinsic.h>
46 #include <X11/StringDefs.h>
47 #include <X11/Shell.h>
48 #include <X11/Xaw/Dialog.h>
49 #include <X11/Xaw/Form.h>
50 #include <X11/Xaw/List.h>
51 #include <X11/Xaw/Label.h>
52 #include <X11/Xaw/SimpleMenu.h>
53 #include <X11/Xaw/SmeBSB.h>
54 #include <X11/Xaw/SmeLine.h>
55 #include <X11/Xaw/Box.h>
56 #include <X11/Xaw/Paned.h>
57 #include <X11/Xaw/MenuButton.h>
58 #include <X11/cursorfont.h>
59 #include <X11/Xaw/Text.h>
60 #include <X11/Xaw/AsciiText.h>
61 #include <X11/Xaw/Viewport.h>
67 // Add xengineo.h later
69 #include <X11/xpm.h>
\r
71 // [HGM] pixmaps of some ICONS used in the engine-outut window
72 #include "pixmaps/WHITE_14.xpm"
73 #include "pixmaps/BLACK_14.xpm"
74 #include "pixmaps/CLEAR_14.xpm"
75 #include "pixmaps/UNKNOWN_14.xpm"
76 #include "pixmaps/THINKING_14.xpm"
77 #include "pixmaps/PONDER_14.xpm"
78 #include "pixmaps/ANALYZING_14.xpm"
86 // imports from xboard.c
87 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
88 extern Display *xDisplay;
89 extern Window xBoardWindow;
90 extern int squareSize;
91 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
92 extern char *layoutName;
94 // temporary kludge to avoid compile errors untill all Windows code has been replaced
98 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
\r
99 #define nColorBlack 1
\r
100 #define nColorWhite 2
\r
101 #define nColorUnknown 3
\r
103 #define nPondering 5
\r
104 #define nThinking 6
\r
105 #define nAnalyzing 7
\r
107 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
\r
109 // [HGM] same for output fields (note that there are two of each type, one per color)
\r
110 #define nColorIcon 1
\r
111 #define nStateIcon 2
\r
113 #define nStateData 4
\r
114 #define nLabelNPS 5
\r
117 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
\r
119 void EngineOutputPopDown();
\r
120 void engineOutputPopUp(char *title, char *text);
\r
121 int EngineOutputIsUp();
\r
122 static void SetEngineColorIcon( int which );
\r
124 #define SHOW_PONDERING
\r
126 /* Imports from backend.c */
\r
127 char * SavePart(char *str);
128 extern int opponentKibitzes;
\r
130 /* Imports from winboard.c */
\r
131 //extern HWND engineOutputDialog;
\r
132 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
\r
134 //extern WindowPlacement wpEngineOutput;
\r
136 Position engineOutputX = -1, engineOutputY = -1;
137 Dimension engineOutputW, engineOutputH;
138 Widget engineOutputShell;
139 int engineOutputDialogUp;
141 /* Module variables */
\r
144 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
\r
145 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
\r
147 #define ICON_SIZE 14
\r
149 #define STATE_UNKNOWN -1
\r
150 #define STATE_THINKING 0
\r
151 #define STATE_IDLE 1
\r
152 #define STATE_PONDERING 2
\r
153 #define STATE_ANALYZING 3
\r
155 static int windowMode = 1;
\r
157 static int needInit = TRUE;
\r
159 static int lastDepth[2] = { -1, -1 };
\r
160 static int lastForwardMostMove[2] = { -1, -1 };
\r
161 static int engineState[2] = { -1, -1 };
\r
167 unsigned long nodes;
\r
174 } EngineOutputData;
\r
176 static int VerifyDisplayMode();
\r
177 static void UpdateControls( EngineOutputData * ed );
\r
178 static SetEngineState( int which, int state, char * state_data );
\r
180 void ReadIcon(char *pixData[], int iconNr)
184 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
\r
187 NULL, NULL /*&attr*/)) != 0) {
\r
188 fprintf(stderr, "Error %d loading icon image\n", r);
\r
193 static void InitializeEngineOutput()
\r
196 ReadIcon(WHITE_14, nColorWhite);
\r
197 ReadIcon(BLACK_14, nColorBlack);
\r
198 ReadIcon(UNKNOWN_14, nColorUnknown);
\r
200 ReadIcon(CLEAR_14, nClear);
\r
201 ReadIcon(PONDER_14, nPondering);
\r
202 ReadIcon(THINK_14, nThinking);
\r
203 ReadIcon(ANALYZE_14, nAnalyzing);
\r
204 // icons[nClear] = wIconPixmap;
\r
205 // icons[nPondering] = bIconPixmap;
\r// icons[nThinking] = wIconPixmap;
\r
206 // icons[nAnalyzing] = bIconPixmap;
\r}
209 // Windows routines commented out
212 static HICON LoadIconEx( int id )
\r
214 return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );
\r
217 // [HGM] the platform-dependent way of indicating where output should go is now all
\r
218 // concentrated here, where a table of platform-dependent handles are initialized.
\r
219 // This cleanses most other routines of front-end stuff, so they can go into the back end.
\r
220 static void InitializeEngineOutput()
\r
222 // if( needInit ) { // needInit was already tested before call
\r
223 // [HGM] made this into a table, rather than separate global variables
\r
224 icons[nColorBlack] = LoadIconEx( IDI_BLACK_14 );
\r
225 icons[nColorWhite] = LoadIconEx( IDI_WHITE_14 );
\r
226 icons[nColorUnknown] = LoadIconEx( IDI_UNKNOWN_14 );
\r
227 icons[nClear] = LoadIconEx( IDI_TRANS_14 );
\r
228 icons[nPondering] = LoadIconEx( IDI_PONDER_14 );
\r
229 icons[nThinking] = LoadIconEx( IDI_CLOCK_14 );
\r
230 icons[nAnalyzing] = LoadIconEx( IDI_ANALYZE2_14 );
\r
232 // [HGM] also make a table of handles to output controls
\r
233 // Note that engineOutputDialog must be defined first!
\r
234 outputField[0][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color1 );
\r
235 outputField[0][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );
\r
236 outputField[0][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );
\r
237 outputField[0][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData1 );
\r
238 outputField[0][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );
\r
239 outputField[0][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );
\r
241 outputField[1][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color2 );
\r
242 outputField[1][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );
\r
243 outputField[1][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );
\r
244 outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 );
\r
245 outputField[1][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );
\r
246 outputField[1][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );
\r
247 // needInit = FALSE;
\r
252 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )
\r
254 HWND hControl = GetDlgItem( hDlg, id );
\r
256 SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );
\r
259 #define HIDDEN_X 20000
\r
260 #define HIDDEN_Y 20000
\r
263 static void HideControl( HWND hDlg, int id )
\r
265 HWND hControl = GetDlgItem( hDlg, id );
\r
268 GetWindowRect( hControl, &rc );
\r
271 Avoid hiding an already hidden control, because that causes many
\r
272 unnecessary WM_ERASEBKGND messages!
\r
274 if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {
\r
275 SetControlPos( hDlg, id, 20000, 20000, 100, 100 );
\r
279 // front end, although we might make GetWindowRect front end instead
\r
280 static int GetControlWidth( HWND hDlg, int id )
\r
284 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
286 return rc.right - rc.left;
\r
290 static int GetControlHeight( HWND hDlg, int id )
\r
294 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
296 return rc.bottom - rc.top;
\r
299 static int GetHeaderHeight()
\r
301 int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );
\r
303 if( result < ICON_SIZE ) result = ICON_SIZE;
\r
308 // The size calculations should be backend? If setControlPos is a platform-dependent way of doing things,
\r
309 // a platform-independent wrapper for it should be supplied.
\r
310 static void PositionControlSet( HWND hDlg, int x, int y, int clientWidth, int memoHeight, int idColor, int idEngineLabel, int idNPS, int idMemo, int idStateIcon, int idStateData )
\r
312 int label_x = x + ICON_SIZE + H_MARGIN;
\r
313 int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
314 int label_y = y + ICON_SIZE - label_h;
\r
315 int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
316 int nps_x = clientWidth - H_MARGIN - nps_w;
\r
317 int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );
\r
318 int state_data_x = nps_x - H_MARGIN - state_data_w;
\r
319 int state_icon_x = state_data_x - ICON_SIZE - 2;
\r
320 int max_w = clientWidth - 2*H_MARGIN;
\r
321 int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;
\r
323 SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );
\r
324 SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );
\r
325 SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );
\r
326 SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );
\r
327 SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );
\r
328 SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );
\r
331 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine
\r
332 static void ResizeWindowControls( HWND hDlg, int mode )
\r
335 int headerHeight = GetHeaderHeight();
\r
336 int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
337 int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;
\r
338 int labelDeltaY = ICON_SIZE - labelHeight;
\r
341 int maxControlWidth;
\r
344 /* Initialize variables */
\r
345 GetClientRect( hDlg, &rc );
\r
347 clientWidth = rc.right - rc.left;
\r
348 clientHeight = rc.bottom - rc.top;
\r
350 maxControlWidth = clientWidth - 2*H_MARGIN;
\r
352 npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
354 /* Resize controls */
\r
357 PositionControlSet( hDlg, H_MARGIN, V_MARGIN,
\r
359 clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,
\r
360 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
362 /* Hide controls for the second engine */
\r
363 HideControl( hDlg, IDC_Color2 );
\r
364 HideControl( hDlg, IDC_EngineLabel2 );
\r
365 HideControl( hDlg, IDC_StateIcon2 );
\r
366 HideControl( hDlg, IDC_StateData2 );
\r
367 HideControl( hDlg, IDC_Engine2_NPS );
\r
368 HideControl( hDlg, IDC_EngineMemo2 );
\r
369 SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );
\r
370 /* TODO: we should also hide/disable them!!! what about tab stops?!?! */
\r
374 int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;
\r
375 int header1_y = V_MARGIN;
\r
376 int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;
\r
378 PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,
\r
379 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
381 PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,
\r
382 IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );
\r
385 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );
\r
386 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );
\r
389 // front end. Actual printing of PV lines into the output field
\r
390 static void InsertIntoMemo( int which, char * text )
\r
392 SendMessage( outputField[which][nMemo], EM_SETSEL, 0, 0 );
\r
394 SendMessage( outputField[which][nMemo], EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );
\r
397 // front end. Associates an icon with an output field ("control" in Windows jargon).
\r
398 // [HGM] let it find out the output field from the 'which' number by itself
\r
399 static void SetIcon( int which, int field, int nIcon )
\r
403 SendMessage( outputField[which][field], STM_SETICON, (WPARAM) icons[nIcon], 0 );
\r
407 // front end wrapper for SetWindowText, taking control number in stead of handle
\r
408 void DoSetWindowText(int which, int field, char *s_label)
\r
410 SetWindowText( outputField[which][field], s_label );
\r
414 void DoSetWindowText(int which, int field, char *s_label)
\r
418 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
\r
419 XtSetValues(outputField[which][field], &arg, 1);
\r
422 static void InsertIntoMemo( int which, char * text )
\r
424 Arg arg; XawTextBlock t; Widget edit;
426 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
\r
427 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
\r
428 XawTextReplace(edit, 0, 0, &t);
429 // XtSetArg(arg, XtNstring, (XtArgVal) text);
\r
430 // XtSetValues(outputField[which][nMemo], &arg, 1);
\r
433 static void SetIcon( int which, int field, int nIcon )
438 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
\r
439 XtSetValues(outputField[which][field], &arg, 1);
\r
443 void DoClearMemo(int which)
\r{
\r Arg args[16];
\r
447 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
\r
448 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
\r
449 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
\r
452 // The following routines are mutated clones of the commentPopUp routines
\r
454 void PositionControlSet(which, form, bw_width)
\r
457 Dimension bw_width;
\r{
\r
459 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
\r
462 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
463 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
464 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
465 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
466 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r XtSetArg(args[j], XtNright, XtChainLeft); j++;
\r XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
467 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
\r
468 outputField[which][nColorIcon] = ColorWidget =
469 XtCreateManagedWidget("Color", labelWidgetClass,
\r
473 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
474 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
475 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
\r
476 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
477 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
478 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
479 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
\r
480 outputField[which][nLabel] = NameWidget =
481 XtCreateManagedWidget("Engine", labelWidgetClass,
\r
485 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
486 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
487 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
\r
488 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
489 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
490 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
491 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
\r
492 outputField[which][nStateIcon] = ModeWidget =
493 XtCreateManagedWidget("Mode", labelWidgetClass,
\r
497 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
498 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
499 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
\r
500 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
\r
501 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
502 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
503 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
504 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
\r
505 outputField[which][nStateData] = MoveWidget =
506 XtCreateManagedWidget("Move", labelWidgetClass,
\r
510 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
511 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
\r
512 XtSetArg(args[j], XtNlabel, (XtArgVal) "NPS"); j++;
\r
513 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
\r
514 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
515 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
\r
516 XtSetArg(args[j], XtNleft, XtChainRight); j++;
\r XtSetArg(args[j], XtNright, XtChainRight); j++;
\r XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
\r
517 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
\r
518 outputField[which][nLabelNPS] = NodesWidget =
519 XtCreateManagedWidget("Nodes", labelWidgetClass,
\r
522 // create "text" within "form"
525 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
\r
526 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
\r
528 XtSetArg(args[j], XtNstring, ""); j++;
\r
529 XtSetArg(args[j], XtNdisplayCaret, False); j++;
\r
530 XtSetArg(args[j], XtNtop, XtChainTop); j++;
\r
531 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
\r
532 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
\r
533 XtSetArg(args[j], XtNright, XtChainRight); j++;
\r
534 XtSetArg(args[j], XtNresizable, True); j++;
\r
535 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
\r
537 XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded); j++;
\r
539 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
\r
540 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
\r
541 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
\r#endif
\r
542 // XtSetArg(args[j], XtNautoFill, True); j++;
\r
543 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
\r
544 outputField[which][nMemo] = edit =
\r
545 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
\r
548 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
\r
549 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
\r
550 XtSetValues(edit, args, j);
\r
553 Widget EngineOutputCreate(name, text)
\r
557 Widget shell, layout, form, form2, edit;
558 Dimension bw_width, bw_height;
\r
563 XtSetArg(args[j], XtNwidth, &bw_width); j++;
\r XtSetArg(args[j], XtNheight, &bw_height); j++;
\r XtGetValues(boardWidget, args, j);
\r
565 // define form within layout within shell.
567 XtSetArg(args[j], XtNresizable, True); j++;
\r
569 XtCreatePopupShell(name, transientShellWidgetClass,
\r
570 shellWidget, args, j);
\r
572 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
\r
573 layoutArgs, XtNumber(layoutArgs));
\r
574 // divide window vertically into two equal parts, by creating two forms
576 XtCreateManagedWidget("form", formWidgetClass, layout,
\r
577 formArgs, XtNumber(formArgs));
\r
579 XtCreateManagedWidget("form2", formWidgetClass, layout,
\r
580 formArgs, XtNumber(formArgs));
\r
581 j = 0;
\r XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
\r XtSetValues(form2, args, j);
\r
582 // make sure width is known in advance, for better placement of child widgets
583 j = 0;
\r XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
\r XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
\r XtSetValues(shell, args, j);
\r
585 // fill up both forms with control elements
586 PositionControlSet(0, form, bw_width);
587 PositionControlSet(1, form2, bw_width);
589 XtRealizeWidget(shell);
\r
591 if (engineOutputX == -1) {
\r
594 Dimension pw_height;
\r
595 Dimension ew_height;
\r
598 XtSetArg(args[j], XtNheight, &ew_height); j++;
\r
599 XtGetValues(edit, args, j);
\r
602 XtSetArg(args[j], XtNheight, &pw_height); j++;
\r
603 XtGetValues(shell, args, j);
\r
604 engineOutputH = pw_height + (lines - 1) * ew_height;
\r
605 engineOutputW = bw_width - 16;
607 engineOutputH = bw_height/2;
\r engineOutputW = bw_width-16;
\r#endif
609 XSync(xDisplay, False);
\r
611 /* This code seems to tickle an X bug if it is executed too soon
\r
612 after xboard starts up. The coordinates get transformed as if
\r
613 the main window was positioned at (0, 0).
\r
615 XtTranslateCoords(shellWidget,
\r
616 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
\r
617 &engineOutputX, &engineOutputY);
\r
619 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
\r
620 RootWindowOfScreen(XtScreen(shellWidget)),
\r
621 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
\r
623 engineOutputX = xx;
\r
624 engineOutputY = yy;
\r
626 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
\r
629 XtSetArg(args[j], XtNheight, engineOutputH); j++;
\r XtSetArg(args[j], XtNwidth, engineOutputW); j++;
\r
630 XtSetArg(args[j], XtNx, engineOutputX); j++;
\r
631 XtSetArg(args[j], XtNy, engineOutputY); j++;
\r
632 XtSetValues(shell, args, j);
\r
633 // XtSetKeyboardFocus(shell, edit);
\r
638 void ResizeWindowControls(shell, mode)
645 Dimension ew_height, tmp;
647 form1 = XtNameToWidget(shell, "*form");
\r
648 form2 = XtNameToWidget(shell, "*form2");
651 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
\r XtGetValues(form1, args, j);
653 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
\r XtGetValues(form2, args, j);
654 ew_height += tmp; // total height
658 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
\r
659 XtSetValues(form2, args, j);
661 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
\r
662 XtSetValues(form1, args, j);
665 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
\r
666 XtSetValues(form1, args, j);
668 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
\r
669 XtSetValues(form2, args, j);
674 void EngineOutputCallback(w, client_data, call_data)
\r
676 XtPointer client_data, call_data;
\r
683 XtSetArg(args[j], XtNlabel, &name); j++;
\r
684 XtGetValues(w, args, j);
\r
686 if (strcmp(name, "close") == 0) {
\r
687 EngineOutputPopDown();
\r
688 } else if (strcmp(name, "edit") == 0) {
\r
689 EngineOutputPopDown();
\r
690 EditCommentEvent();
\r
696 // This seems pure front end
\r
697 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
\r
699 static SnapData sd;
\r
702 case WM_INITDIALOG:
\r
703 if( engineOutputDialog == NULL ) {
\r
704 engineOutputDialog = hDlg;
\r
706 RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */
\r
708 ResizeWindowControls( hDlg, windowMode );
\r
710 SetEngineState( 0, STATE_IDLE, "" );
\r
711 SetEngineState( 1, STATE_IDLE, "" );
\r
717 switch (LOWORD(wParam)) {
\r
719 EndDialog(hDlg, TRUE);
\r
723 EndDialog(hDlg, FALSE);
\r
732 case WM_GETMINMAXINFO:
\r
734 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
\r
736 mmi->ptMinTrackSize.x = 100;
\r
737 mmi->ptMinTrackSize.y = 160;
\r
742 EngineOutputPopDown();
\r
746 ResizeWindowControls( hDlg, windowMode );
\r
749 case WM_ENTERSIZEMOVE:
\r
750 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
753 return OnSizing( &sd, hDlg, wParam, lParam );
\r
756 return OnMoving( &sd, hDlg, wParam, lParam );
\r
758 case WM_EXITSIZEMOVE:
\r
759 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
766 void EngineOutputPopUp(title, text)
\r
767 char *title, *text;
\r
773 if (engineOutputShell == NULL) {
\r
774 engineOutputShell =
\r
775 EngineOutputCreate(title, text);
\r
776 XtRealizeWidget(engineOutputShell);
\r
777 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
\r
779 InitializeEngineOutput();
\r
780 needInit = FALSE;
\r }
\r
781 SetEngineColorIcon( 0 );
\r
782 SetEngineColorIcon( 1 );
\r
783 SetEngineState( 0, STATE_IDLE, "" );
\r
784 SetEngineState( 1, STATE_IDLE, "" );
\r
786 edit = XtNameToWidget(engineOutputShell, "*form.text");
\r
788 XtSetArg(args[j], XtNstring, text); j++;
\r
789 XtSetValues(edit, args, j);
\r
791 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
\r
792 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
\r
793 XtSetValues(engineOutputShell, args, j);
\r
796 XtPopup(engineOutputShell, XtGrabNone);
\r
797 XSync(xDisplay, False);
\r
800 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
801 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
804 engineOutputDialogUp = True;
\r
805 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
810 void EngineOutputPopUp()
\r
814 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);
\r
816 if( engineOutputDialog ) {
\r
817 SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );
\r
819 if( ! engineOutputDialogUp ) {
\r
820 ShowWindow(engineOutputDialog, SW_SHOW);
\r
824 lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );
\r
826 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
\r
827 CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );
\r
829 FreeProcInstance(lpProc);
\r
832 // [HGM] displaced to after creation of dialog, to allow initialization of output fields
\r
834 InitializeEngineOutput();
\r
838 engineOutputDialogUp = TRUE;
\r
842 void EngineOutputPopDown()
\r
847 if (!engineOutputDialogUp) return;
\r
850 XtSetArg(args[j], XtNx, &engineOutputX); j++;
\r
851 XtSetArg(args[j], XtNy, &engineOutputY); j++;
\r
852 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
\r
853 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
\r
854 XtGetValues(engineOutputShell, args, j);
\r
855 XtPopdown(engineOutputShell);
\r
856 XSync(xDisplay, False);
858 XtSetArg(args[j], XtNleftBitmap, None); j++;
859 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
862 engineOutputDialogUp = False;
\r
863 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
868 void EngineOutputPopDown()
\r
870 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);
\r
872 if( engineOutputDialog ) {
\r
873 ShowWindow(engineOutputDialog, SW_HIDE);
\r
876 engineOutputDialogUp = FALSE;
\r
879 // front end. [HGM] Takes handle of output control from table, so only number is passed
\r
880 void DoClearMemo(int which)
\r
882 SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" );
\r
886 //------------------------ pure back-end routines -------------------------------
\r
889 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
\r
890 static SetEngineState( int which, int state, char * state_data )
\r
892 int x_which = 1 - which;
\r
894 if( engineState[ which ] != state ) {
\r
895 engineState[ which ] = state;
\r
898 case STATE_THINKING:
\r
899 SetIcon( which, nStateIcon, nThinking );
\r
900 if( engineState[ x_which ] == STATE_THINKING ) {
\r
901 SetEngineState( x_which, STATE_IDLE, "" );
\r
904 case STATE_PONDERING:
\r
905 SetIcon( which, nStateIcon, nPondering );
\r
907 case STATE_ANALYZING:
\r
908 SetIcon( which, nStateIcon, nAnalyzing );
\r
911 SetIcon( which, nStateIcon, nClear );
\r
916 if( state_data != 0 ) {
\r
917 DoSetWindowText( which, nStateData, state_data );
\r
921 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
\r
922 void EngineOutputUpdate( FrontEndProgramStats * stats )
\r
924 EngineOutputData ed;
\r
925 int clearMemo = FALSE;
\r
930 SetEngineState( 0, STATE_IDLE, "" );
\r
931 SetEngineState( 1, STATE_IDLE, "" );
\r
935 if(gameMode == IcsObserving) return; // [HGM] kibitz: shut up engine if we are observing an ICS game
937 which = stats->which;
\r
938 depth = stats->depth;
\r
940 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
\r
944 if( engineOutputShell == NULL ) {
\r
948 VerifyDisplayMode();
\r
952 ed.nodes = stats->nodes;
\r
953 ed.score = stats->score;
\r
954 ed.time = stats->time;
\r
956 ed.hint = stats->hint;
\r
957 ed.an_move_index = stats->an_move_index;
\r
958 ed.an_move_count = stats->an_move_count;
\r
960 /* Get target control. [HGM] this is moved to front end, which get them from a table */
\r
962 ed.name = first.tidy;
\r
965 ed.name = second.tidy;
\r
968 /* Clear memo if needed */
\r
969 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
\r
973 if( lastForwardMostMove[which] != forwardMostMove ) {
\r
977 if( clearMemo ) DoClearMemo(which);
\r
980 lastDepth[which] = depth;
\r
981 lastForwardMostMove[which] = forwardMostMove;
\r
983 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
\r
984 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
\r
989 UpdateControls( &ed );
\r
992 #define ENGINE_COLOR_WHITE 'w'
\r
993 #define ENGINE_COLOR_BLACK 'b'
\r
994 #define ENGINE_COLOR_UNKNOWN ' '
\r
997 char GetEngineColor( int which )
\r
999 char result = ENGINE_COLOR_UNKNOWN;
\r
1001 if( which == 0 || which == 1 ) {
\r
1002 ChessProgramState * cps;
\r
1004 switch (gameMode) {
\r
1005 case MachinePlaysBlack:
\r
1006 case IcsPlayingBlack:
\r
1007 result = ENGINE_COLOR_BLACK;
\r
1009 case MachinePlaysWhite:
\r
1010 case IcsPlayingWhite:
\r
1011 result = ENGINE_COLOR_WHITE;
\r
1015 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
1017 case TwoMachinesPlay:
\r
1018 cps = (which == 0) ? &first : &second;
\r
1019 result = cps->twoMachinesColor[0];
\r
1020 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
1029 char GetActiveEngineColor()
\r
1031 char result = ENGINE_COLOR_UNKNOWN;
\r
1033 if( gameMode == TwoMachinesPlay ) {
\r
1034 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
\r
1041 static int IsEnginePondering( int which )
\r
1043 int result = FALSE;
\r
1045 switch (gameMode) {
\r
1046 case MachinePlaysBlack:
\r
1047 case IcsPlayingBlack:
\r
1048 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
1050 case MachinePlaysWhite:
\r
1051 case IcsPlayingWhite:
\r
1052 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
\r
1054 case TwoMachinesPlay:
\r
1055 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
\r
1056 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
\r
1065 static void SetDisplayMode( int mode )
\r
1067 if( windowMode != mode ) {
\r
1068 windowMode = mode;
\r
1070 ResizeWindowControls( engineOutputShell, mode );
\r
1075 int VerifyDisplayMode()
\r
1079 /* Get proper mode for current game */
\r
1080 switch( gameMode ) {
\r
1083 case MachinePlaysWhite:
\r
1084 case MachinePlaysBlack:
\r
1087 case IcsPlayingWhite:
\r
1088 case IcsPlayingBlack:
\r
1089 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
\r
1091 case TwoMachinesPlay:
\r
1095 /* Do not change */
\r
1099 SetDisplayMode( mode );
\r
1102 // back end. Determine what icon to se in the color-icon field, and print it
\r
1103 static void SetEngineColorIcon( int which )
\r
1105 char color = GetEngineColor(which);
\r
1108 if( color == ENGINE_COLOR_BLACK )
\r
1109 nicon = nColorBlack;
\r
1110 else if( color == ENGINE_COLOR_WHITE )
\r
1111 nicon = nColorWhite;
\r
1113 nicon = nColorUnknown;
\r
1115 SetIcon( which, nColorIcon, nicon );
\r
1118 #define MAX_NAME_LENGTH 32
\r
1120 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
\r
1121 static void UpdateControls( EngineOutputData * ed )
\r
1123 int isPondering = FALSE;
\r
1125 char s_label[MAX_NAME_LENGTH + 32];
\r
1127 char * name = ed->name;
\r
1130 if( name == 0 || *name == '\0' ) {
\r
1134 strncpy( s_label, name, MAX_NAME_LENGTH );
\r
1135 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
\r
1137 #ifdef SHOW_PONDERING
\r
1138 if( IsEnginePondering( ed->which ) ) {
\r
1143 if( ed->hint != 0 && *ed->hint != '\0' ) {
\r
1144 strncpy( buf, ed->hint, sizeof(buf) );
\r
1145 buf[sizeof(buf)-1] = '\0';
\r
1147 else if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
1148 char * sep = strchr( ed->pv, ' ' );
\r
1149 int buflen = sizeof(buf);
\r
1151 if( sep != NULL ) {
\r
1152 buflen = sep - ed->pv + 1;
\r
1153 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
\r
1156 strncpy( buf, ed->pv, buflen );
\r
1157 buf[ buflen-1 ] = '\0';
\r
1160 SetEngineState( ed->which, STATE_PONDERING, buf );
\r
1162 else if( gameMode == TwoMachinesPlay ) {
\r
1163 SetEngineState( ed->which, STATE_THINKING, "" );
\r
1165 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile ) {
\r
1167 int time_secs = ed->time / 100;
\r
1168 int time_mins = time_secs / 60;
\r
1172 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
\r
1175 strncpy( mov, ed->hint, sizeof(mov) );
\r
1176 mov[ sizeof(mov)-1 ] = '\0';
\r
1178 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
1181 SetEngineState( ed->which, STATE_ANALYZING, buf );
\r
1184 SetEngineState( ed->which, STATE_IDLE, "" );
\r
1188 DoSetWindowText( ed->which, nLabel, s_label );
\r
1190 s_label[0] = '\0';
\r
1192 if( ed->time > 0 && ed->nodes > 0 ) {
\r
1193 unsigned long nps_100 = ed->nodes / ed->time;
\r
1195 if( nps_100 < 100000 ) {
\r
1196 sprintf( s_label, "NPS: %lu", nps_100 * 100 );
\r
1199 sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );
\r
1203 DoSetWindowText( ed->which, nLabelNPS, s_label );
\r
1206 if( ed->pv != 0 && *ed->pv != '\0' ) {
\r
1212 int time_secs = ed->time / 100;
\r
1213 int time_cent = ed->time % 100;
\r
1216 if( ed->nodes < 1000000 ) {
\r
1217 sprintf( s_nodes, "%lu", ed->nodes );
\r
1220 sprintf( s_nodes, "%.1fM", ed->nodes / 1000000.0 );
\r
1224 if( ed->score > 0 ) {
\r
1225 sprintf( s_score, "+%.2f", ed->score / 100.0 );
\r
1227 sprintf( s_score, "%.2f", ed->score / 100.0 );
\r
1230 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
\r
1232 /* Put all together... */
\r
1233 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
\r
1236 buflen = strlen(buf);
\r
1238 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
\r
1240 buf[ sizeof(buf) - 3 ] = '\0';
\r
1242 strcat( buf + buflen, "\n" );
\r
1245 InsertIntoMemo( ed->which, buf );
\r
1249 SetEngineColorIcon( ed->which );
\r
1253 int EngineOutputIsUp()
\r
1255 return engineOutputDialogUp;
\r
1259 EngineOutputProc(w, event, prms, nprms)
1265 if (engineOutputDialogUp) {
1266 EngineOutputPopDown();
1268 EngineOutputPopUp("engine output","This feature is experimental");
1270 // ToNrEvent(currentMove);
1273 // [HGM] kibitz: write kibitz line; split window for it if necessary
1274 void OutputKibitz(int window, char *text)
1276 if(!EngineOutputIsUp()) return;
1277 if(!opponentKibitzes) { // on first kibitz of game, clear memos
1279 if(gameMode == IcsObserving) DoClearMemo(0);
1281 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
1282 VerifyDisplayMode();
1283 if(gameMode == IcsObserving) {
1284 DoSetWindowText(0, nLabel, gameInfo.white);
1285 SetIcon( 0, nColorIcon, nColorWhite);
1286 SetIcon( 0, nStateIcon, nClear);
1288 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
1289 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
1290 SetIcon( 1, nStateIcon, nClear);
1291 InsertIntoMemo(window-1, text);