mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
d732c869c2
Add the names of the main widgets as keywords to our demos, but also things like "game". This helps finding relevant demos in our growing list. You can now for example type "label", and find the "error states" and "links" demos showing GtkLabel features.
456 lines
13 KiB
C
456 lines
13 KiB
C
/* Combo Boxes
|
|
* #Keywords: GtkCellRenderer
|
|
*
|
|
* The GtkComboBox widget allows to select one option out of a list.
|
|
* The GtkComboBoxEntry additionally allows the user to enter a value
|
|
* that is not in the list of options.
|
|
*
|
|
* How the options are displayed is controlled by cell renderers.
|
|
*/
|
|
|
|
#include <glib/gi18n.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
enum
|
|
{
|
|
ICON_NAME_COL,
|
|
TEXT_COL
|
|
};
|
|
|
|
static GtkTreeModel *
|
|
create_icon_store (void)
|
|
{
|
|
const char *icon_names[6] = {
|
|
"dialog-warning",
|
|
"process-stop",
|
|
"document-new",
|
|
"edit-clear",
|
|
NULL,
|
|
"document-open"
|
|
};
|
|
const char *labels[6] = {
|
|
N_("Warning"),
|
|
N_("Stop"),
|
|
N_("New"),
|
|
N_("Clear"),
|
|
NULL,
|
|
N_("Open")
|
|
};
|
|
|
|
GtkTreeIter iter;
|
|
GtkListStore *store;
|
|
int i;
|
|
|
|
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (icon_names); i++)
|
|
{
|
|
if (icon_names[i])
|
|
{
|
|
gtk_list_store_append (store, &iter);
|
|
gtk_list_store_set (store, &iter,
|
|
ICON_NAME_COL, icon_names[i],
|
|
TEXT_COL, _(labels[i]),
|
|
-1);
|
|
}
|
|
else
|
|
{
|
|
gtk_list_store_append (store, &iter);
|
|
gtk_list_store_set (store, &iter,
|
|
ICON_NAME_COL, NULL,
|
|
TEXT_COL, "separator",
|
|
-1);
|
|
}
|
|
}
|
|
|
|
return GTK_TREE_MODEL (store);
|
|
}
|
|
|
|
/* A GtkCellLayoutDataFunc that demonstrates how one can control
|
|
* sensitivity of rows. This particular function does nothing
|
|
* useful and just makes the second row insensitive.
|
|
*/
|
|
static void
|
|
set_sensitive (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
gpointer data)
|
|
{
|
|
GtkTreePath *path;
|
|
int *indices;
|
|
gboolean sensitive;
|
|
|
|
path = gtk_tree_model_get_path (tree_model, iter);
|
|
indices = gtk_tree_path_get_indices (path);
|
|
sensitive = indices[0] != 1;
|
|
gtk_tree_path_free (path);
|
|
|
|
g_object_set (cell, "sensitive", sensitive, NULL);
|
|
}
|
|
|
|
/* A GtkTreeViewRowSeparatorFunc that demonstrates how rows can be
|
|
* rendered as separators. This particular function does nothing
|
|
* useful and just turns the fourth row into a separator.
|
|
*/
|
|
static gboolean
|
|
is_separator (GtkTreeModel *model,
|
|
GtkTreeIter *iter,
|
|
gpointer data)
|
|
{
|
|
GtkTreePath *path;
|
|
gboolean result;
|
|
|
|
path = gtk_tree_model_get_path (model, iter);
|
|
result = gtk_tree_path_get_indices (path)[0] == 4;
|
|
gtk_tree_path_free (path);
|
|
|
|
return result;
|
|
}
|
|
|
|
static GtkTreeModel *
|
|
create_capital_store (void)
|
|
{
|
|
struct {
|
|
const char *group;
|
|
const char *capital;
|
|
} capitals[] = {
|
|
{ "A - B", NULL },
|
|
{ NULL, "Albany" },
|
|
{ NULL, "Annapolis" },
|
|
{ NULL, "Atlanta" },
|
|
{ NULL, "Augusta" },
|
|
{ NULL, "Austin" },
|
|
{ NULL, "Baton Rouge" },
|
|
{ NULL, "Bismarck" },
|
|
{ NULL, "Boise" },
|
|
{ NULL, "Boston" },
|
|
{ "C - D", NULL },
|
|
{ NULL, "Carson City" },
|
|
{ NULL, "Charleston" },
|
|
{ NULL, "Cheyenne" },
|
|
{ NULL, "Columbia" },
|
|
{ NULL, "Columbus" },
|
|
{ NULL, "Concord" },
|
|
{ NULL, "Denver" },
|
|
{ NULL, "Des Moines" },
|
|
{ NULL, "Dover" },
|
|
{ "E - J", NULL },
|
|
{ NULL, "Frankfort" },
|
|
{ NULL, "Harrisburg" },
|
|
{ NULL, "Hartford" },
|
|
{ NULL, "Helena" },
|
|
{ NULL, "Honolulu" },
|
|
{ NULL, "Indianapolis" },
|
|
{ NULL, "Jackson" },
|
|
{ NULL, "Jefferson City" },
|
|
{ NULL, "Juneau" },
|
|
{ "K - O", NULL },
|
|
{ NULL, "Lansing" },
|
|
{ NULL, "Lincoln" },
|
|
{ NULL, "Little Rock" },
|
|
{ NULL, "Madison" },
|
|
{ NULL, "Montgomery" },
|
|
{ NULL, "Montpelier" },
|
|
{ NULL, "Nashville" },
|
|
{ NULL, "Oklahoma City" },
|
|
{ NULL, "Olympia" },
|
|
{ "P - S", NULL },
|
|
{ NULL, "Phoenix" },
|
|
{ NULL, "Pierre" },
|
|
{ NULL, "Providence" },
|
|
{ NULL, "Raleigh" },
|
|
{ NULL, "Richmond" },
|
|
{ NULL, "Sacramento" },
|
|
{ NULL, "Salem" },
|
|
{ NULL, "Salt Lake City" },
|
|
{ NULL, "Santa Fe" },
|
|
{ NULL, "Springfield" },
|
|
{ NULL, "St. Paul" },
|
|
{ "T - Z", NULL },
|
|
{ NULL, "Tallahassee" },
|
|
{ NULL, "Topeka" },
|
|
{ NULL, "Trenton" },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
GtkTreeIter iter, iter2;
|
|
GtkTreeStore *store;
|
|
int i;
|
|
|
|
store = gtk_tree_store_new (1, G_TYPE_STRING);
|
|
|
|
for (i = 0; capitals[i].group || capitals[i].capital; i++)
|
|
{
|
|
if (capitals[i].group)
|
|
{
|
|
gtk_tree_store_append (store, &iter, NULL);
|
|
gtk_tree_store_set (store, &iter, 0, capitals[i].group, -1);
|
|
}
|
|
else if (capitals[i].capital)
|
|
{
|
|
gtk_tree_store_append (store, &iter2, &iter);
|
|
gtk_tree_store_set (store, &iter2, 0, capitals[i].capital, -1);
|
|
}
|
|
}
|
|
|
|
return GTK_TREE_MODEL (store);
|
|
}
|
|
|
|
static void
|
|
is_capital_sensitive (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
gpointer data)
|
|
{
|
|
gboolean sensitive;
|
|
|
|
sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
|
|
|
|
g_object_set (cell, "sensitive", sensitive, NULL);
|
|
}
|
|
|
|
static void
|
|
fill_combo_entry (GtkWidget *combo)
|
|
{
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "One");
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Two");
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "2\302\275");
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Three");
|
|
}
|
|
|
|
|
|
/* A simple validating entry */
|
|
|
|
#define TYPE_MASK_ENTRY (mask_entry_get_type ())
|
|
#define MASK_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MASK_ENTRY, MaskEntry))
|
|
#define MASK_ENTRY_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), TYPE_MASK_ENTRY, MaskEntryClass))
|
|
#define IS_MASK_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MASK_ENTRY))
|
|
#define IS_MASK_ENTRY_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TYPE_MASK_ENTRY))
|
|
#define MASK_ENTRY_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), TYPE_MASK_ENTRY, MaskEntryClass))
|
|
|
|
|
|
typedef struct _MaskEntry MaskEntry;
|
|
struct _MaskEntry
|
|
{
|
|
GtkEntry entry;
|
|
const char *mask;
|
|
};
|
|
|
|
typedef struct _MaskEntryClass MaskEntryClass;
|
|
struct _MaskEntryClass
|
|
{
|
|
GtkEntryClass parent_class;
|
|
};
|
|
|
|
|
|
static void mask_entry_editable_init (GtkEditableInterface *iface);
|
|
|
|
static GType mask_entry_get_type (void);
|
|
G_DEFINE_TYPE_WITH_CODE (MaskEntry, mask_entry, GTK_TYPE_ENTRY,
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
|
|
mask_entry_editable_init));
|
|
|
|
|
|
static void
|
|
mask_entry_set_background (MaskEntry *entry)
|
|
{
|
|
if (entry->mask)
|
|
{
|
|
if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
|
|
{
|
|
PangoAttrList *attrs;
|
|
|
|
attrs = pango_attr_list_new ();
|
|
pango_attr_list_insert (attrs, pango_attr_foreground_new (65535, 32767, 32767));
|
|
gtk_entry_set_attributes (GTK_ENTRY (entry), attrs);
|
|
pango_attr_list_unref (attrs);
|
|
return;
|
|
}
|
|
}
|
|
|
|
gtk_entry_set_attributes (GTK_ENTRY (entry), NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
mask_entry_changed (GtkEditable *editable)
|
|
{
|
|
mask_entry_set_background (MASK_ENTRY (editable));
|
|
}
|
|
|
|
|
|
static void
|
|
mask_entry_init (MaskEntry *entry)
|
|
{
|
|
entry->mask = NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
mask_entry_class_init (MaskEntryClass *klass)
|
|
{ }
|
|
|
|
|
|
static void
|
|
mask_entry_editable_init (GtkEditableInterface *iface)
|
|
{
|
|
iface->changed = mask_entry_changed;
|
|
}
|
|
|
|
|
|
GtkWidget *
|
|
do_combobox (GtkWidget *do_widget)
|
|
{
|
|
static GtkWidget *window = NULL;
|
|
GtkWidget *vbox, *frame, *box, *combo, *entry;
|
|
GtkTreeModel *model;
|
|
GtkCellRenderer *renderer;
|
|
GtkTreePath *path;
|
|
GtkTreeIter iter;
|
|
|
|
if (!window)
|
|
{
|
|
window = gtk_window_new ();
|
|
gtk_window_set_display (GTK_WINDOW (window),
|
|
gtk_widget_get_display (do_widget));
|
|
gtk_window_set_title (GTK_WINDOW (window), "Combo Boxes");
|
|
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
|
gtk_widget_set_margin_start (vbox, 10);
|
|
gtk_widget_set_margin_end (vbox, 10);
|
|
gtk_widget_set_margin_top (vbox, 10);
|
|
gtk_widget_set_margin_bottom (vbox, 10);
|
|
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
|
|
|
/* A combobox demonstrating cell renderers, separators and
|
|
* insensitive rows
|
|
*/
|
|
frame = gtk_frame_new ("Items with icons");
|
|
gtk_box_append (GTK_BOX (vbox), frame);
|
|
|
|
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_widget_set_margin_start (box, 5);
|
|
gtk_widget_set_margin_end (box, 5);
|
|
gtk_widget_set_margin_top (box, 5);
|
|
gtk_widget_set_margin_bottom (box, 5);
|
|
gtk_frame_set_child (GTK_FRAME (frame), box);
|
|
|
|
model = create_icon_store ();
|
|
combo = gtk_combo_box_new_with_model (model);
|
|
g_object_unref (model);
|
|
gtk_box_append (GTK_BOX (box), combo);
|
|
|
|
renderer = gtk_cell_renderer_pixbuf_new ();
|
|
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
|
|
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
|
|
"icon-name", ICON_NAME_COL,
|
|
NULL);
|
|
|
|
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
|
|
renderer,
|
|
set_sensitive,
|
|
NULL, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
|
|
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
|
|
"text", TEXT_COL,
|
|
NULL);
|
|
|
|
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
|
|
renderer,
|
|
set_sensitive,
|
|
NULL, NULL);
|
|
|
|
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
|
|
is_separator, NULL, NULL);
|
|
|
|
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
|
|
|
|
/* A combobox demonstrating trees.
|
|
*/
|
|
frame = gtk_frame_new ("Where are we ?");
|
|
gtk_box_append (GTK_BOX (vbox), frame);
|
|
|
|
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_widget_set_margin_start (box, 5);
|
|
gtk_widget_set_margin_end (box, 5);
|
|
gtk_widget_set_margin_top (box, 5);
|
|
gtk_widget_set_margin_bottom (box, 5);
|
|
gtk_frame_set_child (GTK_FRAME (frame), box);
|
|
|
|
model = create_capital_store ();
|
|
combo = gtk_combo_box_new_with_model (model);
|
|
g_object_unref (model);
|
|
gtk_box_append (GTK_BOX (box), combo);
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
|
|
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
|
|
"text", 0,
|
|
NULL);
|
|
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
|
|
renderer,
|
|
is_capital_sensitive,
|
|
NULL, NULL);
|
|
|
|
path = gtk_tree_path_new_from_indices (0, 8, -1);
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
gtk_tree_path_free (path);
|
|
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
|
|
|
|
/* A GtkComboBoxEntry with validation */
|
|
frame = gtk_frame_new ("Editable");
|
|
gtk_box_append (GTK_BOX (vbox), frame);
|
|
|
|
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_widget_set_margin_start (box, 5);
|
|
gtk_widget_set_margin_end (box, 5);
|
|
gtk_widget_set_margin_top (box, 5);
|
|
gtk_widget_set_margin_bottom (box, 5);
|
|
gtk_frame_set_child (GTK_FRAME (frame), box);
|
|
|
|
combo = gtk_combo_box_text_new_with_entry ();
|
|
fill_combo_entry (combo);
|
|
gtk_box_append (GTK_BOX (box), combo);
|
|
|
|
entry = g_object_new (TYPE_MASK_ENTRY, NULL);
|
|
MASK_ENTRY (entry)->mask = "^([0-9]*|One|Two|2\302\275|Three)$";
|
|
|
|
gtk_combo_box_set_child (GTK_COMBO_BOX (combo), entry);
|
|
|
|
/* A combobox with string IDs */
|
|
frame = gtk_frame_new ("String IDs");
|
|
gtk_box_append (GTK_BOX (vbox), frame);
|
|
|
|
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_widget_set_margin_start (box, 5);
|
|
gtk_widget_set_margin_end (box, 5);
|
|
gtk_widget_set_margin_top (box, 5);
|
|
gtk_widget_set_margin_bottom (box, 5);
|
|
gtk_frame_set_child (GTK_FRAME (frame), box);
|
|
|
|
combo = gtk_combo_box_text_new ();
|
|
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "never", "Not visible");
|
|
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "when-active", "Visible when active");
|
|
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "always", "Always visible");
|
|
gtk_box_append (GTK_BOX (box), combo);
|
|
|
|
entry = gtk_entry_new ();
|
|
g_object_bind_property (combo, "active-id",
|
|
entry, "text",
|
|
G_BINDING_BIDIRECTIONAL);
|
|
gtk_box_append (GTK_BOX (box), entry);
|
|
}
|
|
|
|
if (!gtk_widget_get_visible (window))
|
|
gtk_widget_show (window);
|
|
else
|
|
gtk_window_destroy (GTK_WINDOW (window));
|
|
|
|
return window;
|
|
}
|