forked from AuroraMiddleware/gtk
386b63b85d
In 99.9% of all cases, these are just NULL, NULL. So just do away with these arguments, people can use the setters for the rare cases where they want the scrolled window to use a different adjustment.
416 lines
12 KiB
C
416 lines
12 KiB
C
/* Tree View/Editable Cells
|
|
*
|
|
* This demo demonstrates the use of editable cells in a GtkTreeView. If
|
|
* you're new to the GtkTreeView widgets and associates, look into
|
|
* the GtkListStore example first. It also shows how to use the
|
|
* GtkCellRenderer::editing-started signal to do custom setup of the
|
|
* editable widget.
|
|
*
|
|
* The cell renderers used in this demo are GtkCellRendererText,
|
|
* GtkCellRendererCombo and GtkCellRendererProgress.
|
|
*/
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
typedef struct
|
|
{
|
|
gint number;
|
|
gchar *product;
|
|
gint yummy;
|
|
}
|
|
Item;
|
|
|
|
enum
|
|
{
|
|
COLUMN_ITEM_NUMBER,
|
|
COLUMN_ITEM_PRODUCT,
|
|
COLUMN_ITEM_YUMMY,
|
|
NUM_ITEM_COLUMNS
|
|
};
|
|
|
|
enum
|
|
{
|
|
COLUMN_NUMBER_TEXT,
|
|
NUM_NUMBER_COLUMNS
|
|
};
|
|
|
|
static GArray *articles = NULL;
|
|
|
|
static void
|
|
add_items (void)
|
|
{
|
|
Item foo;
|
|
|
|
g_return_if_fail (articles != NULL);
|
|
|
|
foo.number = 3;
|
|
foo.product = g_strdup ("bottles of coke");
|
|
foo.yummy = 20;
|
|
g_array_append_vals (articles, &foo, 1);
|
|
|
|
foo.number = 5;
|
|
foo.product = g_strdup ("packages of noodles");
|
|
foo.yummy = 50;
|
|
g_array_append_vals (articles, &foo, 1);
|
|
|
|
foo.number = 2;
|
|
foo.product = g_strdup ("packages of chocolate chip cookies");
|
|
foo.yummy = 90;
|
|
g_array_append_vals (articles, &foo, 1);
|
|
|
|
foo.number = 1;
|
|
foo.product = g_strdup ("can vanilla ice cream");
|
|
foo.yummy = 60;
|
|
g_array_append_vals (articles, &foo, 1);
|
|
|
|
foo.number = 6;
|
|
foo.product = g_strdup ("eggs");
|
|
foo.yummy = 10;
|
|
g_array_append_vals (articles, &foo, 1);
|
|
}
|
|
|
|
static GtkTreeModel *
|
|
create_items_model (void)
|
|
{
|
|
gint i = 0;
|
|
GtkListStore *model;
|
|
GtkTreeIter iter;
|
|
|
|
/* create array */
|
|
articles = g_array_sized_new (FALSE, FALSE, sizeof (Item), 1);
|
|
|
|
add_items ();
|
|
|
|
/* create list store */
|
|
model = gtk_list_store_new (NUM_ITEM_COLUMNS, G_TYPE_INT, G_TYPE_STRING,
|
|
G_TYPE_INT, G_TYPE_BOOLEAN);
|
|
|
|
/* add items */
|
|
for (i = 0; i < articles->len; i++)
|
|
{
|
|
gtk_list_store_append (model, &iter);
|
|
|
|
gtk_list_store_set (model, &iter,
|
|
COLUMN_ITEM_NUMBER,
|
|
g_array_index (articles, Item, i).number,
|
|
COLUMN_ITEM_PRODUCT,
|
|
g_array_index (articles, Item, i).product,
|
|
COLUMN_ITEM_YUMMY,
|
|
g_array_index (articles, Item, i).yummy,
|
|
-1);
|
|
}
|
|
|
|
return GTK_TREE_MODEL (model);
|
|
}
|
|
|
|
static GtkTreeModel *
|
|
create_numbers_model (void)
|
|
{
|
|
#define N_NUMBERS 10
|
|
gint i = 0;
|
|
GtkListStore *model;
|
|
GtkTreeIter iter;
|
|
|
|
/* create list store */
|
|
model = gtk_list_store_new (NUM_NUMBER_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
|
|
|
|
/* add numbers */
|
|
for (i = 0; i < N_NUMBERS; i++)
|
|
{
|
|
char str[2];
|
|
|
|
str[0] = '0' + i;
|
|
str[1] = '\0';
|
|
|
|
gtk_list_store_append (model, &iter);
|
|
|
|
gtk_list_store_set (model, &iter,
|
|
COLUMN_NUMBER_TEXT, str,
|
|
-1);
|
|
}
|
|
|
|
return GTK_TREE_MODEL (model);
|
|
|
|
#undef N_NUMBERS
|
|
}
|
|
|
|
static void
|
|
add_item (GtkWidget *button, gpointer data)
|
|
{
|
|
Item foo;
|
|
GtkTreeIter current, iter;
|
|
GtkTreePath *path;
|
|
GtkTreeModel *model;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeView *treeview = (GtkTreeView *)data;
|
|
|
|
g_return_if_fail (articles != NULL);
|
|
|
|
foo.number = 0;
|
|
foo.product = g_strdup ("Description here");
|
|
foo.yummy = 50;
|
|
g_array_append_vals (articles, &foo, 1);
|
|
|
|
/* Insert a new row below the current one */
|
|
gtk_tree_view_get_cursor (treeview, &path, NULL);
|
|
model = gtk_tree_view_get_model (treeview);
|
|
if (path)
|
|
{
|
|
gtk_tree_model_get_iter (model, ¤t, path);
|
|
gtk_tree_path_free (path);
|
|
gtk_list_store_insert_after (GTK_LIST_STORE (model), &iter, ¤t);
|
|
}
|
|
else
|
|
{
|
|
gtk_list_store_insert (GTK_LIST_STORE (model), &iter, -1);
|
|
}
|
|
|
|
/* Set the data for the new row */
|
|
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
|
|
COLUMN_ITEM_NUMBER, foo.number,
|
|
COLUMN_ITEM_PRODUCT, foo.product,
|
|
COLUMN_ITEM_YUMMY, foo.yummy,
|
|
-1);
|
|
|
|
/* Move focus to the new row */
|
|
path = gtk_tree_model_get_path (model, &iter);
|
|
column = gtk_tree_view_get_column (treeview, 0);
|
|
gtk_tree_view_set_cursor (treeview, path, column, FALSE);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
static void
|
|
remove_item (GtkWidget *widget, gpointer data)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeView *treeview = (GtkTreeView *)data;
|
|
GtkTreeModel *model = gtk_tree_view_get_model (treeview);
|
|
GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
|
|
|
|
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
|
|
{
|
|
gint i;
|
|
GtkTreePath *path;
|
|
|
|
path = gtk_tree_model_get_path (model, &iter);
|
|
i = gtk_tree_path_get_indices (path)[0];
|
|
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
|
|
|
|
g_array_remove_index (articles, i);
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
separator_row (GtkTreeModel *model,
|
|
GtkTreeIter *iter,
|
|
gpointer data)
|
|
{
|
|
GtkTreePath *path;
|
|
gint idx;
|
|
|
|
path = gtk_tree_model_get_path (model, iter);
|
|
idx = gtk_tree_path_get_indices (path)[0];
|
|
|
|
gtk_tree_path_free (path);
|
|
|
|
return idx == 5;
|
|
}
|
|
|
|
static void
|
|
editing_started (GtkCellRenderer *cell,
|
|
GtkCellEditable *editable,
|
|
const gchar *path,
|
|
gpointer data)
|
|
{
|
|
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (editable),
|
|
separator_row, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
cell_edited (GtkCellRendererText *cell,
|
|
const gchar *path_string,
|
|
const gchar *new_text,
|
|
gpointer data)
|
|
{
|
|
GtkTreeModel *model = (GtkTreeModel *)data;
|
|
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
|
|
GtkTreeIter iter;
|
|
|
|
gint column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
|
|
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
|
|
switch (column)
|
|
{
|
|
case COLUMN_ITEM_NUMBER:
|
|
{
|
|
gint i;
|
|
|
|
i = gtk_tree_path_get_indices (path)[0];
|
|
g_array_index (articles, Item, i).number = atoi (new_text);
|
|
|
|
gtk_list_store_set (GTK_LIST_STORE (model), &iter, column,
|
|
g_array_index (articles, Item, i).number, -1);
|
|
}
|
|
break;
|
|
|
|
case COLUMN_ITEM_PRODUCT:
|
|
{
|
|
gint i;
|
|
gchar *old_text;
|
|
|
|
gtk_tree_model_get (model, &iter, column, &old_text, -1);
|
|
g_free (old_text);
|
|
|
|
i = gtk_tree_path_get_indices (path)[0];
|
|
g_free (g_array_index (articles, Item, i).product);
|
|
g_array_index (articles, Item, i).product = g_strdup (new_text);
|
|
|
|
gtk_list_store_set (GTK_LIST_STORE (model), &iter, column,
|
|
g_array_index (articles, Item, i).product, -1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
static void
|
|
add_columns (GtkTreeView *treeview,
|
|
GtkTreeModel *items_model,
|
|
GtkTreeModel *numbers_model)
|
|
{
|
|
GtkCellRenderer *renderer;
|
|
|
|
/* number column */
|
|
renderer = gtk_cell_renderer_combo_new ();
|
|
g_object_set (renderer,
|
|
"model", numbers_model,
|
|
"text-column", COLUMN_NUMBER_TEXT,
|
|
"has-entry", FALSE,
|
|
"editable", TRUE,
|
|
NULL);
|
|
g_signal_connect (renderer, "edited",
|
|
G_CALLBACK (cell_edited), items_model);
|
|
g_signal_connect (renderer, "editing-started",
|
|
G_CALLBACK (editing_started), NULL);
|
|
g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (COLUMN_ITEM_NUMBER));
|
|
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
|
-1, "Number", renderer,
|
|
"text", COLUMN_ITEM_NUMBER,
|
|
NULL);
|
|
|
|
/* product column */
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
g_object_set (renderer,
|
|
"editable", TRUE,
|
|
NULL);
|
|
g_signal_connect (renderer, "edited",
|
|
G_CALLBACK (cell_edited), items_model);
|
|
g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (COLUMN_ITEM_PRODUCT));
|
|
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
|
-1, "Product", renderer,
|
|
"text", COLUMN_ITEM_PRODUCT,
|
|
NULL);
|
|
|
|
/* yummy column */
|
|
renderer = gtk_cell_renderer_progress_new ();
|
|
g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (COLUMN_ITEM_YUMMY));
|
|
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
|
-1, "Yummy", renderer,
|
|
"value", COLUMN_ITEM_YUMMY,
|
|
NULL);
|
|
}
|
|
|
|
GtkWidget *
|
|
do_editable_cells (GtkWidget *do_widget)
|
|
{
|
|
static GtkWidget *window = NULL;
|
|
|
|
if (!window)
|
|
{
|
|
GtkWidget *vbox;
|
|
GtkWidget *hbox;
|
|
GtkWidget *sw;
|
|
GtkWidget *treeview;
|
|
GtkWidget *button;
|
|
GtkTreeModel *items_model;
|
|
GtkTreeModel *numbers_model;
|
|
|
|
window = gtk_window_new ();
|
|
gtk_window_set_display (GTK_WINDOW (window),
|
|
gtk_widget_get_display (do_widget));
|
|
gtk_window_set_title (GTK_WINDOW (window), "Editable Cells");
|
|
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
gtk_widget_set_margin_start (vbox, 5);
|
|
gtk_widget_set_margin_end (vbox, 5);
|
|
gtk_widget_set_margin_top (vbox, 5);
|
|
gtk_widget_set_margin_bottom (vbox, 5);
|
|
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
|
|
|
gtk_box_append (GTK_BOX (vbox),
|
|
gtk_label_new ("Shopping list (you can edit the cells!)"));
|
|
|
|
sw = gtk_scrolled_window_new ();
|
|
gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
|
GTK_POLICY_AUTOMATIC,
|
|
GTK_POLICY_AUTOMATIC);
|
|
gtk_box_append (GTK_BOX (vbox), sw);
|
|
|
|
/* create models */
|
|
items_model = create_items_model ();
|
|
numbers_model = create_numbers_model ();
|
|
|
|
/* create tree view */
|
|
treeview = gtk_tree_view_new_with_model (items_model);
|
|
gtk_widget_set_vexpand (treeview, TRUE);
|
|
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
|
|
GTK_SELECTION_SINGLE);
|
|
|
|
add_columns (GTK_TREE_VIEW (treeview), items_model, numbers_model);
|
|
|
|
g_object_unref (numbers_model);
|
|
g_object_unref (items_model);
|
|
|
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), treeview);
|
|
|
|
/* some buttons */
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
|
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
|
|
gtk_box_append (GTK_BOX (vbox), hbox);
|
|
|
|
button = gtk_button_new_with_label ("Add item");
|
|
g_signal_connect (button, "clicked",
|
|
G_CALLBACK (add_item), treeview);
|
|
gtk_box_append (GTK_BOX (hbox), button);
|
|
|
|
button = gtk_button_new_with_label ("Remove item");
|
|
g_signal_connect (button, "clicked",
|
|
G_CALLBACK (remove_item), treeview);
|
|
gtk_box_append (GTK_BOX (hbox), button);
|
|
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 320, 200);
|
|
}
|
|
|
|
if (!gtk_widget_get_visible (window))
|
|
gtk_widget_show (window);
|
|
else
|
|
gtk_window_destroy (GTK_WINDOW (window));
|
|
|
|
return window;
|
|
}
|