/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */ /* * Copyright (C) 2011 Ruby-GNOME2 Project Team * Copyright (C) 2002-2005 Masao Mutoh * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "rbgtk3private.h" #define RG_TARGET_NAMESPACE cTreeView #define _SELF(s) (RVAL2GTKTREEVIEW(s)) static VALUE rb_mGtk; static ID id_model; static ID id_selection; static VALUE rg_initialize(int argc, VALUE *argv, VALUE self) { VALUE model; GtkWidget *widget; if (rb_scan_args(argc, argv, "01", &model) == 1) { G_CHILD_SET(self, id_model, model); widget = gtk_tree_view_new_with_model(RVAL2GTKTREEMODEL(model)); } else { widget = gtk_tree_view_new(); } RBGTK_INITIALIZE(self, widget); return Qnil; } static VALUE rg_selection(VALUE self) { VALUE ret = GOBJ2RVAL(gtk_tree_view_get_selection(_SELF(self))); G_CHILD_SET(self, id_selection, ret); return ret; } static VALUE rg_columns_autosize(VALUE self) { gtk_tree_view_columns_autosize(_SELF(self)); return self; } static VALUE rg_append_column(VALUE self, VALUE column) { G_CHILD_ADD(self, column); return INT2NUM(gtk_tree_view_append_column(_SELF(self), RVAL2GTKTREEVIEWCOLUMN(column))); } static VALUE rg_remove_column(VALUE self, VALUE column) { G_CHILD_REMOVE(self, column); return INT2NUM(gtk_tree_view_remove_column(_SELF(self), RVAL2GTKTREEVIEWCOLUMN(column))); } static void cell_data_func(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer func) { iter->user_data3 = model; rb_funcall((VALUE)func, id_call, 4, GOBJ2RVAL(column), GOBJ2RVAL(cell), GOBJ2RVAL(model), GTKTREEITER2RVAL(iter)); } static VALUE rg_insert_column(int argc, VALUE *argv, VALUE self) { VALUE args[4]; rb_scan_args(argc, argv, "22", /* NORMAL ATTRIBUTES DATA_FUNC */ &args[0], /* column position position */ &args[1], /* position title title */ &args[2], /* renderer renderer */ &args[3]); /* attributes */ if (argc == 2) { G_CHILD_ADD(self, args[0]); return INT2NUM(gtk_tree_view_insert_column(_SELF(self), RVAL2GTKTREEVIEWCOLUMN(args[0]), NUM2INT(args[1]))); } else if (argc == 3) { int ret; VALUE func = rb_block_proc(); G_RELATIVE(self, func); ret = gtk_tree_view_insert_column_with_data_func(_SELF(self), NUM2INT(args[0]), RVAL2CSTR(args[1]), RVAL2GTKCELLRENDERER(args[2]), (GtkTreeCellDataFunc)cell_data_func, (gpointer)func, NULL); return INT2NUM(ret); } else if (argc == 4) { int i; int col; int ret; const gchar *name; VALUE ary; GtkCellRenderer* renderer = RVAL2GTKCELLRENDERER(args[2]); GtkTreeViewColumn* column = gtk_tree_view_column_new(); Check_Type(args[3], T_HASH); /* TODO: Should this really be done before we know that everything * below worked without error? */ G_CHILD_ADD(self, args[2]); G_CHILD_ADD(self, args[3]); gtk_tree_view_column_set_title(column, RVAL2CSTR(args[1])); gtk_tree_view_column_pack_start(column, renderer, TRUE); ret = gtk_tree_view_insert_column(_SELF(self), column, NUM2INT(args[0])); ary = rb_funcall(args[3], rb_intern("to_a"), 0); for (i = 0; i < RARRAY_LEN(ary); i++) { VALUE val = RARRAY_PTR(RARRAY_PTR(ary)[i])[0]; if (SYMBOL_P(val)) { name = rb_id2name(SYM2ID(val)); } else { name = RVAL2CSTR(val); } col = NUM2INT(RARRAY_PTR(RARRAY_PTR(ary)[i])[1]); gtk_tree_view_column_add_attribute(column, renderer, name, col); } return INT2NUM(ret); } else { rb_raise(rb_eArgError, "Wrong number of arguments: %d", argc); } return Qnil; } static VALUE rg_get_column(VALUE self, VALUE num) { return GOBJ2RVAL(gtk_tree_view_get_column(_SELF(self), NUM2INT(num))); } static VALUE rg_columns(VALUE self) { return GOBJGLIST2RVAL_FREE(gtk_tree_view_get_columns(_SELF(self)), g_list_free, NULL); } static VALUE rg_move_column_after(VALUE self, VALUE column, VALUE base_column) { gtk_tree_view_move_column_after(_SELF(self), RVAL2GTKTREEVIEWCOLUMN(column), NIL_P(base_column) ? NULL : RVAL2GTKTREEVIEWCOLUMN(base_column)); return self; } static gboolean column_drop_func(GtkTreeView *treeview, GtkTreeViewColumn *column, GtkTreeViewColumn *prev_column, GtkTreeViewColumn *next_column, gpointer func) { return RVAL2CBOOL(rb_funcall((VALUE)func, id_call, 4, GOBJ2RVAL(treeview), GOBJ2RVAL(column), GOBJ2RVAL(prev_column), GOBJ2RVAL(next_column))); } static VALUE rg_set_column_drag_function(VALUE self) { VALUE func = rb_block_proc(); G_RELATIVE(self, func); gtk_tree_view_set_column_drag_function(_SELF(self), (GtkTreeViewColumnDropFunc)column_drop_func, (gpointer)func, NULL); return self; } static VALUE rg_scroll_to_point(VALUE self, VALUE x, VALUE y) { gtk_tree_view_scroll_to_point(_SELF(self), NUM2INT(x), NUM2INT(y)); return self; } static VALUE rg_scroll_to_cell(VALUE self, VALUE path, VALUE column, VALUE use_align, VALUE row_align, VALUE col_align) { gtk_tree_view_scroll_to_cell(_SELF(self), NIL_P(path) ? NULL : RVAL2GTKTREEPATH(path), NIL_P(column) ? NULL : RVAL2GTKTREEVIEWCOLUMN(column), RVAL2CBOOL(use_align), NUM2DBL(row_align), NUM2DBL(col_align)); return self; } static VALUE rg_set_cursor(VALUE self, VALUE path, VALUE focus_column, VALUE start_editing) { gtk_tree_view_set_cursor(_SELF(self), RVAL2GTKTREEPATH(path), NIL_P(focus_column) ? NULL : RVAL2GTKTREEVIEWCOLUMN(focus_column), RVAL2CBOOL(start_editing)); return self; } static VALUE rg_cursor(VALUE self) { GtkTreePath* path; GtkTreeViewColumn* focus_column; gtk_tree_view_get_cursor(_SELF(self), &path, &focus_column); return rb_ary_new3(2, path ? GTKTREEPATH2RVAL(path) : Qnil, GOBJ2RVAL(focus_column)); } static VALUE rg_expand_all(VALUE self) { gtk_tree_view_expand_all(_SELF(self)); return self; } static VALUE rg_collapse_all(VALUE self) { gtk_tree_view_collapse_all(_SELF(self)); return self; } static VALUE rg_expand_row(VALUE self, VALUE path, VALUE open_all) { return CBOOL2RVAL(gtk_tree_view_expand_row(_SELF(self), RVAL2GTKTREEPATH(path), RVAL2CBOOL(open_all))); } static VALUE rg_expand_to_path(VALUE self, VALUE path) { gtk_tree_view_expand_to_path(_SELF(self), RVAL2GTKTREEPATH(path)); return self; } static VALUE rg_collapse_row(VALUE self, VALUE path) { return CBOOL2RVAL(gtk_tree_view_collapse_row(_SELF(self), RVAL2GTKTREEPATH(path))); } static void mapping_func(GtkTreeView *treeview, GtkTreePath *path, gpointer func) { rb_funcall((VALUE)func, id_call, 2, GOBJ2RVAL(treeview), GTKTREEPATH2RVAL(path)); } static VALUE rg_map_expanded_rows(VALUE self) { VALUE func = rb_block_proc(); G_RELATIVE(self, func); gtk_tree_view_map_expanded_rows(_SELF(self), (GtkTreeViewMappingFunc)mapping_func, (gpointer)func); return self; } static VALUE rg_row_expanded_p(VALUE self, VALUE path) { return CBOOL2RVAL(gtk_tree_view_row_expanded(_SELF(self), RVAL2GTKTREEPATH(path))); } static VALUE rg_get_path_at_pos(VALUE self, VALUE x, VALUE y) { GtkTreePath* path; GtkTreeViewColumn* column; gint cell_x, cell_y; gboolean ret; ret = gtk_tree_view_get_path_at_pos(_SELF(self), NUM2INT(x), NUM2INT(y), &path, &column, &cell_x, &cell_y); return ret ? rb_ary_new3(4, path ? GTKTREEPATH2RVAL(path) : Qnil, column ? GOBJ2RVAL(column) : Qnil, INT2NUM(cell_x), INT2NUM(cell_y)) : Qnil; } static VALUE rg_get_cell_area(VALUE self, VALUE path, VALUE column) { GdkRectangle rect; gtk_tree_view_get_cell_area(_SELF(self), NIL_P(path) ? NULL : RVAL2GTKTREEPATH(path), NIL_P(column) ? NULL : RVAL2GTKTREEVIEWCOLUMN(column), &rect); return GDKRECTANGLE2RVAL(&rect); } static VALUE rg_get_background_area(VALUE self, VALUE path, VALUE column) { GdkRectangle rect; gtk_tree_view_get_background_area(_SELF(self), NIL_P(path) ? NULL : RVAL2GTKTREEPATH(path), NIL_P(column) ? NULL : RVAL2GTKTREEVIEWCOLUMN(column), &rect); return GDKRECTANGLE2RVAL(&rect); } static VALUE rg_visible_rect(VALUE self) { GdkRectangle rect; gtk_tree_view_get_visible_rect(_SELF(self), &rect); return GDKRECTANGLE2RVAL(&rect); } static VALUE rg_visible_range(VALUE self) { GtkTreePath* start_path; GtkTreePath* end_path; gboolean valid_paths = gtk_tree_view_get_visible_range(_SELF(self), &start_path, &end_path); return valid_paths ? rb_assoc_new(GTKTREEPATH2RVAL(start_path), GTKTREEPATH2RVAL(end_path)) : Qnil; } static VALUE rg_bin_window(VALUE self) { return GOBJ2RVAL(gtk_tree_view_get_bin_window(_SELF(self))); } static VALUE rg_convert_bin_window_to_tree_coords(VALUE self, VALUE bx, VALUE by) { gint tx, ty; gtk_tree_view_convert_bin_window_to_tree_coords(_SELF(self), NUM2INT(bx), NUM2INT(by), &tx, &ty); return rb_ary_new3(2, INT2NUM(tx), INT2NUM(ty)); } static VALUE rg_convert_bin_window_to_widget_coords(VALUE self, VALUE bx, VALUE by) { gint wx, wy; gtk_tree_view_convert_bin_window_to_widget_coords(_SELF(self), NUM2INT(bx), NUM2INT(by), &wx, &wy); return rb_ary_new3(2, INT2NUM(wx), INT2NUM(wy)); } static VALUE rg_convert_tree_to_bin_window_coords(VALUE self, VALUE tx, VALUE ty) { gint bx, by; gtk_tree_view_convert_tree_to_bin_window_coords(_SELF(self), NUM2INT(tx), NUM2INT(ty), &bx, &by); return rb_ary_new3(2, INT2NUM(bx), INT2NUM(by)); } static VALUE rg_convert_tree_to_widget_coords(VALUE self, VALUE tx, VALUE ty) { gint wx, wy; gtk_tree_view_convert_tree_to_widget_coords(_SELF(self), NUM2INT(tx), NUM2INT(ty), &wx, &wy); return rb_ary_new3(2, INT2NUM(wx), INT2NUM(wy)); } static VALUE rg_convert_widget_to_bin_window_coords(VALUE self, VALUE wx, VALUE wy) { gint bx, by; gtk_tree_view_convert_widget_to_bin_window_coords(_SELF(self), NUM2INT(wx), NUM2INT(wy), &bx, &by); return rb_ary_new3(2, INT2NUM(bx), INT2NUM(by)); } static VALUE rg_convert_widget_to_tree_coords(VALUE self, VALUE wx, VALUE wy) { gint tx, ty; gtk_tree_view_convert_widget_to_tree_coords(_SELF(self), NUM2INT(wx), NUM2INT(wy), &tx, &ty); return rb_ary_new3(2, INT2NUM(tx), INT2NUM(ty)); } static VALUE rg_enable_model_drag_dest(VALUE self, VALUE rbtargets, VALUE rbactions) { GtkTreeView *view = _SELF(self); GdkDragAction actions = RVAL2GDKDRAGACTION(rbactions); long n; GtkTargetEntry *targets = RVAL2GTKTARGETENTRIES(rbtargets, &n); gtk_tree_view_enable_model_drag_dest(view, targets, n, actions); g_free(targets); return self; } static VALUE rg_enable_model_drag_source(VALUE self, VALUE rbstart_button_mask, VALUE rbtargets, VALUE rbactions) { GtkTreeView *view = _SELF(self); GdkModifierType start_button_mask = RVAL2GDKMODIFIERTYPE(rbstart_button_mask); GdkDragAction actions = RVAL2GDKDRAGACTION(rbactions); long n; GtkTargetEntry *targets = RVAL2GTKTARGETENTRIES_ACCEPT_NIL(rbtargets, &n); if (targets == NULL) return self; gtk_tree_view_enable_model_drag_source(view, start_button_mask, targets, n, actions); g_free(targets); return self; } static VALUE rg_unset_rows_drag_source(VALUE self) { gtk_tree_view_unset_rows_drag_source(_SELF(self)); return self; } static VALUE rg_unset_rows_drag_dest(VALUE self) { gtk_tree_view_unset_rows_drag_dest(_SELF(self)); return self; } static VALUE rg_set_drag_dest_row(VALUE self, VALUE path, VALUE pos) { gtk_tree_view_set_drag_dest_row(_SELF(self), NIL_P(path)?NULL:RVAL2GTKTREEPATH(path), RVAL2GTKTREEVIEWDROPPOSITION(pos)); return self; } static VALUE rg_drag_dest_row(VALUE self) { GtkTreePath* path = NULL; GtkTreeViewDropPosition pos; gtk_tree_view_get_drag_dest_row(_SELF(self), &path, &pos); return rb_ary_new3(2, path ? GTKTREEPATH2RVAL(path) : Qnil, GTKTREEVIEWDROPPOSITION2RVAL(pos)); } static VALUE rg_get_dest_row_at_pos(VALUE self, VALUE drag_x, VALUE drag_y) { GtkTreePath* path; GtkTreeViewDropPosition pos; gboolean ret; ret = gtk_tree_view_get_dest_row_at_pos(_SELF(self), NUM2INT(drag_x), NUM2INT(drag_y), &path, &pos); return ret ? rb_ary_new3(2, path ? GTKTREEPATH2RVAL(path) : Qnil, GTKTREEVIEWDROPPOSITION2RVAL(pos)) : Qnil; } static VALUE rg_create_row_drag_icon(VALUE self, VALUE path) { return GOBJ2RVAL(gtk_tree_view_create_row_drag_icon(_SELF(self), RVAL2GTKTREEPATH(path))); } /* We don't need this. GtkTreeViewSearchEqualFunc gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view); */ static gboolean search_equal_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer func) { iter->user_data3 = model; return RVAL2CBOOL(rb_funcall((VALUE)func, id_call, 4, GOBJ2RVAL(model), INT2NUM(column), CSTR2RVAL(key), GTKTREEITER2RVAL(iter))); } static VALUE rg_set_search_equal_func(VALUE self) { VALUE func = rb_block_proc(); G_RELATIVE(self, func); gtk_tree_view_set_search_equal_func(_SELF(self), (GtkTreeViewSearchEqualFunc)search_equal_func, (gpointer)func, NULL); return self; } /* * Optional Signals */ static VALUE treeview_signal_func(G_GNUC_UNUSED guint num, const GValue *values) { GtkTreeView* view = g_value_get_object(&values[0]); GtkTreeIter* iter = g_value_get_boxed(&values[1]); iter->user_data3 = gtk_tree_view_get_model(view); return rb_ary_new3(3, GOBJ2RVAL(view), GTKTREEITER2RVAL(iter), GVAL2RVAL(&values[2])); } static VALUE rg_set_cursor_on_cell(VALUE self, VALUE path, VALUE focus_column, VALUE focus_cell, VALUE start_editing) { gtk_tree_view_set_cursor_on_cell(_SELF(self), RVAL2GTKTREEPATH(path), NIL_P(focus_column) ? NULL : RVAL2GTKTREEVIEWCOLUMN(focus_column), NIL_P(focus_cell) ? NULL : RVAL2GTKCELLRENDERER(focus_cell), RVAL2CBOOL(start_editing)); return self; } /* How can I implement this? GtkTreeViewRowSeparatorFunc gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view); */ static gboolean row_separator_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer func) { VALUE ret; iter->user_data3 = model; ret = rb_funcall((VALUE)func, id_call, 2, GOBJ2RVAL(model), GTKTREEITER2RVAL(iter)); return CBOOL2RVAL(ret); } static VALUE rg_set_row_separator_func(VALUE self) { VALUE func = rb_block_proc(); G_RELATIVE(self, func); gtk_tree_view_set_row_separator_func(_SELF(self), row_separator_func, (gpointer)func, (GDestroyNotify)NULL); return self; } static VALUE rg_search_entry(VALUE self) { return GOBJ2RVAL(gtk_tree_view_get_search_entry(_SELF(self))); } static VALUE rg_set_search_entry(VALUE self, VALUE entry) { gtk_tree_view_set_search_entry(_SELF(self), RVAL2GTKENTRY(entry)); return self; } /* Can't define this. GtkTreeViewSearchPositionFunc gtk_tree_view_get_search_position_func (GtkTreeView *tree_view); */ struct callback_arg { VALUE callback; VALUE tree_view; VALUE search_dialog; }; static VALUE invoke_callback(VALUE data) { struct callback_arg *arg = (struct callback_arg *)data; rb_funcall(arg->callback, id_call, 2, arg->tree_view, arg->search_dialog); return Qnil; } static void search_position_func(GtkTreeView *tree_view, GtkWidget *search_dialog, gpointer func) { struct callback_arg arg; arg.callback = (VALUE)func; arg.tree_view = GOBJ2RVAL(tree_view); arg.search_dialog = GOBJ2RVAL(search_dialog); G_PROTECT_CALLBACK(invoke_callback, &arg); } static void remove_callback_reference(gpointer data) { G_CHILD_REMOVE(rb_mGtk, (VALUE)data); } static VALUE rg_set_search_position_func(VALUE self) { VALUE func = rb_block_proc(); G_CHILD_ADD(rb_mGtk, func); gtk_tree_view_set_search_position_func(_SELF(self), (GtkTreeViewSearchPositionFunc)search_position_func, (gpointer)func, (GDestroyNotify)remove_callback_reference); return self; } void Init_gtk_treeview(VALUE mGtk) { rb_mGtk = mGtk; VALUE RG_TARGET_NAMESPACE = G_DEF_CLASS(GTK_TYPE_TREE_VIEW, "TreeView", mGtk); id_selection = rb_intern("selection"); id_model = rb_intern("model"); RG_DEF_METHOD(initialize, -1); RG_DEF_METHOD(selection, 0); RG_DEF_METHOD(columns_autosize, 0); RG_DEF_METHOD(append_column, 1); RG_DEF_METHOD(remove_column, 1); RG_DEF_METHOD(insert_column, -1); RG_DEF_METHOD(get_column, 1); RG_DEF_METHOD(columns, 0); RG_DEF_METHOD(move_column_after, 2); RG_DEF_METHOD(set_column_drag_function, 0); RG_DEF_METHOD(scroll_to_point, 2); RG_DEF_METHOD(scroll_to_cell, 5); RG_DEF_METHOD(set_cursor, 3); RG_DEF_METHOD(cursor, 0); RG_DEF_METHOD(expand_all, 0); RG_DEF_METHOD(collapse_all, 0); RG_DEF_METHOD(expand_row, 2); RG_DEF_METHOD(collapse_row, 1); RG_DEF_METHOD(expand_to_path, 1); RG_DEF_METHOD(map_expanded_rows, 0); RG_DEF_METHOD_P(row_expanded, 1); RG_DEF_METHOD(get_path_at_pos, 2); RG_DEF_ALIAS("get_path", "get_path_at_pos"); RG_DEF_METHOD(get_cell_area, 2); RG_DEF_METHOD(get_background_area, 2); RG_DEF_METHOD(visible_rect, 0); RG_DEF_METHOD(visible_range, 0); RG_DEF_METHOD(bin_window, 0); RG_DEF_METHOD(convert_bin_window_to_tree_coords, 2); RG_DEF_METHOD(convert_bin_window_to_widget_coords, 2); RG_DEF_METHOD(convert_tree_to_bin_window_coords, 2); RG_DEF_METHOD(convert_tree_to_widget_coords, 2); RG_DEF_METHOD(convert_widget_to_bin_window_coords, 2); RG_DEF_METHOD(convert_widget_to_tree_coords, 2); RG_DEF_METHOD(enable_model_drag_dest, 2); RG_DEF_METHOD(enable_model_drag_source, 3); RG_DEF_METHOD(unset_rows_drag_source, 0); RG_DEF_METHOD(unset_rows_drag_dest, 0); RG_DEF_METHOD(set_drag_dest_row, 2); RG_DEF_METHOD(drag_dest_row, 0); RG_DEF_METHOD(get_dest_row_at_pos, 2); RG_DEF_ALIAS("get_dest_row", "get_dest_row_at_pos"); RG_DEF_METHOD(create_row_drag_icon, 1); RG_DEF_METHOD(set_search_equal_func, 0); RG_DEF_METHOD(set_cursor_on_cell, 4); RG_DEF_METHOD(set_row_separator_func, 0); RG_DEF_METHOD(search_entry, 0); RG_DEF_METHOD(set_search_entry, 1); RG_DEF_METHOD(set_search_position_func, 0); G_DEF_CLASS(GTK_TYPE_TREE_VIEW_DROP_POSITION, "DropPosition", RG_TARGET_NAMESPACE); G_DEF_CLASS(GTK_TYPE_TREE_VIEW_GRID_LINES, "GridLines", RG_TARGET_NAMESPACE); /* Option Signals */ G_DEF_SIGNAL_FUNC(RG_TARGET_NAMESPACE, "row-collapsed", (GValToRValSignalFunc)treeview_signal_func); G_DEF_SIGNAL_FUNC(RG_TARGET_NAMESPACE, "row-expanded", (GValToRValSignalFunc)treeview_signal_func); G_DEF_SIGNAL_FUNC(RG_TARGET_NAMESPACE, "test-collapse-row", (GValToRValSignalFunc)treeview_signal_func); G_DEF_SIGNAL_FUNC(RG_TARGET_NAMESPACE, "test-expand-row", (GValToRValSignalFunc)treeview_signal_func); }