📄 gtkdlg.c
字号:
/* * GTK doesn't appear to make it easy to * implement a proper draggable list; so * instead I'm just going to have to put an Up * and a Down button to the right of the actual * list box. Ah well. */ GtkWidget *cols, *button; static const gint percentages[2] = { 80, 20 }; cols = columns_new(4); columns_set_cols(COLUMNS(cols), 2, percentages); columns_add(COLUMNS(cols), w, 0, 1); gtk_widget_show(w); button = gtk_button_new_with_label("Up"); columns_add(COLUMNS(cols), button, 1, 1); gtk_widget_show(button); gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(draglist_up), dp); gtk_signal_connect(GTK_OBJECT(button), "focus_in_event", GTK_SIGNAL_FUNC(widget_focus), dp); button = gtk_button_new_with_label("Down"); columns_add(COLUMNS(cols), button, 1, 1); gtk_widget_show(button); gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(draglist_down), dp); gtk_signal_connect(GTK_OBJECT(button), "focus_in_event", GTK_SIGNAL_FUNC(widget_focus), dp); w = cols; } } if (ctrl->generic.label) { GtkWidget *label, *container; label = gtk_label_new(ctrl->generic.label); container = columns_new(4); if (ctrl->listbox.percentwidth == 100) { columns_add(COLUMNS(container), label, 0, 1); columns_force_left_align(COLUMNS(container), label); columns_add(COLUMNS(container), w, 0, 1); } else { gint percentages[2]; percentages[1] = ctrl->listbox.percentwidth; percentages[0] = 100 - ctrl->listbox.percentwidth; columns_set_cols(COLUMNS(container), 2, percentages); columns_add(COLUMNS(container), label, 0, 1); columns_force_left_align(COLUMNS(container), label); columns_add(COLUMNS(container), w, 1, 1); } gtk_widget_show(label); gtk_widget_show(w); shortcut_add(scs, label, ctrl->listbox.shortcut, SHORTCUT_UCTRL, uc); w = container; } break; case CTRL_TEXT: /* * Wrapping text widgets don't sit well with the GTK * layout model, in which widgets state a minimum size * and the whole window then adjusts to the smallest * size it can sensibly take given its contents. A * wrapping text widget _has_ no clear minimum size; * instead it has a range of possibilities. It can be * one line deep but 2000 wide, or two lines deep and * 1000 pixels, or three by 867, or four by 500 and so * on. It can be as short as you like provided you * don't mind it being wide, or as narrow as you like * provided you don't mind it being tall. * * Therefore, it fits very badly into the layout model. * Hence the only thing to do is pick a width and let * it choose its own number of lines. To do this I'm * going to cheat a little. All new wrapping text * widgets will be created with a minimal text content * "X"; then, after the rest of the dialog box is set * up and its size calculated, the text widgets will be * told their width and given their real text, which * will cause the size to be recomputed in the y * direction (because many of them will expand to more * than one line). */ uc->text = w = gtk_label_new("X"); gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.0); gtk_label_set_line_wrap(GTK_LABEL(w), TRUE); uc->textsig = gtk_signal_connect(GTK_OBJECT(w), "size-allocate", GTK_SIGNAL_FUNC(label_sizealloc), dp); break; } assert(w != NULL); columns_add(cols, w, COLUMN_START(ctrl->generic.column), COLUMN_SPAN(ctrl->generic.column)); if (left) columns_force_left_align(cols, w); gtk_widget_show(w); uc->toplevel = w; dlg_add_uctrl(dp, uc); } return ret;}struct selparam { struct dlgparam *dp; Panels *panels; GtkWidget *panel, *treeitem; struct Shortcuts shortcuts;};static void treeitem_sel(GtkItem *item, gpointer data){ struct selparam *sp = (struct selparam *)data; panels_switch_to(sp->panels, sp->panel); sp->dp->shortcuts = &sp->shortcuts; sp->dp->currtreeitem = sp->treeitem;}static void window_destroy(GtkWidget *widget, gpointer data){ gtk_main_quit();}static int tree_grab_focus(struct dlgparam *dp){ int i, f; /* * See if any of the treeitems has the focus. */ f = -1; for (i = 0; i < dp->ntreeitems; i++) if (GTK_WIDGET_HAS_FOCUS(dp->treeitems[i])) { f = i; break; } if (f >= 0) return FALSE; else { gtk_widget_grab_focus(dp->currtreeitem); return TRUE; }}gint tree_focus(GtkContainer *container, GtkDirectionType direction, gpointer data){ struct dlgparam *dp = (struct dlgparam *)data; gtk_signal_emit_stop_by_name(GTK_OBJECT(container), "focus"); /* * If there's a focused treeitem, we return FALSE to cause the * focus to move on to some totally other control. If not, we * focus the selected one. */ return tree_grab_focus(dp);}int win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data){ struct dlgparam *dp = (struct dlgparam *)data; if (event->keyval == GDK_Escape && dp->cancelbutton) { gtk_signal_emit_by_name(GTK_OBJECT(dp->cancelbutton), "clicked"); return TRUE; } if ((event->state & GDK_MOD1_MASK) && (unsigned char)event->string[0] > 0 && (unsigned char)event->string[0] <= 127) { int schr = (unsigned char)event->string[0]; struct Shortcut *sc = &dp->shortcuts->sc[schr]; switch (sc->action) { case SHORTCUT_TREE: tree_grab_focus(dp); break; case SHORTCUT_FOCUS: gtk_widget_grab_focus(sc->widget); break; case SHORTCUT_UCTRL: /* * We must do something sensible with a uctrl. * Precisely what this is depends on the type of * control. */ switch (sc->uc->ctrl->generic.type) { case CTRL_CHECKBOX: case CTRL_BUTTON: /* Check boxes and buttons get the focus _and_ get toggled. */ gtk_widget_grab_focus(sc->uc->toplevel); gtk_signal_emit_by_name(GTK_OBJECT(sc->uc->toplevel), "clicked"); break; case CTRL_FILESELECT: case CTRL_FONTSELECT: /* File/font selectors have their buttons pressed (ooer), * and focus transferred to the edit box. */ gtk_signal_emit_by_name(GTK_OBJECT(sc->uc->button), "clicked"); gtk_widget_grab_focus(sc->uc->entry); break; case CTRL_RADIO: /* * Radio buttons are fun, because they have * multiple shortcuts. We must find whether the * activated shortcut is the shortcut for the whole * group, or for a particular button. In the former * case, we find the currently selected button and * focus it; in the latter, we focus-and-click the * button whose shortcut was pressed. */ if (schr == sc->uc->ctrl->radio.shortcut) { int i; for (i = 0; i < sc->uc->ctrl->radio.nbuttons; i++) if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(sc->uc->buttons[i]))) { gtk_widget_grab_focus(sc->uc->buttons[i]); } } else if (sc->uc->ctrl->radio.shortcuts) { int i; for (i = 0; i < sc->uc->ctrl->radio.nbuttons; i++) if (schr == sc->uc->ctrl->radio.shortcuts[i]) { gtk_widget_grab_focus(sc->uc->buttons[i]); gtk_signal_emit_by_name (GTK_OBJECT(sc->uc->buttons[i]), "clicked"); } } break; case CTRL_LISTBOX: /* * If the list is really an option menu, we focus * and click it. Otherwise we tell it to focus one * of its children, which appears to do the Right * Thing. */ if (sc->uc->optmenu) { GdkEventButton bev; gint returnval; gtk_widget_grab_focus(sc->uc->optmenu); /* Option menus don't work using the "clicked" signal. * We need to manufacture a button press event :-/ */ bev.type = GDK_BUTTON_PRESS; bev.button = 1; gtk_signal_emit_by_name(GTK_OBJECT(sc->uc->optmenu), "button_press_event", &bev, &returnval); } else { assert(sc->uc->list != NULL); gtk_container_focus(GTK_CONTAINER(sc->uc->list), GTK_DIR_TAB_FORWARD); } break; } break; } } return FALSE;}int tree_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data){ struct dlgparam *dp = (struct dlgparam *)data; if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up || event->keyval == GDK_Down || event->keyval == GDK_KP_Down) { int dir, i, j = -1; for (i = 0; i < dp->ntreeitems; i++) if (widget == dp->treeitems[i]) break; if (i < dp->ntreeitems) { if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up) dir = -1; else dir = +1; while (1) { i += dir; if (i < 0 || i >= dp->ntreeitems) break; /* nothing in that dir to select */ /* * Determine if this tree item is visible. */ { GtkWidget *w = dp->treeitems[i]; int vis = TRUE; while (w && (GTK_IS_TREE_ITEM(w) || GTK_IS_TREE(w))) { if (!GTK_WIDGET_VISIBLE(w)) { vis = FALSE; break; } w = w->parent; } if (vis) { j = i; /* got one */ break; } } } } gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event"); if (j >= 0) { gtk_signal_emit_by_name(GTK_OBJECT(dp->treeitems[j]), "toggle"); gtk_widget_grab_focus(dp->treeitems[j]); } return TRUE; } /* * It's nice for Left and Right to expand and collapse tree * branches. */ if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) { gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event"); gtk_tree_item_collapse(GTK_TREE_ITEM(widget)); return TRUE; } if (event->keyval == GDK_Right || event->keyval == GDK_KP_Right) { gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event"); gtk_tree_item_expand(GTK_TREE_ITEM(widget)); return TRUE; } return FALSE;}void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw, int chr, int action, void *ptr){ GtkLabel *label = GTK_LABEL(labelw); gchar *currstr, *pattern; int i; if (chr == NO_SHORTCUT) return; chr = tolower((unsigned char)chr); assert(scs->sc[chr].action == SHORTCUT_EMPTY); scs->sc[chr].action = action; if (action == SHORTCUT_FOCUS) { scs->sc[chr].uc = NULL; scs->sc[chr].widget = (GtkWidget *)ptr; } else { scs->sc[chr].widget = NULL; scs->sc[chr].uc = (struct uctrl *)ptr; } gtk_label_get(label, &currstr); for (i = 0; currstr[i]; i++) if (tolower((unsigned char)currstr[i]) == chr) { GtkRequisition req; pattern = dupprintf("%*s_", i, ""); gtk_widget_size_request(GTK_WIDGET(label), &req); gtk_label_set_pattern(label, pattern); gtk_widget_set_usize(GTK_WIDGET(label), -1, req.height); sfree(pattern); break; }}int get_listitemheight(void){ GtkWidget *listitem = gtk_list_item_new_with_label("foo"); Gtk
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -