/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */ /* * Copyright (C) 2011-2013 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 cListStore #define _SELF(s) (RVAL2GTKLISTSTORE(s)) static ID id_to_a, id_size; static VALUE rg_initialize(int argc, VALUE *argv, VALUE self) { gint cnt; GtkListStore* store; GType* buf; if (argc == 0) rb_raise(rb_eArgError, "need more than 1 class type."); buf = ALLOCA_N(GType, argc); for (cnt = 0; cnt < argc; cnt++) { buf[cnt] = CLASS2GTYPE(argv[cnt]); } store = gtk_list_store_newv(argc, buf); G_INITIALIZE(self, store); return Qnil; } static VALUE rg_set_column_types(int argc, VALUE *argv, VALUE self) { gint cnt; GType* buf; if (argc == 0) rb_raise(rb_eArgError, "need more than 1 class type."); buf = ALLOCA_N(GType, argc); for (cnt = 0; cnt < argc; cnt++) { buf[cnt] = CLASS2GTYPE(argv[cnt]); } gtk_list_store_set_column_types(_SELF(self), argc, buf); return self; } static VALUE rg_set_value(VALUE self, VALUE iter, VALUE column, VALUE value) { GType gtype = gtk_tree_model_get_column_type(RVAL2GTKTREEMODEL(self), NUM2INT(column)); GValue gval = G_VALUE_INIT; g_value_init(&gval, gtype); rbgobj_rvalue_to_gvalue(value, &gval); G_CHILD_ADD(iter, value); gtk_list_store_set_value(_SELF(self), RVAL2GTKTREEITER(iter), NUM2INT(column), &gval); g_value_unset(&gval); return self; } typedef struct _ValuesInfo { gint i; VALUE iter; GtkTreeModel *model; gint *g_columns; GValue *g_values; } ValuesInfo; static int collect_value(VALUE key, VALUE value, ValuesInfo *info) { GType g_type; gint column; column = NUM2INT(key); info->g_columns[info->i] = column; g_type = gtk_tree_model_get_column_type(info->model, column); g_value_init(&(info->g_values[info->i]), g_type); rbgobj_rvalue_to_gvalue(value, &(info->g_values[info->i])); G_CHILD_ADD(info->iter, value); info->i++; return ST_CONTINUE; } static void hash_to_values(VALUE hash, VALUE iter, GtkTreeModel *model, gint *g_columns, GValue *g_values, G_GNUC_UNUSED gint length) { ValuesInfo info; info.i = 0; info.iter = iter; info.model = model; info.g_columns = g_columns; info.g_values = g_values; rb_hash_foreach(hash, collect_value, (VALUE)(&info)); } static void array_to_values(VALUE array, VALUE iter, GtkTreeModel *model, gint *g_columns, GValue *g_values, gint length) { gint i; for (i = 0; i < length; i++) { GType g_type; g_columns[i] = i; g_type = gtk_tree_model_get_column_type(model, i); g_value_init(&g_values[i], g_type); rbgobj_rvalue_to_gvalue(RARRAY_PTR(array)[i], &g_values[i]); G_CHILD_ADD(iter, RARRAY_PTR(array)[i]); } } static VALUE rg_set_values(VALUE self, VALUE iter, VALUE values) { GValue *g_values; GtkListStore *store; GtkTreeModel *model; gint *g_columns; gint i, length; length = NUM2INT(rb_funcall(values, id_size, 0)); if (length == 0) return self; g_columns = ALLOCA_N(gint, length); g_values = ALLOCA_N(GValue, length); MEMZERO(g_values, GValue, length); store = _SELF(self); model = GTK_TREE_MODEL(store); if (RVAL2CBOOL(rb_obj_is_kind_of(values, rb_cHash))) { hash_to_values(values, iter, model, g_columns, g_values, length); } else if (RVAL2CBOOL(rb_obj_is_kind_of(values, rb_cArray))) { array_to_values(values, iter, model, g_columns, g_values, length); } else { rb_raise(rb_eArgError, "must be array or hash of values"); } gtk_list_store_set_valuesv(store, RVAL2GTKTREEITER(iter), g_columns, g_values, length); for (i = 0; i < length; i++) g_value_unset(&g_values[i]); return self; } static VALUE rg_remove(VALUE self, VALUE iter) { G_CHILD_REMOVE(self, iter); return CBOOL2RVAL(gtk_list_store_remove(_SELF(self), RVAL2GTKTREEITER(iter))); } struct lstore_insert_args { GtkListStore *store; GtkTreeIter iter; gint position; VALUE ary; long i; long n; gint *columns; GValue *values; }; static VALUE lstore_insert_body(VALUE value) { struct lstore_insert_args *args = (struct lstore_insert_args *)value; GtkTreeModel *model = GTK_TREE_MODEL(args->store); for (args->i = 0; args->i < args->n; args->i++) { VALUE ary = rb_ary_to_ary(RARRAY_PTR(args->ary)[args->i]); args->columns[args->i] = NUM2INT(RARRAY_PTR(ary)[1]); g_value_init(&args->values[args->i], gtk_tree_model_get_column_type(model, args->columns[args->i])); rbgobj_rvalue_to_gvalue(RARRAY_PTR(ary)[0], &args->values[args->i]); } gtk_list_store_insert_with_valuesv(args->store, &args->iter, args->position, args->columns, args->values, args->n); return Qnil; } static VALUE lstore_insert_ensure(VALUE value) { long i; struct lstore_insert_args *args = (struct lstore_insert_args *)value; for (i = 0; i < args->i; i++) g_value_unset(&args->values[i]); g_free(args->values); g_free(args->columns); return Qnil; } /* Gtk::ListStore#insert(pos, val1 => 0, val2 => 2, ... ) */ static VALUE rg_insert(int argc, VALUE *argv, VALUE self) { VALUE position, values, result; struct lstore_insert_args args; args.store = _SELF(self); rb_scan_args(argc, argv, "11", &position, &values); args.position = NUM2INT(position); if (NIL_P(values)){ gtk_list_store_insert(args.store, &args.iter, args.position); } else { args.ary = rb_funcall(values, id_to_a, 0); args.n = RARRAY_LEN(args.ary); args.columns = g_new(gint, args.n); args.values = g_new0(GValue, args.n); rb_ensure(lstore_insert_body, (VALUE)&args, lstore_insert_ensure, (VALUE)&args); } args.iter.user_data3 = args.store; result = GTKTREEITER2RVAL(&args.iter); return result; } static VALUE rg_insert_before(VALUE self, VALUE sibling) { VALUE ret; GtkTreeIter iter; GtkListStore* model = _SELF(self); gtk_list_store_insert_before(model, &iter, NIL_P(sibling) ? NULL : RVAL2GTKTREEITER(sibling)); iter.user_data3 = model; ret = GTKTREEITER2RVAL(&iter); return ret; } static VALUE rg_insert_after(VALUE self, VALUE sibling) { VALUE ret; GtkTreeIter iter; GtkListStore* model = _SELF(self); gtk_list_store_insert_after(model, &iter, NIL_P(sibling) ? NULL : RVAL2GTKTREEITER(sibling)); iter.user_data3 = model; ret = GTKTREEITER2RVAL(&iter); return ret; } static VALUE rg_prepend(VALUE self) { VALUE ret; GtkTreeIter iter; GtkListStore* model = _SELF(self); gtk_list_store_prepend(model, &iter); iter.user_data3 = model; ret = GTKTREEITER2RVAL(&iter); return ret; } static VALUE rg_append(VALUE self) { VALUE ret; GtkTreeIter iter; GtkListStore* model = _SELF(self); gtk_list_store_append(model, &iter); iter.user_data3 = model; ret = GTKTREEITER2RVAL(&iter); return ret; } static VALUE rg_clear(VALUE self) { G_CHILD_REMOVE_ALL(self); gtk_list_store_clear(_SELF(self)); return self; } static VALUE rg_iter_is_valid_p(VALUE self, VALUE iter) { return (NIL_P(iter)) ? Qfalse : CBOOL2RVAL(gtk_list_store_iter_is_valid(_SELF(self), RVAL2GTKTREEITER(iter))); } static VALUE rg_reorder(VALUE self, VALUE rbnew_order) { GtkListStore *store = _SELF(self); long n; gint *new_order = RVAL2GINTS(rbnew_order, n); gtk_list_store_reorder(store, new_order); g_free(new_order); return self; } static VALUE rg_swap(VALUE self, VALUE iter1, VALUE iter2) { gtk_list_store_swap(_SELF(self), RVAL2GTKTREEITER(iter1), RVAL2GTKTREEITER(iter2)); return self; } static VALUE rg_move_before(VALUE self, VALUE iter, VALUE position) { gtk_list_store_move_before(_SELF(self), RVAL2GTKTREEITER(iter), NIL_P(position) ? NULL : RVAL2GTKTREEITER(position)); return self; } static VALUE rg_move_after(VALUE self, VALUE iter, VALUE position) { gtk_list_store_move_after(_SELF(self), RVAL2GTKTREEITER(iter), NIL_P(position) ? NULL : RVAL2GTKTREEITER(position)); return self; } void Init_gtk_list_store(VALUE mGtk) { VALUE RG_TARGET_NAMESPACE = G_DEF_CLASS(GTK_TYPE_LIST_STORE, "ListStore", mGtk); id_to_a = rb_intern("to_a"); id_size = rb_intern("size"); rbgtk_register_treeiter_set_value_func(GTK_TYPE_LIST_STORE, (rbgtkiter_set_value_func)>k_list_store_set_value); RG_DEF_METHOD(initialize, -1); RG_DEF_METHOD(set_column_types, -1); RG_DEF_METHOD(set_value, 3); RG_DEF_METHOD(remove, 1); RG_DEF_METHOD(insert, -1); RG_DEF_METHOD(insert_before, 1); RG_DEF_METHOD(insert_after, 1); RG_DEF_METHOD(prepend, 0); RG_DEF_METHOD(append, 0); RG_DEF_METHOD(clear, 0); RG_DEF_METHOD_P(iter_is_valid, 1); RG_DEF_METHOD(reorder, 1); RG_DEF_METHOD(swap, 2); RG_DEF_METHOD(move_before, 2); RG_DEF_METHOD(move_after, 2); RG_DEF_METHOD(set_values, 2); }