/* * $Id: rb_edje.c 355 2006-02-10 18:15:13Z tilman $ * * Copyright (C) 2004 Tilman Sauerbeck (tilman at code-monkey de) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #define __RB_EDJE_C #include "rb_edje.h" #include "rb_edje_main.h" #include "rb_part.h" VALUE cEdje; static VALUE cMsg, eEdjeError; static void c_mark (RbEdje *e) { c_evas_object_mark (&e->real); if (!NIL_P (e->parts)) rb_gc_mark (e->parts); if (!NIL_P (e->callbacks)) rb_gc_mark (e->callbacks); if (!NIL_P (e->on_text_changed_cb)) rb_gc_mark (e->on_text_changed_cb); } static void c_free (RbEdje *e) { c_evas_object_free (&e->real, false); free (e); edje_shutdown (); } static VALUE c_alloc (VALUE klass) { RbEdje *e = NULL; edje_init (); return Data_Make_Struct (klass, RbEdje, c_mark, c_free, e); } /* * call-seq: * Edje::Edje.new(evas) => edje * * Creates an Edje::Edje object. */ static VALUE c_init (VALUE self, VALUE evas) { CHECK_CLASS (evas, cEvas); GET_OBJ (evas, RbEvas, e); GET_OBJ (self, RbEdje, edje); /* c_new_from_pointer() might already have initialized the pointer */ if (!edje->real.real) edje->real.real = edje_object_add (e->real); edje->parts = Qnil; edje->callbacks = Qnil; edje->on_text_changed_cb = Qnil; rb_call_super (1, &evas); return self; } static VALUE c_new_from_pointer (VALUE klass, VALUE evas, VALUE ptr) { VALUE self = rb_obj_alloc (klass); GET_OBJ (self, RbEdje, edje); edje->real.real = (Evas_Object *) ptr; rb_obj_call_init (self, 1, &evas); return self; } /* * call-seq: * edje.freeze => nil * * Freezes edje. */ static VALUE c_freeze (VALUE self) { GET_OBJ (self, RbEdje, e); edje_object_freeze (e->real.real); return Qnil; } /* * call-seq: * edje.thaw => nil * * Thaws edje. */ static VALUE c_thaw (VALUE self) { GET_OBJ (self, RbEdje, e); edje_object_thaw (e->real.real); return Qnil; } /* * call-seq: * edje.load(eet, group) => nil * * Loads eet into edje. group is the * name of the group to be displayed. */ static VALUE c_load (VALUE self, VALUE eet, VALUE group) { GET_OBJ (self, RbEdje, e); Check_Type (eet, T_STRING); Check_Type (group, T_STRING); if (!edje_object_file_set (e->real.real, StringValuePtr (eet), StringValuePtr (group))) rb_raise (rb_eException, "Cannot load eet"); return Qnil; } /* * call-seq: * edje.get_size_min => array * * Returns an array that contains the minimum size * of edje. */ static VALUE c_get_size_min (VALUE self) { int w = 0, h = 0; GET_OBJ (self, RbEdje, e); edje_object_size_min_get (e->real.real, &w, &h); return rb_ary_new3 (2, INT2FIX (w), INT2FIX (h)); } /* * call-seq: * edje.get_size_max => array * * Returns an array that contains the maximum size * of edje. */ static VALUE c_get_size_max (VALUE self) { int w = 0, h = 0; GET_OBJ (self, RbEdje, e); edje_object_size_max_get (e->real.real, &w, &h); return rb_ary_new3 (2, INT2FIX (w), INT2FIX (h)); } /* * call-seq: * edje.part_exists?(part) => true or false * * Returns true if edje has a part called part, * else returns false. */ static VALUE c_part_exists_get (VALUE self, VALUE name) { int r; GET_OBJ (self, RbEdje, e); Check_Type (name, T_STRING); r = edje_object_part_exists (e->real.real, StringValuePtr (name)); return r ? Qtrue : Qfalse; } /* * call-seq: * edje.part(part_name) => part * * Returns the Edje::Part object that corresponds to * part_name. If there's no part with that name in edje, * an exception is raised. */ static VALUE c_part_get (VALUE self, VALUE name) { VALUE part; const char *cname = StringValuePtr (name); GET_OBJ (self, RbEdje, e); if (!edje_object_part_exists (e->real.real, cname)) { rb_raise (rb_eException, "Unknown part name - %s", cname); return Qnil; } if (NIL_P (e->parts)) e->parts = rb_hash_new (); if (NIL_P (part = rb_hash_aref (e->parts, name))) { part = TO_PART (self, name); rb_hash_aset (e->parts, name, part); } return part; } static void on_text_changed (void *data, Evas_Object *eo, const char *part_name) { VALUE self = (VALUE) data, part, name; GET_OBJ (self, RbEdje, e); name = rb_str_new2 (part_name); if (NIL_P (e->parts)) e->parts = rb_hash_new (); if (NIL_P (part = rb_hash_aref (e->parts, name))) { part = TO_PART (self, name); rb_hash_aset (e->parts, name, part); } rb_funcall (e->on_text_changed_cb, rb_intern ("call"), 1, part); } /* * call-seq: * edje.on_text_changed { |part_obj| block } * * Registers a callback that will get called when the text * of any part is changed in edje. * The block is passed the Edje::Part object * of which the text changed. */ static VALUE c_on_text_changed (VALUE self) { GET_OBJ (self, RbEdje, e); if (!rb_block_given_p ()) return Qnil; e->on_text_changed_cb = rb_block_proc (); edje_object_text_change_cb_set (e->real.real, on_text_changed, (void *) self); return Qnil; } /* * call-seq: * edje.emit_signal(signal, source) => nil * * Emits a signal to edje. * * edje.emit_signal("signal_foo", "part_bar") #=> nil */ static VALUE c_emit_signal (VALUE self, VALUE signal, VALUE source) { GET_OBJ (self, RbEdje, e); Check_Type (signal, T_STRING); Check_Type (source, T_STRING); edje_object_signal_emit (e->real.real, StringValuePtr (signal), StringValuePtr (source)); return Qnil; } static void on_signal (void *data, Evas_Object *o, const char *signal, const char *src) { rb_funcall ((VALUE) data, rb_intern ("call"), 2, rb_str_new2 (signal), rb_str_new2 (src)); } /* * call-seq: * edje.on_signal(signal [, source]) { |signal, source| block } => nil * * Registers a callback that will get called when signal * is emitted by source. * If source is nil, "*" will be used instead. * The block is passed two strings, signal and source, which identify * the emission. */ static VALUE c_on_signal (int argc, VALUE *argv, VALUE self) { VALUE signal, src, cb; char *ssrc = "*"; GET_OBJ (self, RbEdje, e); rb_scan_args (argc, argv, "11", &signal, &src); Check_Type (signal, T_STRING); if (!NIL_P (src)) { Check_Type (src, T_STRING); ssrc = StringValuePtr (src); } if (!rb_block_given_p ()) return Qnil; cb = rb_block_proc (); if (NIL_P (e->callbacks)) e->callbacks = rb_ary_new (); rb_ary_push (e->callbacks, cb); edje_object_signal_callback_add (e->real.real, StringValuePtr (signal), ssrc, on_signal, (void *) cb); return Qnil; } /* * call-seq: * edje.play? => true or false * * Returns true if edje is in play mode, else returns false. */ static VALUE c_play_get (VALUE self) { GET_OBJ (self, RbEdje, e); return edje_object_play_get (e->real.real) ? Qtrue : Qfalse; } /* * call-seq: * edje.play(true or false) * * Sets edje to play resp. pause mode. */ static VALUE c_play_set (VALUE self, VALUE val) { GET_OBJ (self, RbEdje, e); CHECK_BOOL(val); edje_object_play_set (e->real.real, val == Qtrue); return Qnil; } /* * call-seq: * edje.animation? => true or false * * Returns the animation state of edje. */ static VALUE c_animation_get (VALUE self) { GET_OBJ (self, RbEdje, e); return edje_object_animation_get (e->real.real) ? Qtrue : Qfalse; } /* * call-seq: * edje.animation(true or false) * * Sets the animation state of edje. */ static VALUE c_animation_set (VALUE self, VALUE val) { GET_OBJ (self, RbEdje, e); CHECK_BOOL(val); edje_object_animation_set (e->real.real, val == Qtrue); return Qnil; } static VALUE c_data_get (VALUE self, VALUE key) { const char *s; GET_OBJ (self, RbEdje, e); Check_Type (key, T_STRING); s = edje_object_data_get (e->real.real, StringValuePtr (key)); return s ? rb_str_new2 (s) : Qnil; } static Edje_Message_Type get_msg_type (VALUE val) { VALUE ary, entry; Edje_Message_Type type; int i, len; if (NIL_P (val)) return EDJE_MESSAGE_NONE; if (!NIL_P (rb_check_string_type (val))) { return EDJE_MESSAGE_STRING; } else if (rb_obj_is_kind_of (val, rb_cFixnum)) { return EDJE_MESSAGE_INT; } else if (rb_obj_is_kind_of (val, rb_cFloat)) { return EDJE_MESSAGE_FLOAT; } else if (NIL_P (ary = rb_check_array_type (val))) return EDJE_MESSAGE_NONE; len = RARRAY (ary)->len; if (len <= 0) return EDJE_MESSAGE_NONE; entry = rb_ary_entry (ary, 0); if (rb_obj_is_kind_of (entry, rb_cFixnum)) return EDJE_MESSAGE_INT_SET; else if (rb_obj_is_kind_of (entry, rb_cFloat)) return EDJE_MESSAGE_FLOAT_SET; else if (NIL_P (rb_check_string_type (entry))) return EDJE_MESSAGE_NONE; /* first entry is a string. * so if we only have one entry, it's a string set */ if (len == 1) return EDJE_MESSAGE_STRING_SET; entry = rb_ary_entry (ary, 1); if (!NIL_P (rb_check_string_type (entry))) type = EDJE_MESSAGE_STRING_SET; else if (rb_obj_is_kind_of (entry, rb_cFixnum)) type = len == 2 ? EDJE_MESSAGE_STRING_INT : EDJE_MESSAGE_STRING_INT_SET; else if (rb_obj_is_kind_of (entry, rb_cFloat)) type = len == 2 ? EDJE_MESSAGE_STRING_FLOAT :EDJE_MESSAGE_STRING_FLOAT_SET; else return EDJE_MESSAGE_NONE; switch (type) { case EDJE_MESSAGE_STRING_SET: for (i = 2; i < len; i++) { entry = rb_ary_entry (ary, i); if (NIL_P(rb_check_string_type (entry))) return EDJE_MESSAGE_NONE; } break; case EDJE_MESSAGE_INT_SET: case EDJE_MESSAGE_STRING_INT_SET: for (i = 2; i < len; i++) { entry = rb_ary_entry (ary, i); if (!rb_obj_is_kind_of (entry, rb_cFixnum)) return EDJE_MESSAGE_NONE; } break; case EDJE_MESSAGE_FLOAT_SET: case EDJE_MESSAGE_STRING_FLOAT_SET: for (i = 2; i < len; i++) { entry = rb_ary_entry (ary, 2); if (!rb_obj_is_kind_of (entry, rb_cFloat)) return EDJE_MESSAGE_NONE; } break; default: break; } return type; } static VALUE c_send_message (VALUE self, VALUE msg) { Edje_Message_String msg_s; Edje_Message_Int msg_i; Edje_Message_Float msg_f; Edje_Message_String_Set *s_set = NULL; Edje_Message_Int_Set *i_set = NULL; Edje_Message_Float_Set *f_set = NULL; Edje_Message_String_Int si; Edje_Message_String_Float sf; Edje_Message_String_Int_Set *si_set = NULL; Edje_Message_String_Float_Set *sf_set = NULL; Edje_Message_Type type; void *data = NULL; int id, i, len = 0; bool free_data = false; VALUE v, ary, entry; GET_OBJ (self, RbEdje, e); CHECK_CLASS (msg, cMsg); id = FIX2INT (rb_iv_get (msg, "@id")); v = rb_iv_get (msg, "@value"); type = get_msg_type (v); if (!NIL_P (ary = rb_check_array_type (v))) len = RARRAY (ary)->len; switch (type) { case EDJE_MESSAGE_NONE: rb_raise (eEdjeError, "unsupported value"); return Qnil; case EDJE_MESSAGE_SIGNAL: return Qnil; /* cannot happen */ case EDJE_MESSAGE_STRING: msg_s.str = StringValuePtr (v); data = &msg_s; break; case EDJE_MESSAGE_INT: msg_i.val = FIX2INT (v); data = &msg_i; break; case EDJE_MESSAGE_FLOAT: msg_f.val = NUM2DBL (v); data = &msg_f; break; case EDJE_MESSAGE_STRING_SET: s_set = malloc (sizeof (Edje_Message_String_Set) + ((len - 1) * sizeof (char *))); s_set->count = len; free_data = true; for (i = 0; i < len; i++) { entry = rb_ary_entry (ary, i); s_set->str[i] = StringValuePtr (entry); } data = s_set; break; case EDJE_MESSAGE_INT_SET: i_set = malloc (sizeof (Edje_Message_Int_Set) + ((len - 1) * sizeof (int))); i_set->count = len; free_data = true; for (i = 0; i < len; i++) { entry = rb_ary_entry (ary, i); i_set->val[i] = FIX2INT (entry); } data = i_set; break; case EDJE_MESSAGE_FLOAT_SET: f_set = malloc (sizeof (Edje_Message_Float_Set) + ((len - 1) * sizeof (double))); f_set->count = len; free_data = true; for (i = 0; i < len; i++) { entry = rb_ary_entry (ary, i); f_set->val[i] = NUM2DBL (entry); } data = f_set; break; case EDJE_MESSAGE_STRING_INT: entry = rb_ary_entry (ary, 0); si.str = StringValuePtr (entry); entry = rb_ary_entry (ary, 1); si.val = FIX2INT (entry); data = &si; break; case EDJE_MESSAGE_STRING_FLOAT: entry = rb_ary_entry (ary, 0); sf.str = StringValuePtr (entry); entry = rb_ary_entry (ary, 1); sf.val = NUM2DBL (entry); data = &sf; break; case EDJE_MESSAGE_STRING_INT_SET: si_set = malloc (sizeof (Edje_Message_String_Int_Set) + ((len - 1) * sizeof (int))); si_set->count = len - 1; free_data = true; entry = rb_ary_entry (ary, 0); si_set->str = StringValuePtr (entry); for (i = 1; i < len; i++) { entry = rb_ary_entry (ary, i); si_set->val[i - 1] = FIX2INT (entry); } data = &si_set; break; case EDJE_MESSAGE_STRING_FLOAT_SET: sf_set = malloc (sizeof (Edje_Message_String_Float_Set) + ((len - 1) * sizeof (double))); sf_set->count = len - 1; free_data = true; entry = rb_ary_entry (ary, 0); sf_set->str = StringValuePtr (entry); for (i = 1; i < len; i++) { entry = rb_ary_entry (ary, i); sf_set->val[i - 1] = NUM2DBL (entry); } data = &sf_set; break; } edje_object_message_send (e->real.real, type, id, data); if (free_data) free (data); return Qnil; } static VALUE c_msg_init (int argc, VALUE *argv, VALUE self) { VALUE id, val; if (argc == 2) rb_scan_args (argc, argv, "11", &id, &val); else rb_scan_args (argc, argv, "1*", &id, &val); Check_Type (id, T_FIXNUM); rb_iv_set (self, "@id", id); rb_iv_set (self, "@value", val); return self; } void Init_Edje (void) { cEdje = rb_define_class_under (mEdje, "Edje", cEvasObject); rb_define_alloc_func (cEdje, c_alloc); rb_define_singleton_method (cEdje, "new_from_pointer", c_new_from_pointer, 2); rb_define_method (cEdje, "initialize", c_init, 1); rb_define_method (cEdje, "freeze", c_freeze, 0); rb_define_method (cEdje, "thaw", c_thaw, 0); rb_define_method (cEdje, "load", c_load, 2); rb_define_method (cEdje, "get_size_min", c_get_size_min, 0); rb_define_method (cEdje, "get_size_max", c_get_size_max, 0); rb_define_method (cEdje, "part_exists?", c_part_exists_get, 1); rb_define_method (cEdje, "part", c_part_get, 1); rb_define_method (cEdje, "on_text_changed", c_on_text_changed, 0); rb_define_method (cEdje, "emit_signal", c_emit_signal, 2); rb_define_method (cEdje, "on_signal", c_on_signal, -1); rb_define_method (cEdje, "play?", c_play_get, 0); rb_define_method (cEdje, "play=", c_play_set, 1); rb_define_method (cEdje, "animation?", c_animation_get, 0); rb_define_method (cEdje, "animation=", c_animation_set, 1); rb_define_method (cEdje, "data", c_data_get, 1); rb_define_method (cEdje, "send_message", c_send_message, 1); cMsg = rb_define_class_under (mEdje, "Message", rb_cObject); rb_define_method (cMsg, "initialize", c_msg_init, -1); rb_define_attr (cMsg, "id", 1, 1); rb_define_attr (cMsg, "value", 1, 1); eEdjeError = rb_define_class_under (mEdje, "EdjeError", rb_eStandardError); }