Mercurial > geeqie
annotate src/ui_tree_edit.c @ 1650:c16f499ea1ce
made file_util_start_editor_from_file consider also sidecars
author | nadvornik |
---|---|
date | Wed, 17 Jun 2009 18:41:10 +0000 |
parents | 2349fa90226d |
children | 9a351e8f3b97 |
rev | line source |
---|---|
9 | 1 /* |
2 * (SLIK) SimpLIstic sKin functions | |
3 * (C) 2004 John Ellis | |
1284 | 4 * Copyright (C) 2008 - 2009 The Geeqie Team |
9 | 5 * |
6 * Author: John Ellis | |
7 * | |
8 * This software is released under the GNU General Public License (GNU GPL). | |
9 * Please read the included file COPYING for more information. | |
10 * This software comes with no warranty of any kind, use at your own risk! | |
11 */ | |
12 | |
13 #ifdef HAVE_CONFIG_H | |
14 # include "config.h" | |
15 #endif | |
16 #include "intl.h" | |
17 | |
18 #include <stdio.h> | |
19 #include <stdlib.h> | |
20 #include <string.h> | |
21 | |
22 #include <gtk/gtk.h> | |
23 #include <gdk/gdkkeysyms.h> | |
24 | |
25 #include "ui_tree_edit.h" | |
26 | |
27 /* | |
28 *------------------------------------------------------------------- | |
29 * cell popup editor | |
30 *------------------------------------------------------------------- | |
31 */ | |
32 | |
33 static void tree_edit_close(TreeEditData *ted) | |
34 { | |
35 gtk_grab_remove(ted->window); | |
36 gdk_keyboard_ungrab(GDK_CURRENT_TIME); | |
37 gdk_pointer_ungrab(GDK_CURRENT_TIME); | |
38 | |
39 gtk_widget_destroy(ted->window); | |
40 | |
41 g_free(ted->old_name); | |
42 g_free(ted->new_name); | |
43 gtk_tree_path_free(ted->path); | |
44 | |
45 g_free(ted); | |
46 } | |
47 | |
48 static void tree_edit_do(TreeEditData *ted) | |
49 { | |
50 ted->new_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(ted->entry))); | |
51 | |
52 if (strcmp(ted->new_name, ted->old_name) != 0) | |
53 { | |
54 if (ted->edit_func) | |
55 { | |
56 if (ted->edit_func(ted, ted->old_name, ted->new_name, ted->edit_data)) | |
57 { | |
58 /* hmm, should the caller be required to set text instead ? */ | |
59 } | |
60 } | |
61 } | |
62 } | |
63 | |
1448 | 64 static gboolean tree_edit_click_end_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) |
9 | 65 { |
66 TreeEditData *ted = data; | |
67 | |
68 tree_edit_do(ted); | |
69 tree_edit_close(ted); | |
70 | |
71 return TRUE; | |
72 } | |
73 | |
1448 | 74 static gboolean tree_edit_click_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) |
9 | 75 { |
76 TreeEditData *ted = data; | |
77 | |
78 gint x, y; | |
79 gint w, h; | |
80 | |
81 gint xr, yr; | |
82 | |
83 xr = (gint)event->x_root; | |
84 yr = (gint)event->y_root; | |
85 | |
86 gdk_window_get_origin(ted->window->window, &x, &y); | |
87 gdk_drawable_get_size(ted->window->window, &w, &h); | |
88 | |
89 if (xr < x || yr < y || xr > x + w || yr > y + h) | |
90 { | |
91 /* gobble the release event, so it does not propgate to an underlying widget */ | |
92 g_signal_connect(G_OBJECT(ted->window), "button_release_event", | |
93 G_CALLBACK(tree_edit_click_end_cb), ted); | |
94 return TRUE; | |
95 } | |
96 return FALSE; | |
97 } | |
98 | |
1448 | 99 static gboolean tree_edit_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) |
9 | 100 { |
101 TreeEditData *ted = data; | |
102 | |
103 switch (event->keyval) | |
104 { | |
105 case GDK_Return: | |
106 case GDK_KP_Enter: | |
107 case GDK_Tab: /* ok, we are going to intercept the focus change | |
108 from keyboard and act like return was hit */ | |
109 case GDK_ISO_Left_Tab: | |
110 case GDK_Up: | |
111 case GDK_Down: | |
112 case GDK_KP_Up: | |
113 case GDK_KP_Down: | |
114 case GDK_KP_Left: | |
115 case GDK_KP_Right: | |
116 tree_edit_do(ted); | |
117 tree_edit_close(ted); | |
118 break; | |
119 case GDK_Escape: | |
120 tree_edit_close(ted); | |
121 break; | |
122 default: | |
123 break; | |
124 } | |
125 | |
126 return FALSE; | |
127 } | |
128 | |
129 static gboolean tree_edit_by_path_idle_cb(gpointer data) | |
130 { | |
131 TreeEditData *ted = data; | |
132 GdkRectangle rect; | |
133 gint x, y, w, h; /* geometry of cell within tree */ | |
134 gint wx, wy; /* geometry of tree from root window */ | |
135 gint sx, sw; | |
136 | |
137 gtk_tree_view_get_cell_area(ted->tree, ted->path, ted->column, &rect); | |
138 | |
139 x = rect.x; | |
140 y = rect.y; | |
141 w = rect.width + 4; | |
142 h = rect.height + 4; | |
143 | |
144 if (gtk_tree_view_column_cell_get_position(ted->column, ted->cell, &sx, &sw)) | |
145 { | |
146 x += sx; | |
147 w = MAX(w - sx, sw); | |
148 } | |
149 | |
150 gdk_window_get_origin(gtk_tree_view_get_bin_window(ted->tree), &wx, &wy); | |
151 | |
152 x += wx - 2; /* the -val is to 'fix' alignment of entry position */ | |
153 y += wy - 2; | |
154 | |
155 /* now show it */ | |
156 gtk_widget_set_size_request(ted->window, w, h); | |
157 gtk_widget_realize(ted->window); | |
158 gtk_window_move(GTK_WINDOW(ted->window), x, y); | |
159 gtk_window_resize(GTK_WINDOW(ted->window), w, h); | |
160 gtk_widget_show(ted->window); | |
161 | |
162 /* grab it */ | |
163 gtk_widget_grab_focus(ted->entry); | |
164 /* explicitely set the focus flag for the entry, for some reason on popup windows this | |
165 * is not set, and causes no edit cursor to appear ( popups not allowed focus? ) | |
166 */ | |
167 GTK_WIDGET_SET_FLAGS(ted->entry, GTK_HAS_FOCUS); | |
168 gtk_grab_add(ted->window); | |
169 gdk_pointer_grab(ted->window->window, TRUE, | |
170 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK, | |
171 NULL, NULL, GDK_CURRENT_TIME); | |
172 gdk_keyboard_grab(ted->window->window, TRUE, GDK_CURRENT_TIME); | |
173 | |
174 return FALSE; | |
175 } | |
176 | |
1448 | 177 gboolean tree_edit_by_path(GtkTreeView *tree, GtkTreePath *tpath, gint column, const gchar *text, |
178 gboolean (*edit_func)(TreeEditData *, const gchar *, const gchar *, gpointer), gpointer data) | |
9 | 179 { |
180 TreeEditData *ted; | |
181 GtkTreeViewColumn *tcolumn; | |
182 GtkCellRenderer *cell = NULL; | |
183 GList *list; | |
184 GList *work; | |
185 | |
186 if (!edit_func) return FALSE; | |
187 if (!GTK_WIDGET_VISIBLE(tree)) return FALSE; | |
188 | |
189 tcolumn = gtk_tree_view_get_column(tree, column); | |
190 if (!tcolumn) return FALSE; | |
191 | |
192 list = gtk_tree_view_column_get_cell_renderers(tcolumn); | |
193 work = list; | |
194 while (work && !cell) | |
195 { | |
196 cell = work->data; | |
197 if (!GTK_IS_CELL_RENDERER_TEXT(cell)) | |
198 { | |
199 cell = NULL; | |
200 } | |
201 work = work->next; | |
202 } | |
203 | |
204 g_list_free(list); | |
205 if (!cell) return FALSE; | |
206 | |
207 if (!text) text = ""; | |
208 | |
209 ted = g_new0(TreeEditData, 1); | |
210 | |
211 ted->old_name = g_strdup(text); | |
212 | |
213 ted->edit_func = edit_func; | |
214 ted->edit_data = data; | |
215 | |
216 ted->tree = tree; | |
217 ted->path = gtk_tree_path_copy(tpath); | |
218 ted->column = tcolumn; | |
219 ted->cell = cell; | |
220 | |
221 gtk_tree_view_scroll_to_cell(ted->tree, ted->path, ted->column, FALSE, 0.0, 0.0); | |
222 | |
223 /* create the window */ | |
224 | |
225 ted->window = gtk_window_new(GTK_WINDOW_POPUP); | |
226 gtk_window_set_resizable(GTK_WINDOW(ted->window), FALSE); | |
227 g_signal_connect(G_OBJECT(ted->window), "button_press_event", | |
228 G_CALLBACK(tree_edit_click_cb), ted); | |
229 g_signal_connect(G_OBJECT(ted->window), "key_press_event", | |
230 G_CALLBACK(tree_edit_key_press_cb), ted); | |
231 | |
232 ted->entry = gtk_entry_new(); | |
233 gtk_entry_set_text(GTK_ENTRY(ted->entry), ted->old_name); | |
234 gtk_editable_select_region(GTK_EDITABLE(ted->entry), 0, strlen(ted->old_name)); | |
235 gtk_container_add(GTK_CONTAINER(ted->window), ted->entry); | |
236 gtk_widget_show(ted->entry); | |
237 | |
238 /* due to the fact that gtktreeview scrolls in an idle loop, we cannot | |
239 * reliably get the cell position until those scroll priority signals are processed | |
240 */ | |
241 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE - 2, tree_edit_by_path_idle_cb, ted, NULL); | |
242 | |
243 return TRUE; | |
244 } | |
245 | |
246 /* | |
247 *------------------------------------------------------------------- | |
248 * tree cell position retrieval | |
249 *------------------------------------------------------------------- | |
250 */ | |
251 | |
1448 | 252 gboolean tree_view_get_cell_origin(GtkTreeView *widget, GtkTreePath *tpath, gint column, gboolean text_cell_only, |
253 gint *x, gint *y, gint *width, gint *height) | |
9 | 254 { |
255 gint x_origin, y_origin; | |
256 gint x_offset, y_offset; | |
257 gint header_size; | |
258 GtkTreeViewColumn *tv_column; | |
259 GdkRectangle rect; | |
260 | |
261 tv_column = gtk_tree_view_get_column(widget, column); | |
262 if (!tv_column || !tpath) return FALSE; | |
263 | |
264 /* hmm, appears the rect will not account for X scroll, but does for Y scroll | |
265 * use x_offset instead for X scroll (sigh) | |
266 */ | |
267 gtk_tree_view_get_cell_area(widget, tpath, tv_column, &rect); | |
1147
4220d5536ad9
fixed usage of deprecated functions - patch by Omari Stephens
nadvornik
parents:
1055
diff
changeset
|
268 #if GTK_CHECK_VERSION(2,12,0) |
4220d5536ad9
fixed usage of deprecated functions - patch by Omari Stephens
nadvornik
parents:
1055
diff
changeset
|
269 gtk_tree_view_convert_tree_to_widget_coords(widget, 0, 0, &x_offset, &y_offset); |
1043 | 270 #else |
9 | 271 gtk_tree_view_tree_to_widget_coords(widget, 0, 0, &x_offset, &y_offset); |
1043 | 272 #endif |
9 | 273 gdk_window_get_origin(GTK_WIDGET(widget)->window, &x_origin, &y_origin); |
274 | |
275 if (gtk_tree_view_get_headers_visible(widget)) | |
276 { | |
277 header_size = tv_column->button->allocation.height; | |
278 } | |
279 else | |
280 { | |
281 header_size = 0; | |
282 } | |
283 | |
284 if (text_cell_only) | |
285 { | |
286 GtkCellRenderer *cell = NULL; | |
287 GList *renderers; | |
288 GList *work; | |
289 gint cell_x; | |
290 gint cell_width; | |
291 | |
292 renderers = gtk_tree_view_column_get_cell_renderers(tv_column); | |
293 work = renderers; | |
294 while (work && !cell) | |
295 { | |
296 cell = work->data; | |
297 work = work->next; | |
298 if (!GTK_IS_CELL_RENDERER_TEXT(cell)) cell = NULL; | |
299 } | |
300 g_list_free(renderers); | |
301 | |
302 if (!cell) return FALSE; | |
442 | 303 |
9 | 304 if (!gtk_tree_view_column_cell_get_position(tv_column, cell, &cell_x, &cell_width)) |
305 { | |
306 cell_x = 0; | |
307 cell_width = rect.width; | |
308 } | |
309 *x = x_origin + x_offset + rect.x + cell_x; | |
310 *width = cell_width; | |
311 } | |
312 else | |
313 { | |
314 *x = x_origin + x_offset + rect.x; | |
315 *width = rect.width; | |
316 } | |
317 *y = y_origin + rect.y + header_size; | |
318 *height = rect.height; | |
319 return TRUE; | |
320 } | |
321 | |
1448 | 322 void tree_view_get_cell_clamped(GtkTreeView *widget, GtkTreePath *tpath, gint column, gboolean text_cell_only, |
9 | 323 gint *x, gint *y, gint *width, gint *height) |
324 { | |
325 gint wx, wy, ww, wh; | |
326 GdkWindow *window; | |
327 | |
328 window = GTK_WIDGET(widget)->window; | |
329 gdk_window_get_origin(window, &wx, &wy); | |
330 gdk_drawable_get_size(window, &ww, &wh); | |
331 if (!tree_view_get_cell_origin(widget, tpath, column, text_cell_only, x, y, width, height)) | |
332 { | |
333 *x = wx; | |
334 *y = wy; | |
335 *width = ww; | |
336 *height = wh; | |
337 return; | |
338 } | |
339 | |
340 *width = MIN(*width, ww); | |
341 *x = CLAMP(*x, wx, wx + ww - (*width)); | |
342 *y = CLAMP(*y, wy, wy + wh); | |
343 *height = MIN(*height, wy + wh - (*y)); | |
344 } | |
345 | |
1631
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
346 #if GTK_CHECK_VERSION(2,8,0) |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
347 /* an implementation that uses gtk_tree_view_get_visible_range */ |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
348 gint tree_view_row_get_visibility(GtkTreeView *widget, GtkTreeIter *iter, gboolean fully_visible) |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
349 { |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
350 GtkTreeModel *store; |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
351 GtkTreePath *tpath, *start_path, *end_path; |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
352 gint ret = 0; |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
353 |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
354 if (!gtk_tree_view_get_visible_range(widget, &start_path, &end_path)) return -1; /* we will most probably scroll down, needed for tree_view_row_make_visible */ |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
355 |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
356 store = gtk_tree_view_get_model(widget); |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
357 tpath = gtk_tree_model_get_path(store, iter); |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
358 |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
359 if (fully_visible) |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
360 { |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
361 if (gtk_tree_path_compare(tpath, start_path) <= 0) |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
362 { |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
363 ret = -1; |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
364 } |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
365 else if (gtk_tree_path_compare(tpath, end_path) >= 0) |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
366 { |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
367 ret = 1; |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
368 } |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
369 } |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
370 else |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
371 { |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
372 if (gtk_tree_path_compare(tpath, start_path) < 0) |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
373 { |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
374 ret = -1; |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
375 } |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
376 else if (gtk_tree_path_compare(tpath, end_path) > 0) |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
377 { |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
378 ret = 1; |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
379 } |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
380 } |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
381 |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
382 gtk_tree_path_free(tpath); |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
383 gtk_tree_path_free(start_path); |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
384 gtk_tree_path_free(end_path); |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
385 return ret; |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
386 } |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
387 |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
388 #else |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
389 /* an implementation that uses gtk_tree_view_get_visible_rect, it seems to be more error prone than the variant above */ |
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
390 |
1448 | 391 gint tree_view_row_get_visibility(GtkTreeView *widget, GtkTreeIter *iter, gboolean fully_visible) |
9 | 392 { |
393 GtkTreeModel *store; | |
442 | 394 GtkTreePath *tpath; |
9 | 395 gint cx, cy; |
442 | 396 |
9 | 397 GdkRectangle vrect; |
398 GdkRectangle crect; | |
399 | |
958 | 400 if (!GTK_WIDGET_REALIZED(GTK_WIDGET(widget))) return -1; /* we will most probably scroll down, needed for tree_view_row_make_visible */ |
9 | 401 |
402 store = gtk_tree_view_get_model(widget); | |
403 tpath = gtk_tree_model_get_path(store, iter); | |
404 | |
405 gtk_tree_view_get_visible_rect(widget, &vrect); | |
406 gtk_tree_view_get_cell_area(widget, tpath, NULL, &crect); | |
407 gtk_tree_path_free(tpath); | |
408 | |
1043 | 409 |
1147
4220d5536ad9
fixed usage of deprecated functions - patch by Omari Stephens
nadvornik
parents:
1055
diff
changeset
|
410 #if GTK_CHECK_VERSION(2,12,0) |
4220d5536ad9
fixed usage of deprecated functions - patch by Omari Stephens
nadvornik
parents:
1055
diff
changeset
|
411 gtk_tree_view_convert_widget_to_tree_coords(widget, crect.x, crect.y, &cx, &cy); |
1043 | 412 #else |
9 | 413 gtk_tree_view_widget_to_tree_coords(widget, crect.x, crect.y, &cx, &cy); |
1043 | 414 #endif |
9 | 415 |
416 if (fully_visible) | |
417 { | |
418 if (cy < vrect.y) return -1; | |
419 if (cy + crect.height > vrect.y + vrect.height) return 1; | |
420 return 0; | |
421 } | |
422 | |
423 if (cy + crect.height < vrect.y) return -1; | |
424 if (cy > vrect.y + vrect.height) return 1; | |
425 return 0; | |
426 } | |
1631
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
427 #endif |
9 | 428 |
1448 | 429 gint tree_view_row_make_visible(GtkTreeView *widget, GtkTreeIter *iter, gboolean center) |
9 | 430 { |
431 GtkTreePath *tpath; | |
432 gint vis; | |
433 | |
434 vis = tree_view_row_get_visibility(widget, iter, TRUE); | |
435 | |
436 tpath = gtk_tree_model_get_path(gtk_tree_view_get_model(widget), iter); | |
437 if (center && vis != 0) | |
438 { | |
439 gtk_tree_view_scroll_to_cell(widget, tpath, NULL, TRUE, 0.5, 0.0); | |
440 } | |
441 else if (vis < 0) | |
442 { | |
443 gtk_tree_view_scroll_to_cell(widget, tpath, NULL, TRUE, 0.0, 0.0); | |
444 } | |
445 else if (vis > 0) | |
446 { | |
447 gtk_tree_view_scroll_to_cell(widget, tpath, NULL, TRUE, 1.0, 0.0); | |
448 } | |
449 gtk_tree_path_free(tpath); | |
450 | |
451 return vis; | |
452 } | |
453 | |
1448 | 454 gboolean tree_view_move_cursor_away(GtkTreeView *widget, GtkTreeIter *iter, gboolean only_selected) |
9 | 455 { |
456 GtkTreeModel *store; | |
457 GtkTreePath *tpath; | |
458 GtkTreePath *fpath; | |
1437 | 459 gboolean move = FALSE; |
9 | 460 |
461 if (!iter) return FALSE; | |
462 | |
463 store = gtk_tree_view_get_model(widget); | |
464 tpath = gtk_tree_model_get_path(store, iter); | |
465 gtk_tree_view_get_cursor(widget, &fpath, NULL); | |
466 | |
467 if (fpath && gtk_tree_path_compare(tpath, fpath) == 0) | |
468 { | |
469 GtkTreeSelection *selection; | |
470 | |
471 selection = gtk_tree_view_get_selection(widget); | |
472 | |
473 if (!only_selected || | |
474 gtk_tree_selection_path_is_selected(selection, tpath)) | |
475 { | |
476 GtkTreeIter current; | |
477 | |
478 current = *iter; | |
479 if (gtk_tree_model_iter_next(store, ¤t)) | |
480 { | |
481 gtk_tree_path_next(tpath); | |
482 move = TRUE; | |
483 } | |
484 else if (gtk_tree_path_prev(tpath) && | |
485 gtk_tree_model_get_iter(store, ¤t, tpath)) | |
486 { | |
487 move = TRUE; | |
488 } | |
489 | |
490 if (move) | |
491 { | |
492 gtk_tree_view_set_cursor(widget, tpath, NULL, FALSE); | |
493 } | |
494 } | |
495 } | |
496 | |
497 gtk_tree_path_free(tpath); | |
498 if (fpath) gtk_tree_path_free(fpath); | |
499 | |
500 return move; | |
501 } | |
502 | |
503 gint tree_path_to_row(GtkTreePath *tpath) | |
504 { | |
505 gint *indices; | |
442 | 506 |
9 | 507 indices = gtk_tree_path_get_indices(tpath); |
508 if (indices) return indices[0]; | |
442 | 509 |
9 | 510 return -1; |
511 } | |
512 | |
513 | |
514 /* | |
515 *------------------------------------------------------------------- | |
516 * color utilities | |
517 *------------------------------------------------------------------- | |
518 */ | |
519 | |
520 void shift_color(GdkColor *src, gshort val, gint direction) | |
521 { | |
522 gshort cs; | |
523 | |
524 if (val == -1) | |
525 { | |
526 val = STYLE_SHIFT_STANDARD; | |
527 } | |
528 else | |
529 { | |
530 val = CLAMP(val, 1, 100); | |
531 } | |
532 cs = 0xffff / 100 * val; | |
533 | |
534 /* up or down ? */ | |
535 if (direction < 0 || | |
536 (direction == 0 &&((gint)src->red + (gint)src->green + (gint)src->blue) / 3 > 0xffff / 2)) | |
537 { | |
538 src->red = MAX(0 , src->red - cs); | |
539 src->green = MAX(0 , src->green - cs); | |
540 src->blue = MAX(0 , src->blue - cs); | |
541 } | |
542 else | |
543 { | |
544 src->red = MIN(0xffff, src->red + cs); | |
545 src->green = MIN(0xffff, src->green + cs); | |
546 src->blue = MIN(0xffff, src->blue + cs); | |
547 } | |
548 } | |
549 | |
550 /* darkens or lightens a style's color for given state | |
551 * esp. useful for alternating dark/light in (c)lists | |
552 */ | |
553 void style_shift_color(GtkStyle *style, GtkStateType type, gshort shift_value, gint direction) | |
554 { | |
555 if (!style) return; | |
556 | |
557 shift_color(&style->base[type], shift_value, direction); | |
558 shift_color(&style->bg[type], shift_value, direction); | |
559 } | |
560 | |
561 /* | |
562 *------------------------------------------------------------------- | |
563 * auto scroll by mouse position | |
564 *------------------------------------------------------------------- | |
565 */ | |
566 | |
567 #define AUTO_SCROLL_DEFAULT_SPEED 100 | |
568 #define AUTO_SCROLL_DEFAULT_REGION 20 | |
569 | |
570 typedef struct _AutoScrollData AutoScrollData; | |
571 struct _AutoScrollData | |
572 { | |
1523 | 573 guint timer_id; /* event source id */ |
9 | 574 gint region_size; |
575 GtkWidget *widget; | |
576 GtkAdjustment *adj; | |
577 gint max_step; | |
578 | |
579 gint (*notify_func)(GtkWidget *, gint, gint, gpointer); | |
580 gpointer notify_data; | |
581 }; | |
582 | |
583 void widget_auto_scroll_stop(GtkWidget *widget) | |
584 { | |
585 AutoScrollData *sd; | |
586 | |
587 sd = g_object_get_data(G_OBJECT(widget), "autoscroll"); | |
588 if (!sd) return; | |
589 g_object_set_data(G_OBJECT(widget), "autoscroll", NULL); | |
590 | |
1523 | 591 if (sd->timer_id) g_source_remove(sd->timer_id); |
9 | 592 g_free(sd); |
593 } | |
594 | |
1448 | 595 static gboolean widget_auto_scroll_cb(gpointer data) |
9 | 596 { |
597 AutoScrollData *sd = data; | |
598 GdkWindow *window; | |
599 gint x, y; | |
600 gint w, h; | |
601 gint amt = 0; | |
602 | |
603 if (sd->max_step < sd->region_size) | |
604 { | |
605 sd->max_step = MIN(sd->region_size, sd->max_step + 2); | |
606 } | |
607 | |
608 window = sd->widget->window; | |
609 gdk_window_get_pointer(window, &x, &y, NULL); | |
610 gdk_drawable_get_size(window, &w, &h); | |
611 | |
612 if (x < 0 || x >= w || y < 0 || y >= h) | |
613 { | |
1523 | 614 sd->timer_id = 0; |
9 | 615 widget_auto_scroll_stop(sd->widget); |
616 return FALSE; | |
617 } | |
618 | |
619 if (h < sd->region_size * 3) | |
620 { | |
621 /* height is cramped, nicely divide into three equal regions */ | |
622 if (y < h / 3 || y > h / 3 * 2) | |
623 { | |
624 amt = (y < h / 2) ? 0 - ((h / 2) - y) : y - (h / 2); | |
625 } | |
626 } | |
627 else if (y < sd->region_size) | |
628 { | |
629 amt = 0 - (sd->region_size - y); | |
630 } | |
631 else if (y >= h - sd->region_size) | |
632 { | |
633 amt = y - (h - sd->region_size); | |
634 } | |
635 | |
636 if (amt != 0) | |
637 { | |
638 amt = CLAMP(amt, 0 - sd->max_step, sd->max_step); | |
639 | |
640 if (sd->adj->value != CLAMP(sd->adj->value + amt, sd->adj->lower, sd->adj->upper - sd->adj->page_size)) | |
641 { | |
642 /* only notify when scrolling is needed */ | |
643 if (sd->notify_func && !sd->notify_func(sd->widget, x, y, sd->notify_data)) | |
644 { | |
1523 | 645 sd->timer_id = 0; |
9 | 646 widget_auto_scroll_stop(sd->widget); |
647 return FALSE; | |
648 } | |
649 | |
650 gtk_adjustment_set_value(sd->adj, | |
651 CLAMP(sd->adj->value + amt, sd->adj->lower, sd->adj->upper - sd->adj->page_size)); | |
652 } | |
653 } | |
654 | |
655 return TRUE; | |
656 } | |
657 | |
658 gint widget_auto_scroll_start(GtkWidget *widget, GtkAdjustment *v_adj, gint scroll_speed, gint region_size, | |
659 gint (*notify_func)(GtkWidget *widget, gint x, gint y, gpointer data), gpointer notify_data) | |
660 { | |
661 AutoScrollData *sd; | |
662 | |
663 if (!widget || !v_adj) return 0; | |
664 if (g_object_get_data(G_OBJECT(widget), "autoscroll")) return 0; | |
665 if (scroll_speed < 1) scroll_speed = AUTO_SCROLL_DEFAULT_SPEED; | |
666 if (region_size < 1) region_size = AUTO_SCROLL_DEFAULT_REGION; | |
667 | |
668 sd = g_new0(AutoScrollData, 1); | |
669 sd->widget = widget; | |
670 sd->adj = v_adj; | |
671 sd->region_size = region_size; | |
672 sd->max_step = 1; | |
673 sd->timer_id = g_timeout_add(scroll_speed, widget_auto_scroll_cb, sd); | |
674 | |
675 sd->notify_func = notify_func; | |
676 sd->notify_data = notify_data; | |
677 | |
678 g_object_set_data(G_OBJECT(widget), "autoscroll", sd); | |
679 | |
680 return scroll_speed; | |
681 } | |
682 | |
683 | |
684 /* | |
685 *------------------------------------------------------------------- | |
686 * GList utils | |
687 *------------------------------------------------------------------- | |
688 */ | |
689 | |
690 GList *uig_list_insert_link(GList *list, GList *link, gpointer data) | |
691 { | |
692 GList *new_list; | |
693 | |
694 if (!list || link == list) return g_list_prepend(list, data); | |
695 if (!link) return g_list_append(list, data); | |
696 | |
513
985fdfebd89e
Remove whitespace between function name and first parenthesis for the sake of consistency. (pass 2)
zas_
parents:
475
diff
changeset
|
697 new_list = g_list_alloc(); |
9 | 698 new_list->data = data; |
699 | |
700 if (link->prev) | |
701 { | |
702 link->prev->next = new_list; | |
703 new_list->prev = link->prev; | |
704 } | |
705 else | |
706 { | |
707 list = new_list; | |
708 } | |
709 link->prev = new_list; | |
710 new_list->next = link; | |
711 | |
712 return list; | |
713 } | |
714 | |
715 GList *uig_list_insert_list(GList *parent, GList *insert_link, GList *list) | |
716 { | |
717 GList *end; | |
718 | |
719 if (!insert_link) return g_list_concat(parent, list); | |
720 if (insert_link == parent) return g_list_concat(list, parent); | |
721 if (!parent) return list; | |
722 if (!list) return parent; | |
723 | |
724 end = g_list_last(list); | |
725 | |
726 if (insert_link->prev) insert_link->prev->next = list; | |
727 list->prev = insert_link->prev; | |
728 insert_link->prev = end; | |
729 end->next = insert_link; | |
730 | |
731 return parent; | |
732 } | |
1055
1646720364cf
Adding a vim modeline to all files - patch by Klaus Ethgen
nadvornik
parents:
1046
diff
changeset
|
733 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ |