static gboolean which_tooltip_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data) { gchar *text = ""; GncCombott *combott = GNC_COMBOTT (user_data); GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); if(priv->active != 0) { gtk_tree_model_get( priv->model, &priv->active_iter, priv->tip_col, &text, -1 ); if(g_strcmp0(text, "") && (text != NULL)) { gchar *label = ""; gtk_tooltip_set_text (tooltip, text); g_free(text); return TRUE; } else { g_free(text); return FALSE; } } return FALSE; }
static gboolean button_press_cb (GtkWidget *widget, GdkEvent *event, gpointer *user_data ) { GncCombott *combott = GNC_COMBOTT (user_data); GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); if(priv->model != NULL) { if (event->type == GDK_BUTTON_PRESS) { GdkEventButton *bevent = (GdkEventButton *) event; gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, gctt_combott_menu_position, combott, bevent->button, bevent->time); /* Tell calling code that we have handled this event; the buck * stops here. */ return TRUE; } } /* Tell calling code that we have not handled this event; pass it on. */ return FALSE; }
/* Note that g_value_set_object() refs the object, as does * g_object_get(). But g_object_get() only unrefs once when it disgorges * the object, leaving an unbalanced ref, which leaks. So instead of * using g_value_set_object(), use g_value_take_object() which doesn't * ref the object when used in get_property(). */ static void gctt_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { GncCombott *combott = GNC_COMBOTT (object); GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); switch (param_id) { case PROP_MODEL: g_value_take_object (value, priv->model); break; case PROP_ACTIVE: g_value_set_int (value, gnc_combott_get_active (combott)); break; case PROP_TEXT_COL: g_value_set_int (value, priv->text_col); break; case PROP_TIP_COL: g_value_set_int (value, priv->tip_col); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } }
void gnc_combott_set_active (GncCombott *combott, gint index) { GncCombottPrivate *priv; GtkTreeIter iter; gboolean valid = TRUE; gint active = 1; g_return_if_fail (GNC_IS_COMBOTT (combott)); g_return_if_fail (index >= -1); priv = GNC_COMBOTT_GET_PRIVATE (combott); /* Do we have a valid model */ if (priv->model != NULL) { /* Is index the same as current option */ if(index + 1 != priv->active) { /* Set button label to blank for no selection */ if(index == -1) { priv->active = 0; gtk_label_set_text(GTK_LABEL(priv->label), ""); g_signal_emit (combott, combott_signals[CHANGED], 0); } else { /* Get the corresponding entry in the list store */ valid = gtk_tree_model_get_iter_first (priv->model, &iter); while (valid) { /* Walk through the list, reading each row */ gchar *str_data; gchar *tip_data; /* Make sure you terminate calls to gtk_tree_model_get() * with a '-1' value */ gtk_tree_model_get (priv->model, &iter, priv->text_col, &str_data, priv->tip_col, &tip_data, -1); if(index + 1 == active) { priv->active = index + 1; priv->active_iter = iter; gtk_label_set_text(GTK_LABEL(priv->label), str_data); gnc_label_set_alignment (priv->label, 0, 0.5); g_signal_emit (combott, combott_signals[CHANGED], 0); } g_free (str_data); g_free (tip_data); active ++; valid = gtk_tree_model_iter_next (priv->model, &iter); } } } } }
static void menu_getsize_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer *user_data) { GncCombott *combott = GNC_COMBOTT (user_data); GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); /* Set the menu width */ gtk_widget_set_size_request (widget, priv->width - 6, allocation->height); }
static void button_getsize_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer *user_data) { GncCombott *combott = GNC_COMBOTT (user_data); GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); priv->width = allocation->width; priv->height = allocation->height; priv->x = allocation->x; priv->y = allocation->y; }
static void gctt_refresh_menu (GncCombott *combott, GtkTreeModel *model) { GncCombottPrivate *priv; g_return_if_fail (GNC_IS_COMBOTT (combott)); g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model)); priv = GNC_COMBOTT_GET_PRIVATE (combott); gctt_rebuild_menu(combott, model); }
static void gctt_combott_menu_position (GtkMenu *menu, gint *x, gint *y, gint *push_in, gpointer user_data) { GncCombott *combott = GNC_COMBOTT (user_data); GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); gint sx, sy; GtkWidget *child; GtkRequisition req; GtkAllocation alloc; GtkBorder padding; GtkStyleContext *sc = gtk_widget_get_style_context (GTK_WIDGET (priv->button)); GtkStateFlags state_flags = gtk_style_context_get_state (sc); child = gtk_bin_get_child (GTK_BIN (priv->button)); sx = sy = 0; if (!gtk_widget_get_has_window (child)) { gtk_widget_get_allocation (child, &alloc); sx += alloc.x; sy += alloc.y; } gdk_window_get_root_coords (gtk_widget_get_window (child), sx, sy, &sx, &sy); gtk_style_context_get_padding (sc, state_flags, &padding); sx -= padding.left; gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL); if (gtk_widget_get_direction (GTK_WIDGET (priv->button)) == GTK_TEXT_DIR_LTR) *x = sx; else { gtk_widget_get_allocation (child, &alloc); *x = sx + alloc.width - req.width; } if(priv->active == -1 || priv->active == 0) *y = sy; else *y = sy - ((req.height / priv->num_items) * (priv->active - 1)); *push_in = FALSE; }
gint gnc_combott_get_active (GncCombott *combott) { GncCombottPrivate *priv; gint result; g_return_val_if_fail (GNC_IS_COMBOTT (combott), 0); priv = GNC_COMBOTT_GET_PRIVATE (combott); result = priv->active - 1; return result; }
static void menuitem_response_cb (GtkMenuItem *item, gpointer *user_data ) { const gchar *label_text; GtkTreeIter iter, iter_now = {0, NULL, NULL, NULL}; gboolean valid; gint active = 1; gint active_now = 1; GncCombott *combott = GNC_COMBOTT (user_data); GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); label_text = gtk_menu_item_get_label (item); /* Set the button Label */ gtk_label_set_text(GTK_LABEL(priv->label), label_text); gtk_misc_set_alignment (GTK_MISC(priv->label), 0, 0.5); /* Get the corresponding entry in the list store */ valid = gtk_tree_model_get_iter_first (priv->model, &iter); while (valid) { /* Walk through the list, reading each row */ gchar *str_data; gchar *tip_data; gtk_tree_model_get (priv->model, &iter, priv->text_col, &str_data, priv->tip_col, &tip_data, -1); if(!g_strcmp0(str_data, label_text)) { active_now = active; iter_now = iter; } g_free (str_data); g_free (tip_data); active ++; valid = gtk_tree_model_iter_next (priv->model, &iter); } /* Emit Changed signal if we have selected a new entry */ if(priv->active != active_now) { priv->active = active_now; priv->active_iter = iter_now; g_signal_emit (combott, combott_signals[CHANGED], 0); } }
static void gctt_combott_menu_position (GtkMenu *menu, gint *x, gint *y, gint *push_in, gpointer user_data) { GncCombott *combott = GNC_COMBOTT (user_data); GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); gint sx, sy; GtkWidget *child; GtkRequisition req; GtkAllocation alloc; child = gtk_bin_get_child (GTK_BIN (priv->button)); sx = sy = 0; if (!gtk_widget_get_has_window (child)) { gtk_widget_get_allocation (child, &alloc); sx += alloc.x; sy += alloc.y; } gdk_window_get_root_coords (gtk_widget_get_window (child), sx, sy, &sx, &sy); sx -= gtk_widget_get_style (GTK_WIDGET (priv->button))->xthickness; gtk_widget_size_request (GTK_WIDGET (menu), &req); if (gtk_widget_get_direction (GTK_WIDGET (priv->button)) == GTK_TEXT_DIR_LTR) *x = sx; else { gtk_widget_get_allocation (child, &alloc); *x = sx + alloc.width - req.width; } if(priv->active == -1 || priv->active == 0) *y = sy; else *y = sy - ((req.height / priv->num_items) * (priv->active - 1)); *push_in = FALSE; }
static void gctt_init (GncCombott *combott) { GtkWidget *hbox; GtkWidget *label; GtkWidget *arrow; GtkWidget *button; GtkWidget *sep; GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); priv->active = 0; priv->text_col = 0; priv->tip_col = 1; hbox = gtk_hbox_new(FALSE, 0); arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0); sep = gtk_vseparator_new(); gtk_box_pack_end (GTK_BOX (hbox), sep, FALSE, FALSE, 0); label = gtk_label_new(NULL); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); priv->label = label; button = gtk_button_new(); gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(hbox)); priv->button = button; gtk_container_add(GTK_CONTAINER(combott), GTK_WIDGET(button)); g_signal_connect (button, "event", G_CALLBACK (button_press_cb), combott); gtk_widget_set_has_tooltip (GTK_WIDGET(combott), TRUE); g_signal_connect(G_OBJECT(combott), "query-tooltip", G_CALLBACK(which_tooltip_cb), combott); g_signal_connect(G_OBJECT(combott), "size-allocate", G_CALLBACK(button_getsize_cb), combott); gtk_widget_show(GTK_WIDGET(priv->button)); }
static void gctt_finalize (GObject *object) { GncCombott *combott; GncCombottPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (GNC_IS_COMBOTT (object)); combott = GNC_COMBOTT (object); priv = GNC_COMBOTT_GET_PRIVATE (combott); if (priv->model) { priv->model = NULL; } if (priv->menu) { priv->menu = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gctt_rebuild_menu (GncCombott *combott, GtkTreeModel *model) { GncCombottPrivate *priv; GtkTreeIter iter; GtkWidget *menu_items; gboolean valid; gint num = 1; gint items = 0; g_return_if_fail (GNC_IS_COMBOTT (combott)); g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model)); priv = GNC_COMBOTT_GET_PRIVATE (combott); priv->menu = NULL; priv->menu = gtk_menu_new(); valid = gtk_tree_model_get_iter_first (model, &iter); while (valid) { GtkWidget *label; /* Walk through the list, reading each row */ gchar *str_data; gchar *tip_data; gtk_tree_model_get (model, &iter, priv->text_col, &str_data, priv->tip_col, &tip_data, -1); /* Create a new menu-item with a name... */ menu_items = gtk_menu_item_new_with_label (str_data); /* Get widget width to max number of characters in list */ if(strlen(str_data) > num) num = strlen(str_data); /* Add the tooltip to the child label */ label = gtk_bin_get_child(GTK_BIN(menu_items)); gtk_widget_set_tooltip_text (label, tip_data); gtk_misc_set_alignment (GTK_MISC(label), 0, 0.5); /* ...and add it to the menu. */ gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_items); g_signal_connect (menu_items, "activate", G_CALLBACK (menuitem_response_cb), combott); /* Show the widget */ gtk_widget_show (menu_items); g_free (str_data); g_free (tip_data); items++; valid = gtk_tree_model_iter_next (model, &iter); } g_signal_connect(G_OBJECT(priv->menu), "size-allocate", G_CALLBACK(menu_getsize_cb), combott); /* Set widget width to max number of characters in list */ priv->max_number_char = num; gtk_label_set_width_chars(GTK_LABEL(priv->label), priv->max_number_char); priv->num_items = items; }
static void gctt_init (GncCombott *combott) { GtkWidget *hbox; GtkWidget *label; GtkWidget *arrow; GtkWidget *button; GtkWidget *sep; GncCombottPrivate *priv = GNC_COMBOTT_GET_PRIVATE (combott); gtk_orientable_set_orientation (GTK_ORIENTABLE(combott), GTK_ORIENTATION_HORIZONTAL); // Set the style context for this widget so it can be easily manipulated with css gnc_widget_set_style_context (GTK_WIDGET(combott), "GncCombott"); priv->active = 0; priv->text_col = 0; priv->tip_col = 1; hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_set_homogeneous (GTK_BOX(hbox), FALSE); arrow = gtk_image_new_from_icon_name ("go-down", GTK_ICON_SIZE_BUTTON); g_signal_connect (G_OBJECT (arrow), "draw", G_CALLBACK (gnc_draw_arrow_cb), GINT_TO_POINTER(1)); #if GTK_CHECK_VERSION(3,12,0) gtk_widget_set_margin_start (GTK_WIDGET(arrow), 5); #else gtk_widget_set_margin_left (GTK_WIDGET(arrow), 5); #endif gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0); sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL); gtk_box_pack_end (GTK_BOX (hbox), sep, FALSE, FALSE, 0); label = gtk_label_new(NULL); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); priv->label = label; button = gtk_button_new(); gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(hbox)); priv->button = button; gtk_container_add(GTK_CONTAINER(combott), GTK_WIDGET(button)); g_signal_connect (button, "event", G_CALLBACK (button_press_cb), combott); gtk_widget_set_has_tooltip (GTK_WIDGET(combott), TRUE); g_signal_connect(G_OBJECT(combott), "query-tooltip", G_CALLBACK(which_tooltip_cb), combott); g_signal_connect(G_OBJECT(combott), "size-allocate", G_CALLBACK(button_getsize_cb), combott); gtk_widget_show(GTK_WIDGET(priv->button)); }