From: Woochan Lee Date: Mon, 20 Nov 2017 10:12:49 +0000 (+0900) Subject: efl_ui_spin: Add new spin and spin_button widgets X-Git-Tag: submit/sandbox/upgrade/efl120/20180319.053334~1510 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=eefcb49419af9d0057ba4c03e6c9009a1265e31e;p=platform%2Fupstream%2Fefl.git efl_ui_spin: Add new spin and spin_button widgets Summary: https://phab.enlightenment.org/T5900 Creating base class(efl_ui_spin) to support various shape of spinner. Added button interaction widget efl_ui_spin_button inherited from efl_ui_spin. Test Plan: Add tests in elementary_test. Reviewers: Jaehyun_Cho, woohyun, jpeg, singh.amitesh Subscribers: jenkins, id213sin, cedric, jpeg Differential Revision: https://phab.enlightenment.org/D5424 --- diff --git a/data/elementary/themes/Makefile.am b/data/elementary/themes/Makefile.am index dfe26d5..f1ee7b1 100644 --- a/data/elementary/themes/Makefile.am +++ b/data/elementary/themes/Makefile.am @@ -146,6 +146,8 @@ elementary/themes/edc/elm/separator.edc \ elementary/themes/edc/elm/slider.edc \ elementary/themes/edc/elm/slideshow.edc \ elementary/themes/edc/elm/spinner.edc \ +elementary/themes/edc/elm/spin.edc \ +elementary/themes/edc/elm/spin_button.edc \ elementary/themes/edc/elm/textpath.edc \ elementary/themes/edc/elm/thumb.edc \ elementary/themes/edc/elm/toolbar.edc \ diff --git a/data/elementary/themes/default.edc b/data/elementary/themes/default.edc index 5e54ffd..9d61529 100644 --- a/data/elementary/themes/default.edc +++ b/data/elementary/themes/default.edc @@ -67,6 +67,8 @@ collections { #include "edc/elm/border.edc" // XXX: min size calc problems - too wide! ... err ok on my 32bit box... eh? #include "edc/elm/spinner.edc" +#include "edc/elm/spin.edc" +#include "edc/elm/spin_button.edc" #include "edc/elm/menu.edc" #include "edc/elm/clock.edc" #include "edc/elm/gengrid.edc" diff --git a/data/elementary/themes/edc/elm/button.edc b/data/elementary/themes/edc/elm/button.edc index a05260f..c5c48d3 100644 --- a/data/elementary/themes/edc/elm/button.edc +++ b/data/elementary/themes/edc/elm/button.edc @@ -1472,6 +1472,7 @@ group { name: "elm/button/base/hoversel_horizontal_entry/default"; /******************* SPINNER BUTTONS STYLES **********************/ group { name: "elm/button/base/spinner/increase/default"; alias: "elm/button/base/spinner/increase/colorselector/default"; + alias: "elm/button/base/spin_button/increase/default"; alias: "elm/button/base/calendar/increase/default"; alias: "elm/button/base/calendar/increase/double_spinners"; images.image: "sym_right_light_normal.png" COMP; @@ -1626,6 +1627,7 @@ group { name: "elm/button/base/hoversel_horizontal_entry/default"; group { name: "elm/button/base/spinner/decrease/default"; alias: "elm/button/base/spinner/decrease/colorselector/default"; inherit: "elm/button/base/spinner/increase/default"; + alias: "elm/button/base/spin_button/decrease/default"; alias: "elm/button/base/calendar/decrease/default"; alias: "elm/button/base/calendar/decrease/double_spinners"; images.image: "sym_left_light_normal.png" COMP; @@ -1654,6 +1656,8 @@ group { name: "elm/button/base/hoversel_horizontal_entry/default"; group { name: "elm/button/base/spinner/default"; alias: "elm/button/base/spinner/colorselector/default"; alias: "elm/button/base/spinner/vertical"; + alias: "elm/button/base/spin_button/default"; + alias: "elm/button/base/spin_button/vertical"; parts { part { name: "bg"; type: SPACER; @@ -1730,6 +1734,7 @@ group { name: "elm/button/base/hoversel_horizontal_entry/default"; } group { name: "elm/button/base/spinner/increase/vertical"; inherit: "elm/button/base/spinner/increase/default"; + alias: "elm/button/base/spin_button/increase/vertical"; images.image: "sym_up_light_normal.png" COMP; images.image: "sym_up_glow_normal.png" COMP; images.image: "sym_up_dark_normal.png" COMP; @@ -1755,6 +1760,7 @@ group { name: "elm/button/base/hoversel_horizontal_entry/default"; group { name: "elm/button/base/spinner/decrease/vertical"; inherit: "elm/button/base/spinner/decrease/default"; + alias: "elm/button/base/spin_button/decrease/vertical"; images.image: "sym_down_light_normal.png" COMP; images.image: "sym_down_glow_normal.png" COMP; images.image: "sym_down_dark_normal.png" COMP; diff --git a/data/elementary/themes/edc/elm/entry.edc b/data/elementary/themes/edc/elm/entry.edc index 4c43cff..bf881da 100644 --- a/data/elementary/themes/edc/elm/entry.edc +++ b/data/elementary/themes/edc/elm/entry.edc @@ -854,6 +854,8 @@ group { name: "elm/entry/base-single/default"; group { name: "elm/entry/base-single/spinner/default"; alias: "elm/entry/base-single/spinner/vertical"; + alias: "elm/entry/base-single/spin_button/default"; + alias: "elm/entry/base-single/spin_button/vertical"; inherit: "elm/entry/base-single/default"; styles { style { name: "entry_single_spinner_style"; diff --git a/data/elementary/themes/edc/elm/spin.edc b/data/elementary/themes/edc/elm/spin.edc new file mode 100644 index 0000000..77cf917 --- /dev/null +++ b/data/elementary/themes/edc/elm/spin.edc @@ -0,0 +1,27 @@ +group { name: "elm/spin/base/default"; + parts { + part { name: "bg"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color: 0 0 0 0; + } + } + part { name: "elm.text"; + type: TEXT; + mouse_events: 0; + scale: 1; + description { state: "default" 0.0; + color: FN_COL_DEFAULT; + text { + font: FNBD; + size: 10; + min: 1 1; + ellipsis: -1; + align: 0.5 0.5; + } + rel.to: "bg"; + } + } + } +} diff --git a/data/elementary/themes/edc/elm/spin_button.edc b/data/elementary/themes/edc/elm/spin_button.edc new file mode 100644 index 0000000..5b53382 --- /dev/null +++ b/data/elementary/themes/edc/elm/spin_button.edc @@ -0,0 +1,218 @@ +group { name: "elm/spin_button/base/default"; + images.image: "vert_bar_inset.png" COMP; + parts { + part { name: "clip"; type: RECT; + description { state: "default" 0.0; + rel1.to: "elm.swallow.text_button"; + rel2.to: "elm.swallow.text_button"; + } + } + part { name: "bg"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color_class: "spinner_bg"; + } + } + part { name: "inset"; mouse_events: 0; + description { state: "default" 0.0; + rel1.offset: 0 1; + rel2.offset: -1 -2; + image.normal: "vert_bar_inset.png"; + image.border: 1 1 8 6; + image.middle: 0; + fill.smooth: 0; + } + } + part { name: "access"; + type: RECT; + repeat_events: 1; + description { state: "default" 0.0; + fixed: 1 1; + color: 0 0 0 0; + rel1.to: "inset"; + rel2.to: "inset"; + visible: 0; + } + description { state: "active" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { name: "elm.swallow.entry"; + type: SWALLOW; + clip_to: "clip"; + description { state: "default" 0.0; + fixed: 1 1; + rel1.to: "elm.swallow.text_button"; + rel2.to: "elm.swallow.text_button"; + visible: 0; + } + description { state: "active" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { name: "elm.swallow.dec_button"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0; + fixed: 1 0; + rel1.to: "inset"; + rel1.offset: 1 1; + rel2.to: "inset"; + rel2.offset: 1 -2; + rel2.relative: 0.0 1.0; + align: 0.0 0.5; + min: 15 15; + aspect: 1.0 1.0; aspect_preference: VERTICAL; + } + } + part { name: "elm.swallow.inc_button"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0; + fixed: 1 0; + rel1.to: "inset"; + rel1.offset: 1 1; + rel1.relative: 1.0 0.0; + rel2.to: "inset"; + rel2.offset: 1 -2; + align: 1.0 0.5; + min: 15 15; + aspect: 1.0 1.0; aspect_preference: VERTICAL; + } + } + part { name: "elm.swallow.text_button"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0; + visible: 1; + rel1.to_y: "inset"; + rel1.to_x: "elm.swallow.dec_button"; + rel1.relative: 1.0 0.0; + rel1.offset: 1 1; + rel2.to_y: "inset"; + rel2.to_x: "elm.swallow.inc_button"; + rel2.relative: 0.0 1.0; + rel2.offset: -2 -2; + } + description { state: "inactive" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + part { name: "disabler"; + type: RECT; + repeat_events: 0; + mouse_events: 0; + description { state: "default" 0.0; + color: 0 0 0 0; + visible: 0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + } + programs { + program { name: "entry_active"; + signal: "elm,state,entry,active"; + source: "elm"; + action: STATE_SET "active" 0.0; + target: "elm.swallow.entry"; + } + program { name: "entry_inactive"; + signal: "elm,state,entry,inactive"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "elm.swallow.entry"; + } + program { name: "text_button_active"; + signal: "elm,state,button,active"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "elm.swallow.text_button"; + } + program { name: "text_button_inactive"; + signal: "elm,state,button,inactive"; + source: "elm"; + action: STATE_SET "inactive" 0.0; + target: "elm.swallow.text_button"; + } + program { name: "access_activate"; + signal: "elm,state,access,active"; + source: "elm"; + action: STATE_SET "active" 0.0; + target: "access"; + } + program { name: "access_inactivate"; + signal: "elm,state,access,inactive"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "access"; + } + program { name: "disable"; + signal: "elm,state,disabled"; + source: "elm"; + action: STATE_SET "disabled" 0.0; + target: "disabler"; + } + program { name: "enable"; + signal: "elm,state,enabled"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "disabler"; + } + } +} + +group { name: "elm/spin_button/base/vertical"; + inherit: "elm/spin_button/base/default"; + parts { + part { name: "elm.swallow.inc_button"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0; + rel1.to: "inset"; + rel1.offset: 1 1; + rel1.relative: 1.0 0.0; + rel2.to: "inset"; + rel2.offset: 1 -2; + align: 1.0 0.5; + } + } + part { name: "elm.swallow.text_button"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0; + visible: 1; + rel1.to_y: "inset"; + rel1.to_x: "elm.swallow.dec_button"; + rel1.relative: 1.0 0.0; + rel1.offset: 1 1; + rel2.to_y: "inset"; + rel2.to_x: "elm.swallow.inc_button"; + rel2.relative: 0.0 1.0; + rel2.offset: -2 -2; + } + description { state: "active" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + part { name: "elm.swallow.dec_button"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0; + rel1.to: "inset"; + rel1.offset: 1 1; + rel2.to: "inset"; + rel2.offset: 1 -2; + rel2.relative: 0.0 1.0; + align: 0.0 0.5; + } + } + } +} diff --git a/src/Makefile_Efl.am b/src/Makefile_Efl.am index 39c7330..769abd6 100644 --- a/src/Makefile_Efl.am +++ b/src/Makefile_Efl.am @@ -57,7 +57,6 @@ efl_eolian_files = \ lib/efl/interfaces/efl_ui_base.eo \ lib/efl/interfaces/efl_ui_direction.eo \ lib/efl/interfaces/efl_ui_drag.eo \ - lib/efl/interfaces/efl_ui_spin.eo \ lib/efl/interfaces/efl_ui_range.eo \ lib/efl/interfaces/efl_ui_view.eo \ lib/efl/interfaces/efl_ui_model_connect.eo \ diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am index be45275..3950d11 100644 --- a/src/Makefile_Elementary.am +++ b/src/Makefile_Elementary.am @@ -20,6 +20,8 @@ elm_public_eolian_files = \ lib/elementary/efl_ui_radio.eo \ lib/elementary/efl_ui_slider.eo \ lib/elementary/efl_ui_slider_interval.eo \ + lib/elementary/efl_ui_spin.eo \ + lib/elementary/efl_ui_spin_button.eo \ lib/elementary/efl_ui_video.eo \ lib/elementary/efl_ui_win.eo \ lib/elementary/efl_ui_win_inlined.eo \ @@ -311,6 +313,8 @@ includesunstable_HEADERS = \ lib/elementary/efl_ui_slider_private.h \ lib/elementary/elm_widget_slideshow.h \ lib/elementary/elm_widget_spinner.h \ + lib/elementary/efl_ui_spin_private.h \ + lib/elementary/efl_ui_spin_button_private.h \ lib/elementary/elm_widget_table.h \ lib/elementary/elm_widget_thumb.h \ lib/elementary/elm_widget_toolbar.h \ @@ -656,6 +660,8 @@ lib_elementary_libelementary_la_SOURCES = \ lib/elementary/elm_separator.c \ lib/elementary/efl_ui_slider.c \ lib/elementary/efl_ui_slider_interval.c \ + lib/elementary/efl_ui_spin.c \ + lib/elementary/efl_ui_spin_button.c \ lib/elementary/elm_slideshow.c \ lib/elementary/elm_spinner.c \ lib/elementary/elm_store.c \ @@ -877,6 +883,8 @@ bin/elementary/test_segment_control.c \ bin/elementary/test_separator.c \ bin/elementary/test_slider.c \ bin/elementary/test_ui_slider_interval.c \ +bin/elementary/test_ui_spin.c \ +bin/elementary/test_ui_spin_button.c \ bin/elementary/test_slideshow.c \ bin/elementary/test_spinner.c \ bin/elementary/test_store.c \ diff --git a/src/bin/elementary/Makefile.am b/src/bin/elementary/Makefile.am index 0ce67b0..8f2a810 100644 --- a/src/bin/elementary/Makefile.am +++ b/src/bin/elementary/Makefile.am @@ -128,6 +128,8 @@ test_slider.c \ test_ui_slider_interval.c \ test_slideshow.c \ test_spinner.c \ +test_ui_spinner.c \ +test_ui_buttonspin.c \ test_store.c \ test_sys_notify.c \ test_systray.c \ diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c index c4f5e9b..68201b2 100644 --- a/src/bin/elementary/test.c +++ b/src/bin/elementary/test.c @@ -176,6 +176,8 @@ void test_scroller3(void *data, Evas_Object *obj, void *event_info); void test_scroller4(void *data, Evas_Object *obj, void *event_info); void test_scroller5(void *data, Evas_Object *obj, void *event_info); void test_spinner(void *data, Evas_Object *obj, void *event_info); +void test_ui_spin(void *data, Evas_Object *obj, void *event_info); +void test_ui_spin_button(void *data, Evas_Object *obj, void *event_info); void test_index(void *data, Evas_Object *obj, void *event_info); void test_index2(void *data, Evas_Object *obj, void *event_info); void test_index3(void *data, Evas_Object *obj, void *event_info); @@ -1016,6 +1018,8 @@ add_tests: //------------------------------// ADD_TEST(NULL, "Range Values", "Spinner", test_spinner); + ADD_TEST(NULL, "Range Values", "Ui.Spin", test_ui_spin); + ADD_TEST(NULL, "Range Values", "Ui.Spin.Button", test_ui_spin_button); ADD_TEST(NULL, "Range Values", "Slider", test_slider); ADD_TEST(NULL, "Range Values", "Progressbar", test_progressbar); ADD_TEST(NULL, "Range Values", "Progressbar 2", test_progressbar2); diff --git a/src/bin/elementary/test_flipselector.c b/src/bin/elementary/test_flipselector.c index b9cd936..13216bd 100644 --- a/src/bin/elementary/test_flipselector.c +++ b/src/bin/elementary/test_flipselector.c @@ -186,10 +186,10 @@ test_flipselector(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *ev fpd = elm_flipselector_add(bx); evas_object_size_hint_weight_set(fpd, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - efl_ui_spin_step_set(fpd, 1.5); - efl_ui_spin_min_max_set(fpd, 2.3, 10.1); - efl_ui_spin_value_set(fpd, 5.3); - printf("Current value is %f\n", efl_ui_spin_value_get(fpd)); + efl_ui_range_step_set(fpd, 1.5); + efl_ui_range_min_max_set(fpd, 2.3, 10.1); + efl_ui_range_value_set(fpd, 5.3); + printf("Current value is %f\n", efl_ui_range_value_get(fpd)); elm_box_pack_end(bx, fpd); evas_object_show(fpd); diff --git a/src/bin/elementary/test_ui_spin.c b/src/bin/elementary/test_ui_spin.c new file mode 100644 index 0000000..be41b75 --- /dev/null +++ b/src/bin/elementary/test_ui_spin.c @@ -0,0 +1,71 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#include + +static void +_spin_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + printf("Value changed %d\n", (int)efl_ui_range_value_get(ev->object)); +} +static void +_spin_min_reached_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + printf("Min reached %d\n", (int)efl_ui_range_value_get(ev->object)); +} +static void +_spin_max_reached_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + printf("Max reached %d\n", (int)efl_ui_range_value_get(ev->object)); +} + +static void +_inc_clicked(void *data, const Efl_Event *ev EINA_UNUSED) +{ + int val = (int)efl_ui_range_value_get(data); + efl_ui_range_value_set(data, ++val); +} + +static void +_dec_clicked(void *data, const Efl_Event *ev EINA_UNUSED) +{ + int val = (int)efl_ui_range_value_get(data); + efl_ui_range_value_set(data, --val); +} + +void +test_ui_spin(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Eo *win, *bx, *sp; + + win = efl_add(EFL_UI_WIN_CLASS, NULL, + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Spin"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + + bx = efl_add(EFL_UI_BOX_CLASS, win, + efl_content_set(win, efl_added), + efl_ui_direction_set(efl_added, EFL_UI_DIR_DOWN)); + + sp = efl_add(EFL_UI_SPIN_CLASS, bx, + efl_ui_range_min_max_set(efl_added, 0, 10), + efl_ui_range_value_set(efl_added, 6), + efl_ui_range_step_set(efl_added, 2), + efl_ui_format_string_set(efl_added, "test %d"), + efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_spin_changed_cb, NULL), + efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_MIN_REACHED,_spin_min_reached_cb, NULL), + efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_MAX_REACHED,_spin_max_reached_cb, NULL), + efl_pack(bx, efl_added)); + + efl_add(EFL_UI_BUTTON_CLASS, bx, + efl_text_set(efl_added, "Increse Spinner value"), + efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED, _inc_clicked, sp), + efl_pack(bx, efl_added)); + + efl_add(EFL_UI_BUTTON_CLASS, bx, + efl_text_set(efl_added, "Decrease Spinner value"), + efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED, _dec_clicked, sp), + efl_pack(bx, efl_added)); + + efl_gfx_size_set(win, EINA_SIZE2D(100, 80)); +} diff --git a/src/bin/elementary/test_ui_spin_button.c b/src/bin/elementary/test_ui_spin_button.c new file mode 100644 index 0000000..e973072 --- /dev/null +++ b/src/bin/elementary/test_ui_spin_button.c @@ -0,0 +1,43 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#include + +static void +_spin_delay_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + printf("Value delay changed %d\n", (int)efl_ui_range_value_get(ev->object)); +} + +void +test_ui_spin_button(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Eo *win, *bx; + + win = efl_add(EFL_UI_WIN_CLASS, NULL, + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Spin_Button"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + + bx = efl_add(EFL_UI_BOX_CLASS, win, + efl_content_set(win, efl_added), + efl_ui_direction_set(efl_added, EFL_UI_DIR_DOWN)); + + efl_add(EFL_UI_SPIN_BUTTON_CLASS, bx, + efl_ui_range_min_max_set(efl_added, 0, 10), + efl_ui_range_value_set(efl_added, 6), + efl_ui_range_step_set(efl_added, 2), + efl_ui_spin_button_loop_set(efl_added, EINA_TRUE), + efl_ui_spin_button_editable_set(efl_added, EINA_TRUE), + efl_event_callback_add(efl_added, EFL_UI_SPIN_BUTTON_EVENT_DELAY_CHANGED,_spin_delay_changed_cb, NULL), + efl_pack(bx, efl_added)); + + efl_add(EFL_UI_SPIN_BUTTON_CLASS, bx, + efl_ui_range_min_max_set(efl_added, -100.0, 100.0), + efl_ui_range_value_set(efl_added, 0), + efl_ui_format_string_set(efl_added, "test float %0.2f"), + efl_ui_spin_button_editable_set(efl_added, EINA_FALSE), + efl_pack(bx, efl_added)); + + efl_gfx_size_set(win, EINA_SIZE2D(180, 100)); +} diff --git a/src/lib/efl/CMakeLists.txt b/src/lib/efl/CMakeLists.txt index af3c443..6637bed 100644 --- a/src/lib/efl/CMakeLists.txt +++ b/src/lib/efl/CMakeLists.txt @@ -54,7 +54,6 @@ set(PUBLIC_EO_FILES interfaces/efl_ui_item.eo interfaces/efl_ui_menu.eo interfaces/efl_ui_range.eo - interfaces/efl_ui_spin.eo interfaces/efl_ui_autorepeat.eo interfaces/efl_vpath.eo interfaces/efl_vpath_core.eo diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h index 8e1c6a6..683745f 100644 --- a/src/lib/efl/Efl.h +++ b/src/lib/efl/Efl.h @@ -90,7 +90,6 @@ typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command; #include "interfaces/efl_ui_base.eo.h" #include "interfaces/efl_ui_direction.eo.h" #include "interfaces/efl_ui_drag.eo.h" -#include "interfaces/efl_ui_spin.eo.h" #include "interfaces/efl_ui_range.eo.h" #include "interfaces/efl_ui_item.eo.h" #include "interfaces/efl_ui_menu.eo.h" diff --git a/src/lib/efl/interfaces/efl_interfaces_main.c b/src/lib/efl/interfaces/efl_interfaces_main.c index 5ebf073..e3b4e56 100644 --- a/src/lib/efl/interfaces/efl_interfaces_main.c +++ b/src/lib/efl/interfaces/efl_interfaces_main.c @@ -58,7 +58,6 @@ #include "interfaces/efl_ui_base.eo.c" #include "interfaces/efl_ui_direction.eo.c" #include "interfaces/efl_ui_drag.eo.c" -#include "interfaces/efl_ui_spin.eo.c" #include "interfaces/efl_ui_range.eo.c" #include "interfaces/efl_ui_menu.eo.c" #include "interfaces/efl_ui_autorepeat.eo.c" diff --git a/src/lib/efl/interfaces/efl_ui_range.eo b/src/lib/efl/interfaces/efl_ui_range.eo index a13ce57..56d4f89 100644 --- a/src/lib/efl/interfaces/efl_ui_range.eo +++ b/src/lib/efl/interfaces/efl_ui_range.eo @@ -28,7 +28,7 @@ interface Efl.Ui.Range If it is bigger then $max, will be updated to $max. Actual value can be get with @Efl.Ui.Range.range_value.get - By default, min is equal to 0.0, and max is equal to 1.0. + The minimum and maximum values may be different for each class. Warning: maximum must be greater than minimum, otherwise behavior is undefined. @@ -46,5 +46,21 @@ interface Efl.Ui.Range max: double; [[The maximum value.]] } } + @property range_step { + [[Control the step used to increment or decrement values for given widget. + + This value will be incremented or decremented to the displayed value. + + By default step value is equal to 1. + + Warning: The step value should be bigger than 0.]] + set { + } + get { + } + values { + step: double; [[The step value.]] + } + } } } diff --git a/src/lib/efl/interfaces/efl_ui_spin.eo b/src/lib/efl/interfaces/efl_ui_spin.eo deleted file mode 100644 index bfeca2b..0000000 --- a/src/lib/efl/interfaces/efl_ui_spin.eo +++ /dev/null @@ -1,84 +0,0 @@ -interface Efl.Ui.Spin() -{ - [[Efl UI spinner interface]] - methods { - @property min_max { - [[Control the minimum and maximum values for the spinner. - - Define the allowed range of values to be selected by the user. - - If actual value is less than $min, it will be updated to $min. If it - is bigger then $max, will be updated to $max. - - By default, min is equal to 0, and max is equal to 100. - - Warning: Maximum must be greater than minimum.]] - set { - } - get { - } - values { - min: double; [[The minimum value.]] - max: double; [[The maximum value.]] - } - } - @property step { - [[Control the step used to increment or decrement the spinner value. - - This value will be incremented or decremented to the displayed value. - It will be incremented while the user keep right or top arrow pressed, - and will be decremented while the user keep left or bottom arrow pressed. - - The interval to increment / decrement can be set with @.interval.set. - - By default step value is equal to 1.]] - set { - } - get { - } - values { - step: double; [[The step value.]] - } - } - @property value { - [[Control the value the spinner displays. - - Value will be presented on the label following format specified with - elm_spinner_format_set(). - - Warning The value must to be between min and max values. This values - are set by elm_spinner_min_max_set().]] - set { - } - get { - } - values { - val: double; [[The value to be displayed.]] - } - } - @property interval { - [[Control the interval on time updates for an user mouse button hold on spinner widgets' arrows. - - This interval value is decreased while the user holds the - mouse pointer either incrementing or decrementing spinner's value. - - This helps the user to get to a given value distant from the - current one easier/faster, as it will start to change quicker and - quicker on mouse button holds. - - The calculation for the next change interval value, starting from - the one set with this call, is the previous interval divided by - $1.05, so it decreases a little bit. - - The default starting interval value for automatic changes is - $0.85 seconds.]] - set { - } - get { - } - values { - interval: double; [[The (first) interval value in seconds.]] - } - } - } -} diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h index 431c1e8..64367ca 100644 --- a/src/lib/elementary/Elementary.h +++ b/src/lib/elementary/Elementary.h @@ -304,6 +304,8 @@ EAPI extern Elm_Version *elm_version; # include # include # include +# include +# include # include #endif diff --git a/src/lib/elementary/efl_ui_spin.c b/src/lib/elementary/efl_ui_spin.c new file mode 100644 index 0000000..13dbadc --- /dev/null +++ b/src/lib/elementary/efl_ui_spin.c @@ -0,0 +1,311 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#define EFL_ACCESS_PROTECTED +#define EFL_ACCESS_VALUE_PROTECTED +#define EFL_ACCESS_WIDGET_ACTION_PROTECTED + +#include + +#include "elm_priv.h" +#include "efl_ui_spin_private.h" + +#define MY_CLASS EFL_UI_SPIN_CLASS + +#define MY_CLASS_NAME "Efl.Ui.Spin" + +static Eina_Bool +_is_valid_digit(char x) +{ + return ((x >= '0' && x <= '9') || (x == '.')) ? EINA_TRUE : EINA_FALSE; +} + +static Efl_Ui_Spin_Format_Type +_is_label_format_integer(const char *fmt) +{ + const char *itr = NULL; + const char *start = NULL; + Eina_Bool found = EINA_FALSE; + Efl_Ui_Spin_Format_Type ret_type = SPIN_FORMAT_INVALID; + + start = strchr(fmt, '%'); + if (!start) return SPIN_FORMAT_INVALID; + + while (start) + { + if (found && start[1] != '%') + { + return SPIN_FORMAT_INVALID; + } + + if (start[1] != '%' && !found) + { + found = EINA_TRUE; + for (itr = start + 1; *itr != '\0'; itr++) + { + if ((*itr == 'd') || (*itr == 'u') || (*itr == 'i') || + (*itr == 'o') || (*itr == 'x') || (*itr == 'X')) + { + ret_type = SPIN_FORMAT_INT; + break; + } + else if ((*itr == 'f') || (*itr == 'F')) + { + ret_type = SPIN_FORMAT_FLOAT; + break; + } + else if (_is_valid_digit(*itr)) + { + continue; + } + else + { + return SPIN_FORMAT_INVALID; + } + } + } + start = strchr(start + 2, '%'); + } + + return ret_type; +} +static void +_label_write(Evas_Object *obj) +{ + Efl_Ui_Spin_Data *sd = efl_data_scope_get(obj, MY_CLASS); + + if (sd->format_cb) + { + const char *buf; + Eina_Value val; + + if (sd->format_type == SPIN_FORMAT_INT) + { + eina_value_setup(&val, EINA_VALUE_TYPE_INT); + eina_value_set(&val, (int)sd->val); + } + else + { + eina_value_setup(&val, EINA_VALUE_TYPE_DOUBLE); + eina_value_set(&val, sd->val); + } + eina_strbuf_reset(sd->format_strbuf); + sd->format_cb(sd->format_cb_data, sd->format_strbuf, val); + + buf = eina_strbuf_string_get(sd->format_strbuf); + eina_value_flush(&val); + elm_layout_text_set(obj, "elm.text", buf); + sd->templates = buf; + } + else + { + char buf[1024]; + snprintf(buf, sizeof(buf), "%.0f", sd->val); + elm_layout_text_set(obj, "elm.text", buf); + } +} + +static int +_decimal_points_get(const char *label) +{ + char result[16] = "0"; + const char *start = strchr(label, '%'); + + while (start) + { + if (start[1] != '%') + { + start = strchr(start, '.'); + if (start) + start++; + break; + } + else + start = strchr(start + 2, '%'); + } + + if (start) + { + const char *p = strchr(start, 'f'); + + if ((p) && ((p - start) < 15)) + sscanf(start, "%[^f]", result); + } + + return atoi(result); +} + +EOLIAN static void +_efl_ui_spin_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Spin_Data *_pd EINA_UNUSED) +{ + Evas_Coord minw = -1, minh = -1; + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + elm_coords_finger_size_adjust(1, &minw, 1, &minh); + edje_object_size_min_restricted_calc + (wd->resize_obj, &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, -1, -1); +} + +EOLIAN static Efl_Ui_Theme_Apply +_efl_ui_spin_elm_widget_theme_apply(Eo *obj, Efl_Ui_Spin_Data *sd EINA_UNUSED) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_FAILED); + + if (!elm_layout_theme_set(obj, "spin", "base", elm_widget_style_get(obj))) + CRI("Failed to set layout!"); + + elm_layout_sizing_eval(obj); + + return EFL_UI_THEME_APPLY_SUCCESS; +} + +EOLIAN static Eo * +_efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + + elm_widget_sub_object_parent_add(obj); + + sd->val_max = 100.0; + sd->step = 1.0; + + if (!elm_layout_theme_set(obj, "spin", "base", + elm_widget_style_get(obj))) + CRI("Failed to set layout!"); + + _label_write(obj); + elm_widget_can_focus_set(obj, EINA_TRUE); + + elm_layout_sizing_eval(obj); + + return obj; +} + +EOLIAN static Eo * +_efl_ui_spin_efl_object_finalize(Eo *obj, Efl_Ui_Spin_Data *sd EINA_UNUSED) +{ + obj = efl_finalize(efl_super(obj, MY_CLASS)); + + return obj; +} + +EOLIAN static void +_efl_ui_spin_efl_object_destructor(Eo *obj, Efl_Ui_Spin_Data *sd EINA_UNUSED) +{ + efl_ui_format_cb_set(obj, NULL, NULL, NULL); + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static void +_efl_ui_spin_efl_ui_format_format_cb_set(Eo *obj, Efl_Ui_Spin_Data *sd, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb) +{ + if (sd->format_cb_data == func_data && sd->format_cb == func) + return; + + if (sd->format_cb_data && sd->format_free_cb) + sd->format_free_cb(sd->format_cb_data); + + sd->format_cb = func; + sd->format_cb_data = func_data; + sd->format_free_cb = func_free_cb; + if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new(); + + const char *format = efl_ui_format_string_get(obj); + if (format) + { + sd->format_type = _is_label_format_integer(format); + if (sd->format_type == SPIN_FORMAT_INVALID) + { + ERR("format:\"%s\" is invalid, cannot be set", format); + return; + } + else if (sd->format_type == SPIN_FORMAT_FLOAT) + sd->decimal_points = _decimal_points_get(format); + } + + _label_write(obj); + elm_layout_sizing_eval(obj); +} + +EOLIAN static void +_efl_ui_spin_efl_ui_range_range_min_max_set(Eo *obj, Efl_Ui_Spin_Data *sd, double min, double max) +{ + if (max < min) + { + ERR("Wrong params. min(%lf) is bigger than max(%lf). It will swaped.", min, max); + double t = min; + min = max; + max = t; + } + if ((EINA_DBL_EQ(sd->val_min, min)) && (EINA_DBL_EQ(sd->val_max, max))) return; + + sd->val_min = min; + sd->val_max = max; + + if (sd->val < sd->val_min) sd->val = sd->val_min; + if (sd->val > sd->val_max) sd->val = sd->val_max; + + _label_write(obj); +} + +EOLIAN static void +_efl_ui_spin_efl_ui_range_range_min_max_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Data *sd, double *min, double *max) +{ + if (min) *min = sd->val_min; + if (max) *max = sd->val_max; +} + +EOLIAN static void +_efl_ui_spin_efl_ui_range_range_step_set(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Data *sd, double step) +{ + if (step <= 0) + { + ERR("Wrong param. The step(%lf) should be bigger than 0.0", step); + return; + } + + sd->step = step; +} + +EOLIAN static double +_efl_ui_spin_efl_ui_range_range_step_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Data *sd) +{ + return sd->step; +} + +EOLIAN static void +_efl_ui_spin_efl_ui_range_range_value_set(Eo *obj, Efl_Ui_Spin_Data *sd, double val) +{ + if (val < sd->val_min) + val = sd->val_min; + else if (val > sd->val_max) + val = sd->val_max; + + if (EINA_DBL_EQ(val, sd->val)) return; + + sd->val = val; + + if (EINA_DBL_EQ(sd->val, sd->val_min)) + efl_event_callback_call(obj, EFL_UI_SPIN_EVENT_MIN_REACHED, NULL); + else if (EINA_DBL_EQ(sd->val, sd->val_max)) + efl_event_callback_call(obj, EFL_UI_SPIN_EVENT_MAX_REACHED, NULL); + + efl_event_callback_call(obj, EFL_UI_SPIN_EVENT_CHANGED, NULL); + + _label_write(obj); +} + +EOLIAN static double +_efl_ui_spin_efl_ui_range_range_value_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Data *sd) +{ + return sd->val; +} + +#define EFL_UI_SPIN_EXTRA_OPS \ + ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_spin), \ + +#include "efl_ui_spin.eo.c" diff --git a/src/lib/elementary/efl_ui_spin.eo b/src/lib/elementary/efl_ui_spin.eo new file mode 100644 index 0000000..df2e2bd --- /dev/null +++ b/src/lib/elementary/efl_ui_spin.eo @@ -0,0 +1,26 @@ +class Efl.Ui.Spin (Efl.Ui.Layout, Efl.Ui.Range, Efl.Ui.Format, + Efl.Access.Value, Efl.Access.Widget.Action) +{ + [[A Spin. + + This is a widget which allows the user to increase or decrease numeric values + using user interactions. It's base type of widget to picking a value and showing value. + + @since 1.21 + ]] + implements { + Efl.Object.constructor; + Efl.Object.finalize; + Efl.Object.destructor; + Elm.Widget.theme_apply; + Efl.Ui.Range.range_min_max { get; set; } + Efl.Ui.Range.range_step { get; set; } + Efl.Ui.Range.range_value { get; set; } + Efl.Ui.Format.format_cb { set; } + } + events { + changed; [[Called when spin changed]] + min,reached; [[Called when spin value reached min]] + max,reached; [[Called when spin value reached max]] + } +} diff --git a/src/lib/elementary/efl_ui_spin_button.c b/src/lib/elementary/efl_ui_spin_button.c new file mode 100644 index 0000000..21b0e28 --- /dev/null +++ b/src/lib/elementary/efl_ui_spin_button.c @@ -0,0 +1,922 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#define EFL_ACCESS_PROTECTED +#define EFL_ACCESS_VALUE_PROTECTED +#define EFL_ACCESS_WIDGET_ACTION_PROTECTED +#define EFL_UI_FOCUS_COMPOSITION_PROTECTED + +#include + +#include "elm_priv.h" +#include "efl_ui_spin_button_private.h" +#include "efl_ui_spin_private.h" +#include "elm_entry.eo.h" + +#define MY_CLASS EFL_UI_SPIN_BUTTON_CLASS + +#define MY_CLASS_NAME "Efl.Ui.Spin_Button" + +#define EFL_UI_SPIN_BUTTON_DELAY_CHANGE_TIME 0.2 + +static void +_inc_dec_button_clicked_cb(void *data, const Efl_Event *event); +static void +_inc_dec_button_pressed_cb(void *data, const Efl_Event *event); +static void +_inc_dec_button_unpressed_cb(void *data, const Efl_Event *event); +static void +_inc_dec_button_mouse_move_cb(void *data, const Efl_Event *event); +static void +_entry_activated_cb(void *data, const Efl_Event *event); +static void +_entry_focus_changed_cb(void *data, const Efl_Event *event); +static void +_access_increment_decrement_info_say(Evas_Object *obj, Eina_Bool is_incremented); + +EFL_CALLBACKS_ARRAY_DEFINE(_inc_dec_button_cb, + { EFL_UI_EVENT_CLICKED, _inc_dec_button_clicked_cb}, + { EFL_UI_EVENT_PRESSED, _inc_dec_button_pressed_cb}, + { EFL_UI_EVENT_UNPRESSED, _inc_dec_button_unpressed_cb}, + { EFL_EVENT_POINTER_MOVE, _inc_dec_button_mouse_move_cb } + ); + +static void +_entry_show(Evas_Object *obj) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + char buf[32], fmt[32] = "%0.f"; + + /* try to construct just the format from given label + * completely ignoring pre/post words + */ + if (pd->templates) + { + const char *start = strchr(pd->templates, '%'); + while (start) + { + /* handle %% */ + if (start[1] != '%') + break; + else + start = strchr(start + 2, '%'); + } + + if (start) + { + const char *itr, *end = NULL; + for (itr = start + 1; *itr != '\0'; itr++) + { + if ((*itr == 'd') || (*itr == 'u') || (*itr == 'i') || (*itr == 'o') || + (*itr == 'x') || (*itr == 'X') || (*itr == 'f') || (*itr == 'F')) + { + end = itr + 1; + break; + } + } + + if ((end) && ((size_t)(end - start + 1) < sizeof(fmt))) + { + memcpy(fmt, start, end - start); + fmt[end - start] = '\0'; + } + } + } + + if (pd->format_type == SPIN_FORMAT_INT) + snprintf(buf, sizeof(buf), fmt, (int)pd->val); + else + snprintf(buf, sizeof(buf), fmt, pd->val); + + elm_object_text_set(sd->ent, buf); +} + +static void +_label_write(Evas_Object *obj) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + + if (pd->templates) + elm_layout_text_set(sd->text_button, "elm.text", pd->templates); + else + { + char buf[1024]; + + snprintf(buf, sizeof(buf), "%.0f", pd->val); + elm_layout_text_set(sd->text_button, "elm.text", buf); + } +} + +static Eina_Bool +_delay_change_timer_cb(void *data) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + sd->delay_change_timer = NULL; + efl_event_callback_call(data, EFL_UI_SPIN_BUTTON_EVENT_DELAY_CHANGED, NULL); + + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_value_set(Evas_Object *obj, + double new_val) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + + if (sd->loop) + { + if (new_val < pd->val_min) + new_val = pd->val_max; + else if (new_val > pd->val_max) + new_val = pd->val_min; + } + + efl_ui_range_value_set(obj, new_val); + ecore_timer_del(sd->delay_change_timer); + sd->delay_change_timer = ecore_timer_add(EFL_UI_SPIN_BUTTON_DELAY_CHANGE_TIME, + _delay_change_timer_cb, obj); + + return EINA_TRUE; +} + +static void +_entry_hide(Evas_Object *obj) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + + elm_layout_signal_emit(obj, "elm,state,button,active", "elm"); + evas_object_show(sd->text_button); + elm_layout_signal_emit(obj, "elm,state,entry,inactive", "elm"); + evas_object_hide(sd->ent); + + if (sd->entry_visible && !evas_focus_state_get(evas_object_evas_get(obj))) + sd->entry_reactivate = EINA_TRUE; + + sd->entry_visible = EINA_FALSE; +} + +static void +_entry_value_apply(Evas_Object *obj) +{ + const char *str; + double val; + char *end; + + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + + if (!sd->entry_visible) return; + + efl_event_callback_del(sd->ent, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED, + _entry_focus_changed_cb, obj); + _entry_hide(obj); + str = elm_object_text_get(sd->ent); + if (!str) return; + + val = strtod(str, &end); + if (((*end != '\0') && (!isspace(*end))) || (fabs(val - pd->val) < DBL_EPSILON)) return; + efl_ui_range_value_set(obj, val); + + efl_event_callback_call(obj, EFL_UI_SPIN_EVENT_CHANGED, NULL); + ecore_timer_del(sd->delay_change_timer); + sd->delay_change_timer = ecore_timer_add(EFL_UI_SPIN_BUTTON_DELAY_CHANGE_TIME, + _delay_change_timer_cb, obj); +} + +static void +_invalid_input_validity_filter(void *data EINA_UNUSED, Evas_Object *obj, char **text) +{ + char *insert = NULL; + const char *str = NULL; + int cursor_pos = 0; + int read_idx = 0, read_char, cmp_char; + + EINA_SAFETY_ON_NULL_RETURN(obj); + EINA_SAFETY_ON_NULL_RETURN(text); + + insert = *text; + str = elm_object_text_get(obj); + + evas_string_char_next_get(*text, 0, &read_char); + cursor_pos = elm_entry_cursor_pos_get(obj); + if (read_char) + { + if (read_char == '-') + { + if (cursor_pos != 0) + { + goto invalid_input; + } + } + if (read_char == '.') + { + read_idx = evas_string_char_next_get(str, 0, &cmp_char); + while (cmp_char) + { + if (read_char == cmp_char) + { + goto invalid_input; + } + read_idx = evas_string_char_next_get(str, read_idx, &cmp_char); + } + } + read_idx = evas_string_char_next_get(str, 0, &cmp_char); + if ((cmp_char == '-') && (cursor_pos == 0)) + { + goto invalid_input; + } + } + return; + +invalid_input: + *insert = 0; +} + +static void +_entry_accept_filter_add(Evas_Object *obj) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + static Elm_Entry_Filter_Accept_Set digits_filter_data; + + if (!sd->ent) return; + + elm_entry_markup_filter_remove(sd->ent, elm_entry_filter_accept_set, &digits_filter_data); + + if (pd->decimal_points > 0) + digits_filter_data.accepted = "-.0123456789"; + else + digits_filter_data.accepted = "-0123456789"; + + elm_entry_markup_filter_prepend(sd->ent, elm_entry_filter_accept_set, &digits_filter_data); +} + +static char * +_text_insert(const char *text, const char *input, int pos) +{ + char *result = NULL; + int text_len, input_len; + + text_len = evas_string_char_len_get(text); + input_len = evas_string_char_len_get(input); + result = (char *)calloc(text_len + input_len + 1, sizeof(char)); + if (!result) return NULL; + + strncpy(result, text, pos); + strcpy(result + pos, input); + strcpy(result + pos + input_len, text + pos); + + return result; +} + +static void +_min_max_validity_filter(void *data, Evas_Object *obj, char **text) +{ + const char *str, *point; + char *insert, *new_str = NULL; + double val; + int max_len, len; + + EINA_SAFETY_ON_NULL_RETURN(data); + EINA_SAFETY_ON_NULL_RETURN(obj); + EINA_SAFETY_ON_NULL_RETURN(text); + + Efl_Ui_Spin_Data *pd = efl_data_scope_get(data, EFL_UI_SPIN_CLASS); + + str = elm_object_text_get(obj); + if (!str) return; + + insert = *text; + new_str = _text_insert(str, insert, elm_entry_cursor_pos_get(obj)); + if (!new_str) return; + max_len = log10(fabs(pd->val_max)) + 1; + + new_str = _text_insert(str, insert, elm_entry_cursor_pos_get(obj)); + if (pd->format_type == SPIN_FORMAT_INT) + { + len = strlen(new_str); + if (len < max_len) goto end; + } + else if (pd->format_type == SPIN_FORMAT_FLOAT) + { + point = strchr(new_str, '.'); + if (point) + { + if ((int) strlen(point + 1) > pd->decimal_points) + { + *insert = 0; + goto end; + } + } + } + + val = strtod(new_str, NULL); + if ((val < pd->val_min) || (val > pd->val_max)) + *insert = 0; + +end: + free(new_str); +} + +static void +_entry_show_cb(void *data, + Evas *e EINA_UNUSED, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + _entry_show(data); + elm_object_focus_set(obj, EINA_TRUE); + elm_entry_select_all(obj); + sd->entry_visible = EINA_TRUE; + elm_layout_signal_emit(data, "elm,state,button,inactive", "elm"); + evas_object_hide(sd->text_button); +} + +static void +_toggle_entry(Evas_Object *obj) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + + if (elm_widget_disabled_get(obj)) return; + if (!sd->editable) return; + if (sd->entry_visible) _entry_value_apply(obj); + else + { + if (!sd->ent) + { + sd->ent = elm_entry_add(obj); + Eina_Strbuf *buf = eina_strbuf_new(); + eina_strbuf_append_printf(buf, "spinner/%s", elm_widget_style_get(obj)); + elm_widget_style_set(sd->ent, eina_strbuf_string_get(buf)); + eina_strbuf_free(buf); + evas_object_event_callback_add + (sd->ent, EVAS_CALLBACK_SHOW, _entry_show_cb, obj); + elm_entry_single_line_set(sd->ent, EINA_TRUE); + elm_layout_content_set(obj, "elm.swallow.entry", sd->ent); + _entry_accept_filter_add(obj); + elm_entry_markup_filter_append(sd->ent, _invalid_input_validity_filter, NULL); + if (_elm_config->spinner_min_max_filter_enable) + elm_entry_markup_filter_append(sd->ent, _min_max_validity_filter, obj); + efl_event_callback_add(sd->ent, ELM_ENTRY_EVENT_ACTIVATED, + _entry_activated_cb, obj); + } + + efl_event_callback_add(sd->ent, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED, + _entry_focus_changed_cb, obj); + sd->entry_visible = EINA_TRUE; + elm_layout_signal_emit(obj, "elm,state,entry,active", "elm"); + evas_object_show(sd->ent); + { + Eina_List *items = NULL; + + items = eina_list_append(items, sd->dec_button); + items = eina_list_append(items, sd->text_button); + items = eina_list_append(items, sd->ent); + items = eina_list_append(items, sd->inc_button); + + efl_ui_focus_composition_elements_set(obj, items); + } + + efl_ui_focus_manager_focus_set(efl_ui_focus_user_manager_get(obj), sd->ent); + } +} + +static void +_entry_toggle_cb(void *data EINA_UNUSED, + Evas_Object *obj, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + _toggle_entry(obj); +} + +static Eina_Bool +_spin_value(void *data) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + Efl_Ui_Spin_Data *pd = efl_data_scope_get(data, EFL_UI_SPIN_CLASS); + + if (_value_set(data, pd->val + (sd->inc_val ? pd->step : -pd->step))) + _label_write(data); + + return ECORE_CALLBACK_RENEW; +} + +static void +_spin_stop(Evas_Object *obj) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + + ELM_SAFE_FREE(sd->spin_timer, ecore_timer_del); + + elm_widget_scroll_freeze_pop(obj); +} + +static Eina_Bool +_inc_dec_button_press_start(void *data) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + sd->interval = sd->first_interval; + sd->longpress_timer = NULL; + ecore_timer_del(sd->spin_timer); + sd->spin_timer = ecore_timer_add(sd->interval, _spin_value, data); + _spin_value(data); + + elm_widget_scroll_freeze_push(data); + + return ECORE_CALLBACK_CANCEL; +} + +static void +_inc_dec_button_clicked_cb(void *data, const Efl_Event *event) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + _spin_stop(data); + sd->inc_val = sd->inc_button == event->object ? EINA_TRUE : EINA_FALSE; + _spin_value(data); + + if (_elm_config->access_mode) + _access_increment_decrement_info_say(data, EINA_TRUE); +} + + +static void +_inc_dec_button_pressed_cb(void *data, const Efl_Event *event) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + sd->inc_val = sd->inc_button == event->object ? EINA_TRUE : EINA_FALSE; + + if (sd->longpress_timer) ecore_timer_del(sd->longpress_timer); + + sd->longpress_timer = ecore_timer_add + (_elm_config->longpress_timeout, + _inc_dec_button_press_start, data); + + if (sd->entry_visible) _entry_value_apply(data); +} + +static void +_inc_dec_button_unpressed_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + if (sd->longpress_timer) + { + ecore_timer_del(sd->longpress_timer); + sd->longpress_timer = NULL; + } + + _spin_stop(data); +} + +static void +_inc_dec_button_mouse_move_cb(void *data, const Efl_Event *event) +{ + Efl_Input_Pointer *ev = event->info; + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + if (efl_input_processed_get(ev) && sd->longpress_timer) + { + ecore_timer_del(sd->longpress_timer); + sd->longpress_timer = NULL; + } +} + +static void +_text_button_focus_changed_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + _toggle_entry(data); +} + +static void +_entry_activated_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + _toggle_entry(data); +} + +static void +_entry_focus_changed_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + _toggle_entry(data); +} + +static void +_text_button_clicked_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + if (sd->entry_visible) return; + _toggle_entry(data); +} + +static Eina_Bool +_key_action_toggle(Evas_Object *obj, const char *params EINA_UNUSED) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + + if (sd->spin_timer) _spin_stop(obj); + else if (sd->entry_visible) _entry_toggle_cb(NULL, obj, NULL, NULL); + + return EINA_FALSE; +} + +EOLIAN static Eina_Bool +_efl_ui_spin_button_elm_widget_widget_event(Eo *obj, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED, const Efl_Event *eo_event, Evas_Object *src EINA_UNUSED) +{ + Eo *ev = eo_event->info; + + if (efl_input_processed_get(ev)) return EINA_FALSE; + if (eo_event->desc == EFL_EVENT_KEY_DOWN) + { + if (sd->spin_timer) _spin_stop(obj); + else return EINA_FALSE; + } + else if (eo_event->desc == EFL_EVENT_KEY_UP) + { + if (sd->spin_timer) _spin_stop(obj); + else return EINA_FALSE; + } + else if (eo_event->desc == EFL_EVENT_POINTER_WHEEL) + { + sd->interval = sd->first_interval; + if (efl_input_pointer_wheel_delta_get(ev) < 0) + sd->inc_val = EINA_TRUE; + else + sd->inc_val = EINA_FALSE; + + _spin_value(obj); + } + else return EINA_FALSE; + + efl_input_processed_set(ev, EINA_TRUE); + return EINA_TRUE; +} + +EOLIAN static Eina_Bool +_efl_ui_spin_button_elm_widget_on_focus_update(Eo *obj, Efl_Ui_Spin_Button_Data *sd, Elm_Object_Item *item EINA_UNUSED) +{ + Eina_Bool int_ret = EINA_FALSE; + + int_ret = efl_ui_widget_on_focus_update(efl_super(obj, MY_CLASS), NULL); + if (!int_ret) return EINA_FALSE; + + if (!elm_widget_focus_get(obj)) + { + ELM_SAFE_FREE(sd->delay_change_timer, ecore_timer_del); + ELM_SAFE_FREE(sd->spin_timer, ecore_timer_del); + } + else + { + if (sd->entry_reactivate) + { + _toggle_entry(obj); + + sd->entry_reactivate = EINA_FALSE; + } + } + + return EINA_TRUE; +} + +EOLIAN static void +_efl_ui_spin_button_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Spin_Button_Data *_pd EINA_UNUSED) +{ + Evas_Coord minw = -1, minh = -1; + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + elm_coords_finger_size_adjust(1, &minw, 1, &minh); + edje_object_size_min_restricted_calc + (wd->resize_obj, &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, -1, -1); +} + +static char * +_access_info_cb(void *data, Evas_Object *obj EINA_UNUSED) +{ + const char *txt = NULL; + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + if (sd->entry_visible) + txt = elm_object_text_get(sd->ent); + else + txt = elm_object_text_get(sd->text_button); + + if (txt) return strdup(txt); + + return NULL; +} + +static char * +_access_state_cb(void *data, Evas_Object *obj EINA_UNUSED) +{ + if (elm_widget_disabled_get(data)) + return strdup(E_("State: Disabled")); + + return NULL; +} + +static void +_access_activate_spin_button_cb(void *data, + Evas_Object *part_obj EINA_UNUSED, + Elm_Object_Item *item EINA_UNUSED) +{ + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(data, MY_CLASS); + + if (elm_widget_disabled_get(data)) return; + if (!sd->entry_visible) + _toggle_entry(data); +} + +static void +_access_increment_decrement_info_say(Evas_Object *obj, + Eina_Bool is_incremented) +{ + Eina_Strbuf *buf; + + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + + buf = eina_strbuf_new(); + if (is_incremented) + { + elm_object_signal_emit + (sd->inc_button, "elm,action,anim,activate", "elm"); + eina_strbuf_append(buf, E_("incremented")); + } + else + { + elm_object_signal_emit + (sd->dec_button, "elm,action,anim,activate", "elm"); + eina_strbuf_append(buf, E_("decremented")); + } + + eina_strbuf_append_printf + (buf, "%s", elm_object_text_get(sd->text_button)); + + _elm_access_say(eina_strbuf_string_get(buf)); + eina_strbuf_free(buf); +} + +static void +_access_spinner_register(Evas_Object *obj, Eina_Bool is_access) +{ + Evas_Object *ao; + Elm_Access_Info *ai; + + Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); + + if (!is_access) + { + /* unregister access */ + _elm_access_edje_object_part_object_unregister + (obj, elm_layout_edje_get(obj), "access"); + elm_layout_signal_emit(obj, "elm,state,access,inactive", "elm"); + return; + } + elm_layout_signal_emit(obj, "elm,state,access,active", "elm"); + ao = _elm_access_edje_object_part_object_register + (obj, elm_layout_edje_get(obj), "access"); + + ai = _elm_access_info_get(ao); + _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("spinner")); + _elm_access_callback_set(ai, ELM_ACCESS_STATE, _access_state_cb, obj); + _elm_access_activate_callback_set(ai, _access_activate_spin_button_cb, obj); + + /*Do not register spinner buttons if widget is disabled*/ + if (!elm_widget_disabled_get(obj)) + { + ai = _elm_access_info_get(sd->inc_button); + _elm_access_text_set(ai, ELM_ACCESS_TYPE, + E_("spinner increment button")); + ai = _elm_access_info_get(sd->dec_button); + _elm_access_text_set(ai, ELM_ACCESS_TYPE, + E_("spinner decrement button")); + ai = _elm_access_info_get(sd->text_button); + _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("spinner text")); + _elm_access_callback_set(ai, ELM_ACCESS_INFO, _access_info_cb, obj); + } +} + +EOLIAN static Efl_Ui_Theme_Apply +_efl_ui_spin_button_elm_widget_theme_apply(Eo *obj, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_FAILED); + + if (!elm_layout_theme_set(obj, "spin_button", "base", elm_widget_style_get(obj))) + CRI("Failed to set layout!"); + + if (sd->ent) + { + Eina_Strbuf *buf = eina_strbuf_new(); + eina_strbuf_append_printf(buf, "spin_button/%s", elm_widget_style_get(obj)); + elm_widget_style_set(sd->ent, eina_strbuf_string_get(buf)); + eina_strbuf_free(buf); + } + + if (sd->inc_button) + { + Eina_Strbuf *buf = eina_strbuf_new(); + eina_strbuf_append_printf(buf, "spin_button/increase/%s", elm_widget_style_get(obj)); + elm_widget_style_set(sd->inc_button, eina_strbuf_string_get(buf)); + eina_strbuf_free(buf); + } + + if (sd->text_button) + { + Eina_Strbuf *buf = eina_strbuf_new(); + eina_strbuf_append_printf(buf, "spin_button/%s", elm_widget_style_get(obj)); + elm_widget_style_set(sd->text_button, eina_strbuf_string_get(buf)); + eina_strbuf_free(buf); + } + + if (sd->dec_button) + { + Eina_Strbuf *buf = eina_strbuf_new(); + eina_strbuf_append_printf(buf, "spin_button/decrease/%s", elm_widget_style_get(obj)); + elm_widget_style_set(sd->dec_button, eina_strbuf_string_get(buf)); + eina_strbuf_free(buf); + } + + if (_elm_config->access_mode) + _access_spinner_register(obj, EINA_TRUE); + + elm_layout_sizing_eval(obj); + return EFL_UI_THEME_APPLY_SUCCESS; +} + +EOLIAN static Eo * +_efl_ui_spin_button_efl_object_finalize(Eo *obj, Efl_Ui_Spin_Button_Data *sd) +{ + obj = efl_finalize(efl_super(obj, MY_CLASS)); + + elm_widget_sub_object_parent_add(obj); + + sd->first_interval = 0.85; + + if (!elm_layout_theme_set(obj, "spin_button", "base", + elm_widget_style_get(obj))) + CRI("Failed to set layout!"); + + sd->inc_button = elm_button_add(obj); + elm_object_style_set(sd->inc_button, "spinner/increase/default"); + + efl_event_callback_array_add(sd->inc_button, _inc_dec_button_cb(), obj); + + elm_layout_content_set(obj, "elm.swallow.inc_button", sd->inc_button); + elm_widget_sub_object_add(obj, sd->inc_button); + + sd->text_button = elm_button_add(obj); + elm_object_style_set(sd->text_button, "spinner/default"); + + efl_event_callback_add(sd->text_button, EFL_UI_EVENT_CLICKED, + _text_button_clicked_cb, obj); + efl_event_callback_add(sd->text_button, + EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED, + _text_button_focus_changed_cb, obj); + + elm_layout_content_set(obj, "elm.swallow.text_button", sd->text_button); + elm_widget_sub_object_add(obj, sd->text_button); + + sd->dec_button = elm_button_add(obj); + elm_object_style_set(sd->dec_button, "spinner/decrease/default"); + + efl_event_callback_array_add(sd->dec_button, _inc_dec_button_cb(), obj); + + elm_layout_content_set(obj, "elm.swallow.dec_button", sd->dec_button); + elm_widget_sub_object_add(obj, sd->dec_button); + + { + Eina_List *items = NULL; + + items = eina_list_append(items, sd->dec_button); + items = eina_list_append(items, sd->text_button); + items = eina_list_append(items, sd->inc_button); + + efl_ui_focus_composition_elements_set(obj, items); + } + + elm_layout_signal_callback_add + (obj, "elm,action,entry,toggle", "*", _entry_toggle_cb, NULL); + + _label_write(obj); + elm_widget_can_focus_set(obj, EINA_TRUE); + + elm_layout_sizing_eval(obj); + efl_access_role_set(obj, EFL_ACCESS_ROLE_SPIN_BUTTON); + + return obj; +} + +EOLIAN static void +_efl_ui_spin_button_efl_ui_range_range_value_set(Eo *obj, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED, double val) +{ + efl_ui_range_value_set(efl_super(obj, MY_CLASS), val); + + _label_write(obj); +} + +EOLIAN static void +_efl_ui_spin_button_editable_set(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Button_Data *sd, Eina_Bool editable) +{ + sd->editable = editable; +} + +EOLIAN static Eina_Bool +_efl_ui_spin_button_editable_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Button_Data *sd) +{ + return sd->editable; +} + +EOLIAN static void +_efl_ui_spin_button_loop_set(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Button_Data *sd, Eina_Bool loop) +{ + sd->loop = loop; +} + +EOLIAN static Eina_Bool +_efl_ui_spin_button_loop_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Button_Data *sd) +{ + return sd->loop; +} + +EOLIAN static const Efl_Access_Action_Data * +_efl_ui_spin_button_efl_access_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED) +{ + static Efl_Access_Action_Data atspi_actions[] = { + { "toggle", "toggle", NULL, _key_action_toggle}, + { NULL, NULL, NULL, NULL } + }; + return &atspi_actions[0]; +} + +// A11Y Accessibility + +EOLIAN static void +_efl_ui_spin_button_efl_access_value_value_and_text_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED, double *value, const char **text) +{ + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + + if (value) *value = pd->val; + if (text) *text = NULL; +} + +EOLIAN static Eina_Bool +_efl_ui_spin_button_efl_access_value_value_and_text_set(Eo *obj, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED, double value, const char *text EINA_UNUSED) +{ + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + + if (pd->val_min > value) return EINA_FALSE; + if (pd->val_max < value) return EINA_FALSE; + + pd->val = value; + efl_ui_range_value_set(efl_super(obj, MY_CLASS), value); + + return EINA_TRUE; +} + +EOLIAN static void +_efl_ui_spin_button_efl_access_value_range_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED, double *lower, double *upper, const char **descr) +{ + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + + if (lower) *lower = pd->val_min; + if (upper) *upper = pd->val_max; + if (descr) *descr = NULL; +} + +EOLIAN static double +_efl_ui_spin_button_efl_access_value_increment_get(Eo *obj EINA_UNUSED, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED) +{ + Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); + + return pd->step; +} + +EOLIAN static const char* +_efl_ui_spin_button_efl_access_name_get(Eo *obj, Efl_Ui_Spin_Button_Data *sd EINA_UNUSED) +{ + const char *name; + name = efl_access_name_get(efl_super(obj, EFL_UI_SPIN_BUTTON_CLASS)); + if (name) return name; + const char *ret = elm_layout_text_get(obj, "elm.text"); + return ret; +} + +// A11Y Accessibility - END + +#define EFL_UI_SPIN_BUTTON_EXTRA_OPS \ + ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_spin_button), \ + +#include "efl_ui_spin_button.eo.c" diff --git a/src/lib/elementary/efl_ui_spin_button.eo b/src/lib/elementary/efl_ui_spin_button.eo new file mode 100644 index 0000000..06c604e --- /dev/null +++ b/src/lib/elementary/efl_ui_spin_button.eo @@ -0,0 +1,80 @@ +class Efl.Ui.Spin_Button (Efl.Ui.Spin, Efl.Ui.Focus.Composition, + Efl.Access.Value, Efl.Access.Widget.Action) +{ + [[A Button Spin. + + This is a widget which allows the user to increase or decrease + numeric values using arrow buttons, or edit values directly, clicking + over it and typing the new value. + + @since 1.21 + ]] + methods { + @property loop { + [[Control whether the spin should loop when it reaches its minimum or maximum value. + + Disabled by default. If disabled, when the user tries to increment the + value, + but displayed value plus step value is bigger than maximum value, + the new value will be the maximum value. + The same happens when the user tries to decrement it, + but the value less step is less than minimum value. In this case, + the new displayed value will be the minimum value. + + When loop is enabled, when the user tries to increment the value, + but displayed value plus step value is bigger than maximum value, + the new value will be the minimum value. When the the user tries to + decrement it, but the value less step is less than minimum value, + the new displayed value will be the maximum value. + + E.g.: + $min = 10 + $max = 50 + $step = 20 + $displayed = 20 + + When the user decrement value (using left or bottom arrow), it will + displays $50.]] + set { + } + get { + } + values { + loop: bool(false); [[$true to enable loop or $false to disable it.]] + } + } + @property editable { + [[Control whether the spin can be directly edited by the user or not. + + Spin objects can have edition disabled, in which state they will + be changed only by arrows. + Useful for contexts + where you don't want your users to interact with it writing the value. + Specially + when using special values, the user can see real value instead + of special label on edition.]] + set { + } + get { + } + values { + editable: bool(false); [[$true to allow users to edit it or $false to don't allow users to edit it directly.]] + } + } + } + implements { + Efl.Object.finalize; + Elm.Widget.theme_apply; + Elm.Widget.widget_event; + Elm.Widget.on_focus_update; + Efl.Ui.Range.range_value { set; } + Efl.Access.name { get; } + Efl.Access.Value.value_and_text { get; set; } + Efl.Access.Value.range { get; } + Efl.Access.Value.increment { get; } + Efl.Access.Widget.Action.elm_actions { get; } + } + events { + delay,changed; [[Called when spin delay changed]] + } +} diff --git a/src/lib/elementary/efl_ui_spin_button_private.h b/src/lib/elementary/efl_ui_spin_button_private.h new file mode 100644 index 0000000..4b59f7c --- /dev/null +++ b/src/lib/elementary/efl_ui_spin_button_private.h @@ -0,0 +1,20 @@ +#ifndef EFL_UI_SPIN_BUTTON_PRIVATE_H +#define EFL_UI_SPIN_BUTTON_PRIVATE_H + +typedef struct _Efl_Ui_Spin_Button_Data Efl_Ui_Spin_Button_Data; +struct _Efl_Ui_Spin_Button_Data +{ + double interval, first_interval; + Evas_Object *ent, *inc_button, *dec_button, *text_button; + Ecore_Timer *delay_change_timer; /**< a timer for a delay,changed smart callback */ + Ecore_Timer *spin_timer; /**< a timer for a repeated spinner value change on mouse down */ + Ecore_Timer *longpress_timer; /**< a timer to detect long press. After lonpress timeout, + start continuous change of values until mouse up */ + Eina_Bool entry_visible : 1; + Eina_Bool entry_reactivate : 1; + Eina_Bool editable : 1; + Eina_Bool inc_val : 1; + Eina_Bool loop : 1; +}; + +#endif diff --git a/src/lib/elementary/efl_ui_spin_private.h b/src/lib/elementary/efl_ui_spin_private.h new file mode 100644 index 0000000..a8065dc --- /dev/null +++ b/src/lib/elementary/efl_ui_spin_private.h @@ -0,0 +1,29 @@ +#ifndef EFL_UI_SPIN_PRIVATE_H +#define EFL_UI_SPIN_PRIVATE_H + +#include "Elementary.h" + +typedef enum _Efl_Ui_Spin_Format_Type +{ + SPIN_FORMAT_FLOAT, + SPIN_FORMAT_INT, + SPIN_FORMAT_INVALID +} Efl_Ui_Spin_Format_Type; + +typedef struct _Efl_Ui_Spin_Data Efl_Ui_Spin_Data; +struct _Efl_Ui_Spin_Data +{ + const char *templates; + double val, val_min, val_max; + double step; /**< step for the value change. 1 by default. */ + int decimal_points; + Ecore_Timer *spin_timer; /**< a timer for a repeated spin value change on mouse down */ + Efl_Ui_Spin_Format_Type format_type; + + Efl_Ui_Format_Func_Cb format_cb; + Eina_Free_Cb format_free_cb; + void *format_cb_data; + Eina_Strbuf *format_strbuf; +}; + +#endif diff --git a/src/lib/elementary/elm_flipselector.c b/src/lib/elementary/elm_flipselector.c index 6a80600..ac69bd6 100644 --- a/src/lib/elementary/elm_flipselector.c +++ b/src/lib/elementary/elm_flipselector.c @@ -470,7 +470,7 @@ _items_add(Evas_Object *obj) } EOLIAN static void -_elm_flipselector_efl_ui_spin_min_max_set(Eo *obj, Elm_Flipselector_Data *sd, double min, double max) +_elm_flipselector_efl_ui_range_range_min_max_set(Eo *obj, Elm_Flipselector_Data *sd, double min, double max) { if (min > max) return; if ((sd->val_min == min) && (sd->val_max == max)) return; @@ -482,14 +482,14 @@ _elm_flipselector_efl_ui_spin_min_max_set(Eo *obj, Elm_Flipselector_Data *sd, do } EOLIAN static void -_elm_flipselector_efl_ui_spin_min_max_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double *min, double *max) +_elm_flipselector_efl_ui_range_range_min_max_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double *min, double *max) { if (min) *min = sd->val_min; if (max) *max = sd->val_max; } EOLIAN static void -_elm_flipselector_efl_ui_spin_step_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double step) +_elm_flipselector_efl_ui_range_range_step_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double step) { if (sd->step == step) return; @@ -498,13 +498,13 @@ _elm_flipselector_efl_ui_spin_step_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Dat } EOLIAN static double -_elm_flipselector_efl_ui_spin_step_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd) +_elm_flipselector_efl_ui_range_range_step_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd) { return sd->step; } EOLIAN static double -_elm_flipselector_efl_ui_spin_value_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd) +_elm_flipselector_efl_ui_range_range_value_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd) { if (sd->val_min == 0 && sd->val_max == 0) { @@ -516,7 +516,7 @@ _elm_flipselector_efl_ui_spin_value_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Da } EOLIAN static void -_elm_flipselector_efl_ui_spin_value_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double val) +_elm_flipselector_efl_ui_range_range_value_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double val) { Eina_List *l; Elm_Object_Item *it; @@ -657,18 +657,6 @@ elm_flipselector_add(Evas_Object *parent) return elm_legacy_add(MY_CLASS, parent); } -EAPI void -elm_flipselector_first_interval_set(Evas_Object *obj, double interval) -{ - efl_ui_spin_interval_set(obj, interval); -} - -EAPI double -elm_flipselector_first_interval_get(const Evas_Object *obj) -{ - return efl_ui_spin_interval_get(obj); -} - EOLIAN static Eo * _elm_flipselector_efl_object_constructor(Eo *obj, Elm_Flipselector_Data *sd) { @@ -869,14 +857,14 @@ _elm_flipselector_item_next_get(const Eo *eo_item, return NULL; } -EOLIAN static void -_elm_flipselector_efl_ui_spin_interval_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double interval) +EOLIAN void +_elm_flipselector_first_interval_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double interval) { sd->first_interval = interval; } -EOLIAN static double -_elm_flipselector_efl_ui_spin_interval_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd) +EOLIAN double +_elm_flipselector_first_interval_get(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd) { return sd->first_interval; } diff --git a/src/lib/elementary/elm_flipselector.eo b/src/lib/elementary/elm_flipselector.eo index 964cc59..4ba48de 100644 --- a/src/lib/elementary/elm_flipselector.eo +++ b/src/lib/elementary/elm_flipselector.eo @@ -1,4 +1,4 @@ -class Elm.Flipselector (Efl.Ui.Layout, Efl.Ui.Spin, +class Elm.Flipselector (Efl.Ui.Layout, Efl.Ui.Range, Efl.Access.Widget.Action, Efl.Ui.Selectable) { @@ -60,6 +60,40 @@ class Elm.Flipselector (Efl.Ui.Layout, Efl.Ui.Spin, } } + @property first_interval { + set { + [[Set the interval on time updates for a user mouse button hold + on a flip selector widget. + + This interval value is decreased while the user holds the + mouse pointer either flipping up or flipping down a given flip + selector. + + This helps the user to get to a given item distant from the + current one easier/faster, as it will start to flip quicker and + quicker on mouse button holds. + + The calculation for the next flip interval value, starting from + the one set with this call, is the previous interval divided by + 1.05, so it decreases a little bit. + + The default starting interval value for automatic flips is + 0.85 seconds. + + See also @.first_interval.get. + ]] + } + get { + [[Get the interval on time updates for an user mouse button hold + on a flip selector widget. + + See also @.first_interval.set for more details. + ]] + } + values { + interval: double; [[The (first) interval value in seconds.]] + } + } item_prepend { [[Prepend a (text) item to a flip selector widget @@ -129,10 +163,9 @@ class Elm.Flipselector (Efl.Ui.Layout, Efl.Ui.Spin, Efl.Object.constructor; Elm.Widget.theme_apply; Elm.Widget.widget_event; - Efl.Ui.Spin.min_max { get; set; } - Efl.Ui.Spin.step { get; set; } - Efl.Ui.Spin.value { get; set; } - Efl.Ui.Spin.interval { get; set; } + Efl.Ui.Range.range_min_max { get; set; } + Efl.Ui.Range.range_step { get; set; } + Efl.Ui.Range.range_value { get; set; } Efl.Access.Widget.Action.elm_actions { get; } } events { diff --git a/src/lib/elementary/elm_flipselector_legacy.h b/src/lib/elementary/elm_flipselector_legacy.h index f928d35..a2fbd58 100644 --- a/src/lib/elementary/elm_flipselector_legacy.h +++ b/src/lib/elementary/elm_flipselector_legacy.h @@ -11,42 +11,5 @@ */ EAPI Evas_Object *elm_flipselector_add(Evas_Object *parent); -/** - * @brief Set the interval on time updates for a user mouse button hold on a - * flip selector widget. - * - * This interval value is decreased while the user holds the mouse pointer - * either flipping up or flipping down a given flip selector. - * - * This helps the user to get to a given item distant from the current one - * easier/faster, as it will start to flip quicker and quicker on mouse button - * holds. - * - * The calculation for the next flip interval value, starting from the one set - * with this call, is the previous interval divided by 1.05, so it decreases a - * little bit. - * - * The default starting interval value for automatic flips is 0.85 seconds. - * - * See also @ref elm_obj_flipselector_first_interval_get. - * - * @param[in] interval The (first) interval value in seconds. - * - * @ingroup Elm_Flipselector - */ -EAPI void elm_flipselector_first_interval_set(Evas_Object *obj, double interval); - -/** - * @brief Get the interval on time updates for an user mouse button hold on a - * flip selector widget. - * - * See also @ref elm_obj_flipselector_first_interval_set for more details. - * - * @return The (first) interval value in seconds. - * - * @ingroup Elm_Flipselector - */ -EAPI double elm_flipselector_first_interval_get(const Evas_Object *obj); - #include "elm_flipselector_item.eo.legacy.h" #include "elm_flipselector.eo.legacy.h" diff --git a/src/lib/elementary/elm_spinner.c b/src/lib/elementary/elm_spinner.c index 96fc4eb..b1de7ef 100644 --- a/src/lib/elementary/elm_spinner.c +++ b/src/lib/elementary/elm_spinner.c @@ -1359,49 +1359,37 @@ elm_spinner_add(Evas_Object *parent) EAPI void elm_spinner_min_max_set(Evas_Object *obj, double min, double max) { - efl_ui_spin_min_max_set(obj, min, max); + efl_ui_range_min_max_set(obj, min, max); } EAPI void elm_spinner_min_max_get(const Evas_Object *obj, double *min, double *max) { - efl_ui_spin_min_max_get(obj, min, max); + efl_ui_range_min_max_get(obj, min, max); } EAPI void elm_spinner_step_set(Evas_Object *obj, double step) { - efl_ui_spin_step_set(obj, step); + efl_ui_range_step_set(obj, step); } EAPI double elm_spinner_step_get(const Evas_Object *obj) { - return efl_ui_spin_step_get(obj); -} - -EAPI void -elm_spinner_interval_set(Evas_Object *obj, double interval) -{ - efl_ui_spin_interval_set(obj, interval); -} - -EAPI double -elm_spinner_interval_get(const Evas_Object *obj) -{ - return efl_ui_spin_interval_get(obj); + return efl_ui_range_step_get(obj); } EAPI void elm_spinner_value_set(Evas_Object *obj, double val) { - efl_ui_spin_value_set(obj, val); + efl_ui_range_value_set(obj, val); } EAPI double elm_spinner_value_get(const Evas_Object *obj) { - return efl_ui_spin_value_get(obj); + return efl_ui_range_value_get(obj); } EOLIAN static Eo * @@ -1447,7 +1435,7 @@ _elm_spinner_label_format_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd) } EOLIAN static void -_elm_spinner_efl_ui_spin_min_max_set(Eo *obj, Elm_Spinner_Data *sd, double min, double max) +_elm_spinner_efl_ui_range_range_min_max_set(Eo *obj, Elm_Spinner_Data *sd, double min, double max) { if ((sd->val_min == min) && (sd->val_max == max)) return; @@ -1462,26 +1450,26 @@ _elm_spinner_efl_ui_spin_min_max_set(Eo *obj, Elm_Spinner_Data *sd, double min, } EOLIAN static void -_elm_spinner_efl_ui_spin_min_max_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd, double *min, double *max) +_elm_spinner_efl_ui_range_range_min_max_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd, double *min, double *max) { if (min) *min = sd->val_min; if (max) *max = sd->val_max; } EOLIAN static void -_elm_spinner_efl_ui_spin_step_set(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd, double step) +_elm_spinner_efl_ui_range_range_step_set(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd, double step) { sd->step = step; } EOLIAN static double -_elm_spinner_efl_ui_spin_step_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd) +_elm_spinner_efl_ui_range_range_step_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd) { return sd->step; } EOLIAN static void -_elm_spinner_efl_ui_spin_value_set(Eo *obj, Elm_Spinner_Data *sd, double val) +_elm_spinner_efl_ui_range_range_value_set(Eo *obj, Elm_Spinner_Data *sd, double val) { if (sd->val == val) return; @@ -1504,7 +1492,7 @@ _elm_spinner_efl_ui_spin_value_set(Eo *obj, Elm_Spinner_Data *sd, double val) } EOLIAN static double -_elm_spinner_efl_ui_spin_value_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd) +_elm_spinner_efl_ui_range_range_value_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd) { return sd->val; } @@ -1601,13 +1589,13 @@ _elm_spinner_editable_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd) } EOLIAN static void -_elm_spinner_efl_ui_spin_interval_set(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd, double interval) +_elm_spinner_interval_set(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd, double interval) { sd->first_interval = interval; } EOLIAN static double -_elm_spinner_efl_ui_spin_interval_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd) +_elm_spinner_interval_get(Eo *obj EINA_UNUSED, Elm_Spinner_Data *sd) { return sd->first_interval; } diff --git a/src/lib/elementary/elm_spinner.eo b/src/lib/elementary/elm_spinner.eo index 8809167..f149610 100644 --- a/src/lib/elementary/elm_spinner.eo +++ b/src/lib/elementary/elm_spinner.eo @@ -1,4 +1,4 @@ -class Elm.Spinner (Efl.Ui.Layout, Efl.Ui.Spin, Efl.Ui.Focus.Composition, +class Elm.Spinner (Efl.Ui.Layout, Efl.Ui.Range, Efl.Ui.Focus.Composition, Efl.Access.Value, Efl.Access.Widget.Action) { [[Elementary spinner class]] @@ -39,6 +39,30 @@ class Elm.Spinner (Efl.Ui.Layout, Efl.Ui.Spin, Efl.Ui.Focus.Composition, wrap: bool; [[$true to enable wrap or $false to disable it.]] } } + @property interval { + [[Control the interval on time updates for an user mouse button hold on spinner widgets' arrows. + + This interval value is decreased while the user holds the + mouse pointer either incrementing or decrementing spinner's value. + + This helps the user to get to a given value distant from the + current one easier/faster, as it will start to change quicker and + quicker on mouse button holds. + + The calculation for the next change interval value, starting from + the one set with this call, is the previous interval divided by + $1.05, so it decreases a little bit. + + The default starting interval value for automatic changes is + $0.85 seconds.]] + set { + } + get { + } + values { + interval: double; [[The (first) interval value in seconds.]] + } + } @property round { [[Control the round value for rounding @@ -150,10 +174,9 @@ class Elm.Spinner (Efl.Ui.Layout, Efl.Ui.Spin, Efl.Ui.Focus.Composition, Elm.Widget.on_access_update; Elm.Widget.on_focus_update; Elm.Widget.widget_event; - Efl.Ui.Spin.min_max { get; set; } - Efl.Ui.Spin.step { get; set; } - Efl.Ui.Spin.value { get; set; } - Efl.Ui.Spin.interval { get; set; } + Efl.Ui.Range.range_min_max { get; set; } + Efl.Ui.Range.range_step { get; set; } + Efl.Ui.Range.range_value { get; set; } Efl.Access.name { get; } Efl.Access.Value.value_and_text { get; set; } Efl.Access.Value.range { get; } diff --git a/src/lib/elementary/elm_spinner_legacy.h b/src/lib/elementary/elm_spinner_legacy.h index a09c19d..8c4812b 100644 --- a/src/lib/elementary/elm_spinner_legacy.h +++ b/src/lib/elementary/elm_spinner_legacy.h @@ -119,52 +119,6 @@ EAPI void elm_spinner_step_set(Evas_Object *obj, double step); EAPI double elm_spinner_step_get(const Evas_Object *obj); /** - * @brief Control the interval on time updates for an user mouse button hold on - * spinner widgets' arrows. - * - * This interval value is decreased while the user holds the mouse pointer - * either incrementing or decrementing spinner's value. - * - * This helps the user to get to a given value distant from the current one - * easier/faster, as it will start to change quicker and quicker on mouse - * button holds. - * - * The calculation for the next change interval value, starting from the one - * set with this call, is the previous interval divided by $1.05, so it - * decreases a little bit. - * - * The default starting interval value for automatic changes is $0.85 seconds. - * - * @param[in] interval The (first) interval value in seconds. - * - * @ingroup Elm_Spinner - */ -EAPI void elm_spinner_interval_set(Evas_Object *obj, double interval); - -/** - * @brief Control the interval on time updates for an user mouse button hold on - * spinner widgets' arrows. - * - * This interval value is decreased while the user holds the mouse pointer - * either incrementing or decrementing spinner's value. - * - * This helps the user to get to a given value distant from the current one - * easier/faster, as it will start to change quicker and quicker on mouse - * button holds. - * - * The calculation for the next change interval value, starting from the one - * set with this call, is the previous interval divided by $1.05, so it - * decreases a little bit. - * - * The default starting interval value for automatic changes is $0.85 seconds. - * - * @return The (first) interval value in seconds. - * - * @ingroup Elm_Spinner - */ -EAPI double elm_spinner_interval_get(const Evas_Object *obj); - -/** * @brief Control the value the spinner displays. * * Value will be presented on the label following format specified with