1#include <gtk/gtk.h>
2#include <glib/gstdio.h>
3
4typedef struct {
5 GtkListBoxRow parent;
6 GtkWidget *box;
7 GtkWidget *revealer;
8 GtkWidget *check;
9} SelectableRow;
10
11typedef struct {
12 GtkListBoxRowClass parent_class;
13} SelectableRowClass;
14
15static GType selectable_row_get_type (void);
16G_DEFINE_TYPE (SelectableRow, selectable_row, GTK_TYPE_LIST_BOX_ROW)
17
18static void
19selectable_row_init (SelectableRow *row)
20{
21 row->box = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10);
22 row->revealer = gtk_revealer_new ();
23 gtk_revealer_set_transition_type (GTK_REVEALER (row->revealer), transition: GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT);
24 row->check = gtk_check_button_new ();
25 gtk_widget_set_margin_start (widget: row->check, margin: 10);
26 gtk_widget_set_margin_end (widget: row->check, margin: 10);
27 gtk_widget_set_margin_top (widget: row->check, margin: 10);
28 gtk_widget_set_margin_bottom (widget: row->check, margin: 10);
29
30 gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), child: row->box);
31 gtk_box_append (GTK_BOX (row->box), child: row->revealer);
32 gtk_revealer_set_child (GTK_REVEALER (row->revealer), child: row->check);
33}
34
35static void
36selectable_row_add (SelectableRow *row, GtkWidget *child)
37{
38 gtk_box_append (GTK_BOX (row->box), child);
39}
40
41static void
42update_selectable (GtkWidget *widget)
43{
44 SelectableRow *row = (SelectableRow *)widget;
45 GtkListBox *list;
46
47 list = GTK_LIST_BOX (gtk_widget_get_parent (widget));
48
49 if (gtk_list_box_get_selection_mode (box: list) != GTK_SELECTION_NONE)
50 gtk_revealer_set_reveal_child (GTK_REVEALER (row->revealer), TRUE);
51 else
52 gtk_revealer_set_reveal_child (GTK_REVEALER (row->revealer), FALSE);
53}
54
55static void
56update_selected (GtkWidget *widget)
57{
58 SelectableRow *row = (SelectableRow *)widget;
59
60 if (gtk_list_box_row_is_selected (GTK_LIST_BOX_ROW (row)))
61 {
62 gtk_check_button_set_active (GTK_CHECK_BUTTON (row->check), TRUE);
63 gtk_widget_unset_state_flags (widget, flags: GTK_STATE_FLAG_SELECTED);
64 }
65 else
66 gtk_check_button_set_active (GTK_CHECK_BUTTON (row->check), FALSE);
67}
68
69static void
70selectable_row_class_init (SelectableRowClass *class)
71{
72}
73
74static GtkWidget *
75selectable_row_new (void)
76{
77 return GTK_WIDGET (g_object_new (selectable_row_get_type (), NULL));
78}
79
80static void
81add_row (GtkWidget *list, int i)
82{
83 GtkWidget *row;
84 GtkWidget *label;
85 char *text;
86
87 row = selectable_row_new ();
88 text = g_strdup_printf (format: "Docker %d", i);
89 label = gtk_label_new (str: text);
90 gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START);
91 selectable_row_add (row: (SelectableRow*)row, child: label);
92 g_free (mem: text);
93
94 gtk_list_box_insert (GTK_LIST_BOX (list), child: row, position: -1);
95}
96
97static void
98selection_mode_enter (GtkButton *button, GtkBuilder *builder)
99{
100 GtkWidget *header;
101 GtkWidget *list;
102 GtkWidget *headerbutton;
103 GtkWidget *cancelbutton;
104 GtkWidget *selectbutton;
105 GtkWidget *titlestack;
106 GtkWidget *child;
107
108 header = GTK_WIDGET (gtk_builder_get_object (builder, "header"));
109 list = GTK_WIDGET (gtk_builder_get_object (builder, "list"));
110 headerbutton = GTK_WIDGET (gtk_builder_get_object (builder, "headerbutton"));
111 cancelbutton = GTK_WIDGET (gtk_builder_get_object (builder, "cancel-button"));
112 selectbutton = GTK_WIDGET (gtk_builder_get_object (builder, "select-button"));
113 titlestack = GTK_WIDGET (gtk_builder_get_object (builder, "titlestack"));
114
115 gtk_widget_add_css_class (widget: header, css_class: "selection-mode");
116 gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
117 gtk_widget_hide (widget: headerbutton);
118 gtk_widget_hide (widget: selectbutton);
119 gtk_widget_show (widget: cancelbutton);
120 gtk_stack_set_visible_child_name (GTK_STACK (titlestack), name: "selection");
121
122 gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (list), FALSE);
123 gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), mode: GTK_SELECTION_MULTIPLE);
124 for (child = gtk_widget_get_first_child (widget: list);
125 child != NULL;
126 child = gtk_widget_get_next_sibling (widget: child))
127 update_selectable (widget: child);
128}
129
130static void
131selection_mode_leave (GtkButton *button, GtkBuilder *builder)
132{
133 GtkWidget *header;
134 GtkWidget *list;
135 GtkWidget *headerbutton;
136 GtkWidget *cancelbutton;
137 GtkWidget *selectbutton;
138 GtkWidget *titlestack;
139 GtkWidget *child;
140
141 header = GTK_WIDGET (gtk_builder_get_object (builder, "header"));
142 list = GTK_WIDGET (gtk_builder_get_object (builder, "list"));
143 headerbutton = GTK_WIDGET (gtk_builder_get_object (builder, "headerbutton"));
144 cancelbutton = GTK_WIDGET (gtk_builder_get_object (builder, "cancel-button"));
145 selectbutton = GTK_WIDGET (gtk_builder_get_object (builder, "select-button"));
146 titlestack = GTK_WIDGET (gtk_builder_get_object (builder, "titlestack"));
147
148 gtk_widget_remove_css_class (widget: header, css_class: "selection-mode");
149 gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
150 gtk_widget_show (widget: headerbutton);
151 gtk_widget_show (widget: selectbutton);
152 gtk_widget_hide (widget: cancelbutton);
153 gtk_stack_set_visible_child_name (GTK_STACK (titlestack), name: "title");
154
155 gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (list), TRUE);
156 gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), mode: GTK_SELECTION_NONE);
157 for (child = gtk_widget_get_first_child (widget: list);
158 child != NULL;
159 child = gtk_widget_get_next_sibling (widget: child))
160 update_selectable (widget: child);
161}
162
163static void
164select_all (GAction *action, GVariant *param, GtkWidget *list)
165{
166 gtk_list_box_select_all (GTK_LIST_BOX (list));
167}
168
169static void
170select_none (GAction *action, GVariant *param, GtkWidget *list)
171{
172 gtk_list_box_unselect_all (GTK_LIST_BOX (list));
173}
174
175static void
176selected_rows_changed (GtkListBox *list)
177{
178 GtkWidget *child;
179
180 for (child = gtk_widget_get_first_child (GTK_WIDGET (list));
181 child != NULL;
182 child = gtk_widget_get_next_sibling (widget: child))
183 update_selected (widget: child);
184}
185
186int
187main (int argc, char *argv[])
188{
189 GtkBuilder *builder;
190 GtkWidget *window;
191 GtkWidget *list;
192 GtkWidget *button;
193 int i;
194 GSimpleActionGroup *group;
195 GSimpleAction *action;
196
197#ifdef GTK_SRCDIR
198 g_chdir (GTK_SRCDIR);
199#endif
200
201 gtk_init ();
202
203 builder = gtk_builder_new_from_file (filename: "selectionmode.ui");
204 window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
205 list = GTK_WIDGET (gtk_builder_get_object (builder, "list"));
206
207 group = g_simple_action_group_new ();
208 action = g_simple_action_new (name: "select-all", NULL);
209 g_signal_connect (action, "activate", G_CALLBACK (select_all), list);
210 g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action));
211
212 action = g_simple_action_new (name: "select-none", NULL);
213 g_signal_connect (action, "activate", G_CALLBACK (select_none), list);
214 g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action));
215
216 gtk_widget_insert_action_group (widget: window, name: "win", G_ACTION_GROUP (group));
217
218 for (i = 0; i < 10; i++)
219 add_row (list, i);
220
221 button = GTK_WIDGET (gtk_builder_get_object (builder, "select-button"));
222 g_signal_connect (button, "clicked", G_CALLBACK (selection_mode_enter), builder);
223 button = GTK_WIDGET (gtk_builder_get_object (builder, "cancel-button"));
224 g_signal_connect (button, "clicked", G_CALLBACK (selection_mode_leave), builder);
225
226 g_signal_connect (list, "selected-rows-changed", G_CALLBACK (selected_rows_changed), NULL);
227
228 gtk_widget_show (widget: window);
229
230 while (TRUE)
231 g_main_context_iteration (NULL, TRUE);
232
233 return 0;
234}
235

source code of gtk/tests/testselectionmode.c