elementary - fileselecto, actionslider, anchorview, fileselector_button, anchorblock...
[framework/uifw/elementary.git] / src / lib / elc_fileselector_button.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup File_Selector_Button File Selector Button
6  *
7  * A button that, when clicked, creates an Elementary window (or inner
8  * window) with an Elementary File Selector within. When a file is
9  * chosen, the (inner) window is closed and the selected file is
10  * exposed as an evas_object_smart_callback_call() of the button.
11  */
12
13 typedef struct _Widget_Data Widget_Data;
14
15 struct _Widget_Data
16 {
17    Evas_Object *self, *btn, *fs, *fsw;
18    const char  *window_title;
19    Evas_Coord   w, h;
20    struct
21      {
22         const char *path;
23         Eina_Bool   expandable : 1;
24         Eina_Bool   folder_only : 1;
25         Eina_Bool   is_save : 1;
26      } fsd;
27    Eina_Bool inwin_mode : 1;
28 };
29
30 #define DEFAULT_WINDOW_TITLE "Select a file"
31
32 static const char *widtype = NULL;
33
34 static void _del_hook(Evas_Object *obj);
35 static void _theme_hook(Evas_Object *obj);
36 static void _disable_hook(Evas_Object *obj);
37 static void _sizing_eval(Evas_Object *obj);
38 static void _changed_size_hints(void        *data,
39                                 Evas        *e,
40                                 Evas_Object *obj,
41                                 void        *event_info);
42 static void _on_focus_hook(void        *data,
43                            Evas_Object *obj);
44 static void _selection_done(void        *data,
45                             Evas_Object *obj,
46                             void        *event_info);
47 static void _activate(Widget_Data *wd);
48
49 static const char SIG_FILE_CHOSEN[] = "file,chosen";
50 static const Evas_Smart_Cb_Description _signals[] = {
51        {SIG_FILE_CHOSEN, "s"},
52        {NULL, NULL}
53 };
54
55 static void
56 _del_hook(Evas_Object *obj)
57 {
58    Evas_Object *win;
59    Widget_Data *wd;
60
61    wd = elm_widget_data_get(obj);
62    if (!wd) return;
63
64    if (wd->window_title) eina_stringshare_del(wd->window_title);
65    if (wd->fsd.path) eina_stringshare_del(wd->fsd.path);
66    if (wd->fs)
67      {
68         win = evas_object_data_del(obj, "win");
69         evas_object_del(win);
70      }
71    free(wd);
72 }
73
74 static void
75 _on_focus_hook(void *data   __UNUSED__,
76                Evas_Object *obj)
77 {
78    Widget_Data *wd = elm_widget_data_get(obj);
79    if (!wd) return;
80    if (elm_widget_focus_get(obj))
81      elm_widget_focus_steal(wd->btn);
82 }
83
84 static void
85 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
86 {
87    Widget_Data *wd = elm_widget_data_get(obj);
88    if (!wd) return;
89    elm_widget_mirrored_set(wd->btn, rtl);
90    elm_widget_mirrored_set(wd->fs, rtl);
91 }
92
93 static void
94 _theme_hook(Evas_Object *obj)
95 {
96    Widget_Data *wd = elm_widget_data_get(obj);
97    char buf[4096];
98    if (!wd) return;
99    _elm_widget_mirrored_reload(obj);
100    _mirrored_set(obj, elm_widget_mirrored_get(obj));
101
102    snprintf(buf, sizeof(buf), "fileselector_button/%s",
103             elm_widget_style_get(obj));
104    elm_object_style_set(wd->btn, buf);
105    _sizing_eval(obj);
106 }
107
108 static void
109 _disable_hook(Evas_Object *obj)
110 {
111    Widget_Data *wd = elm_widget_data_get(obj);
112    if (!wd) return;
113    elm_widget_disabled_set(wd->btn, elm_widget_disabled_get(obj));
114 }
115
116 static void
117 _sizing_eval(Evas_Object *obj)
118 {
119    Widget_Data *wd = elm_widget_data_get(obj);
120    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
121    if (!wd) return;
122    evas_object_size_hint_min_get(wd->btn, &minw, &minh);
123    evas_object_size_hint_max_get(wd->btn, &maxw, &maxh);
124    evas_object_size_hint_min_set(obj, minw, minh);
125    evas_object_size_hint_max_set(obj, maxw, maxh);
126 }
127
128 static void
129 _changed_size_hints(void            *data,
130                     Evas *e          __UNUSED__,
131                     Evas_Object *obj __UNUSED__,
132                     void *event_info __UNUSED__)
133 {
134    Widget_Data *wd = elm_widget_data_get(data);
135    if (!wd) return;
136    _sizing_eval(data);
137 }
138
139 static void
140 _activate_hook(Evas_Object *obj)
141 {
142    Widget_Data *wd;
143    wd = elm_widget_data_get(obj);
144    if (!wd) return;
145    _activate(wd);
146 }
147
148 static void
149 _button_clicked(void            *data,
150                 Evas_Object *obj __UNUSED__,
151                 void *event_info __UNUSED__)
152 {
153    _activate(data);
154 }
155
156 static Evas_Object *
157 _parent_win_get(Evas_Object *obj)
158 {
159    while ((obj) && (strcmp(elm_widget_type_get(obj), "win")))
160      obj = elm_object_parent_widget_get(obj);
161
162    return obj;
163 }
164
165 static Evas_Object *
166 _new_window_add(Widget_Data *wd)
167 {
168    Evas_Object *win, *bg;
169
170    win = elm_win_add(NULL, "fileselector_button", ELM_WIN_DIALOG_BASIC);
171    elm_win_title_set(win, wd->window_title);
172    elm_win_autodel_set(win, EINA_TRUE);
173
174    bg = elm_bg_add(win);
175    elm_win_resize_object_add(win, bg);
176    evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
177    evas_object_show(bg);
178
179    evas_object_resize(win, wd->w, wd->h);
180    return win;
181 }
182
183 static void
184 _activate(Widget_Data *wd)
185 {
186    Eina_Bool is_inwin = EINA_FALSE;
187
188    if (wd->fs) return;
189
190    if (wd->inwin_mode)
191      {
192         wd->fsw = _parent_win_get(wd->self);
193
194         if (!wd->fsw)
195           wd->fsw = _new_window_add(wd);
196         else
197           {
198              wd->fsw = elm_win_inwin_add(wd->fsw);
199              is_inwin = EINA_TRUE;
200           }
201      }
202    else
203      wd->fsw = _new_window_add(wd);
204
205    wd->fs = elm_fileselector_add(wd->fsw);
206    elm_widget_mirrored_set(wd->fs, elm_widget_mirrored_get(wd->self));
207    elm_widget_mirrored_automatic_set(wd->fs, EINA_FALSE);
208    elm_fileselector_expandable_set(wd->fs, wd->fsd.expandable);
209    elm_fileselector_folder_only_set(wd->fs, wd->fsd.folder_only);
210    elm_fileselector_is_save_set(wd->fs, wd->fsd.is_save);
211    elm_fileselector_selected_set(wd->fs, wd->fsd.path);
212    evas_object_size_hint_weight_set(wd->fs, EVAS_HINT_EXPAND,
213                                     EVAS_HINT_EXPAND);
214    evas_object_size_hint_align_set(wd->fs, EVAS_HINT_FILL, EVAS_HINT_FILL);
215    evas_object_smart_callback_add(wd->fs, "done", _selection_done, wd);
216    evas_object_show(wd->fs);
217
218    if (is_inwin)
219      {
220         elm_win_inwin_content_set(wd->fsw, wd->fs);
221         elm_win_inwin_activate(wd->fsw);
222      }
223    else
224      {
225         elm_win_resize_object_add(wd->fsw, wd->fs);
226         evas_object_show(wd->fsw);
227      }
228 }
229
230 static void
231 _selection_done(void            *data,
232                 Evas_Object *obj __UNUSED__,
233                 void            *event_info)
234 {
235    const char *file = event_info;
236    Widget_Data *wd = data;
237    Evas_Object *del;
238    if (!wd) return;
239
240    if (file) eina_stringshare_replace(&wd->fsd.path, file);
241
242    del = wd->fsw;
243    wd->fs = NULL;
244    wd->fsw = NULL;
245    evas_object_del(del);
246
247    evas_object_smart_callback_call(wd->self, SIG_FILE_CHOSEN,
248                                    (void *)wd->fsd.path);
249 }
250
251 /**
252  * Add a new file selector button into the parent object.
253  *
254  * @param parent The parent object
255  * @return The new object or NULL if it cannot be created
256  *
257  * @ingroup File_Selector_Button
258  */
259 EAPI Evas_Object *
260 elm_fileselector_button_add(Evas_Object *parent)
261 {
262    Evas_Object *obj;
263    Evas *e;
264    Widget_Data *wd;
265
266    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
267
268    ELM_SET_WIDTYPE(widtype, "fileselector_button");
269    elm_widget_type_set(obj, "fileselector_button");
270    elm_widget_sub_object_add(parent, obj);
271    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
272    elm_widget_data_set(obj, wd);
273    elm_widget_del_hook_set(obj, _del_hook);
274    elm_widget_theme_hook_set(obj, _theme_hook);
275    elm_widget_disable_hook_set(obj, _disable_hook);
276    elm_widget_can_focus_set(obj, EINA_TRUE);
277    elm_widget_activate_hook_set(obj, _activate_hook);
278
279    wd->self = obj;
280    wd->window_title = eina_stringshare_add(DEFAULT_WINDOW_TITLE);
281    if (getenv("HOME")) wd->fsd.path = eina_stringshare_add(getenv("HOME"));
282    else wd->fsd.path = eina_stringshare_add("/");
283    wd->fsd.expandable = _elm_config->fileselector_expand_enable;
284    wd->inwin_mode = _elm_config->inwin_dialogs_enable;
285    wd->w = 400;
286    wd->h = 400;
287
288    wd->btn = elm_button_add(parent);
289    elm_widget_mirrored_automatic_set(wd->btn, EINA_FALSE);
290    elm_widget_resize_object_set(obj, wd->btn);
291    evas_object_event_callback_add(wd->btn, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
292                                   _changed_size_hints, obj);
293    evas_object_smart_callback_add(wd->btn, "clicked", _button_clicked, wd);
294    elm_widget_sub_object_add(obj, wd->btn);
295
296    _theme_hook(obj);
297    evas_object_smart_callbacks_descriptions_set(obj, _signals);
298    return obj;
299 }
300
301 /**
302  * Set the label used in the file selector button.
303  *
304  * @param obj The button object
305  * @param label The text label text to be displayed on the button
306  *
307  * @ingroup File_Selector_Button
308  */
309 EAPI void
310 elm_fileselector_button_label_set(Evas_Object *obj,
311                                   const char  *label)
312 {
313    ELM_CHECK_WIDTYPE(obj, widtype);
314    Widget_Data *wd = elm_widget_data_get(obj);
315    if (!wd) return;
316    elm_button_label_set(wd->btn, label);
317 }
318
319 /**
320  * Get the label used in the file selector button.
321  *
322  * @param obj The button object
323  * @return The button label
324  *
325  * @ingroup File_Selector_Button
326  */
327 EAPI const char *
328 elm_fileselector_button_label_get(const Evas_Object *obj)
329 {
330    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
331    Widget_Data *wd = elm_widget_data_get(obj);
332    if (!wd) return NULL;
333    return elm_button_label_get(wd->btn);
334 }
335
336 /**
337  * Set the title of the file selector button's window.
338  *
339  * @param obj The button object
340  * @param title The title string
341  *
342  * Note that it will only take any effect if the fileselector button
343  * not at "inwin mode".
344  *
345  * @ingroup File_Selector_Button
346  */
347 EAPI void
348 elm_fileselector_button_window_title_set(Evas_Object *obj,
349                                          const char  *title)
350 {
351    ELM_CHECK_WIDTYPE(obj, widtype);
352    Widget_Data *wd = elm_widget_data_get(obj);
353
354    if (!wd) return;
355    eina_stringshare_replace(&wd->window_title, title);
356
357    if (wd->fsw)
358      elm_win_title_set(wd->fsw, wd->window_title);
359 }
360
361 /**
362  * Get the title of the file selector button's window.
363  *
364  * @param obj The button object
365  * @return Title of the file selector button's window
366  *
367  * @ingroup File_Selector_Button
368  */
369 EAPI const char *
370 elm_fileselector_button_window_title_get(const Evas_Object *obj)
371 {
372    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
373    Widget_Data *wd = elm_widget_data_get(obj);
374
375    if (!wd) return NULL;
376    return wd->window_title;
377 }
378
379 /**
380  * Set the size of the file selector button's window.
381  *
382  * @param obj The button object
383  * @param width The width
384  * @param height The height
385  *
386  * Note that it will only take any effect if the fileselector button not at
387  * "inwin mode". Default size for the window (when applicable) is 400x400.
388  *
389  * @ingroup File_Selector_Button
390  */
391 EAPI void
392 elm_fileselector_button_window_size_set(Evas_Object *obj,
393                                         Evas_Coord   width,
394                                         Evas_Coord   height)
395 {
396    ELM_CHECK_WIDTYPE(obj, widtype);
397    Widget_Data *wd = elm_widget_data_get(obj);
398
399    if (!wd) return;
400    wd->w = width;
401    wd->h = height;
402
403    if (wd->fsw)
404      evas_object_resize(wd->fsw, wd->w, wd->h);
405 }
406
407 /**
408  * Get the size of the file selector button's window.
409  *
410  * @param obj The button object
411  * @param width Pointer into which to store the width value
412  * @param height Pointer into which to store the height value
413  *
414  * @ingroup File_Selector_Button
415  */
416 EAPI void
417 elm_fileselector_button_window_size_get(const Evas_Object *obj,
418                                         Evas_Coord        *width,
419                                         Evas_Coord        *height)
420 {
421    ELM_CHECK_WIDTYPE(obj, widtype);
422    Widget_Data *wd = elm_widget_data_get(obj);
423
424    if (!wd) return;
425    if (width) *width = wd->w;
426    if (height) *height = wd->h;
427 }
428
429 /**
430  * Set the starting path of the file selector button's window.
431  *
432  * @param obj The button object
433  * @param path The path string
434  *
435  * It must be a <b>directory</b> path.
436  * Default path is "HOME" environment variable's value.
437  *
438  * @ingroup File_Selector_Button
439  */
440 EAPI void
441 elm_fileselector_button_path_set(Evas_Object *obj,
442                                  const char  *path)
443 {
444    ELM_CHECK_WIDTYPE(obj, widtype);
445    Widget_Data *wd = elm_widget_data_get(obj);
446
447    if (!wd) return;
448    eina_stringshare_replace(&wd->fsd.path, path);
449
450    if (wd->fs)
451      elm_fileselector_selected_set(wd->fs, wd->fsd.path);
452 }
453
454 /**
455  * Get the <b>last</b> path of the file selector button's window.
456  *
457  * @param obj The button object
458  *
459  * @ingroup File_Selector_Button
460  */
461 EAPI const char *
462 elm_fileselector_button_path_get(const Evas_Object *obj)
463 {
464    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
465    Widget_Data *wd = elm_widget_data_get(obj);
466    if (!wd) return NULL;
467    return wd->fsd.path;
468 }
469
470 /**
471  * Set whether the button's file selector is to present itself as an
472  * Elementary Generic List (which will expand its entries for nested
473  * directories) or as canonical list, which will be rendered again
474  * with the contents of each selected directory.
475  *
476  * @param obj The button object
477  * @param value The expandable flag
478  *
479  * @ingroup File_Selector_Button
480  */
481 EAPI void
482 elm_fileselector_button_expandable_set(Evas_Object *obj,
483                                        Eina_Bool    value)
484 {
485    ELM_CHECK_WIDTYPE(obj, widtype);
486    Widget_Data *wd = elm_widget_data_get(obj);
487
488    if (!wd) return;
489    wd->fsd.expandable = value;
490
491    if (wd->fs)
492      elm_fileselector_expandable_set(wd->fs, wd->fsd.expandable);
493 }
494
495 /**
496  * Get the button's file selector expandable flag.
497  *
498  * @param obj The button object
499  * @return value The expandable flag
500  *
501  * @ingroup File_Selector_Button
502  */
503 EAPI Eina_Bool
504 elm_fileselector_button_expandable_get(const Evas_Object *obj)
505 {
506    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
507    Widget_Data *wd = elm_widget_data_get(obj);
508
509    if (!wd) return EINA_FALSE;
510    return wd->fsd.expandable;
511 }
512
513 /**
514  * Set whether the button's file selector list is to display folders
515  * only or the directory contents, as well.
516  *
517  * @param obj The button object
518  * @param value The "folder only" flag
519  *
520  * @ingroup File_Selector_Button
521  */
522 EAPI void
523 elm_fileselector_button_folder_only_set(Evas_Object *obj,
524                                         Eina_Bool    value)
525 {
526    ELM_CHECK_WIDTYPE(obj, widtype);
527    Widget_Data *wd = elm_widget_data_get(obj);
528
529    if (!wd) return;
530    wd->fsd.folder_only = value;
531
532    if (wd->fs)
533      elm_fileselector_folder_only_set(wd->fs, wd->fsd.folder_only);
534 }
535
536 /**
537  * Get the button's file selector "folder only" flag.
538  *
539  * @param obj The button object
540  * @return value The "folder only" flag
541  *
542  * @ingroup File_Selector_Button
543  */
544 EAPI Eina_Bool
545 elm_fileselector_button_folder_only_get(const Evas_Object *obj)
546 {
547    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
548    Widget_Data *wd = elm_widget_data_get(obj);
549
550    if (!wd) return EINA_FALSE;
551    return wd->fsd.folder_only;
552 }
553
554 /**
555  * Set whether the button's file selector has an editable text entry
556  * which will hold its current selection.
557  *
558  * @param obj The button object
559  * @param value The "is save" flag
560  *
561  * @ingroup File_Selector_Button
562  */
563 EAPI void
564 elm_fileselector_button_is_save_set(Evas_Object *obj,
565                                     Eina_Bool    value)
566 {
567    ELM_CHECK_WIDTYPE(obj, widtype);
568    Widget_Data *wd = elm_widget_data_get(obj);
569
570    if (!wd) return;
571    wd->fsd.is_save = value;
572
573    if (wd->fs)
574      elm_fileselector_is_save_set(wd->fs, wd->fsd.is_save);
575 }
576
577 /**
578  * Get the button's file selector "is save" flag.
579  *
580  * @param obj The button object
581  * @return value The "is save" flag
582  *
583  * @ingroup File_Selector_Button
584  */
585 EAPI Eina_Bool
586 elm_fileselector_button_is_save_get(const Evas_Object *obj)
587 {
588    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
589    Widget_Data *wd = elm_widget_data_get(obj);
590
591    if (!wd) return EINA_FALSE;
592    return wd->fsd.is_save;
593 }
594
595 /**
596  * Set whether the button's file selector will raise an Elementary
597  * Inner Window, instead of a dedicated Elementary Window. By default,
598  * it won't.
599  *
600  * @param obj The button object
601  * @param value The "inwin mode" flag
602  *
603  * @ingroup File_Selector_Button
604  */
605 EAPI void
606 elm_fileselector_button_inwin_mode_set(Evas_Object *obj,
607                                        Eina_Bool    value)
608 {
609    ELM_CHECK_WIDTYPE(obj, widtype);
610    Widget_Data *wd = elm_widget_data_get(obj);
611
612    if (!wd) return;
613    wd->inwin_mode = value;
614 }
615
616 /**
617  * Get the button's file selector "inwin mode" flag.
618  *
619  * @param obj The button object
620  * @return value The "inwin mode" flag
621  *
622  * @ingroup File_Selector_Button
623  */
624 EAPI Eina_Bool
625 elm_fileselector_button_inwin_mode_get(const Evas_Object *obj)
626 {
627    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
628    Widget_Data *wd = elm_widget_data_get(obj);
629
630    if (!wd) return EINA_FALSE;
631    return wd->inwin_mode;
632 }
633
634 /**
635  * Set the icon used for the button
636  *
637  * Once the icon object is set, a previously set one will be deleted.
638  * If you want to keep that old content object, use the
639  * elm_fileselector_button_icon_unset() function.
640  *
641  * @param obj The button object
642  * @param icon  The icon object for the button
643  *
644  * @ingroup File_Selector_Button
645  */
646 EAPI void
647 elm_fileselector_button_icon_set(Evas_Object *obj,
648                                  Evas_Object *icon)
649 {
650    ELM_CHECK_WIDTYPE(obj, widtype);
651    Widget_Data *wd = elm_widget_data_get(obj);
652    if (!wd)
653      {
654         evas_object_del(icon);
655         return;
656      }
657    elm_button_icon_set(wd->btn, icon);
658 }
659
660 /**
661  * Get the icon used for the button
662  *
663  * @param obj The button object
664  * @return The icon object that is being used
665  *
666  * @ingroup File_Selector_Button
667  */
668 EAPI Evas_Object *
669 elm_fileselector_button_icon_get(const Evas_Object *obj)
670 {
671    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
672    Widget_Data *wd = elm_widget_data_get(obj);
673    if (!wd) return NULL;
674    return elm_button_icon_get(wd->btn);
675 }
676
677 /**
678  * Unset the icon used for the button
679  *
680  * Unparent and return the icon object which was set for this widget.
681  *
682  * @param obj The button object
683  * @return The icon object that was being used
684  *
685  * @ingroup File_Selector_Button
686  */
687 EAPI Evas_Object *
688 elm_fileselector_button_icon_unset(Evas_Object *obj)
689 {
690    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
691    Widget_Data *wd = elm_widget_data_get(obj);
692    if (!wd) return NULL;
693    return elm_button_icon_unset(wd->btn);
694 }
695