static gboolean gimp_container_tree_view_scroll_timeout (gpointer data) { GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (data); GtkAdjustment *adj; gdouble new_value; adj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (tree_view->view)); #ifdef SCROLL_DEBUG g_print ("scroll_timeout: scrolling by %d\n", SCROLL_STEP); #endif if (tree_view->scroll_dir == GDK_SCROLL_UP) new_value = adj->value - SCROLL_STEP; else new_value = adj->value + SCROLL_STEP; new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size); gtk_adjustment_set_value (adj, new_value); if (tree_view->scroll_timeout_id) { g_source_remove (tree_view->scroll_timeout_id); tree_view->scroll_timeout_id = g_timeout_add (tree_view->scroll_timeout_interval, gimp_container_tree_view_scroll_timeout, tree_view); } return FALSE; }
/* cleans up the item list, sets up the iter hash when called for the first time */ void item_list_view_clear (ItemListView *ilv) { GtkAdjustment *adj; GtkTreeStore *itemstore; itemstore = GTK_TREE_STORE (gtk_tree_view_get_model (ilv->priv->treeview)); /* unselecting all items is important to remove items whose removal is deferred until unselecting */ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (ilv->priv->treeview)); adj = gtk_tree_view_get_vadjustment (ilv->priv->treeview); gtk_adjustment_set_value (adj, 0.0); #if GTK_API_VERSION >= 3 gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (ilv->priv->treeview), adj); #else gtk_tree_view_set_vadjustment (ilv->priv->treeview, adj); #endif if (itemstore) gtk_tree_store_clear (itemstore); if (ilv->priv->item_id_to_iter) g_hash_table_destroy (ilv->priv->item_id_to_iter); ilv->priv->item_id_to_iter = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); /* enable batch mode for following item adds */ ilv->priv->batch_mode = TRUE; ilv->priv->batch_itemstore = item_list_view_create_tree_store (); }
/* Scroll function taken/adapted from gtktreeview.c */ static gint scroll_row_timeout (gpointer data) { GtkTreeView *tree_view = data; GdkRectangle visible_rect; gint y, x; gint offset; gfloat value; GtkAdjustment* vadj; RbTreeDndData *priv_data; GDK_THREADS_ENTER (); priv_data = g_object_get_data (G_OBJECT (tree_view), RB_TREE_DND_STRING); g_return_val_if_fail(priv_data != NULL, TRUE); gdk_window_get_pointer (gtk_tree_view_get_bin_window (tree_view), &x, &y, NULL); gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &x, &y); gtk_tree_view_convert_bin_window_to_tree_coords (tree_view, x, y, &x, &y); gtk_tree_view_get_visible_rect (tree_view, &visible_rect); /* see if we are near the edge. */ if (x < visible_rect.x && x > visible_rect.x + visible_rect.width) { GDK_THREADS_LEAVE (); priv_data->scroll_timeout = 0; return FALSE; } offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE); if (offset > 0) { offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE); if (offset < 0) { GDK_THREADS_LEAVE (); priv_data->scroll_timeout = 0; return FALSE; } } vadj = gtk_tree_view_get_vadjustment (tree_view); value = CLAMP (vadj->value + offset, vadj->lower, vadj->upper - vadj->page_size); gtk_adjustment_set_value (vadj, value); /* don't remove it if we're on the edge and not scrolling */ if (ABS (vadj->value - value) > 0.0001) remove_select_on_drag_timeout(tree_view); GDK_THREADS_LEAVE (); return TRUE; }
static void test_position (GtkTreeView *tree_view, GtkTreePath *path, gboolean use_align, gfloat row_align, gfloat col_align) { gint pos; gchar *path_str; GdkRectangle rect; GtkTreeModel *model; gint row_start; /* Get the location of the path we scrolled to */ gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view), path, NULL, &rect); row_start = get_row_start_for_index (GTK_TREE_VIEW (tree_view), gtk_tree_path_get_indices (path)[0]); /* Ugh */ pos = get_pos_from_path (GTK_TREE_VIEW (tree_view), path, rect.height, gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (tree_view))); /* This is only tested for during test_single() */ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); if (gtk_tree_model_iter_n_children (model, NULL) == 1) { GtkTreePath *tmppath; /* Test nothing is dangling at the bottom; read * description for test_single() for more information. */ /* FIXME: hardcoded width */ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view), 0, GTK_WIDGET (tree_view)->allocation.height - 30, &tmppath, NULL, NULL, NULL)) { g_assert_not_reached (); gtk_tree_path_free (tmppath); } } path_str = gtk_tree_path_to_string (path); if (use_align) { g_assert (test_position_with_align (tree_view, pos, rect.y, row_start, rect.height, row_align)); } else { g_assert (test_position_without_align (tree_view, row_start, rect.height)); } g_free (path_str); }
static void scroll_new_row_tree (ScrollFixture *fixture, gconstpointer test_data) { GtkTreeModel *model; GtkAdjustment *vadjustment; int i; /* The goal of this test is to append new rows at the end of a tree * store and immediately scroll to them. If there is a parent * node with a couple of childs in the "area above" to explore, * this used to lead to unexpected results due to a bug. * * This issue has been reported by Miroslav Rajcic on * gtk-app-devel-list: * http://mail.gnome.org/archives/gtk-app-devel-list/2008-December/msg00068.html */ gtk_widget_show_all (fixture->window); gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view)); while (gtk_events_pending ()) gtk_main_iteration (); model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)); vadjustment = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (fixture->tree_view)); for (i = 0; i < 5; i++) { GtkTreeIter scroll_iter; GtkTreePath *scroll_path; gtk_tree_store_append (GTK_TREE_STORE (model), &scroll_iter, NULL); gtk_tree_store_set (GTK_TREE_STORE (model), &scroll_iter, 0, "New node", -1); scroll_path = gtk_tree_model_get_path (model, &scroll_iter); gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view), scroll_path, NULL, FALSE, 0.0, 0.0); gtk_tree_path_free (scroll_path); while (gtk_events_pending ()) gtk_main_iteration (); /* Test position, the scroll bar must be at the end */ g_assert (vadjustment->value == vadjustment->upper - vadjustment->page_size); } }
static void scroll_to_position (PhidiasItemsClassic *view) { GtkAdjustment *adj; /** TODO Save a status for each submitted model, so to be able to return to the original position */ adj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (view->priv->list)); if (adj != NULL) { gtk_adjustment_set_value (adj, 0.0); gtk_tree_view_set_vadjustment (GTK_TREE_VIEW (view->priv->list), adj); } }
static void test_editable_position (GtkWidget *tree_view, GtkWidget *editable, GtkTreePath *cursor_path) { GdkRectangle rect; GtkAdjustment *vadj; gtk_tree_view_get_background_area (GTK_TREE_VIEW (tree_view), cursor_path, NULL, &rect); vadj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (tree_view)); /* There are all in bin_window coordinates */ g_assert (editable->allocation.y == rect.y + ((rect.height - editable->allocation.height) / 2)); }
static gboolean test_position_without_align (GtkTreeView *tree_view, gint row_start, gint row_height) { GtkAdjustment *vadj = gtk_tree_view_get_vadjustment (tree_view); /* Without align the tree view does as less work as possible, * so basically we only have to check whether the row * is visible on the screen. */ if (vadj->value <= row_start && vadj->value + vadj->page_size >= row_start + row_height) return TRUE; return FALSE; }
/* Test for GNOME bugzilla bug 359231; tests "recovery when removing a bunch of * rows at the bottom. */ static void test_bug316689 (ScrollFixture *fixture, gconstpointer test_data) { GtkTreeIter iter; GtkTreePath *path; GtkAdjustment *vadj; GtkTreeModel *model; /* The aim of this test is to scroll to the bottom of a TreeView, * remove at least one page_size of items and check if TreeView * correctly corrects the scroll bar (else they will look "broken"). * * See #316689. */ g_test_bug ("316689"); /* Scroll to some place close to the end */ path = gtk_tree_path_new_from_indices (N_ROWS - 4, -1); scroll (fixture, path, FALSE, 0.0); gtk_tree_path_free (path); /* No need for a while events pending loop here, scroll() does this for us. * * We now remove a bunch of rows, wait for events to process and then * check the adjustments to see if the TreeView gracefully recovered. */ model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view)); while (gtk_tree_model_iter_nth_child (model, &iter, NULL, N_ROWS - 15)) gtk_list_store_remove (GTK_LIST_STORE (model), &iter); while (gtk_events_pending ()) gtk_main_iteration (); vadj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (fixture->tree_view)); g_assert (vadj->value + vadj->page_size <= vadj->upper); g_assert (vadj->value == vadj->upper - vadj->page_size); }
static gboolean usage_view_tree_view_scroll_event_cb (GtkWidget *widget, GdkEventScroll *event, gpointer data) { GtkAdjustment *adj; GtkTreeView *tv = GTK_TREE_VIEW (widget); gdouble new_value; if (event->direction != GDK_SCROLL_UP && event->direction != GDK_SCROLL_DOWN) { return FALSE; } adj = gtk_tree_view_get_vadjustment (tv); if (event->direction == GDK_SCROLL_UP) { new_value = adj->value - adj->page_increment / 2; } else { new_value = adj->value + adj->page_increment / 2; } new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size); gtk_adjustment_set_value (adj, new_value); return TRUE; }
/* * init debug related GUI (watch tree view) * arguments: */ void debug_init() { /* create watch page */ wtree = wtree_init(on_watch_expanded_callback, on_watch_dragged_callback, on_watch_key_pressed_callback, on_watch_changed, on_watch_button_pressed_callback); wmodel = gtk_tree_view_get_model(GTK_TREE_VIEW(wtree)); wstore = GTK_TREE_STORE(wmodel); tab_watch = gtk_scrolled_window_new( gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(wtree)), gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(wtree)) ); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_watch), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(tab_watch), wtree); /* create autos page */ atree = atree_init(on_watch_expanded_callback, on_watch_button_pressed_callback); tab_autos = gtk_scrolled_window_new( gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(atree)), gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(atree)) ); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_autos), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(tab_autos), atree); /* create stack trace page */ stree = stree_init(editor_open_position, on_select_frame); tab_call_stack = gtk_scrolled_window_new( gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(stree )), gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(stree )) ); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_call_stack), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(tab_call_stack), stree); /* create debug terminal page */ terminal = vte_terminal_new(); /* create PTY */ openpty(&pty_master, &pty_slave, NULL, NULL, NULL); grantpt(pty_master); unlockpt(pty_master); vte_terminal_set_pty(VTE_TERMINAL(terminal), pty_master); GtkWidget *scrollbar = gtk_vscrollbar_new(GTK_ADJUSTMENT(VTE_TERMINAL(terminal)->adjustment)); GTK_WIDGET_UNSET_FLAGS(scrollbar, GTK_CAN_FOCUS); tab_terminal = gtk_frame_new(NULL); gtk_frame_set_shadow_type (GTK_FRAME(tab_terminal), GTK_SHADOW_NONE); GtkWidget *hbox = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(tab_terminal), hbox); gtk_box_pack_start(GTK_BOX(hbox), terminal, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, FALSE, 0); /* set the default widget size first to prevent VTE expanding too much, * sometimes causing the hscrollbar to be too big or out of view. */ gtk_widget_set_size_request(GTK_WIDGET(terminal), 10, 10); vte_terminal_set_size(VTE_TERMINAL(terminal), 30, 1); /* set terminal font. */ GKeyFile *config = g_key_file_new(); gchar *configfile = g_strconcat(geany_data->app->configdir, G_DIR_SEPARATOR_S, "geany.conf", NULL); g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL); gchar *font = utils_get_setting_string(config, "VTE", "font", "Monospace 10"); vte_terminal_set_font_from_string (VTE_TERMINAL(terminal), font); /* debug messages page */ tab_messages = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_messages), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(tab_messages)); vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(tab_messages)); debugger_messages_textview = gtk_text_view_new(); gtk_text_view_set_editable (GTK_TEXT_VIEW (debugger_messages_textview), FALSE); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tab_messages), debugger_messages_textview); /* create tex tags */ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(debugger_messages_textview)); gtk_text_buffer_create_tag(buffer, "black", "foreground", "#000000", NULL); gtk_text_buffer_create_tag(buffer, "grey", "foreground", "#AAAAAA", NULL); gtk_text_buffer_create_tag(buffer, "red", "foreground", "#FF0000", NULL); gtk_text_buffer_create_tag(buffer, "green", "foreground", "#00FF00", NULL); gtk_text_buffer_create_tag(buffer, "blue", "foreground", "#0000FF", NULL); gtk_text_buffer_create_tag(buffer, "yellow", "foreground", "#FFFF00", NULL); gtk_text_buffer_create_tag(buffer, "brown", "foreground", "#BB8915", NULL); gtk_text_buffer_create_tag(buffer, "rose", "foreground", "#BA92B7", NULL); }
gfloat userlist_get_value (GtkWidget *treeview) { return gtk_adjustment_get_value (gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (treeview))); }
void userlist_set_value (GtkWidget *treeview, gfloat val) { gtk_adjustment_set_value ( gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (treeview)), val); }
static void set_up_tree_view (TotemYouTubePlugin *self, GtkBuilder *builder, guint key) { GtkUIManager *ui_manager; GtkActionGroup *action_group; GtkAction *action, *menu_item; GtkWidget *vscroll, *tree_view; GtkTreeViewColumn *column; GtkCellRenderer *renderer; /* Add the cell renderer. This can't be done with GtkBuilder, because it unavoidably sets the expand parameter to FALSE */ /* TODO: Depends on bug #453692 */ renderer = GTK_CELL_RENDERER (totem_cell_renderer_video_new (TRUE)); column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, (key == SEARCH_TREE_VIEW) ? "yt_treeview_search_column" : "yt_treeview_related_column")); gtk_tree_view_column_pack_start (column, renderer, TRUE); gtk_tree_view_column_set_attributes (column, renderer, "thumbnail", 0, "title", 1, NULL); /* Give the video lists a handle to Totem and connect their scrollbar signals */ if (key == SEARCH_TREE_VIEW) { tree_view = GTK_WIDGET (gtk_builder_get_object (builder, "yt_treeview_search")); vscroll = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (gtk_builder_get_object (builder, "yt_scrolled_window_search"))); self->list_store[key] = GTK_LIST_STORE (gtk_builder_get_object (builder, "yt_list_store_search")); self->tree_view[key] = GTK_TREE_VIEW (tree_view); self->progress_bar[key] = GTK_PROGRESS_BAR (gtk_builder_get_object (builder, "yt_progress_bar_search")); } else { tree_view = GTK_WIDGET (gtk_builder_get_object (builder, "yt_treeview_related")); vscroll = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (gtk_builder_get_object (builder, "yt_scrolled_window_related"))); self->list_store[key] = GTK_LIST_STORE (gtk_builder_get_object (builder, "yt_list_store_related")); self->tree_view[key] = GTK_TREE_VIEW (tree_view); self->progress_bar[key] = GTK_PROGRESS_BAR (gtk_builder_get_object (builder, "yt_progress_bar_related")); } g_object_set (tree_view, "totem", self->totem, NULL); g_signal_connect (vscroll, "button-press-event", G_CALLBACK (button_press_event_cb), self); g_signal_connect (vscroll, "button-release-event", G_CALLBACK (button_release_event_cb), self); /* Add the extra popup menu options. This is done here rather than in the UI file, because it's done for multiple treeviews; * if it were done in the UI file, the same action group would be used multiple times, which GTK+ doesn't like. */ ui_manager = totem_video_list_get_ui_manager (TOTEM_VIDEO_LIST (tree_view)); action_group = gtk_action_group_new ("youtube-action-group"); action = gtk_action_new ("open-in-web-browser", _("_Open in Web Browser"), _("Open the video in your web browser"), "gtk-jump-to"); gtk_action_group_add_action_with_accel (action_group, action, NULL); gtk_ui_manager_insert_action_group (ui_manager, action_group, 1); gtk_ui_manager_add_ui (ui_manager, gtk_ui_manager_new_merge_id (ui_manager), "/ui/totem-video-list-popup/", "open-in-web-browser", "open-in-web-browser", GTK_UI_MANAGER_MENUITEM, FALSE); menu_item = gtk_ui_manager_get_action (ui_manager, "/ui/totem-video-list-popup/open-in-web-browser"); g_signal_connect (menu_item, "activate", G_CALLBACK (open_in_web_browser_activate_cb), self); /* Connect to more scroll events */ #if GTK_CHECK_VERSION(3, 0, 0) self->vadjust[key] = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(tree_view)); #else self->vadjust[key] = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(tree_view)); #endif g_signal_connect (self->vadjust[key], "value-changed", G_CALLBACK (value_changed_cb), self); self->cancel_button = GTK_WIDGET (gtk_builder_get_object (builder, "yt_cancel_button")); }
static GtkWidget * usage_view_create_widget (PlannerView *view) { PlannerUsageViewPriv *priv; MrpProject *project; GtkWidget *hpaned; GtkWidget *left_frame; GtkWidget *right_frame; PlannerUsageModel *model; GtkWidget *tree; GtkWidget *vbox; GtkWidget *sw; GtkWidget *chart; GtkAdjustment *hadj, *vadj; project = planner_window_get_project (view->main_window); priv = PLANNER_USAGE_VIEW (view)->priv; priv->project = project; g_signal_connect (project, "loaded", G_CALLBACK (usage_view_project_loaded_cb), view); g_signal_connect (project, "resource_added", G_CALLBACK (usage_view_resource_added_cb), view); model = planner_usage_model_new (project); tree = planner_usage_tree_new (view->main_window, model); priv->tree = tree; left_frame = gtk_frame_new (NULL); right_frame = gtk_frame_new (NULL); vbox = gtk_vbox_new (FALSE, 3); gtk_box_pack_start (GTK_BOX (vbox), tree, TRUE, TRUE, 0); hadj = gtk_tree_view_get_hadjustment (GTK_TREE_VIEW (tree)); gtk_box_pack_start (GTK_BOX (vbox), gtk_hscrollbar_new (hadj), FALSE, TRUE, 0); gtk_container_add (GTK_CONTAINER (left_frame), vbox); hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 0, 90, 250, 2000)); vadj = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (tree)); chart = planner_usage_chart_new_with_model (GTK_TREE_MODEL (model)); priv->chart = PLANNER_USAGE_CHART (chart); planner_usage_chart_set_view (PLANNER_USAGE_CHART (priv->chart), PLANNER_USAGE_TREE (priv->tree)); gtk_widget_set_events (GTK_WIDGET (priv->chart), GDK_SCROLL_MASK); g_signal_connect (priv->chart, "scroll-event", G_CALLBACK (usage_view_chart_scroll_event), view); sw = gtk_scrolled_window_new (hadj, vadj); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (right_frame), sw); gtk_container_add (GTK_CONTAINER (sw), chart); hpaned = gtk_hpaned_new (); gtk_frame_set_shadow_type (GTK_FRAME (left_frame), GTK_SHADOW_IN); gtk_frame_set_shadow_type (GTK_FRAME (right_frame), GTK_SHADOW_IN); gtk_paned_add1 (GTK_PANED (hpaned), left_frame); gtk_paned_add2 (GTK_PANED (hpaned), right_frame); usage_view_load_columns (PLANNER_USAGE_VIEW (view)); g_signal_connect (tree, "columns-changed", G_CALLBACK (usage_view_tree_view_columns_changed_cb), view); g_signal_connect (tree, "destroy", G_CALLBACK (usage_view_tree_view_destroy_cb), view); g_signal_connect (tree, "row_expanded", G_CALLBACK (usage_view_row_expanded), chart); g_signal_connect (tree, "row_collapsed", G_CALLBACK (usage_view_row_collapsed), chart); g_signal_connect (tree, "expand_all", G_CALLBACK (usage_view_expand_all), chart); g_signal_connect (tree, "collapse_all", G_CALLBACK (usage_view_collapse_all), chart); g_signal_connect (chart, "status_updated", G_CALLBACK (usage_view_usage_status_updated), view); g_signal_connect_after (tree, "size_request", G_CALLBACK (usage_view_tree_view_size_request_cb), NULL); g_signal_connect_after (tree, "scroll_event", G_CALLBACK (usage_view_tree_view_scroll_event_cb), view); g_signal_connect (tree, "style_set", G_CALLBACK (usage_view_tree_style_set_cb), view); gtk_tree_view_expand_all (GTK_TREE_VIEW (tree)); planner_usage_chart_expand_all (PLANNER_USAGE_CHART (chart)); g_object_unref (model); return hpaned; }
static gboolean test_position_with_align (GtkTreeView *tree_view, enum Pos pos, gint row_y, gint row_start, gint row_height, gfloat row_align) { gboolean passed = TRUE; GtkAdjustment *vadj = gtk_tree_view_get_vadjustment (tree_view); /* Switch on row-align: 0.0, 0.5, 1.0 */ switch ((int)(row_align * 2.)) { case 0: if (pos == POS_TOP || pos == POS_CENTER) { /* The row in question is the first row * in the view. * - rect.y should be zero * - dy should be equal to the top * y coordinate of the row. */ if (row_y != 0) passed = FALSE; if (vadj->value != row_start) passed = FALSE; } else { /* The row can be anywhere at the last * page of the tree view. * - dy is set to the start of the * last page. */ if (vadj->value != vadj->upper - vadj->page_size) passed = FALSE; } break; case 1: /* 0.5 */ if (pos == POS_TOP && row_start < vadj->page_size / 2) { /* For the first half of the top view we can't * center the row in the view, instead we * show the first page. * - dy should be zero */ if (vadj->value != 0) passed = FALSE; } else if (pos == POS_BOTTOM && row_start >= vadj->upper - vadj->page_size / 2) { /* For the last half of the bottom view we * can't center the row in the view, instead * we show the last page. * - dy should be the start of the * last page. */ if (vadj->value != vadj->upper - vadj->page_size) passed = FALSE; } else { /* The row is located in the middle of * the view. * - top y coordinate is equal to * middle of the view minus * half the height of the row. * (ie. the row's center is at the * center of the view). */ if (row_y != (int)(vadj->page_size / 2 - row_height / 2)) passed = FALSE; } break; case 2: /* 1.0 */ if (pos == POS_TOP) { /* The row can be anywhere on the * first page of the tree view. * - dy is zero. */ if (vadj->value != 0) passed = FALSE; } else if (pos == POS_CENTER || pos == POS_BOTTOM) { /* The row is the last row visible in the * view. * - rect.y is set to the top of the * last row. * - row_start is greater than page_size * (ie we are not on the first page). * - dy is greater than zero */ if (row_start < vadj->page_size && row_start + row_height < vadj->page_size) passed = FALSE; if (vadj->value <= 0) passed = FALSE; if (row_y != vadj->page_size - row_height) passed = FALSE; } break; } return passed; }