X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=xoptions.c;h=583ab9dcdd5e9c523813f48eede4319638251594;hb=6004960398b36a83d05c068ee633591b855b2c0b;hp=1c5987c0e4bf8052fc4a68e5d0c13ebd6b6aafe8;hpb=08d1f3b890ecc8b41beca2ce3afa8ba17c9dc401;p=xboard.git diff --git a/xoptions.c b/xoptions.c index 1c5987c..583ab9d 100644 --- a/xoptions.c +++ b/xoptions.c @@ -232,21 +232,13 @@ SetWidgetText (Option *opt, char *buf, int n) void GetWidgetState (Option *opt, int *state) { -#ifdef TODO_GTK - Arg arg; - XtSetArg(arg, XtNstate, state); - XtGetValues(opt->handle, &arg, 1); -#endif + *state = gtk_toggle_button_get_active(opt->handle); } void SetWidgetState (Option *opt, int state) { -#ifdef TODO_GTK - Arg arg; - XtSetArg(arg, XtNstate, state); - XtSetValues(opt->handle, &arg, 1); -#endif + gtk_toggle_button_set_active(opt->handle, state); } void @@ -295,43 +287,8 @@ LoadListBox (Option *opt, char *emptyText, int n1, int n2) } } -int -ReadScroll (Option *opt, float *top, float *bottom) -{ // retreives fractions of top and bottom of thumb -#ifdef TODO_GTK - Arg args[16]; - Widget w = XtParent(opt->handle); // viewport - Widget v = XtNameToWidget(w, "vertical"); - int j=0; - float h; - if(!v) return FALSE; // no scroll bar - XtSetArg(args[j], XtNshown, &h); j++; - XtSetArg(args[j], XtNtopOfThumb, top); j++; - XtGetValues(v, args, j); - *bottom = *top + h; -#endif - return TRUE; -} - -void -SetScroll (Option *opt, float f) -{ // sets top of thumb to given fraction -#ifdef TODO_GTK - static char *params[3] = { "", "Continuous", "Proportional" }; - static XEvent event; - Widget w = XtParent(opt->handle); // viewport - Widget v = XtNameToWidget(w, "vertical"); - if(!v) return; // no scroll bar - XtCallActionProc(v, "StartScroll", &event, params+1, 1); - XawScrollbarSetThumb(v, f, -1.0); - XtCallActionProc(v, "NotifyThumb", &event, params, 0); -// XtCallActionProc(v, "NotifyScroll", &event, params+2, 1); - XtCallActionProc(v, "EndScroll", &event, params, 0); -#endif -} - void -HighlightListBoxItem (Option *opt, int index) +HighlightItem (Option *opt, int index, int scroll) { char *value, **data = (char **) (opt->target); GtkWidget *list = (GtkWidget *) (opt->handle); @@ -340,15 +297,21 @@ HighlightListBoxItem (Option *opt, int index) GtkListStore *store = GTK_LIST_STORE(model); GtkTreePath *path = gtk_tree_path_new_from_indices(index, -1); GtkTreeIter iter; - gtk_tree_model_get_iter(GTK_TREE_MODEL (store), &iter, path); + gtk_tree_selection_select_path(selection, path); + if(scroll) gtk_tree_view_scroll_to_cell(list, path, NULL, 0, 0, 0); gtk_tree_path_free(path); - gtk_tree_selection_select_iter(selection, &iter); } void -HighlightWithScroll (Option *opt, int sel, int max) +HighlightListBoxItem (Option *opt, int index) +{ + HighlightItem (opt, index, FALSE); +} + +void +HighlightWithScroll (Option *opt, int index, int max) { - HighlightListBoxItem (opt, index); // just highlight, as GTK scrolls by itself + HighlightItem (opt, index, TRUE); // ignore max } int @@ -375,6 +338,7 @@ FocusOnWidget (Option *opt, DialogClass dlg) #ifdef TODO_GTK XtSetKeyboardFocus(shells[dlg], opt->handle); #endif + gtk_widget_grab_focus(opt->handle); } void @@ -389,55 +353,6 @@ SetIconName (DialogClass dlg, char *name) #endif } -#ifdef TODO_GTK -static void -CheckCallback (Widget ww, XtPointer client_data, XEvent *event, Boolean *b) -{ - int s, data = (intptr_t) client_data; - Option *opt = dialogOptions[data >> 8] + (data & 255); - - if(opt->type == Label) { ((ButtonCallback*) opt->target)(data&255); return; } - - GetWidgetState(opt, &s); - SetWidgetState(opt, !s); -} -#endif - -#ifdef TODO_GTK -static void -SpinCallback (Widget w, XtPointer client_data, XtPointer call_data) -{ - String name, val; - Arg args[16]; - char buf[MSG_SIZ], *p; - int j = 0; // Initialisation is necessary because the text value may be non-numeric causing the scanf conversion to fail - int data = (intptr_t) client_data; - Option *opt = dialogOptions[data >> 8] + (data & 255); - - XtSetArg(args[0], XtNlabel, &name); - XtGetValues(w, args, 1); - - GetWidgetText(opt, &val); - sscanf(val, "%d", &j); - if (strcmp(name, _("browse")) == 0) { - char *q=val, *r; - for(r = ""; *q; q++) if(*q == '.') r = q; else if(*q == '/') r = ""; // last dot after last slash - if(!strcmp(r, "") && !currentCps && opt->type == FileName && opt->textValue) - r = opt->textValue; - Browse(data>>8, opt->name, NULL, r, opt->type == PathName, "", &p, (FILE**) opt); - return; - } else - if (strcmp(name, "+") == 0) { - if(++j > opt->max) return; - } else - if (strcmp(name, "-") == 0) { - if(--j < opt->min) return; - } else return; - snprintf(buf, MSG_SIZ, "%d", j); - SetWidgetText(opt, buf, TransientDlg); -} -#endif - void ComboSelect(GtkWidget *widget, gpointer addr) { Option *opt = dialogOptions[((intptr_t)addr)>>8]; // applicable option list @@ -474,33 +389,6 @@ CreateMenuItem (Widget menu, char *msg, XtCallbackProc CB, int n) } #endif -#ifdef TODO_GTK -static Widget -CreateComboPopup (Widget parent, Option *opt, int n, int fromList, int def) -{ // fromList determines if the item texts are taken from a list of strings, or from a menu table - int i; - Widget menu, entry; - Arg arg; - MenuItem *mb = (MenuItem *) opt->choice; - char **list = (char **) opt->choice; - - if(list[0] == NULL) return NULL; // avoid empty menus, as they cause crash - menu = XtCreatePopupShell(opt->name, simpleMenuWidgetClass, parent, NULL, 0); - - for (i=0; 1; i++) - { - char *msg = fromList ? list[i] : mb[i].string; - if(!msg) break; - entry = CreateMenuItem(menu, opt->min & NO_GETTEXT ? msg : _(msg), (XtCallbackProc) ComboSelect, (n<<16)+i); - if(!fromList) mb[i].handle = (void*) entry; // save item ID, for enabling / checkmarking - if(i==def) { - XtSetArg(arg, XtNpopupOnEntry, entry); - XtSetValues(menu, &arg, 1); - } - } - return menu; -} -#else static void MenuSelect (gpointer addr) // callback for all combo items { @@ -545,7 +433,6 @@ CreateMenuPopup (Option *opt, int n, int def) } return menu; } -#endif char moveTypeInTranslations[] = "Return: TypeInProc(1) \n" @@ -560,9 +447,29 @@ char *translationTable[] = { // beware: order is essential! filterTranslations, gameListTranslations, memoTranslations }; +Option *typeIn; // kludge to distinguish type-in callback from input-box callback + +void +CursorAtEnd (Option *opt) +{ + gtk_editable_set_position(opt->handle, -1); +} + static gboolean -ICSKeyEvent(GtkWidget *widget, GdkEventKey *event) +ICSKeyEvent(GtkWidget *widget, GdkEventKey *event, gpointer g) { + Option *opt = (Option *) g; + if(opt == typeIn) { + if(event->keyval == GDK_Return) { + char *val; + GetWidgetText(opt, &val); + TypeInDoneEvent(val); + PopDown(TransientDlg); + return TRUE; + } + return FALSE; + } + switch(event->keyval) { case GDK_Return: IcsKey(0); return TRUE; case GDK_Up: IcsKey(1); return TRUE; @@ -571,6 +478,36 @@ ICSKeyEvent(GtkWidget *widget, GdkEventKey *event) } } +int shiftState, controlState; + +static gboolean +TypeInProc (GtkWidget *widget, GdkEventKey *event, gpointer gdata) +{ // This callback catches key presses on text-entries, and uses and as synonyms for dialog OK or Cancel + // *** kludge alert *** If a dialog does want some other action, like sending the line typed in the text-entry to an ICS, + // it should define an OK handler that does so, and returns FALSE to suppress the popdown. + int n = (intptr_t) gdata; + int dlg = n >> 16; + Option *opt; + n &= 0xFFFF; + opt = &dialogOptions[dlg][n]; + + if(opt == icsBox) return ICSKeyEvent(event->keyval); // Intercept ICS Input Box, which needs special treatment + + shiftState = event->state & GDK_SHIFT_MASK; + controlState = event->state & GDK_CONTROL_MASK; + switch(event->keyval) { + case GDK_Return: + if(GenericReadout(dialogOptions[dlg], -1)) PopDown(dlg); + break; + case GDK_Escape: + PopDown(dlg); + break; + default: + return FALSE; + } + return TRUE; +} + void HighlightText (Option *opt, int from, int to, Boolean highlight) { @@ -587,6 +524,43 @@ HighlightText (Option *opt, int from, int to, Boolean highlight) gtk_text_buffer_apply_tag_by_name(opt->handle, highlight ? "highlight" : "normal", &start, &end); } +int +ShiftKeys () +{ // bassic primitive for determining if modifier keys are pressed + return 3*(shiftState != 0) + 0xC*(controlState != 0); // rely on what last mouse button press left us +} + +static gboolean +GameListEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata) +{ + int n = (int) gdata; + + if(n == 4) { + if(((GdkEventKey *) event)->keyval != GDK_Return) return FALSE; + SetFilter(); + return TRUE; + } + + if(event->type == GDK_KEY_PRESS) { + int ctrl = (((GdkEventKey *) event)->state & GDK_CONTROL_MASK) != 0; + switch(((GdkEventKey *) event)->keyval) { + case GDK_Up: GameListClicks(-1 - 2*ctrl); return TRUE; + case GDK_Left: GameListClicks(-1); return TRUE; + case GDK_Down: GameListClicks(1 + 2*ctrl); return TRUE; + case GDK_Right: GameListClicks(1); return TRUE; + case GDK_Prior: GameListClicks(-4); return TRUE; + case GDK_Next: GameListClicks(4); return TRUE; + case GDK_Home: GameListClicks(-2); return TRUE; + case GDK_End: GameListClicks(2); return TRUE; + case GDK_Return: GameListClicks(0); return TRUE; + default: return FALSE; + } + } + if(event->type != GDK_2BUTTON_PRESS || ((GdkEventButton *) event)->button != 1) return FALSE; + GameListClicks(0); + return TRUE; +} + static gboolean MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata) { // handle mouse clicks on text widgets that need it @@ -601,6 +575,8 @@ MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata) gboolean res; gint index, x, y; + if(memo->type == Label) { ((ButtonCallback*) memo->target)(memo->value); return TRUE; } // only clock widgets use this + switch(event->type) { // figure out what's up case GDK_MOTION_NOTIFY: f = 0; @@ -614,6 +590,8 @@ MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata) case GDK_BUTTON_PRESS: w = bevent->x; h = bevent->y; button = bevent->button; + shiftState = bevent->state & GDK_SHIFT_MASK; + controlState = bevent->state & GDK_CONTROL_MASK; // 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); @@ -636,20 +614,25 @@ MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata) } void -AddHandler (Option *opt, int nr) +AddHandler (Option *opt, DialogClass dlg, int nr) { switch(nr) { - case 0: - case 1: - case 2: 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; + case 0: // history (now uses generic textview callback) + case 1: // comment (likewise) + break; + case 2: // move type-in + typeIn = opt; + case 3: // input box + g_signal_connect(opt->handle, "key-press-event", G_CALLBACK (ICSKeyEvent), (gpointer) opt); + break; + case 5: // game list + g_signal_connect(opt->handle, "button-press-event", G_CALLBACK (GameListEvent), (gpointer) 0 ); + case 4: // game-list filter + g_signal_connect(opt->handle, "key-press-event", G_CALLBACK (GameListEvent), (gpointer) nr ); + break; + case 6: // engine output (uses generic textview callback) + break; } -#ifdef TODO_GTK - XtOverrideTranslations(opt->handle, XtParseTranslationTable(translationTable[nr])); -#endif } //----------------------------Generic dialog -------------------------------------------- @@ -688,7 +671,9 @@ RaiseWindow (DialogClass dlg) xev.xclient.data.l[1] = CurrentTime; XSendEvent (xDisplay, - root, False, + root, False,static gboolean +MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata) + SubstructureRedirectMask | SubstructureNotifyMask, &xev); @@ -872,6 +857,8 @@ GraphEventProc(GtkWidget *widget, GdkEvent *event, gpointer gdata) case GDK_BUTTON_PRESS: w = bevent->x; h = bevent->y; button = bevent->button; + shiftState = bevent->state & GDK_SHIFT_MASK; + controlState = bevent->state & GDK_CONTROL_MASK; } button *= f; @@ -993,55 +980,6 @@ void BrowseGTK(GtkWidget *widget, gpointer gdata) dialog = NULL; } -#ifdef TODO_GTK -void -TabProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) -{ // for transfering focus to the next text-edit - Option *opt; - for(opt = currentOption; opt->type != EndMark; opt++) { - if(opt->handle == w) { - while(++opt) { - if(opt->type == EndMark) opt = currentOption; // wrap - if(opt->handle == w) return; // full circle - if(opt->type == TextBox || opt->type == Spin || opt->type == Fractional || opt->type == FileName || opt->type == PathName) { - SetFocus(opt->handle, XtParent(XtParent(XtParent(w))), NULL, 0); - return; - } - } - } - } -} -#endif - -#ifdef TODO_GTK -void -WheelProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) -{ // for scrolling a widget seen through a viewport with the mouse wheel (ListBox!) - int j=0, n = atoi(prms[0]); - static char *params[3] = { "", "Continuous", "Proportional" }; - Arg args[16]; - float h, top; - Widget v; - if(!n) { // transient dialogs also use this for list-selection callback - n = prms[1][0]-'0'; - Option *opt=dialogOptions[prms[2][0]-'A'] + n; - if(opt->textValue) ((ListBoxCallback*) opt->textValue)(n, SelectedListBoxItem(opt)); - return; - } - v = XtNameToWidget(XtParent(w), "vertical"); - if(!v) return; - XtSetArg(args[j], XtNshown, &h); j++; - XtSetArg(args[j], XtNtopOfThumb, &top); j++; - XtGetValues(v, args, j); - top += 0.1f*h*n; if(top < 0.f) top = 0.; - XtCallActionProc(v, "StartScroll", event, params+1, 1); - XawScrollbarSetThumb(v, top, -1.0); - XtCallActionProc(v, "NotifyThumb", event, params, 0); -// XtCallActionProc(w, "NotifyScroll", event, params+2, 1); - XtCallActionProc(v, "EndScroll", event, params, 0); -} -#endif - static char *oneLiner = "Return: redraw-display() \n \ Tab: TabProc() \n "; @@ -1336,7 +1274,11 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent gtk_container_add(GTK_CONTAINER(frame), label); label = frame; } - Pack(hbox, table, label, left, left+3, top); + Pack(hbox, table, label, left, left+3, top); + if(option[i].target) { // allow user to specify event handler for button presses + gtk_widget_add_events(GTK_WIDGET(label), GDK_BUTTON_PRESS_MASK); + g_signal_connect(label, "button-press-event", G_CALLBACK(MemoEvent), (gpointer) &option[i]); + } break; case SaveButton: case Button: