1 | #include <gtk/gtk.h> |
2 | #include <glib/gstdio.h> |
3 | |
4 | typedef struct { |
5 | GtkListBoxRow parent; |
6 | GtkWidget *box; |
7 | GtkWidget *revealer; |
8 | GtkWidget *check; |
9 | } SelectableRow; |
10 | |
11 | typedef struct { |
12 | GtkListBoxRowClass parent_class; |
13 | } SelectableRowClass; |
14 | |
15 | static GType selectable_row_get_type (void); |
16 | G_DEFINE_TYPE (SelectableRow, selectable_row, GTK_TYPE_LIST_BOX_ROW) |
17 | |
18 | static void |
19 | selectable_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 | |
35 | static void |
36 | selectable_row_add (SelectableRow *row, GtkWidget *child) |
37 | { |
38 | gtk_box_append (GTK_BOX (row->box), child); |
39 | } |
40 | |
41 | static void |
42 | update_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 | |
55 | static void |
56 | update_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 | |
69 | static void |
70 | selectable_row_class_init (SelectableRowClass *class) |
71 | { |
72 | } |
73 | |
74 | static GtkWidget * |
75 | selectable_row_new (void) |
76 | { |
77 | return GTK_WIDGET (g_object_new (selectable_row_get_type (), NULL)); |
78 | } |
79 | |
80 | static void |
81 | add_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 | |
97 | static void |
98 | selection_mode_enter (GtkButton *button, GtkBuilder *builder) |
99 | { |
100 | GtkWidget *; |
101 | GtkWidget *list; |
102 | GtkWidget *; |
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 | |
130 | static void |
131 | selection_mode_leave (GtkButton *button, GtkBuilder *builder) |
132 | { |
133 | GtkWidget *; |
134 | GtkWidget *list; |
135 | GtkWidget *; |
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 | |
163 | static void |
164 | select_all (GAction *action, GVariant *param, GtkWidget *list) |
165 | { |
166 | gtk_list_box_select_all (GTK_LIST_BOX (list)); |
167 | } |
168 | |
169 | static void |
170 | select_none (GAction *action, GVariant *param, GtkWidget *list) |
171 | { |
172 | gtk_list_box_unselect_all (GTK_LIST_BOX (list)); |
173 | } |
174 | |
175 | static void |
176 | selected_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 | |
186 | int |
187 | main (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 | |