Contents of /trunk/src/list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 148 - (show annotations)
Fri Mar 27 14:49:30 2009 UTC (15 years, 2 months ago) by harbaum
File MIME type: text/plain
File size: 10330 byte(s)
More unified lists
1 /*
2 * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of OSM2Go.
5 *
6 * OSM2Go is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * OSM2Go is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21 * list.c - generic implementation of a list style widget:
22 *
23 * +---------+-----------+
24 * | Key | Key |
25 * +---------+-----------+
26 * | Test1 Test2 ^|
27 * | Test3 Test4 #|
28 * | ||
29 * | v|
30 * +---------------------+
31 * ( Add )( Edit )(Remove)
32 */
33
34 #include "appdata.h"
35
36 #include <stdarg.h>
37
38 static const char *list_button_id_to_name(list_button_t id) {
39 const char *names[] = { "btn_new", "btn_edit", "btn_remove",
40 "btn_user0", "btn_user1", "btn_user2" };
41 g_assert(id < 6);
42 return names[id];
43 }
44
45 GtkWidget *list_get_view(GtkWidget *list) {
46 return g_object_get_data(G_OBJECT(list), "view");
47 }
48
49 /* a list supports up to three user defined buttons besides */
50 /* add, edit and remove */
51 void list_set_user_buttons(GtkWidget *list, ...) {
52 va_list ap;
53 GtkWidget *table = g_object_get_data(G_OBJECT(list), "table");
54 void *data = g_object_get_data(G_OBJECT(list), "userdata");
55
56 /* make space for user buttons */
57 gtk_table_resize(GTK_TABLE(table), 2, 3);
58
59 va_start(ap, list);
60 list_button_t id = va_arg(ap, list_button_t);
61 while(id) {
62 char *label = va_arg(ap, char*);
63 GCallback cb = va_arg(ap, GCallback);
64
65 GtkWidget *button = gtk_button_new_with_label(label);
66 gtk_table_attach_defaults(GTK_TABLE(table), button,
67 id-LIST_BUTTON_USER0, id-LIST_BUTTON_USER0+1, 1, 2);
68 g_object_set_data(G_OBJECT(list), list_button_id_to_name(id), button);
69 gtk_signal_connect(GTK_OBJECT(button), "clicked",
70 GTK_SIGNAL_FUNC(cb), data);
71
72 id = va_arg(ap, list_button_t);
73 }
74
75 va_end(ap);
76 }
77
78 void list_set_columns(GtkWidget *list, ...) {
79 va_list ap;
80 GtkWidget *view = g_object_get_data(G_OBJECT(list), "view");
81
82 va_start(ap, list);
83 char *name = va_arg(ap, char*);
84 while(name) {
85 int hlkey = -1, key = va_arg(ap, int);
86 int flags = va_arg(ap, int);
87
88 if(flags & LIST_FLAG_CAN_HIGHLIGHT)
89 hlkey = va_arg(ap, int);
90
91 GtkTreeViewColumn *column = NULL;
92
93 if(flags & LIST_FLAG_TOGGLE) {
94 GCallback cb = va_arg(ap, GCallback);
95 gpointer data = va_arg(ap, gpointer);
96
97 GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new();
98 column = gtk_tree_view_column_new_with_attributes(
99 name, renderer, "active", key, NULL);
100 g_signal_connect(renderer, "toggled", cb, data);
101
102 } else if(flags & LIST_FLAG_STOCK_ICON) {
103 GtkCellRenderer *pixbuf_renderer = gtk_cell_renderer_pixbuf_new();
104 column = gtk_tree_view_column_new_with_attributes(name,
105 pixbuf_renderer, "stock_id", key, NULL);
106 } else {
107 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
108
109 if(flags & LIST_FLAG_CAN_HIGHLIGHT)
110 g_object_set(renderer, "background", "red", NULL );
111
112 if(flags & LIST_FLAG_ELLIPSIZE)
113 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
114
115 column = gtk_tree_view_column_new_with_attributes(name, renderer,
116 "text", key,
117 (flags & LIST_FLAG_CAN_HIGHLIGHT)?"background-set":NULL, hlkey,
118 NULL);
119
120 gtk_tree_view_column_set_expand(column, flags & (LIST_FLAG_EXPAND | LIST_FLAG_ELLIPSIZE));
121 }
122
123 gtk_tree_view_column_set_sort_column_id(column, key);
124 gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
125
126 name = va_arg(ap, char*);
127 }
128
129 va_end(ap);
130 }
131
132 static GtkWidget *list_button_get(GtkWidget *list, list_button_t id) {
133 return g_object_get_data(G_OBJECT(list), list_button_id_to_name(id));
134 }
135
136 void list_button_connect(GtkWidget *list, list_button_t id,
137 GCallback cb, gpointer data) {
138 GtkWidget *but = list_button_get(list, id);
139 gtk_signal_connect(GTK_OBJECT(but), "clicked", GTK_SIGNAL_FUNC(cb), data);
140 }
141
142 /* put a custom widget into one of the button slots */
143 void list_set_custom_user_button(GtkWidget *list, list_button_t id,
144 GtkWidget *widget) {
145 GtkWidget *table = g_object_get_data(G_OBJECT(list), "table");
146 g_assert((id >= 3) && (id < 6));
147
148 /* make space for user buttons */
149 gtk_table_resize(GTK_TABLE(table), 2, 3);
150
151 gtk_table_attach_defaults(GTK_TABLE(table), widget,
152 id-LIST_BUTTON_USER0, id-LIST_BUTTON_USER0+1, 1, 2);
153 g_object_set_data(G_OBJECT(list), list_button_id_to_name(id), widget);
154 }
155
156 GtkTreeSelection *list_get_selection(GtkWidget *list) {
157 GtkWidget *view = g_object_get_data(G_OBJECT(list), "view");
158 return gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
159 }
160
161 void list_button_enable(GtkWidget *list, list_button_t id, gboolean enable) {
162 GtkWidget *but = list_button_get(list, id);
163 if(but) gtk_widget_set_sensitive(but, enable);
164 }
165
166 void list_set_store(GtkWidget *list, GtkListStore *store) {
167 gtk_tree_view_set_model(
168 GTK_TREE_VIEW(g_object_get_data(G_OBJECT(list), "view")),
169 GTK_TREE_MODEL(store));
170 }
171
172 void list_set_selection_function(GtkWidget *list, GtkTreeSelectionFunc func,
173 gpointer data) {
174 GtkWidget *view = g_object_get_data(G_OBJECT(list), "view");
175 gtk_tree_selection_set_select_function(
176 gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
177 func, data, NULL);
178 }
179
180 /* default selection function enables edit and remove if a row is being */
181 /* selected */
182 static gboolean
183 list_selection_function(GtkTreeSelection *selection, GtkTreeModel *model,
184 GtkTreePath *path, gboolean path_currently_selected,
185 gpointer list) {
186 GtkTreeIter iter;
187
188 if(gtk_tree_model_get_iter(model, &iter, path)) {
189 g_assert(gtk_tree_path_get_depth(path) == 1);
190
191 list_button_enable(GTK_WIDGET(list), LIST_BUTTON_REMOVE, TRUE);
192 list_button_enable(GTK_WIDGET(list), LIST_BUTTON_EDIT, TRUE);
193 }
194
195 return TRUE; /* allow selection state to change */
196 }
197
198 void list_set_static_buttons(GtkWidget *list, GCallback cb_new,
199 GCallback cb_edit, GCallback cb_remove, gpointer data) {
200 GtkWidget *table = g_object_get_data(G_OBJECT(list), "table");
201 g_object_set_data(G_OBJECT(list), "userdata", data);
202
203 /* add the three default buttons, but keep the disabled for now */
204 GtkWidget *button = NULL;
205 if(cb_new) {
206 button = gtk_button_new_with_label(_("Add..."));
207 gtk_table_attach_defaults(GTK_TABLE(table), button, 0, 1, 0, 1);
208 gtk_widget_set_sensitive(button, TRUE);
209 g_object_set_data(G_OBJECT(list), "btn_new", button);
210 gtk_signal_connect(GTK_OBJECT(button), "clicked",
211 GTK_SIGNAL_FUNC(cb_new), data);
212 }
213
214 if(cb_edit) {
215 button = gtk_button_new_with_label(_("Edit..."));
216 gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, 0, 1);
217 gtk_widget_set_sensitive(button, FALSE);
218 g_object_set_data(G_OBJECT(list), "btn_edit", button);
219 gtk_signal_connect(GTK_OBJECT(button), "clicked",
220 GTK_SIGNAL_FUNC(cb_edit), data);
221 }
222
223 if(cb_remove) {
224 button = gtk_button_new_with_label(_("Remove"));
225 gtk_table_attach_defaults(GTK_TABLE(table), button, 2, 3, 0, 1);
226 gtk_widget_set_sensitive(button, FALSE);
227 g_object_set_data(G_OBJECT(list), "btn_remove", button);
228 gtk_signal_connect(GTK_OBJECT(button), "clicked",
229 GTK_SIGNAL_FUNC(cb_remove), data);
230 }
231 }
232
233 GtkTreeModel *list_get_model(GtkWidget *list) {
234 return gtk_tree_view_get_model(GTK_TREE_VIEW(
235 g_object_get_data(G_OBJECT(list), "view")));
236 }
237
238 void list_pre_inplace_edit_tweak (GtkTreeModel *model) {
239 // Remove any current sort ordering, leaving items where they are.
240 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
241 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
242 GTK_SORT_ASCENDING);
243 }
244
245
246 /* Refocus a GtkTreeView an item specified by iter, unselecting the current
247 selection and optionally highlighting the new one. Typically called after
248 making an edit to an item with a covering sub-dialog. */
249
250 void list_focus_on(GtkWidget *list, GtkTreeIter *iter, gboolean highlight) {
251 GtkTreeView *view = g_object_get_data(G_OBJECT(list), "view");
252 GtkTreeModel *model = gtk_tree_view_get_model(view);
253
254 // Handle de/reselection
255 GtkTreeSelection *sel = gtk_tree_view_get_selection(view);
256 gtk_tree_selection_unselect_all(sel);
257
258 // Scroll to it, since it might now be out of view.
259 GtkTreePath *path = gtk_tree_model_get_path(model, iter);
260 gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0);
261 gtk_tree_path_free(path);
262
263 // reselect
264 if (highlight)
265 gtk_tree_selection_select_iter(sel, iter);
266 }
267
268
269
270 /* a generic list widget with "add", "edit" and "remove" buttons as used */
271 /* for all kinds of lists in osm2go */
272 #ifdef USE_HILDON
273 GtkWidget *list_new(gboolean show_headers)
274 #else
275 GtkWidget *list_new(void)
276 #endif
277 {
278 GtkWidget *vbox = gtk_vbox_new(FALSE,3);
279 GtkWidget *view = gtk_tree_view_new();
280 g_object_set_data(G_OBJECT(vbox), "view", view);
281
282 #ifdef USE_HILDON
283 if(show_headers) {
284 /* hildon hides these by default */
285 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
286 }
287 #endif
288
289 gtk_tree_selection_set_select_function(
290 gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
291 list_selection_function, vbox, NULL);
292
293 /* put view into a scrolled window */
294 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
295 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
296 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
297 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
298 GTK_SHADOW_ETCHED_IN);
299 gtk_container_add(GTK_CONTAINER(scrolled_window), view);
300 gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window);
301
302 /* add button box */
303 GtkWidget *table = gtk_table_new(1, 3, TRUE);
304 g_object_set_data(G_OBJECT(vbox), "table", table);
305
306 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
307
308 return vbox;
309 }
310