11 #include <yui/Libyui_config.h>
12 #include "ygtktreeview.h"
17 extern char *ygutils_mapKBAccel (
const char *src);
19 static guint right_click_signal = 0;
21 G_DEFINE_TYPE (
YGtkTreeView, ygtk_tree_view, GTK_TYPE_TREE_VIEW)
27 static void ygtk_tree_view_finalize (GObject *
object)
30 if (view->empty_text) {
31 g_free (view->empty_text);
32 view->empty_text = NULL;
34 G_OBJECT_CLASS (ygtk_tree_view_parent_class)->finalize (
object);
37 static void _gtk_widget_destroy (gpointer widget)
38 { gtk_widget_destroy (GTK_WIDGET (widget)); }
40 static guint32 _popup_time = 0;
41 static gint _popup_x = 0, _popup_y = 0;
43 #if GTK_CHECK_VERSION (3, 22, 0)
45 static void _ygtk_tree_view_menu_position_func (
46 GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
47 { *x = _popup_x; *y = _popup_y; }
50 void ygtk_tree_view_popup_menu (
YGtkTreeView *view, GtkWidget *menu)
52 GtkWidget *widget = GTK_WIDGET (view);
55 g_object_set_data_full (G_OBJECT (view),
"popup", menu, _gtk_widget_destroy);
57 gtk_menu_attach_to_widget (GTK_MENU (menu), widget, NULL);
59 # if GTK_CHECK_VERSION (3, 22, 0)
60 gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
62 gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
63 _ygtk_tree_view_menu_position_func,
64 widget, 3, _popup_time);
67 gtk_widget_show_all (menu);
70 static gboolean ygtk_tree_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
72 if (event->button == 3) {
73 GtkTreeView *view = GTK_TREE_VIEW (widget);
76 outreach = !gtk_tree_view_get_path_at_pos (view, event->x, event->y, &path, NULL, NULL, NULL);
78 GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
79 GtkTreeModel *model = gtk_tree_view_get_model (view);
81 gtk_tree_model_get_iter (model, &iter, path);
83 if (!gtk_tree_selection_iter_is_selected (selection, &iter))
84 gtk_tree_view_set_cursor (view, path, NULL, FALSE);
85 gtk_tree_path_free (path);
88 _popup_time =
event->time;
89 _popup_x =
event->x_root; _popup_y =
event->y_root;
91 gtk_widget_grab_focus (widget);
92 g_signal_emit (widget, right_click_signal, 0, outreach);
95 return GTK_WIDGET_CLASS (ygtk_tree_view_parent_class)->button_press_event (widget, event);
98 static gboolean _ygtk_tree_view_popup_menu (GtkWidget *widget)
100 GtkTreeView *view = GTK_TREE_VIEW (widget);
101 GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
102 gboolean outreach = gtk_tree_selection_count_selected_rows (selection) == 0;
104 _popup_time = gtk_get_current_event_time();
106 _popup_x = (_popup_y = 0);
108 GList *rows = gtk_tree_selection_get_selected_rows (selection, NULL);
109 GtkTreePath *path = (GtkTreePath *) g_list_last (rows)->data;
112 gtk_tree_view_scroll_to_cell (view, path, NULL, FALSE, 0, 0);
115 gtk_tree_view_get_cell_area (view, path, NULL, &rect);
117 _popup_y = rect.y + rect.height;
119 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
123 gtk_tree_view_convert_bin_window_to_widget_coords (
124 view, _popup_x, _popup_y, &_popup_x, &_popup_y);
126 gdk_window_get_origin (gtk_widget_get_window(widget), &x_orig, &y_orig);
127 _popup_x += x_orig; _popup_y += y_orig;
129 g_signal_emit (widget, right_click_signal, 0, outreach);
133 static gboolean _ygtk_tree_view_draw (GtkWidget *widget, cairo_t *cr)
135 GTK_WIDGET_CLASS (ygtk_tree_view_parent_class)->draw(widget, cr);
137 GtkTreeView *view = GTK_TREE_VIEW (widget);
139 if (yview->empty_text) {
140 GtkTreeModel *model = gtk_tree_view_get_model (view);
142 if (!model || !gtk_tree_model_get_iter_first (model, &iter)) {
143 const gchar *text = yview->empty_text;
145 text = _(
"Loading...");
147 layout = gtk_widget_create_pango_layout (widget, text);
149 PangoAttrList *attrs = pango_attr_list_new();
150 pango_attr_list_insert (attrs, pango_attr_foreground_new (160<<8, 160<<8, 160<<8));
151 pango_layout_set_attributes (layout, attrs);
152 pango_attr_list_unref (attrs);
155 pango_layout_get_pixel_size (layout, &width, &height);
156 GtkAllocation allocation;
157 gtk_widget_get_allocation(widget, &allocation);
159 x = (allocation.width - width) / 2;
160 y = (allocation.height - height) / 2;
161 cairo_move_to (cr, x, y);
163 pango_cairo_show_layout (cr, layout);
164 g_object_unref (layout);
170 static void show_column_cb (GtkCheckMenuItem *item, GtkTreeView *view)
172 int col = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item),
"column"));
173 GtkTreeViewColumn *column = gtk_tree_view_get_column (view, col);
174 gboolean visible = gtk_check_menu_item_get_active (item);
175 gtk_tree_view_column_set_visible (column, visible);
178 GtkWidget *ygtk_tree_view_create_show_columns_menu (
YGtkTreeView *view)
180 GtkWidget *menu = gtk_menu_new();
181 GList *columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (view));
183 gboolean reverse = gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL &&
184 gtk_widget_get_direction (GTK_WIDGET (view)) != GTK_TEXT_DIR_RTL;
187 for (n = 0, i = columns; i; i = i->next, n++) {
188 GtkTreeViewColumn *column = (GtkTreeViewColumn *) i->data;
189 const gchar *header = gtk_tree_view_column_get_title (column);
191 GtkWidget *item = gtk_check_menu_item_new_with_label (header);
192 g_object_set_data (G_OBJECT (item),
"column", GINT_TO_POINTER (n));
194 gboolean visible = gtk_tree_view_column_get_visible (column);
195 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), visible);
196 g_signal_connect (G_OBJECT (item),
"toggled",
197 G_CALLBACK (show_column_cb), view);
200 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
202 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
205 if (n == 0 && !reverse)
206 gtk_widget_set_sensitive (item, FALSE);
209 g_list_free (columns);
213 GtkWidget *ygtk_tree_view_append_show_columns_item (
YGtkTreeView *view, GtkWidget *menu)
216 menu = gtk_menu_new();
218 GList *children = gtk_container_get_children (GTK_CONTAINER (menu));
219 g_list_free (children);
221 gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new());
223 GtkWidget *submenu = ygtk_tree_view_create_show_columns_menu (view);
224 char *label = ygutils_mapKBAccel (_(
"&Show column"));
225 GtkWidget *item = gtk_menu_item_new_with_mnemonic (label);
227 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
228 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
232 void ygtk_tree_view_append_column (
YGtkTreeView *view, GtkTreeViewColumn *column)
235 if (gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL) {
236 gtk_widget_set_direction (GTK_WIDGET (view), GTK_TEXT_DIR_LTR);
238 GList *renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column)), *i;
239 for (i = renderers; i; i = i->next) {
240 GtkCellRenderer *renderer = (GtkCellRenderer *) i->data;
241 if (GTK_IS_CELL_RENDERER_TEXT (renderer)) {
242 PangoAlignment alignment;
243 g_object_get (G_OBJECT (renderer),
"alignment", &alignment, NULL);
244 if (alignment == PANGO_ALIGN_LEFT)
245 alignment = PANGO_ALIGN_RIGHT;
246 else if (alignment == PANGO_ALIGN_RIGHT)
247 alignment = PANGO_ALIGN_LEFT;
248 g_object_set (G_OBJECT (renderer),
"alignment", alignment, NULL);
251 g_object_get (G_OBJECT (renderer),
"xalign", &xalign, NULL);
252 xalign = 1.0 - xalign;
253 g_object_set (G_OBJECT (renderer),
"xalign", xalign, NULL);
255 PangoEllipsizeMode ellipsize;
256 g_object_get (G_OBJECT (renderer),
"ellipsize", &ellipsize, NULL);
257 if (ellipsize == PANGO_ELLIPSIZE_END)
258 ellipsize = PANGO_ELLIPSIZE_START;
259 else if (ellipsize == PANGO_ELLIPSIZE_START)
260 ellipsize = PANGO_ELLIPSIZE_END;
261 g_object_set (G_OBJECT (renderer),
"ellipsize", ellipsize, NULL);
264 g_list_free (renderers);
267 gtk_tree_view_insert_column (GTK_TREE_VIEW (view), column, pos);
270 GtkTreeViewColumn *ygtk_tree_view_get_column (
YGtkTreeView *view, gint nb)
272 GtkTreeViewColumn *column;
273 if (gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL) {
274 GList *columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (view));
275 nb = g_list_length (columns) - nb - 1;
276 column = g_list_nth_data (columns, nb);
277 g_list_free (columns);
280 column = gtk_tree_view_get_column (GTK_TREE_VIEW (view), nb);
285 void ygtk_tree_view_set_empty_text (
YGtkTreeView *view,
const gchar *empty_text)
287 if (view->empty_text)
288 g_free (view->empty_text);
289 view->empty_text = empty_text ? g_strdup (empty_text) : NULL;
292 GtkWidget *ygtk_tree_view_new (
const gchar *empty_text)
295 view->empty_text = empty_text ? g_strdup (empty_text) : NULL;
296 return GTK_WIDGET (view);
301 GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
302 gtkwidget_class->button_press_event = ygtk_tree_view_button_press_event;
303 gtkwidget_class->popup_menu = _ygtk_tree_view_popup_menu;
304 gtkwidget_class->draw = _ygtk_tree_view_draw;
306 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
307 gobject_class->finalize = ygtk_tree_view_finalize;
309 right_click_signal = g_signal_new (
"right-click",
310 G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
312 NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);