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