Mercurial > geeqie
annotate src/ui_tree_edit.c @ 1811:f405ec9b696b default tip
Some small logic mistakes
Use boolean operators for booleans and bitwise otherwise only.
| author | mow |
|---|---|
| date | Mon, 10 May 2010 11:33:13 +0000 |
| parents | c416d099a3dc |
| children |
| rev | line source |
|---|---|
| 9 | 1 /* |
| 2 * (SLIK) SimpLIstic sKin functions | |
| 3 * (C) 2004 John Ellis | |
| 1802 | 4 * Copyright (C) 2008 - 2010 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; | |
| 1810 | 187 #if GTK_CHECK_VERSION(2,20,0) |
| 188 if (!gtk_widget_get_visible(tree)) return FALSE; | |
| 189 #else | |
| 9 | 190 if (!GTK_WIDGET_VISIBLE(tree)) return FALSE; |
| 1810 | 191 #endif |
| 9 | 192 |
| 193 tcolumn = gtk_tree_view_get_column(tree, column); | |
| 194 if (!tcolumn) return FALSE; | |
| 195 | |
| 1767 | 196 #if GTK_CHECK_VERSION(2,18,0) |
| 197 list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(tcolumn)); | |
| 198 #else | |
| 9 | 199 list = gtk_tree_view_column_get_cell_renderers(tcolumn); |
| 1767 | 200 #endif |
| 9 | 201 work = list; |
| 202 while (work && !cell) | |
| 203 { | |
| 204 cell = work->data; | |
| 205 if (!GTK_IS_CELL_RENDERER_TEXT(cell)) | |
| 206 { | |
| 207 cell = NULL; | |
| 208 } | |
| 209 work = work->next; | |
| 210 } | |
| 211 | |
| 212 g_list_free(list); | |
| 213 if (!cell) return FALSE; | |
| 214 | |
| 215 if (!text) text = ""; | |
| 216 | |
| 217 ted = g_new0(TreeEditData, 1); | |
| 218 | |
| 219 ted->old_name = g_strdup(text); | |
| 220 | |
| 221 ted->edit_func = edit_func; | |
| 222 ted->edit_data = data; | |
| 223 | |
| 224 ted->tree = tree; | |
| 225 ted->path = gtk_tree_path_copy(tpath); | |
| 226 ted->column = tcolumn; | |
| 227 ted->cell = cell; | |
| 228 | |
| 229 gtk_tree_view_scroll_to_cell(ted->tree, ted->path, ted->column, FALSE, 0.0, 0.0); | |
| 230 | |
| 231 /* create the window */ | |
| 232 | |
| 233 ted->window = gtk_window_new(GTK_WINDOW_POPUP); | |
| 234 gtk_window_set_resizable(GTK_WINDOW(ted->window), FALSE); | |
| 235 g_signal_connect(G_OBJECT(ted->window), "button_press_event", | |
| 236 G_CALLBACK(tree_edit_click_cb), ted); | |
| 237 g_signal_connect(G_OBJECT(ted->window), "key_press_event", | |
| 238 G_CALLBACK(tree_edit_key_press_cb), ted); | |
| 239 | |
| 240 ted->entry = gtk_entry_new(); | |
| 241 gtk_entry_set_text(GTK_ENTRY(ted->entry), ted->old_name); | |
| 242 gtk_editable_select_region(GTK_EDITABLE(ted->entry), 0, strlen(ted->old_name)); | |
| 243 gtk_container_add(GTK_CONTAINER(ted->window), ted->entry); | |
| 244 gtk_widget_show(ted->entry); | |
| 245 | |
| 246 /* due to the fact that gtktreeview scrolls in an idle loop, we cannot | |
| 247 * reliably get the cell position until those scroll priority signals are processed | |
| 248 */ | |
| 249 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE - 2, tree_edit_by_path_idle_cb, ted, NULL); | |
| 250 | |
| 251 return TRUE; | |
| 252 } | |
| 253 | |
| 254 /* | |
| 255 *------------------------------------------------------------------- | |
| 256 * tree cell position retrieval | |
| 257 *------------------------------------------------------------------- | |
| 258 */ | |
| 259 | |
| 1448 | 260 gboolean tree_view_get_cell_origin(GtkTreeView *widget, GtkTreePath *tpath, gint column, gboolean text_cell_only, |
| 261 gint *x, gint *y, gint *width, gint *height) | |
| 9 | 262 { |
| 263 gint x_origin, y_origin; | |
| 264 gint x_offset, y_offset; | |
| 265 gint header_size; | |
| 266 GtkTreeViewColumn *tv_column; | |
| 267 GdkRectangle rect; | |
| 268 | |
| 269 tv_column = gtk_tree_view_get_column(widget, column); | |
| 270 if (!tv_column || !tpath) return FALSE; | |
| 271 | |
| 272 /* hmm, appears the rect will not account for X scroll, but does for Y scroll | |
| 273 * use x_offset instead for X scroll (sigh) | |
| 274 */ | |
| 275 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
|
276 #if GTK_CHECK_VERSION(2,12,0) |
|
4220d5536ad9
fixed usage of deprecated functions - patch by Omari Stephens
nadvornik
parents:
1055
diff
changeset
|
277 gtk_tree_view_convert_tree_to_widget_coords(widget, 0, 0, &x_offset, &y_offset); |
| 1043 | 278 #else |
| 9 | 279 gtk_tree_view_tree_to_widget_coords(widget, 0, 0, &x_offset, &y_offset); |
| 1043 | 280 #endif |
| 9 | 281 gdk_window_get_origin(GTK_WIDGET(widget)->window, &x_origin, &y_origin); |
| 282 | |
| 283 if (gtk_tree_view_get_headers_visible(widget)) | |
| 284 { | |
| 285 header_size = tv_column->button->allocation.height; | |
| 286 } | |
| 287 else | |
| 288 { | |
| 289 header_size = 0; | |
| 290 } | |
| 291 | |
| 292 if (text_cell_only) | |
| 293 { | |
| 294 GtkCellRenderer *cell = NULL; | |
| 295 GList *renderers; | |
| 296 GList *work; | |
| 297 gint cell_x; | |
| 298 gint cell_width; | |
| 299 | |
| 1767 | 300 #if GTK_CHECK_VERSION(2,18,0) |
| 301 renderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(tv_column)); | |
| 302 #else | |
| 9 | 303 renderers = gtk_tree_view_column_get_cell_renderers(tv_column); |
| 1767 | 304 #endif |
| 9 | 305 work = renderers; |
| 306 while (work && !cell) | |
| 307 { | |
| 308 cell = work->data; | |
| 309 work = work->next; | |
| 310 if (!GTK_IS_CELL_RENDERER_TEXT(cell)) cell = NULL; | |
| 311 } | |
| 312 g_list_free(renderers); | |
| 313 | |
| 314 if (!cell) return FALSE; | |
| 442 | 315 |
| 9 | 316 if (!gtk_tree_view_column_cell_get_position(tv_column, cell, &cell_x, &cell_width)) |
| 317 { | |
| 318 cell_x = 0; | |
| 319 cell_width = rect.width; | |
| 320 } | |
| 321 *x = x_origin + x_offset + rect.x + cell_x; | |
| 322 *width = cell_width; | |
| 323 } | |
| 324 else | |
| 325 { | |
| 326 *x = x_origin + x_offset + rect.x; | |
| 327 *width = rect.width; | |
| 328 } | |
| 329 *y = y_origin + rect.y + header_size; | |
| 330 *height = rect.height; | |
| 331 return TRUE; | |
| 332 } | |
| 333 | |
| 1448 | 334 void tree_view_get_cell_clamped(GtkTreeView *widget, GtkTreePath *tpath, gint column, gboolean text_cell_only, |
| 9 | 335 gint *x, gint *y, gint *width, gint *height) |
| 336 { | |
| 337 gint wx, wy, ww, wh; | |
| 338 GdkWindow *window; | |
| 339 | |
| 340 window = GTK_WIDGET(widget)->window; | |
| 341 gdk_window_get_origin(window, &wx, &wy); | |
| 342 gdk_drawable_get_size(window, &ww, &wh); | |
| 343 if (!tree_view_get_cell_origin(widget, tpath, column, text_cell_only, x, y, width, height)) | |
| 344 { | |
| 345 *x = wx; | |
| 346 *y = wy; | |
| 347 *width = ww; | |
| 348 *height = wh; | |
| 349 return; | |
| 350 } | |
| 351 | |
| 352 *width = MIN(*width, ww); | |
| 353 *x = CLAMP(*x, wx, wx + ww - (*width)); | |
| 354 *y = CLAMP(*y, wy, wy + wh); | |
| 355 *height = MIN(*height, wy + wh - (*y)); | |
| 356 } | |
| 357 | |
|
1631
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
358 #if GTK_CHECK_VERSION(2,8,0) |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
359 /* an implementation that uses gtk_tree_view_get_visible_range */ |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
360 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
|
361 { |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
362 GtkTreeModel *store; |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
363 GtkTreePath *tpath, *start_path, *end_path; |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
364 gint ret = 0; |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
365 |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
366 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
|
367 |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
368 store = gtk_tree_view_get_model(widget); |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
369 tpath = gtk_tree_model_get_path(store, iter); |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
370 |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
371 if (fully_visible) |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
372 { |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
373 if (gtk_tree_path_compare(tpath, start_path) <= 0) |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
374 { |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
375 ret = -1; |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
376 } |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
377 else if (gtk_tree_path_compare(tpath, end_path) >= 0) |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
378 { |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
379 ret = 1; |
|
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 else |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
383 { |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
384 if (gtk_tree_path_compare(tpath, start_path) < 0) |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
385 { |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
386 ret = -1; |
|
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 if (gtk_tree_path_compare(tpath, end_path) > 0) |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
389 { |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
390 ret = 1; |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
391 } |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
392 } |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
393 |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
394 gtk_tree_path_free(tpath); |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
395 gtk_tree_path_free(start_path); |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
396 gtk_tree_path_free(end_path); |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
397 return ret; |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
398 } |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
399 |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
400 #else |
|
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
401 /* 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
|
402 |
| 1448 | 403 gint tree_view_row_get_visibility(GtkTreeView *widget, GtkTreeIter *iter, gboolean fully_visible) |
| 9 | 404 { |
| 405 GtkTreeModel *store; | |
| 442 | 406 GtkTreePath *tpath; |
| 9 | 407 gint cx, cy; |
| 442 | 408 |
| 9 | 409 GdkRectangle vrect; |
| 410 GdkRectangle crect; | |
| 411 | |
| 958 | 412 if (!GTK_WIDGET_REALIZED(GTK_WIDGET(widget))) return -1; /* we will most probably scroll down, needed for tree_view_row_make_visible */ |
| 9 | 413 |
| 414 store = gtk_tree_view_get_model(widget); | |
| 415 tpath = gtk_tree_model_get_path(store, iter); | |
| 416 | |
| 417 gtk_tree_view_get_visible_rect(widget, &vrect); | |
| 418 gtk_tree_view_get_cell_area(widget, tpath, NULL, &crect); | |
| 419 gtk_tree_path_free(tpath); | |
| 420 | |
| 1043 | 421 |
|
1147
4220d5536ad9
fixed usage of deprecated functions - patch by Omari Stephens
nadvornik
parents:
1055
diff
changeset
|
422 #if GTK_CHECK_VERSION(2,12,0) |
|
4220d5536ad9
fixed usage of deprecated functions - patch by Omari Stephens
nadvornik
parents:
1055
diff
changeset
|
423 gtk_tree_view_convert_widget_to_tree_coords(widget, crect.x, crect.y, &cx, &cy); |
| 1043 | 424 #else |
| 9 | 425 gtk_tree_view_widget_to_tree_coords(widget, crect.x, crect.y, &cx, &cy); |
| 1043 | 426 #endif |
| 9 | 427 |
| 428 if (fully_visible) | |
| 429 { | |
| 430 if (cy < vrect.y) return -1; | |
| 431 if (cy + crect.height > vrect.y + vrect.height) return 1; | |
| 432 return 0; | |
| 433 } | |
| 434 | |
| 435 if (cy + crect.height < vrect.y) return -1; | |
| 436 if (cy > vrect.y + vrect.height) return 1; | |
| 437 return 0; | |
| 438 } | |
|
1631
2349fa90226d
better implementation of tree_view_row_get_visibility,
nadvornik
parents:
1523
diff
changeset
|
439 #endif |
| 9 | 440 |
| 1448 | 441 gint tree_view_row_make_visible(GtkTreeView *widget, GtkTreeIter *iter, gboolean center) |
| 9 | 442 { |
| 443 GtkTreePath *tpath; | |
| 444 gint vis; | |
| 445 | |
| 446 vis = tree_view_row_get_visibility(widget, iter, TRUE); | |
| 447 | |
| 448 tpath = gtk_tree_model_get_path(gtk_tree_view_get_model(widget), iter); | |
| 449 if (center && vis != 0) | |
| 450 { | |
| 451 gtk_tree_view_scroll_to_cell(widget, tpath, NULL, TRUE, 0.5, 0.0); | |
| 452 } | |
| 453 else if (vis < 0) | |
| 454 { | |
| 455 gtk_tree_view_scroll_to_cell(widget, tpath, NULL, TRUE, 0.0, 0.0); | |
| 456 } | |
| 457 else if (vis > 0) | |
| 458 { | |
| 459 gtk_tree_view_scroll_to_cell(widget, tpath, NULL, TRUE, 1.0, 0.0); | |
| 460 } | |
| 461 gtk_tree_path_free(tpath); | |
| 462 | |
| 463 return vis; | |
| 464 } | |
| 465 | |
| 1448 | 466 gboolean tree_view_move_cursor_away(GtkTreeView *widget, GtkTreeIter *iter, gboolean only_selected) |
| 9 | 467 { |
| 468 GtkTreeModel *store; | |
| 469 GtkTreePath *tpath; | |
| 470 GtkTreePath *fpath; | |
| 1437 | 471 gboolean move = FALSE; |
| 9 | 472 |
| 473 if (!iter) return FALSE; | |
| 474 | |
| 475 store = gtk_tree_view_get_model(widget); | |
| 476 tpath = gtk_tree_model_get_path(store, iter); | |
| 477 gtk_tree_view_get_cursor(widget, &fpath, NULL); | |
| 478 | |
| 479 if (fpath && gtk_tree_path_compare(tpath, fpath) == 0) | |
| 480 { | |
| 481 GtkTreeSelection *selection; | |
| 482 | |
| 483 selection = gtk_tree_view_get_selection(widget); | |
| 484 | |
| 485 if (!only_selected || | |
| 486 gtk_tree_selection_path_is_selected(selection, tpath)) | |
| 487 { | |
| 488 GtkTreeIter current; | |
| 489 | |
| 490 current = *iter; | |
| 491 if (gtk_tree_model_iter_next(store, ¤t)) | |
| 492 { | |
| 493 gtk_tree_path_next(tpath); | |
| 494 move = TRUE; | |
| 495 } | |
| 496 else if (gtk_tree_path_prev(tpath) && | |
| 497 gtk_tree_model_get_iter(store, ¤t, tpath)) | |
| 498 { | |
| 499 move = TRUE; | |
| 500 } | |
| 501 | |
| 502 if (move) | |
| 503 { | |
| 504 gtk_tree_view_set_cursor(widget, tpath, NULL, FALSE); | |
| 505 } | |
| 506 } | |
| 507 } | |
| 508 | |
| 509 gtk_tree_path_free(tpath); | |
| 510 if (fpath) gtk_tree_path_free(fpath); | |
| 511 | |
| 512 return move; | |
| 513 } | |
| 514 | |
| 515 gint tree_path_to_row(GtkTreePath *tpath) | |
| 516 { | |
| 517 gint *indices; | |
| 442 | 518 |
| 9 | 519 indices = gtk_tree_path_get_indices(tpath); |
| 520 if (indices) return indices[0]; | |
| 442 | 521 |
| 9 | 522 return -1; |
| 523 } | |
| 524 | |
| 525 | |
| 526 /* | |
| 527 *------------------------------------------------------------------- | |
| 528 * color utilities | |
| 529 *------------------------------------------------------------------- | |
| 530 */ | |
| 531 | |
| 532 void shift_color(GdkColor *src, gshort val, gint direction) | |
| 533 { | |
| 534 gshort cs; | |
| 535 | |
| 536 if (val == -1) | |
| 537 { | |
| 538 val = STYLE_SHIFT_STANDARD; | |
| 539 } | |
| 540 else | |
| 541 { | |
| 542 val = CLAMP(val, 1, 100); | |
| 543 } | |
| 544 cs = 0xffff / 100 * val; | |
| 545 | |
| 546 /* up or down ? */ | |
| 547 if (direction < 0 || | |
| 548 (direction == 0 &&((gint)src->red + (gint)src->green + (gint)src->blue) / 3 > 0xffff / 2)) | |
| 549 { | |
| 550 src->red = MAX(0 , src->red - cs); | |
| 551 src->green = MAX(0 , src->green - cs); | |
| 552 src->blue = MAX(0 , src->blue - cs); | |
| 553 } | |
| 554 else | |
| 555 { | |
| 556 src->red = MIN(0xffff, src->red + cs); | |
| 557 src->green = MIN(0xffff, src->green + cs); | |
| 558 src->blue = MIN(0xffff, src->blue + cs); | |
| 559 } | |
| 560 } | |
| 561 | |
| 562 /* darkens or lightens a style's color for given state | |
| 563 * esp. useful for alternating dark/light in (c)lists | |
| 564 */ | |
| 565 void style_shift_color(GtkStyle *style, GtkStateType type, gshort shift_value, gint direction) | |
| 566 { | |
| 567 if (!style) return; | |
| 568 | |
| 569 shift_color(&style->base[type], shift_value, direction); | |
| 570 shift_color(&style->bg[type], shift_value, direction); | |
| 571 } | |
| 572 | |
| 573 /* | |
| 574 *------------------------------------------------------------------- | |
| 575 * auto scroll by mouse position | |
| 576 *------------------------------------------------------------------- | |
| 577 */ | |
| 578 | |
| 579 #define AUTO_SCROLL_DEFAULT_SPEED 100 | |
| 580 #define AUTO_SCROLL_DEFAULT_REGION 20 | |
| 581 | |
| 582 typedef struct _AutoScrollData AutoScrollData; | |
| 583 struct _AutoScrollData | |
| 584 { | |
| 1523 | 585 guint timer_id; /* event source id */ |
| 9 | 586 gint region_size; |
| 587 GtkWidget *widget; | |
| 588 GtkAdjustment *adj; | |
| 589 gint max_step; | |
| 590 | |
| 591 gint (*notify_func)(GtkWidget *, gint, gint, gpointer); | |
| 592 gpointer notify_data; | |
| 593 }; | |
| 594 | |
| 595 void widget_auto_scroll_stop(GtkWidget *widget) | |
| 596 { | |
| 597 AutoScrollData *sd; | |
| 598 | |
| 599 sd = g_object_get_data(G_OBJECT(widget), "autoscroll"); | |
| 600 if (!sd) return; | |
| 601 g_object_set_data(G_OBJECT(widget), "autoscroll", NULL); | |
| 602 | |
| 1523 | 603 if (sd->timer_id) g_source_remove(sd->timer_id); |
| 9 | 604 g_free(sd); |
| 605 } | |
| 606 | |
| 1448 | 607 static gboolean widget_auto_scroll_cb(gpointer data) |
| 9 | 608 { |
| 609 AutoScrollData *sd = data; | |
| 610 GdkWindow *window; | |
| 611 gint x, y; | |
| 612 gint w, h; | |
| 613 gint amt = 0; | |
| 614 | |
| 615 if (sd->max_step < sd->region_size) | |
| 616 { | |
| 617 sd->max_step = MIN(sd->region_size, sd->max_step + 2); | |
| 618 } | |
| 619 | |
| 620 window = sd->widget->window; | |
| 621 gdk_window_get_pointer(window, &x, &y, NULL); | |
| 622 gdk_drawable_get_size(window, &w, &h); | |
| 623 | |
| 624 if (x < 0 || x >= w || y < 0 || y >= h) | |
| 625 { | |
| 1523 | 626 sd->timer_id = 0; |
| 9 | 627 widget_auto_scroll_stop(sd->widget); |
| 628 return FALSE; | |
| 629 } | |
| 630 | |
| 631 if (h < sd->region_size * 3) | |
| 632 { | |
| 633 /* height is cramped, nicely divide into three equal regions */ | |
| 634 if (y < h / 3 || y > h / 3 * 2) | |
| 635 { | |
| 636 amt = (y < h / 2) ? 0 - ((h / 2) - y) : y - (h / 2); | |
| 637 } | |
| 638 } | |
| 639 else if (y < sd->region_size) | |
| 640 { | |
| 641 amt = 0 - (sd->region_size - y); | |
| 642 } | |
| 643 else if (y >= h - sd->region_size) | |
| 644 { | |
| 645 amt = y - (h - sd->region_size); | |
| 646 } | |
| 647 | |
| 648 if (amt != 0) | |
| 649 { | |
| 650 amt = CLAMP(amt, 0 - sd->max_step, sd->max_step); | |
| 651 | |
| 652 if (sd->adj->value != CLAMP(sd->adj->value + amt, sd->adj->lower, sd->adj->upper - sd->adj->page_size)) | |
| 653 { | |
| 654 /* only notify when scrolling is needed */ | |
| 655 if (sd->notify_func && !sd->notify_func(sd->widget, x, y, sd->notify_data)) | |
| 656 { | |
| 1523 | 657 sd->timer_id = 0; |
| 9 | 658 widget_auto_scroll_stop(sd->widget); |
| 659 return FALSE; | |
| 660 } | |
| 661 | |
| 662 gtk_adjustment_set_value(sd->adj, | |
| 663 CLAMP(sd->adj->value + amt, sd->adj->lower, sd->adj->upper - sd->adj->page_size)); | |
| 664 } | |
| 665 } | |
| 666 | |
| 667 return TRUE; | |
| 668 } | |
| 669 | |
| 670 gint widget_auto_scroll_start(GtkWidget *widget, GtkAdjustment *v_adj, gint scroll_speed, gint region_size, | |
| 671 gint (*notify_func)(GtkWidget *widget, gint x, gint y, gpointer data), gpointer notify_data) | |
| 672 { | |
| 673 AutoScrollData *sd; | |
| 674 | |
| 675 if (!widget || !v_adj) return 0; | |
| 676 if (g_object_get_data(G_OBJECT(widget), "autoscroll")) return 0; | |
| 677 if (scroll_speed < 1) scroll_speed = AUTO_SCROLL_DEFAULT_SPEED; | |
| 678 if (region_size < 1) region_size = AUTO_SCROLL_DEFAULT_REGION; | |
| 679 | |
| 680 sd = g_new0(AutoScrollData, 1); | |
| 681 sd->widget = widget; | |
| 682 sd->adj = v_adj; | |
| 683 sd->region_size = region_size; | |
| 684 sd->max_step = 1; | |
| 685 sd->timer_id = g_timeout_add(scroll_speed, widget_auto_scroll_cb, sd); | |
| 686 | |
| 687 sd->notify_func = notify_func; | |
| 688 sd->notify_data = notify_data; | |
| 689 | |
| 690 g_object_set_data(G_OBJECT(widget), "autoscroll", sd); | |
| 691 | |
| 692 return scroll_speed; | |
| 693 } | |
| 694 | |
| 695 | |
| 696 /* | |
| 697 *------------------------------------------------------------------- | |
| 698 * GList utils | |
| 699 *------------------------------------------------------------------- | |
| 700 */ | |
| 701 | |
| 702 GList *uig_list_insert_link(GList *list, GList *link, gpointer data) | |
| 703 { | |
| 704 GList *new_list; | |
| 705 | |
| 706 if (!list || link == list) return g_list_prepend(list, data); | |
| 707 if (!link) return g_list_append(list, data); | |
| 708 | |
|
513
985fdfebd89e
Remove whitespace between function name and first parenthesis for the sake of consistency. (pass 2)
zas_
parents:
475
diff
changeset
|
709 new_list = g_list_alloc(); |
| 9 | 710 new_list->data = data; |
| 711 | |
| 712 if (link->prev) | |
| 713 { | |
| 714 link->prev->next = new_list; | |
| 715 new_list->prev = link->prev; | |
| 716 } | |
| 717 else | |
| 718 { | |
| 719 list = new_list; | |
| 720 } | |
| 721 link->prev = new_list; | |
| 722 new_list->next = link; | |
| 723 | |
| 724 return list; | |
| 725 } | |
| 726 | |
| 727 GList *uig_list_insert_list(GList *parent, GList *insert_link, GList *list) | |
| 728 { | |
| 729 GList *end; | |
| 730 | |
| 731 if (!insert_link) return g_list_concat(parent, list); | |
| 732 if (insert_link == parent) return g_list_concat(list, parent); | |
| 733 if (!parent) return list; | |
| 734 if (!list) return parent; | |
| 735 | |
| 736 end = g_list_last(list); | |
| 737 | |
| 738 if (insert_link->prev) insert_link->prev->next = list; | |
| 739 list->prev = insert_link->prev; | |
| 740 insert_link->prev = end; | |
| 741 end->next = insert_link; | |
| 742 | |
| 743 return parent; | |
| 744 } | |
|
1055
1646720364cf
Adding a vim modeline to all files - patch by Klaus Ethgen
nadvornik
parents:
1046
diff
changeset
|
745 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ |
