📄 view_dir_tree.c
字号:
list = parts_list(path); list = parts_list_add_node_points(vdt, list); work = list; while (work) { PathData *pd = work->data; if (pd->node == NULL) { PathData *parent_pd; GtkTreeIter parent_iter; GtkTreeIter iter; NodeData *nd; if (work == list) { /* should not happen */ printf("vdtree warning, root node not found\n"); parts_list_free(list); vdtree_busy_pop(vdt); return NULL; } parent_pd = work->prev->data; if (!vdtree_find_row(vdt, parent_pd->node, &parent_iter, NULL) || !vdtree_populate_path_by_iter(vdt, &parent_iter, force, path) || (nd = vdtree_find_iter_by_name(vdt, &parent_iter, pd->name, &iter)) == NULL) { printf("vdtree warning, aborted at %s\n", parent_pd->name); parts_list_free(list); vdtree_busy_pop(vdt); return NULL; } pd->node = nd->fd; if (pd->node) { if (expand) { vdtree_expand_by_iter(vdt, &parent_iter, TRUE); vdtree_expand_by_iter(vdt, &iter, TRUE); } vdtree_populate_path_by_iter(vdt, &iter, force, path); } } else { GtkTreeIter iter; if (vdtree_find_row(vdt, pd->node, &iter, NULL)) { if (expand) vdtree_expand_by_iter(vdt, &iter, TRUE); vdtree_populate_path_by_iter(vdt, &iter, force, path); } } work = work->next; } work = g_list_last(list); if (work) { PathData *pd = work->data; fd = pd->node; } parts_list_free(list); vdtree_busy_pop(vdt); return fd;}/* *---------------------------------------------------------------------------- * access *---------------------------------------------------------------------------- */static gint selection_is_ok = FALSE;static gboolean vdtree_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath, gboolean path_currently_selected, gpointer data){ return selection_is_ok;}static void vdtree_select_row(ViewDirTree *vdt, FileData *fd){ GtkTreeSelection *selection; GtkTreeIter iter; if (!vdtree_find_row(vdt, fd, &iter, NULL)) return; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vdt->treeview)); /* hack, such that selection is only allowed to be changed from here */ selection_is_ok = TRUE; gtk_tree_selection_select_iter(selection, &iter); selection_is_ok = FALSE; if (!vdtree_populate_path_by_iter(vdt, &iter, FALSE, vdt->path)) return; vdtree_expand_by_iter(vdt, &iter, TRUE); if (fd && vdt->select_func) { vdt->select_func(vdt, fd->path, vdt->select_data); }}gint vdtree_set_path(ViewDirTree *vdt, const gchar *path){ FileData *fd; GtkTreeIter iter; if (!path) return FALSE; if (vdt->path && strcmp(path, vdt->path) == 0) return TRUE; g_free(vdt->path); vdt->path = g_strdup(path); fd = vdtree_populate_path(vdt, vdt->path, TRUE, TRUE); if (!fd) return FALSE; if (vdtree_find_row(vdt, fd, &iter, NULL)) { GtkTreeModel *store; GtkTreePath *tpath; tree_view_row_make_visible(GTK_TREE_VIEW(vdt->treeview), &iter, TRUE); store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); tpath = gtk_tree_model_get_path(store, &iter); gtk_tree_view_set_cursor(GTK_TREE_VIEW(vdt->treeview), tpath, NULL, FALSE); gtk_tree_path_free(tpath); vdtree_select_row(vdt, fd); } return TRUE;}#if 0const gchar *vdtree_get_path(ViewDirTree *vdt){ return vdt->path;}#endifvoid vdtree_refresh(ViewDirTree *vdt){ vdtree_populate_path(vdt, vdt->path, FALSE, TRUE);}const gchar *vdtree_row_get_path(ViewDirTree *vdt, gint row){ printf("FIXME: no get row path\n"); return NULL;}/* *---------------------------------------------------------------------------- * callbacks *---------------------------------------------------------------------------- */static void vdtree_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data){ ViewDirTree *vdt = data; GtkTreeModel *store; GtkTreeIter iter; GtkTreePath *tpath; gint cw, ch; if (vdtree_find_row(vdt, vdt->click_fd, &iter, NULL) < 0) return; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); tpath = gtk_tree_model_get_path(store, &iter); tree_view_get_cell_clamped(GTK_TREE_VIEW(vdt->treeview), tpath, 0, TRUE, x, y, &cw, &ch); gtk_tree_path_free(tpath); *y += ch; popup_menu_position_clamp(menu, x, y, 0);}static gint vdtree_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data){ ViewDirTree *vdt = data; GtkTreePath *tpath; GtkTreeIter iter; FileData *fd = NULL; gtk_tree_view_get_cursor(GTK_TREE_VIEW(vdt->treeview), &tpath, NULL); if (tpath) { GtkTreeModel *store; NodeData *nd; store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); gtk_tree_path_free(tpath); fd = (nd) ? nd->fd : NULL; } switch (event->keyval) { case GDK_Menu: vdt->click_fd = fd; vdtree_color_set(vdt, vdt->click_fd, TRUE); vdt->popup = vdtree_pop_menu(vdt, vdt->click_fd); gtk_menu_popup(GTK_MENU(vdt->popup), NULL, NULL, vdtree_menu_position_cb, vdt, 0, GDK_CURRENT_TIME); return TRUE; break; case GDK_plus: case GDK_Right: case GDK_KP_Add: if (fd) { vdtree_populate_path_by_iter(vdt, &iter, FALSE, vdt->path); vdtree_icon_set_by_iter(vdt, &iter, vdt->pf->open); } break; } return FALSE;}static gint vdtree_clicked_on_expander(GtkTreeView *treeview, GtkTreePath *tpath, GtkTreeViewColumn *column, gint x, gint y, gint *left_of_expander){ gint depth; gint size; gint sep; gint exp_width; if (column != gtk_tree_view_get_expander_column(treeview)) return FALSE; gtk_widget_style_get(GTK_WIDGET(treeview), "expander-size", &size, "horizontal-separator", &sep, NULL); depth = gtk_tree_path_get_depth(tpath); exp_width = sep + size + sep; if (x <= depth * exp_width) { if (left_of_expander) *left_of_expander = !(x >= (depth - 1) * exp_width); return TRUE; } return FALSE;}static gint vdtree_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data){ ViewDirTree *vdt = data; GtkTreePath *tpath; GtkTreeViewColumn *column; GtkTreeIter iter; NodeData *nd = NULL; if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y, &tpath, &column, NULL, NULL)) { GtkTreeModel *store; gint left_of_expander; store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE); if (vdtree_clicked_on_expander(GTK_TREE_VIEW(widget), tpath, column, bevent->x, bevent->y, &left_of_expander)) { vdt->click_fd = NULL; /* clicking this region should automatically reveal an expander, if necessary * treeview bug: the expander will not expand until a button_motion_event highlights it. */ if (bevent->button == 1 && !left_of_expander && !gtk_tree_view_row_expanded(GTK_TREE_VIEW(vdt->treeview), tpath)) { vdtree_populate_path_by_iter(vdt, &iter, FALSE, vdt->path); vdtree_icon_set_by_iter(vdt, &iter, vdt->pf->open); } gtk_tree_path_free(tpath); return FALSE; } gtk_tree_path_free(tpath); } vdt->click_fd = (nd) ? nd->fd : NULL; vdtree_color_set(vdt, vdt->click_fd, TRUE); if (bevent->button == 3) { vdt->popup = vdtree_pop_menu(vdt, vdt->click_fd); gtk_menu_popup(GTK_MENU(vdt->popup), NULL, NULL, NULL, NULL, bevent->button, bevent->time); } return (bevent->button != 1);}static gint vdtree_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data){ ViewDirTree *vdt = data; GtkTreePath *tpath; GtkTreeIter iter; NodeData *nd = NULL; if (!vdt->click_fd) return FALSE; vdtree_color_set(vdt, vdt->click_fd, FALSE); if (bevent->button != 1) return TRUE; if ((bevent->x != 0 || bevent->y != 0) && gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y, &tpath, NULL, NULL, NULL)) { GtkTreeModel *store; store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); gtk_tree_path_free(tpath); } if (nd && vdt->click_fd == nd->fd) { vdtree_select_row(vdt, vdt->click_fd); } return FALSE;}static void vdtree_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *tpath, gpointer data){ ViewDirTree *vdt = data; vdtree_populate_path_by_iter(vdt, iter, FALSE, NULL); vdtree_icon_set_by_iter(vdt, iter, vdt->pf->open);}static void vdtree_row_collapsed(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *tpath, gpointer data){ ViewDirTree *vdt = data; vdtree_icon_set_by_iter(vdt, iter, vdt->pf->close);}static gint vdtree_sort_cb(GtkTreeModel *store, GtkTreeIter *a, GtkTreeIter *b, gpointer data){ NodeData *nda; NodeData *ndb; gtk_tree_model_get(store, a, DIR_COLUMN_POINTER, &nda, -1); gtk_tree_model_get(store, b, DIR_COLUMN_POINTER, &ndb, -1); return CASE_SORT(nda->fd->name, ndb->fd->name);}/* *---------------------------------------------------------------------------- * core *---------------------------------------------------------------------------- */static void vdtree_setup_root(ViewDirTree *vdt){ const gchar *path = "/"; FileData *fd; fd = g_new0(FileData, 1); fd->path = g_strdup(path); fd->name = fd->path; fd->size = 0; fd->date = filetime(path); vdtree_add_by_data(vdt, fd, NULL); vdtree_expand_by_data(vdt, fd, TRUE); vdtree_populate_path(vdt, path, FALSE, FALSE);}static void vdtree_activate_cb(GtkTreeView *tview, GtkTreePath *tpath, GtkTreeViewColumn *column, gpointer data){ ViewDirTree *vdt = data; GtkTreeModel *store; GtkTreeIter iter; NodeData *nd; store = gtk_tree_view_get_model(tview); gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); vdtree_select_row(vdt, nd->fd);}static GdkColor *vdtree_color_shifted(GtkWidget *widget){ static GdkColor color; static GtkWidget *done = NULL; if (done != widget) { GtkStyle *style; style = gtk_widget_get_style(widget); memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color)); shift_color(&color, -1, 0); done = widget; } return &color;}static void vdtree_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data){ ViewDirTree *vdt = data; gboolean set; gtk_tree_model_get(tree_model, iter, DIR_COLUMN_COLOR, &set, -1); g_object_set(G_OBJECT(cell), "cell-background-gdk", vdtree_color_shifted(vdt->treeview), "cell-background-set", set, NULL);}static gboolean vdtree_destroy_node_cb(GtkTreeModel *store, GtkTreePath *tpath, GtkTreeIter *iter, gpointer data){ NodeData *nd; gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); vdtree_node_free(nd); return FALSE;}static void vdtree_destroy_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; GtkTreeModel *store; if (vdt->popup) { g_signal_handlers_disconnect_matched(G_OBJECT(vdt->popup), G_SIGNAL_MATCH_DATA, 0, 0, 0, NULL, vdt); gtk_widget_destroy(vdt->popup); } vdtree_dnd_drop_expand_cancel(vdt); vdtree_dnd_drop_scroll_cancel(vdt); widget_auto_scroll_stop(vdt->treeview); store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); gtk_tree_model_foreach(store, vdtree_destroy_node_cb, vdt); path_list_free(vdt->drop_list); folder_icons_free(vdt->pf); g_free(vdt->path); g_free(vdt);}ViewDirTree *vdtree_new(const gchar *path, gint expand){ ViewDirTree *vdt; GtkTreeStore *store; GtkTreeSelection *selection; GtkTreeViewColumn *column; GtkCellRenderer *renderer; vdt = g_new0(ViewDirTree, 1); vdt->path = NULL; vdt->click_fd = NULL; vdt->drop_fd = NULL; vdt->drop_list = NULL; vdt->drop_scroll_id = -1; vdt->drop_expand_id = -1; vdt->popup = NULL; vdt->busy_ref = 0; vdt->widget = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(vdt->widget), GTK_SHADOW_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vdt->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); g_signal_connect(G_OBJECT(vdt->widget), "destroy", G_CALLBACK(vdtree_destroy_cb), vdt); store = gtk_tree_store_new(4, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT); vdt->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(store); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vdt->treeview), FALSE); gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vdt->treeview), FALSE); gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), vdtree_sort_cb, vdt, NULL); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); g_signal_connect(G_OBJECT(vdt->treeview), "row_activated", G_CALLBACK(vdtree_activate_cb), vdt); g_signal_connect(G_OBJECT(vdt->treeview), "row_expanded", G_CALLBACK(vdtree_row_expanded), vdt); g_signal_connect(G_OBJECT(vdt->treeview), "row_collapsed", G_CALLBACK(vdtree_row_collapsed), vdt);#if 0 g_signal_connect(G_OBJECT(store), "row_deleted", G_CALLBACK(vdtree_row_deleted_cb), vdt);#endif selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vdt->treeview)); gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); gtk_tree_selection_set_select_function(selection, vdtree_select_cb, vdt, NULL); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column, renderer, FALSE); gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", DIR_COLUMN_ICON); gtk_tree_view_column_set_cell_data_func(column, renderer, vdtree_color_cb, vdt, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", DIR_COLUMN_NAME); gtk_tree_view_column_set_cell_data_func(column, renderer, vdtree_color_cb, vdt, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(vdt->treeview), column); g_signal_connect(G_OBJECT(vdt->treeview), "key_press_event", G_CALLBACK(vdtree_press_key_cb), vdt); gtk_container_add(GTK_CONTAINER(vdt->widget), vdt->treeview); gtk_widget_show(vdt->treeview); vdt->pf = folder_icons_new(); vdtree_setup_root(vdt); vdtree_dnd_init(vdt); g_signal_connect(G_OBJECT(vdt->treeview), "button_press_event", G_CALLBACK(vdtree_press_cb), vdt); g_signal_connect(G_OBJECT(vdt->treeview), "button_release_event", G_CALLBACK(vdtree_release_cb), vdt); vdtree_set_path(vdt, path); return vdt;}void vdtree_set_select_func(ViewDirTree *vdt, void (*func)(ViewDirTree *vdt, const gchar *path, gpointer data), gpointer data){ vdt->select_func = func; vdt->select_data = data;}#if 0void vdtree_set_click_func(ViewDirTree *vdt, void (*func)(ViewDirTree *vdt, GdkEventButton *event, FileData *fd, gpointer), gpointer data){ if (!td) return; vdt->click_func = func; vdt->click_data = data;}#endifvoid vdtree_set_layout(ViewDirTree *vdt, LayoutWindow *layout){ vdt->layout = layout;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -