8abf0de844051767ed34b037e74bc3ad995bb36b
[framework/uifw/elementary.git] / src / lib / elc_fileselector_button.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5
6 struct _Widget_Data
7 {
8    Evas_Object *self, *btn, *fs, *fsw;
9    const char  *window_title;
10    Evas_Coord   w, h;
11    struct
12    {
13       const char *path;
14       Eina_Bool   expandable : 1;
15       Eina_Bool   folder_only : 1;
16       Eina_Bool   is_save : 1;
17    } fsd;
18    Eina_Bool inwin_mode : 1;
19 };
20
21 #define DEFAULT_WINDOW_TITLE "Select a file"
22
23 static const char *widtype = NULL;
24
25 static void _del_pre_hook(Evas_Object *obj);
26 static void _del_hook(Evas_Object *obj);
27 static void _theme_hook(Evas_Object *obj);
28 static void _disable_hook(Evas_Object *obj);
29 static void _sizing_eval(Evas_Object *obj);
30 static void _changed_size_hints(void        *data,
31                                 Evas        *e,
32                                 Evas_Object *obj,
33                                 void        *event_info);
34 static void _button_clicked(void        *data,
35                             Evas_Object *obj,
36                             void        *event_info);
37 static void _on_focus_hook(void        *data,
38                            Evas_Object *obj);
39 static void _selection_done(void        *data,
40                             Evas_Object *obj,
41                             void        *event_info);
42 static void _activate(Widget_Data *wd);
43
44 static const char SIG_FILE_CHOSEN[] = "file,chosen";
45 static const Evas_Smart_Cb_Description _signals[] = {
46        {SIG_FILE_CHOSEN, "s"},
47        {NULL, NULL}
48 };
49
50 static void
51 _del_pre_hook(Evas_Object *obj)
52 {
53    Widget_Data *wd = elm_widget_data_get(obj);
54    if (!wd) return;
55    evas_object_event_callback_del_full(wd->btn, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
56                                        _changed_size_hints, obj);
57    evas_object_smart_callback_del(wd->btn, "clicked", _button_clicked);
58 }
59
60 static void
61 _del_hook(Evas_Object *obj)
62 {
63    Evas_Object *win;
64    Widget_Data *wd;
65
66    wd = elm_widget_data_get(obj);
67    if (!wd) return;
68
69    if (wd->window_title) eina_stringshare_del(wd->window_title);
70    if (wd->fsd.path) eina_stringshare_del(wd->fsd.path);
71    if (wd->fs)
72      {
73         win = evas_object_data_del(obj, "win");
74         evas_object_del(win);
75      }
76    free(wd);
77 }
78
79 static void
80 _on_focus_hook(void *data   __UNUSED__,
81                Evas_Object *obj)
82 {
83    Widget_Data *wd = elm_widget_data_get(obj);
84    if (!wd) return;
85    if (elm_widget_focus_get(obj))
86      elm_widget_focus_steal(wd->btn);
87 }
88
89 static void
90 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
91 {
92    Widget_Data *wd = elm_widget_data_get(obj);
93    if (!wd) return;
94    elm_widget_mirrored_set(wd->btn, rtl);
95    elm_widget_mirrored_set(wd->fs, rtl);
96 }
97
98 static void
99 _theme_hook(Evas_Object *obj)
100 {
101    Widget_Data *wd = elm_widget_data_get(obj);
102    char buf[4096];
103    if (!wd) return;
104    _elm_widget_mirrored_reload(obj);
105    _mirrored_set(obj, elm_widget_mirrored_get(obj));
106
107    snprintf(buf, sizeof(buf), "fileselector_button/%s",
108             elm_widget_style_get(obj));
109    elm_object_style_set(wd->btn, buf);
110    _sizing_eval(obj);
111 }
112
113 static void
114 _disable_hook(Evas_Object *obj)
115 {
116    Widget_Data *wd = elm_widget_data_get(obj);
117    if (!wd) return;
118    elm_widget_disabled_set(wd->btn, elm_widget_disabled_get(obj));
119 }
120
121 static void
122 _sizing_eval(Evas_Object *obj)
123 {
124    Widget_Data *wd = elm_widget_data_get(obj);
125    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
126    if (!wd) return;
127    evas_object_size_hint_min_get(wd->btn, &minw, &minh);
128    evas_object_size_hint_max_get(wd->btn, &maxw, &maxh);
129    evas_object_size_hint_min_set(obj, minw, minh);
130    evas_object_size_hint_max_set(obj, maxw, maxh);
131 }
132
133 static void
134 _changed_size_hints(void            *data,
135                     Evas *e          __UNUSED__,
136                     Evas_Object *obj __UNUSED__,
137                     void *event_info __UNUSED__)
138 {
139    Widget_Data *wd = elm_widget_data_get(data);
140    if (!wd) return;
141    _sizing_eval(data);
142 }
143
144 static void
145 _activate_hook(Evas_Object *obj)
146 {
147    Widget_Data *wd;
148    wd = elm_widget_data_get(obj);
149    if (!wd) return;
150    _activate(wd);
151 }
152
153 static void
154 _button_clicked(void            *data,
155                 Evas_Object *obj __UNUSED__,
156                 void *event_info __UNUSED__)
157 {
158    _activate(data);
159 }
160
161 static Evas_Object *
162 _parent_win_get(Evas_Object *obj)
163 {
164    while ((obj) && (strcmp(elm_widget_type_get(obj), "win")))
165      obj = elm_object_parent_widget_get(obj);
166
167    return obj;
168 }
169
170 static Evas_Object *
171 _new_window_add(Widget_Data *wd)
172 {
173    Evas_Object *win, *bg;
174
175    win = elm_win_add(NULL, "fileselector_button", ELM_WIN_DIALOG_BASIC);
176    elm_win_title_set(win, wd->window_title);
177    elm_win_autodel_set(win, EINA_TRUE);
178
179    bg = elm_bg_add(win);
180    elm_win_resize_object_add(win, bg);
181    evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
182    evas_object_show(bg);
183
184    evas_object_resize(win, wd->w, wd->h);
185    return win;
186 }
187
188 static void
189 _activate(Widget_Data *wd)
190 {
191    Eina_Bool is_inwin = EINA_FALSE;
192
193    if (wd->fs) return;
194
195    if (wd->inwin_mode)
196      {
197         wd->fsw = _parent_win_get(wd->self);
198
199         if (!wd->fsw)
200           wd->fsw = _new_window_add(wd);
201         else
202           {
203              wd->fsw = elm_win_inwin_add(wd->fsw);
204              is_inwin = EINA_TRUE;
205           }
206      }
207    else
208      wd->fsw = _new_window_add(wd);
209
210    wd->fs = elm_fileselector_add(wd->fsw);
211    elm_widget_mirrored_set(wd->fs, elm_widget_mirrored_get(wd->self));
212    elm_widget_mirrored_automatic_set(wd->fs, EINA_FALSE);
213    elm_fileselector_expandable_set(wd->fs, wd->fsd.expandable);
214    elm_fileselector_folder_only_set(wd->fs, wd->fsd.folder_only);
215    elm_fileselector_is_save_set(wd->fs, wd->fsd.is_save);
216    elm_fileselector_selected_set(wd->fs, wd->fsd.path);
217    evas_object_size_hint_weight_set(wd->fs, EVAS_HINT_EXPAND,
218                                     EVAS_HINT_EXPAND);
219    evas_object_size_hint_align_set(wd->fs, EVAS_HINT_FILL, EVAS_HINT_FILL);
220    evas_object_smart_callback_add(wd->fs, "done", _selection_done, wd);
221    evas_object_show(wd->fs);
222
223    if (is_inwin)
224      {
225         elm_win_inwin_content_set(wd->fsw, wd->fs);
226         elm_win_inwin_activate(wd->fsw);
227      }
228    else
229      {
230         elm_win_resize_object_add(wd->fsw, wd->fs);
231         evas_object_show(wd->fsw);
232      }
233 }
234
235 static void
236 _selection_done(void            *data,
237                 Evas_Object *obj __UNUSED__,
238                 void            *event_info)
239 {
240    const char *file = event_info;
241    Widget_Data *wd = data;
242    Evas_Object *del;
243    if (!wd) return;
244
245    if (file) eina_stringshare_replace(&wd->fsd.path, file);
246
247    del = wd->fsw;
248    wd->fs = NULL;
249    wd->fsw = NULL;
250    evas_object_del(del);
251
252    evas_object_smart_callback_call(wd->self, SIG_FILE_CHOSEN,
253                                    (void *)wd->fsd.path);
254 }
255
256 static void
257 _elm_fileselector_button_label_set(Evas_Object *obj, const char *item,
258                                   const char  *label)
259 {
260    ELM_CHECK_WIDTYPE(obj, widtype);
261    if (item && strcmp(item, "default")) return;
262    Widget_Data *wd = elm_widget_data_get(obj);
263    if (!wd) return;
264    elm_object_text_set(wd->btn, label);
265 }
266
267 static const char *
268 _elm_fileselector_button_label_get(const Evas_Object *obj, const char *item)
269 {
270    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
271    Widget_Data *wd = elm_widget_data_get(obj);
272    if (item && strcmp(item, "default")) return NULL;
273    if (!wd) return NULL;
274    return elm_object_text_get(wd->btn);
275 }
276
277 EAPI Evas_Object *
278 elm_fileselector_button_add(Evas_Object *parent)
279 {
280    Evas_Object *obj;
281    Evas *e;
282    Widget_Data *wd;
283
284    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
285
286    ELM_SET_WIDTYPE(widtype, "fileselector_button");
287    elm_widget_type_set(obj, "fileselector_button");
288    elm_widget_sub_object_add(parent, obj);
289    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
290    elm_widget_data_set(obj, wd);
291    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
292    elm_widget_del_hook_set(obj, _del_hook);
293    elm_widget_theme_hook_set(obj, _theme_hook);
294    elm_widget_disable_hook_set(obj, _disable_hook);
295    elm_widget_can_focus_set(obj, EINA_TRUE);
296    elm_widget_activate_hook_set(obj, _activate_hook);
297    elm_widget_text_set_hook_set(obj, _elm_fileselector_button_label_set);
298    elm_widget_text_get_hook_set(obj, _elm_fileselector_button_label_get);
299
300    wd->self = obj;
301    wd->window_title = eina_stringshare_add(DEFAULT_WINDOW_TITLE);
302    if (getenv("HOME")) wd->fsd.path = eina_stringshare_add(getenv("HOME"));
303    else wd->fsd.path = eina_stringshare_add("/");
304    wd->fsd.expandable = _elm_config->fileselector_expand_enable;
305    wd->inwin_mode = _elm_config->inwin_dialogs_enable;
306    wd->w = 400;
307    wd->h = 400;
308
309    wd->btn = elm_button_add(parent);
310    elm_widget_mirrored_automatic_set(wd->btn, EINA_FALSE);
311    elm_widget_resize_object_set(obj, wd->btn);
312    evas_object_event_callback_add(wd->btn, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
313                                   _changed_size_hints, obj);
314    evas_object_smart_callback_add(wd->btn, "clicked", _button_clicked, wd);
315    elm_widget_sub_object_add(obj, wd->btn);
316
317    _theme_hook(obj);
318    evas_object_smart_callbacks_descriptions_set(obj, _signals);
319    return obj;
320 }
321
322 EAPI void
323 elm_fileselector_button_label_set(Evas_Object *obj,
324                                   const char  *label)
325 {
326    _elm_fileselector_button_label_set(obj, NULL, label);
327 }
328
329 EAPI const char *
330 elm_fileselector_button_label_get(const Evas_Object *obj)
331 {
332    return _elm_fileselector_button_label_get(obj, NULL);
333 }
334
335 EAPI void
336 elm_fileselector_button_window_title_set(Evas_Object *obj,
337                                          const char  *title)
338 {
339    ELM_CHECK_WIDTYPE(obj, widtype);
340    Widget_Data *wd = elm_widget_data_get(obj);
341
342    if (!wd) return;
343    eina_stringshare_replace(&wd->window_title, title);
344
345    if (wd->fsw)
346      elm_win_title_set(wd->fsw, wd->window_title);
347 }
348
349 EAPI const char *
350 elm_fileselector_button_window_title_get(const Evas_Object *obj)
351 {
352    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
353    Widget_Data *wd = elm_widget_data_get(obj);
354
355    if (!wd) return NULL;
356    return wd->window_title;
357 }
358
359 EAPI void
360 elm_fileselector_button_window_size_set(Evas_Object *obj,
361                                         Evas_Coord   width,
362                                         Evas_Coord   height)
363 {
364    ELM_CHECK_WIDTYPE(obj, widtype);
365    Widget_Data *wd = elm_widget_data_get(obj);
366
367    if (!wd) return;
368    wd->w = width;
369    wd->h = height;
370
371    if (wd->fsw)
372      evas_object_resize(wd->fsw, wd->w, wd->h);
373 }
374
375 EAPI void
376 elm_fileselector_button_window_size_get(const Evas_Object *obj,
377                                         Evas_Coord        *width,
378                                         Evas_Coord        *height)
379 {
380    ELM_CHECK_WIDTYPE(obj, widtype);
381    Widget_Data *wd = elm_widget_data_get(obj);
382
383    if (!wd) return;
384    if (width) *width = wd->w;
385    if (height) *height = wd->h;
386 }
387
388 EAPI void
389 elm_fileselector_button_path_set(Evas_Object *obj,
390                                  const char  *path)
391 {
392    ELM_CHECK_WIDTYPE(obj, widtype);
393    Widget_Data *wd = elm_widget_data_get(obj);
394
395    if (!wd) return;
396    eina_stringshare_replace(&wd->fsd.path, path);
397
398    if (wd->fs)
399      elm_fileselector_selected_set(wd->fs, wd->fsd.path);
400 }
401
402 EAPI const char *
403 elm_fileselector_button_path_get(const Evas_Object *obj)
404 {
405    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
406    Widget_Data *wd = elm_widget_data_get(obj);
407    if (!wd) return NULL;
408    return wd->fsd.path;
409 }
410
411 EAPI void
412 elm_fileselector_button_expandable_set(Evas_Object *obj,
413                                        Eina_Bool    value)
414 {
415    ELM_CHECK_WIDTYPE(obj, widtype);
416    Widget_Data *wd = elm_widget_data_get(obj);
417
418    if (!wd) return;
419    wd->fsd.expandable = value;
420
421    if (wd->fs)
422      elm_fileselector_expandable_set(wd->fs, wd->fsd.expandable);
423 }
424
425 EAPI Eina_Bool
426 elm_fileselector_button_expandable_get(const Evas_Object *obj)
427 {
428    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
429    Widget_Data *wd = elm_widget_data_get(obj);
430
431    if (!wd) return EINA_FALSE;
432    return wd->fsd.expandable;
433 }
434
435 EAPI void
436 elm_fileselector_button_folder_only_set(Evas_Object *obj,
437                                         Eina_Bool    value)
438 {
439    ELM_CHECK_WIDTYPE(obj, widtype);
440    Widget_Data *wd = elm_widget_data_get(obj);
441
442    if (!wd) return;
443    wd->fsd.folder_only = value;
444
445    if (wd->fs)
446      elm_fileselector_folder_only_set(wd->fs, wd->fsd.folder_only);
447 }
448
449 EAPI Eina_Bool
450 elm_fileselector_button_folder_only_get(const Evas_Object *obj)
451 {
452    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
453    Widget_Data *wd = elm_widget_data_get(obj);
454
455    if (!wd) return EINA_FALSE;
456    return wd->fsd.folder_only;
457 }
458
459 EAPI void
460 elm_fileselector_button_is_save_set(Evas_Object *obj,
461                                     Eina_Bool    value)
462 {
463    ELM_CHECK_WIDTYPE(obj, widtype);
464    Widget_Data *wd = elm_widget_data_get(obj);
465
466    if (!wd) return;
467    wd->fsd.is_save = value;
468
469    if (wd->fs)
470      elm_fileselector_is_save_set(wd->fs, wd->fsd.is_save);
471 }
472
473 EAPI Eina_Bool
474 elm_fileselector_button_is_save_get(const Evas_Object *obj)
475 {
476    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
477    Widget_Data *wd = elm_widget_data_get(obj);
478
479    if (!wd) return EINA_FALSE;
480    return wd->fsd.is_save;
481 }
482
483 EAPI void
484 elm_fileselector_button_inwin_mode_set(Evas_Object *obj,
485                                        Eina_Bool    value)
486 {
487    ELM_CHECK_WIDTYPE(obj, widtype);
488    Widget_Data *wd = elm_widget_data_get(obj);
489
490    if (!wd) return;
491    wd->inwin_mode = value;
492 }
493
494 EAPI Eina_Bool
495 elm_fileselector_button_inwin_mode_get(const Evas_Object *obj)
496 {
497    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
498    Widget_Data *wd = elm_widget_data_get(obj);
499
500    if (!wd) return EINA_FALSE;
501    return wd->inwin_mode;
502 }
503
504 EAPI void
505 elm_fileselector_button_icon_set(Evas_Object *obj,
506                                  Evas_Object *icon)
507 {
508    ELM_CHECK_WIDTYPE(obj, widtype);
509    Widget_Data *wd = elm_widget_data_get(obj);
510    if (!wd)
511      {
512         evas_object_del(icon);
513         return;
514      }
515    elm_object_part_content_set(wd->btn, "icon", icon);
516 }
517
518 EAPI Evas_Object *
519 elm_fileselector_button_icon_get(const Evas_Object *obj)
520 {
521    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
522    Widget_Data *wd = elm_widget_data_get(obj);
523    if (!wd) return NULL;
524    return elm_object_part_content_get(wd->btn, "icon");
525 }
526
527 EAPI Evas_Object *
528 elm_fileselector_button_icon_unset(Evas_Object *obj)
529 {
530    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
531    Widget_Data *wd = elm_widget_data_get(obj);
532    if (!wd) return NULL;
533    return elm_object_part_content_unset(wd->btn, "icon");
534 }
535