update for beta release
[framework/uifw/e17.git] / src / modules / conf_wallpaper2 / e_int_config_wallpaper.c
1 #include "e.h"
2 #include "e_mod_main.h"
3
4 // FIXME:
5 //   need choice after add (file, gradient, online source)
6 //   need delete select mode
7 //   need after select on delete an ok/cancel if file or "ok to remove whole online source" if online
8 //   need to make "exchange" wallpapers have a different look
9 //   bug: animated wp doesn't workon first show
10 //   need to be able to "type name to search/filter"
11
12 typedef struct _Info Info;
13 typedef struct _Smart_Data Smart_Data;
14 typedef struct _Item Item;
15
16 struct _Info
17 {
18    E_Win *win;
19    Evas_Object *bg, *preview, *mini, *button, *box, *sframe, *span;
20    char *bg_file;
21    int iw, ih;
22    Eina_List *dirs;
23    char *curdir;
24    DIR *dir;
25    Ecore_Idler *idler;
26    int scans;
27    int con_num, zone_num, desk_x, desk_y;
28    int use_theme_bg;
29    int mode;
30 };
31
32 struct _Smart_Data
33 {
34    Eina_List *items;
35    Ecore_Idle_Enterer *idle_enter;
36    Ecore_Animator *animator;
37    Ecore_Timer *seltimer;
38    Info *info;
39    Evas_Coord x, y, w, h;
40    Evas_Coord cx, cy, cw, ch;
41    Evas_Coord sx, sy;
42    int id_num;
43    int sort_num;
44    double seltime;
45    double selmove;
46    Eina_Bool selin : 1;
47    Eina_Bool selout : 1;
48    Eina_Bool jump2hi : 1;
49 };
50
51 struct _Item
52 {
53    Evas_Object *obj;
54    Evas_Coord x, y, w, h;
55    const char *file;
56    char *sort_id;
57    Evas_Object *frame, *image;
58    Eina_Bool selected : 1;
59    Eina_Bool have_thumb : 1;
60    Eina_Bool do_thumb : 1;
61    Eina_Bool remote : 1;
62    Eina_Bool theme : 1;
63    Eina_Bool visible : 1;
64    Eina_Bool hilighted : 1;
65 };
66
67 static Info *global_info = NULL;
68
69 static void _e_smart_reconfigure(Evas_Object *obj);
70 static void _e_smart_reconfigure(Evas_Object *obj);
71 static void _thumb_gen(void *data, Evas_Object *obj, void *event_info);
72 static void _item_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
73 static void _item_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
74 static int _sort_cb(const void *d1, const void *d2);
75 static void _scan(Info *info);
76
77 static void
78 _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
79 {
80    Smart_Data *sd = evas_object_smart_data_get(obj);
81
82    if (x > (sd->cw - sd->w)) x = sd->cw - sd->w;
83    if (y > (sd->ch - sd->h)) y = sd->ch - sd->h;
84    if (x < 0) x = 0;
85    if (y < 0) y = 0;
86    if ((sd->cx == x) && (sd->cy == y)) return;
87    sd->cx = x;
88    sd->cy = y;
89    _e_smart_reconfigure(obj);
90 }
91
92 static void
93 _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
94 {
95    Smart_Data *sd = evas_object_smart_data_get(obj);
96
97    if (x) *x = sd->cx;
98    if (y) *y = sd->cy;
99 }
100
101 static void
102 _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
103 {
104    Smart_Data *sd = evas_object_smart_data_get(obj);
105
106    if (x)
107      {
108         if (sd->w < sd->cw) *x = sd->cw - sd->w;
109         else *x = 0;
110      }
111    if (y)
112      {
113         if (sd->h < sd->ch) *y = sd->ch - sd->h;
114         else *y = 0;
115      }
116 }
117
118 static void
119 _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
120 {
121    Smart_Data *sd = evas_object_smart_data_get(obj);
122
123    if (w) *w = sd->cw;
124    if (h) *h = sd->ch;
125 }
126
127 static Eina_Bool
128 _e_smart_reconfigure_do(void *data)
129 {
130    Evas_Object *obj = data;
131    Smart_Data *sd = evas_object_smart_data_get(obj);
132    Eina_List *l;
133    Item *it;
134    int iw, redo = 0, changed = 0;
135    static int recursion = 0;
136    Evas_Coord x, y, xx, yy, ww, hh, mw, mh, ox, oy, dd;
137    Evas *evas;
138
139    if (!sd) return ECORE_CALLBACK_CANCEL;
140    if (sd->cx > (sd->cw - sd->w)) sd->cx = sd->cw - sd->w;
141    if (sd->cy > (sd->ch - sd->h)) sd->cy = sd->ch - sd->h;
142    if (sd->cx < 0) sd->cx = 0;
143    if (sd->cy < 0) sd->cy = 0;
144
145    iw = sd->w / 4;
146    if (iw > (120 * e_scale)) iw = (120 * e_scale);
147    else
148      {
149         if (iw < (60 * e_scale)) iw = (sd->w / 3);
150         if (iw < (60 * e_scale)) iw = (sd->w / 2);
151         if (iw < (60 * e_scale)) iw = sd->w;
152      }
153    x = 0;
154    y = 0;
155    ww = iw;
156    hh = (sd->info->ih * iw) / (sd->info->iw);
157    mw = mh = 0;
158
159    evas = evas_object_evas_get(obj);
160    EINA_LIST_FOREACH(sd->items, l, it)
161      {
162         if (x > (sd->w - ww))
163           {
164              x = 0;
165              y += hh;
166           }
167         it->x = x;
168         it->y = y;
169         it->w = ww;
170         it->h = hh;
171         if (it->selected)
172           {
173              sd->sx = it->x + (it->w / 2);
174              sd->sy = it->y + (it->h / 2);
175           }
176         if ((x + ww) > mw) mw = x + ww;
177         if ((y + hh) > mh) mh = y + hh;
178         x += ww;
179      }
180    if ((mw != sd->cw) || (mh != sd->ch))
181      {
182         sd->cw = mw;
183         sd->ch = mh;
184         if (sd->cx > (sd->cw - sd->w))
185           {
186              sd->cx = sd->cw - sd->w;
187              redo = 1;
188           }
189         if (sd->cy > (sd->ch - sd->h))
190           {
191              sd->cy = sd->ch - sd->h;
192              redo = 1;
193           }
194         if (sd->cx < 0)
195           {
196              sd->cx = 0;
197              redo = 1;
198           }
199         if (sd->cy < 0)
200           {
201              sd->cy = 0;
202              redo = 1;
203           }
204         if (redo)
205           {
206              recursion = 1;
207              _e_smart_reconfigure_do(obj);
208              recursion = 0;
209           }
210         changed = 1;
211      }
212
213    ox = 0;
214    if (sd->w > sd->cw) ox = (sd->w - sd->cw) / 2;
215    oy = 0;
216    if (sd->h > sd->ch) oy = (sd->h - sd->ch) / 2;
217
218    EINA_LIST_FOREACH(sd->items, l, it)
219      { 
220         Evas_Coord dx, dy, vw, vh;
221
222         dx = dy = 0;
223         if ((sd->sx >= 0) && (sd->selmove > 0.0)
224             
225 /*            &&
226             ((it->x + it->w) > sd->cx) &&
227             ((it->x) < (sd->cx + sd->w)) &&
228             ((it->y + it->h) > sd->cy) &&
229             ((it->y) < (sd->cy + sd->h))
230  */
231             )
232           {
233              double a, d;
234              int sum = 0;
235              char *p;
236
237              // -----0X0+++++
238              dx = (it->x + (it->w / 2)) - sd->sx;
239              dy = (it->y + (it->h / 2)) - sd->sy;
240              if (dx > 0)
241                {
242                   // |/
243                   // +--
244                   if (dy < 0)
245                     a = -atan(-(double)dy / (double)dx);
246                   // +--
247                   /* |\ */
248                   else
249                     a = atan((double)dy / (double)dx);
250                }
251              else if (dx == 0)
252                {
253                   //   |
254                   //   +
255                   if (dy < 0) a = -M_PI / 2;
256                   //   +
257                   //   |
258                   else a = M_PI / 2;
259                }
260              else
261                {
262                   //  \|
263                   // --+
264                   if (dy < 0)
265                     a = -M_PI + atan((double)dy / (double)dx);
266                   // --+
267                   //  /|
268                   else
269                     a = M_PI - atan(-(double)dy / (double)dx);
270                }
271              d = sqrt((double)(dx * dx) + (double)(dy * dy));
272
273              sum = 0;
274              if (it->file)
275                {
276                   for (p = (char *)it->file; *p; p++) sum += (int)(*p);
277                }
278              sum = (sum & 0xff) - 128;
279              a = a + ((double)sum / 1024.0);
280              xx = sd->sx - sd->cx + ox;
281              yy = sd->sy - sd->cy + oy;
282              if (xx < (sd->w / 2)) dx = sd->w - xx;
283              else dx = xx;
284              if (yy < (sd->h / 2)) dy = sd->h - yy;
285              else dy = yy;
286              dd = dx - d;
287              if (dy > dx) dd = dy - d;
288              if (dd < 0) dd = 0;
289              dy = sin(a) * sd->selmove * (dd * 0.9);
290              dx = cos(a) * sd->selmove * (dd * 0.9);
291           }
292         xx = sd->x - sd->cx + it->x + ox;
293         yy = sd->y - sd->cy + it->y + oy;
294         evas_output_viewport_get(evas, NULL, NULL, &vw, &vh);
295         if (E_INTERSECTS(xx, yy, it->w, it->h, 0, 0, vw, vh))
296           {
297              if (!it->have_thumb)
298                {
299                   if (!it->do_thumb)
300                     {
301                        e_thumb_icon_begin(it->image);
302                        it->do_thumb = EINA_TRUE;
303                     }
304                }
305              else
306                {
307                   if (!it->frame)
308                     {
309                        it->frame = edje_object_add(evas);
310                        if (it->theme)
311                          e_theme_edje_object_set(it->frame, "base/theme/widgets",
312                                                  "e/conf/wallpaper/main/mini-theme");
313                        else if (it->remote)
314                          e_theme_edje_object_set(it->frame, "base/theme/widgets",
315                                                  "e/conf/wallpaper/main/mini-remote");
316                        else
317                          e_theme_edje_object_set(it->frame, "base/theme/widgets",
318                                                  "e/conf/wallpaper/main/mini");
319                        if (it->hilighted)
320                          {
321                             edje_object_signal_emit(it->frame, "e,state,selected", "e");
322                             evas_object_raise(it->frame);
323                          }
324                        evas_object_event_callback_add(it->frame, EVAS_CALLBACK_MOUSE_DOWN,
325                                                       _item_down, it);
326                        evas_object_event_callback_add(it->frame, EVAS_CALLBACK_MOUSE_UP,
327                                                       _item_up, it);
328
329                        evas_object_smart_member_add(it->frame, obj);
330                        evas_object_clip_set(it->frame, evas_object_clip_get(obj));
331                        it->image = e_thumb_icon_add(evas);
332                        edje_object_part_swallow(it->frame, "e.swallow.content", it->image);
333                        evas_object_smart_callback_add(it->image, "e_thumb_gen", _thumb_gen, it);
334                        if (it->theme)
335                          {
336                             const char *f;
337
338                             f = e_theme_edje_file_get("base/theme/backgrounds",
339                                                       "e/desktop/background");
340                             e_thumb_icon_file_set(it->image, f, 
341                                                   "e/desktop/background");
342                          }
343                        else
344                          e_thumb_icon_file_set(it->image, it->file, 
345                                                "e/desktop/background");
346                        e_thumb_icon_size_set(it->image, sd->info->iw, 
347                                              sd->info->ih);
348                        evas_object_show(it->image);
349
350                        e_thumb_icon_begin(it->image);
351                     }
352                }
353              evas_object_move(it->frame, xx + dx, yy + dy);
354              evas_object_resize(it->frame, it->w, it->h);
355              evas_object_show(it->frame);
356              it->visible = EINA_TRUE;
357           }
358         else
359           {
360              if (it->have_thumb)
361                {
362                   if (it->do_thumb)
363                     {
364                        e_thumb_icon_end(it->image);
365                        it->do_thumb = EINA_FALSE;
366                     }
367                   evas_object_del(it->image);
368                   it->image = NULL;
369                   evas_object_del(it->frame);
370                   it->frame = NULL;
371                }
372              it->visible = EINA_FALSE;
373 /*             
374              if (it->have_thumb)
375                {
376                   if (it->do_thumb)
377                     {
378                        e_thumb_icon_end(it->image);
379                        it->do_thumb = EINA_FALSE;
380                     }
381                   evas_object_del(it->image);
382                   it->have_thumb = EINA_FALSE;
383                   it->image = e_thumb_icon_add(evas);
384                   edje_object_part_swallow(it->frame, "e.swallow.content", it->image);
385                   evas_object_smart_callback_add(it->image, "e_thumb_gen", _thumb_gen, it);
386                   if (it->theme)
387                     {
388                        const char *f = e_theme_edje_file_get("base/theme/backgrounds",
389                                                              "e/desktop/background");
390                        e_thumb_icon_file_set(it->image, f, "e/desktop/background");
391                     }
392                   else
393                     e_thumb_icon_file_set(it->image, it->file, "e/desktop/background");
394                   e_thumb_icon_size_set(it->image, sd->info->iw, sd->info->ih);
395                   evas_object_show(it->image);
396                   edje_object_signal_emit(it->frame, "e,action,thumb,ungen", "e");
397                }
398              else
399                {
400                   if (it->sort_id)
401                     {
402                        if (it->do_thumb)
403                          {
404                             e_thumb_icon_end(it->image);
405                             it->do_thumb = 0;
406                          }
407                     }
408                }
409  */
410           }
411      }
412
413    if (changed)
414      evas_object_smart_callback_call(obj, "changed", NULL);
415    if (recursion == 0) sd->idle_enter = NULL;
416    return ECORE_CALLBACK_CANCEL;
417 }
418
419 static void
420 _e_smart_reconfigure(Evas_Object *obj)
421 {
422    Smart_Data *sd = evas_object_smart_data_get(obj);
423
424    if (sd->idle_enter) return;
425    sd->idle_enter = ecore_idle_enterer_before_add(_e_smart_reconfigure_do, obj);
426 }
427
428 static void
429 _e_smart_add(Evas_Object *obj)
430 {
431    Smart_Data *sd = calloc(1, sizeof(Smart_Data));
432
433    if (!sd) return;
434
435    sd->sx = sd->sy = -1;
436    evas_object_smart_data_set(obj, sd);
437 }
438
439 static void
440 _e_smart_del(Evas_Object *obj)
441 {
442    Smart_Data *sd = evas_object_smart_data_get(obj);
443    Item *it;
444
445    if (sd->seltimer)
446      ecore_timer_del(sd->seltimer);
447    if (sd->idle_enter)
448      ecore_idle_enterer_del(sd->idle_enter);
449    if (sd->animator)
450      ecore_animator_del(sd->animator);
451    // sd->info is just referenced
452    // sd->child_obj is unused
453    EINA_LIST_FREE(sd->items, it)
454      {
455         if (it->frame) evas_object_del(it->frame);
456         if (it->image) evas_object_del(it->image);
457         if (it->file) eina_stringshare_del(it->file);
458         free(it->sort_id);
459         free(it);
460      }
461    free(sd);
462    evas_object_smart_data_set(obj, NULL);
463 }
464
465 static void
466 _e_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
467 {
468    Smart_Data *sd = evas_object_smart_data_get(obj);
469
470    sd->x = x;
471    sd->y = y;
472    _e_smart_reconfigure(obj);
473 }
474
475 static void
476 _e_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
477 {
478    Smart_Data *sd = evas_object_smart_data_get(obj);
479
480    sd->w = w;
481    sd->h = h;
482    _e_smart_reconfigure(obj);
483    evas_object_smart_callback_call(obj, "changed", NULL);
484 }
485
486 static void
487 _e_smart_show(Evas_Object *obj __UNUSED__)
488 {
489 //   Smart_Data *sd = evas_object_smart_data_get(obj);
490 //   evas_object_show(sd->child_obj);
491 }
492
493 static void
494 _e_smart_hide(Evas_Object *obj __UNUSED__)
495 {
496 //   Smart_Data *sd = evas_object_smart_data_get(obj);
497 //   evas_object_hide(sd->child_obj);
498 }
499
500 static void
501 _e_smart_color_set(Evas_Object *obj __UNUSED__, int r __UNUSED__, int g __UNUSED__, int b __UNUSED__, int a __UNUSED__)
502 {
503 //   Smart_Data *sd = evas_object_smart_data_get(obj);
504 //   evas_object_color_set(sd->child_obj, r, g, b, a);
505 }
506
507 static void
508 _e_smart_clip_set(Evas_Object *obj __UNUSED__, Evas_Object * clip __UNUSED__)
509 {
510 //   Smart_Data *sd = evas_object_smart_data_get(obj);
511 //   evas_object_clip_set(sd->child_obj, clip);
512 }
513
514 static void
515 _e_smart_clip_unset(Evas_Object *obj __UNUSED__)
516 {
517 //   Smart_Data *sd = evas_object_smart_data_get(obj);
518 //   evas_object_clip_unset(sd->child_obj);
519 }
520
521 static Evas_Object *
522 _pan_add(Evas *evas)
523 {
524    static Evas_Smart *smart = NULL;
525    static const Evas_Smart_Class sc =
526      {
527         "wp_pan",
528           EVAS_SMART_CLASS_VERSION,
529           _e_smart_add,
530           _e_smart_del,
531           _e_smart_move,
532           _e_smart_resize,
533           _e_smart_show,
534           _e_smart_hide,
535           _e_smart_color_set,
536           _e_smart_clip_set,
537           _e_smart_clip_unset,
538           NULL,
539           NULL,
540           NULL,
541           NULL, 
542           NULL, 
543           NULL, 
544           NULL
545      };
546    smart = evas_smart_class_new(&sc);
547    return evas_object_smart_add(evas, smart);
548 }
549
550 static void
551 _pan_info_set(Evas_Object *obj, Info *info)
552 {
553    Smart_Data *sd = evas_object_smart_data_get(obj);
554
555    sd->info = info;
556 }
557
558 static Eina_Bool
559 _sel_anim(void *data)
560 {
561    Evas_Object *obj = data;
562    Smart_Data *sd = evas_object_smart_data_get(obj);
563    double t = ecore_loop_time_get() - sd->seltime;
564    double len = 1.0;
565    double p = t / len;
566    double d;
567
568    if (p > 1.0) p = 1.0;
569    if (!sd->selin)
570      {
571         d = (p * 2) - 1.0;
572         if (d > 0.0)
573           {
574              d = 1.0 - d;
575              d = d * d * d;
576              d = 1.0 - d;
577           }
578         else
579           {
580              d = -1.0 - d;
581              d = d * d * d;
582              d = -1.0 - d;
583           }
584         d = (1.0 + d) / 2.0;
585         sd->selmove = d;
586      }
587    else
588      {
589         d = ((1.0 - p) * 2) - 1.0;
590         if (d > 0.0)
591           {
592              d = 1.0 - d;
593              d = d * d * d;
594              d = 1.0 - d;
595           }
596         else
597           {
598              d = -1.0 - d;
599              d = d * d * d;
600              d = -1.0 - d;
601           }
602         d = (1.0 + d) / 2.0;
603         sd->selmove = d;
604      }
605    _e_smart_reconfigure(obj);
606    if (p == 1.0)
607      {
608         if (sd->selout)
609           {
610              sd->selin = EINA_TRUE;
611              sd->selout = EINA_FALSE;
612              sd->seltime = ecore_loop_time_get();
613              return ECORE_CALLBACK_RENEW;
614           }
615         sd->selout = EINA_FALSE;
616         sd->selin = EINA_FALSE;
617         sd->animator = NULL;
618         return ECORE_CALLBACK_CANCEL;
619      }
620    return ECORE_CALLBACK_RENEW;
621 }
622
623 static Eina_Bool
624 _sel_timer(void *data)
625 {
626    Evas_Object *obj = data;
627    Smart_Data *sd = evas_object_smart_data_get(obj);
628
629    if (!sd->animator)
630      {
631         sd->seltime = ecore_time_get();
632         sd->animator = ecore_animator_add(_sel_anim, obj);
633         sd->selin = EINA_FALSE;
634      }
635    sd->seltimer = NULL;
636    return ECORE_CALLBACK_CANCEL;
637 }
638
639 static void
640 _pan_unhilight(Evas_Object *obj __UNUSED__, Item *it)
641 {
642 //   Smart_Data *sd = evas_object_smart_data_get(obj);
643    if (!it->hilighted) return;
644    it->hilighted = 0;
645    if (it->frame)
646      edje_object_signal_emit(it->frame, "e,state,unselected", "e");
647 }
648
649 static void
650 _pan_hilight(Evas_Object *obj __UNUSED__, Item *it)
651 {
652    Eina_List *l;
653    Item *it2;
654    Smart_Data *sd = evas_object_smart_data_get(obj);
655
656    if (it->hilighted) return;
657    EINA_LIST_FOREACH(sd->items, l, it2)
658      {
659         if (it2->hilighted)
660           {
661              _pan_unhilight(obj, it2);
662              break;
663           }
664      }
665    it->hilighted = 1;
666    if (it->frame)
667      {
668         edje_object_signal_emit(it->frame, "e,state,selected", "e");
669         evas_object_raise(it->frame);
670      }
671 }
672
673
674 static void
675 _pan_sel(Evas_Object *obj, Item *it)
676 {
677    Smart_Data *sd = evas_object_smart_data_get(obj);
678
679    if (sd->selmove > 0.0) return;
680    edje_object_signal_emit(it->frame, "e,state,selected", "e");
681    evas_object_raise(it->frame); 
682    if (!it->selected)
683      {
684         Eina_List *l;
685         Item *it2;
686
687         EINA_LIST_FOREACH(sd->items, l, it2)
688           {
689              if (it2->selected) it2->selected = 0;
690           }
691         it->selected = EINA_TRUE;
692         if (sd->info->bg_file) free(sd->info->bg_file);
693         evas_object_hide(sd->info->mini);
694         if (it->file)
695           {
696              char *name = NULL, *p;
697
698              sd->info->use_theme_bg = 0;
699              sd->info->bg_file = strdup(it->file);
700              edje_object_file_set(sd->info->mini, sd->info->bg_file,
701                                   "e/desktop/background");
702              p = strrchr(sd->info->bg_file, '/');
703              if (p)
704                {
705                   p++;
706                   name = strdup(p);
707                   p = strrchr(name, '.');
708                   if (p) *p = 0;
709                }
710              edje_object_part_text_set(sd->info->bg, "e.text.filename", name);
711              if (name) free(name);
712           }
713         else
714           {
715              const char *f = e_theme_edje_file_get("base/theme/backgrounds",
716                                                    "e/desktop/background");
717
718              edje_object_file_set(sd->info->mini, f, "e/desktop/background");
719              sd->info->use_theme_bg = 1;
720              sd->info->bg_file = NULL;
721              edje_object_part_text_set(sd->info->bg, "e.text.filename", 
722                                        _("Theme Wallpaper"));
723           }
724         evas_object_show(sd->info->mini);
725      }
726    if (sd->seltimer) ecore_timer_del(sd->seltimer);
727    sd->seltimer = ecore_timer_add(0.2, _sel_timer, obj);
728 }
729
730 static void
731 _pan_sel_up(Evas_Object *obj)
732 {
733    Smart_Data *sd = evas_object_smart_data_get(obj);
734
735    if (sd->selmove == 0.0) return;
736    if (!sd->animator)
737      {
738         sd->seltime = ecore_loop_time_get();
739         sd->animator = ecore_animator_add(_sel_anim, obj);
740         sd->selin = EINA_TRUE;
741      }
742    else
743      {
744         if (sd->selin) return;
745         sd->selout = EINA_TRUE;
746      }
747 }
748
749 static int
750 _sort_cb(const void *d1, const void *d2)
751 {
752    const Item *it1 = d1, *it2 = d2;
753
754    if ((!it1->sort_id) || (!it2->sort_id)) return 0;
755    return strcmp(it1->sort_id, it2->sort_id);
756 }
757
758 static void
759 _item_sort(Item *it)
760 {
761    Evas_Object *obj = it->obj;
762    Smart_Data *sd = evas_object_smart_data_get(obj);
763    int num, dosort = 0;
764
765    sd->id_num++;
766    sd->info->scans--;
767    num = eina_list_count(sd->items);
768 //   if (sd->sort_num < sd->id_num)
769 //     {
770 //        sd->sort_num = sd->id_num + 10;
771 //        dosort = 1;
772 //     }
773    if ((sd->id_num == num) || (dosort))
774      {
775         sd->items = eina_list_sort(sd->items, num, _sort_cb);
776         _e_smart_reconfigure_do(obj);
777          if (sd->jump2hi)
778           {
779              Eina_List *l;
780              Item *it2 = NULL;
781
782              EINA_LIST_FOREACH(sd->items, l, it2)
783                {
784                   if (it2->hilighted) break;
785                   it2 = NULL;
786                }
787              if (it2)
788                e_scrollframe_child_region_show(sd->info->sframe,
789                                                it2->x, it2->y, it2->w, it2->h);
790              sd->jump2hi = 1;
791           }
792      }
793    if (sd->info->scans == 0)
794      edje_object_signal_emit(sd->info->bg, "e,state,busy,off", "e");
795 }
796
797 static void
798 _thumb_gen(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
799 {
800    Item *it = data;
801
802    edje_object_signal_emit(it->frame, "e,action,thumb,gen", "e");
803    if (!it->sort_id)
804      {
805         const char *id = e_thumb_sort_id_get(it->image);
806
807         if (id)
808           {
809              it->sort_id = strdup(id);
810              _item_sort(it);
811           }
812      }
813    it->have_thumb = EINA_TRUE;
814    if (!it->visible)
815      {
816         if (it->do_thumb)
817           {
818              e_thumb_icon_end(it->image);
819              it->do_thumb = EINA_FALSE;
820           }
821         evas_object_del(it->image);
822         it->image = NULL;
823         evas_object_del(it->frame);
824         it->frame = NULL;
825      }
826 }
827
828 static void         
829 _item_down(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
830 {
831 //   Evas_Event_Mouse_Down *ev = event_info;
832 //   Item *it = data;
833 //   _pan_sel(it->obj, it);
834 }
835     
836 static void         
837 _item_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
838 {
839    Evas_Event_Mouse_Up *ev = event_info;
840    Item *it = data;
841
842    if (ev->button == 1)
843      {
844         if (!(ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD))
845           {
846              _pan_hilight(it->obj, it);
847              _pan_sel(it->obj, it);
848              // FIXME: select image!!!
849           }
850      }
851 }
852     
853 static void
854 _pan_file_add(Evas_Object *obj, const char *file, Eina_Bool remote, Eina_Bool theme)
855 {
856    Smart_Data *sd = evas_object_smart_data_get(obj);
857    Item *it = calloc(1, sizeof(Item));
858    Evas *evas;
859
860    if (!it) return;
861    evas = evas_object_evas_get(obj);
862    sd->items = eina_list_append(sd->items, it);
863    it->obj = obj;
864    it->remote = remote;
865    it->theme = theme;
866    it->file = eina_stringshare_add(file);
867    it->frame = edje_object_add(evas);
868    if (it->theme)
869      e_theme_edje_object_set(it->frame, "base/theme/widgets",
870                              "e/conf/wallpaper/main/mini-theme");
871    else if (it->remote)
872      e_theme_edje_object_set(it->frame, "base/theme/widgets",
873                              "e/conf/wallpaper/main/mini-remote");
874    else
875      e_theme_edje_object_set(it->frame, "base/theme/widgets",
876                              "e/conf/wallpaper/main/mini");
877    if (it->hilighted)
878      {
879         edje_object_signal_emit(it->frame, "e,state,selected", "e");
880         evas_object_raise(it->frame);
881      }
882    evas_object_event_callback_add(it->frame, EVAS_CALLBACK_MOUSE_DOWN,
883                                   _item_down, it);
884    evas_object_event_callback_add(it->frame, EVAS_CALLBACK_MOUSE_UP,
885                                   _item_up, it);
886
887    evas_object_smart_member_add(it->frame, obj);
888    evas_object_clip_set(it->frame, evas_object_clip_get(obj));
889    evas_object_show(it->frame);
890    it->image = e_thumb_icon_add(evas);
891    edje_object_part_swallow(it->frame, "e.swallow.content", it->image);
892    evas_object_smart_callback_add(it->image, "e_thumb_gen", _thumb_gen, it);
893    if (it->theme)
894      {
895         const char *f = e_theme_edje_file_get("base/theme/backgrounds",
896                                               "e/desktop/background");
897
898         e_thumb_icon_file_set(it->image, f, "e/desktop/background");
899      }
900    else
901      e_thumb_icon_file_set(it->image, it->file, "e/desktop/background");
902    e_thumb_icon_size_set(it->image, sd->info->iw, sd->info->ih);
903    evas_object_show(it->image);
904
905    e_thumb_icon_begin(it->image);
906    it->do_thumb = 1;
907 //   e_thumb_icon_begin(it->image);
908
909    if (it->theme)
910      {
911         if (sd->info->use_theme_bg)
912           {
913              _pan_hilight(it->obj, it);
914              edje_object_part_text_set(sd->info->bg, "e.text.filename", 
915                                        _("Theme Wallpaper"));
916           }
917      }
918    else
919      {
920         if (sd->info->bg_file)
921           {
922              int match = 0;
923
924              if (!strcmp(sd->info->bg_file, it->file)) match = 1;
925              if (!match)
926                {
927                   const char *p1, *p2;
928
929                   p1 = ecore_file_file_get(sd->info->bg_file);
930                   p2 = ecore_file_file_get(it->file);
931                   if (!strcmp(p1, p2)) match = 1;
932                }
933              if (match)
934                {
935                   char *name = NULL, *p;
936
937                   sd->jump2hi = 1;
938                   _pan_hilight(it->obj, it);
939                   p = strrchr(sd->info->bg_file, '/');
940                   if (p)
941                     {
942                        p++;
943                        name = strdup(p);
944                        p = strrchr(name, '.');
945                        if (p) *p = 0;
946                     }
947                   edje_object_part_text_set(sd->info->bg, "e.text.filename", name);
948                   if (name) free(name);
949                }
950           }
951      }
952    _e_smart_reconfigure(obj);
953 }
954
955 ////////
956
957 static void
958 _resize(E_Win *wn)
959 {
960    Info *info = wn->data;
961
962    evas_object_resize(info->bg, wn->w, wn->h);
963 }
964
965 static void
966 _delete(E_Win *wn __UNUSED__)
967 {
968    wp_conf_hide();
969 }
970
971 static void
972 _bg_clicked(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
973 {
974    Info *info = data;
975
976    _pan_sel_up(info->span);
977 }
978
979 static void
980 _ok(void *data, void *data2 __UNUSED__)
981 {
982    Info *info = data;
983
984    if (info->mode == 0)
985      {
986         /* all desktops */
987         while (e_config->desktop_backgrounds)
988           {
989              E_Config_Desktop_Background *cfbg;
990
991              cfbg = e_config->desktop_backgrounds->data;
992              e_bg_del(cfbg->container, cfbg->zone, cfbg->desk_x, cfbg->desk_y);
993           }
994         if ((info->use_theme_bg) || (!info->bg_file))
995           e_bg_default_set(NULL);
996         else
997           e_bg_default_set(info->bg_file);
998      }
999    else if (info->mode == 1)
1000      {
1001         /* specific desk */
1002         e_bg_del(info->con_num, info->zone_num, info->desk_x, info->desk_y);
1003         e_bg_add(info->con_num, info->zone_num, info->desk_x, info->desk_y, 
1004                  info->bg_file);
1005      }
1006    else
1007      {
1008         Eina_List *dlist = NULL, *l;
1009         E_Config_Desktop_Background *cfbg;
1010
1011         /* this screen */
1012         EINA_LIST_FOREACH(e_config->desktop_backgrounds, l, cfbg)
1013           {
1014              if (cfbg->zone == info->zone_num)
1015                dlist = eina_list_append(dlist, cfbg);
1016           }
1017         EINA_LIST_FREE(dlist, cfbg)
1018           e_bg_del(cfbg->container, cfbg->zone, cfbg->desk_x, cfbg->desk_y);
1019         e_bg_add(info->con_num, info->zone_num, -1, -1, info->bg_file);
1020      }
1021    e_bg_update();
1022    e_config_save_queue();
1023    wp_conf_hide();
1024 }
1025
1026 static void
1027 _wp_add(void *data, void *data2 __UNUSED__)
1028 {
1029    Info *info = data;
1030
1031    edje_object_signal_emit(info->bg, "e,action,panel,hide", "e");
1032 }
1033
1034 static void
1035 _wp_delete(void *data, void *data2 __UNUSED__)
1036 {
1037    Info *info = data;
1038
1039    edje_object_signal_emit(info->bg, "e,action,panel,hide", "e");
1040 }
1041
1042 static void
1043 _wp_changed(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1044 {
1045    Info *info = data;
1046
1047    edje_object_signal_emit(info->bg, "e,action,panel,hide", "e");
1048 }
1049
1050 static Eina_Bool
1051 _idler(void *data)
1052 {
1053    struct dirent *dp;
1054    char buf[PATH_MAX];
1055    Info *info = data;
1056
1057    if (!info->dir)
1058      {
1059         info->idler = NULL;
1060         return ECORE_CALLBACK_CANCEL;
1061      }
1062    dp = readdir(info->dir);
1063    if (!dp)
1064      {
1065         free(info->curdir);
1066         info->curdir = NULL;
1067         closedir(info->dir);
1068         info->dir = NULL;
1069         info->idler = NULL;
1070         _scan(info);
1071         return ECORE_CALLBACK_CANCEL;
1072      }
1073    if ((!strcmp(dp->d_name, ".")) || (!strcmp(dp->d_name, "..")))
1074      return ECORE_CALLBACK_RENEW;
1075    if (dp->d_name[0] == '.')
1076      return ECORE_CALLBACK_RENEW;
1077    snprintf(buf, sizeof(buf), "%s/%s", info->curdir, dp->d_name);
1078    if (ecore_file_is_dir(buf))
1079      {
1080         info->dirs = eina_list_append(info->dirs, strdup(buf));
1081         return ECORE_CALLBACK_RENEW;
1082      }
1083    info->scans++;
1084    _pan_file_add(info->span, buf, 0, 0);
1085
1086    e_util_wakeup();
1087    return ECORE_CALLBACK_RENEW;
1088 }
1089
1090 static void
1091 _scan(Info *info)
1092 {
1093    if (info->dirs)
1094      {
1095         if (info->scans <= 0)
1096           {
1097              info->scans = 0;
1098              edje_object_signal_emit(info->bg, "e,state,busy,on", "e");
1099              edje_object_part_text_set(info->bg, "e.text.busy_label", 
1100                                        _("Loading files..."));
1101           }
1102         if (info->curdir) free(info->curdir);
1103         info->curdir = info->dirs->data;
1104         info->dirs = eina_list_remove_list(info->dirs, info->dirs);
1105         if (!info->dir) info->dir = opendir(info->curdir);
1106         info->idler = ecore_idler_add(_idler, info);
1107      }
1108 }
1109
1110 Info *
1111 wp_browser_new(E_Container *con)
1112 {
1113    Info *info;
1114    E_Win *win;
1115    E_Zone *zone;
1116    E_Desk *desk;
1117    const E_Config_Desktop_Background *cfbg;
1118    Evas_Coord mw, mh;
1119    Evas_Object *o, *o2, *ob;
1120    E_Radio_Group *rg;
1121    char buf[PATH_MAX];   
1122
1123    info = calloc(1, sizeof(Info));
1124    if (!info) return NULL;
1125
1126    zone = e_util_zone_current_get(con->manager);
1127    desk = e_desk_current_get(zone);
1128    info->con_num = con->num;
1129    info->zone_num = zone->id;
1130    info->desk_x = desk->x;
1131    info->desk_y = desk->y;
1132    info->mode = 0;
1133    cfbg = e_bg_config_get(con->num, zone->id, desk->x, desk->y);
1134    if (cfbg)
1135      {
1136         if ((cfbg->container >= 0) && (cfbg->zone >= 0))
1137           {
1138              if ((cfbg->desk_x >= 0) && (cfbg->desk_y >= 0))
1139                info->mode = 1;
1140              else
1141                info->mode = 2;
1142           }
1143         info->bg_file = strdup(cfbg->file);
1144      }
1145    if ((!info->bg_file) && (e_config->desktop_default_background))
1146      info->bg_file = strdup(e_config->desktop_default_background);
1147    else
1148      info->use_theme_bg = 1;
1149
1150    info->iw = (120 * e_scale);
1151    info->ih = (zone->h * info->iw) / (zone->w);
1152
1153    win = e_win_new(con);
1154    if (!win)
1155      {
1156         free(info);
1157         info = NULL;
1158         return NULL;
1159      }
1160    info->win = win;
1161    win->data = info;
1162
1163    e_user_dir_concat_static(buf, "backgrounds");
1164    info->dirs = eina_list_append(info->dirs, strdup(buf));
1165    e_prefix_data_concat_static(buf, "data/backgrounds");
1166    info->dirs = eina_list_append(info->dirs, strdup(buf));
1167
1168    e_win_title_set(win, _("Wallpaper Settings"));
1169    e_win_name_class_set(win, "E", "_config::appearance/wallpaper2");
1170    e_win_resize_callback_set(win, _resize);
1171    e_win_delete_callback_set(win, _delete);
1172
1173    // bg + container
1174    info->bg = edje_object_add(info->win->evas);
1175    e_theme_edje_object_set(info->bg, "base/theme/widgets",
1176                            "e/conf/wallpaper/main/window");
1177    edje_object_signal_callback_add(info->bg, "e,action,click", "e",
1178                                    _bg_clicked, info);
1179
1180    // ok button
1181    info->box = e_widget_list_add(info->win->evas, 1, 1);
1182
1183    info->button = e_widget_button_add(info->win->evas, _("OK"), NULL, 
1184                                       _ok, info, NULL);
1185    evas_object_show(info->button);
1186    e_widget_list_object_append(info->box, info->button, 1, 0, 0.5);
1187
1188    e_widget_size_min_get(info->box, &mw, &mh);
1189    edje_extern_object_min_size_set(info->box, mw, mh);
1190    edje_object_part_swallow(info->bg, "e.swallow.buttons", info->box);
1191    evas_object_show(info->box);
1192
1193    // preview
1194    info->preview = e_livethumb_add(info->win->evas);
1195    e_livethumb_vsize_set(info->preview, zone->w, zone->h);
1196    edje_extern_object_aspect_set(info->preview, EDJE_ASPECT_CONTROL_NEITHER, 
1197                                  zone->w, zone->h);
1198    edje_object_part_swallow(info->bg, "e.swallow.preview", info->preview);
1199    evas_object_show(info->preview);
1200
1201    info->mini = edje_object_add(e_livethumb_evas_get(info->preview));
1202    e_livethumb_thumb_set(info->preview, info->mini);
1203    evas_object_show(info->mini);
1204    if (info->bg_file)
1205      edje_object_file_set(info->mini, info->bg_file, "e/desktop/background");
1206    else
1207      {
1208         const char *f = e_theme_edje_file_get("base/theme/backgrounds",
1209                                               "e/desktop/background");
1210
1211         edje_object_file_set(info->mini, f, "e/desktop/background");
1212      }
1213
1214    // scrolled thumbs
1215    info->span = _pan_add(info->win->evas);
1216    _pan_info_set(info->span, info);
1217
1218    // the scrollframe holding the scrolled thumbs
1219    info->sframe = e_scrollframe_add(info->win->evas);
1220    e_scrollframe_custom_theme_set(info->sframe, "base/theme/widgets",
1221                                   "e/conf/wallpaper/main/scrollframe");
1222    e_scrollframe_extern_pan_set(info->sframe, info->span,
1223                                 _pan_set, _pan_get, _pan_max_get, 
1224                                 _pan_child_size_get);
1225    edje_object_part_swallow(info->bg, "e.swallow.list", info->sframe);
1226    evas_object_show(info->sframe);
1227    evas_object_show(info->span);
1228
1229    ob = e_widget_list_add(info->win->evas, 0, 1);
1230
1231    o = e_widget_list_add(info->win->evas, 1, 0);
1232
1233    rg = e_widget_radio_group_new(&(info->mode));
1234    o2 = e_widget_radio_add(info->win->evas, _("All Desktops"), 0, rg);
1235    evas_object_smart_callback_add(o2, "changed", _wp_changed, info);
1236    e_widget_list_object_append(o, o2, 1, 0, 0.5);
1237    e_widget_disabled_set(o2, (e_util_container_desk_count_get(con) < 2));
1238    evas_object_show(o2);
1239
1240    o2 = e_widget_radio_add(info->win->evas, _("This Desktop"), 1, rg);
1241    evas_object_smart_callback_add(o2, "changed", _wp_changed, info);
1242    e_widget_list_object_append(o, o2, 1, 0, 0.5);
1243    evas_object_show(o2);
1244
1245    o2 = e_widget_radio_add(info->win->evas, _("This Screen"), 2, rg);
1246    evas_object_smart_callback_add(o2, "changed", _wp_changed, info);
1247    e_widget_list_object_append(o, o2, 1, 0, 0.5);
1248    if (!(e_util_container_zone_number_get(0, 1) || 
1249          (e_util_container_zone_number_get(1, 0))))
1250      e_widget_disabled_set(o2, EINA_TRUE);
1251    evas_object_show(o2);
1252
1253    e_widget_list_object_append(ob, o, 1, 0, 0.5);
1254    evas_object_show(o);
1255
1256    o = e_widget_list_add(info->win->evas, 1, 0);
1257
1258    o2 =  e_widget_button_add(info->win->evas, _("Add"), NULL, 
1259                              _wp_add, info, NULL);
1260    e_widget_list_object_append(o, o2, 1, 0, 0.5);
1261    evas_object_show(o2);
1262
1263    o2 =  e_widget_button_add(info->win->evas, _("Delete"), NULL, 
1264                              _wp_delete, info, NULL);
1265    e_widget_list_object_append(o, o2, 1, 0, 0.5);
1266    evas_object_show(o2);
1267
1268    e_widget_list_object_append(ob, o, 1, 0, 0.5);
1269    evas_object_show(o);
1270
1271    e_widget_size_min_get(ob, &mw, &mh);
1272    edje_extern_object_min_size_set(ob, mw, mh);
1273    edje_object_part_swallow(info->bg, "e.swallow.extras", ob);
1274    evas_object_show(ob);
1275
1276    // min size calc
1277    edje_object_size_min_calc(info->bg, &mw, &mh);
1278    e_win_size_min_set(win, mw, mh);
1279    if ((zone->w / 4) > mw) mw = (zone->w / 4);
1280    if ((zone->h / 4) > mh) mh = (zone->h / 4);
1281    e_win_resize(win, mw, mh);
1282    e_win_centered_set(win, 1);
1283    e_win_show(win);
1284    e_win_border_icon_set(win, "preferences-desktop-wallpaper");
1285
1286    evas_object_resize(info->bg, info->win->w, info->win->h);
1287    evas_object_show(info->bg);
1288
1289    // add theme bg
1290    _pan_file_add(info->span, NULL, 0, 1);
1291
1292    _scan(info);
1293    return info;
1294 }
1295
1296 void
1297 wp_broser_free(Info *info)
1298 {
1299    char *s;
1300
1301    if (!info) return;
1302    e_object_del(E_OBJECT(info->win));
1303    if (info->dir) closedir(info->dir);
1304    free(info->bg_file);
1305    free(info->curdir);
1306    EINA_LIST_FREE(info->dirs, s) 
1307      free(s);
1308    if (info->idler) ecore_idler_del(info->idler);
1309    // del other stuff
1310    free(info);
1311    info = NULL;
1312 }
1313
1314 E_Config_Dialog *
1315 wp_conf_show(E_Container *con, const char *params __UNUSED__)
1316 {
1317    if (global_info)
1318      {
1319         e_win_show(global_info->win);
1320         e_win_raise(global_info->win);
1321      }
1322    global_info = wp_browser_new(con);
1323
1324    return NULL;
1325 }
1326
1327 void
1328 wp_conf_hide(void)
1329 {
1330    if (global_info)
1331      {
1332         wp_broser_free(global_info);
1333         global_info = NULL;
1334      }
1335 }