Contents of /trunk/src/list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 177 - (show annotations)
Wed Jun 10 12:07:11 2009 UTC (14 years, 11 months ago) by harbaum
File MIME type: text/plain
File size: 10333 byte(s)
Removed project dirty flag, removed trailing ... in labels
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,
121 flags & (LIST_FLAG_EXPAND | LIST_FLAG_ELLIPSIZE));
122 }
123
124 gtk_tree_view_column_set_sort_column_id(column, key);
125 gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
126
127 name = va_arg(ap, char*);
128 }
129
130 va_end(ap);
131 }
132
133 static GtkWidget *list_button_get(GtkWidget *list, list_button_t id) {
134 return g_object_get_data(G_OBJECT(list), list_button_id_to_name(id));
135 }
136
137 void list_button_connect(GtkWidget *list, list_button_t id,
138 GCallback cb, gpointer data) {
139 GtkWidget *but = list_button_get(list, id);
140 gtk_signal_connect(GTK_OBJECT(but), "clicked", GTK_SIGNAL_FUNC(cb), data);
141 }
142
143 /* put a custom widget into one of the button slots */
144 void list_set_custom_user_button(GtkWidget *list, list_button_t id,
145 GtkWidget *widget) {
146 GtkWidget *table = g_object_get_data(G_OBJECT(list), "table");
147 g_assert((id >= 3) && (id < 6));
148
149 /* make space for user buttons */
150 gtk_table_resize(GTK_TABLE(table), 2, 3);
151
152 gtk_table_attach_defaults(GTK_TABLE(table), widget,
153 id-LIST_BUTTON_USER0, id-LIST_BUTTON_USER0+1, 1, 2);
154 g_object_set_data(G_OBJECT(list), list_button_id_to_name(id), widget);
155 }
156
157 GtkTreeSelection *list_get_selection(GtkWidget *list) {
158 GtkWidget *view = g_object_get_data(G_OBJECT(list), "view");
159 return gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
160 }
161
162 void list_button_enable(GtkWidget *list, list_button_t id, gboolean enable) {
163 GtkWidget *but = list_button_get(list, id);
164 if(but) gtk_widget_set_sensitive(but, enable);
165 }
166
167 void list_set_store(GtkWidget *list, GtkListStore *store) {
168 gtk_tree_view_set_model(
169 GTK_TREE_VIEW(g_object_get_data(G_OBJECT(list), "view")),
170 GTK_TREE_MODEL(store));
171 }
172
173 void list_set_selection_function(GtkWidget *list, GtkTreeSelectionFunc func,
174 gpointer data) {
175 GtkWidget *view = g_object_get_data(G_OBJECT(list), "view");
176 gtk_tree_selection_set_select_function(
177 gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
178 func, data, NULL);
179 }
180
181 /* default selection function enables edit and remove if a row is being */
182 /* selected */
183 static gboolean
184 list_selection_function(GtkTreeSelection *selection, GtkTreeModel *model,
185 GtkTreePath *path, gboolean path_currently_selected,
186 gpointer list) {
187 GtkTreeIter iter;
188
189 if(gtk_tree_model_get_iter(model, &iter, path)) {
190 g_assert(gtk_tree_path_get_depth(path) == 1);
191
192 list_button_enable(GTK_WIDGET(list), LIST_BUTTON_REMOVE, TRUE);
193 list_button_enable(GTK_WIDGET(list), LIST_BUTTON_EDIT, TRUE);
194 }
195
196 return TRUE; /* allow selection state to change */
197 }
198
199 void list_set_static_buttons(GtkWidget *list, GCallback cb_new,
200 GCallback cb_edit, GCallback cb_remove, gpointer data) {
201 GtkWidget *table = g_object_get_data(G_OBJECT(list), "table");
202 g_object_set_data(G_OBJECT(list), "userdata", data);
203
204 /* add the three default buttons, but keep the disabled for now */
205 GtkWidget *button = NULL;
206 if(cb_new) {
207 button = gtk_button_new_with_label(_("Add"));
208 gtk_table_attach_defaults(GTK_TABLE(table), button, 0, 1, 0, 1);
209 gtk_widget_set_sensitive(button, TRUE);
210 g_object_set_data(G_OBJECT(list), "btn_new", button);
211 gtk_signal_connect(GTK_OBJECT(button), "clicked",
212 GTK_SIGNAL_FUNC(cb_new), data);
213 }
214
215 if(cb_edit) {
216 button = gtk_button_new_with_label(_("Edit"));
217 gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, 0, 1);
218 gtk_widget_set_sensitive(button, FALSE);
219 g_object_set_data(G_OBJECT(list), "btn_edit", button);
220 gtk_signal_connect(GTK_OBJECT(button), "clicked",
221 GTK_SIGNAL_FUNC(cb_edit), data);
222 }
223
224 if(cb_remove) {
225 button = gtk_button_new_with_label(_("Remove"));
226 gtk_table_attach_defaults(GTK_TABLE(table), button, 2, 3, 0, 1);
227 gtk_widget_set_sensitive(button, FALSE);
228 g_object_set_data(G_OBJECT(list), "btn_remove", button);
229 gtk_signal_connect(GTK_OBJECT(button), "clicked",
230 GTK_SIGNAL_FUNC(cb_remove), data);
231 }
232 }
233
234 GtkTreeModel *list_get_model(GtkWidget *list) {
235 return gtk_tree_view_get_model(GTK_TREE_VIEW(
236 g_object_get_data(G_OBJECT(list), "view")));
237 }
238
239 void list_pre_inplace_edit_tweak (GtkTreeModel *model) {
240 // Remove any current sort ordering, leaving items where they are.
241 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
242 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
243 GTK_SORT_ASCENDING);
244 }
245
246
247 /* Refocus a GtkTreeView an item specified by iter, unselecting the current
248 selection and optionally highlighting the new one. Typically called after
249 making an edit to an item with a covering sub-dialog. */
250
251 void list_focus_on(GtkWidget *list, GtkTreeIter *iter, gboolean highlight) {
252 GtkTreeView *view = g_object_get_data(G_OBJECT(list), "view");
253 GtkTreeModel *model = gtk_tree_view_get_model(view);
254
255 // Handle de/reselection
256 GtkTreeSelection *sel = gtk_tree_view_get_selection(view);
257 gtk_tree_selection_unselect_all(sel);
258
259 // Scroll to it, since it might now be out of view.
260 GtkTreePath *path = gtk_tree_model_get_path(model, iter);
261 gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0);
262 gtk_tree_path_free(path);
263
264 // reselect
265 if (highlight)
266 gtk_tree_selection_select_iter(sel, iter);
267 }
268
269
270
271 /* a generic list widget with "add", "edit" and "remove" buttons as used */
272 /* for all kinds of lists in osm2go */
273 #ifdef USE_HILDON
274 GtkWidget *list_new(gboolean show_headers)
275 #else
276 GtkWidget *list_new(void)
277 #endif
278 {
279 GtkWidget *vbox = gtk_vbox_new(FALSE,3);
280 GtkWidget *view = gtk_tree_view_new();
281 g_object_set_data(G_OBJECT(vbox), "view", view);
282
283 #ifdef USE_HILDON
284 if(show_headers) {
285 /* hildon hides these by default */
286 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
287 }
288 #endif
289
290 gtk_tree_selection_set_select_function(
291 gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
292 list_selection_function, vbox, NULL);
293
294 /* put view into a scrolled window */
295 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
296 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
297 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
298 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
299 GTK_SHADOW_ETCHED_IN);
300 gtk_container_add(GTK_CONTAINER(scrolled_window), view);
301 gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window);
302
303 /* add button box */
304 GtkWidget *table = gtk_table_new(1, 3, TRUE);
305 g_object_set_data(G_OBJECT(vbox), "table", table);
306
307 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
308
309 return vbox;
310 }
311