]> Pileus Git - ~andy/gtk/blob - tests/testiconview-keynav.c
stylecontext: Do invalidation on first resize container
[~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, 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
28 static GtkTreeModel *
29 get_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 (1, G_TYPE_STRING);
38
39   gtk_list_store_append (store, &iter);
40   gtk_list_store_set (store, &iter, 0, "One", -1);
41   gtk_list_store_append (store, &iter);
42   gtk_list_store_set (store, &iter, 0, "Two", -1);
43   gtk_list_store_append (store, &iter);
44   gtk_list_store_set (store, &iter, 0, "Three", -1);
45   gtk_list_store_append (store, &iter);
46   gtk_list_store_set (store, &iter, 0, "Four", -1);
47   gtk_list_store_append (store, &iter);
48   gtk_list_store_set (store, &iter, 0, "Five", -1);
49   gtk_list_store_append (store, &iter);
50   gtk_list_store_set (store, &iter, 0, "Six", -1);
51   gtk_list_store_append (store, &iter);
52   gtk_list_store_set (store, &iter, 0, "Seven", -1);
53   gtk_list_store_append (store, &iter);
54   gtk_list_store_set (store, &iter, 0, "Eight", -1);
55
56   return (GtkTreeModel *) store;
57 }
58
59 static gboolean
60 visible_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 (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
80 GtkTreeModel *
81 get_filter_model (gboolean first)
82 {
83   GtkTreeModelFilter *model;
84
85   model = (GtkTreeModelFilter *)gtk_tree_model_filter_new (get_model (), NULL);
86
87   gtk_tree_model_filter_set_visible_func (model, visible_func, GINT_TO_POINTER (first), NULL);
88
89   return (GtkTreeModel *) model;
90 }
91
92 static GtkWidget *
93 get_view (gboolean first)
94 {
95   GtkWidget *view;
96
97   view = gtk_icon_view_new_with_model (get_filter_model (first));
98   gtk_icon_view_set_text_column (GTK_ICON_VIEW (view), 0);
99   gtk_widget_set_size_request (view, 0, -1);
100
101   return view;
102 }
103
104 typedef struct
105 {
106   GtkWidget *header1;
107   GtkWidget *view1;
108   GtkWidget *header2;
109   GtkWidget *view2;
110 } Views;
111
112 static gboolean
113 keynav_failed (GtkWidget        *view,
114                GtkDirectionType  direction,
115                Views            *views)
116 {
117   GtkTreePath *path;
118   GtkTreeModel *model;
119   GtkTreeIter iter;
120   gint 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, 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 (model, &iter);
133           do {
134             path = gtk_tree_model_get_path (model, &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 (model, &iter));
141
142           gtk_icon_view_set_cursor (GTK_ICON_VIEW (views->view2), sel, NULL, FALSE);
143           gtk_tree_path_free (sel);
144         }
145       gtk_widget_grab_focus (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, 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 (model, &iter);
159           do {
160             path = gtk_tree_model_get_path (model, &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 (sel);
165                 sel = path;
166               }
167             else
168               gtk_tree_path_free (path);
169           } while (gtk_tree_model_iter_next (model, &iter));
170
171           gtk_icon_view_set_cursor (GTK_ICON_VIEW (views->view1), sel, NULL, FALSE);
172           gtk_tree_path_free (sel);
173         }
174       gtk_widget_grab_focus (views->view1);
175       return TRUE;
176     }
177
178   return FALSE;
179 }
180
181 static gboolean
182 focus_out (GtkWidget     *view,
183            GdkEventFocus *event,
184            gpointer       data)
185 {
186   gtk_icon_view_unselect_all (GTK_ICON_VIEW (view));
187
188   return FALSE;
189 }
190
191 static gboolean
192 focus_in (GtkWidget     *view,
193           GdkEventFocus *event,
194           gpointer       data)
195 {
196   GtkTreePath *path;
197
198   if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL))
199     {
200       path = gtk_tree_path_new_from_indices (0, -1);
201       gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE);
202     }
203
204   gtk_icon_view_select_path (GTK_ICON_VIEW (view), path);
205   gtk_tree_path_free (path);
206
207   return FALSE;
208 }
209
210 #define CSS \
211   "GtkWindow {\n" \
212   "  background-color: @base_color;\n" \
213   "}\n"
214
215 static void
216 set_styles (void)
217 {
218   GtkCssProvider *provider;
219   GdkScreen *screen;
220
221   provider = gtk_css_provider_new ();
222
223   if (!gtk_css_provider_load_from_data (provider, CSS, -1, NULL))
224     {
225       g_assert_not_reached ();
226     }
227
228   screen = gdk_display_get_default_screen (gdk_display_get_default ());
229
230   gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),
231                                              GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
232 }
233
234 int
235 main (int argc, char *argv[])
236 {
237   GtkWidget *window;
238   GtkWidget *vbox;
239   Views views;
240
241   gtk_init (&argc, &argv);
242
243   set_styles ();
244
245   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
246   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
247   gtk_container_add (GTK_CONTAINER (window), vbox);
248
249   views.header1 = g_object_new (GTK_TYPE_LABEL,
250                                 "label", "<b>Group 1</b>",
251                                 "use-markup", TRUE,
252                                 "xalign", 0.0,
253                                 NULL);
254   views.view1 = get_view (TRUE);
255   views.header2 = g_object_new (GTK_TYPE_LABEL,
256                                 "label", "<b>Group 2</b>",
257                                 "use-markup", TRUE,
258                                 "xalign", 0.0,
259                                 NULL);
260   views.view2 = get_view (FALSE);
261
262   g_signal_connect (views.view1, "keynav-failed",
263                     G_CALLBACK (keynav_failed), &views);
264   g_signal_connect (views.view2, "keynav-failed",
265                     G_CALLBACK (keynav_failed), &views);
266   g_signal_connect (views.view1, "focus-in-event",
267                     G_CALLBACK (focus_in), NULL);
268   g_signal_connect (views.view1, "focus-out-event",
269                     G_CALLBACK (focus_out), NULL);
270   g_signal_connect (views.view2, "focus-in-event",
271                     G_CALLBACK (focus_in), NULL);
272   g_signal_connect (views.view2, "focus-out-event",
273                     G_CALLBACK (focus_out), NULL);
274
275   gtk_container_add (GTK_CONTAINER (vbox), views.header1);
276   gtk_container_add (GTK_CONTAINER (vbox), views.view1);
277   gtk_container_add (GTK_CONTAINER (vbox), views.header2);
278   gtk_container_add (GTK_CONTAINER (vbox), views.view2);
279
280   gtk_widget_show_all (window);
281
282   gtk_main ();
283
284   return 0;
285 }
286