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