move elementary to trunk base. out of TMP/st.
[framework/uifw/elementary.git] / src / lib / elc_fileselector_entry.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4  /**
5  * @defgroup File_Selector_Entry File Selector Entry
6  *
7  * An entry that shows to enter/display path and have an associated
8  * button to allow selecting the file from a dialog.
9  *
10  * The button, when clicked, creates an Elementary window (or inner
11  * window) with an Elementary File Selector within. When a file is
12  * chosen, the (inner) window is closed and the selected file is
13  * exposed as an evas_object_smart_callback_call() of the button.
14  */
15
16 typedef struct _Widget_Data Widget_Data;
17
18 struct _Widget_Data
19 {
20    Evas_Object *edje;
21    Evas_Object *button;
22    Evas_Object *entry;
23 };
24
25 static const char *widtype = NULL;
26
27 static const char SIG_CHANGED[] = "changed";
28 static const char SIG_ACTIVATED[] = "activated";
29 static const char SIG_PRESS[] = "press";
30 static const char SIG_LONGPRESSED[] = "longpressed";
31 static const char SIG_CLICKED[] = "clicked";
32 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
33 static const char SIG_FOCUSED[] = "focused";
34 static const char SIG_UNFOCUSED[] = "unfocused";
35 static const char SIG_SELECTION_PASTE[] = "selection,paste";
36 static const char SIG_SELECTION_COPY[] = "selection,copy";
37 static const char SIG_SELECTION_CUT[] = "selection,cut";
38 static const char SIG_UNPRESSED[] = "unpressed";
39 static const char SIG_FILE_CHOSEN[] = "file,chosen";
40 static const Evas_Smart_Cb_Description _signals[] =
41 {
42   {SIG_CHANGED, ""},
43   {SIG_ACTIVATED, ""},
44   {SIG_PRESS, ""},
45   {SIG_LONGPRESSED, ""},
46   {SIG_CLICKED, ""},
47   {SIG_CLICKED_DOUBLE, ""},
48   {SIG_FOCUSED, ""},
49   {SIG_UNFOCUSED, ""},
50   {SIG_SELECTION_PASTE, ""},
51   {SIG_SELECTION_COPY, ""},
52   {SIG_SELECTION_CUT, ""},
53   {SIG_UNPRESSED, ""},
54   {SIG_FILE_CHOSEN, "s"},
55   {NULL, NULL}
56 };
57
58 #define SIG_FWD(name)                                                    \
59 static void                                                              \
60 _##name##_fwd(void *data, Evas_Object *obj __UNUSED__, void *event_info) \
61 {                                                                        \
62    evas_object_smart_callback_call(data, SIG_##name, event_info);        \
63 }
64 SIG_FWD(CHANGED)
65 SIG_FWD(PRESS)
66 SIG_FWD(LONGPRESSED)
67 SIG_FWD(CLICKED)
68 SIG_FWD(CLICKED_DOUBLE)
69 SIG_FWD(FOCUSED)
70 SIG_FWD(UNFOCUSED)
71 SIG_FWD(SELECTION_PASTE)
72 SIG_FWD(SELECTION_COPY)
73 SIG_FWD(SELECTION_CUT)
74 SIG_FWD(UNPRESSED)
75 #undef SIG_FWD
76
77 static void
78 _FILE_CHOSEN_fwd(void *data, Evas_Object *obj __UNUSED__, void *event_info)
79 {
80    Widget_Data *wd = elm_widget_data_get(data);
81    const char *file = event_info;
82    elm_scrolled_entry_entry_set(wd->entry, file);
83    evas_object_smart_callback_call(data, SIG_FILE_CHOSEN, event_info);
84 }
85
86 static void
87 _ACTIVATED_fwd(void *data, Evas_Object *obj __UNUSED__, void *event_info)
88 {
89    Widget_Data *wd = elm_widget_data_get(data);
90    const char *file = elm_scrolled_entry_entry_get(wd->entry);
91    elm_fileselector_button_path_set(wd->button, file);
92    evas_object_smart_callback_call(data, SIG_ACTIVATED, event_info);
93 }
94
95 static void
96 _del_hook(Evas_Object *obj)
97 {
98    Widget_Data *wd = elm_widget_data_get(obj);
99    free(wd);
100 }
101
102 static void
103 _sizing_eval(Evas_Object *obj)
104 {
105    Widget_Data *wd = elm_widget_data_get(obj);
106    Evas_Coord minw = -1, minh = -1;
107    if (!wd) return;
108    edje_object_size_min_calc(wd->edje, &minw, &minh);
109    evas_object_size_hint_min_set(obj, minw, minh);
110    evas_object_size_hint_max_set(obj, -1, -1);
111 }
112
113 static Eina_Bool
114 _elm_fileselector_entry_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
115 {
116    Widget_Data *wd = elm_widget_data_get(obj);
117
118    if (!wd)
119      return EINA_FALSE;
120
121    Evas_Object *chain[2];
122
123    /* Direction */
124    if (dir == ELM_FOCUS_PREVIOUS)
125      {
126         chain[0] = wd->button;
127         chain[1] = wd->entry;
128      }
129    else if (dir == ELM_FOCUS_NEXT)
130      {
131         chain[0] = wd->entry;
132         chain[1] = wd->button;
133      }
134    else
135      return EINA_FALSE;
136
137    unsigned char i = elm_widget_focus_get(chain[1]);
138
139    if (elm_widget_focus_next_get(chain[i], dir, next))
140      return EINA_TRUE;
141
142    i = !i;
143
144    Evas_Object *to_focus;
145    if (elm_widget_focus_next_get(chain[i], dir, &to_focus))
146      {
147         *next = to_focus;
148         return !!i;
149      }
150
151    return EINA_FALSE;
152 }
153
154 static void
155 _theme_hook(Evas_Object *obj)
156 {
157    Widget_Data *wd = elm_widget_data_get(obj);
158    const char *style = elm_widget_style_get(obj);
159    char buf[1024];
160
161    if (!wd) return;
162    _elm_theme_object_set(obj, wd->edje, "fileselector_entry", "base", style);
163    if (elm_object_disabled_get(obj))
164       edje_object_signal_emit(wd->edje, "elm,state,disabled", "elm");
165
166    if (!style) style = "default";
167    snprintf(buf, sizeof(buf), "fileselector_entry/%s", style);
168    elm_widget_style_set(wd->button, buf);
169    elm_widget_style_set(wd->entry, buf);
170
171    edje_object_part_swallow(obj, "elm.swallow.button", wd->button);
172    edje_object_part_swallow(obj, "elm.swallow.entry", wd->entry);
173
174    edje_object_message_signal_process(wd->edje);
175    edje_object_scale_set
176      (wd->edje, elm_widget_scale_get(obj) * _elm_config->scale);
177    _sizing_eval(obj);
178 }
179
180 static void
181 _disable_hook(Evas_Object *obj)
182 {
183    Widget_Data *wd = elm_widget_data_get(obj);
184    Eina_Bool val = elm_widget_disabled_get(obj);
185    if (!wd) return;
186    if (val)
187      edje_object_signal_emit(wd->edje, "elm,state,disabled", "elm");
188    else
189      edje_object_signal_emit(wd->edje, "elm,state,enabled", "elm");
190
191    elm_widget_disabled_set(wd->button, val);
192    elm_widget_disabled_set(wd->entry, val);
193 }
194
195 static void
196 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
197 {
198    _sizing_eval(data);
199 }
200
201 /**
202  * Add a new file selector entry into the parent object.
203  *
204  * @param parent The parent object
205  * @return The new object or NULL if it cannot be created
206  *
207  * @ingroup File_Selector_Entry
208  */
209 EAPI Evas_Object *
210 elm_fileselector_entry_add(Evas_Object *parent)
211 {
212    Evas_Object *obj;
213    Evas *e = evas_object_evas_get(parent);
214    if (!e) return NULL;
215    Widget_Data *wd;
216
217    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
218
219    wd = ELM_NEW(Widget_Data);
220
221    obj = elm_widget_add(e);
222    ELM_SET_WIDTYPE(widtype, "fileselector_entry");
223    elm_widget_type_set(obj, "fileselector_entry");
224    elm_widget_sub_object_add(parent, obj);
225    elm_widget_data_set(obj, wd);
226    elm_widget_del_hook_set(obj, _del_hook);
227    elm_widget_disable_hook_set(obj, _disable_hook);
228    elm_widget_focus_next_hook_set(obj, _elm_fileselector_entry_focus_next_hook);
229    elm_widget_can_focus_set(obj, EINA_FALSE);
230    elm_widget_theme_hook_set(obj, _theme_hook);
231
232    wd->edje = edje_object_add(e);
233    _elm_theme_object_set(obj, wd->edje, "fileselector_entry", "base", "default");
234    elm_widget_resize_object_set(obj, wd->edje);
235
236    wd->button = elm_fileselector_button_add(obj);
237    elm_widget_style_set(wd->button, "fileselector_entry/default");
238    edje_object_part_swallow(wd->edje, "elm.swallow.button", wd->button);
239    elm_widget_sub_object_add(obj, wd->button);
240    evas_object_event_callback_add
241      (wd->button, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, obj);
242    elm_fileselector_button_expandable_set(wd->button,
243                                           _elm_config->fileselector_expand_enable);
244
245 #define SIG_FWD(name)                                                   \
246    evas_object_smart_callback_add(wd->button, SIG_##name, _##name##_fwd, obj)
247    SIG_FWD(CLICKED);
248    SIG_FWD(UNPRESSED);
249    SIG_FWD(FILE_CHOSEN);
250 #undef SIG_FWD
251
252    wd->entry = elm_scrolled_entry_add(obj);
253    elm_widget_style_set(wd->entry, "fileselector_entry/default");
254    elm_scrolled_entry_single_line_set(wd->entry, EINA_TRUE);
255    elm_scrolled_entry_editable_set(wd->entry, EINA_TRUE);
256    edje_object_part_swallow(wd->edje, "elm.swallow.entry", wd->entry);
257    elm_widget_sub_object_add(obj, wd->entry);
258    evas_object_event_callback_add
259      (wd->entry, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, obj);
260
261 #define SIG_FWD(name)                                                   \
262    evas_object_smart_callback_add(wd->entry, SIG_##name, _##name##_fwd, obj)
263    SIG_FWD(CHANGED);
264    SIG_FWD(ACTIVATED);
265    SIG_FWD(PRESS);
266    SIG_FWD(LONGPRESSED);
267    SIG_FWD(CLICKED);
268    SIG_FWD(CLICKED_DOUBLE);
269    SIG_FWD(FOCUSED);
270    SIG_FWD(UNFOCUSED);
271    SIG_FWD(SELECTION_PASTE);
272    SIG_FWD(SELECTION_COPY);
273    SIG_FWD(SELECTION_CUT);
274 #undef SIG_FWD
275
276    _sizing_eval(obj);
277
278    // TODO: convert Elementary to subclassing of Evas_Smart_Class
279    // TODO: and save some bytes, making descriptions per-class and not instance!
280    evas_object_smart_callbacks_descriptions_set(obj, _signals);
281    return obj;
282 }
283
284 /**
285  * Set the label used in the file selector entry.
286  *
287  * @param obj The entry object
288  * @param label The text label text to be displayed on the entry
289  *
290  * @ingroup File_Selector_Entry
291  */
292 EAPI void
293 elm_fileselector_entry_button_label_set(Evas_Object *obj, const char *label)
294 {
295    ELM_CHECK_WIDTYPE(obj, widtype);
296    Widget_Data *wd = elm_widget_data_get(obj);
297    if (!wd) return;
298    elm_fileselector_button_label_set(wd->button, label);
299 }
300
301 EAPI const char *
302 elm_fileselector_entry_button_label_get(const Evas_Object *obj)
303 {
304    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
305    Widget_Data *wd = elm_widget_data_get(obj);
306    if (!wd) return NULL;
307    return elm_fileselector_button_label_get(wd->button);
308 }
309
310 /**
311  * Set the path to start the entry's file selector with, when clicked.
312  *
313  * @param obj The entry object
314  * @param path Path to a file/directory
315  *
316  * Default path is "HOME" environment variable's value.
317  *
318  * @ingroup File_Selector_Entry
319  */
320 EAPI void
321 elm_fileselector_entry_selected_set(Evas_Object *obj, const char *path)
322 {
323    ELM_CHECK_WIDTYPE(obj, widtype);
324    Widget_Data *wd = elm_widget_data_get(obj);
325    if (!wd) return;
326    elm_fileselector_button_path_set(wd->button, path);
327 }
328
329 /**
330  * Get the <b>last</b> path which the entry's file selector was set to.
331  *
332  * @param obj The entry object
333  * @param path Path to a file/directory
334  *
335  * Default path is "HOME" environment variable's value.
336  *
337  * @ingroup File_Selector_Entry
338  */
339 EAPI const char *
340 elm_fileselector_entry_selected_get(const Evas_Object *obj)
341 {
342    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
343    Widget_Data *wd = elm_widget_data_get(obj);
344    if (!wd) return NULL;
345    return elm_fileselector_button_path_get(wd->button);
346 }
347
348 /**
349  * Set the title of the file selector entry's window.
350  *
351  * @param obj The entry object
352  * @param title The title string
353  *
354  * Note that it will only take any effect if the fileselector entry
355  * not at "inwin mode".
356  *
357  * @ingroup File_Selector_Entry
358  */
359 EAPI void
360 elm_fileselector_entry_window_title_set(Evas_Object *obj, const char *title)
361 {
362    ELM_CHECK_WIDTYPE(obj, widtype);
363    Widget_Data *wd = elm_widget_data_get(obj);
364    if (!wd) return;
365    elm_fileselector_button_window_title_set(wd->button, title);
366 }
367
368 /**
369  * Get the title of the file selector entry's window.
370  *
371  * @param obj The entry object
372  *
373  * @ingroup File_Selector_Entry
374  */
375 EAPI const char *
376 elm_fileselector_entry_window_title_get(const Evas_Object *obj)
377 {
378    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
379    Widget_Data *wd = elm_widget_data_get(obj);
380    if (!wd) return NULL;
381    return elm_fileselector_button_window_title_get(wd->button);
382 }
383
384 /**
385  * Set the size of the file selector entry's window.
386  *
387  * @param obj The entry object
388  * @param width The width
389  * @param height The height
390  *
391  * Note that it will only take any effect if the fileselector entry not at
392  * "inwin mode". Default size for the window (when applicable) is 400x400.
393  *
394  * @ingroup File_Selector_Entry
395  */
396 EAPI void
397 elm_fileselector_entry_window_size_set(Evas_Object *obj, Evas_Coord width, Evas_Coord height)
398 {
399    ELM_CHECK_WIDTYPE(obj, widtype);
400    Widget_Data *wd = elm_widget_data_get(obj);
401    if (!wd) return;
402    elm_fileselector_button_window_size_set(wd->button, width, height);
403 }
404
405 /**
406  * Get the size of the file selector entry's window.
407  *
408  * @param obj The entry object
409  * @param width Pointer into which to store the width value
410  * @param height Pointer into which to store the height value
411  *
412  * @ingroup File_Selector_Entry
413  */
414 EAPI void
415 elm_fileselector_entry_window_size_get(const Evas_Object *obj, Evas_Coord *width, Evas_Coord *height)
416 {
417    ELM_CHECK_WIDTYPE(obj, widtype);
418    Widget_Data *wd = elm_widget_data_get(obj);
419    if (!wd) return;
420    elm_fileselector_button_window_size_get(wd->button, width, height);
421 }
422
423 /**
424  * Set the starting path of the file selector entry's window.
425  *
426  * @param obj The entry object
427  * @param path The path string
428  *
429  * It must be a <b>directory</b> path.
430  *
431  * @ingroup File_Selector_Entry
432  */
433 EAPI void
434 elm_fileselector_entry_path_set(Evas_Object *obj, const char *path)
435 {
436    ELM_CHECK_WIDTYPE(obj, widtype);
437    Widget_Data *wd = elm_widget_data_get(obj);
438    if (!wd) return;
439    elm_fileselector_button_path_set(wd->button, path);
440    elm_scrolled_entry_entry_set(wd->entry, path);
441 }
442
443 /**
444  * Get the <b>last</b> path of the file selector entry's window.
445  *
446  * @param obj The entry object
447  *
448  * @ingroup File_Selector_Entry
449  */
450 EAPI const char *
451 elm_fileselector_entry_path_get(const Evas_Object *obj)
452 {
453    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
454    Widget_Data *wd = elm_widget_data_get(obj);
455    if (!wd) return NULL;
456    return elm_scrolled_entry_entry_get(wd->entry);
457 }
458
459 /**
460  * Set whether the entry's file selector is to present itself as an
461  * Elementary Generic List (which will expand its entries for nested
462  * directories) or as canonical list, which will be rendered again
463  * with the contents of each selected directory.
464  *
465  * @param obj The entry object
466  * @param value The expandable flag
467  *
468  * @ingroup File_Selector_Entry
469  */
470 EAPI void
471 elm_fileselector_entry_expandable_set(Evas_Object *obj, Eina_Bool value)
472 {
473    ELM_CHECK_WIDTYPE(obj, widtype);
474    Widget_Data *wd = elm_widget_data_get(obj);
475    if (!wd) return;
476    elm_fileselector_button_expandable_set(wd->button, value);
477 }
478
479 /**
480  * Get the entry's file selector expandable flag.
481  *
482  * @param obj The entry object
483  * @return value The expandable flag
484  *
485  * @ingroup File_Selector_Entry
486  */
487 EAPI Eina_Bool
488 elm_fileselector_entry_expandable_get(const Evas_Object *obj)
489 {
490    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
491    Widget_Data *wd = elm_widget_data_get(obj);
492    if (!wd) return EINA_FALSE;
493    return elm_fileselector_button_expandable_get(wd->button);
494 }
495
496 /**
497  * Set whether the entry's file selector list is to display folders
498  * only or the directory contents, as well.
499  *
500  * @param obj The entry object
501  * @param value The "folder only" flag
502  *
503  * @ingroup File_Selector_Entry
504  */
505 EAPI void
506 elm_fileselector_entry_folder_only_set(Evas_Object *obj, Eina_Bool value)
507 {
508    ELM_CHECK_WIDTYPE(obj, widtype);
509    Widget_Data *wd = elm_widget_data_get(obj);
510    if (!wd) return;
511    elm_fileselector_button_folder_only_set(wd->button, value);
512 }
513
514 /**
515  * Get the entry's file selector "folder only" flag.
516  *
517  * @param obj The entry object
518  * @return value The "folder only" flag
519  *
520  * @ingroup File_Selector_Entry
521  */
522 EAPI Eina_Bool
523 elm_fileselector_entry_folder_only_get(const Evas_Object *obj)
524 {
525    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
526    Widget_Data *wd = elm_widget_data_get(obj);
527    if (!wd) return EINA_FALSE;
528    return elm_fileselector_button_folder_only_get(wd->button);
529 }
530
531 /**
532  * Set whether the entry's file selector has an editable text entry
533  * which will hold its current selection.
534  *
535  * @param obj The entry object
536  * @param value The "is save" flag
537  *
538  * @ingroup File_Selector_Entry
539  */
540 EAPI void
541 elm_fileselector_entry_is_save_set(Evas_Object *obj, Eina_Bool value)
542 {
543    ELM_CHECK_WIDTYPE(obj, widtype);
544    Widget_Data *wd = elm_widget_data_get(obj);
545    if (!wd) return;
546    elm_fileselector_button_is_save_set(wd->button, value);
547 }
548
549 /**
550  * Get the entry's file selector "is save" flag.
551  *
552  * @param obj The entry object
553  * @return value The "is save" flag
554  *
555  * @ingroup File_Selector_Entry
556  */
557 EAPI Eina_Bool
558 elm_fileselector_entry_is_save_get(const Evas_Object *obj)
559 {
560    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
561    Widget_Data *wd = elm_widget_data_get(obj);
562    if (!wd) return EINA_FALSE;
563    return elm_fileselector_button_is_save_get(wd->button);
564 }
565
566 /**
567  * Set whether the entry's file selector will raise an Elementary
568  * Inner Window, instead of a dedicated Elementary Window. By default,
569  * it won't.
570  *
571  * @param obj The entry object
572  * @param value The "inwin mode" flag
573  *
574  * @ingroup File_Selector_Entry
575  */
576 EAPI void
577 elm_fileselector_entry_inwin_mode_set(Evas_Object *obj, Eina_Bool value)
578 {
579    ELM_CHECK_WIDTYPE(obj, widtype);
580    Widget_Data *wd = elm_widget_data_get(obj);
581    if (!wd) return;
582    elm_fileselector_button_inwin_mode_set(wd->button, value);
583 }
584
585 /**
586  * Get the entry's file selector "inwin mode" flag.
587  *
588  * @param obj The entry object
589  * @return value The "inwin mode" flag
590  *
591  * @ingroup File_Selector_Entry
592  */
593 EAPI Eina_Bool
594 elm_fileselector_entry_inwin_mode_get(const Evas_Object *obj)
595 {
596    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
597    Widget_Data *wd = elm_widget_data_get(obj);
598    if (!wd) return EINA_FALSE;
599    return elm_fileselector_button_inwin_mode_get(wd->button);
600 }
601
602 /**
603  * Set the icon used for the entry button
604  *
605  * Once the icon object is set, a previously set one will be deleted.
606  *
607  * @param obj The entry object
608  * @param icon  The image for the entry
609  *
610  * @ingroup File_Selector_Entry
611  */
612 EAPI void
613 elm_fileselector_entry_button_icon_set(Evas_Object *obj, Evas_Object *icon)
614 {
615    ELM_CHECK_WIDTYPE(obj, widtype);
616    Widget_Data *wd = elm_widget_data_get(obj);
617    if (!wd) return;
618    elm_fileselector_button_icon_set(wd->button, icon);
619 }
620
621 /**
622  * Get the icon used for the entry button
623  *
624  * @param obj The entry object
625  * @return The image for the entry
626  *
627  * @ingroup File_Selector_Entry
628  */
629 EAPI Evas_Object *
630 elm_fileselector_entry_button_icon_get(const Evas_Object *obj)
631 {
632    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
633    Widget_Data *wd = elm_widget_data_get(obj);
634    if (!wd) return NULL;
635    return elm_fileselector_button_icon_get(wd->button);
636 }
637
638 /**
639  * Unset the icon used for the entry button
640  *
641  * Unparent and return the icon object which was set for this widget.
642  *
643  * @param obj The entry object
644  * @return The icon object that was being used
645  *
646  * @ingroup File_Selector_Entry
647  */
648 EAPI Evas_Object *
649 elm_fileselector_entry_button_icon_unset(Evas_Object *obj)
650 {
651    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
652    Widget_Data *wd = elm_widget_data_get(obj);
653    if (!wd) return NULL;
654    return elm_fileselector_button_icon_unset(wd->button);
655 }