From cbb23e5f23cee542f8099c7f80fd07df8d9f0a08 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Tue, 16 Oct 2012 19:44:40 +0200 Subject: [PATCH] Make generic memo-event handler, and connect history callback 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 | 1 + nengineoutput.c | 24 ++++++++++++++++++++++-- nhistory.c | 10 +++++++++- xboard.c | 8 -------- xengineoutput.c | 33 ++++++++++++++++----------------- xhistory.c | 11 ----------- xoptions.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 101 insertions(+), 40 deletions(-) diff --git a/dialogs.h b/dialogs.h index 5b21b9f..3032dcc 100644 --- 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); diff --git a/nengineoutput.c b/nengineoutput.c index f494a7e..c925792 100644 --- a/nengineoutput.c +++ b/nengineoutput.c @@ -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 , "" } }; diff --git a/nhistory.c b/nhistory.c index 2cddab6..cefb706 100644 --- a/nhistory.c +++ b/nhistory.c @@ -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 , "" } }; diff --git a/xboard.c b/xboard.c index 3157544..032214d 100644 --- 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 diff --git a/xengineoutput.c b/xengineoutput.c index f83dcf0..bdf4928 100644 --- a/xengineoutput.c +++ b/xengineoutput.c @@ -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: select-start() extend-end() SelectPV(1) \n \ Any: select-start() extend-end() SelectPV(0) \n \ : 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 ----------------------------------- diff --git a/xhistory.c b/xhistory.c index 4d0afe8..0ac764f 100644 --- a/xhistory.c +++ b/xhistory.c @@ -85,14 +85,3 @@ char historyTranslations[] = ": select-start() \n \ : 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 - diff --git a/xoptions.c b/xoptions.c index 2743f97..f209698 100644 --- a/xoptions.c +++ b/xoptions.c @@ -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; } -- 1.7.0.4