Make generic memo-event handler, and connect history callback
authorH.G. Muller <h.g.muller@hccnet.nl>
Tue, 16 Oct 2012 17:44:40 +0000 (19:44 +0200)
committerH.G. Muller <h.g.muller@hccnet.nl>
Tue, 6 Nov 2012 13:13:54 +0000 (14:13 +0100)
Large text widgets can now define a user handler in their Option.choice
field. If they do, agneric callback is added tothem, which catches mouse
events. Button release and pointer motion pass their coordinate and type
to the specified user routine. Button presses in addition retrieve
the text from the widget, set the cursor in it to the clicked point,
and convert it to a character position, also passed to the user.
  The user is responsible for ignoring events he is not interested in.

dialogs.h
nengineoutput.c
nhistory.c
xboard.c
xengineoutput.c
xhistory.c
xoptions.c

index 5b21b9f..3032dcc 100644 (file)
--- a/dialogs.h
+++ b/dialogs.h
@@ -110,6 +110,7 @@ BrowserDlg,
 NrOfDialogs     // dummy for total
 } DialogClass;
 
+typedef int MemoCallback (Option *opt, int n, int x, int y, char *text, int index);
 typedef Option *PointerCallback(int n, int x, int y);
 typedef void ListBoxCallback(int n, int selected);
 typedef void ButtonCallback(int n);
index f494a7e..c925792 100644 (file)
@@ -70,20 +70,40 @@ int  windowMode = 1;
 
 char *mem1, *mem2; // dummies, as this dialog can never be OK'ed
 
+void
+MemoProc (Option *opt, int n, int x, int y)
+{
+    static int pressed; // keep track of button 3 state
+    switch(n) {
+      case 0: // pointer motion
+       if(!pressed) return;
+//     MovePV(x, y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
+       break;
+      case 3: // press button 3
+       pressed = 1;
+       SelectPV(opt, x, y);
+       break;
+      case -3: // release button 3
+       pressed = 0;
+       StopPV(opt);
+       break;
+    }
+}
+
 Option engoutOptions[] = {
 {  0,  LL|T2T,           17, NULL, NULL, NULL, NULL, Label, " " },
 {  0, L2L|T2T|SAME_ROW, 163, NULL, NULL, NULL, NULL, Label, N_("engine name") },
 {  0,     T2T|SAME_ROW,  30, NULL, NULL, NULL, NULL, Label, " " },
 {  0, R2R|T2T|SAME_ROW, 188, NULL, NULL, NULL, NULL, Label, N_("move") },
 {  0,  RR|T2T|SAME_ROW,  80, NULL, NULL, NULL, NULL, Label, N_("NPS") },
-{200, T_VSCRL | T_TOP,  500, NULL, (void*) &mem1, "", NULL, TextBox, "" },
+{200, T_VSCRL | T_TOP,  500, NULL, (void*) &mem1, "", (char**) MemoProc, TextBox, "" },
 {  0,         0,         0, NULL, NULL, "", NULL, Break , "" },
 {  0,  LL|T2T,           17, NULL, NULL, NULL, NULL, Label, " " },
 {  0, L2L|T2T|SAME_ROW, 163, NULL, NULL, NULL, NULL, Label, N_("engine name") },
 {  0,     T2T|SAME_ROW,  30, NULL, NULL, NULL, NULL, Label, " " },
 {  0, R2R|T2T|SAME_ROW, 188, NULL, NULL, NULL, NULL, Label, N_("move") },
 {  0,  RR|T2T|SAME_ROW,  80, NULL, NULL, NULL, NULL, Label, N_("NPS") },
-{200, T_VSCRL | T_TOP,  500, NULL, (void*) &mem2, "", NULL, TextBox, "" },
+{200, T_VSCRL | T_TOP,  500, NULL, (void*) &mem2, "", (char**) MemoProc, TextBox, "" },
 {   0,      NO_OK,       0, NULL, NULL, "", NULL, EndMark , "" }
 };
 
index 2cddab6..cefb706 100644 (file)
@@ -64,8 +64,16 @@ AppendToHistoryMemo (char * text, int bold, int colorNr)
 
 char *historyText;
 
+int
+SelectMove (Option *opt, int n, int x, int y, char *text, int index)
+{
+       if(n != 3 && n != 1) return FALSE; // only on button-1 and 3 press
+       FindMoveByCharIndex( index ); // [HGM] also does the actual moving to it, now
+       return (n == 3);  // suppress context menu for button 3, but allow selection with button 1
+}
+
 Option historyOptions[] = {
-{ 200, T_VSCRL | T_FILL | T_WRAP | T_TOP, 400, NULL, (void*) &historyText, "", NULL, TextBox, "" },
+{ 200, T_VSCRL | T_FILL | T_WRAP | T_TOP, 400, NULL, (void*) &historyText, NULL, (char**) &SelectMove, TextBox, "" },
 {   0,           NO_OK,             0, NULL, (void*) NULL, "", NULL, EndMark , "" }
 };
 
index 3157544..032214d 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -1851,14 +1851,6 @@ DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
 #endif
 
 
-#ifdef TODO_GTK
-void
-HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
-{   // [HGM] pv: walk PV
-    MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
-}
-#endif
-
 static int savedIndex;  /* gross that this is global */
 
 #ifdef TODO_GTK
index f83dcf0..bdf4928 100644 (file)
@@ -83,6 +83,7 @@ static int currentPV, highTextStart[2], highTextEnd[2];
 static Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
 static Widget memoWidget;
 #endif
+static void *memoWidget;
 
 #ifdef TODO_GTK
 static void
@@ -162,39 +163,37 @@ Shift<Btn3Down>: select-start() extend-end() SelectPV(1) \n \
 Any<Btn3Down>: select-start() extend-end() SelectPV(0) \n \
 <Btn3Up>: StopPV() \n";
 
-#ifdef TODO_GTK
 void
-SelectPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
+SelectPV (Option *opt, int x, int y)
 {      // [HGM] pv: translate click to PV line, and load it for display
-       String val;
-       int start, end;
-       XawTextPosition index, dummy;
-       int x, y;
-       Arg arg;
-
-       x = event->xmotion.x; y = event->xmotion.y;
-       currentPV = (w != memoWidget);
+       int start, end, index;
+       char *val;
+       int currentPV = (opt->handle != memoWidget);
+#ifdef TODO_GTK
        XawTextGetSelectionPos(w, &index, &dummy);
        XtSetArg(arg, XtNstring, &val);
        XtGetValues(w, &arg, 1);
-       shiftKey = strcmp(params[0], "0");
+#endif
        if(LoadMultiPV(x, y, val, index, &start, &end, currentPV)) {
+#ifdef TODO_GTK
            XawTextSetSelection( w, start, end );
+#endif
            highTextStart[currentPV] = start; highTextEnd[currentPV] = end;
        }
 }
-#endif
 
-#ifdef TODO_GTK
 void
-StopPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
+StopPV (Option *opt)
 {      // [HGM] pv: on right-button release, stop displaying PV
-        XawTextUnsetSelection( w );
+#ifdef TODO_GTK
+        XawTextUnsetSelection( opt->handle );
+#endif
         highTextStart[currentPV] = highTextEnd[currentPV] = 0;
         UnLoadPV();
-        XtCallActionProc(w, "beginning-of-file", event, NULL, 0);
-}
+#ifdef TODO_GTK
+        XtCallActionProc(opt->handle, "beginning-of-file", event, NULL, 0);
 #endif
+}
 
 //------------------------------- pane switching -----------------------------------
 
index 4d0afe8..0ac764f 100644 (file)
@@ -85,14 +85,3 @@ char historyTranslations[] =
 "<Btn3Down>: select-start() \n \
 <Btn3Up>: extend-end() SelectMove() \n";
 
-#ifdef TODO_GTK
-void
-SelectMove (Widget w, XEvent * event, String * params, Cardinal * nParams)
-{
-       XawTextPosition index, dummy;
-
-       XawTextGetSelectionPos(w, &index, &dummy);
-       FindMoveByCharIndex( index ); // [HGM] also does the actual moving to it, now
-}
-#endif
-
index 2743f97..f209698 100644 (file)
@@ -546,6 +546,53 @@ ICSKeyEvent(GtkWidget *widget, GdkEventKey *event)
     }
 }
 
+static gboolean
+MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata)
+{   // handle mouse clicks on text widgets that need it
+    int w, h;
+    int button=10, f=1;
+    Option *opt, *memo = (Option *) gdata;
+    MemoCallback *userHandler = (MemoCallback *) memo->choice;
+    GdkEventButton *bevent = (GdkEventButton *) event;
+    GdkEventMotion *mevent = (GdkEventMotion *) event;
+    GtkTextIter start, end;
+    String val = NULL;
+    gboolean res;
+    gint index, x, y;
+
+    switch(event->type) { // figure out what's up
+       case GDK_MOTION_NOTIFY:
+           f = 0;
+           w = mevent->x; h = mevent->y;
+           break;
+       case GDK_BUTTON_RELEASE:
+           f = -1; // release indicated by negative button numbers
+           w = bevent->x; h = bevent->y;
+           break;
+       case GDK_BUTTON_PRESS:
+           w = bevent->x; h = bevent->y;
+           button = bevent->button;
+// GTK_TODO: is this really the most efficient way to get the character at the mouse cursor???
+           gtk_text_view_window_to_buffer_coords(widget, GTK_TEXT_WINDOW_WIDGET, w, h, &x, &y);
+           gtk_text_view_get_iter_at_location(widget, &start, x, y);
+           gtk_text_buffer_place_cursor(memo->handle, &start);
+           /* get cursor position into index */
+           g_object_get(memo->handle, "cursor-position", &index, NULL);
+           /* get text from textbuffer */
+           gtk_text_buffer_get_start_iter (memo->handle, &start);
+           gtk_text_buffer_get_end_iter (memo->handle, &end);
+           val = gtk_text_buffer_get_text (memo->handle, &start, &end, FALSE); 
+           break;
+       default:
+           return FALSE; // should not happen
+    }
+    button *= f;
+    // hand click parameters as well as text & location to user
+    res = (userHandler) (memo, button, w, h, val, index);
+    if(val) g_free(val);
+    return res;
+}
+
 void
 AddHandler (Option *opt, int nr)
 {
@@ -553,7 +600,7 @@ AddHandler (Option *opt, int nr)
       case 0: 
       case 1: 
       case 2: break;
-      case 3: g_signal_connect(opt->handle, "key-press-event", G_CALLBACK (ICSKeyEvent), NULL); break;
+      case 3: g_signal_connect(opt->handle, "key-press-event", G_CALLBACK (ICSKeyEvent), NULL); break; // Input Box
       case 4: 
       case 5: 
       case 6: break;
@@ -1184,6 +1231,11 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent
                 else
                     gtk_text_buffer_set_text (textbuffer, "", -1); 
                 option[i].handle = (void*)textbuffer;
+               if(option[i].choice) { // textviews can request a handler for mouse events in the choice field
+                   g_signal_connect(textview, "button-press-event", G_CALLBACK (MemoEvent), (gpointer) &option[i] );
+                   g_signal_connect(textview, "button-release-event", G_CALLBACK (MemoEvent), (gpointer) &option[i] );
+                   g_signal_connect(textview, "motion-notify-event", G_CALLBACK (MemoEvent), (gpointer) &option[i] );
+               }
                 break; 
             }