elementary: fix various bug in elm_icon related to ethumb usage.
[framework/uifw/elementary.git] / src / lib / els_icon.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Smart_Data Smart_Data;
5
6 struct _Smart_Data
7 {
8    Evas_Coord   x, y, w, h;
9    Evas_Object *obj;
10    int          size;
11    double       scale;
12    Eina_Bool fill_inside : 1;
13    Eina_Bool scale_up : 1;
14    Eina_Bool scale_down : 1;
15    Eina_Bool preloading : 1;
16    Eina_Bool show : 1;
17    Eina_Bool edit : 1;
18    Eina_Bool edje : 1;
19    Eina_Bool aspect_ratio_retained: 1;
20    Elm_Image_Orient orient;
21 };
22
23 /* local subsystem functions */
24 static void _smart_reconfigure(Smart_Data *sd);
25 static void _smart_init(void);
26 static void _smart_add(Evas_Object *obj);
27 static void _smart_del(Evas_Object *obj);
28 static void _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
29 static void _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
30 static void _smart_show(Evas_Object *obj);
31 static void _smart_hide(Evas_Object *obj);
32 static void _smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
33 static void _smart_clip_set(Evas_Object *obj, Evas_Object * clip);
34 static void _smart_clip_unset(Evas_Object *obj);
35
36 static void _els_smart_icon_flip_horizontal(Smart_Data *sd);
37 static void _els_smart_icon_flip_vertical(Smart_Data *sd);
38 static void _els_smart_icon_rotate_180(Smart_Data *sd);
39 static Eina_Bool _els_smart_icon_dropcb(void *,Evas_Object *, Elm_Selection_Data *);
40
41 /* local subsystem globals */
42 static Evas_Smart *_e_smart = NULL;
43
44 /* externally accessible functions */
45 Evas_Object *
46 _els_smart_icon_add(Evas *evas)
47 {
48    _smart_init();
49    return evas_object_smart_add(evas, _e_smart);
50 }
51
52 static void
53 _preloaded(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
54 {
55    Smart_Data *sd = data;
56
57    sd->preloading = EINA_FALSE;
58    if (sd->show)
59      evas_object_show(sd->obj);
60 }
61
62 Eina_Bool
63 _els_smart_icon_file_key_set(Evas_Object *obj, const char *file, const char *key)
64 {
65    Smart_Data *sd;
66    Evas_Object *pclip;
67
68    sd = evas_object_smart_data_get(obj);
69    if (!sd) return EINA_FALSE;
70    /* smart code here */
71    if (sd->edje)
72      {
73         pclip = evas_object_clip_get(sd->obj);
74         if (sd->obj) evas_object_del(sd->obj);
75         sd->obj = evas_object_image_add(evas_object_evas_get(obj));
76         evas_object_image_scale_hint_set(sd->obj, EVAS_IMAGE_SCALE_HINT_STATIC);
77         evas_object_smart_member_add(sd->obj, obj);
78         evas_object_event_callback_add(sd->obj, EVAS_CALLBACK_IMAGE_PRELOADED,
79                                        _preloaded, sd);
80         evas_object_clip_set(sd->obj, pclip);
81         sd->edje = EINA_FALSE;
82      }
83    if (!sd->size)
84      evas_object_image_load_size_set(sd->obj, sd->size, sd->size);
85    evas_object_image_file_set(sd->obj, file, key);
86    sd->preloading = EINA_TRUE;
87    sd->show = EINA_TRUE;
88    evas_object_hide(sd->obj);
89    evas_object_image_preload(sd->obj, EINA_FALSE);
90    if (evas_object_image_load_error_get(sd->obj) != EVAS_LOAD_ERROR_NONE)
91      {
92         ERR("Things are going bad for '%s' (%p)", file, sd->obj);
93         return EINA_FALSE;
94      }
95    _smart_reconfigure(sd);
96    return EINA_TRUE;
97 }
98
99 Eina_Bool
100 _els_smart_icon_file_edje_set(Evas_Object *obj, const char *file, const char *part)
101 {
102    Smart_Data *sd;
103    Evas_Object *pclip;
104
105    sd = evas_object_smart_data_get(obj);
106    if (!sd) return EINA_FALSE;
107    /* smart code here */
108    if (!sd->edje)
109      {
110         pclip = evas_object_clip_get(sd->obj);
111         if (sd->obj) evas_object_del(sd->obj);
112         sd->obj = edje_object_add(evas_object_evas_get(obj));
113         evas_object_smart_member_add(sd->obj, obj);
114         if (sd->show) evas_object_show(sd->obj);
115         evas_object_clip_set(sd->obj, pclip);
116      }
117    sd->edje = EINA_TRUE;
118    if (!edje_object_file_set(sd->obj, file, part))
119      return EINA_FALSE;
120    _smart_reconfigure(sd);
121    return EINA_TRUE;
122 }
123
124 void
125 _els_smart_icon_file_get(const Evas_Object *obj, const char **file, const char **key)
126 {
127    Smart_Data *sd = evas_object_smart_data_get(obj);
128    if (!sd) return;
129    if (sd->edje)
130      edje_object_file_get(sd->obj, file, key);
131    else
132      evas_object_image_file_get(sd->obj, file, key);
133 }
134
135 void
136 _els_smart_icon_smooth_scale_set(Evas_Object *obj, Eina_Bool smooth)
137 {
138    Smart_Data *sd = evas_object_smart_data_get(obj);
139    if (!sd) return;
140    if (sd->edje)
141      return;
142    evas_object_image_smooth_scale_set(sd->obj, smooth);
143 }
144
145 Eina_Bool
146 _els_smart_icon_smooth_scale_get(const Evas_Object *obj)
147 {
148    Smart_Data *sd = evas_object_smart_data_get(obj);
149    if (!sd) return EINA_FALSE;
150    if (sd->edje)
151      return EINA_FALSE;
152    return evas_object_image_smooth_scale_get(sd->obj);
153 }
154
155 Evas_Object *
156 _els_smart_icon_object_get(const Evas_Object *obj)
157 {
158    Smart_Data *sd = evas_object_smart_data_get(obj);
159    if (!sd) return NULL;
160    return sd->obj;
161 }
162
163 void
164 _els_smart_icon_size_get(const Evas_Object *obj, int *w, int *h)
165 {
166    Smart_Data *sd;
167    int tw, th;
168    int cw, ch;
169
170    sd = evas_object_smart_data_get(obj);
171    if (!sd) return;
172    if (!strcmp(evas_object_type_get(sd->obj), "edje"))
173      edje_object_size_min_get(sd->obj, &tw, &th);
174    else
175      evas_object_image_size_get(sd->obj, &tw, &th);
176    evas_object_geometry_get(sd->obj, NULL, NULL, &cw, &ch);
177    tw = tw > cw ? tw : cw;
178    th = th > ch ? th : ch;
179    tw = ((double)tw) * sd->scale;
180    th = ((double)th) * sd->scale;
181    if (w) *w = tw;
182    if (h) *h = th;
183 }
184
185 void
186 _els_smart_icon_fill_inside_set(Evas_Object *obj, Eina_Bool fill_inside)
187 {
188    Smart_Data *sd;
189
190    sd = evas_object_smart_data_get(obj);
191    if (!sd) return;
192    if (((sd->fill_inside) && (fill_inside)) ||
193        ((!sd->fill_inside) && (!fill_inside))) return;
194    sd->fill_inside = fill_inside;
195    _smart_reconfigure(sd);
196 }
197
198 Eina_Bool
199 _els_smart_icon_fill_inside_get(const Evas_Object *obj)
200 {
201    Smart_Data *sd = evas_object_smart_data_get(obj);
202    if (!sd) return EINA_FALSE;
203    return sd->fill_inside;
204 }
205
206 void
207 _els_smart_icon_scale_up_set(Evas_Object *obj, Eina_Bool scale_up)
208 {
209    Smart_Data *sd;
210
211    sd = evas_object_smart_data_get(obj);
212    if (!sd) return;
213    if (((sd->scale_up) && (scale_up)) ||
214        ((!sd->scale_up) && (!scale_up))) return;
215    sd->scale_up = scale_up;
216    _smart_reconfigure(sd);
217 }
218
219 Eina_Bool
220 _els_smart_icon_scale_up_get(const Evas_Object *obj)
221 {
222    Smart_Data *sd; sd = evas_object_smart_data_get(obj);
223    if (!sd) return EINA_FALSE;
224    return sd->scale_up;
225 }
226
227 void
228 _els_smart_icon_scale_down_set(Evas_Object *obj, Eina_Bool scale_down)
229 {
230    Smart_Data *sd;
231
232    sd = evas_object_smart_data_get(obj);
233    if (!sd) return;
234    if (((sd->scale_down) && (scale_down)) ||
235        ((!sd->scale_down) && (!scale_down))) return;
236    sd->scale_down = scale_down;
237    _smart_reconfigure(sd);
238 }
239
240 Eina_Bool
241 _els_smart_icon_scale_down_get(const Evas_Object *obj)
242 {
243    Smart_Data *sd; sd = evas_object_smart_data_get(obj);
244    if (!sd) return EINA_FALSE;
245    return sd->scale_up;
246 }
247
248 void
249 _els_smart_icon_scale_size_set(Evas_Object *obj, int size)
250 {
251    Smart_Data *sd;
252
253    sd = evas_object_smart_data_get(obj);
254    if (!sd) return;
255    sd->size = size;
256    if (!sd->obj) return;
257    if (sd->edje)
258      return;
259    evas_object_image_load_size_set(sd->obj, sd->size, sd->size);
260 }
261
262 int
263 _els_smart_icon_scale_size_get(const Evas_Object *obj)
264 {
265    Smart_Data *sd; sd = evas_object_smart_data_get(obj);
266    if (!sd) return 0;
267    return sd->size;
268 }
269
270 void
271 _els_smart_icon_scale_set(Evas_Object *obj, double scale)
272 {
273    Smart_Data *sd = evas_object_smart_data_get(obj);
274    if (!sd) return;
275    sd->scale = scale;
276    _smart_reconfigure(sd);
277 }
278
279 double
280 _els_smart_icon_scale_get(const Evas_Object *obj)
281 {
282    Smart_Data *sd; sd = evas_object_smart_data_get(obj);
283    if (!sd) return 0.0;
284    return sd->scale;
285 }
286
287 void
288 _els_smart_icon_orient_set(Evas_Object *obj, Elm_Image_Orient orient)
289 {
290    Smart_Data   *sd;
291    Evas_Object  *tmp;
292    unsigned int *data, *data2, *to, *from;
293    int           x, y, w, hw, iw, ih;
294    const char   *file, *key;
295
296    sd = evas_object_smart_data_get(obj);
297    if (!sd) return;
298    if (sd->edje)
299      return;
300
301    switch (orient)
302      {
303       case ELM_IMAGE_FLIP_HORIZONTAL:
304          _els_smart_icon_flip_horizontal(sd);
305          return;
306       case ELM_IMAGE_FLIP_VERTICAL:
307          _els_smart_icon_flip_vertical(sd);
308          return;
309       case ELM_IMAGE_ROTATE_180_CW:
310          _els_smart_icon_rotate_180(sd);
311          return;
312       default:
313          break;
314      }
315
316    evas_object_image_size_get(sd->obj, &iw, &ih);
317    evas_object_image_file_get(sd->obj, &file, &key);
318    tmp = evas_object_image_add(evas_object_evas_get(sd->obj));
319    evas_object_image_file_set(tmp, file, key);
320    data2 = evas_object_image_data_get(tmp, EINA_FALSE);
321
322    w = ih;
323    ih = iw;
324    iw = w;
325    hw = w * ih;
326
327    evas_object_image_size_set(sd->obj, iw, ih);
328    data = evas_object_image_data_get(sd->obj, EINA_TRUE);
329    switch (orient)
330      {
331       case ELM_IMAGE_FLIP_TRANSPOSE:
332          to = data;
333          hw = -hw + 1;
334          break;
335       case ELM_IMAGE_FLIP_TRANSVERSE:
336          to = data + hw - 1;
337          w = -w;
338          hw = hw - 1;
339          break;
340       case ELM_IMAGE_ROTATE_90_CW:
341          to = data + w - 1;
342          hw = -hw - 1;
343          break;
344       case ELM_IMAGE_ROTATE_90_CCW:
345          to = data + hw - w;
346          w = -w;
347          hw = hw + 1;
348          break;
349       default:
350          ERR("unknown orient %d", orient);
351          evas_object_del(tmp);
352          evas_object_image_data_set(sd->obj, data); // give it back
353          return;
354      }
355    from = data2;
356    for (x = iw; --x >= 0;)
357      {
358         for (y = ih; --y >= 0;)
359           {
360              *to = *from;
361              from++;
362              to += w;
363           }
364         to += hw;
365      }
366    sd->orient = orient;
367    evas_object_del(tmp);
368    evas_object_image_data_set(sd->obj, data);
369    evas_object_image_data_update_add(sd->obj, 0, 0, iw, ih);
370    _smart_reconfigure(sd);
371 }
372
373 Elm_Image_Orient
374 _els_smart_icon_orient_get(const Evas_Object *obj)
375 {
376    Smart_Data *sd; sd = evas_object_smart_data_get(obj);
377    if (!sd) return 0;
378    return sd->orient;
379 }
380
381 /**
382  * Turns on editing through drag and drop and copy and paste.
383  */
384 void
385 _els_smart_icon_edit_set(Evas_Object *obj, Eina_Bool edit, Evas_Object *parent)
386 {
387    Smart_Data   *sd = evas_object_smart_data_get(obj);
388    if (!sd) return;
389
390    if (sd->edje)
391      {
392         printf("No editing edje objects yet (ever)\n");
393         return;
394      }
395
396    /* Unfortunately eina bool is not a bool, but a char */
397    if (edit == sd->edit) return;
398
399    sd->edit = edit;
400
401    if (sd->edit)
402      elm_drop_target_add(obj, ELM_SEL_FORMAT_IMAGE, _els_smart_icon_dropcb,
403                          parent);
404    else
405      elm_drop_target_del(obj);
406 }
407
408 Eina_Bool
409 _els_smart_icon_edit_get(const Evas_Object *obj)
410 {
411    Smart_Data *sd; sd = evas_object_smart_data_get(obj);
412    if (!sd) return EINA_FALSE;
413    return sd->edit;
414 }
415
416 Evas_Object *
417 _els_smart_icon_edje_get(Evas_Object *obj)
418 {
419    Smart_Data *sd = evas_object_smart_data_get(obj);
420    if (!sd) return NULL;
421    if (!sd->edje) return NULL;
422    return sd->obj;
423 }
424
425 void
426 _els_smart_icon_aspect_ratio_retained_set(Evas_Object *obj, Eina_Bool retained)
427 {
428    Smart_Data *sd;
429
430    sd = evas_object_smart_data_get(obj);
431    if (!sd) return;
432
433    retained = !!retained;
434    if (sd->aspect_ratio_retained == retained) return;
435    sd->aspect_ratio_retained = retained;
436    _smart_reconfigure(sd);
437 }
438
439 Eina_Bool
440 _els_smart_icon_aspect_ratio_retained_get(const Evas_Object *obj)
441 {
442    Smart_Data *sd;
443
444    sd = evas_object_smart_data_get(obj);
445    if (!sd) return EINA_FALSE;
446    return sd->aspect_ratio_retained;
447 }
448
449 /* local subsystem globals */
450 static void
451 _smart_reconfigure(Smart_Data *sd)
452 {
453    Evas_Coord x, y, w, h;
454
455    if (!sd->obj) return;
456
457    w = sd->w;
458    h = sd->h;
459
460    if (!strcmp(evas_object_type_get(sd->obj), "edje"))
461      {
462         x = sd->x;
463         y = sd->y;
464         evas_object_move(sd->obj, x, y);
465         evas_object_resize(sd->obj, w, h);
466      }
467    else
468      {
469         int iw = 0, ih = 0;
470
471         evas_object_image_size_get(sd->obj, &iw, &ih);
472
473         iw = ((double)iw) * sd->scale;
474         ih = ((double)ih) * sd->scale;
475
476         if (iw < 1) iw = 1;
477         if (ih < 1) ih = 1;
478
479         if (sd->aspect_ratio_retained)
480           {
481              h = ((double)ih * w) / (double)iw;
482              if (sd->fill_inside)
483                {
484                   if (h > sd->h)
485                     {
486                        h = sd->h;
487                        w = ((double)iw * h) / (double)ih;
488                     }
489                }
490              else
491                {
492                   if (h < sd->h)
493                     {
494                        h = sd->h;
495                        w = ((double)iw * h) / (double)ih;
496                     }
497                }
498           }
499         if (!sd->scale_up)
500           {
501              if (w > iw) w = iw;
502              if (h > ih) h = ih;
503           }
504         if (!sd->scale_down)
505           {
506              if (w < iw) w = iw;
507              if (h < ih) h = ih;
508           }
509         x = sd->x + ((sd->w - w) / 2);
510         y = sd->y + ((sd->h - h) / 2);
511         evas_object_move(sd->obj, x, y);
512         evas_object_image_fill_set(sd->obj, 0, 0, w, h);
513         evas_object_resize(sd->obj, w, h);
514      }
515 }
516
517 static void
518 _smart_init(void)
519 {
520    if (_e_smart) return;
521      {
522         static const Evas_Smart_Class sc =
523           {
524              "e_icon",
525              EVAS_SMART_CLASS_VERSION,
526              _smart_add,
527              _smart_del,
528              _smart_move,
529              _smart_resize,
530              _smart_show,
531              _smart_hide,
532              _smart_color_set,
533              _smart_clip_set,
534              _smart_clip_unset,
535              NULL,
536              NULL,
537              NULL,
538              NULL,
539              NULL,
540              NULL,
541              NULL
542           };
543         _e_smart = evas_smart_class_new(&sc);
544      }
545 }
546
547 static void
548 _smart_add(Evas_Object *obj)
549 {
550    Smart_Data *sd;
551
552    sd = calloc(1, sizeof(Smart_Data));
553    if (!sd) return;
554    sd->obj = evas_object_image_add(evas_object_evas_get(obj));
555    evas_object_image_scale_hint_set(sd->obj, EVAS_IMAGE_SCALE_HINT_STATIC);
556    sd->x = 0;
557    sd->y = 0;
558    sd->w = 0;
559    sd->h = 0;
560    sd->fill_inside = EINA_TRUE;
561    sd->scale_up = EINA_TRUE;
562    sd->scale_down = EINA_TRUE;
563    sd->aspect_ratio_retained = EINA_TRUE;
564    sd->size = 64;
565    sd->scale = 1.0;
566    evas_object_smart_member_add(sd->obj, obj);
567    evas_object_smart_data_set(obj, sd);
568    evas_object_event_callback_add(sd->obj, EVAS_CALLBACK_IMAGE_PRELOADED,
569                                   _preloaded, sd);
570 }
571
572 static void
573 _smart_del(Evas_Object *obj)
574 {
575    Smart_Data *sd;
576
577    sd = evas_object_smart_data_get(obj);
578    if (!sd) return;
579    evas_object_del(sd->obj);
580    free(sd);
581 }
582
583 static void
584 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
585 {
586    Smart_Data *sd;
587
588    sd = evas_object_smart_data_get(obj);
589    if (!sd) return;
590    if ((sd->x == x) && (sd->y == y)) return;
591    sd->x = x;
592    sd->y = y;
593    _smart_reconfigure(sd);
594 }
595
596 static void
597 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
598 {
599    Smart_Data *sd;
600
601    sd = evas_object_smart_data_get(obj);
602    if (!sd) return;
603    if ((sd->w == w) && (sd->h == h)) return;
604    sd->w = w;
605    sd->h = h;
606    _smart_reconfigure(sd);
607 }
608
609 static void
610 _smart_show(Evas_Object *obj)
611 {
612    Smart_Data *sd;
613
614    sd = evas_object_smart_data_get(obj);
615    if (!sd) return;
616    sd->show = EINA_TRUE;
617    if (!sd->preloading)
618      evas_object_show(sd->obj);
619 }
620
621 static void
622 _smart_hide(Evas_Object *obj)
623 {
624    Smart_Data *sd;
625
626    sd = evas_object_smart_data_get(obj);
627    if (!sd) return;
628    sd->show = EINA_FALSE;
629    evas_object_hide(sd->obj);
630 }
631
632 static void
633 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
634 {
635    Smart_Data *sd;
636
637    sd = evas_object_smart_data_get(obj);
638    if (!sd) return;
639    evas_object_color_set(sd->obj, r, g, b, a);
640 }
641
642 static void
643 _smart_clip_set(Evas_Object *obj, Evas_Object * clip)
644 {
645    Smart_Data *sd;
646
647    sd = evas_object_smart_data_get(obj);
648    if (!sd) return;
649    evas_object_clip_set(sd->obj, clip);
650 }
651
652 static void
653 _smart_clip_unset(Evas_Object *obj)
654 {
655    Smart_Data *sd;
656
657    sd = evas_object_smart_data_get(obj);
658    if (!sd) return;
659    evas_object_clip_unset(sd->obj);
660 }
661
662 static void
663 _els_smart_icon_flip_horizontal(Smart_Data *sd)
664 {
665    unsigned int   *data;
666    unsigned int   *p1, *p2, tmp;
667    int             x, y, iw, ih;
668
669    evas_object_image_size_get(sd->obj, &iw, &ih);
670    data = evas_object_image_data_get(sd->obj, EINA_TRUE);
671
672    for (y = 0; y < ih; y++)
673      {
674         p1 = data + (y * iw);
675         p2 = data + ((y + 1) * iw) - 1;
676         for (x = 0; x < (iw >> 1); x++)
677           {
678              tmp = *p1;
679              *p1 = *p2;
680              *p2 = tmp;
681              p1++;
682              p2--;
683           }
684      }
685
686    evas_object_image_data_set(sd->obj, data);
687    evas_object_image_data_update_add(sd->obj, 0, 0, iw, ih);
688    _smart_reconfigure(sd);
689 }
690
691 static void
692 _els_smart_icon_flip_vertical(Smart_Data *sd)
693 {
694    unsigned int   *data;
695    unsigned int   *p1, *p2, tmp;
696    int             x, y, iw, ih;
697
698    evas_object_image_size_get(sd->obj, &iw, &ih);
699    data = evas_object_image_data_get(sd->obj, EINA_TRUE);
700
701    for (y = 0; y < (ih >> 1); y++)
702      {
703         p1 = data + (y * iw);
704         p2 = data + ((ih - 1 - y) * iw);
705         for (x = 0; x < iw; x++)
706           {
707              tmp = *p1;
708              *p1 = *p2;
709              *p2 = tmp;
710              p1++;
711              p2++;
712           }
713      }
714
715    evas_object_image_data_set(sd->obj, data);
716    evas_object_image_data_update_add(sd->obj, 0, 0, iw, ih);
717    _smart_reconfigure(sd);
718 }
719
720 static void
721 _els_smart_icon_rotate_180(Smart_Data *sd)
722 {
723    unsigned int   *data;
724    unsigned int   *p1, *p2, tmp;
725    int             x, hw, iw, ih;
726
727    evas_object_image_size_get(sd->obj, &iw, &ih);
728    data = evas_object_image_data_get(sd->obj, 1);
729
730    hw = iw * ih;
731    x = (hw / 2);
732    p1 = data;
733    p2 = data + hw - 1;
734    for (; --x > 0;)
735      {
736         tmp = *p1;
737         *p1 = *p2;
738         *p2 = tmp;
739         p1++;
740         p2--;
741      }
742    evas_object_image_data_set(sd->obj, data);
743    evas_object_image_data_update_add(sd->obj, 0, 0, iw, ih);
744    _smart_reconfigure(sd);
745 }
746
747 static Eina_Bool
748 _els_smart_icon_dropcb(void *elmobj,Evas_Object *obj, Elm_Selection_Data *drop)
749 {
750    _els_smart_icon_file_key_set(obj, drop->data, NULL);
751    evas_object_smart_callback_call(elmobj, "drop", drop->data);
752
753    return EINA_TRUE;
754 }
755 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/