From: Gustavo Lima Chaves Date: Thu, 8 Apr 2010 20:36:37 +0000 (+0000) Subject: Welcome a new Elementary widget: file selector button. X-Git-Tag: v1.0.0~4638 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7ac62f3043ada908881cb045625468261dea4c4d;p=platform%2Fupstream%2Felementary.git Welcome a new Elementary widget: file selector button. This is an elm button extended to launch a file selector on click and to callback_call registered funcs when selection is completed. Many uses may arise from it, but as a fresh 1st example here comes the first (primitive, but cool) video player in edje: externals { external: "emotion"; external: "elm"; } collections { group { name: "main"; parts { part { name: "video"; type: EXTERNAL; source: "emotion"; description { state: "default" 0; rel1 { offset: 10 10; } rel2 { offset: -11 -61; } params { choice: "engine" "gstreamer"; } } } part { name: "play"; type: RECT; description { state: "default" 0; color: 0 255 0 128; rel1 { relative: 0 1; offset: 10 -51; } rel2 { relative: 0.3 1; offset: -6 -11; } } } part { name: "pause"; type: RECT; description { state: "default" 0; color: 255 0 0 128; rel1 { relative: 0.3 1; offset: 5 -51; } rel2 { relative: 0.6 1; offset: -6 -11; } } } part { name: "file_sel_btn"; type: EXTERNAL; source: "elm/fileselector_button"; description { state: "default" 0; rel1 { relative: 0.6 1; offset: 5 -51; } rel2 { offset: -11 -11; } params { string: "label" "open file"; string: "icon" "file"; } } } programs { program { signal: "mouse,clicked,1"; source: "play"; after: "do_play"; } program { name: "do_play"; action: PARAM_SET "video" "play" "1"; } program { signal: "mouse,clicked,1"; source: "pause"; action: PARAM_SET "video" "play" "0"; } program { signal: "file,chosen"; source: "file_sel_btn"; action: PARAM_COPY "file_sel_btn" "path" "video" "file"; after: "do_play"; } } } } } Enjoy. I've seen bugs on the fileselector itself wrt to list selection logic. I'll dig into then soon. SVN revision: 47846 --- diff --git a/data/edje_externals/Makefile.am b/data/edje_externals/Makefile.am index 6218705..6de0e28 100644 --- a/data/edje_externals/Makefile.am +++ b/data/edje_externals/Makefile.am @@ -16,6 +16,7 @@ ico_button.png \ ico_check.png \ ico_clock.png \ ico_fileselector.png \ +ico_fileselector_button.png \ ico_genlist.png \ ico_hoversel.png \ ico_map.png \ @@ -25,11 +26,11 @@ ico_progressbar.png \ ico_radio.png \ ico_scrolled_entry.png \ ico_slider.png \ +ico_slideshow.png \ ico_spinner.png \ ico_thumb.png \ ico_toggle.png \ -ico_toolbar.png \ -ico_slideshow.png +ico_toolbar.png icons.edj: Makefile $(EXTRA_DIST) $(EDJE_CC) $(EDJE_FLAGS) \ diff --git a/data/edje_externals/ico_fileselector_button.png b/data/edje_externals/ico_fileselector_button.png new file mode 100644 index 0000000..6b5c773 Binary files /dev/null and b/data/edje_externals/ico_fileselector_button.png differ diff --git a/data/edje_externals/icons.edc b/data/edje_externals/icons.edc index ba7cf7b..4bccee2 100644 --- a/data/edje_externals/icons.edc +++ b/data/edje_externals/icons.edc @@ -17,6 +17,7 @@ ICON("button") ICON("check") ICON("clock") ICON("fileselector") +ICON("fileselector_button") ICON("genlist") ICON("hoversel") ICON("map") @@ -26,9 +27,8 @@ ICON("progressbar") ICON("radio") ICON("scrolled_entry") ICON("slider") +ICON("slideshow") ICON("spinner") ICON("thumb") ICON("toggle") ICON("toolbar") -ICON("slideshow") - diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 565aa3a..64ef4b0 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -33,6 +33,7 @@ test_bg.c \ test_icon.c \ test_box.c \ test_button.c \ +test_fileselector_button.c \ test_toggle.c \ test_table.c \ test_clock.c \ diff --git a/src/bin/test.c b/src/bin/test.c index ea78ae4..33affd8 100644 --- a/src/bin/test.c +++ b/src/bin/test.c @@ -9,6 +9,7 @@ void test_box_vert(void *data, Evas_Object *obj, void *event_info); void test_box_vert2(void *data, Evas_Object *obj, void *event_info); void test_box_horiz(void *data, Evas_Object *obj, void *event_info); void test_button(void *data, Evas_Object *obj, void *event_info); +void test_fileselector_button(void *data, Evas_Object *obj, void *event_info); void test_toggle(void *data, Evas_Object *obj, void *event_info); void test_clock(void *data, Evas_Object *obj, void *event_info); void test_check(void *data, Evas_Object *obj, void *event_info); @@ -197,6 +198,7 @@ my_win_main(void) ADD_TEST("Box Vert 2", test_box_vert2); ADD_TEST("Box Horiz", test_box_horiz); ADD_TEST("Buttons", test_button); + ADD_TEST("File Selector Button", test_fileselector_button); ADD_TEST("Toggles", test_toggle); ADD_TEST("Table", test_table); ADD_TEST("Clock", test_clock); diff --git a/src/bin/test_fileselector_button.c b/src/bin/test_fileselector_button.c new file mode 100644 index 0000000..ff1d643 --- /dev/null +++ b/src/bin/test_fileselector_button.c @@ -0,0 +1,132 @@ +#include + +#ifndef ELM_LIB_QUICKLAUNCH +static void +_file_chosen(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *entry = data; + char *file = event_info; + elm_entry_entry_set(entry, file); + printf("File chosen: %s\n", file); +} + +static void +_inwin_mode_toggle(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *fs_bt = data; + Eina_Bool value = elm_fileselector_button_inwin_mode_get(fs_bt); + elm_fileselector_button_inwin_mode_set(fs_bt, !value); + printf("Inwin mode set to: %s\n", value ? "false" : "true"); +} + +static void +_current_sel_toggle(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *fs_bt = data; + Eina_Bool value = elm_fileselector_button_folder_only_get(fs_bt); + elm_fileselector_button_folder_only_set(fs_bt, !value); + printf("Current selection entry display set to: %s\n", + value ? "false" : "true"); +} + +static void +_folder_only_toggle(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *fs_bt = data; + Eina_Bool value = elm_fileselector_button_folder_only_get(fs_bt); + elm_fileselector_button_folder_only_set(fs_bt, !value); + printf("Folder only flag set to: %s\n", value ? "false" : "true"); +} + +static void +_expandable_toggle(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *fs_bt = data; + Eina_Bool value = elm_fileselector_button_expandable_get(fs_bt); + elm_fileselector_button_expandable_set(fs_bt, !value); + printf("Expandable flag set to: %s\n", value ? "false" : "true"); +} + +void +test_fileselector_button(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *win, *bg, *vbox, *hbox, *ic, *bt, *fs_bt, *en, *lb; + + win = elm_win_add(NULL, "fileselector button", ELM_WIN_BASIC); + elm_win_title_set(win, "File Selector Button"); + elm_win_autodel_set(win, 1); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + vbox = elm_box_add(win); + elm_win_resize_object_add(win, vbox); + evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(vbox); + + vbox = elm_box_add(win); + evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, vbox); + evas_object_show(vbox); + + /* file selector button */ + ic = elm_icon_add(win); + elm_icon_standard_set(ic, "file"); + evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1); + fs_bt = elm_fileselector_button_add(win); + elm_fileselector_button_label_set(fs_bt, "Select a file"); + elm_fileselector_button_icon_set(fs_bt, ic); + elm_fileselector_button_inwin_mode_set(fs_bt, EINA_TRUE); + + elm_box_pack_end(vbox, fs_bt); + evas_object_show(fs_bt); + evas_object_show(ic); + + /* attribute setting buttons */ + hbox = elm_box_add(win); + elm_box_horizontal_set(hbox, EINA_TRUE); + elm_box_pack_end(vbox, hbox); + evas_object_show(hbox); + + bt = elm_button_add(win); + elm_button_label_set(bt, "Toggle current selection text entry"); + evas_object_smart_callback_add(bt, "clicked", _current_sel_toggle, fs_bt); + elm_box_pack_end(hbox, bt); + evas_object_show(bt); + + bt = elm_button_add(win); + elm_button_label_set(bt, "Toggle inwin mode"); + evas_object_smart_callback_add(bt, "clicked", _inwin_mode_toggle, fs_bt); + elm_box_pack_end(hbox, bt); + evas_object_show(bt); + + bt = elm_button_add(win); + elm_button_label_set(bt, "Toggle folder only mode"); + evas_object_smart_callback_add(bt, "clicked", _folder_only_toggle, fs_bt); + elm_box_pack_end(hbox, bt); + evas_object_show(bt); + + bt = elm_button_add(win); + elm_button_label_set(bt, "Toggle expandable mode"); + evas_object_smart_callback_add(bt, "clicked", _expandable_toggle, fs_bt); + elm_box_pack_end(hbox, bt); + evas_object_show(bt); + + lb = elm_label_add(win); + elm_label_label_set(lb, "Last selection:"); + elm_box_pack_end(vbox, lb); + evas_object_show(lb); + + en = elm_entry_add(win); + elm_entry_line_wrap_set(en, EINA_FALSE); + elm_entry_editable_set(en, EINA_FALSE); + evas_object_smart_callback_add(fs_bt, "file,chosen", _file_chosen, en); + elm_box_pack_end(vbox, en); + evas_object_show(en); + + evas_object_resize(win, 400, 400); + evas_object_show(win); +} +#endif diff --git a/src/edje_externals/Makefile.am b/src/edje_externals/Makefile.am index 449200b..2b85a02 100644 --- a/src/edje_externals/Makefile.am +++ b/src/edje_externals/Makefile.am @@ -33,6 +33,7 @@ elm_button.c \ elm_check.c \ elm_clock.c \ elm_fileselector.c \ +elm_fileselector_button.c \ elm_genlist.c \ elm_hoversel.c \ elm_map.c \ @@ -42,11 +43,11 @@ elm_progressbar.c \ elm_radio.c \ elm_scrolled_entry.c \ elm_slider.c \ +elm_slideshow.c \ elm_spinner.c \ elm_thumb.c \ elm_toggle.c \ -elm_toolbar.c \ -elm_slideshow.c +elm_toolbar.c elm_la_LIBADD = $(top_builddir)/src/lib/libelementary.la elm_la_LDFLAGS = $(all_libraries) -no-undefined @lt_enable_auto_import@ -module -avoid-version -shared -fPIC diff --git a/src/edje_externals/elm_fileselector_button.c b/src/edje_externals/elm_fileselector_button.c new file mode 100644 index 0000000..bfa0650 --- /dev/null +++ b/src/edje_externals/elm_fileselector_button.c @@ -0,0 +1,244 @@ +#include "private.h" + +typedef struct _Elm_Params_fileselector_button +{ + Elm_Params base; + Evas_Object *icon; + + struct { + const char *path; + Eina_Bool is_save:1; + Eina_Bool is_save_set:1; + Eina_Bool folder_only:1; + Eina_Bool folder_only_set:1; + Eina_Bool expandable:1; + Eina_Bool expandable_set:1; + Eina_Bool inwin_mode:1; + Eina_Bool inwin_mode_set:1; + } fs; +} Elm_Params_fileselector_button; + +static void +external_fileselector_button_state_set(void *data __UNUSED__, Evas_Object *obj, const void *from_params, const void *to_params, float pos __UNUSED__) +{ + const Elm_Params_fileselector_button *p; + + if (to_params) p = to_params; + else if (from_params) p = from_params; + else return; + + if (p->base.label) + elm_fileselector_button_label_set(obj, p->base.label); + if (p->icon) elm_fileselector_button_icon_set(obj, p->icon); + if (p->fs.path) elm_fileselector_button_selected_set(obj, p->fs.path); + if (p->fs.is_save_set) + elm_fileselector_button_is_save_set(obj, p->fs.is_save); + if (p->fs.folder_only_set) + elm_fileselector_button_folder_only_set(obj, p->fs.folder_only); + if (p->fs.expandable_set) + elm_fileselector_button_expandable_set(obj, p->fs.expandable); + if (p->fs.inwin_mode_set) + elm_fileselector_button_inwin_mode_set(obj, p->fs.inwin_mode); +} + +static Eina_Bool +external_fileselector_button_param_set(void *data __UNUSED__, Evas_Object *obj, const Edje_External_Param *param) +{ + if (!strcmp(param->name, "label")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) + { + elm_fileselector_button_label_set(obj, param->s); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "icon")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) + { + Evas_Object *icon = external_common_param_icon_get(obj, param); + if (icon) + { + elm_fileselector_button_icon_set(obj, icon); + return EINA_TRUE; + } + } + } + else if (!strcmp(param->name, "path")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) + { + elm_fileselector_button_selected_set(obj, param->s); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "save")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + elm_fileselector_button_is_save_set(obj, param->i); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "folder only")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + elm_fileselector_button_folder_only_set(obj, param->i); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "expandable")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + elm_fileselector_button_expandable_set(obj, param->i); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "inwin mode")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + elm_fileselector_button_inwin_mode_set(obj, param->i); + return EINA_TRUE; + } + } + + ERR("unknown parameter '%s' of type '%s'", + param->name, edje_external_param_type_str(param->type)); + + return EINA_FALSE; +} + +static Eina_Bool +external_fileselector_button_param_get(void *data __UNUSED__, const Evas_Object *obj, Edje_External_Param *param) +{ + if (!strcmp(param->name, "label")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) + { + param->s = elm_fileselector_button_label_get(obj); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "icon")) + { + /* not easy to get icon name back from live object */ + return EINA_FALSE; + } + else if (!strcmp(param->name, "path")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) + { + param->s = elm_fileselector_button_selected_get(obj); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "save")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + param->i = elm_fileselector_button_is_save_get(obj); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "folder only")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + param->i = elm_fileselector_button_folder_only_get(obj); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "expandable")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + param->i = elm_fileselector_button_expandable_get(obj); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "inwin mode")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + param->i = elm_fileselector_button_inwin_mode_get(obj); + return EINA_TRUE; + } + } + + ERR("unknown parameter '%s' of type '%s'", + param->name, edje_external_param_type_str(param->type)); + + return EINA_FALSE; +} + +static void * +external_fileselector_button_params_parse(void *data, Evas_Object *obj, const Eina_List *params) +{ + Elm_Params_fileselector_button *mem; + Edje_External_Param *param; + const Eina_List *l; + + mem = external_common_params_parse(Elm_Params_fileselector_button, + data, obj, params); + if (!mem) + return NULL; + + external_common_icon_param_parse(&mem->icon, obj, params); + + EINA_LIST_FOREACH(params, l, param) + { + if (!strcmp(param->name, "path")) + mem->fs.path = eina_stringshare_add(param->s); + else if (!strcmp(param->name, "save")) + { + mem->fs.is_save = !!param->i; + mem->fs.is_save_set = EINA_TRUE; + } + else if (!strcmp(param->name, "folder only")) + { + mem->fs.folder_only = !!param->i; + mem->fs.folder_only_set = EINA_TRUE; + } + else if (!strcmp(param->name, "expandable")) + { + mem->fs.expandable = !!param->i; + mem->fs.expandable_set = EINA_TRUE; + } + else if (!strcmp(param->name, "inwin mode")) + { + mem->fs.inwin_mode = !!param->i; + mem->fs.inwin_mode_set = EINA_TRUE; + } + } + + return mem; +} + + static void +external_fileselector_button_params_free(void *params) +{ + Elm_Params_fileselector_button *mem = params; + + if (mem->icon) + evas_object_del(mem->icon); + if (mem->fs.path) + eina_stringshare_del(mem->fs.path); + external_common_params_free(params); +} + +static Edje_External_Param_Info external_fileselector_button_params[] = { + DEFINE_EXTERNAL_COMMON_PARAMS, + EDJE_EXTERNAL_PARAM_INFO_STRING("icon"), + EDJE_EXTERNAL_PARAM_INFO_STRING("path"), + EDJE_EXTERNAL_PARAM_INFO_BOOL("save"), + EDJE_EXTERNAL_PARAM_INFO_BOOL("folder only"), + EDJE_EXTERNAL_PARAM_INFO_BOOL("expandable"), + EDJE_EXTERNAL_PARAM_INFO_BOOL("inwin mode"), + EDJE_EXTERNAL_PARAM_INFO_SENTINEL +}; + +DEFINE_EXTERNAL_ICON_ADD(fileselector_button, "fileselector_button"); +DEFINE_EXTERNAL_TYPE_SIMPLE(fileselector_button, "File Selector Button"); diff --git a/src/edje_externals/modules.inc b/src/edje_externals/modules.inc index bf856a0..8a54899 100644 --- a/src/edje_externals/modules.inc +++ b/src/edje_externals/modules.inc @@ -5,6 +5,7 @@ DEFINE_TYPE(button) DEFINE_TYPE(check) DEFINE_TYPE(clock) DEFINE_TYPE(fileselector) +DEFINE_TYPE(fileselector_button) DEFINE_TYPE(genlist) DEFINE_TYPE(hoversel) DEFINE_TYPE(map) @@ -14,9 +15,8 @@ DEFINE_TYPE(progressbar) DEFINE_TYPE(radio) DEFINE_TYPE(scrolled_entry) DEFINE_TYPE(slider) +DEFINE_TYPE(slideshow) DEFINE_TYPE(spinner) DEFINE_TYPE(thumb) DEFINE_TYPE(toggle) DEFINE_TYPE(toolbar) -DEFINE_TYPE(slideshow) - diff --git a/src/lib/Elementary.h.in b/src/lib/Elementary.h.in index ab23529..e238ac6 100644 --- a/src/lib/Elementary.h.in +++ b/src/lib/Elementary.h.in @@ -403,6 +403,29 @@ extern "C" { EAPI void elm_button_autorepeat_set(Evas_Object *obj, Eina_Bool on); EAPI void elm_button_autorepeat_initial_timeout_set(Evas_Object *obj, double t); EAPI void elm_button_autorepeat_gap_timeout_set(Evas_Object *obj, double t); + + EAPI Evas_Object *elm_fileselector_button_add(Evas_Object *parent); + EAPI void elm_fileselector_button_label_set(Evas_Object *obj, const char *label); + EAPI const char *elm_fileselector_button_label_get(const Evas_Object *obj); + EAPI void elm_fileselector_button_icon_set(Evas_Object *obj, Evas_Object *icon); + EAPI Evas_Object *elm_fileselector_button_icon_get(const Evas_Object *obj); + EAPI void elm_fileselector_button_window_title_set(Evas_Object *obj, const char *title); + EAPI const char *elm_fileselector_button_window_title_get(Evas_Object *obj); + EAPI void elm_fileselector_button_window_size_set(Evas_Object *obj, Evas_Coord width, Evas_Coord height); + EAPI void elm_fileselector_button_window_size_get(Evas_Object *obj, Evas_Coord *width, Evas_Coord *height); + EAPI void elm_fileselector_button_path_set(Evas_Object *obj, const char *path); + EAPI const char *elm_fileselector_button_path_get(Evas_Object *obj); + EAPI void elm_fileselector_button_expandable_set(Evas_Object *obj, Eina_Bool value); + EAPI Eina_Bool elm_fileselector_button_expandable_get(Evas_Object *obj); + EAPI void elm_fileselector_button_folder_only_set(Evas_Object *obj, Eina_Bool value); + EAPI Eina_Bool elm_fileselector_button_folder_only_get(Evas_Object *obj); + EAPI void elm_fileselector_button_is_save_set(Evas_Object *obj, Eina_Bool value); + EAPI Eina_Bool elm_fileselector_button_is_save_get(Evas_Object *obj); + EAPI void elm_fileselector_button_inwin_mode_set(Evas_Object *obj, Eina_Bool value); + EAPI Eina_Bool elm_fileselector_button_inwin_mode_get(Evas_Object *obj); + EAPI void elm_fileselector_button_selected_set(Evas_Object *obj, const char *path); + EAPI const char *elm_fileselector_button_selected_get(const Evas_Object *obj); + /* available styles: * default * anchor @@ -1063,6 +1086,8 @@ extern "C" { EAPI void elm_fileselector_path_set(Evas_Object *obj, const char *path); EAPI const char *elm_fileselector_path_get(const Evas_Object *obj); EAPI const char *elm_fileselector_selected_get(const Evas_Object *obj); + EAPI Eina_Bool elm_fileselector_selected_set(Evas_Object *obj, const char *path); + /* smart callbacks called: * "selected" - the user click on a file * "directory,open" - the list is populate with a new content. event_info is a directory. diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index d8a7b57..450165e 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -74,11 +74,12 @@ elm_conform.c \ elm_mapbuf.c \ elm_thumb.c \ \ -elc_notepad.c \ -elc_anchorview.c \ elc_anchorblock.c \ -elc_hoversel.c \ +elc_anchorview.c \ elc_fileselector.c \ +elc_fileselector_button.c \ +elc_hoversel.c \ +elc_notepad.c \ elc_scrolled_entry.c \ \ els_pan.c \ diff --git a/src/lib/elc_fileselector.c b/src/lib/elc_fileselector.c index 1434018..ec3ee7e 100644 --- a/src/lib/elc_fileselector.c +++ b/src/lib/elc_fileselector.c @@ -695,9 +695,9 @@ elm_fileselector_path_get(const Evas_Object *obj) } /** - * This gets the currently selected object in the fileselector. + * This gets the currently selected path in the file selector. * - * @param obj The fileselector object + * @param obj The file selector object * @return The absolute path of the selected object in the fileselector * * @ingroup Fileselector @@ -726,3 +726,38 @@ elm_fileselector_selected_get(const Evas_Object *obj) return wd->path; } + +/** + * This sets the currently selected path in the file selector. + * + * @param obj The file selector object + * @param path The path to a file or directory + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. The + * latter case occurs if the directory or file pointed to do not + * exist. + * + * @ingroup Fileselector + */ +EAPI Eina_Bool +elm_fileselector_selected_set(Evas_Object *obj, const char *path) +{ + ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; + Widget_Data *wd = elm_widget_data_get(obj); + Elm_Genlist_Item *it; + if (!wd) return EINA_FALSE; + + if (ecore_file_is_dir(path)) _populate(obj, path, NULL); + else + { + if (!ecore_file_exists(path)) return EINA_FALSE; + + _populate(obj, ecore_file_dir_get(path), NULL); + if (wd->entry2) + { + elm_entry_entry_set(wd->entry2, ecore_file_file_get(path)); + eina_stringshare_replace(&wd->selection, path); + } + } + + return EINA_TRUE; +} diff --git a/src/lib/elc_fileselector_button.c b/src/lib/elc_fileselector_button.c new file mode 100644 index 0000000..8c63470 --- /dev/null +++ b/src/lib/elc_fileselector_button.c @@ -0,0 +1,746 @@ +#include +#include "elm_priv.h" + + /** + * @defgroup File_Selector_Button File Selector Button + * + * A button that, when clicked, creates an Elementary window (or inner + * window) with an Elementary File Selector within. When a file is + * chosen, the (inner) window is closed and the selected file is + * exposed as an evas_object_smart_callback_call() of the button. + */ + +typedef struct _Widget_Data Widget_Data; + +struct _Widget_Data +{ + Evas_Object *btn, *icon, *fs; + const char *window_title; + const char *btn_label; + Evas_Coord w, h; + struct { + const char *path; + Eina_Bool expandable:1; + Eina_Bool folder_only:1; + Eina_Bool is_save:1; + } fsd; + Eina_Bool inwin_mode:1; +}; + +static const char DEFAULT_WINDOW_TITLE[] = "Select a file"; + +static const char *widtype = NULL; +static void _del_hook(Evas_Object *obj); +static void _theme_hook(Evas_Object *obj); +static void _disable_hook(Evas_Object *obj); +static void _sizing_eval(Evas_Object *obj); +static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _sub_del(void *data, Evas_Object *obj, void *event_info); +static void _signal_clicked(void *data, Evas_Object *obj, const char *emission, const char *source); +static void _signal_pressed(void *data, Evas_Object *obj, const char *emission, const char *source); +static void _signal_unpressed(void *data, Evas_Object *obj, const char *emission, const char *source); +static void _on_focus_hook(void *data, Evas_Object *obj); +static void _selection_done(void *data, Evas_Object *obj, void *event_info); + +static const char SIG_CLICKED[] = "clicked"; +static const char SIG_UNPRESSED[] = "unpressed"; +static const char SIG_FILE_CHOSEN[] = "file,chosen"; +static const Evas_Smart_Cb_Description _signals[] = { + {SIG_CLICKED, ""}, + {SIG_UNPRESSED, ""}, + {SIG_FILE_CHOSEN, "s"}, + {NULL, NULL} +}; + +static void +_del_hook(Evas_Object *obj) +{ + Evas_Object *win; + Widget_Data *wd; + + wd = elm_widget_data_get(obj); + if (!wd) return; + + if (wd->btn_label) eina_stringshare_del(wd->btn_label); + if (wd->window_title) eina_stringshare_del(wd->window_title); + if (wd->fsd.path) eina_stringshare_del(wd->fsd.path); + if (wd->fs) + { + win = evas_object_data_del(obj, "win"); + evas_object_del(win); + } + free(wd); +} + +static void +_on_focus_hook(void *data __UNUSED__, Evas_Object *obj) +{ + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + if (elm_widget_focus_get(obj)) + edje_object_signal_emit(wd->btn, "elm,action,focus", "elm"); + else + edje_object_signal_emit(wd->btn, "elm,action,unfocus", "elm"); +} + +static void +_theme_hook(Evas_Object *obj) +{ + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + _elm_theme_set(wd->btn, "button", "base", elm_widget_style_get(obj)); + if (wd->icon) + edje_object_part_swallow(wd->btn, "elm.swallow.content", wd->icon); + if (wd->btn_label) + edje_object_signal_emit(wd->btn, "elm,state,text,visible", "elm"); + else + edje_object_signal_emit(wd->btn, "elm,state,text,hidden", "elm"); + if (wd->icon) + edje_object_signal_emit(wd->btn, "elm,state,icon,visible", "elm"); + else + edje_object_signal_emit(wd->btn, "elm,state,icon,hidden", "elm"); + edje_object_part_text_set(wd->btn, "elm.text", wd->btn_label); + edje_object_message_signal_process(wd->btn); + edje_object_scale_set(wd->btn, elm_widget_scale_get(obj) * \ + _elm_config->scale); + _sizing_eval(obj); +} + +static void +_disable_hook(Evas_Object *obj) +{ + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + if (elm_widget_disabled_get(obj)) + edje_object_signal_emit(wd->btn, "elm,state,disabled", "elm"); + else + edje_object_signal_emit(wd->btn, "elm,state,enabled", "elm"); +} + +static void +_sizing_eval(Evas_Object *obj) +{ + Widget_Data *wd = elm_widget_data_get(obj); + Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1; + + if (!wd) return; + elm_coords_finger_size_adjust(1, &minw, 1, &minh); + edje_object_size_min_restricted_calc(wd->btn, &minw, &minh, minw, minh); + elm_coords_finger_size_adjust(1, &minw, 1, &minh); + evas_object_size_hint_min_set(obj, minw, minh); + evas_object_size_hint_max_set(obj, maxw, maxh); +} + +static void +_changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) +{ + Widget_Data *wd = elm_widget_data_get(data); + if (!wd) return; + if (obj != wd->icon) return; + _sizing_eval(data); +} + +static void +_sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info) +{ + Widget_Data *wd = elm_widget_data_get(obj); + Evas_Object *sub = event_info; + if (!wd) return; + if (sub == wd->icon) + { + edje_object_signal_emit(wd->btn, "elm,state,icon,hidden", "elm"); + evas_object_event_callback_del_full(sub, + EVAS_CALLBACK_CHANGED_SIZE_HINTS, + _changed_size_hints, obj); + wd->icon = NULL; + edje_object_message_signal_process(wd->btn); + _sizing_eval(obj); + } +} + +static void +_signal_clicked(void *data, Evas_Object *obj, const char *emission, const char *source) +{ + + Widget_Data *wd = elm_widget_data_get(data); + if (!wd) return; + + evas_object_smart_callback_call(data, SIG_CLICKED, NULL); + + /* safe guard when the theme does not emit the 'unpress' signal */ + _signal_unpressed(data, obj, emission, source); +} + +static Evas_Object * +_parent_win_get(Evas_Object *obj) +{ + Evas_Object *ret; + + ret = elm_object_parent_widget_get(obj); + if (!ret) return NULL; + + if (strcmp(elm_widget_type_get(ret), "win") != 0) + { + DBG("Widget type (%s) is not \"win\", going up\n", + elm_widget_type_get(ret)); + return _parent_win_get(ret); + } + + return ret; +} + +static Evas_Object * +_new_window_add(Widget_Data *wd) +{ + Evas_Object *win, *bg; + + win = elm_win_add(NULL, "fileselector_button", ELM_WIN_DIALOG_BASIC); + elm_win_title_set(win, wd->window_title); + elm_win_autodel_set(win, EINA_TRUE); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + evas_object_resize(win, wd->w, wd->h); + return win; +} + +static void +_fs_launch(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Evas_Object *fs_btn, *win, *iw, *fs; + Eina_Bool win_fallback; + Widget_Data *wd; + + fs_btn = data; + wd = elm_widget_data_get(fs_btn); + + if (!wd) return; + if (wd->fs) return; + + win_fallback = EINA_FALSE; + if (wd->inwin_mode) + { + win = _parent_win_get(fs_btn); + + if (!win) + { + ERR("No elementary window found as parent of the file selector " + "button! Launching the file selector inside a new elementary" + " window, then."); + win_fallback = EINA_TRUE; + } + else + { + iw = elm_win_inwin_add(win); + evas_object_data_set(fs_btn, "win", iw); + } + } + + if (!wd->inwin_mode || win_fallback) + { + win = _new_window_add(wd); + evas_object_data_set(fs_btn, "win", win); + } + + wd->fs = elm_fileselector_add(win); + elm_fileselector_expandable_set(wd->fs, wd->fsd.expandable); + elm_fileselector_folder_only_set(wd->fs, wd->fsd.folder_only); + elm_fileselector_is_save_set(wd->fs, wd->fsd.is_save); + elm_fileselector_selected_set(wd->fs, wd->fsd.path); + evas_object_size_hint_weight_set(wd->fs, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(wd->fs, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(wd->fs, "done", _selection_done, fs_btn); + evas_object_show(wd->fs); + + if (wd->inwin_mode && !win_fallback) + { + elm_win_inwin_content_set(iw, wd->fs); + elm_win_inwin_activate(iw); + } + else + { + elm_win_resize_object_add(win, wd->fs); + evas_object_show(win); + } +} + +static void +_selection_done(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *fs_btn, *win; + const char *file; + Widget_Data *wd; + + file = event_info; + fs_btn = data; + + wd = elm_widget_data_get(fs_btn); + if (!wd) return; + + win = evas_object_data_del(fs_btn, "win"); + + evas_object_smart_callback_call(fs_btn, SIG_FILE_CHOSEN, file); + eina_stringshare_replace(&wd->fsd.path, file); + + wd->fs = NULL; + evas_object_del(win); +} + +static void +_signal_pressed(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Widget_Data *wd = elm_widget_data_get(data); + if (!wd) return; +} + +static void +_signal_unpressed(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Widget_Data *wd = elm_widget_data_get(data); + if (!wd) return; + evas_object_smart_callback_call(data, SIG_UNPRESSED, NULL); +} + +/** + * Add a new file selector button into the parent object. + * + * @param parent The parent object + * @return The new object or NULL if it cannot be created + * + * @ingroup File_Selector_Button + */ +EAPI Evas_Object * +elm_fileselector_button_add(Evas_Object *parent) +{ + Evas_Object *obj; + Evas *e; + Widget_Data *wd; + + wd = ELM_NEW(Widget_Data); + wd->window_title = eina_stringshare_add(DEFAULT_WINDOW_TITLE); + wd->fsd.path = eina_stringshare_add(getenv("HOME")); + wd->w = 400; + wd->h = 400; + + e = evas_object_evas_get(parent); + obj = elm_widget_add(e); + ELM_SET_WIDTYPE(widtype, "fileselector_button"); + elm_widget_type_set(obj, "fileselector_button"); + elm_widget_sub_object_add(parent, obj); + elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL); + elm_widget_data_set(obj, wd); + elm_widget_del_hook_set(obj, _del_hook); + elm_widget_theme_hook_set(obj, _theme_hook); + elm_widget_disable_hook_set(obj, _disable_hook); + elm_widget_can_focus_set(obj, 1); + + wd->btn = edje_object_add(e); + _elm_theme_set(wd->btn, "button", "base", "default"); + edje_object_signal_callback_add(wd->btn, "elm,action,click", "", + _signal_clicked, obj); + edje_object_signal_callback_add(wd->btn, "elm,action,click", "", + _fs_launch, obj); + edje_object_signal_callback_add(wd->btn, "elm,action,press", "", + _signal_pressed, obj); + edje_object_signal_callback_add(wd->btn, "elm,action,unpress", "", + _signal_unpressed, obj); + elm_widget_resize_object_set(obj, wd->btn); + + evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj); + + _sizing_eval(obj); + + // TODO: convert Elementary to subclassing of Evas_Smart_Class + // TODO: and save some bytes, making descriptions per-class and not instance! + evas_object_smart_callbacks_descriptions_set(obj, _signals); + return obj; +} + +/** + * Set the label used in the file selector button. + * + * @param obj The button object + * @param label The text label text to be displayed on the button + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_label_set(Evas_Object *obj, const char *label) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + eina_stringshare_replace(&wd->btn_label, label); + if (label) + edje_object_signal_emit(wd->btn, "elm,state,text,visible", "elm"); + else + edje_object_signal_emit(wd->btn, "elm,state,text,hidden", "elm"); + edje_object_message_signal_process(wd->btn); + edje_object_part_text_set(wd->btn, "elm.text", label); + _sizing_eval(obj); +} + +EAPI const char * +elm_fileselector_button_label_get(const Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + return wd->btn_label; +} + +/** + * Set the path to start the button's file selector with, when clicked. + * + * @param obj The button object + * @param path Path to a file/directory + * + * Default path is "HOME" environment variable's value. + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_selected_set(Evas_Object *obj, const char *path) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + + eina_stringshare_replace(&wd->fsd.path, path); +} + +/** + * Get the last path which the button's file selector was set to. + * + * @param obj The button object + * @param path Path to a file/directory + * + * Default path is "HOME" environment variable's value. + * + * @ingroup File_Selector_Button + */ +EAPI const char * +elm_fileselector_button_selected_get(const Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + return wd->fsd.path; +} + +/** + * Set the title of the file selector button's window. + * + * @param obj The button object + * @param title The title string + * + * Note that it will only take any effect if the fileselector button + * not at "inwin mode". + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_window_title_set(Evas_Object *obj, const char *title) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + eina_stringshare_replace(&wd->window_title, title); +} + +/** + * Get the title of the file selector button's window. + * + * @param obj The button object + * + * @ingroup File_Selector_Button + */ +EAPI const char * +elm_fileselector_button_window_title_get(Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + return wd->window_title; +} + +/** + * Set the size of the file selector button's window. + * + * @param obj The button object + * @param width The width + * @param height The height + * + * Note that it will only take any effect if the fileselector button not at + * "inwin mode". Default size for the window (when applicable) is 400x400. + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_window_size_set(Evas_Object *obj, Evas_Coord width, Evas_Coord height) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + + wd->w = width; + wd->h = height; +} + +/** + * Get the size of the file selector button's window. + * + * @param obj The button object + * @param width Pointer into which to store the width value + * @param height Pointer into which to store the height value + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_window_size_get(Evas_Object *obj, Evas_Coord *width, Evas_Coord *height) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + + if (width) *width = wd->w; + if (height) *height = wd->h; +} + +/** + * Set the starting path of the file selector button's window. + * + * @param obj The button object + * @param path The path string + * + * It must be a directory path. + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_path_set(Evas_Object *obj, const char *path) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + eina_stringshare_replace(&wd->fsd.path, path); +} + +/** + * Get the last path of the file selector button's window. + * + * @param obj The button object + * + * @ingroup File_Selector_Button + */ +EAPI const char * +elm_fileselector_button_path_get(Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + return wd->fsd.path; +} + +/** + * Set whether the button's file selector is to present itself as an + * Elementary Generic List (which will expand its entries for nested + * directories) or as canonical list, which will be rendered again + * with the contents of each selected directory. + * + * @param obj The button object + * @param value The expandable flag + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_expandable_set(Evas_Object *obj, Eina_Bool value) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + + wd->fsd.expandable = value; +} + +/** + * Get the button's file selector expandable flag. + * + * @param obj The button object + * @return value The expandable flag + * + * @ingroup File_Selector_Button + */ +EAPI Eina_Bool +elm_fileselector_button_expandable_get(Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + + return wd->fsd.expandable; +} + +/** + * Set whether the button's file selector list is to display folders + * only or the directory contents, as well. + * + * @param obj The button object + * @param value The "folder only" flag + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_folder_only_set(Evas_Object *obj, Eina_Bool value) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + + wd->fsd.folder_only = value; +} + +/** + * Get the button's file selector "folder only" flag. + * + * @param obj The button object + * @return value The "folder only" flag + * + * @ingroup File_Selector_Button + */ +EAPI Eina_Bool +elm_fileselector_button_folder_only_get(Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + + return wd->fsd.folder_only; +} + +/** + * Set whether the button's file selector has an editable text entry + * which will hold its current selection. + * + * @param obj The button object + * @param value The "is save" flag + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_is_save_set(Evas_Object *obj, Eina_Bool value) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + + wd->fsd.is_save = value; +} + +/** + * Get the button's file selector "is save" flag. + * + * @param obj The button object + * @return value The "is save" flag + * + * @ingroup File_Selector_Button + */ +EAPI Eina_Bool +elm_fileselector_button_is_save_get(Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + + return wd->fsd.is_save; +} + +/** + * Set whether the button's file selector will raise an Elementary + * Inner Window, instead of a dedicated Elementary Window. By default, + * it won't. + * + * @param obj The button object + * @param value The "inwin mode" flag + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_inwin_mode_set(Evas_Object *obj, Eina_Bool value) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + + wd->inwin_mode = value; +} + +/** + * Get the button's file selector "inwin mode" flag. + * + * @param obj The button object + * @return value The "inwin mode" flag + * + * @ingroup File_Selector_Button + */ +EAPI Eina_Bool +elm_fileselector_button_inwin_mode_get(Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + + return wd->inwin_mode; +} + +/** + * Set the icon used for the button + * + * @param obj The button object + * @param icon The image for the button + * + * @ingroup File_Selector_Button + */ +EAPI void +elm_fileselector_button_icon_set(Evas_Object *obj, Evas_Object *icon) +{ + ELM_CHECK_WIDTYPE(obj, widtype); + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return; + if ((wd->icon != icon) && (wd->icon)) + elm_widget_sub_object_del(obj, wd->icon); + if ((icon) && (wd->icon != icon)) + { + wd->icon = icon; + elm_widget_sub_object_add(obj, icon); + evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS, + _changed_size_hints, obj); + edje_object_part_swallow(wd->btn, "elm.swallow.content", icon); + edje_object_signal_emit(wd->btn, "elm,state,icon,visible", "elm"); + edje_object_message_signal_process(wd->btn); + _sizing_eval(obj); + } + else + wd->icon = icon; +} + +/** + * Get the icon used for the button + * + * @param obj The button object + * @return The image for the button + * + * @ingroup File_Selector_Button + */ +EAPI Evas_Object * +elm_fileselector_button_icon_get(const Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) NULL; + Widget_Data *wd = elm_widget_data_get(obj); + if (!wd) return NULL; + return wd->icon; +}