From ef2e6afd1f7c890297900937fa1f12f0f4f76980 Mon Sep 17 00:00:00 2001 From: Woochan Lee Date: Wed, 25 Apr 2018 16:43:53 +0900 Subject: [PATCH] Intrudoce Efl Ui Date, Time interface and picker. Summary: Create datepicker, timepicker with one manager class(efl_datetime). Test Plan: datepicker, timepicker sample. Reviewers: herb, Jaehyun_Cho, woohyun, SanghyeonLee Reviewed By: Jaehyun_Cho Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D5871 --- data/elementary/themes/Makefile.am | 2 + data/elementary/themes/colorclasses.edc | 8 + data/elementary/themes/default.edc | 2 + data/elementary/themes/edc/efl/datepicker.edc | 345 +++++++++++++++ .../elementary/themes/edc/efl/spin_button.edc | 4 + data/elementary/themes/edc/efl/timepicker.edc | 409 ++++++++++++++++++ data/elementary/themes/edc/elm/entry.edc | 2 - src/Makefile_Elementary.am | 10 + src/bin/elementary/Makefile.am | 2 + src/bin/elementary/test.c | 4 + src/bin/elementary/test_ui_datepicker.c | 37 ++ src/bin/elementary/test_ui_timepicker.c | 36 ++ src/lib/elementary/Elementary.h | 2 + src/lib/elementary/efl_datetime_manager.c | 193 +++++++++ src/lib/elementary/efl_datetime_manager.eo | 50 +++ src/lib/elementary/efl_ui_datepicker.c | 349 +++++++++++++++ src/lib/elementary/efl_ui_datepicker.eo | 75 ++++ .../elementary/efl_ui_datepicker_private.h | 22 + src/lib/elementary/efl_ui_spin_button.c | 9 +- src/lib/elementary/efl_ui_timepicker.c | 285 ++++++++++++ src/lib/elementary/efl_ui_timepicker.eo | 44 ++ .../elementary/efl_ui_timepicker_private.h | 21 + src/lib/elementary/elm_config.c | 2 + src/lib/elementary/elm_priv.h | 1 + 24 files changed, 1905 insertions(+), 9 deletions(-) create mode 100644 data/elementary/themes/edc/efl/datepicker.edc create mode 100644 data/elementary/themes/edc/efl/timepicker.edc create mode 100644 src/bin/elementary/test_ui_datepicker.c create mode 100644 src/bin/elementary/test_ui_timepicker.c create mode 100644 src/lib/elementary/efl_datetime_manager.c create mode 100644 src/lib/elementary/efl_datetime_manager.eo create mode 100644 src/lib/elementary/efl_ui_datepicker.c create mode 100644 src/lib/elementary/efl_ui_datepicker.eo create mode 100644 src/lib/elementary/efl_ui_datepicker_private.h create mode 100644 src/lib/elementary/efl_ui_timepicker.c create mode 100644 src/lib/elementary/efl_ui_timepicker.eo create mode 100644 src/lib/elementary/efl_ui_timepicker_private.h diff --git a/data/elementary/themes/Makefile.am b/data/elementary/themes/Makefile.am index 8ae08444af..992d5ca500 100644 --- a/data/elementary/themes/Makefile.am +++ b/data/elementary/themes/Makefile.am @@ -1035,6 +1035,8 @@ elementary/themes/edc/efl/scroller.edc \ elementary/themes/edc/efl/slider.edc \ elementary/themes/edc/efl/spin.edc \ elementary/themes/edc/efl/spin_button.edc \ +elementary/themes/edc/efl/datepicker.edc \ +elementary/themes/edc/efl/timepicker.edc \ elementary/themes/edc/efl/text.edc \ elementary/themes/edc/efl/textpath.edc \ elementary/themes/edc/efl/tooltip.edc \ diff --git a/data/elementary/themes/colorclasses.edc b/data/elementary/themes/colorclasses.edc index bf294bfe1c..2500ce7ab4 100644 --- a/data/elementary/themes/colorclasses.edc +++ b/data/elementary/themes/colorclasses.edc @@ -208,6 +208,14 @@ color_classes { color: 0 0 0 0; desc: "Background of a datetime widget"; } + color_class { name: "datepicker_bg"; + color: 0 0 0 0; + desc: "Background of a datepicker widget"; + } + color_class { name: "timepicker_bg"; + color: 0 0 0 0; + desc: "Background of a timepicker widget"; + } color_class { name: "datetime_separator_text"; color: FN_COL_DEFAULT; desc: "Text in a datetime separator area"; diff --git a/data/elementary/themes/default.edc b/data/elementary/themes/default.edc index 00f8973c8b..67fbd78720 100644 --- a/data/elementary/themes/default.edc +++ b/data/elementary/themes/default.edc @@ -190,6 +190,8 @@ collections { #include "edc/efl/border.edc" #include "edc/efl/spin.edc" #include "edc/efl/spin_button.edc" +#include "edc/efl/datepicker.edc" +#include "edc/efl/timepicker.edc" // XXX: min size calc problems - too wide! ... err ok on my 32bit box... eh? #include "edc/efl/cursor.edc" #include "edc/efl/pointer.edc" diff --git a/data/elementary/themes/edc/efl/datepicker.edc b/data/elementary/themes/edc/efl/datepicker.edc new file mode 100644 index 0000000000..f0fa470313 --- /dev/null +++ b/data/elementary/themes/edc/efl/datepicker.edc @@ -0,0 +1,345 @@ +group { "efl/datepicker"; + parts { + spacer { "base"; + scale; + desc { "default"; + min: 150 170; + } + } + rect { "base_bg"; + scale; + desc { "default"; + rel.to: "base"; + color_class: "datepicker_bg"; + } + } + spacer { "padding_bg_top"; + scale; + desc { "default"; + min: 0 10; + max: -1 10; + fixed: 0 1; + rel1 { + relative: 0.0 0.0; + to: "base_bg"; + } + rel2 { + relative: 1.0 0.0; + to: "base_bg"; + } + align: 0.5 0.0; + } + } + spacer { "padding_bg_bottom"; + scale; + desc { "default"; + min: 0 10; + max: -1 10; + fixed: 0 1; + rel1 { + relative: 0.0 1.0; + to: "base_bg"; + } + rel2 { + relative: 1.0 1.0; + to: "base_bg"; + } + align: 0.5 1.0; + } + } + spacer { "bg"; + scale; + desc { "default"; + min: 150 150; + max: 150 150; + rel1 { + relative: 0.0 1.0; + to: "padding_bg_top"; + } + rel2 { + relative: 1.0 0.0; + to: "padding_bg_bottom"; + } + } + } + spacer { "padding_left"; + scale; + desc { "default"; + min: 5 0; + max: 5 -1; + fixed: 1 0; + rel1 { + relative: 0.0 0.0; + to: "bg"; + } + rel2 { + relative: 0.0 1.0; + to: "bg"; + } + align: 0.0 0.0; + } + } + spacer { "padding_right"; + scale; + desc { "default"; + min: 5 0; + max: 5 -1; + fixed: 1 0; + rel2.to: "bg"; + rel1 { + relative: 1.0 0.0; + to: "bg"; + } + rel2 { + relative: 1.0 1.0; + to: "bg"; + } + align: 1.0 1.0; + } + } + swallow { "field0"; + mouse; + scale; + desc { "default"; + fixed: 1 0; + min: 40 0; + rel1 { + relative: 1.0 0.0; + to: "padding_left"; + } + rel2.to: "padding_left"; + align: 0.0 0.5; + } + } + spacer { "padding_center1"; + scale; + desc { "default"; + fixed: 1 0; + min: 10 0; + max: 10 -1; + rel1 { + relative: 1.0 0.0; + to: "field0"; + } + rel2.to: "field0"; + align: 0.0 0.5; + } + } + swallow { "field1"; + mouse; + scale; + desc { "default"; + fixed: 1 0; + min: 40 0; + rel1 { + relative: 1.0 0.0; + to: "padding_center1"; + } + rel2 { + relative: 0.0 1.0; + to_x: "padding_center2"; + to_y: "padding_center1"; + } + } + } + spacer { "padding_center2"; + scale; + desc { "default"; + fixed: 1 0; + min: 10 0; + max: 10 -1; + rel1.to: "field2"; + rel2 { + relative: 0.0 1.0; + to: "field2"; + } + align: 1.0 0.5; + } + } + swallow { "field2"; + mouse; + scale; + desc { "default"; + fixed: 1 0; + min: 40 0; + rel1.to: "padding_right"; + rel2 { + relative: 0.0 1.0; + to: "padding_right"; + } + align: 1.0 0.5; + } + } + rect { "access"; + repeat; + desc { "default"; + fixed: 1 1; + rel1.to: "bg"; + rel2.to: "bg"; + color: 0 0 0 0; + } + } + } +} + +group { "efl/datepicker/spin_button"; + parts { + rect { "clip"; + desc { "default"; + rel.to: "elm.swallow.text_button"; + } + } + spacer { "base"; + scale; + desc { "default"; + min: 40 150; + } + } + rect { "bg"; + scale; + desc { "default"; + color_class: "spinner_bg"; + } + } + rect { "access"; + repeat; + desc { "default"; + fixed: 1 1; + color: 0 0 0 0; + rel1.to: "base"; + rel2.to: "base"; + hid; + } + desc { "active"; + inherit: "default"; + vis; + } + } + swallow { "elm.swallow.inc_button"; + scale; + desc { "default"; + align: 0.5 0.0; + min: 40 40; + max: 40 40; + fixed: 1 1; + } + } + swallow { "elm.swallow.dec_button"; + scale; + desc { "default"; + align: 0.5 1.0; + min: 40 40; + max: 40 40; + fixed: 1 1; + } + } + swallow { "elm.swallow.entry"; + clip: "clip"; + desc { "default"; + fixed: 1 1; + rel1.to: "elm.swallow.text_button"; + rel2.to: "elm.swallow.text_button"; + hid; + } + desc { "active"; + inherit: "default"; + vis; + } + } + swallow { "elm.swallow.text_button"; + scale; + desc { "default"; + rel.to_x: "base"; + rel1 { + to_y: "elm.swallow.inc_button"; + relative: 0.0 1.0; + } + rel2 { + to_y: "elm.swallow.dec_button"; + relative: 1.0 0.0; + } + min: 0 70; + max: -1 70; + fixed: 0 1; + } + desc { "inactive"; + inherit: "default"; + hid; + } + } + rect { "disabler"; + norepeat; + nomouse; + desc { "default"; + color: 0 0 0 0; + hid; + } + desc { "disabled"; + inherit: "default"; + vis; + } + } + } + programs { + program { "entry_active"; + signal: "elm,state,entry,active"; + source: "elm"; + action: STATE_SET "active"; + target: "elm.swallow.entry"; + } + program { "entry_inactive"; + signal: "elm,state,entry,inactive"; + source: "elm"; + action: STATE_SET "default"; + target: "elm.swallow.entry"; + } + program { "text_button_active"; + signal: "elm,state,button,active"; + source: "elm"; + action: STATE_SET "default"; + target: "elm.swallow.text_button"; + } + program { "text_button_inactive"; + signal: "elm,state,button,inactive"; + source: "elm"; + action: STATE_SET "inactive"; + target: "elm.swallow.text_button"; + } + program { "access_activate"; + signal: "elm,state,access,active"; + source: "elm"; + action: STATE_SET "active"; + target: "access"; + } + program { "access_inactivate"; + signal: "elm,state,access,inactive"; + source: "elm"; + action: STATE_SET "default"; + target: "access"; + } + program { "disable"; + signal: "elm,state,disabled"; + source: "elm"; + action: STATE_SET "disabled"; + target: "disabler"; + } + program { "enable"; + signal: "elm,state,enabled"; + source: "elm"; + action: STATE_SET "default"; + target: "disabler"; + } + } +} + +group { "efl/datepicker/spin_button/text_button"; + inherit: "efl/spin_button/text_button"; +} + +group { "efl/datepicker/spin_button/inc_button"; + inherit: "elm/button/base/spinner/increase/vertical"; +} + +group { "efl/datepicker/spin_button/dec_button"; + inherit: "elm/button/base/spinner/decrease/vertical"; +} diff --git a/data/elementary/themes/edc/efl/spin_button.edc b/data/elementary/themes/edc/efl/spin_button.edc index 4d502e3779..1873c9c422 100644 --- a/data/elementary/themes/edc/efl/spin_button.edc +++ b/data/elementary/themes/edc/efl/spin_button.edc @@ -356,6 +356,10 @@ group { name: "efl/spin_button/inc_button"; } } +group { "efl/spin_button/entry"; + inherit: "efl/text"; +} + group { name: "efl/spin_button/dec_button"; inherit: "efl/spin_button/inc_button"; images.image: "sym_left_light_normal.png" COMP; diff --git a/data/elementary/themes/edc/efl/timepicker.edc b/data/elementary/themes/edc/efl/timepicker.edc new file mode 100644 index 0000000000..a33ada0d4a --- /dev/null +++ b/data/elementary/themes/edc/efl/timepicker.edc @@ -0,0 +1,409 @@ +group { "efl/timepicker"; + nomouse; + parts { + spacer { "base"; + scale; + desc { "default"; + min: 150 170; + } + desc { "24layout"; + min: 110 170; + } + } + rect { "base_bg"; + scale; + desc { "default"; + rel.to: "base"; + color_class: "timepicker_bg"; + } + } + spacer { "padding_bg_top"; + scale; + desc { "default"; + min: 0 10; + max: -1 10; + fixed: 0 1; + rel1 { + relative: 0.0 0.0; + to: "base_bg"; + } + rel2 { + relative: 1.0 0.0; + to: "base_bg"; + } + align: 0.5 0.0; + } + } + spacer { "padding_bg_bottom"; + scale; + desc { "default"; + min: 0 10; + max: -1 10; + fixed: 0 1; + rel1 { + relative: 0.0 1.0; + to: "base_bg"; + } + rel2 { + relative: 1.0 1.0; + to: "base_bg"; + } + align: 0.5 1.0; + } + } + spacer { "bg"; + scale; + desc { "default"; + min: 150 150; + max: 150 150; + rel1 { + relative: 0.0 1.0; + to: "padding_bg_top"; + } + rel2 { + relative: 1.0 0.0; + to: "padding_bg_bottom"; + } + } + desc { "24layout"; + inherit: "default"; + min: 110 150; + max: 110 150; + } + } + spacer { "padding_left"; + scale; + desc { "default"; + min: 0 0; + max: 0 -1; + fixed: 1 0; + rel1 { + relative: 0.0 0.0; + to: "bg"; + } + rel2 { + relative: 0.0 1.0; + to: "bg"; + } + align: 0.0 0.0; + } + } + spacer { "padding_right"; + scale; + desc { "default"; + min: 0 0; + max: 0 -1; + fixed: 1 0; + rel1 { + relative: 1.0 0.0; + to: "bg"; + } + rel2 { + relative: 1.0 1.0; + to: "bg"; + } + align: 1.0 1.0; + } + } + swallow { "field0"; + mouse; + scale; + desc { "default"; + fixed: 1 0; + min: 40 0; + rel1 { + relative: 1.0 0.0; + to: "padding_left"; + } + rel2.to: "padding_left"; + align: 0.0 0.5; + } + } + spacer{ "padding_center1"; + scale; + desc { "default"; + fixed: 1 0; + min: 3 0; + max: 3 -1; + rel1 { + relative: 1.0 0.0; + to: "field0"; + } + rel2.to: "field0"; + align: 0.0 0.5; + } + desc { "invisible"; + inherit: default 0.0; + min: 15 0; + max: 15 -1; + } + } + spacer { "bg_text"; + scale; + desc { "default"; + rel1 { + relative: 1.0 0.0; + to: "padding_center1"; + } + rel2.to: "padding_center1"; + align: 0.0 0.5; + min: 9 0; + max: 9 -1; + fixed: 1 0; + } + desc { "invisible"; + inherit: default 0.0; + min: 0 0; + max: 0 0; + } + } + text { "hour_minute_colon"; + scale; + desc { "default"; + rel1.to: "bg_text"; + rel2.to: "bg_text"; + color: 255 255 255 255; + fixed: 1 1; + text { + min: 1 0; + font: "Sans"; + size: "15"; + //text: ":"; + align: 0.5 0.44; + } + vis; + } + desc { "invisible"; + inherit: default 0.0; + hid; + } + } + spacer { "padding_center2"; + scale; + desc { "default"; + fixed: 1 0; + min: 3 0; + max: 3 -1; + rel1 { + relative: 1.0 0.0; + to: "bg_text"; + } + rel2.to: "bg_text"; + align: 0.0 0.5; + } + desc { "invisible"; + inherit: default 0.0; + min: 0 0; + max: 0 0; + } + } + swallow { "field1"; + mouse; + scale; + desc { "default"; + fixed: 1 0; + min: 40 0; + rel1 { + relative: 1.0 0.0; + to: "padding_center2"; + } + rel2.to: "padding_center2"; + align: 0.0 0.5; + } + } + spacer { "padding_center3"; + scale; + desc { "default"; + fixed: 1 0; + min: 3 0; + max: 3 -1; + rel1 { + relative: 1.0 0.0; + to: "field1"; + } + rel2.to: "field1"; + align: 0.0 0.5; + } + desc { "invisible"; + inherit: default 0.0; + min: 15 0; + max: 15 -1; + } + } + spacer { "bg_text2"; + scale; + desc { "default"; + rel1 { + relative: 1.0 0.0; + to: "padding_center3"; + } + rel2.to: "padding_center3"; + align: 0.0 0.5; + min: 9 0; + max: 9 -1; + fixed: 1 0; + } + desc { "invisible"; + inherit: default 0.0; + min: 0 0; + max: 0 0; + } + } + text { "hour_minute_colon2"; + scale; + desc { "default"; + rel1.to: "bg_text2"; + rel2.to: "bg_text2"; + color: 255 255 255 255; + fixed: 1 1; + text { + min: 1 0; + font: "Sans"; + size: "15"; + //text: ":"; + align: 0.5 0.44; + } + vis; + } + desc { "invisible"; + inherit: default 0.0; + hid; + } + } + spacer { "padding_center4"; + scale; + desc { "default"; + fixed: 1 0; + min: 3 0; + max: 3 -1; + rel1 { + relative: 1.0 0.0; + to: "bg_text2"; + } + rel2.to: "bg_text2"; + align: 0.0 0.5; + } + desc { "invisible"; + inherit: default 0.0; + min: 0 0; + max: 0 0; + } + } + swallow { "field2"; + mouse; + scale; + desc { "default"; + fixed: 1 0; + min: 40 0; + max: 40 -1; + rel1 { + relative: 1.0 0.0; + to: "padding_center4"; + } + rel2.to: "padding_center4"; + align: 0.0 0.5; + } + desc { "24layout"; + hid; + min: 0 0; + max: 0 -1; + } + } + rect { "access"; + repeat; + desc { "default"; + fixed: 1 1; + rel1.to: "bg"; + rel2.to: "bg"; + color: 0 0 0 0; + } + } + } + programs { + program { "visible_ampm"; + signal: "elm,state,ampm,visible"; + source: "elm"; + script { + set_state(PART:"base", "default", 0.0); + set_state(PART:"bg", "default", 0.0); + set_state(PART:"field2", "default", 0.0); + } + } + program { "invisible_ampm"; + signal: "elm,state,ampm,invisible"; + source: "elm"; + script { + set_state(PART:"base", "24layout", 0.0); + set_state(PART:"bg", "24layout", 0.0); + set_state(PART:"field2", "24layout", 0.0); + } + } + program { "visible_colon_field0"; + signal: "elm,state,colon,visible,field0"; + source: "elm"; + action: STATE_SET "default"; + target: "padding_center1"; + target: "hour_minute_colon"; + target: "bg_text"; + target: "padding_center2"; + } + program { "invisible_colon_field0"; + signal: "elm,state,colon,invisible,field0"; + source: "elm"; + action: STATE_SET "invisible"; + target: "padding_center1"; + target: "hour_minute_colon"; + target: "bg_text"; + target: "padding_center2"; + } + program { "visible_colon_field1"; + signal: "elm,state,colon,visible,field1"; + source: "elm"; + action: STATE_SET "default"; + target: "padding_center3"; + target: "hour_minute_colon2"; + target: "bg_text2"; + target: "padding_center4"; + } + program { "invisible_colon_field1"; + signal: "elm,state,colon,invisible,field1"; + source: "elm"; + action: STATE_SET "invisible"; + target: "padding_center3"; + target: "hour_minute_colon2"; + target: "bg_text2"; + target: "padding_center4"; + } + } +} + +group { "efl/timepicker/spin_button"; + inherit: "efl/datepicker/spin_button"; +} + +group { "efl/timepicker/spin_button/text_button"; + inherit: "efl/spin_button/text_button"; +} + +group { "efl/timepicker/spin_button/inc_button"; + inherit: "elm/button/base/spinner/increase/vertical"; +} + +group { "efl/timepicker/spin_button/dec_button"; + inherit: "elm/button/base/spinner/decrease/vertical"; +} +group { "efl/timepicker/button"; + inherit: "efl/button"; + parts { + image { "base"; + desc { "default"; + min: 40 40; + max: 40 40; + } + desc { "pressed"; + min: 40 40; + max: 40 40; + } + } + } +} diff --git a/data/elementary/themes/edc/elm/entry.edc b/data/elementary/themes/edc/elm/entry.edc index 189bf968d7..303857db07 100644 --- a/data/elementary/themes/edc/elm/entry.edc +++ b/data/elementary/themes/edc/elm/entry.edc @@ -854,8 +854,6 @@ 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/src/Makefile_Elementary.am b/src/Makefile_Elementary.am index e6a4059fde..d101d85bdb 100644 --- a/src/Makefile_Elementary.am +++ b/src/Makefile_Elementary.am @@ -27,6 +27,8 @@ elm_public_eolian_files = \ lib/elementary/efl_ui_slider_interval.eo \ lib/elementary/efl_ui_spin.eo \ lib/elementary/efl_ui_spin_button.eo \ + lib/elementary/efl_ui_datepicker.eo \ + lib/elementary/efl_ui_timepicker.eo \ lib/elementary/efl_ui_video.eo \ lib/elementary/efl_ui_win.eo \ lib/elementary/efl_ui_win_inlined.eo \ @@ -145,6 +147,7 @@ elm_private_eolian_files = \ tests/elementary/focus_test.eo \ tests/elementary/focus_test_sub_main.eo \ lib/elementary/efl_selection_manager.eo \ + lib/elementary/efl_datetime_manager.eo \ $(NULL) # Legacy classes - not part of public EO API @@ -382,6 +385,8 @@ includesunstable_HEADERS = \ lib/elementary/elm_widget_spinner.h \ lib/elementary/efl_ui_spin_private.h \ lib/elementary/efl_ui_spin_button_private.h \ + lib/elementary/efl_ui_datepicker_private.h \ + lib/elementary/efl_ui_timepicker_private.h \ lib/elementary/elm_widget_table.h \ lib/elementary/elm_widget_thumb.h \ lib/elementary/elm_widget_toolbar.h \ @@ -742,6 +747,8 @@ lib_elementary_libelementary_la_SOURCES = \ lib/elementary/efl_ui_slider_interval.c \ lib/elementary/efl_ui_spin.c \ lib/elementary/efl_ui_spin_button.c \ + lib/elementary/efl_ui_datepicker.c \ + lib/elementary/efl_ui_timepicker.c \ lib/elementary/elm_slideshow.c \ lib/elementary/elm_spinner.c \ lib/elementary/elm_store.c \ @@ -812,6 +819,7 @@ lib_elementary_libelementary_la_SOURCES = \ lib/elementary/efl_selection_manager.c \ lib/elementary/efl_selection_manager_private.h \ lib/elementary/efl_selection.c \ + lib/elementary/efl_datetime_manager.c \ lib/elementary/efl_ui_dnd.c \ static_libs/buildsystem/buildsystem.h \ static_libs/buildsystem/buildsystem_autotools.c \ @@ -1000,6 +1008,8 @@ bin/elementary/test_ui_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_ui_datepicker.c \ +bin/elementary/test_ui_timepicker.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 0749293876..57c6035b79 100644 --- a/src/bin/elementary/Makefile.am +++ b/src/bin/elementary/Makefile.am @@ -133,6 +133,8 @@ test_slideshow.c \ test_spinner.c \ test_ui_spinner.c \ test_ui_buttonspin.c \ +test_ui_datepicker.c \ +test_ui_timepicker.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 4ef1ac78d6..3bd23e908f 100644 --- a/src/bin/elementary/test.c +++ b/src/bin/elementary/test.c @@ -183,6 +183,8 @@ void test_efl_ui_scroller2(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_ui_datepicker(void *data, Evas_Object *obj, void *event_info); +void test_ui_timepicker(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); @@ -1084,6 +1086,8 @@ add_tests: ADD_TEST(NULL, "Times & Dates", "Datetime", test_datetime); ADD_TEST_EO(NULL, "Times & Dates", "Efl.Ui.Calendar", test_efl_ui_calendar); ADD_TEST_EO(NULL, "Times & Dates", "Efl.Ui.Clock", test_ui_clock); + ADD_TEST_EO(NULL, "Times & Dates", "Efl.Ui.Datepicker", test_ui_datepicker); + ADD_TEST_EO(NULL, "Times & Dates", "Efl.Ui.Timepicker", test_ui_timepicker); //------------------------------// ADD_TEST(NULL, "Text", "Label", test_label); diff --git a/src/bin/elementary/test_ui_datepicker.c b/src/bin/elementary/test_ui_datepicker.c new file mode 100644 index 0000000000..1eb04612b1 --- /dev/null +++ b/src/bin/elementary/test_ui_datepicker.c @@ -0,0 +1,37 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#include + +static void +_date_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + int year, month, day; + + efl_ui_datepicker_date_get(ev->object, &year, &month, &day); + printf("Current date is %d %d %d\n", year, month, day); +} + +void +test_ui_datepicker(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Eo *win, *bx; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Datepicker"), + 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_DATEPICKER_CLASS, bx, + efl_ui_datepicker_date_set(efl_added, 1987, 9, 17), + efl_ui_datepicker_max_set(efl_added, 1990, 9, 17), + efl_ui_datepicker_min_set(efl_added, 1980, 9, 17), + efl_event_callback_add(efl_added, EFL_UI_DATEPICKER_EVENT_CHANGED,_date_changed_cb, NULL), + efl_pack(bx, efl_added)); + + efl_gfx_entity_size_set(win, EINA_SIZE2D(150, 170)); +} diff --git a/src/bin/elementary/test_ui_timepicker.c b/src/bin/elementary/test_ui_timepicker.c new file mode 100644 index 0000000000..cb88ef508b --- /dev/null +++ b/src/bin/elementary/test_ui_timepicker.c @@ -0,0 +1,36 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif +#include + +static void +_time_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + int hour, min; + + efl_ui_timepicker_time_get(ev->object, &hour, &min); + printf("Current time is %d %d\n", hour, min); +} + + +void +test_ui_timepicker(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Eo *win, *bx; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "Efl.Ui.Timepicker"), + 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_TIMEPICKER_CLASS, bx, + efl_ui_timepicker_time_set(efl_added, 11, 35), + efl_event_callback_add(efl_added, EFL_UI_TIMEPICKER_EVENT_CHANGED,_time_changed_cb, NULL), + efl_pack(bx, efl_added)); + + efl_gfx_entity_size_set(win, EINA_SIZE2D(150, 170)); +} diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h index 0a79fbb60e..2853ba26e9 100644 --- a/src/lib/elementary/Elementary.h +++ b/src/lib/elementary/Elementary.h @@ -319,6 +319,8 @@ typedef Eo Efl_Ui_Focus_Manager; # include # include # include +# include +# include # include # include # include diff --git a/src/lib/elementary/efl_datetime_manager.c b/src/lib/elementary/efl_datetime_manager.c new file mode 100644 index 0000000000..8739be8251 --- /dev/null +++ b/src/lib/elementary/efl_datetime_manager.c @@ -0,0 +1,193 @@ +#include +#include "Efl.h" + +#ifdef HAVE_LANGINFO_H +# include +#endif + +#include +#include "elm_priv.h" + +#define MY_CLASS EFL_DATETIME_MANAGER_CLASS + +#define MAX_FORMAT_LEN 32 + +static const char *multifield_formats = "cxXrRTDF"; + +typedef struct +{ + Efl_Time time; + char format[MAX_FORMAT_LEN]; +} Efl_Datetime_Manager_Data; + +Eina_Bool init = EINA_FALSE; + +static void +_time_init(Efl_Time *curr_time) +{ + time_t t; + + t = time(NULL); + localtime_r(&t, curr_time); + + init = EINA_TRUE; +} + +static char * +_expanded_fmt_str_get(char ch) +{ + char *exp_fmt = ""; + switch (ch) + { + case 'c': +#if defined(HAVE_LANGINFO_H) || defined (_WIN32) + exp_fmt = nl_langinfo(D_T_FMT); +#else + exp_fmt = ""; +#endif + break; + + case 'x': +#if defined(HAVE_LANGINFO_H) || defined (_WIN32) + exp_fmt = nl_langinfo(D_FMT); +#else + exp_fmt = ""; +#endif + break; + + case 'X': +#if defined(HAVE_LANGINFO_H) || defined (_WIN32) + exp_fmt = nl_langinfo(T_FMT); +#else + exp_fmt = ""; +#endif + break; + + case 'r': +#if defined(HAVE_LANGINFO_H) || defined (_WIN32) + exp_fmt = nl_langinfo(T_FMT_AMPM); +#else + exp_fmt = ""; +#endif + break; + + case 'R': + exp_fmt = "%H:%M"; + break; + + case 'T': + exp_fmt = "%H:%M:%S"; + break; + + case 'D': + exp_fmt = "%m/%d/%y"; + break; + + case 'F': + exp_fmt = "%Y-%m-%d"; + break; + + default: + exp_fmt = ""; + break; + } + + return exp_fmt; +} + +static void +_expand_format(char *dt_fmt) +{ + char *ptr, *expanded_fmt, ch; + unsigned int idx, len = 0; + char buf[MAX_FORMAT_LEN] = {0, }; + Eina_Bool fmt_char, fmt_expanded; + + do { + idx = 0; + fmt_char = EINA_FALSE; + fmt_expanded = EINA_FALSE; + ptr = dt_fmt; + while ((ch = *ptr)) + { + if ((fmt_char) && (strchr(multifield_formats, ch))) + { + /* replace the multi-field format characters with + * corresponding expanded format */ + expanded_fmt = _expanded_fmt_str_get(ch); + len = strlen(expanded_fmt); + if (len > 0) fmt_expanded = EINA_TRUE; + buf[--idx] = 0; + strncat(buf, expanded_fmt, len); + idx += len; + } + else buf[idx++] = ch; + + if (ch == '%') fmt_char = EINA_TRUE; + else fmt_char = EINA_FALSE; + + ptr++; + } + + buf[idx] = 0; + strncpy(dt_fmt, buf, MAX_FORMAT_LEN); + } while (fmt_expanded); +} + +EOLIAN static Eo* +_efl_datetime_manager_efl_object_constructor(Eo *obj, Efl_Datetime_Manager_Data *pd EINA_UNUSED) +{ + obj = efl_constructor(efl_super(obj, MY_CLASS)); + + return obj; +} + + +EOLIAN static void +_efl_datetime_manager_efl_object_destructor(Eo *obj, Efl_Datetime_Manager_Data *pd EINA_UNUSED) +{ + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static void +_efl_datetime_manager_value_set(Eo *obj EINA_UNUSED, Efl_Datetime_Manager_Data *pd, Efl_Time newtime) +{ + pd->time = newtime; +} + +EOLIAN static Efl_Time +_efl_datetime_manager_value_get(const Eo *obj EINA_UNUSED, Efl_Datetime_Manager_Data *pd) +{ + if (!init) _time_init(&pd->time); + + return pd->time; +} + +EOLIAN static void +_efl_datetime_manager_format_set(Eo *obj EINA_UNUSED, Efl_Datetime_Manager_Data *pd EINA_UNUSED, const char *fmt EINA_UNUSED) +{ + //Is this needed? +} + +EOLIAN static const char * +_efl_datetime_manager_format_get(const Eo *obj EINA_UNUSED, Efl_Datetime_Manager_Data *pd) +{ +#if defined(HAVE_LANGINFO_H) || defined (_WIN32) + strncpy(pd->format, nl_langinfo(D_T_FMT), MAX_FORMAT_LEN); +#else + strncpy(pd->format, "", MAX_FORMAT_LEN); +#endif + pd->format[MAX_FORMAT_LEN - 1] = '\0'; + + _expand_format(pd->format); + + return pd->format; +} +EOLIAN static const char * +_efl_datetime_manager_string_get(const Eo *obj EINA_UNUSED, Efl_Datetime_Manager_Data *pd EINA_UNUSED, const char *fmt EINA_UNUSED) +{ + //TODO: strftime on upsteam, icu module connect here on tizen. + return NULL; +} +#include "efl_datetime_manager.eo.c" + diff --git a/src/lib/elementary/efl_datetime_manager.eo b/src/lib/elementary/efl_datetime_manager.eo new file mode 100644 index 0000000000..0728dc7312 --- /dev/null +++ b/src/lib/elementary/efl_datetime_manager.eo @@ -0,0 +1,50 @@ +import efl_types; + +class Efl.Datetime.Manager (Efl.Object) +{ + [[Efl datetime manager class for Datepicker and Timepicker]] + methods { + @property value { + [[The value of a date, time for Datepicker or Timepicker. + + The value for Datepicker contains year, month, and day. (tm_year, tm_mon, and tm_mday in Efl_Time) + The value for Timepicker contains hour, and min. (tm_hour, and tm_min in Efl_Time) + ]] + set { + } + get { + } + values { + newtime: Efl.Time; [[Time structure containing date or time value.]] + } + } + @property format { + [[The format of date or time. + + Default format is taken as per the system locale settings. + ]] + set { + } + get { + } + values { + fmt: string; [[The format string]] + } + } + @property string { + get { + [[Get the string that matches with the format.]] + } + keys { + fmt: string; [[The format string]] + } + values { + string: string; [[The string that matches with the format]] + } + } + } + implements { + Efl.Object.constructor; + Efl.Object.destructor; + } +} diff --git a/src/lib/elementary/efl_ui_datepicker.c b/src/lib/elementary/efl_ui_datepicker.c new file mode 100644 index 0000000000..2429d210b9 --- /dev/null +++ b/src/lib/elementary/efl_ui_datepicker.c @@ -0,0 +1,349 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include + +#include "elm_priv.h" +#include "efl_ui_datepicker_private.h" + +#define MY_CLASS EFL_UI_DATEPICKER_CLASS + +#define MY_CLASS_NAME "Efl.Ui.Datepicker" + +#define FMT_LEN_MAX 32 + +#define DATE_GET() \ + do { \ + Efl_Time t = efl_datetime_manager_value_get(pd->dt_manager); \ + pd->cur_date[DATEPICKER_YEAR] = t.tm_year + 1900; \ + pd->cur_date[DATEPICKER_MONTH] = t.tm_mon + 1; \ + pd->cur_date[DATEPICKER_DAY] = t.tm_mday; \ + } while (0) + +#define DATE_SET() \ + do { \ + Efl_Time t; \ + t.tm_year = pd->cur_date[DATEPICKER_YEAR] - 1900; \ + t.tm_mon = pd->cur_date[DATEPICKER_MONTH] - 1; \ + t.tm_mday = pd->cur_date[DATEPICKER_DAY]; \ + efl_datetime_manager_value_set(pd->dt_manager, t); \ + } while (0) + +static const char *fmt_char[] = {"Yy", "mbBh", "de"}; + +static Eina_Bool +_validate_params(int year, int month, int day) +{ + if (year < 1900 || year > 2037 || month < 1 || month > 12 || day < 0 || day > 31) + return EINA_FALSE; + else return EINA_TRUE; +} + +static Eina_Bool +_date_cmp(int time1[], int time2[]) +{ + unsigned int idx; + + for (idx = 0; idx < EFL_UI_DATEPICKER_TYPE_COUNT; idx++) + { + if (time1[idx] != time2[idx]) + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static Eina_Bool +_validate_date_limits(int time1[], int time2[], Eina_Bool swap) +{ + unsigned int idx; + int *t1, *t2; + + t1 = (swap) ? time2 : time1; + t2 = (swap) ? time1 : time2; + + for (idx = 0; idx < EFL_UI_DATEPICKER_TYPE_COUNT; idx++) + { + if (time1[idx] < time2[idx]) + { + memcpy(t1, t2, (sizeof(int) * EFL_UI_DATEPICKER_TYPE_COUNT)); + return EINA_TRUE; + } + else if (time1[idx] > time2[idx]) + return EINA_FALSE; + } + + return EINA_FALSE; +} + +static int +_max_days_get(int year, int month) +{ + struct tm time1; + time_t t; + int day; + + t = time(NULL); + localtime_r(&t, &time1); + time1.tm_year = year; + time1.tm_mon = month; + for (day = 28; day <= 31; + day++) + { + time1.tm_mday = day; + mktime(&time1); + /* To restrict month wrapping because of summer time in some locales, + * ignore day light saving mode in mktime(). */ + time1.tm_isdst = -1; + if (time1.tm_mday == 1) break; + } + day--; + + return day; +} + +static void +_field_value_update(Eo *obj) +{ + Efl_Ui_Datepicker_Data *pd = efl_data_scope_get(obj, MY_CLASS); + + efl_ui_range_value_set(pd->year, pd->cur_date[DATEPICKER_YEAR]); + efl_ui_range_value_set(pd->month, pd->cur_date[DATEPICKER_MONTH]); + efl_ui_range_value_set(pd->day, pd->cur_date[DATEPICKER_DAY]); + + DATE_SET(); +} + +static void +_field_changed_cb(void *data, const Efl_Event *ev) +{ + int max_day; + + Efl_Ui_Datepicker_Data *pd = efl_data_scope_get(data, MY_CLASS); + + if (ev->object == pd->year) + pd->cur_date[DATEPICKER_YEAR] = efl_ui_range_value_get(pd->year); + else if (ev->object == pd->month) + pd->cur_date[DATEPICKER_MONTH] = efl_ui_range_value_get(pd->month); + else + pd->cur_date[DATEPICKER_DAY] = efl_ui_range_value_get(pd->day); + + if (!(ev->object == pd->day)) + { + max_day = _max_days_get((pd->cur_date[DATEPICKER_YEAR] - 1900), (pd->cur_date[DATEPICKER_MONTH] - 1)); + efl_ui_range_min_max_set(pd->day, 1, max_day); + } + + if (_validate_date_limits(pd->cur_date, pd->min_date, EINA_FALSE) || + _validate_date_limits(pd->max_date, pd->cur_date, EINA_TRUE)) + { + _field_value_update(data); + return; + } + + DATE_SET(); + efl_event_callback_call(data, EFL_UI_DATEPICKER_EVENT_CHANGED, NULL); +} + +static void +_fields_init(Eo *obj) +{ + const char *fmt; + char ch; + int i; + int field = 0; + char buf[FMT_LEN_MAX]; + + Efl_Ui_Datepicker_Data *pd = efl_data_scope_get(obj, MY_CLASS); + + //Field create. + pd->year = efl_add(EFL_UI_SPIN_BUTTON_CLASS, obj, + efl_ui_range_min_max_set(efl_added, 1970, 2037), + efl_ui_spin_button_circulate_set(efl_added, EINA_TRUE), + efl_ui_spin_button_editable_set(efl_added, EINA_TRUE), + efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_field_changed_cb, obj), + elm_widget_element_update(obj, efl_added, "spin_button")); + + pd->month = efl_add(EFL_UI_SPIN_BUTTON_CLASS, obj, + efl_ui_range_min_max_set(efl_added, 1, 12), + efl_ui_spin_button_circulate_set(efl_added, EINA_TRUE), + efl_ui_spin_button_editable_set(efl_added, EINA_TRUE), + efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_field_changed_cb, obj), + elm_widget_element_update(obj, efl_added, "spin_button")); + + pd->day = efl_add(EFL_UI_SPIN_BUTTON_CLASS, obj, + efl_ui_range_min_max_set(efl_added, 1, 31), + efl_ui_spin_button_circulate_set(efl_added, EINA_TRUE), + efl_ui_spin_button_editable_set(efl_added, EINA_TRUE), + efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_field_changed_cb, obj), + elm_widget_element_update(obj, efl_added, "spin_button")); + + DATE_GET(); + //Using system config? + pd->min_date[DATEPICKER_YEAR] = 1970; + pd->min_date[DATEPICKER_MONTH] = 1; + pd->min_date[DATEPICKER_DAY] = 1; + pd->max_date[DATEPICKER_YEAR] = 2037; + pd->max_date[DATEPICKER_MONTH] = 12; + pd->max_date[DATEPICKER_DAY] = 31; + + _field_value_update(obj); + + fmt = efl_datetime_manager_format_get(pd->dt_manager); + if (!fmt) + { + ERR("Failed to get current format."); + //Gives default format when the gets format failed. + fmt = "%Y %b %d"; + } + + //Sort fields by format. + while((ch = *fmt)) + { + //TODO: ignore extensions and separators. + for (i = 0; i < EFL_UI_DATEPICKER_TYPE_COUNT; i++) + { + if (strchr(fmt_char[i], ch)) + { + snprintf(buf, sizeof(buf), "field%d", field++); + if (i == DATEPICKER_YEAR) + efl_content_set(efl_part(obj, buf), pd->year); + else if (i == DATEPICKER_MONTH) + efl_content_set(efl_part(obj, buf), pd->month); + else + efl_content_set(efl_part(obj, buf), pd->day); + + break; + } + } + fmt++; + } +} + +EOLIAN static void +_efl_ui_datepicker_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Datepicker_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 Eo * +_efl_ui_datepicker_efl_object_constructor(Eo *obj, Efl_Ui_Datepicker_Data *pd) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); + + if (!elm_widget_theme_klass_get(obj)) + elm_widget_theme_klass_set(obj, "datepicker"); + obj = efl_constructor(efl_super(obj, MY_CLASS)); + + if (!elm_widget_theme_object_set(obj, wd->resize_obj, + elm_widget_theme_klass_get(obj), + elm_widget_theme_element_get(obj), + elm_widget_theme_style_get(obj))) + CRI("Failed to set layout!"); + + pd->dt_manager = efl_add(EFL_DATETIME_MANAGER_CLASS, obj); + + _fields_init(obj); + + elm_widget_sub_object_parent_add(obj); + + elm_widget_can_focus_set(obj, EINA_TRUE); + + return obj; +} + +EOLIAN static void +_efl_ui_datepicker_efl_object_destructor(Eo *obj, Efl_Ui_Datepicker_Data *pd) +{ + efl_del(pd->dt_manager); + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static void +_efl_ui_datepicker_min_set(Eo *obj, Efl_Ui_Datepicker_Data *pd EINA_UNUSED, int year, int month, int day) +{ + int new_time[EFL_UI_DATEPICKER_TYPE_COUNT] = {year, month, day}; + + if (!_validate_params(year, month, day)) return; + if (_date_cmp(pd->min_date, new_time)) return; + + memcpy(pd->min_date, new_time, (sizeof(int) * EFL_UI_DATEPICKER_TYPE_COUNT)); + + _validate_date_limits(pd->max_date, pd->min_date, EINA_FALSE); + _validate_date_limits(pd->cur_date, pd->min_date, EINA_FALSE); + + DATE_SET(); + _field_value_update(obj); +} + +EOLIAN static void +_efl_ui_datepicker_min_get(const Eo *obj EINA_UNUSED, Efl_Ui_Datepicker_Data *pd, int *year, int *month, int *day) +{ + *year = pd->min_date[DATEPICKER_YEAR]; + *month = pd->min_date[DATEPICKER_MONTH]; + *day = pd->min_date[DATEPICKER_DAY]; +} + +EOLIAN static void +_efl_ui_datepicker_max_set(Eo *obj, Efl_Ui_Datepicker_Data *pd EINA_UNUSED, int year, int month, int day) +{ + int new_time[EFL_UI_DATEPICKER_TYPE_COUNT] = {year, month, day}; + + if (!_validate_params(year, month, day)) return; + if (_date_cmp(pd->max_date, new_time)) return; + + memcpy(pd->max_date, new_time, (sizeof(int) * EFL_UI_DATEPICKER_TYPE_COUNT)); + + _validate_date_limits(pd->max_date, pd->min_date, EINA_TRUE); + _validate_date_limits(pd->max_date, pd->cur_date, EINA_TRUE); + + DATE_SET(); + _field_value_update(obj); +} + +EOLIAN static void +_efl_ui_datepicker_max_get(const Eo *obj EINA_UNUSED, Efl_Ui_Datepicker_Data *pd, int *year, int *month, int *day) +{ + *year = pd->max_date[DATEPICKER_YEAR]; + *month = pd->max_date[DATEPICKER_MONTH]; + *day = pd->max_date[DATEPICKER_DAY]; +} + +EOLIAN static void +_efl_ui_datepicker_date_set(Eo *obj, Efl_Ui_Datepicker_Data *pd, int year, int month, int day) +{ + int new_time[EFL_UI_DATEPICKER_TYPE_COUNT] = {year, month, day}; + + if (!_validate_params(year, month, day)) return; + if (_date_cmp(pd->cur_date, new_time)) return; + + memcpy(pd->cur_date, new_time, (sizeof(int) * EFL_UI_DATEPICKER_TYPE_COUNT)); + + _validate_date_limits(pd->cur_date, pd->min_date, EINA_FALSE); + _validate_date_limits(pd->max_date, pd->cur_date, EINA_TRUE); + + DATE_SET(); + _field_value_update(obj); +} + +EOLIAN static void +_efl_ui_datepicker_date_get(const Eo *obj EINA_UNUSED, Efl_Ui_Datepicker_Data *pd, int *year, int *month, int *day) +{ + *year = pd->cur_date[DATEPICKER_YEAR]; + *month = pd->cur_date[DATEPICKER_MONTH]; + *day = pd->cur_date[DATEPICKER_DAY]; +} + +#define EFL_UI_DATEPICKER_EXTRA_OPS \ + ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_datepicker), \ + +#include "efl_ui_datepicker.eo.c" diff --git a/src/lib/elementary/efl_ui_datepicker.eo b/src/lib/elementary/efl_ui_datepicker.eo new file mode 100644 index 0000000000..2ba89236e2 --- /dev/null +++ b/src/lib/elementary/efl_ui_datepicker.eo @@ -0,0 +1,75 @@ +class Efl.Ui.Datepicker (Efl.Ui.Layout.Object) +{ + [[Datepicker widget + + This is a widget which allows the user to pick a date using internal spinner. + User can use the internal spinner to select year, month, day or user can input + value using internal entry. + ]] + methods { + @property min { + [[The lower boundary of date. + + $year: Year. The year range is from 1900 to 2137. + + $month: Month. The month range is from 1 to 12. + + $day: Day. The day range is from 1 to 31 according to $month. + ]] + set { + } + get{ + } + values { + year: int; [[The year value.]] + month: int; [[The month value from 1 to 12.]] + day: int; [[The day value from 1 to 31.]] + } + } + @property max { + [[The upper boundary of date. + + $year: Year. The year range is from 1900 to 2137. + + $month: Month. The month range is from 1 to 12. + + $day: Day. The day range is from 1 to 31 according to $month. + ]] + set { + } + get { + } + values { + year: int; [[The year value.]] + month: int; [[The month value from 1 to 12.]] + day: int; [[The day value from 1 to 31.]] + } + } + @property date { + [[The current value of date. + + $year: Year. The year range is from 1900 to 2137. + + $month: Month. The month range is from 0 to 11. + + $day: Day. The day range is from 1 to 31 according to $month. + ]] + set { + } + get{ + } + values { + year: int; [[The year value.]] + month: int; [[The month value from 1 to 12.]] + day: int; [[The day value from 1 to 31.]] + } + } + } + implements { + Efl.Object.constructor; + Efl.Object.destructor; + } + events { + changed; [[Called when date value is changed]] + } +} diff --git a/src/lib/elementary/efl_ui_datepicker_private.h b/src/lib/elementary/efl_ui_datepicker_private.h new file mode 100644 index 0000000000..0ee265b8b8 --- /dev/null +++ b/src/lib/elementary/efl_ui_datepicker_private.h @@ -0,0 +1,22 @@ +#ifndef EFL_UI_DATEPICKER_PRIVATE_H +#define EFL_UI_DATEPICKER_PRIVATE_H + +#define EFL_UI_DATEPICKER_TYPE_COUNT 3 + +typedef enum _Efl_Ui_Datepicker_Field_Type +{ + DATEPICKER_YEAR, + DATEPICKER_MONTH, + DATEPICKER_DAY +} Efl_Ui_Datepicker_Field_Type; + +typedef struct _Efl_Ui_Datepicker_Data Efl_Ui_Datepicker_Data; +struct _Efl_Ui_Datepicker_Data +{ + Eo *dt_manager, *year, *month, *day; + int cur_date[EFL_UI_DATEPICKER_TYPE_COUNT], + min_date[EFL_UI_DATEPICKER_TYPE_COUNT], + max_date[EFL_UI_DATEPICKER_TYPE_COUNT]; +}; + +#endif diff --git a/src/lib/elementary/efl_ui_spin_button.c b/src/lib/elementary/efl_ui_spin_button.c index fe11db473b..bb0e9031ce 100644 --- a/src/lib/elementary/efl_ui_spin_button.c +++ b/src/lib/elementary/efl_ui_spin_button.c @@ -20,6 +20,7 @@ #define EFL_UI_SPIN_BUTTON_DELAY_CHANGE_TIME 0.2 +static const char PART_NAME_ENTRY[] = "entry"; static const char PART_NAME_DEC_BUTTON[] = "dec_button"; static const char PART_NAME_TEXT_BUTTON[] = "text_button"; static const char PART_NAME_INC_BUTTON[] = "inc_button"; @@ -723,13 +724,7 @@ _efl_ui_spin_button_efl_ui_widget_theme_apply(Eo *obj, Efl_Ui_Spin_Button_Data * if (!int_ret) return EFL_UI_THEME_APPLY_FAILED; if (sd->ent) - { - //elm_widget_element_update(obj, sd->ent, PART_NAME_TEXT); - 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); - } + elm_widget_element_update(obj, sd->ent, PART_NAME_ENTRY); if (sd->inc_button) elm_widget_element_update(obj, sd->inc_button, PART_NAME_INC_BUTTON); diff --git a/src/lib/elementary/efl_ui_timepicker.c b/src/lib/elementary/efl_ui_timepicker.c new file mode 100644 index 0000000000..49a4e38974 --- /dev/null +++ b/src/lib/elementary/efl_ui_timepicker.c @@ -0,0 +1,285 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include + +#include "elm_priv.h" +#include "efl_ui_timepicker_private.h" + +#define MY_CLASS EFL_UI_TIMEPICKER_CLASS + +#define MY_CLASS_NAME "Efl.Ui.Timepicker" + +#define FMT_LEN_MAX 32 + +#define TIME_GET() \ + do { \ + Efl_Time t = efl_datetime_manager_value_get(pd->dt_manager); \ + pd->cur_time[TIMEPICKER_HOUR] = t.tm_hour; \ + pd->cur_time[TIMEPICKER_MIN] = t.tm_min; \ + } while (0) + +#define TIME_SET() \ + do { \ + Efl_Time t; \ + t.tm_hour = pd->cur_time[TIMEPICKER_HOUR]; \ + t.tm_min = pd->cur_time[TIMEPICKER_MIN]; \ + efl_datetime_manager_value_set(pd->dt_manager, t); \ + } while (0) + +static const char *fmt_char[] = {"IHkl", "M", "Aa"}; + +static Eina_Bool +_validate_params(int hour, int min) +{ + if (hour < 0 || hour > 23 || min < 0 || min > 59) + return EINA_FALSE; + else return EINA_TRUE; +} + +static Eina_Bool +_time_cmp(int time1[], int time2[]) +{ + unsigned int idx; + + for (idx = 0; idx < EFL_UI_TIMEPICKER_TYPE_COUNT -1; idx++) + { + if (time1[idx] != time2[idx]) + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static void +_field_value_update(Eo *obj) +{ + Efl_Ui_Timepicker_Data *pd = efl_data_scope_get(obj, MY_CLASS); + + if (!pd->is_24hour) + { + if (pd->cur_time[TIMEPICKER_HOUR] >= 12) + { + //TODO: gets text from strftime. + efl_text_set(pd->ampm, "PM"); + efl_ui_range_value_set(pd->hour, pd->cur_time[TIMEPICKER_HOUR] - 12); + } + else + { + efl_text_set(pd->ampm, "AM"); + efl_ui_range_value_set(pd->hour, pd->cur_time[TIMEPICKER_HOUR] + 12); + } + } + + efl_ui_range_value_set(pd->min, pd->cur_time[TIMEPICKER_MIN]); + + TIME_SET(); +} + +static void +_field_changed_cb(void *data, const Efl_Event *ev) +{ + Efl_Ui_Timepicker_Data *pd = efl_data_scope_get(data, MY_CLASS); + + //TODO: hour value increase when min reached max. + if (ev->object == pd->hour) + { + pd->cur_time[TIMEPICKER_HOUR] = efl_ui_range_value_get(pd->hour); + if (!pd->is_24hour && !strcmp(efl_text_get(pd->ampm), "PM")) + pd->cur_time[TIMEPICKER_HOUR] += 12; + } + else if (ev->object == pd->min) + pd->cur_time[TIMEPICKER_MIN] = efl_ui_range_value_get(pd->min); + else + { + if (!strcmp(efl_text_get(pd->ampm), "PM")) + { + efl_text_set(pd->ampm, "AM"); + pd->cur_time[TIMEPICKER_HOUR] -= 12; + } + else + { + efl_text_set(pd->ampm, "PM"); + pd->cur_time[TIMEPICKER_HOUR] += 12; + } + } + + TIME_SET(); + efl_event_callback_call(data, EFL_UI_TIMEPICKER_EVENT_CHANGED, NULL); +} + +static void +_fields_init(Eo *obj) +{ + const char *fmt; + char ch; + int i; + int field = 0; + char buf[FMT_LEN_MAX]; + + Efl_Ui_Timepicker_Data *pd = efl_data_scope_get(obj, MY_CLASS); + + //Field create. + pd->hour = efl_add(EFL_UI_SPIN_BUTTON_CLASS, obj, + efl_ui_range_min_max_set(efl_added, 1, 12), + efl_ui_spin_button_circulate_set(efl_added, EINA_TRUE), + efl_ui_spin_button_editable_set(efl_added, EINA_TRUE), + efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_field_changed_cb, obj), + elm_widget_element_update(obj, efl_added, "spin_button")); + + pd->min = efl_add(EFL_UI_SPIN_BUTTON_CLASS, obj, + efl_ui_range_min_max_set(efl_added, 0, 59), + efl_ui_spin_button_circulate_set(efl_added, EINA_TRUE), + efl_ui_spin_button_editable_set(efl_added, EINA_TRUE), + efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_field_changed_cb, obj), + elm_widget_element_update(obj, efl_added, "spin_button")); + + pd->ampm = efl_add(EFL_UI_BUTTON_CLASS, obj, + efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED, _field_changed_cb, obj), + elm_widget_element_update(obj, efl_added, "button")); + + pd->dt_manager = efl_add(EFL_DATETIME_MANAGER_CLASS, obj); + + TIME_GET(); + + pd->is_24hour = EINA_FALSE; + + _field_value_update(obj); + + fmt = efl_datetime_manager_format_get(pd->dt_manager); + if (!fmt) + { + ERR("Failed to get current format."); + //Gives default format when the gets format failed. + fmt = "%H:%M %a"; + } + + //Sort fields by format. + while((ch = *fmt)) + { + //TODO: ignore extensions and separators. + for (i = 0; i < EFL_UI_TIMEPICKER_TYPE_COUNT; i++) + { + if (strchr(fmt_char[i], ch)) + { + snprintf(buf, sizeof(buf), "field%d", field); + if (i == TIMEPICKER_HOUR) + efl_content_set(efl_part(obj, buf), pd->hour); + else if (i == TIMEPICKER_MIN) + efl_content_set(efl_part(obj, buf), pd->min); + else + { + //TODO: monitoring locale change and update field location. + if (field == 0) + { + elm_object_signal_emit(obj, "elm,state,colon,visible,field1", "elm"); + elm_object_signal_emit(obj, "elm,state,colon,invisible,field0", "elm"); + } + else + { + elm_object_signal_emit(obj, "elm,state,colon,visible,field0", "elm"); + elm_object_signal_emit(obj, "elm,state,colon,invisible,field1", "elm"); + } + + elm_layout_signal_emit(obj, "elm,state,ampm,visible", "elm"); + edje_object_message_signal_process(elm_layout_edje_get(obj)); + efl_content_set(efl_part(obj, buf), pd->ampm); + } + + field++; + break; + } + } + fmt++; + } +} + +EOLIAN static void +_efl_ui_timepicker_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Timepicker_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 Eo * +_efl_ui_timepicker_efl_object_constructor(Eo *obj, Efl_Ui_Timepicker_Data *pd EINA_UNUSED) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); + + if (!elm_widget_theme_klass_get(obj)) + elm_widget_theme_klass_set(obj, "timepicker"); + obj = efl_constructor(efl_super(obj, MY_CLASS)); + + if (!elm_widget_theme_object_set(obj, wd->resize_obj, + elm_widget_theme_klass_get(obj), + elm_widget_theme_element_get(obj), + elm_widget_theme_style_get(obj))) + CRI("Failed to set layout!"); + + _fields_init(obj); + + elm_widget_sub_object_parent_add(obj); + + elm_widget_can_focus_set(obj, EINA_TRUE); + + return obj; +} + +EOLIAN static void +_efl_ui_timepicker_efl_object_destructor(Eo *obj, Efl_Ui_Timepicker_Data *pd EINA_UNUSED) +{ + efl_destructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static void +_efl_ui_timepicker_time_set(Eo *obj, Efl_Ui_Timepicker_Data *pd, int hour, int min) +{ + int new_time[EFL_UI_TIMEPICKER_TYPE_COUNT - 1] = {hour, min}; + + if (!_validate_params(hour, min)) return; + if (_time_cmp(pd->cur_time, new_time)) return; + + memcpy(pd->cur_time, new_time, (sizeof(int) * (EFL_UI_TIMEPICKER_TYPE_COUNT -1))); + + TIME_SET(); + _field_value_update(obj); +} + +EOLIAN static void +_efl_ui_timepicker_time_get(const Eo *obj EINA_UNUSED, Efl_Ui_Timepicker_Data *pd, int *hour, int *min) +{ + *hour = pd->cur_time[TIMEPICKER_HOUR]; + *min = pd->cur_time[TIMEPICKER_MIN]; +} + +EOLIAN static void +_efl_ui_timepicker_ampm_set(Eo *obj, Efl_Ui_Timepicker_Data *pd, Eina_Bool is_24hour) +{ + if (pd->is_24hour == is_24hour) return; + + pd->is_24hour = is_24hour; + if (pd->is_24hour == EINA_TRUE) + elm_layout_signal_emit(obj, "elm,state,ampm,invisible", "elm"); + else + elm_layout_signal_emit(obj, "elm,state,ampm,visible", "elm"); + _field_value_update(obj); +} + +EOLIAN static Eina_Bool +_efl_ui_timepicker_ampm_get(const Eo *obj EINA_UNUSED, Efl_Ui_Timepicker_Data *pd) +{ + return pd->is_24hour; +} + +#define EFL_UI_TIMEPICKER_EXTRA_OPS \ + ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_timepicker), \ + +#include "efl_ui_timepicker.eo.c" diff --git a/src/lib/elementary/efl_ui_timepicker.eo b/src/lib/elementary/efl_ui_timepicker.eo new file mode 100644 index 0000000000..3be8f08a5c --- /dev/null +++ b/src/lib/elementary/efl_ui_timepicker.eo @@ -0,0 +1,44 @@ +class Efl.Ui.Timepicker (Efl.Ui.Layout.Object) +{ + [[Timepicker widget + + This is a widget which allows the user to pick a time using internal spinner. + User can use the internal spinner to select hour, minute, AM/PM or user can input + value using internal entry. + ]] + methods { + @property time { + [[The current value of time + + $hour: Hour. The hour value is in terms of 24 hour format from 0 to 23. + + $min: Minute. The minute range is from 0 to 59. + ]] + set { + } + get{ + } + values { + hour: int; [[The hour value from 0 to 23.]] + min: int; [[The minute value from 0 to 59.]] + } + } + @property ampm { + [[Control if the Timepicker displays 24 hour time or 12 hour time including AM/PM button.]] + set { + } + get { + } + values { + is_24hour: bool; [[$true to display the 24 hour time, $false to display 12 hour time including AM/PM button.]] + } + } + } + implements { + Efl.Object.constructor; + Efl.Object.destructor; + } + events { + changed; [[Called when date is changed]] + } +} diff --git a/src/lib/elementary/efl_ui_timepicker_private.h b/src/lib/elementary/efl_ui_timepicker_private.h new file mode 100644 index 0000000000..6c871d7cc2 --- /dev/null +++ b/src/lib/elementary/efl_ui_timepicker_private.h @@ -0,0 +1,21 @@ +#ifndef EFL_UI_TIMEPICKER_PRIVATE_H +#define EFL_UI_TIMEPICKER_PRIVATE_H + +#define EFL_UI_TIMEPICKER_TYPE_COUNT 3 + +typedef enum _Efl_Ui_Timepicker_Field_Type +{ + TIMEPICKER_HOUR, + TIMEPICKER_MIN, + TIMEPICKER_AMPM +} Efl_Ui_Timepicker_Field_Type; + +typedef struct _Efl_Ui_Timepicker_Data Efl_Ui_Timepicker_Data; +struct _Efl_Ui_Timepicker_Data +{ + Eo *dt_manager, *hour, *min, *ampm; + int cur_time[EFL_UI_TIMEPICKER_TYPE_COUNT]; + Eina_Bool is_24hour; +}; + +#endif diff --git a/src/lib/elementary/elm_config.c b/src/lib/elementary/elm_config.c index 1d6291fc18..bfdbd1df97 100644 --- a/src/lib/elementary/elm_config.c +++ b/src/lib/elementary/elm_config.c @@ -112,6 +112,8 @@ static const Elm_Color_Class _elm_color_classes[] = { {"calendar_day_highlighted", "Highlighted Day Effect"}, {"calendar_day_checked", "Checked Day Effect"}, {"datetime_bg", "Datetime Background"}, + {"datepicker_bg", "Datepicker Background"}, + {"timepicker_bg", "Timepicker Background"}, {"datetime_separator_text", "Datetime Separator Text"}, {"datetime_separator_text_disabled", "Datetime Separator Disabled Text"}, {"hoversel_item_active", "Hoversel Item Text"}, diff --git a/src/lib/elementary/elm_priv.h b/src/lib/elementary/elm_priv.h index 6b601604d7..66814bcacd 100644 --- a/src/lib/elementary/elm_priv.h +++ b/src/lib/elementary/elm_priv.h @@ -67,6 +67,7 @@ # include "efl_ui_focus_parent_provider_standard.eo.h" # include "elm_widget_item_static_focus.eo.h" #include "efl_selection_manager.eo.h" +# include "efl_datetime_manager.eo.h" # ifdef HAVE_LANGINFO_H # include