]> Pileus Git - ~andy/gtk/blob - tests/testiconview-keynav.c
928fbc5d93ac8363009aa674a799f74ba7fd0bb3
[~andy/gtk] / tests / testiconview-keynav.c
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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Author: Matthias Clasen
20  */
21
22 /*
23  * This example demonstrates how to use the keynav-failed signal to
24  * extend arrow keynav over adjacent icon views. This can be used when
25  * grouping items.
26  */
27
28 #include <gtk/gtk.h>
29
30 static GtkTreeModel *
31 get_model (void)
32 {
33   static GtkListStore *store;
34   GtkTreeIter iter;
35
36   if (store)
37     return (GtkTreeModel *) g_object_ref (store);
38
39   store = gtk_list_store_new (1, G_TYPE_STRING);
40
41   gtk_list_store_append (store, &iter);
42   gtk_list_store_set (store, &iter, 0, "One", -1);
43   gtk_list_store_append (store, &iter);
44   gtk_list_store_set (store, &iter, 0, "Two", -1);
45   gtk_list_store_append (store, &iter);
46   gtk_list_store_set (store, &iter, 0, "Three", -1);
47   gtk_list_store_append (store, &iter);
48   gtk_list_store_set (store, &iter, 0, "Four", -1);
49   gtk_list_store_append (store, &iter);
50   gtk_list_store_set (store, &iter, 0, "Five", -1);
51   gtk_list_store_append (store, &iter);
52   gtk_list_store_set (store, &iter, 0, "Six", -1);
53   gtk_list_store_append (store, &iter);
54   gtk_list_store_set (store, &iter, 0, "Seven", -1);
55   gtk_list_store_append (store, &iter);
56   gtk_list_store_set (store, &iter, 0, "Eight", -1);
57
58   return (GtkTreeModel *) store;
59 }
60
61 static gboolean
62 visible_func (GtkTreeModel *model,
63               GtkTreeIter  *iter,
64               gpointer      data)
65 {
66   gboolean first = GPOINTER_TO_INT (data);
67   gboolean visible;
68   GtkTreePath *path;
69
70   path = gtk_tree_model_get_path (model, iter);
71
72   if (gtk_tree_path_get_indices (path)[0] < 4)
73     visible = first;
74   else
75     visible = !first;
76
77   gtk_tree_path_free (path);
78
79   return visible;
80 }
81
82 GtkTreeModel *
83 get_filter_model (gboolean first)
84 {
85   GtkTreeModelFilter *model;
86
87   model = (GtkTreeModelFilter *)gtk_tree_model_filter_new (get_model (), NULL);
88
89   gtk_tree_model_filter_set_visible_func (model, visible_func, GINT_TO_POINTER (first), NULL);
90
91   return (GtkTreeModel *) model;
92 }
93
94 static GtkWidget *
95 get_view (gboolean first)
96 {
97   GtkWidget *view;
98
99   view = gtk_icon_view_new_with_model (get_filter_model (first));
100   gtk_icon_view_set_text_column (GTK_ICON_VIEW (view), 0);
101   gtk_widget_set_size_request (view, 0, -1);
102
103   return view;
104 }
105
106 typedef struct
107 {
108   GtkWidget *header1;
109   GtkWidget *view1;
110   GtkWidget *header2;
111   GtkWidget *view2;
112 } Views;
113
114 static gboolean
115 keynav_failed (GtkWidget        *view,
116                GtkDirectionType  direction,
117                Views            *views)
118 {
119   GtkTreePath *path;
120   GtkTreeModel *model;
121   GtkTreeIter iter;
122   gint col;
123   GtkTreePath *sel;
124
125   if (view == views->view1 && direction == GTK_DIR_DOWN)
126     {
127       if (gtk_icon_view_get_cursor (GTK_ICON_VIEW (views->view1), &path, NULL))
128         {
129           col = gtk_icon_view_get_item_column (GTK_ICON_VIEW (views->view1), path);
130           gtk_tree_path_free (path);
131
132           sel = NULL;
133           model = gtk_icon_view_get_model (GTK_ICON_VIEW (views->view2));
134           gtk_tree_model_get_iter_first (model, &iter);
135           do {
136             path = gtk_tree_model_get_path (model, &iter);
137             if (gtk_icon_view_get_item_column (GTK_ICON_VIEW (views->view2), path) == col)
138               {
139                 sel = path;
140                 break;
141               }
142           } while (gtk_tree_model_iter_next (model, &iter));
143
144           gtk_icon_view_set_cursor (GTK_ICON_VIEW (views->view2), sel, NULL, FALSE);
145           gtk_tree_path_free (sel);
146         }
147       gtk_widget_grab_focus (views->view2);
148       return TRUE;
149     }
150
151   if (view == views->view2 && direction == GTK_DIR_UP)
152     {
153       if (gtk_icon_view_get_cursor (GTK_ICON_VIEW (views->view2), &path, NULL))
154         {
155           col = gtk_icon_view_get_item_column (GTK_ICON_VIEW (views->view2), path);
156           gtk_tree_path_free (path);
157
158           sel = NULL;
159           model = gtk_icon_view_get_model (GTK_ICON_VIEW (views->view1));
160           gtk_tree_model_get_iter_first (model, &iter);
161           do {
162             path = gtk_tree_model_get_path (model, &iter);
163             if (gtk_icon_view_get_item_column (GTK_ICON_VIEW (views->view1), path) == col)
164               {
165                 if (sel)
166                   gtk_tree_path_free (sel);
167                 sel = path;
168               }
169             else
170               gtk_tree_path_free (path);
171           } while (gtk_tree_model_iter_next (model, &iter));
172
173           gtk_icon_view_set_cursor (GTK_ICON_VIEW (views->view1), sel, NULL, FALSE);
174           gtk_tree_path_free (sel);
175         }
176       gtk_widget_grab_focus (views->view1);
177       return TRUE;
178     }
179
180   return FALSE;
181 }
182
183 static gboolean
184 focus_out (GtkWidget     *view,
185            GdkEventFocus *event,
186            gpointer       data)
187 {
188   gtk_icon_view_unselect_all (GTK_ICON_VIEW (view));
189
190   return FALSE;
191 }
192
193 static gboolean
194 focus_in (GtkWidget     *view,
195           GdkEventFocus *event,
196           gpointer       data)
197 {
198   GtkTreePath *path;
199
200   if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL))
201     {
202       path = gtk_tree_path_new_from_indices (0, -1);
203       gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE);
204     }
205
206   gtk_icon_view_select_path (GTK_ICON_VIEW (view), path);
207   gtk_tree_path_free (path);
208
209   return FALSE;
210 }
211
212 static void
213 header_style_set (GtkWidget *widget,
214                   GtkStyle  *old_style)
215 {
216   GtkStyle *style;
217
218   style = gtk_widget_get_style (widget);
219
220   g_signal_handlers_block_by_func (widget, header_style_set, NULL);
221   gtk_widget_modify_bg (widget, GTK_STATE_NORMAL,
222                         &style->base[GTK_STATE_NORMAL]);
223   gtk_widget_modify_fg (widget, GTK_STATE_NORMAL,
224                         &style->text[GTK_STATE_NORMAL]);
225   g_signal_handlers_unblock_by_func (widget, header_style_set, NULL);
226 }
227
228 int
229 main (int argc, char *argv[])
230 {
231   GtkWidget *window;
232   GtkWidget *vbox;
233   Views views;
234
235   gtk_init (&argc, &argv);
236
237   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
238   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
239   gtk_container_add (GTK_CONTAINER (window), vbox);
240
241   views.header1 = g_object_new (GTK_TYPE_LABEL,
242                                 "label", "<b>Group 1</b>",
243                                 "use-markup", TRUE,
244                                 "xalign", 0.0,
245                                 NULL);
246   views.view1 = get_view (TRUE);
247   views.header2 = g_object_new (GTK_TYPE_LABEL,
248                                 "label", "<b>Group 2</b>",
249                                 "use-markup", TRUE,
250                                 "xalign", 0.0,
251                                 NULL);
252   views.view2 = get_view (FALSE);
253
254   g_signal_connect (views.view1, "keynav-failed",
255                     G_CALLBACK (keynav_failed), &views);
256   g_signal_connect (views.view2, "keynav-failed",
257                     G_CALLBACK (keynav_failed), &views);
258   g_signal_connect (views.view1, "focus-in-event",
259                     G_CALLBACK (focus_in), NULL);
260   g_signal_connect (views.view1, "focus-out-event",
261                     G_CALLBACK (focus_out), NULL);
262   g_signal_connect (views.view2, "focus-in-event",
263                     G_CALLBACK (focus_in), NULL);
264   g_signal_connect (views.view2, "focus-out-event",
265                     G_CALLBACK (focus_out), NULL);
266   g_signal_connect (views.header1, "style-set",
267                     G_CALLBACK (header_style_set), NULL);
268   g_signal_connect (views.header2, "style-set",
269                     G_CALLBACK (header_style_set), NULL);
270   g_signal_connect (window, "style-set",
271                     G_CALLBACK (header_style_set), NULL);
272
273   gtk_container_add (GTK_CONTAINER (vbox), views.header1);
274   gtk_container_add (GTK_CONTAINER (vbox), views.view1);
275   gtk_container_add (GTK_CONTAINER (vbox), views.header2);
276   gtk_container_add (GTK_CONTAINER (vbox), views.view2);
277
278   gtk_widget_show_all (window);
279
280   gtk_main ();
281
282   return 0;
283 }
284