1/* testiconview-keynav.c
2 * Copyright (C) 2010 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Author: Matthias Clasen
18 */
19
20/*
21 * This example demonstrates how to use the keynav-failed signal to
22 * extend arrow keynav over adjacent icon views. This can be used when
23 * grouping items.
24 */
25
26#include <gtk/gtk.h>
27
28static GtkTreeModel *
29get_model (void)
30{
31 static GtkListStore *store;
32 GtkTreeIter iter;
33
34 if (store)
35 return (GtkTreeModel *) g_object_ref (store);
36
37 store = gtk_list_store_new (n_columns: 1, G_TYPE_STRING);
38
39 gtk_list_store_append (list_store: store, iter: &iter);
40 gtk_list_store_set (list_store: store, iter: &iter, 0, "One", -1);
41 gtk_list_store_append (list_store: store, iter: &iter);
42 gtk_list_store_set (list_store: store, iter: &iter, 0, "Two", -1);
43 gtk_list_store_append (list_store: store, iter: &iter);
44 gtk_list_store_set (list_store: store, iter: &iter, 0, "Three", -1);
45 gtk_list_store_append (list_store: store, iter: &iter);
46 gtk_list_store_set (list_store: store, iter: &iter, 0, "Four", -1);
47 gtk_list_store_append (list_store: store, iter: &iter);
48 gtk_list_store_set (list_store: store, iter: &iter, 0, "Five", -1);
49 gtk_list_store_append (list_store: store, iter: &iter);
50 gtk_list_store_set (list_store: store, iter: &iter, 0, "Six", -1);
51 gtk_list_store_append (list_store: store, iter: &iter);
52 gtk_list_store_set (list_store: store, iter: &iter, 0, "Seven", -1);
53 gtk_list_store_append (list_store: store, iter: &iter);
54 gtk_list_store_set (list_store: store, iter: &iter, 0, "Eight", -1);
55
56 return (GtkTreeModel *) store;
57}
58
59static gboolean
60visible_func (GtkTreeModel *model,
61 GtkTreeIter *iter,
62 gpointer data)
63{
64 gboolean first = GPOINTER_TO_INT (data);
65 gboolean visible;
66 GtkTreePath *path;
67
68 path = gtk_tree_model_get_path (tree_model: model, iter);
69
70 if (gtk_tree_path_get_indices (path)[0] < 4)
71 visible = first;
72 else
73 visible = !first;
74
75 gtk_tree_path_free (path);
76
77 return visible;
78}
79
80static GtkTreeModel *
81get_filter_model (gboolean first)
82{
83 GtkTreeModelFilter *model;
84
85 model = (GtkTreeModelFilter *)gtk_tree_model_filter_new (child_model: get_model (), NULL);
86
87 gtk_tree_model_filter_set_visible_func (filter: model, func: visible_func, GINT_TO_POINTER (first), NULL);
88
89 return (GtkTreeModel *) model;
90}
91
92static GtkWidget *
93get_view (gboolean first)
94{
95 GtkWidget *view;
96
97 view = gtk_icon_view_new_with_model (model: get_filter_model (first));
98 gtk_icon_view_set_text_column (GTK_ICON_VIEW (view), column: 0);
99 gtk_widget_set_size_request (widget: view, width: 0, height: -1);
100
101 return view;
102}
103
104typedef struct
105{
106 GtkWidget *header1;
107 GtkWidget *view1;
108 GtkWidget *header2;
109 GtkWidget *view2;
110} Views;
111
112static gboolean
113keynav_failed (GtkWidget *view,
114 GtkDirectionType direction,
115 Views *views)
116{
117 GtkTreePath *path;
118 GtkTreeModel *model;
119 GtkTreeIter iter;
120 int col;
121 GtkTreePath *sel;
122
123 if (view == views->view1 && direction == GTK_DIR_DOWN)
124 {
125 if (gtk_icon_view_get_cursor (GTK_ICON_VIEW (views->view1), path: &path, NULL))
126 {
127 col = gtk_icon_view_get_item_column (GTK_ICON_VIEW (views->view1), path);
128 gtk_tree_path_free (path);
129
130 sel = NULL;
131 model = gtk_icon_view_get_model (GTK_ICON_VIEW (views->view2));
132 gtk_tree_model_get_iter_first (tree_model: model, iter: &iter);
133 do {
134 path = gtk_tree_model_get_path (tree_model: model, iter: &iter);
135 if (gtk_icon_view_get_item_column (GTK_ICON_VIEW (views->view2), path) == col)
136 {
137 sel = path;
138 break;
139 }
140 } while (gtk_tree_model_iter_next (tree_model: model, iter: &iter));
141
142 gtk_icon_view_set_cursor (GTK_ICON_VIEW (views->view2), path: sel, NULL, FALSE);
143 gtk_tree_path_free (path: sel);
144 }
145 gtk_widget_grab_focus (widget: views->view2);
146 return TRUE;
147 }
148
149 if (view == views->view2 && direction == GTK_DIR_UP)
150 {
151 if (gtk_icon_view_get_cursor (GTK_ICON_VIEW (views->view2), path: &path, NULL))
152 {
153 col = gtk_icon_view_get_item_column (GTK_ICON_VIEW (views->view2), path);
154 gtk_tree_path_free (path);
155
156 sel = NULL;
157 model = gtk_icon_view_get_model (GTK_ICON_VIEW (views->view1));
158 gtk_tree_model_get_iter_first (tree_model: model, iter: &iter);
159 do {
160 path = gtk_tree_model_get_path (tree_model: model, iter: &iter);
161 if (gtk_icon_view_get_item_column (GTK_ICON_VIEW (views->view1), path) == col)
162 {
163 if (sel)
164 gtk_tree_path_free (path: sel);
165 sel = path;
166 }
167 else
168 gtk_tree_path_free (path);
169 } while (gtk_tree_model_iter_next (tree_model: model, iter: &iter));
170
171 gtk_icon_view_set_cursor (GTK_ICON_VIEW (views->view1), path: sel, NULL, FALSE);
172 gtk_tree_path_free (path: sel);
173 }
174 gtk_widget_grab_focus (widget: views->view1);
175 return TRUE;
176 }
177
178 return FALSE;
179}
180
181static void
182focus_changed (GtkWidget *view,
183 GParamSpec *pspec,
184 gpointer data)
185{
186 if (gtk_widget_has_focus (widget: view))
187 {
188 GtkTreePath *path;
189
190 if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), path: &path, NULL))
191 {
192 path = gtk_tree_path_new_from_indices (first_index: 0, -1);
193 gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE);
194 }
195
196 gtk_icon_view_select_path (GTK_ICON_VIEW (view), path);
197 gtk_tree_path_free (path);
198 }
199 else
200 {
201 gtk_icon_view_unselect_all (GTK_ICON_VIEW (view));
202 }
203}
204
205#define CSS \
206 "GtkWindow {\n" \
207 " background-color: @base_color;\n" \
208 "}\n"
209
210static void
211set_styles (void)
212{
213 GtkCssProvider *provider;
214
215 provider = gtk_css_provider_new ();
216
217 gtk_css_provider_load_from_data (css_provider: provider, CSS, length: -1);
218
219 gtk_style_context_add_provider_for_display (display: gdk_display_get_default (),
220 GTK_STYLE_PROVIDER (provider),
221 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
222}
223
224int
225main (int argc, char *argv[])
226{
227 GtkWidget *window;
228 GtkWidget *vbox;
229 Views views;
230
231 gtk_init ();
232
233 set_styles ();
234
235 window = gtk_window_new ();
236 vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 0);
237 gtk_window_set_child (GTK_WINDOW (window), child: vbox);
238
239 views.header1 = g_object_new (GTK_TYPE_LABEL,
240 first_property_name: "label", "<b>Group 1</b>",
241 "use-markup", TRUE,
242 "xalign", 0.0,
243 NULL);
244 views.view1 = get_view (TRUE);
245 views.header2 = g_object_new (GTK_TYPE_LABEL,
246 first_property_name: "label", "<b>Group 2</b>",
247 "use-markup", TRUE,
248 "xalign", 0.0,
249 NULL);
250 views.view2 = get_view (FALSE);
251
252 g_signal_connect (views.view1, "keynav-failed", G_CALLBACK (keynav_failed), &views);
253 g_signal_connect (views.view2, "keynav-failed", G_CALLBACK (keynav_failed), &views);
254 g_signal_connect (views.view1, "notify::has-focus", G_CALLBACK (focus_changed), &views);
255 g_signal_connect (views.view2, "notify::has-focus", G_CALLBACK (focus_changed), &views);
256
257 gtk_box_append (GTK_BOX (vbox), child: views.header1);
258 gtk_box_append (GTK_BOX (vbox), child: views.view1);
259 gtk_box_append (GTK_BOX (vbox), child: views.header2);
260 gtk_box_append (GTK_BOX (vbox), child: views.view2);
261
262 gtk_widget_show (widget: window);
263
264 while (TRUE)
265 g_main_context_iteration (NULL, TRUE);
266
267 return 0;
268}
269
270

source code of gtk/tests/testiconview-keynav.c