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