Display PV from Engine-Output window (XBoard)
[xboard.git] / xengineoutput.c
index 7162631..2d2a9a7 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright 2005 Alessandro Scotti
  *
- * Enhancements Copyright 2009 Free Software Foundation, Inc.
+ * Enhancements Copyright 2009, 2010 Free Software Foundation, Inc.
  *
  * ------------------------------------------------------------------------
  *
@@ -65,6 +65,8 @@ extern char *getenv();
 #include <X11/Xaw/Text.h>
 #include <X11/Xaw/AsciiText.h>
 #include <X11/Xaw/Viewport.h>
+#include <X11/Xatom.h>
+#include <X11/Xmu/Atoms.h>
 
 #include "common.h"
 #include "frontend.h"
@@ -115,7 +117,6 @@ int  EngineOutputIsUp();
 void SetEngineColorIcon( int which );
 
 /* Imports from backend.c */
-char * SavePart(char *str);
 extern int opponentKibitzes;
 
 /* Imports from xboard.c */
@@ -130,6 +131,7 @@ static int engineOutputDialogUp;
 
 /* Module variables */
 int  windowMode = 1;
+static int currentPV, highTextStart[2], highTextEnd[2];
 
 typedef struct {
     char * name;
@@ -184,11 +186,18 @@ void InsertIntoMemo( int which, char * text, int where )
 {
        Arg arg; XawTextBlock t; Widget edit;
 
+       /* the backend adds \r\n, which is needed for winboard, 
+        * for xboard we delete them again over here */
+       if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
+
        t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
        edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
        XawTextReplace(edit, where, where, &t);
-//     XtSetArg(arg, XtNstring, (XtArgVal) text);
-//     XtSetValues(outputField[which][nMemo], &arg, 1);
+       if(where < highTextStart[which]) { // [HGM] multiPVdisplay: move highlighting
+           int len = strlen(text);
+           highTextStart[which] += len; highTextEnd[which] += len;
+           XawTextSetSelection( outputField[which][nMemo], highTextStart[which], highTextEnd[which] );
+       }
 }
 
 void SetIcon( int which, int field, int nIcon )
@@ -212,11 +221,88 @@ void DoClearMemo(int which)
        XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
 }
 
+// cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
+
+extern char *selected_fen_position;
+
+Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
+                Atom *type_return, XtPointer *value_return,
+                unsigned long *length_return, int *format_return); // from xboard.c
+void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b); // from xoptions.c
+
+char memoTranslations[] =
+":Ctrl<Key>c: CopyMemoProc() \n \
+<Btn3Motion>: HandlePV() \n \
+<Btn3Down>: select-start() SelectPV() \n \
+<Btn3Up>: extend-end() StopPV() \n";
+
+void
+SelectPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
+{      // [HGM] pv: translate click to PV line, and load it for display
+       String val;
+       int start, end, memo, j;
+       XawTextPosition index, dummy;
+       int x, y;
+       Arg arg;
+
+       x = event->xmotion.x; y = event->xmotion.y;
+       currentPV = (w == outputField[1][nMemo]);
+       XawTextGetSelectionPos(w, &index, &dummy);
+       XtSetArg(arg, XtNstring, &val);
+       XtGetValues(w, &arg, 1);
+       if(LoadMultiPV(x, y, val, index, &start, &end)) {
+           XawTextSetSelection( outputField[currentPV][nMemo], start, end );
+           highTextStart[currentPV] = start; highTextEnd[currentPV] = end;
+       }
+}
+
+void
+StopPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
+{      // [HGM] pv: on right-button release, stop displaying PV
+        XawTextUnsetSelection( w );
+        highTextStart[currentPV] = highTextEnd[currentPV] = 0;
+        UnLoadPV();
+}
+
+static void
+MemoCB(Widget w, XtPointer client_data, Atom *selection,
+          Atom *type, XtPointer value, unsigned long *len, int *format)
+{
+  if (value==NULL || *len==0) return; /* nothing had been selected to copy */
+  selected_fen_position = value;
+  selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
+    XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
+                  CurrentTime,
+                  SendPositionSelection,
+                  NULL/* lose_ownership_proc */ ,
+                  NULL/* transfer_done_proc */);
+}
+
+void CopyMemoProc(w, event, prms, nprms)
+  Widget w;
+  XEvent *event;
+  String *prms;
+  Cardinal *nprms;
+{
+    if(appData.pasteSelection) return;
+    if (selected_fen_position) free(selected_fen_position);
+    XtGetSelectionValue(menuBarWidget, 
+      XA_PRIMARY, XA_STRING,
+      /* (XtSelectionCallbackProc) */ MemoCB,
+      NULL, /* client_data passed to PastePositionCB */
+
+      /* better to use the time field from the event that triggered the
+       * call to this function, but that isn't trivial to get
+       */
+      CurrentTime
+    );
+}
+
 // The following routines are mutated clones of the commentPopUp routines
 
-void PositionControlSet(which, form, bw_width)
+void PositionControlSet(which, shell, form, bw_width)
      int which;
-     Widget form;
+     Widget shell, form;
      Dimension bw_width;
 {
     Arg args[16];
@@ -311,6 +397,9 @@ void PositionControlSet(which, form, bw_width)
     outputField[which][nMemo] = edit =
       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
 
+    XtOverrideTranslations(edit, XtParseTranslationTable(memoTranslations));
+    XtAddEventHandler(edit, ButtonPressMask, False, SetFocus, (XtPointer) shell);
+
     j = 0;
     XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
 //    XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
@@ -361,11 +450,18 @@ Widget EngineOutputCreate(name, text)
     XtSetValues(shell, args, j);
 
     // fill up both forms with control elements
-    PositionControlSet(0, form,  bw_width);
-    PositionControlSet(1, form2, bw_width);
+    PositionControlSet(0, shell, form,  bw_width);
+    PositionControlSet(1, shell, form2, bw_width);
 
     XtRealizeWidget(shell);
 
+    if(wpEngineOutput.width > 0) {
+      engineOutputW = wpEngineOutput.width;
+      engineOutputH = wpEngineOutput.height;
+      engineOutputX = wpEngineOutput.x;
+      engineOutputY = wpEngineOutput.y;
+    }
+
     if (engineOutputX == -1) {
        int xx, yy;
        Window junk;
@@ -499,6 +595,10 @@ void EngineOutputPopDown()
     XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
     XtSetArg(args[j], XtNheight, &engineOutputH); j++;
     XtGetValues(engineOutputShell, args, j);
+    wpEngineOutput.x = engineOutputX - 4;
+    wpEngineOutput.y = engineOutputY - 23;
+    wpEngineOutput.width = engineOutputW;
+    wpEngineOutput.height = engineOutputH;
     XtPopdown(engineOutputShell);
     XSync(xDisplay, False);
     j=0;