Added Edje.new_from_pointer.
[ruby-edje.git] / src / rb_edje.c
1 /*
2  * $Id: rb_edje.c 335 2005-05-02 17:28:37Z tilman $
3  *
4  * Copyright (C) 2004 Tilman Sauerbeck (tilman at code-monkey de)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <ruby.h>
22 #include <stdbool.h>
23
24 #include <Edje.h>
25 #include <evas/rb_evas.h>
26 #include <evas/rb_evas_object.h>
27
28 #define __RB_EDJE_C
29 #include "rb_edje.h"
30 #include "rb_edje_main.h"
31 #include "rb_part.h"
32
33 VALUE cEdje;
34 static VALUE cMsg, eEdjeError;
35
36 static void c_mark (RbEdje *e)
37 {
38         c_evas_object_mark (&e->real);
39
40         if (!NIL_P (e->parts))
41                 rb_gc_mark (e->parts);
42
43         if (!NIL_P (e->callbacks))
44                 rb_gc_mark (e->callbacks);
45
46         if (!NIL_P (e->on_text_changed_cb))
47                 rb_gc_mark (e->on_text_changed_cb);
48 }
49
50 static void c_free (RbEdje *e)
51 {
52         c_evas_object_free (&e->real, false);
53         free (e);
54
55         edje_shutdown ();
56 }
57
58 /*
59  * call-seq:
60  *  Edje::Edje.new(evas) => edje
61  *
62  * Creates an Edje::Edje object.
63  */
64 static VALUE c_new (VALUE klass, VALUE evas)
65 {
66         VALUE self, argv[1];
67         RbEdje *edje = NULL;
68
69         CHECK_CLASS (evas, cEvas);
70         GET_OBJ (evas, RbEvas, e);
71
72         edje_init ();
73
74         self = Data_Make_Struct (klass, RbEdje, c_mark, c_free, edje);
75
76         edje->real.real = edje_object_add (e->real);
77         edje->parts = Qnil;
78         edje->callbacks = Qnil;
79         edje->on_text_changed_cb = Qnil;
80
81         argv[0] = evas;
82         rb_obj_call_init (self, 1, argv);
83
84         return self;
85 }
86
87 static VALUE c_new_from_pointer (VALUE klass, VALUE evas, VALUE ptr)
88 {
89         VALUE self, argv[1];
90         RbEdje *edje = NULL;
91
92         edje_init ();
93
94         self = Data_Make_Struct (klass, RbEdje, c_mark, c_free, edje);
95
96         edje->real.real = (Evas_Object *) ptr;
97         edje->parts = Qnil;
98         edje->callbacks = Qnil;
99         edje->on_text_changed_cb = Qnil;
100
101         argv[0] = evas;
102         rb_obj_call_init (self, 1, argv);
103
104         return self;
105 }
106
107 /*
108  * call-seq:
109  *  edje.freeze => nil
110  *
111  * Freezes <i>edje</i>.
112  */
113 static VALUE c_freeze (VALUE self)
114 {
115         GET_OBJ (self, RbEdje, e);
116
117         edje_object_freeze (e->real.real);
118
119         return Qnil;
120 }
121
122 /*
123  * call-seq:
124  *  edje.thaw => nil
125  *
126  * Thaws <i>edje</i>.
127  */
128 static VALUE c_thaw (VALUE self)
129 {
130         GET_OBJ (self, RbEdje, e);
131
132         edje_object_thaw (e->real.real);
133
134         return Qnil;
135 }
136
137 /*
138  * call-seq:
139  *  edje.load(eet, group) => nil
140  *
141  * Loads <i>eet</i> into <i>edje</i>. <i>group</i> is the
142  * name of the group to be displayed.
143  */
144 static VALUE c_load (VALUE self, VALUE eet, VALUE group)
145 {
146         GET_OBJ (self, RbEdje, e);
147
148         Check_Type (eet, T_STRING);
149         Check_Type (group, T_STRING);
150
151         if (!edje_object_file_set (e->real.real, StringValuePtr (eet),
152                                    StringValuePtr (group)))
153                 rb_raise (rb_eException, "Cannot load eet");
154
155         return Qnil;
156 }
157
158 /*
159  * call-seq:
160  *  edje.get_size_min => array
161  *
162  * Returns an array that contains the minimum size
163  * of <i>edje</i>.
164  */
165 static VALUE c_get_size_min (VALUE self)
166 {
167         int w = 0, h = 0;
168
169         GET_OBJ (self, RbEdje, e);
170
171         edje_object_size_min_get (e->real.real, &w, &h);
172
173         return rb_ary_new3 (2, INT2FIX (w), INT2FIX (h));
174 }
175
176 /*
177  * call-seq:
178  *  edje.get_size_max => array
179  *
180  * Returns an array that contains the maximum size
181  * of <i>edje</i>.
182  */
183 static VALUE c_get_size_max (VALUE self)
184 {
185         int w = 0, h = 0;
186
187         GET_OBJ (self, RbEdje, e);
188
189         edje_object_size_max_get (e->real.real, &w, &h);
190
191         return rb_ary_new3 (2, INT2FIX (w), INT2FIX (h));
192 }
193
194 /*
195  * call-seq:
196  *  edje.part_exists?(part) => true or false
197  *
198  * Returns true if <i>edje</i> has a part called <i>part</i>,
199  * else returns false.
200  */
201 static VALUE c_part_exists_get (VALUE self, VALUE name)
202 {
203         int r;
204
205         GET_OBJ (self, RbEdje, e);
206
207         Check_Type (name, T_STRING);
208
209         r = edje_object_part_exists (e->real.real, StringValuePtr (name));
210
211         return r ? Qtrue : Qfalse;
212 }
213
214 /*
215  * call-seq:
216  *  edje.part(part_name) => part
217  *
218  * Returns the <code>Edje::Part</code> object that corresponds to
219  * <i>part_name</i>. If there's no part with that name in <i>edje</i>,
220  * an exception is raised.
221  */
222 static VALUE c_part_get (VALUE self, VALUE name)
223 {
224         VALUE part;
225         const char *cname = StringValuePtr (name);
226
227         GET_OBJ (self, RbEdje, e);
228
229         if (!edje_object_part_exists (e->real.real, cname)) {
230                 rb_raise (rb_eException, "Unknown part name - %s", cname);
231                 return Qnil;
232         }
233
234         if (NIL_P (e->parts))
235                 e->parts = rb_hash_new ();
236
237         if (NIL_P (part = rb_hash_aref (e->parts, name))) {
238                 part = TO_PART (self, name);
239                 rb_hash_aset (e->parts, name, part);
240         }
241
242         return part;
243 }
244
245 static void on_text_changed (void *data, Evas_Object *eo,
246                              const char *part_name)
247 {
248         VALUE self = (VALUE) data, part, name;
249
250         GET_OBJ (self, RbEdje, e);
251
252         name = rb_str_new2 (part_name);
253
254         if (NIL_P (e->parts))
255                 e->parts = rb_hash_new ();
256
257         if (NIL_P (part = rb_hash_aref (e->parts, name))) {
258                 part = TO_PART (self, name);
259                 rb_hash_aset (e->parts, name, part);
260         }
261
262         rb_funcall (e->on_text_changed_cb,
263                     rb_intern ("call"), 1, part);
264 }
265
266 /*
267  * call-seq:
268  *  edje.on_text_changed { |part_obj| block }
269  *
270  * Registers a callback that will get called when the text
271  * of any part is changed in <i>edje</i>.
272  * The block is passed the <code>Edje::Part</code> object
273  * of which the text changed.
274  */
275 static VALUE c_on_text_changed (VALUE self)
276 {
277         GET_OBJ (self, RbEdje, e);
278
279         if (!rb_block_given_p ())
280                 return Qnil;
281
282         e->on_text_changed_cb = rb_block_proc ();
283
284         edje_object_text_change_cb_set (e->real.real, on_text_changed,
285                                         (void *) self);
286
287         return Qnil;
288 }
289
290 /*
291  * call-seq:
292  *  edje.emit_signal(signal, source) => nil
293  *
294  * Emits a signal to <i>edje</i>.
295  *
296  *  edje.emit_signal("signal_foo", "part_bar") #=> nil
297  */
298 static VALUE c_emit_signal (VALUE self, VALUE signal, VALUE source)
299 {
300         GET_OBJ (self, RbEdje, e);
301
302         Check_Type (signal, T_STRING);
303         Check_Type (source, T_STRING);
304
305         edje_object_signal_emit (e->real.real, StringValuePtr (signal),
306                                  StringValuePtr (source));
307
308         return Qnil;
309 }
310
311 static void on_signal (void *data, Evas_Object *o,
312                        const char *signal, const char *src)
313 {
314         rb_funcall ((VALUE) data, rb_intern ("call"), 2,
315                     rb_str_new2 (signal), rb_str_new2 (src));
316 }
317
318 /*
319  * call-seq:
320  *  edje.on_signal(signal [, source]) { |signal, source| block } => nil
321  *
322  * Registers a callback that will get called when <i>signal</i>
323  * is emitted by <i>source</i>.
324  * If source is nil, "*" will be used instead.
325  * The block is passed two strings, signal and source, which identify
326  * the emission.
327  */
328 static VALUE c_on_signal (int argc, VALUE *argv, VALUE self)
329 {
330         VALUE signal, src, cb;
331         char *ssrc = "*";
332
333         GET_OBJ (self, RbEdje, e);
334
335         rb_scan_args (argc, argv, "11", &signal, &src);
336
337         Check_Type (signal, T_STRING);
338
339         if (!NIL_P (src)) {
340                 Check_Type (src, T_STRING);
341                 ssrc = StringValuePtr (src);
342         }
343
344         if (!rb_block_given_p ())
345                 return Qnil;
346
347         cb = rb_block_proc ();
348
349         if (NIL_P (e->callbacks))
350                 e->callbacks = rb_ary_new ();
351
352         rb_ary_push (e->callbacks, cb);
353
354         edje_object_signal_callback_add (e->real.real,
355                                          StringValuePtr (signal),
356                                          ssrc, on_signal, (void *) cb);
357
358         return Qnil;
359 }
360
361 /*
362  * call-seq:
363  *  edje.play? => true or false
364  *
365  * Returns true if <i>edje</i> is in play mode, else returns false.
366  */
367 static VALUE c_play_get (VALUE self)
368 {
369         GET_OBJ (self, RbEdje, e);
370
371         return edje_object_play_get (e->real.real) ? Qtrue : Qfalse;
372 }
373
374 /*
375  * call-seq:
376  *  edje.play(true or false)
377  *
378  * Sets <i>edje</i> to play resp. pause mode.
379  */
380 static VALUE c_play_set (VALUE self, VALUE val)
381 {
382         GET_OBJ (self, RbEdje, e);
383
384         CHECK_BOOL(val);
385
386         edje_object_play_set (e->real.real, val == Qtrue);
387
388         return Qnil;
389 }
390
391 /*
392  * call-seq:
393  *  edje.animation? => true or false
394  *
395  * Returns the animation state of <i>edje</i>.
396  */
397 static VALUE c_animation_get (VALUE self)
398 {
399         GET_OBJ (self, RbEdje, e);
400
401         return edje_object_animation_get (e->real.real) ? Qtrue : Qfalse;
402 }
403
404 /*
405  * call-seq:
406  *  edje.animation(true or false)
407  *
408  * Sets the animation state of <i>edje</i>.
409  */
410 static VALUE c_animation_set (VALUE self, VALUE val)
411 {
412         GET_OBJ (self, RbEdje, e);
413
414         CHECK_BOOL(val);
415
416         edje_object_animation_set (e->real.real, val == Qtrue);
417
418         return Qnil;
419 }
420
421 static VALUE c_data_get (VALUE self, VALUE key)
422 {
423         const char *s;
424
425         GET_OBJ (self, RbEdje, e);
426
427         Check_Type (key, T_STRING);
428
429         s = edje_object_data_get (e->real.real, StringValuePtr (key));
430
431         return s ? rb_str_new2 (s) : Qnil;
432 }
433
434 static Edje_Message_Type get_msg_type (VALUE val)
435 {
436         VALUE ary, entry;
437         Edje_Message_Type type;
438         int i, len;
439
440         if (NIL_P (val))
441                 return EDJE_MESSAGE_NONE;
442
443         if (!NIL_P (rb_check_string_type (val))) {
444                 return EDJE_MESSAGE_STRING;
445         } else if (rb_obj_is_kind_of (val, rb_cFixnum)) {
446                 return EDJE_MESSAGE_INT;
447         } else if (rb_obj_is_kind_of (val, rb_cFloat)) {
448                 return EDJE_MESSAGE_FLOAT;
449         } else if (NIL_P (ary = rb_check_array_type (val)))
450                 return EDJE_MESSAGE_NONE;
451
452         len = RARRAY (ary)->len;
453         if (len <= 0)
454                 return EDJE_MESSAGE_NONE;
455
456         entry = rb_ary_entry (ary, 0);
457
458         if (rb_obj_is_kind_of (entry, rb_cFixnum))
459                 return EDJE_MESSAGE_INT_SET;
460         else if (rb_obj_is_kind_of (entry, rb_cFloat))
461                 return EDJE_MESSAGE_FLOAT_SET;
462         else if (NIL_P (rb_check_string_type (entry)))
463                 return EDJE_MESSAGE_NONE;
464
465         /* first entry is a string.
466          * so if we only have one entry, it's a string set
467          */
468         if (len == 1)
469                 return EDJE_MESSAGE_STRING_SET;
470
471         entry = rb_ary_entry (ary, 1);
472
473         if (!NIL_P (rb_check_string_type (entry)))
474                 type = EDJE_MESSAGE_STRING_SET;
475         else if (rb_obj_is_kind_of (entry, rb_cFixnum))
476                 type = len == 2 ? EDJE_MESSAGE_STRING_INT : EDJE_MESSAGE_STRING_INT_SET;
477         else if (rb_obj_is_kind_of (entry, rb_cFloat))
478                 type = len == 2 ? EDJE_MESSAGE_STRING_FLOAT :EDJE_MESSAGE_STRING_FLOAT_SET;
479         else
480                 return EDJE_MESSAGE_NONE;
481
482         switch (type) {
483                 case EDJE_MESSAGE_STRING_SET:
484                         for (i = 2; i < len; i++) {
485                                 entry = rb_ary_entry (ary, i);
486                                 if (NIL_P(rb_check_string_type (entry)))
487                                         return EDJE_MESSAGE_NONE;
488                         }
489
490                         break;
491                 case EDJE_MESSAGE_INT_SET:
492                 case EDJE_MESSAGE_STRING_INT_SET:
493                         for (i = 2; i < len; i++) {
494                                 entry = rb_ary_entry (ary, i);
495                                 if (!rb_obj_is_kind_of (entry, rb_cFixnum))
496                                         return EDJE_MESSAGE_NONE;
497                         }
498
499                         break;
500                 case EDJE_MESSAGE_FLOAT_SET:
501                 case EDJE_MESSAGE_STRING_FLOAT_SET:
502                         for (i = 2; i < len; i++) {
503                                 entry = rb_ary_entry (ary, 2);
504                                 if (!rb_obj_is_kind_of (entry, rb_cFloat))
505                                         return EDJE_MESSAGE_NONE;
506                         }
507
508                         break;
509                 default:
510                         break;
511         }
512
513         return type;
514 }
515
516 static VALUE c_send_message (VALUE self, VALUE msg)
517 {
518         Edje_Message_String msg_s;
519         Edje_Message_Int msg_i;
520         Edje_Message_Float msg_f;
521         Edje_Message_String_Set *s_set = NULL;
522         Edje_Message_Int_Set *i_set = NULL;
523         Edje_Message_Float_Set *f_set = NULL;
524         Edje_Message_String_Int si;
525         Edje_Message_String_Float sf;
526         Edje_Message_String_Int_Set *si_set = NULL;
527         Edje_Message_String_Float_Set *sf_set = NULL;
528         Edje_Message_Type type;
529         void *data = NULL;
530         int id, i, len = 0;
531         bool free_data = false;
532         VALUE v, ary, entry;
533
534         GET_OBJ (self, RbEdje, e);
535
536         CHECK_CLASS (msg, cMsg);
537
538         id = FIX2INT (rb_iv_get (msg, "@id"));
539         v = rb_iv_get (msg, "@value");
540
541         type = get_msg_type (v);
542         if (!NIL_P (ary = rb_check_array_type (v)))
543                 len = RARRAY (ary)->len;
544
545         switch (type) {
546                 case EDJE_MESSAGE_NONE:
547                         rb_raise (eEdjeError, "unsupported value");
548                         return Qnil;
549                 case EDJE_MESSAGE_SIGNAL:
550                         return Qnil; /* cannot happen */
551                 case EDJE_MESSAGE_STRING:
552                         msg_s.str = StringValuePtr (v);
553                         data = &msg_s;
554                         break;
555                 case EDJE_MESSAGE_INT:
556                         msg_i.val = FIX2INT (v);
557                         data = &msg_i;
558                         break;
559                 case EDJE_MESSAGE_FLOAT:
560                         msg_f.val = NUM2DBL (v);
561                         data = &msg_f;
562                         break;
563                 case EDJE_MESSAGE_STRING_SET:
564                         s_set = malloc (sizeof (Edje_Message_String_Set) + ((len - 1) * sizeof (char *)));
565                         s_set->count = len;
566                         free_data = true;
567
568                         for (i = 0; i < len; i++) {
569                                 entry = rb_ary_entry (ary, i);
570                                 s_set->str[i] = StringValuePtr (entry);
571                         }
572
573                         data = s_set;
574
575                         break;
576                 case EDJE_MESSAGE_INT_SET:
577                         i_set = malloc (sizeof (Edje_Message_Int_Set) + ((len - 1) * sizeof (int)));
578                         i_set->count = len;
579                         free_data = true;
580
581                         for (i = 0; i < len; i++) {
582                                 entry = rb_ary_entry (ary, i);
583                                 i_set->val[i] = FIX2INT (entry);
584                         }
585
586                         data = i_set;
587
588                         break;
589                 case EDJE_MESSAGE_FLOAT_SET:
590                         f_set = malloc (sizeof (Edje_Message_Float_Set) + ((len - 1) * sizeof (double)));
591                         f_set->count = len;
592                         free_data = true;
593
594                         for (i = 0; i < len; i++) {
595                                 entry = rb_ary_entry (ary, i);
596                                 f_set->val[i] = NUM2DBL (entry);
597                         }
598
599                         data = f_set;
600
601                         break;
602                 case EDJE_MESSAGE_STRING_INT:
603                         entry = rb_ary_entry (ary, 0);
604                         si.str = StringValuePtr (entry);
605                         entry = rb_ary_entry (ary, 1);
606                         si.val = FIX2INT (entry);
607
608                         data = &si;
609
610                         break;
611                 case EDJE_MESSAGE_STRING_FLOAT:
612                         entry = rb_ary_entry (ary, 0);
613                         sf.str = StringValuePtr (entry);
614                         entry = rb_ary_entry (ary, 1);
615                         sf.val = NUM2DBL (entry);
616
617                         data = &sf;
618
619                         break;
620                 case EDJE_MESSAGE_STRING_INT_SET:
621                         si_set = malloc (sizeof (Edje_Message_String_Int_Set) + ((len - 1) * sizeof (int)));
622                         si_set->count = len - 1;
623                         free_data = true;
624
625                         entry = rb_ary_entry (ary, 0);
626                         si_set->str = StringValuePtr (entry);
627
628                         for (i = 1; i < len; i++) {
629                                 entry = rb_ary_entry (ary, i);
630                                 si_set->val[i - 1] = FIX2INT (entry);
631                         }
632
633                         data = &si_set;
634
635                         break;
636                 case EDJE_MESSAGE_STRING_FLOAT_SET:
637                         sf_set = malloc (sizeof (Edje_Message_String_Float_Set) + ((len - 1) * sizeof (double)));
638                         sf_set->count = len - 1;
639                         free_data = true;
640
641                         entry = rb_ary_entry (ary, 0);
642                         sf_set->str = StringValuePtr (entry);
643
644                         for (i = 1; i < len; i++) {
645                                 entry = rb_ary_entry (ary, i);
646                                 sf_set->val[i - 1] = NUM2DBL (entry);
647                         }
648
649                         data = &sf_set;
650
651                         break;
652         }
653
654         edje_object_message_send (e->real.real, type, id, data);
655
656         if (free_data)
657                 free (data);
658
659         return Qnil;
660 }
661
662 static VALUE c_msg_init (int argc, VALUE *argv, VALUE self)
663 {
664         VALUE id, val;
665
666         if (argc == 2)
667                 rb_scan_args (argc, argv, "11", &id, &val);
668         else
669                 rb_scan_args (argc, argv, "1*", &id, &val);
670
671         Check_Type (id, T_FIXNUM);
672
673         rb_iv_set (self, "@id", id);
674         rb_iv_set (self, "@value", val);
675
676         return self;
677 }
678
679 void Init_Edje (void)
680 {
681         cEdje = rb_define_class_under (mEdje, "Edje", cEvasObject);
682
683         rb_define_singleton_method (cEdje, "new", c_new, 1);
684         rb_define_singleton_method (cEdje, "new_from_pointer",
685                                     c_new_from_pointer, 2);
686         rb_define_method (cEdje, "freeze", c_freeze, 0);
687         rb_define_method (cEdje, "thaw", c_thaw, 0);
688         rb_define_method (cEdje, "load", c_load, 2);
689         rb_define_method (cEdje, "get_size_min", c_get_size_min, 0);
690         rb_define_method (cEdje, "get_size_max", c_get_size_max, 0);
691         rb_define_method (cEdje, "part_exists?", c_part_exists_get, 1);
692         rb_define_method (cEdje, "part", c_part_get, 1);
693         rb_define_method (cEdje, "on_text_changed", c_on_text_changed, 0);
694         rb_define_method (cEdje, "emit_signal", c_emit_signal, 2);
695         rb_define_method (cEdje, "on_signal", c_on_signal, -1);
696         rb_define_method (cEdje, "play?", c_play_get, 0);
697         rb_define_method (cEdje, "play=", c_play_set, 1);
698         rb_define_method (cEdje, "animation?", c_animation_get, 0);
699         rb_define_method (cEdje, "animation=", c_animation_set, 1);
700         rb_define_method (cEdje, "data", c_data_get, 1);
701         rb_define_method (cEdje, "send_message", c_send_message, 1);
702
703         cMsg = rb_define_class_under (mEdje, "Message", rb_cObject);
704
705         rb_define_method (cMsg, "initialize", c_msg_init, -1);
706
707         rb_define_attr (cMsg, "id", 1, 1);
708         rb_define_attr (cMsg, "value", 1, 1);
709
710         eEdjeError = rb_define_class_under (mEdje, "EdjeError",
711                                            rb_eStandardError);
712 }