📄 ui_tree_edit.c
字号:
/* * (SLIK) SimpLIstic sKin functions * (C) 2004 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "intl.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <gtk/gtk.h>#include <gdk/gdkkeysyms.h>#include "ui_tree_edit.h"/* *------------------------------------------------------------------- * cell popup editor *------------------------------------------------------------------- */static void tree_edit_close(TreeEditData *ted){ gtk_grab_remove(ted->window); gdk_keyboard_ungrab(GDK_CURRENT_TIME); gdk_pointer_ungrab(GDK_CURRENT_TIME); gtk_widget_destroy(ted->window); g_free(ted->old_name); g_free(ted->new_name); gtk_tree_path_free(ted->path); g_free(ted);}static void tree_edit_do(TreeEditData *ted){ ted->new_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(ted->entry))); if (strcmp(ted->new_name, ted->old_name) != 0) { if (ted->edit_func) { if (ted->edit_func(ted, ted->old_name, ted->new_name, ted->edit_data)) { /* hmm, should the caller be required to set text instead ? */ } } }}static gint tree_edit_click_end_cb(GtkWidget *widget, GdkEventButton *event, gpointer data){ TreeEditData *ted = data; tree_edit_do(ted); tree_edit_close(ted); return TRUE;}static gint tree_edit_click_cb(GtkWidget *widget, GdkEventButton *event, gpointer data){ TreeEditData *ted = data; gint x, y; gint w, h; gint xr, yr; xr = (gint)event->x_root; yr = (gint)event->y_root; gdk_window_get_origin(ted->window->window, &x, &y); gdk_drawable_get_size(ted->window->window, &w, &h); if (xr < x || yr < y || xr > x + w || yr > y + h) { /* gobble the release event, so it does not propgate to an underlying widget */ g_signal_connect(G_OBJECT(ted->window), "button_release_event", G_CALLBACK(tree_edit_click_end_cb), ted); return TRUE; } return FALSE;}static gint tree_edit_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data){ TreeEditData *ted = data; switch (event->keyval) { case GDK_Return: case GDK_KP_Enter: case GDK_Tab: /* ok, we are going to intercept the focus change from keyboard and act like return was hit */ case GDK_ISO_Left_Tab: case GDK_Up: case GDK_Down: case GDK_KP_Up: case GDK_KP_Down: case GDK_KP_Left: case GDK_KP_Right: tree_edit_do(ted); tree_edit_close(ted); break; case GDK_Escape: tree_edit_close(ted); break; default: break; } return FALSE;}static gboolean tree_edit_by_path_idle_cb(gpointer data){ TreeEditData *ted = data; GdkRectangle rect; gint x, y, w, h; /* geometry of cell within tree */ gint wx, wy; /* geometry of tree from root window */ gint sx, sw; gtk_tree_view_get_cell_area(ted->tree, ted->path, ted->column, &rect); x = rect.x; y = rect.y; w = rect.width + 4; h = rect.height + 4; if (gtk_tree_view_column_cell_get_position(ted->column, ted->cell, &sx, &sw)) { x += sx; w = MAX(w - sx, sw); } gdk_window_get_origin(gtk_tree_view_get_bin_window(ted->tree), &wx, &wy); x += wx - 2; /* the -val is to 'fix' alignment of entry position */ y += wy - 2; /* now show it */ gtk_widget_set_size_request(ted->window, w, h); gtk_widget_realize(ted->window); gtk_window_move(GTK_WINDOW(ted->window), x, y); gtk_window_resize(GTK_WINDOW(ted->window), w, h); gtk_widget_show(ted->window); /* grab it */ gtk_widget_grab_focus(ted->entry); /* explicitely set the focus flag for the entry, for some reason on popup windows this * is not set, and causes no edit cursor to appear ( popups not allowed focus? ) */ GTK_WIDGET_SET_FLAGS(ted->entry, GTK_HAS_FOCUS); gtk_grab_add(ted->window); gdk_pointer_grab(ted->window->window, TRUE, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK, NULL, NULL, GDK_CURRENT_TIME); gdk_keyboard_grab(ted->window->window, TRUE, GDK_CURRENT_TIME); return FALSE;}gint tree_edit_by_path(GtkTreeView *tree, GtkTreePath *tpath, gint column, const gchar *text, gint (*edit_func)(TreeEditData *, const gchar *, const gchar *, gpointer), gpointer data){ TreeEditData *ted; GtkTreeViewColumn *tcolumn; GtkCellRenderer *cell = NULL; GList *list; GList *work; if (!edit_func) return FALSE; if (!GTK_WIDGET_VISIBLE(tree)) return FALSE; tcolumn = gtk_tree_view_get_column(tree, column); if (!tcolumn) return FALSE; list = gtk_tree_view_column_get_cell_renderers(tcolumn); work = list; while (work && !cell) { cell = work->data; if (!GTK_IS_CELL_RENDERER_TEXT(cell)) { cell = NULL; } work = work->next; } g_list_free(list); if (!cell) return FALSE; if (!text) text = ""; ted = g_new0(TreeEditData, 1); ted->old_name = g_strdup(text); ted->new_name = NULL; ted->edit_func = edit_func; ted->edit_data = data; ted->tree = tree; ted->path = gtk_tree_path_copy(tpath); ted->column = tcolumn; ted->cell = cell; gtk_tree_view_scroll_to_cell(ted->tree, ted->path, ted->column, FALSE, 0.0, 0.0); /* create the window */ ted->window = gtk_window_new(GTK_WINDOW_POPUP); gtk_window_set_resizable(GTK_WINDOW(ted->window), FALSE); g_signal_connect(G_OBJECT(ted->window), "button_press_event", G_CALLBACK(tree_edit_click_cb), ted); g_signal_connect(G_OBJECT(ted->window), "key_press_event", G_CALLBACK(tree_edit_key_press_cb), ted); ted->entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(ted->entry), ted->old_name); gtk_editable_select_region(GTK_EDITABLE(ted->entry), 0, strlen(ted->old_name)); gtk_container_add(GTK_CONTAINER(ted->window), ted->entry); gtk_widget_show(ted->entry); /* due to the fact that gtktreeview scrolls in an idle loop, we cannot * reliably get the cell position until those scroll priority signals are processed */ g_idle_add_full(G_PRIORITY_DEFAULT_IDLE - 2, tree_edit_by_path_idle_cb, ted, NULL); return TRUE;}/* *------------------------------------------------------------------- * tree cell position retrieval *------------------------------------------------------------------- */gint tree_view_get_cell_origin(GtkTreeView *widget, GtkTreePath *tpath, gint column, gint text_cell_only, gint *x, gint *y, gint *width, gint *height){ gint x_origin, y_origin; gint x_offset, y_offset; gint header_size; GtkTreeViewColumn *tv_column; GdkRectangle rect; tv_column = gtk_tree_view_get_column(widget, column); if (!tv_column || !tpath) return FALSE; /* hmm, appears the rect will not account for X scroll, but does for Y scroll * use x_offset instead for X scroll (sigh) */ gtk_tree_view_get_cell_area(widget, tpath, tv_column, &rect); gtk_tree_view_tree_to_widget_coords(widget, 0, 0, &x_offset, &y_offset); gdk_window_get_origin(GTK_WIDGET(widget)->window, &x_origin, &y_origin); if (gtk_tree_view_get_headers_visible(widget)) { header_size = tv_column->button->allocation.height; } else { header_size = 0; } if (text_cell_only) { GtkCellRenderer *cell = NULL; GList *renderers; GList *work; gint cell_x; gint cell_width; renderers = gtk_tree_view_column_get_cell_renderers(tv_column); work = renderers; while (work && !cell) { cell = work->data; work = work->next; if (!GTK_IS_CELL_RENDERER_TEXT(cell)) cell = NULL; } g_list_free(renderers); if (!cell) return FALSE; if (!gtk_tree_view_column_cell_get_position(tv_column, cell, &cell_x, &cell_width)) { cell_x = 0; cell_width = rect.width; } *x = x_origin + x_offset + rect.x + cell_x; *width = cell_width; } else { *x = x_origin + x_offset + rect.x; *width = rect.width; } *y = y_origin + rect.y + header_size; *height = rect.height; return TRUE;}void tree_view_get_cell_clamped(GtkTreeView *widget, GtkTreePath *tpath, gint column, gint text_cell_only, gint *x, gint *y, gint *width, gint *height){ gint wx, wy, ww, wh; GdkWindow *window; window = GTK_WIDGET(widget)->window; gdk_window_get_origin(window, &wx, &wy); gdk_drawable_get_size(window, &ww, &wh); if (!tree_view_get_cell_origin(widget, tpath, column, text_cell_only, x, y, width, height)) { *x = wx; *y = wy; *width = ww; *height = wh; return; } *width = MIN(*width, ww); *x = CLAMP(*x, wx, wx + ww - (*width)); *y = CLAMP(*y, wy, wy + wh); *height = MIN(*height, wy + wh - (*y));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -