Fix multi-leg promotions
[xboard.git] / xaw / xengineoutput.c
1 /*
2  * Engine output (PV)
3  *
4  * Author: Alessandro Scotti (Dec 2005)
5  *
6  * Copyright 2005 Alessandro Scotti
7  *
8  * Enhancements Copyright 2009, 2010, 2011, 2012, 2013,
9  * 2014, 2015, 2016 Free Software Foundation, Inc.
10  *
11  * ------------------------------------------------------------------------
12  *
13  * GNU XBoard is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or (at
16  * your option) any later version.
17  *
18  * GNU XBoard is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see http://www.gnu.org/licenses/.
25  *
26  * ------------------------------------------------------------------------
27  ** See the file ChangeLog for a revision history.  */
28
29 #include "config.h"
30
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <sys/types.h>
35
36 #if STDC_HEADERS
37 # include <stdlib.h>
38 # include <string.h>
39 #else /* not STDC_HEADERS */
40 extern char *getenv();
41 # if HAVE_STRING_H
42 #  include <string.h>
43 # else /* not HAVE_STRING_H */
44 #  include <strings.h>
45 # endif /* not HAVE_STRING_H */
46 #endif /* not STDC_HEADERS */
47
48 #if HAVE_UNISTD_H
49 # include <unistd.h>
50 #endif
51
52 #include <X11/Intrinsic.h>
53 #include <X11/StringDefs.h>
54 #include <X11/Shell.h>
55 #include <X11/Xaw/Dialog.h>
56 #include <X11/Xaw/Form.h>
57 #include <X11/Xaw/List.h>
58 #include <X11/Xaw/Label.h>
59 #include <X11/Xaw/SimpleMenu.h>
60 #include <X11/Xaw/SmeBSB.h>
61 #include <X11/Xaw/SmeLine.h>
62 #include <X11/Xaw/Box.h>
63 #include <X11/Xaw/Paned.h>
64 #include <X11/Xaw/MenuButton.h>
65 #include <X11/cursorfont.h>
66 #include <X11/Xaw/Text.h>
67 #include <X11/Xaw/AsciiText.h>
68 #include <X11/Xaw/Viewport.h>
69 #include <X11/Xatom.h>
70 #include <X11/Xmu/Atoms.h>
71
72 #include "common.h"
73 #include "frontend.h"
74 #include "backend.h"
75 #include "dialogs.h"
76 #include "xboard.h"
77 #include "engineoutput.h"
78 #include "gettext.h"
79
80 #ifdef ENABLE_NLS
81 # define  _(s) gettext (s)
82 # define N_(s) gettext_noop (s)
83 #else
84 # define  _(s) (s)
85 # define N_(s)  s
86 #endif
87
88 // [HGM] bitmaps of some ICONS used in the engine-outut window
89
90 static unsigned char CLEAR_14[28];
91
92 static unsigned char WHITE_14[] = {
93 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0x02, 0x10, 0x02, 0x10, 0x01, 0x20, 0x01, 0x20,
94 0x01, 0x20, 0x01, 0x20, 0x02, 0x10, 0x02, 0x10, 0x04, 0x08, 0x18, 0x06, 0xe0, 0x01
95 };
96
97 static unsigned char BLACK_14[] = {
98 0xe0, 0x01, 0xf8, 0x07, 0xfc, 0x0f, 0xfe, 0x1f, 0xfe, 0x1f, 0xff, 0x3f, 0xff, 0x3f,
99 0xff, 0x3f, 0xff, 0x3f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xe0, 0x01
100 };
101
102 static unsigned char ANALYZE_14[] = {
103 0x80, 0x03, 0x60, 0x0c, 0x10, 0x10, 0x90, 0x10, 0xc8, 0x20, 0x08, 0x20, 0x08, 0x20,
104 0x10, 0x10, 0x10, 0x10, 0x68, 0x0c, 0x94, 0x03, 0x0a, 0x00, 0x07, 0x00, 0x00, 0x00
105 };
106
107 static unsigned char THINK_14[] = {
108 0xe0, 0x00, 0x18, 0x03, 0x44, 0x04, 0x42, 0x08, 0x42, 0x08, 0x41, 0x10, 0xe1, 0x13,
109 0x41, 0x10, 0x02, 0x08, 0x02, 0x08, 0x04, 0x04, 0x18, 0x03, 0xe0, 0x00, 0x00, 0x00
110 };
111
112 static unsigned char PONDER_14[] = {
113 0x30, 0x03, 0x8c, 0x0c, 0x02, 0x10, 0x01, 0x08, 0x01, 0x10, 0x06, 0x20, 0x04, 0x20,
114 0x02, 0x10, 0x04, 0x0c, 0xc8, 0x04, 0x34, 0x03, 0x0e, 0x00, 0x01, 0x00, 0x00, 0x00
115 };
116
117 static unsigned char UNKNOWN_14[] = {
118 0xe0, 0x01, 0x58, 0x07, 0xac, 0x0a, 0x56, 0x15, 0xaa, 0x1a, 0x55, 0x35, 0xab, 0x2a,
119 0x55, 0x35, 0xab, 0x2a, 0x56, 0x15, 0xaa, 0x1a, 0x54, 0x0d, 0xb8, 0x06, 0xe0, 0x01
120 };
121
122
123
124 /* Module variables */
125 static int currentPV;
126 static Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
127 static Widget memoWidget;
128
129
130 static void
131 ReadIcon (unsigned char pixData[], int iconNr, Widget w)
132 {
133     icons[iconNr] = XCreateBitmapFromData(xDisplay, XtWindow(w), (char*) pixData, 14, 14);
134 }
135
136 void
137 InitEngineOutput (Option *opt, Option *memo2)
138 {       // front-end, because it must have access to the pixmaps
139         Widget w = opt->handle;
140         memoWidget = memo2->handle;
141
142         ReadIcon(WHITE_14,   nColorWhite, w);
143         ReadIcon(BLACK_14,   nColorBlack, w);
144         ReadIcon(UNKNOWN_14, nColorUnknown, w);
145
146         ReadIcon(CLEAR_14,   nClear, w);
147         ReadIcon(PONDER_14,  nPondering, w);
148         ReadIcon(THINK_14,   nThinking, w);
149         ReadIcon(ANALYZE_14, nAnalyzing, w);
150 }
151
152 void
153 DrawWidgetIcon (Option *opt, int nIcon)
154 {   // as we are already in X front-end, so do X-stuff here
155     Arg arg;
156     XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
157     XtSetValues(opt->handle, &arg, 1);
158 }
159
160 void
161 InsertIntoMemo (int which, char * text, int where)
162 {
163         XawTextBlock t;
164         Widget edit;
165
166         /* the backend adds \r\n, which is needed for winboard,
167          * for xboard we delete them again over here */
168         if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
169
170         t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
171         edit = XtNameToWidget(shells[EngOutDlg], which ? "*paneB.text" : "*paneA.text");
172         XawTextReplace(edit, where, where, &t);
173         if(where < highTextStart[which]) { // [HGM] multiPVdisplay: move highlighting
174             int len = strlen(text);
175             highTextStart[which] += len; highTextEnd[which] += len;
176             XawTextSetSelection( edit, highTextStart[which], highTextEnd[which] );
177         }
178 }
179
180 //--------------------------------- PV walking ---------------------------------------
181
182 char memoTranslations[] =
183 ":Ctrl<Key>c: CopyMemoProc() \n \
184 <Btn3Motion>: HandlePV() \n \
185 Shift<Btn3Down>: select-start() extend-end(PRIMARY) SelectPV(1) \n \
186 Any<Btn3Down>: select-start() extend-end(PRIMARY) SelectPV(0) \n \
187 <Btn3Up>: StopPV() \n";
188
189 void
190 SelectPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
191 {       // [HGM] pv: translate click to PV line, and load it for display
192         String val;
193         int start, end;
194         XawTextPosition index, dummy;
195         int x, y;
196         Arg arg;
197
198         x = event->xmotion.x; y = event->xmotion.y;
199         currentPV = (w != memoWidget);
200         XawTextGetSelectionPos(w, &index, &dummy);
201         XtSetArg(arg, XtNstring, &val);
202         XtGetValues(w, &arg, 1);
203         shiftKey = strcmp(params[0], "0");
204         if(LoadMultiPV(x, y, val, index, &start, &end, currentPV)) {
205             XawTextSetSelection( w, start, end );
206             highTextStart[currentPV] = start; highTextEnd[currentPV] = end;
207         }
208 }
209
210 void
211 StopPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
212 {       // [HGM] pv: on right-button release, stop displaying PV
213         XawTextUnsetSelection( w );
214         highTextStart[currentPV] = highTextEnd[currentPV] = 0;
215         UnLoadPV();
216         XtCallActionProc(w, "beginning-of-file", event, NULL, 0);
217 }
218
219 //------------------------- Ctrl-C copying of memo texts ---------------------------
220
221 // Awfull code: first read our own primary selection into selected_fen_position,
222 //              and then transfer ownership of this to the clipboard, so that the
223 //              copy-position callback can fetch it there when somebody pastes it
224 // Worst of all is that I only added it because I did not know how to copy primary:
225 // my laptop has no middle button. Ctrl-C might not be needed at all... [HGM]
226
227 // cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
228
229 Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
230                  Atom *type_return, XtPointer *value_return,
231                  unsigned long *length_return, int *format_return); // from xboard.c
232
233 static void
234 MemoCB (Widget w, XtPointer client_data, Atom *selection,
235         Atom *type, XtPointer value, unsigned long *len, int *format)
236 {
237   if (value==NULL || *len==0) return; /* nothing had been selected to copy */
238   selected_fen_position = value;
239   selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
240     XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
241                    CurrentTime,
242                    SendPositionSelection,
243                    NULL/* lose_ownership_proc */ ,
244                    NULL/* transfer_done_proc */);
245 }
246
247 void
248 CopyMemoProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
249 {
250     if(appData.pasteSelection) return;
251     if (selected_fen_position) free(selected_fen_position);
252     XtGetSelectionValue(menuBarWidget,
253       XA_PRIMARY, XA_STRING,
254       /* (XtSelectionCallbackProc) */ MemoCB,
255       NULL, /* client_data passed to PastePositionCB */
256
257       /* better to use the time field from the event that triggered the
258        * call to this function, but that isn't trivial to get
259        */
260       CurrentTime
261     );
262 }
263
264 //------------------------------- pane switching -----------------------------------
265
266 void
267 ResizeWindowControls (int mode)
268 {   // another hideous kludge: to have only a single pane, we resize the
269     // second to 5 pixels (which makes it too small to display anything)
270     Widget form1, form2;
271     Arg args[16];
272     int j;
273     Dimension ew_height, tmp;
274     Widget shell = shells[EngOutDlg];
275
276     form1 = XtNameToWidget(shell, "*paneA");
277     form2 = XtNameToWidget(shell, "*paneB");
278
279     j = 0;
280     XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
281     XtGetValues(form1, args, j);
282     j = 0;
283     XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
284     XtGetValues(form2, args, j);
285     ew_height += tmp; // total height
286
287     if(mode==0) {
288         j = 0;
289         XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
290         XtSetValues(form2, args, j);
291         j = 0;
292         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
293         XtSetValues(form1, args, j);
294     } else {
295         j = 0;
296         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
297         XtSetValues(form1, args, j);
298         j = 0;
299         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
300         XtSetValues(form2, args, j);
301     }
302 }