summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavi Artigas <xavierartigas@yahoo.es>2019-07-02 14:40:06 +0200
committerXavi Artigas <xavierartigas@yahoo.es>2019-07-04 19:38:20 +0200
commite776f5f0d7b6292d32c29ccb4fffe3f20063d53d (patch)
tree0191eda9933ca930e90078fc9a35762b4b71538a
parent87cfde51d3e143260a1b431f9c14d30536b549ce (diff)
Efl.Ui.Format revamp
This class helps widgets which contain a numerical value and must display it, like Progressbar (units label), Spin, Spin_Button, Slider (both units and popup labels, in legacy), Tags (when in shrunk mode) or Calendar (year_month label). Previously this was a mix of interface and mixin: widgets had to support setting a formatting func, and the mixin offered support for formatting strings, by setting an internal formatting func. On top of that, the spinner widget supported "special values", a list of values that should be shown as certain strings instead. This has now been simplified and unified: Widgets including this mixin can use the formatted_value_get() method which accepts an Eina_Value and returns a string. Thats's it. The mixin adds three properties to the widget (format_values, format_func and format_string) which users can use to tailor formatting. The widget does not need to know which method has been used, it just retrieves the resulting string. This removes a lot of duplicated widget code, and adds functionality which was missing before. For example, all widgets support passing a list of values now. Widgets must implement the apply_formatted_value() method so they are notified of changes in the format and they can redraw anything they need. Tests have been added to the Elementary Spec suite for all cases. Legacy widgets behavior has not been modified, although a few needed some code changes.
-rw-r--r--src/bin/elementary/test_calendar.c9
-rw-r--r--src/bin/elementary/test_ui_progressbar.c7
-rw-r--r--src/bin/elementary/test_ui_spin.c2
-rw-r--r--src/bin/elementary/test_ui_spin_button.c13
-rw-r--r--src/bin/elementary/test_ui_tags.c2
-rw-r--r--src/examples/elementary/calendar_cxx_example_02.cc8
-rw-r--r--src/lib/efl/Efl.h1
-rw-r--r--src/lib/efl/interfaces/efl_ui_format.c169
-rw-r--r--src/lib/efl/interfaces/efl_ui_format.eo42
-rw-r--r--src/lib/efl/interfaces/meson.build2
-rw-r--r--src/lib/elementary/Efl_Ui.h1
-rw-r--r--src/lib/elementary/efl_ui_calendar.c96
-rw-r--r--src/lib/elementary/efl_ui_calendar.eo3
-rw-r--r--src/lib/elementary/efl_ui_calendar_private.h8
-rw-r--r--src/lib/elementary/efl_ui_format.c345
-rw-r--r--src/lib/elementary/efl_ui_format.eo149
-rw-r--r--src/lib/elementary/efl_ui_progressbar.c57
-rw-r--r--src/lib/elementary/efl_ui_progressbar.eo2
-rw-r--r--src/lib/elementary/efl_ui_progressbar_private.h3
-rw-r--r--src/lib/elementary/efl_ui_spin.c230
-rw-r--r--src/lib/elementary/efl_ui_spin.eo31
-rw-r--r--src/lib/elementary/efl_ui_spin_button.c57
-rw-r--r--src/lib/elementary/efl_ui_spin_private.h18
-rw-r--r--src/lib/elementary/efl_ui_tags.c67
-rw-r--r--src/lib/elementary/efl_ui_tags.eo2
-rw-r--r--src/lib/elementary/efl_ui_tags_private.h5
-rw-r--r--src/lib/elementary/elm_slider.c49
-rw-r--r--src/lib/elementary/elm_slider_eo.c6
-rw-r--r--src/lib/elementary/elm_slider_part_indicator_eo.c8
-rw-r--r--src/lib/elementary/elm_widget_multibuttonentry.h2
-rw-r--r--src/lib/elementary/elm_widget_slider.h4
-rw-r--r--src/lib/elementary/meson.build2
-rw-r--r--src/tests/elementary/spec/README1
-rw-r--r--src/tests/elementary/spec/efl_test_format.c174
-rw-r--r--src/tests/elementary/spec/efl_ui_spec_suite.h1
-rw-r--r--src/tests/elementary/spec/meson.build1
36 files changed, 826 insertions, 751 deletions
diff --git a/src/bin/elementary/test_calendar.c b/src/bin/elementary/test_calendar.c
index 9a5de37..b3f54f5 100644
--- a/src/bin/elementary/test_calendar.c
+++ b/src/bin/elementary/test_calendar.c
@@ -405,17 +405,18 @@ _cal_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev)
405 max_date.tm_year + 1900); 405 max_date.tm_year + 1900);
406} 406}
407 407
408static void 408static Eina_Bool
409_cal_format_cb(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value value) 409_cal_format_cb(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value value)
410{ 410{
411 struct tm current_time; 411 struct tm current_time;
412 412
413 //return if the value type is other than EINA_VALUE_TYPE_TM 413 //return if the value type is other than EINA_VALUE_TYPE_TM
414 if (eina_value_type_get(&value) != EINA_VALUE_TYPE_TM) 414 if (eina_value_type_get(&value) != EINA_VALUE_TYPE_TM)
415 return; 415 return EINA_FALSE;
416 416
417 eina_value_get(&value, &current_time); 417 eina_value_get(&value, &current_time);
418 eina_strbuf_append_strftime(str, "<< %b %y >>", &current_time); 418 eina_strbuf_append_strftime(str, "<< %b %y >>", &current_time);
419 return EINA_TRUE;
419} 420}
420 421
421void 422void
@@ -444,7 +445,7 @@ test_efl_ui_calendar(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void
444 efl_ui_calendar_date_max_set(efl_added, max_date), 445 efl_ui_calendar_date_max_set(efl_added, max_date),
445 efl_ui_calendar_date_set(efl_added, selected_date), 446 efl_ui_calendar_date_set(efl_added, selected_date),
446 efl_event_callback_add(efl_added, EFL_UI_CALENDAR_EVENT_CHANGED, _cal_changed_cb, NULL), 447 efl_event_callback_add(efl_added, EFL_UI_CALENDAR_EVENT_CHANGED, _cal_changed_cb, NULL),
447 efl_ui_format_string_set(efl_added, "%b"), 448 efl_ui_format_string_set(efl_added, "%b", EFL_UI_FORMAT_STRING_TYPE_TIME),
448 efl_pack(box, efl_added)); 449 efl_pack(box, efl_added));
449 450
450 efl_add(EFL_UI_CALENDAR_CLASS, win, 451 efl_add(EFL_UI_CALENDAR_CLASS, win,
@@ -452,7 +453,7 @@ test_efl_ui_calendar(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void
452 efl_ui_calendar_date_max_set(efl_added, max_date), 453 efl_ui_calendar_date_max_set(efl_added, max_date),
453 efl_ui_calendar_date_set(efl_added, selected_date), 454 efl_ui_calendar_date_set(efl_added, selected_date),
454 efl_event_callback_add(efl_added, EFL_UI_CALENDAR_EVENT_CHANGED, _cal_changed_cb, NULL), 455 efl_event_callback_add(efl_added, EFL_UI_CALENDAR_EVENT_CHANGED, _cal_changed_cb, NULL),
455 efl_ui_format_cb_set(efl_added, NULL, _cal_format_cb, NULL), 456 efl_ui_format_func_set(efl_added, NULL, _cal_format_cb, NULL),
456 efl_pack(box, efl_added)); 457 efl_pack(box, efl_added));
457 458
458 efl_gfx_entity_size_set(win, EINA_SIZE2D(300, 300)); 459 efl_gfx_entity_size_set(win, EINA_SIZE2D(300, 300));
diff --git a/src/bin/elementary/test_ui_progressbar.c b/src/bin/elementary/test_ui_progressbar.c
index 3d50d0b..5a1c705 100644
--- a/src/bin/elementary/test_ui_progressbar.c
+++ b/src/bin/elementary/test_ui_progressbar.c
@@ -119,7 +119,7 @@ _win_delete_req_cb(void *d, const Efl_Event *ev EINA_UNUSED)
119 free(pd); 119 free(pd);
120} 120}
121 121
122static void 122static Eina_Bool
123_custom_format_cb(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value value) 123_custom_format_cb(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value value)
124{ 124{
125 double v; 125 double v;
@@ -129,6 +129,7 @@ _custom_format_cb(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value val
129 else if (v < 75.f) eina_strbuf_append_printf(str, "Getting there..."); 129 else if (v < 75.f) eina_strbuf_append_printf(str, "Getting there...");
130 else if (v < 100.f) eina_strbuf_append_printf(str, "Almost done..."); 130 else if (v < 100.f) eina_strbuf_append_printf(str, "Almost done...");
131 else eina_strbuf_append_printf(str, "Done!"); 131 else eina_strbuf_append_printf(str, "Done!");
132 return EINA_TRUE;
132} 133}
133 134
134static void 135static void
@@ -204,7 +205,7 @@ test_ui_progressbar(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_inf
204 efl_pack(bx, efl_added), 205 efl_pack(bx, efl_added),
205 efl_text_set(efl_added, "Custom string"), 206 efl_text_set(efl_added, "Custom string"),
206 efl_ui_range_limits_set(efl_added, 0, 100), 207 efl_ui_range_limits_set(efl_added, 0, 100),
207 efl_ui_format_string_set(efl_added, "%d rabbits"), 208 efl_ui_format_string_set(efl_added, "%d rabbits", EFL_UI_FORMAT_STRING_TYPE_SIMPLE),
208 efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(250, 20)) 209 efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(250, 20))
209 ); 210 );
210 211
@@ -212,7 +213,7 @@ test_ui_progressbar(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_inf
212 efl_pack(bx, efl_added), 213 efl_pack(bx, efl_added),
213 efl_text_set(efl_added, "Custom func"), 214 efl_text_set(efl_added, "Custom func"),
214 efl_ui_range_limits_set(efl_added, 0, 100), 215 efl_ui_range_limits_set(efl_added, 0, 100),
215 efl_ui_format_cb_set(efl_added, NULL, _custom_format_cb, NULL), 216 efl_ui_format_func_set(efl_added, NULL, _custom_format_cb, NULL),
216 efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(250, 20)) 217 efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(250, 20))
217 ); 218 );
218 219
diff --git a/src/bin/elementary/test_ui_spin.c b/src/bin/elementary/test_ui_spin.c
index 1c5b86b..f07a427 100644
--- a/src/bin/elementary/test_ui_spin.c
+++ b/src/bin/elementary/test_ui_spin.c
@@ -50,7 +50,7 @@ test_ui_spin(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_i
50 efl_ui_range_limits_set(efl_added, 0, 10), 50 efl_ui_range_limits_set(efl_added, 0, 10),
51 efl_ui_range_value_set(efl_added, 6), 51 efl_ui_range_value_set(efl_added, 6),
52 efl_ui_range_step_set(efl_added, 2), 52 efl_ui_range_step_set(efl_added, 2),
53 efl_ui_format_string_set(efl_added, "test %d"), 53 efl_ui_format_string_set(efl_added, "test %d", EFL_UI_FORMAT_STRING_TYPE_SIMPLE),
54 efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_spin_changed_cb, NULL), 54 efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_spin_changed_cb, NULL),
55 efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_MIN_REACHED,_spin_min_reached_cb, NULL), 55 efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_MIN_REACHED,_spin_min_reached_cb, NULL),
56 efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_MAX_REACHED,_spin_max_reached_cb, NULL), 56 efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_MAX_REACHED,_spin_max_reached_cb, NULL),
diff --git a/src/bin/elementary/test_ui_spin_button.c b/src/bin/elementary/test_ui_spin_button.c
index 52455e6..82a207f 100644
--- a/src/bin/elementary/test_ui_spin_button.c
+++ b/src/bin/elementary/test_ui_spin_button.c
@@ -16,18 +16,12 @@ void
16test_ui_spin_button(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) 16test_ui_spin_button(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
17{ 17{
18 Eo *win, *bx; 18 Eo *win, *bx;
19 int i; 19 Efl_Ui_Format_Value special_values[] = {
20 Eina_Array *array;
21 Efl_Ui_Spin_Special_Value values[12] = {
22 {1, "January"}, {2, "February"}, {3, "March"}, {4, "April"}, 20 {1, "January"}, {2, "February"}, {3, "March"}, {4, "April"},
23 {5, "May"}, {6, "June"}, {7, "July"}, {8, "August"}, 21 {5, "May"}, {6, "June"}, {7, "July"}, {8, "August"},
24 {9, "September"}, {10, "October"}, {11, "November"}, {12, "December"} 22 {9, "September"}, {10, "October"}, {11, "November"}, {12, "December"}
25 }; 23 };
26 24
27 array = eina_array_new(sizeof(Efl_Ui_Spin_Special_Value));
28 for (i = 0; i < NUM_OF_VALS; i++)
29 eina_array_push(array, &values[i]);
30
31 win = efl_add_ref(EFL_UI_WIN_CLASS, NULL, 25 win = efl_add_ref(EFL_UI_WIN_CLASS, NULL,
32 efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_BASIC), 26 efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_BASIC),
33 efl_text_set(efl_added, "Efl.Ui.Spin_Button"), 27 efl_text_set(efl_added, "Efl.Ui.Spin_Button"),
@@ -49,7 +43,7 @@ test_ui_spin_button(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *
49 efl_add(EFL_UI_SPIN_BUTTON_CLASS, bx, 43 efl_add(EFL_UI_SPIN_BUTTON_CLASS, bx,
50 efl_ui_range_limits_set(efl_added, -100.0, 100.0), 44 efl_ui_range_limits_set(efl_added, -100.0, 100.0),
51 efl_ui_range_value_set(efl_added, 0), 45 efl_ui_range_value_set(efl_added, 0),
52 efl_ui_format_string_set(efl_added, "test float %0.2f"), 46 efl_ui_format_string_set(efl_added, "test float %0.2f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE),
53 efl_ui_spin_button_editable_set(efl_added, EINA_FALSE), 47 efl_ui_spin_button_editable_set(efl_added, EINA_FALSE),
54 efl_pack(bx, efl_added)); 48 efl_pack(bx, efl_added));
55 49
@@ -57,10 +51,9 @@ test_ui_spin_button(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *
57 efl_ui_range_limits_set(efl_added, 1, 12), 51 efl_ui_range_limits_set(efl_added, 1, 12),
58 efl_ui_range_value_set(efl_added, 1), 52 efl_ui_range_value_set(efl_added, 1),
59 efl_ui_spin_button_editable_set(efl_added, EINA_FALSE), 53 efl_ui_spin_button_editable_set(efl_added, EINA_FALSE),
60 efl_ui_spin_special_value_set(efl_added, array), 54 efl_ui_format_values_set(efl_added, EINA_C_ARRAY_ACCESSOR_NEW(special_values)),
61 efl_ui_layout_orientation_set(efl_added, EFL_UI_LAYOUT_ORIENTATION_VERTICAL), 55 efl_ui_layout_orientation_set(efl_added, EFL_UI_LAYOUT_ORIENTATION_VERTICAL),
62 efl_pack(bx, efl_added)); 56 efl_pack(bx, efl_added));
63 eina_array_free(array);
64 57
65 efl_gfx_entity_size_set(win, EINA_SIZE2D(180, 140)); 58 efl_gfx_entity_size_set(win, EINA_SIZE2D(180, 140));
66} 59}
diff --git a/src/bin/elementary/test_ui_tags.c b/src/bin/elementary/test_ui_tags.c
index 410c7b2..2ef7d6d 100644
--- a/src/bin/elementary/test_ui_tags.c
+++ b/src/bin/elementary/test_ui_tags.c
@@ -78,7 +78,7 @@ test_ui_tags(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_i
78 efl_event_callback_add(efl_added, EFL_UI_TAGS_EVENT_ITEM_ADDED, _item_added_cb, array), 78 efl_event_callback_add(efl_added, EFL_UI_TAGS_EVENT_ITEM_ADDED, _item_added_cb, array),
79 efl_event_callback_add(efl_added, EFL_UI_TAGS_EVENT_ITEM_DELETED, _item_deleted_cb, array), 79 efl_event_callback_add(efl_added, EFL_UI_TAGS_EVENT_ITEM_DELETED, _item_deleted_cb, array),
80 efl_text_set(efl_added, "To :"), 80 efl_text_set(efl_added, "To :"),
81 efl_ui_format_string_set(efl_added, "+ %d items"), 81 efl_ui_format_string_set(efl_added, "+ %d items", EFL_UI_FORMAT_STRING_TYPE_SIMPLE),
82 elm_object_part_content_set(layout, "multibuttonentry", efl_added)); 82 elm_object_part_content_set(layout, "multibuttonentry", efl_added));
83 83
84 efl_add(EFL_UI_BUTTON_CLASS, layout, 84 efl_add(EFL_UI_BUTTON_CLASS, layout,
diff --git a/src/examples/elementary/calendar_cxx_example_02.cc b/src/examples/elementary/calendar_cxx_example_02.cc
index 60fb796..e666ae8 100644
--- a/src/examples/elementary/calendar_cxx_example_02.cc
+++ b/src/examples/elementary/calendar_cxx_example_02.cc
@@ -26,17 +26,19 @@ struct appData
26 auto wcal(cal._get_wref()); 26 auto wcal(cal._get_wref());
27 27
28 // FIXME: How does one figure out the argument types for the function? 28 // FIXME: How does one figure out the argument types for the function?
29 auto cb_a = std::bind([=]( 29 auto cb_a = std::bind([](
30 efl::eina::strbuf_wrapper& sb, 30 efl::eina::strbuf_wrapper& sb,
31 efl::eina::value_view const& value) { 31 efl::eina::value_view const& value) -> bool {
32 try { 32 try {
33 sb.append_strftime("%b. %y", efl::eina::get<tm>(value)); 33 sb.append_strftime("%b. %y", efl::eina::get<tm>(value));
34 } catch (std::system_error const&) { 34 } catch (std::system_error const&) {
35 sb.append(value.to_string()); 35 sb.append(value.to_string());
36 } 36 }
37 std::cout << "Month: " << std::string(sb) << std::endl; 37 std::cout << "Month: " << std::string(sb) << std::endl;
38 return true;
38 }, _1, _2); 39 }, _1, _2);
39 cal.format_cb_set(cb_a); 40 // FIXME XAR: I broke this and I do not know how to fix it
41 // cal.format_func_set(cb_a);
40 } 42 }
41 43
42 void destroy() { 44 void destroy() {
diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h
index aa88196..5cbd1c2 100644
--- a/src/lib/efl/Efl.h
+++ b/src/lib/efl/Efl.h
@@ -147,7 +147,6 @@ typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command;
147#include "interfaces/efl_ui_property_bind.eo.h" 147#include "interfaces/efl_ui_property_bind.eo.h"
148#include "interfaces/efl_ui_factory.eo.h" 148#include "interfaces/efl_ui_factory.eo.h"
149#include "interfaces/efl_ui_factory_bind.eo.h" 149#include "interfaces/efl_ui_factory_bind.eo.h"
150#include "interfaces/efl_ui_format.eo.h"
151#include "interfaces/efl_cached_item.eo.h" 150#include "interfaces/efl_cached_item.eo.h"
152 151
153/* Observable interface */ 152/* Observable interface */
diff --git a/src/lib/efl/interfaces/efl_ui_format.c b/src/lib/efl/interfaces/efl_ui_format.c
deleted file mode 100644
index f6f1b81..0000000
--- a/src/lib/efl/interfaces/efl_ui_format.c
+++ /dev/null
@@ -1,169 +0,0 @@
1#include "config.h"
2#include "Efl.h"
3
4#define ERR(...) EINA_LOG_DOM_ERR(EINA_LOG_DOMAIN_DEFAULT, __VA_ARGS__)
5#define DBG(...) EINA_LOG_DOM_DBG(EINA_LOG_DOMAIN_DEFAULT, __VA_ARGS__)
6
7typedef enum _Format_Type
8{
9 FORMAT_TYPE_INVALID,
10 FORMAT_TYPE_DOUBLE,
11 FORMAT_TYPE_INT,
12 FORMAT_TYPE_STRING,
13 FORMAT_TYPE_STATIC
14} Format_Type;
15
16typedef struct
17{
18 const char *template;
19 Format_Type format_type;
20} Efl_Ui_Format_Data;
21
22static Eina_Bool
23_is_valid_digit(char x)
24{
25 return ((x >= '0' && x <= '9') || (x == '.')) ? EINA_TRUE : EINA_FALSE;
26}
27
28static Format_Type
29_format_string_check(const char *fmt)
30{
31 const char *itr;
32 Eina_Bool found = EINA_FALSE;
33 Format_Type ret_type = FORMAT_TYPE_STATIC;
34
35 for (itr = fmt; *itr; itr++)
36 {
37 if (itr[0] != '%') continue;
38 if (itr[1] == '%')
39 {
40 itr++;
41 if (ret_type == FORMAT_TYPE_STATIC)
42 ret_type = FORMAT_TYPE_STRING;
43 continue;
44 }
45
46 if (!found)
47 {
48 found = EINA_TRUE;
49 for (itr++; *itr; itr++)
50 {
51 // FIXME: This does not properly support int64 or unsigned.
52 if ((*itr == 'd') || (*itr == 'u') || (*itr == 'i') ||
53 (*itr == 'o') || (*itr == 'x') || (*itr == 'X'))
54 {
55 ret_type = FORMAT_TYPE_INT;
56 break;
57 }
58 else if ((*itr == 'f') || (*itr == 'F'))
59 {
60 ret_type = FORMAT_TYPE_DOUBLE;
61 break;
62 }
63 else if (*itr == 's')
64 {
65 ret_type = FORMAT_TYPE_STRING;
66 break;
67 }
68 else if (_is_valid_digit(*itr))
69 {
70 continue;
71 }
72 else
73 {
74 ERR("Format string '%s' has unknown format element '%c' in format. It must have one format element of type 's', 'f', 'F', 'd', 'u', 'i', 'o', 'x' or 'X'", fmt, *itr);
75 found = EINA_FALSE;
76 break;
77 }
78 }
79 if (!(*itr)) break;
80 }
81 else
82 {
83 ret_type = FORMAT_TYPE_INVALID;
84 break;
85 }
86 }
87
88 if (ret_type == FORMAT_TYPE_INVALID)
89 {
90 ERR("Format string '%s' is invalid. It must have one and only one format element of type 's', 'f', 'F', 'd', 'u', 'i', 'o', 'x' or 'X'", fmt);
91 }
92 return ret_type;
93}
94
95static void
96_default_format_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
97{
98 Efl_Ui_Format_Data *sd = data;
99 Eina_Value copy;
100
101 if (sd->format_type == FORMAT_TYPE_DOUBLE)
102 {
103 double v = 0.0;
104 eina_value_setup(&copy, EINA_VALUE_TYPE_DOUBLE);
105 eina_value_convert(&value, &copy);
106 eina_value_get(&copy, &v);
107 eina_strbuf_append_printf(str, sd->template, v);
108 eina_value_flush(&copy);
109 }
110 else if (sd->format_type == FORMAT_TYPE_INT)
111 {
112 int v = 0;
113 eina_value_setup(&copy, EINA_VALUE_TYPE_INT);
114 eina_value_convert(&value, &copy);
115 eina_value_get(&copy, &v);
116 eina_strbuf_append_printf(str, sd->template, v);
117 eina_value_flush(&copy);
118 }
119 else if (sd->format_type == FORMAT_TYPE_STRING)
120 {
121 char *v = eina_value_to_string(&value);
122 eina_strbuf_append_printf(str, sd->template, v);
123 free(v);
124 }
125 else if (sd->format_type == FORMAT_TYPE_STATIC)
126 {
127 eina_strbuf_append(str, sd->template);
128 }
129 else
130 {
131 // Error: Discard format string and just print value.
132 DBG("Could not guess value type in format string: '%s'", sd->template);
133 char *v = eina_value_to_string(&value);
134 eina_strbuf_append(str, v);
135 free(v);
136 }
137}
138
139static void
140_default_format_free_cb(void *data)
141{
142 Efl_Ui_Format_Data *sd = data;
143
144 if (sd && sd->template)
145 {
146 eina_stringshare_del(sd->template);
147 sd->template = NULL;
148 }
149}
150
151EOLIAN static void
152_efl_ui_format_format_string_set(Eo *obj, Efl_Ui_Format_Data *sd, const char *template)
153{
154 if (!template) return;
155
156 eina_stringshare_replace(&sd->template, template);
157 sd->format_type = _format_string_check(sd->template);
158
159 efl_ui_format_cb_set(obj, sd, _default_format_cb, _default_format_free_cb);
160}
161
162EOLIAN static const char *
163_efl_ui_format_format_string_get(const Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *sd)
164{
165 return sd->template;
166}
167
168#include "interfaces/efl_ui_format.eo.c"
169
diff --git a/src/lib/efl/interfaces/efl_ui_format.eo b/src/lib/efl/interfaces/efl_ui_format.eo
deleted file mode 100644
index c7b6aba..0000000
--- a/src/lib/efl/interfaces/efl_ui_format.eo
+++ /dev/null
@@ -1,42 +0,0 @@
1import eina_types;
2
3function @beta Efl.Ui.Format_Func_Cb {
4 [[Function pointer for format function hook]]
5 params {
6 @in str: strbuf; [[the formated string to be appended by user.]]
7 @in value: const(any_value); [[The @Eina.Value passed by $obj.]]
8 }
9};
10
11mixin @beta Efl.Ui.Format
12{
13 [[interface class for format_func]]
14 methods {
15 @property format_cb {
16 set @pure_virtual {
17 [[Set the format function pointer to format the string.
18 ]]
19 }
20 values {
21 func: Efl.Ui.Format_Func_Cb; [[The format function callback]]
22 }
23 }
24 @property format_string {
25 [[Control the format string for a given units label
26
27 If $NULL is passed to $format, it will hide $obj's units
28 area completely. If not, it'll set the <b>format
29 string</b> for the units label text. The units label is
30 provided as a floating point value, so the units text can display
31 at most one floating point value. Note that the units label is
32 optional. Use a format string such as "%1.2f meters" for example.
33
34 Note: The default format string is an integer percentage,
35 as in $"%.0f %%".
36 ]]
37 values {
38 units: string; [[The format string for $obj's units label.]]
39 }
40 }
41 }
42}
diff --git a/src/lib/efl/interfaces/meson.build b/src/lib/efl/interfaces/meson.build
index e3baa55..d09a24c 100644
--- a/src/lib/efl/interfaces/meson.build
+++ b/src/lib/efl/interfaces/meson.build
@@ -94,7 +94,6 @@ pub_eo_files = [
94 'efl_observer.eo', 94 'efl_observer.eo',
95 'efl_observable.eo', 95 'efl_observable.eo',
96 'efl_ui_autorepeat.eo', 96 'efl_ui_autorepeat.eo',
97 'efl_ui_format.eo',
98 'efl_gfx_color_class.eo', 97 'efl_gfx_color_class.eo',
99 'efl_gfx_text_class.eo', 98 'efl_gfx_text_class.eo',
100 'efl_gfx_size_class.eo', 99 'efl_gfx_size_class.eo',
@@ -166,7 +165,6 @@ efl_src += files([
166 'efl_io_queue.c', 165 'efl_io_queue.c',
167 'efl_observer.c', 166 'efl_observer.c',
168 'efl_file.c', 167 'efl_file.c',
169 'efl_ui_format.c',
170 'efl_ui_layout_orientable_readonly.c', 168 'efl_ui_layout_orientable_readonly.c',
171 'efl_text_markup_util.c', 169 'efl_text_markup_util.c',
172]) 170])
diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h
index 2647362..dc13d16 100644
--- a/src/lib/elementary/Efl_Ui.h
+++ b/src/lib/elementary/Efl_Ui.h
@@ -246,6 +246,7 @@ typedef Eo Efl_Ui_Active_View_Indicator;
246# include <efl_ui_navigation_layout.eo.h> 246# include <efl_ui_navigation_layout.eo.h>
247# include <efl_ui_clickable.eo.h> 247# include <efl_ui_clickable.eo.h>
248# include <efl_ui_clickable_util.eo.h> 248# include <efl_ui_clickable_util.eo.h>
249# include <efl_ui_format.eo.h>
249 250
250/** 251/**
251 * Initialize Elementary 252 * Initialize Elementary
diff --git a/src/lib/elementary/efl_ui_calendar.c b/src/lib/elementary/efl_ui_calendar.c
index 2005661..7fb1742 100644
--- a/src/lib/elementary/efl_ui_calendar.c
+++ b/src/lib/elementary/efl_ui_calendar.c
@@ -5,6 +5,7 @@
5#define EFL_UI_FOCUS_COMPOSITION_PROTECTED 5#define EFL_UI_FOCUS_COMPOSITION_PROTECTED
6#define EFL_UI_FOCUS_OBJECT_PROTECTED 6#define EFL_UI_FOCUS_OBJECT_PROTECTED
7#define EFL_ACCESS_WIDGET_ACTION_PROTECTED 7#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
8#define EFL_UI_FORMAT_PROTECTED
8 9
9#include <Elementary.h> 10#include <Elementary.h>
10#include "elm_priv.h" 11#include "elm_priv.h"
@@ -167,37 +168,17 @@ _disable(Efl_Ui_Calendar_Data *sd,
167static void 168static void
168_set_month_year(Efl_Ui_Calendar_Data *sd) 169_set_month_year(Efl_Ui_Calendar_Data *sd)
169{ 170{
171 Eina_Strbuf *strbuf = eina_strbuf_new();
172 Eina_Value val;
170 173
171 sd->filling = EINA_TRUE; 174 sd->filling = EINA_TRUE;
172 175
173 if (sd->format_cb) 176 eina_value_setup(&val, EINA_VALUE_TYPE_TM);
174 { 177 eina_value_set(&val, sd->shown_date);
175 Eina_Value val; 178 efl_ui_format_formatted_value_get(sd->obj, strbuf, val);
176 const char *buf; 179 elm_layout_text_set(sd->obj, "month_text", eina_strbuf_string_get(strbuf));
177 180 eina_value_flush(&val);
178 eina_value_setup(&val, EINA_VALUE_TYPE_TM); 181 eina_strbuf_free(strbuf);
179 eina_value_set(&val, sd->shown_date);
180 eina_strbuf_reset(sd->format_strbuf);
181 sd->format_cb(sd->format_cb_data, sd->format_strbuf, val);
182 buf = eina_strbuf_string_get(sd->format_strbuf);
183 eina_value_flush(&val);
184
185 if (buf)
186 elm_layout_text_set(sd->obj, "month_text", buf);
187 else
188 elm_layout_text_set(sd->obj, "month_text", "");
189 }
190 else
191 {
192 char *buf;
193 buf = eina_strftime(E_("%B %Y"), &sd->shown_date);
194 if (buf)
195 {
196 elm_layout_text_set(sd->obj, "month_text", buf);
197 free(buf);
198 }
199 else elm_layout_text_set(sd->obj, "month_text", "");
200 }
201 182
202 sd->filling = EINA_FALSE; 183 sd->filling = EINA_FALSE;
203} 184}
@@ -841,9 +822,6 @@ _efl_ui_calendar_efl_object_destructor(Eo *obj, Efl_Ui_Calendar_Data *sd)
841 822
842 ecore_timer_del(sd->update_timer); 823 ecore_timer_del(sd->update_timer);
843 824
844 efl_ui_format_cb_set(obj, NULL, NULL, NULL);
845 eina_strbuf_free(sd->format_strbuf);
846
847 for (i = 0; i < ELM_DAY_LAST; i++) 825 for (i = 0; i < ELM_DAY_LAST; i++)
848 eina_stringshare_del(sd->weekdays[i]); 826 eina_stringshare_del(sd->weekdays[i]);
849 827
@@ -919,7 +897,6 @@ _efl_ui_calendar_constructor_internal(Eo *obj, Efl_Ui_Calendar_Data *priv)
919 priv->today_it = -1; 897 priv->today_it = -1;
920 priv->selected_it = -1; 898 priv->selected_it = -1;
921 priv->first_day_it = -1; 899 priv->first_day_it = -1;
922 priv->format_cb = NULL;
923 900
924 edje_object_signal_callback_add 901 edje_object_signal_callback_add
925 (wd->resize_obj, "efl,action,selected", "*", 902 (wd->resize_obj, "efl,action,selected", "*",
@@ -1146,64 +1123,11 @@ _efl_ui_calendar_date_get(const Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd)
1146} 1123}
1147 1124
1148EOLIAN static void 1125EOLIAN static void
1149_efl_ui_calendar_efl_ui_format_format_cb_set(Eo *obj, Efl_Ui_Calendar_Data *sd, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb) 1126_efl_ui_calendar_efl_ui_format_apply_formatted_value(Eo *obj, Efl_Ui_Calendar_Data *pd EINA_UNUSED)
1150{ 1127{
1151 if ((sd->format_cb_data == func_data) && (sd->format_cb == func))
1152 return;
1153
1154 if (sd->format_cb_data && sd->format_free_cb)
1155 sd->format_free_cb(sd->format_cb_data);
1156
1157 sd->format_cb = func;
1158 sd->format_cb_data = func_data;
1159 sd->format_free_cb = func_free_cb;
1160 if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
1161
1162 evas_object_smart_changed(obj); 1128 evas_object_smart_changed(obj);
1163} 1129}
1164 1130
1165static void
1166_calendar_format_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
1167{
1168 Efl_Ui_Calendar_Data *sd = data;
1169 const Eina_Value_Type *type = eina_value_type_get(&value);
1170 struct tm v;
1171
1172 if (type == EINA_VALUE_TYPE_TM)
1173 {
1174 eina_value_get(&value, &v);
1175 eina_strbuf_append_strftime(str, sd->format_template, &v);
1176 }
1177}
1178
1179static void
1180_calendar_format_free_cb(void *data)
1181{
1182 Efl_Ui_Calendar_Data *sd = data;
1183
1184 if (sd && sd->format_template)
1185 {
1186 eina_stringshare_del(sd->format_template);
1187 sd->format_template = NULL;
1188 }
1189}
1190
1191EOLIAN static void
1192_efl_ui_calendar_efl_ui_format_format_string_set(Eo *obj, Efl_Ui_Calendar_Data *sd, const char *template)
1193{
1194 if (!template) return;
1195
1196 eina_stringshare_replace(&sd->format_template, template);
1197
1198 efl_ui_format_cb_set(obj, sd, _calendar_format_cb, _calendar_format_free_cb);
1199}
1200
1201EOLIAN static const char *
1202_efl_ui_calendar_efl_ui_format_format_string_get(const Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd)
1203{
1204 return sd->format_template;
1205}
1206
1207EOLIAN static void 1131EOLIAN static void
1208_efl_ui_calendar_first_day_of_week_set(Eo *obj, Efl_Ui_Calendar_Data *sd, Efl_Ui_Calendar_Weekday day) 1132_efl_ui_calendar_first_day_of_week_set(Eo *obj, Efl_Ui_Calendar_Data *sd, Efl_Ui_Calendar_Weekday day)
1209{ 1133{
diff --git a/src/lib/elementary/efl_ui_calendar.eo b/src/lib/elementary/efl_ui_calendar.eo
index 888319d..586535f 100644
--- a/src/lib/elementary/efl_ui_calendar.eo
+++ b/src/lib/elementary/efl_ui_calendar.eo
@@ -111,8 +111,7 @@ class @beta Efl.Ui.Calendar extends Efl.Ui.Layout_Base implements Efl.Ui.Focus.C
111 Efl.Ui.Focus.Object.on_focus_update; 111 Efl.Ui.Focus.Object.on_focus_update;
112 Efl.Ui.Widget.widget_input_event_handler; 112 Efl.Ui.Widget.widget_input_event_handler;
113 Efl.Access.Widget.Action.elm_actions { get; } 113 Efl.Access.Widget.Action.elm_actions { get; }
114 Efl.Ui.Format.format_cb { set; } 114 Efl.Ui.Format.apply_formatted_value;
115 Efl.Ui.Format.format_string { set; get;}
116 } 115 }
117 events { 116 events {
118 changed: void; [[Emitted when the selected date in the calendar is changed]] 117 changed: void; [[Emitted when the selected date in the calendar is changed]]
diff --git a/src/lib/elementary/efl_ui_calendar_private.h b/src/lib/elementary/efl_ui_calendar_private.h
index 78446c6..3d80b89 100644
--- a/src/lib/elementary/efl_ui_calendar_private.h
+++ b/src/lib/elementary/efl_ui_calendar_private.h
@@ -39,15 +39,9 @@ struct _Efl_Ui_Calendar_Data
39 Evas_Object *month_access; 39 Evas_Object *month_access;
40 Eo *items[42]; 40 Eo *items[42];
41 41
42 Efl_Ui_Calendar_Weekday first_week_day; 42 Efl_Ui_Calendar_Weekday first_week_day;
43 unsigned char first_day_it; 43 unsigned char first_day_it;
44 44
45 const char *format_template;
46 Efl_Ui_Format_Func_Cb format_cb;
47 Eina_Free_Cb format_free_cb;
48 void *format_cb_data;
49 Eina_Strbuf *format_strbuf;
50
51 Eina_Bool selected : 1; 45 Eina_Bool selected : 1;
52 Eina_Bool filling : 1; 46 Eina_Bool filling : 1;
53 Eina_Bool weekdays_set : 1; 47 Eina_Bool weekdays_set : 1;
diff --git a/src/lib/elementary/efl_ui_format.c b/src/lib/elementary/efl_ui_format.c
new file mode 100644
index 0000000..beb3945
--- /dev/null
+++ b/src/lib/elementary/efl_ui_format.c
@@ -0,0 +1,345 @@
1#define EFL_UI_FORMAT_PROTECTED 1
2
3#include "config.h"
4#include "Efl_Ui.h"
5#include "elm_priv.h" /* To be able to use elm_widget_is_legacy() */
6
7typedef enum _Format_Type
8{
9 /* When a format string is used, it is parsed to find out the expected data type */
10 FORMAT_TYPE_INVALID, /* Format description not understood */
11 FORMAT_TYPE_DOUBLE, /* double */
12 FORMAT_TYPE_INT, /* int */
13 FORMAT_TYPE_TM, /* struct tm, for time and date values */
14 FORMAT_TYPE_STRING, /* const char* */
15 FORMAT_TYPE_STATIC /* No value is passed, the format string IS the formatted output */
16} Format_Type;
17
18typedef struct
19{
20 Efl_Ui_Format_Func format_func; /* User-supplied formatting function */
21 void *format_func_data; /* User data for the above function */
22 Eina_Free_Cb format_func_free; /* How to free the above data */
23
24 Eina_Inarray *format_values; /* Array of formatting values, owned by us */
25
26 const char *format_string; /* User-supplied formatting string, stringshare */
27 Format_Type format_string_type; /* Type of data expected in the above string */
28} Efl_Ui_Format_Data;
29
30static Eina_Bool
31_is_valid_digit(char x)
32{
33 return ((x >= '0' && x <= '9') || (x == '.')) ? EINA_TRUE : EINA_FALSE;
34}
35
36static Format_Type
37_format_string_check(const char *fmt, Efl_Ui_Format_String_Type type)
38{
39 const char *itr;
40 Eina_Bool found = EINA_FALSE;
41 Format_Type ret_type = FORMAT_TYPE_STATIC;
42
43 if (type == EFL_UI_FORMAT_STRING_TYPE_TIME) return FORMAT_TYPE_TM;
44
45 for (itr = fmt; *itr; itr++)
46 {
47 if (itr[0] != '%') continue;
48 if (itr[1] == '%')
49 {
50 itr++;
51 if (ret_type == FORMAT_TYPE_STATIC)
52 ret_type = FORMAT_TYPE_STRING;
53 continue;
54 }
55
56 if (!found)
57 {
58 found = EINA_TRUE;
59 for (itr++; *itr; itr++)
60 {
61 // FIXME: This does not properly support int64 or unsigned.
62 if ((*itr == 'd') || (*itr == 'u') || (*itr == 'i') ||
63 (*itr == 'o') || (*itr == 'x') || (*itr == 'X'))
64 {
65 ret_type = FORMAT_TYPE_INT;
66 break;
67 }
68 else if ((*itr == 'f') || (*itr == 'F'))
69 {
70 ret_type = FORMAT_TYPE_DOUBLE;
71 break;
72 }
73 else if (*itr == 's')
74 {
75 ret_type = FORMAT_TYPE_STRING;
76 break;
77 }
78 else if (_is_valid_digit(*itr))
79 {
80 continue;
81 }
82 else
83 {
84 ERR("Format string '%s' has unknown format element '%c' in format. It must have one format element of type 's', 'f', 'F', 'd', 'u', 'i', 'o', 'x' or 'X'", fmt, *itr);
85 found = EINA_FALSE;
86 break;
87 }
88 }
89 if (!(*itr)) break;
90 }
91 else
92 {
93 ret_type = FORMAT_TYPE_INVALID;
94 break;
95 }
96 }
97
98 if (ret_type == FORMAT_TYPE_INVALID)
99 {
100 ERR("Format string '%s' is invalid. It must have one and only one format element of type 's', 'f', 'F', 'd', 'u', 'i', 'o', 'x' or 'X'", fmt);
101 }
102 return ret_type;
103}
104
105static Eina_Bool
106_do_format_string(Efl_Ui_Format_Data *pd, Eina_Strbuf *str, const Eina_Value value)
107{
108 switch (pd->format_string_type)
109 {
110 case FORMAT_TYPE_DOUBLE:
111 {
112 double v = 0.0;
113 eina_value_double_convert(&value, &v);
114 eina_strbuf_append_printf(str, pd->format_string, v);
115 break;
116 }
117 case FORMAT_TYPE_INT:
118 {
119 int v = 0;
120 eina_value_int_convert(&value, &v);
121 eina_strbuf_append_printf(str, pd->format_string, v);
122 break;
123 }
124 case FORMAT_TYPE_STRING:
125 {
126 char *v = eina_value_to_string(&value);
127 eina_strbuf_append_printf(str, pd->format_string, v);
128 free(v);
129 break;
130 }
131 case FORMAT_TYPE_STATIC:
132 {
133 eina_strbuf_append(str, pd->format_string);
134 break;
135 }
136 case FORMAT_TYPE_TM:
137 {
138 struct tm v;
139 char *buf;
140 eina_value_get(&value, &v);
141 buf = eina_strftime(pd->format_string, &v);
142 eina_strbuf_append(str, buf);
143 free(buf);
144 break;
145 }
146 default:
147 return EINA_FALSE;
148 }
149 return EINA_TRUE;
150}
151
152static Eina_Bool
153_legacy_default_format_func(void *data, Eina_Strbuf *str, const Eina_Value value)
154{
155 if (!_do_format_string(data, str, value))
156 {
157 /* Fallback to just printing the value if format string fails (legacy behavior) */
158 char *v = eina_value_to_string(&value);
159 eina_strbuf_append(str, v);
160 free(v);
161 }
162 return EINA_TRUE;
163}
164
165EOLIAN static void
166_efl_ui_format_format_func_set(Eo *obj, Efl_Ui_Format_Data *pd, void *func_data, Efl_Ui_Format_Func func, Eina_Free_Cb func_free_cb)
167{
168 if (pd->format_func_free)
169 pd->format_func_free(pd->format_func_data);
170 pd->format_func = func;
171 pd->format_func_data = func_data;
172 pd->format_func_free = func_free_cb;
173
174 if (efl_alive_get(obj))
175 efl_ui_format_apply_formatted_value(obj);
176}
177
178EOLIAN static Efl_Ui_Format_Func
179_efl_ui_format_format_func_get(const Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *pd)
180{
181 return pd->format_func;
182}
183
184static int
185_value_compare(const Efl_Ui_Format_Value *val1, const Efl_Ui_Format_Value *val2)
186{
187 return val1->value - val2->value;
188}
189
190EOLIAN static void
191_efl_ui_format_format_values_set(Eo *obj, Efl_Ui_Format_Data *pd, Eina_Accessor *values)
192{
193 Efl_Ui_Format_Value v;
194 int i;
195 if (pd->format_values)
196 {
197 Efl_Ui_Format_Value *vptr;
198 /* Delete previous values array */
199 EINA_INARRAY_FOREACH(pd->format_values, vptr)
200 {
201 eina_stringshare_del(vptr->text);
202 }
203 eina_inarray_free(pd->format_values);
204 pd->format_values = NULL;
205 }
206 if (values == NULL)
207 {
208 if (efl_alive_get(obj))
209 efl_ui_format_apply_formatted_value(obj);
210 return;
211 }
212
213 /* Copy the values to our internal array */
214 pd->format_values = eina_inarray_new(sizeof(Efl_Ui_Format_Value), 4);
215 EINA_ACCESSOR_FOREACH(values, i, v)
216 {
217 Efl_Ui_Format_Value vcopy = { v.value, eina_stringshare_add(v.text) };
218 eina_inarray_insert_sorted(pd->format_values, &vcopy, (Eina_Compare_Cb)_value_compare);
219 }
220 eina_accessor_free(values);
221
222 if (efl_alive_get(obj))
223 efl_ui_format_apply_formatted_value(obj);
224}
225
226EOLIAN static Eina_Accessor *
227_efl_ui_format_format_values_get(const Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *pd)
228{
229 if (!pd->format_values) return NULL;
230 return eina_inarray_accessor_new(pd->format_values);
231}
232
233EOLIAN static void
234_efl_ui_format_format_string_set(Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *sd, const char *string, Efl_Ui_Format_String_Type type)
235{
236 eina_stringshare_replace(&sd->format_string, string);
237 if (string)
238 sd->format_string_type = _format_string_check(sd->format_string, type);
239 else
240 sd->format_string_type = FORMAT_TYPE_INVALID;
241
242 /* In legacy, setting the format string installs a default format func.
243 Some widgets then override the format_func_set method so we keep that behavior. */
244 if (elm_widget_is_legacy(obj))
245 efl_ui_format_func_set(obj, sd, _legacy_default_format_func, NULL);
246
247 if (efl_alive_get(obj))
248 efl_ui_format_apply_formatted_value(obj);
249}
250
251EOLIAN static void
252_efl_ui_format_format_string_get(const Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *sd, const char **string, Efl_Ui_Format_String_Type *type)
253{
254 if (string) *string = sd->format_string;
255 if (type) *type = sd->format_string_type == FORMAT_TYPE_TM ?
256 EFL_UI_FORMAT_STRING_TYPE_TIME : EFL_UI_FORMAT_STRING_TYPE_SIMPLE;
257}
258
259EOLIAN static void
260_efl_ui_format_formatted_value_get(Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *pd, Eina_Strbuf *str, const Eina_Value value)
261{
262 char *v;
263 eina_strbuf_reset(str);
264 if (pd->format_values)
265 {
266 /* Search in the format_values array if we have one */
267 Efl_Ui_Format_Value v = { 0 };
268 int ndx;
269 eina_value_int_convert(&value, &v.value);
270 ndx = eina_inarray_search_sorted(pd->format_values, &v, (Eina_Compare_Cb)_value_compare);
271 if (ndx > -1) {
272 Efl_Ui_Format_Value *entry = eina_inarray_nth(pd->format_values, ndx);
273 eina_strbuf_append(str, entry->text);
274 return;
275 }
276 }
277 if (pd->format_func)
278 {
279 /* If we have a formatting function, try to use it */
280 if (pd->format_func(pd->format_func_data, str, value))
281 return;
282 }
283 if (pd->format_string)
284 {
285 /* If we have a formatting string, use it */
286 if (_do_format_string(pd, str, value))
287 return;
288 }
289
290 /* Fallback to just printing the value if everything else fails */
291 v = eina_value_to_string(&value);
292 eina_strbuf_append(str, v);
293 free(v);
294}
295
296EOLIAN static int
297_efl_ui_format_decimal_places_get(Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *pd)
298{
299 char result[16] = "0";
300 const char *start;
301
302 /* This method can only be called if a format_string has been supplied */
303 if (!pd->format_string) return 0;
304
305 start = strchr(pd->format_string, '%');
306 while (start)
307 {
308 if (start[1] != '%')
309 {
310 start = strchr(start, '.');
311 if (start)
312 start++;
313 break;
314 }
315 else
316 start = strchr(start + 2, '%');
317 }
318
319 if (start)
320 {
321 const char *p = strchr(start, 'f');
322
323 if ((p) && ((p - start) < 15))
324 sscanf(start, "%[^f]", result);
325 }
326
327 return atoi(result);
328}
329
330EOLIAN static void
331_efl_ui_format_efl_object_destructor(Eo *obj, Efl_Ui_Format_Data *pd EINA_UNUSED)
332{
333 /* Legacy widgets keep their own formatting data and have their own destructors */
334 if (!elm_widget_is_legacy(obj))
335 {
336 /* Otherwise, free formatting data */
337 efl_ui_format_func_set(obj, NULL, NULL, NULL);
338 efl_ui_format_values_set(obj, NULL);
339 efl_ui_format_string_set(obj, NULL, 0);
340 }
341 efl_destructor(efl_super(obj, EFL_UI_FORMAT_MIXIN));
342}
343
344#include "efl_ui_format.eo.c"
345
diff --git a/src/lib/elementary/efl_ui_format.eo b/src/lib/elementary/efl_ui_format.eo
new file mode 100644
index 0000000..3858a79
--- /dev/null
+++ b/src/lib/elementary/efl_ui_format.eo
@@ -0,0 +1,149 @@
1import eina_types;
2
3function @beta Efl.Ui.Format_Func
4{
5 [[A function taking an @Eina.Value and producing its textual representation.
6 See @Efl.Ui.Format.format_func.
7 ]]
8 params {
9 @in str: strbuf; [[Output formatted string. Its contents will be overwritten by this method.]]
10 @in value: const(any_value); [[The @Eina.Value to convert to text.]]
11 }
12 return: bool; [[Whether the conversion succeeded or not.]]
13};
14
15struct @beta Efl.Ui.Format_Value
16{
17 [[A value which should always be displayed as a specific text string.
18 See @Efl.Ui.Format.format_values.
19 ]]
20 value: int; [[Input value.]]
21 text: string; [[Text string to replace it.]]
22}
23
24enum @beta Efl.Ui.Format_String_Type
25{
26 [[Type of formatting string.]]
27 simple, [[This is the simplest formatting mechanism, working pretty much like $printf.
28 Accepted formats are $s, $f, $F, $d, $u, $i, $o, $x and $X.
29 For example, "%1.2f meters", "%.0%%" or "%d items".
30 ]]
31 time [[A strftime-style string used to format date and time values.
32 For example, "%A" for the full name of the day or "%y" for the year as a decimal number
33 without a century (range 00 to 99). Note that these are not the $printf formats.
34 See the man page for the $strftime function for the complete list.
35 ]]
36}
37
38mixin @beta Efl.Ui.Format requires Efl.Object
39{
40 [[Helper mixin that simplifies converting numerical values to text.
41
42 A number of widgets represent a numerical value but display a text representation.
43 For example, an @Efl.Ui.Progressbar can hold the number 0.75 but display the string "75%",
44 or an @Efl.Ui.Spin can hold numbers 1 to 7, but display the strings "Monday" thru "Sunday".
45
46 This conversion can be controlled through the @.format_func, @.format_values and @.format_string properties.
47 Only one of them needs to be set. When more than one is set @.format_values has the highest priority, followed by @.format_func and then @.format_string.
48 If one mechanism fails to produce a valid string the others will be tried (if provided) in descending
49 order of priority.
50 If no user-provided mechanism works, a fallback is used that just displays the value.
51
52 Widgets including this mixin offer their users different properties to control how
53 @Eina.Value's are converted to text.
54 ]]
55 methods {
56 @property format_func {
57 [[User-provided function which takes care of converting an @Eina.Value into a text string.
58 The user is then completely in control of how the string is generated, but it is the
59 most cumbersome method to use.
60 If the conversion fails the other mechanisms will be tried, according to their priorities.
61 ]]
62 values {
63 func: Efl.Ui.Format_Func; [[User-provided formatting function.]]
64 }
65 }
66
67 @property format_values {
68 [[User-provided list of values which are to be rendered using specific text strings.
69 This is more convenient to use than @.format_func and is perfectly suited for cases
70 where the strings make more sense than the numerical values. For example, weekday names
71 ("Monday", "Tuesday", ...) are friendlier than numbers 1 to 7.
72 If a value is not found in the list, the other mechanisms will be tried according to their priorities.
73 List members do not need to be in any particular order. They are sorted internally for
74 performance reasons.
75 ]]
76 values {
77 values: accessor<Efl.Ui.Format_Value>; [[Accessor over a list of value-text pairs.
78 The method will dispose of the accessor, but not of
79 its contents.
80 For convenience, Eina offers a range of helper
81 methods to obtain accessors from Eina.Array,
82 Eina.List or even plain C arrays.
83 ]]
84 }
85 }
86
87 @property format_string {
88 [[A user-provided, string used to format the numerical value.
89
90 For example, "%1.2f meters", "%.0%%" or "%d items".
91
92 This is the simplest formatting mechanism, working pretty much like $printf.
93
94 Different format specifiers (the character after the %) are available, depending on the
95 $type used. Use @Efl.Ui.Format_String_Type.simple for simple numerical values and
96 @Efl.Ui.Format_String_Type.time for time and date values.
97 For instance, %d means "integer" when the first type is used, but it means "day of the month
98 as a decimal number" in the second.
99
100 Pass $NULL to disable this mechanism.
101 ]]
102 values {
103 string: string; [[Formatting string containing regular characters and format specifiers.]]
104 type: Efl.Ui.Format_String_Type(Efl.Ui.Format_String_Type.simple);
105 [[Type of formatting string, which controls how the
106 different format specifiers are to be traslated.]]
107 }
108 }
109
110 formatted_value_get @protected {
111 [[Internal method to be used by widgets including this mixin to perform the conversion
112 from the internal numerical value into the text representation (Users of these widgets
113 do not need to call this method).
114
115 @.formatted_value_get uses any user-provided mechanism to perform the conversion, according to their
116 priorities, and implements a simple fallback if all mechanisms fail.
117 ]]
118 params {
119 @in str: strbuf; [[Output formatted string. Its contents will be overwritten by this method.]]
120 @in value: const(any_value); [[The @Eina.Value to convert to text.]]
121 }
122 }
123
124 decimal_places_get @protected {
125 [[Internal method to be used by widgets including this mixin.
126 It can only be used when a @.format_string has been supplied, and it returns the number
127 of decimal places that the format string will produce for floating point values.
128
129 For example, "%.2f" returns 2, and "%d" returns 0;
130 ]]
131 return: int; [[Number of decimal places, or 0 for non-floating point types.]]
132 }
133
134 apply_formatted_value @pure_virtual @protected {
135 [[Internal method to be implemented by widgets including this mixin.
136
137 The mixin will call this method to signal the widget that the formatting has changed
138 and therefore the current value should be converted and rendered again.
139 Widgets must typically call @.formatted_value_get and display the returned string. This
140 is something they are already doing (whenever the value changes, for example) so there
141 should be no extra code written to implement this method.
142 ]]
143 }
144 }
145
146 implements {
147 Efl.Object.destructor;
148 }
149}
diff --git a/src/lib/elementary/efl_ui_progressbar.c b/src/lib/elementary/efl_ui_progressbar.c
index dfe4b07..637c54f 100644
--- a/src/lib/elementary/efl_ui_progressbar.c
+++ b/src/lib/elementary/efl_ui_progressbar.c
@@ -6,6 +6,7 @@
6#define ELM_LAYOUT_PROTECTED 6#define ELM_LAYOUT_PROTECTED
7#define EFL_ACCESS_VALUE_PROTECTED 7#define EFL_ACCESS_VALUE_PROTECTED
8#define EFL_PART_PROTECTED 8#define EFL_PART_PROTECTED
9#define EFL_UI_FORMAT_PROTECTED
9 10
10#include <Elementary.h> 11#include <Elementary.h>
11 12
@@ -73,7 +74,7 @@ _units_set(Evas_Object *obj)
73{ 74{
74 EFL_UI_PROGRESSBAR_DATA_GET(obj, sd); 75 EFL_UI_PROGRESSBAR_DATA_GET(obj, sd);
75 76
76 if (sd->show_progress_label && sd->format_cb) 77 if (sd->show_progress_label)
77 { 78 {
78 Eina_Value val; 79 Eina_Value val;
79 80
@@ -84,8 +85,8 @@ _units_set(Evas_Object *obj)
84 if (sd->is_legacy_format_string && !sd->is_legacy_format_cb) 85 if (sd->is_legacy_format_string && !sd->is_legacy_format_cb)
85 eina_value_set(&val, 100 * sd->val); 86 eina_value_set(&val, 100 * sd->val);
86 87
87 eina_strbuf_reset(sd->format_strbuf); 88 if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
88 sd->format_cb(sd->format_cb_data, sd->format_strbuf, val); 89 efl_ui_format_formatted_value_get(obj, sd->format_strbuf, val);
89 90
90 eina_value_flush(&val); 91 eina_value_flush(&val);
91 92
@@ -361,7 +362,7 @@ _efl_ui_progressbar_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Progressbar_Data
361 362
362 free(group); 363 free(group);
363 364
364 efl_ui_format_string_set(obj, "%.0f%%"); 365 efl_ui_format_string_set(obj, "%.0f%%", EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
365 366
366 priv->spacer = evas_object_rectangle_add(evas_object_evas_get(obj)); 367 priv->spacer = evas_object_rectangle_add(evas_object_evas_get(obj));
367 evas_object_color_set(priv->spacer, 0, 0, 0, 0); 368 evas_object_color_set(priv->spacer, 0, 0, 0, 0);
@@ -402,8 +403,8 @@ _efl_ui_progressbar_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Progressbar_Data
402 } 403 }
403 } 404 }
404 405
405 efl_ui_format_cb_set(obj, NULL, NULL, NULL);
406 eina_strbuf_free(sd->format_strbuf); 406 eina_strbuf_free(sd->format_strbuf);
407 sd->format_strbuf = NULL;
407 408
408 efl_canvas_group_del(efl_super(obj, MY_CLASS)); 409 efl_canvas_group_del(efl_super(obj, MY_CLASS));
409} 410}
@@ -611,32 +612,6 @@ _efl_ui_progressbar_efl_ui_range_display_range_value_get(const Eo *obj, Efl_Ui_P
611} 612}
612 613
613EOLIAN static void 614EOLIAN static void
614_efl_ui_progressbar_efl_ui_format_format_cb_set(Eo *obj, Efl_Ui_Progressbar_Data *sd, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb)
615{
616 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
617
618 if (sd->format_cb_data == func_data && sd->format_cb == func)
619 return;
620
621 if (sd->format_cb_data && sd->format_free_cb)
622 sd->format_free_cb(sd->format_cb_data);
623
624 sd->format_cb = func;
625 sd->format_cb_data = func_data;
626 sd->format_free_cb = func_free_cb;
627 if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
628
629 if (elm_widget_is_legacy(obj))
630 elm_layout_signal_emit(obj, "elm,state,units,visible", "elm");
631 else
632 elm_layout_signal_emit(obj, "efl,state,units,visible", "efl");
633 edje_object_message_signal_process(wd->resize_obj);
634
635 _units_set(obj);
636 elm_layout_sizing_eval(obj);
637}
638
639EOLIAN static void
640_efl_ui_progressbar_pulse_set(Eo *obj, Efl_Ui_Progressbar_Data *sd, Eina_Bool state) 615_efl_ui_progressbar_pulse_set(Eo *obj, Efl_Ui_Progressbar_Data *sd, Eina_Bool state)
641{ 616{
642 state = !!state; 617 state = !!state;
@@ -773,6 +748,12 @@ _efl_ui_progressbar_show_progress_label_get(const Eo *obj EINA_UNUSED, Efl_Ui_Pr
773 return pd->show_progress_label; 748 return pd->show_progress_label;
774} 749}
775 750
751EOLIAN static void
752_efl_ui_progressbar_efl_ui_format_apply_formatted_value(Eo *obj, Efl_Ui_Progressbar_Data *pd EINA_UNUSED)
753{
754 _units_set(obj);
755}
756
776#include "efl_ui_progressbar_part.eo.c" 757#include "efl_ui_progressbar_part.eo.c"
777 758
778/* Efl.Part end */ 759/* Efl.Part end */
@@ -982,7 +963,7 @@ typedef struct
982 progressbar_freefunc_type format_free_cb; 963 progressbar_freefunc_type format_free_cb;
983} Pb_Format_Wrapper_Data; 964} Pb_Format_Wrapper_Data;
984 965
985static void 966static Eina_Bool
986_format_legacy_to_format_eo_cb(void *data, Eina_Strbuf *str, const Eina_Value value) 967_format_legacy_to_format_eo_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
987{ 968{
988 Pb_Format_Wrapper_Data *pfwd = data; 969 Pb_Format_Wrapper_Data *pfwd = data;
@@ -998,6 +979,8 @@ _format_legacy_to_format_eo_cb(void *data, Eina_Strbuf *str, const Eina_Value va
998 if (buf) 979 if (buf)
999 eina_strbuf_append(str, buf); 980 eina_strbuf_append(str, buf);
1000 if (pfwd->format_free_cb) pfwd->format_free_cb(buf); 981 if (pfwd->format_free_cb) pfwd->format_free_cb(buf);
982
983 return EINA_TRUE;
1001} 984}
1002 985
1003static void 986static void
@@ -1018,8 +1001,8 @@ elm_progressbar_unit_format_function_set(Evas_Object *obj, progressbar_func_type
1018 pfwd->format_free_cb = free_func; 1001 pfwd->format_free_cb = free_func;
1019 sd->is_legacy_format_cb = EINA_TRUE; 1002 sd->is_legacy_format_cb = EINA_TRUE;
1020 1003
1021 efl_ui_format_cb_set(obj, pfwd, _format_legacy_to_format_eo_cb, 1004 efl_ui_format_func_set(obj, pfwd, _format_legacy_to_format_eo_cb,
1022 _format_legacy_to_format_eo_free_cb); 1005 _format_legacy_to_format_eo_free_cb);
1023} 1006}
1024 1007
1025EAPI void 1008EAPI void
@@ -1042,13 +1025,15 @@ elm_progressbar_unit_format_set(Evas_Object *obj, const char *units)
1042 EFL_UI_PROGRESSBAR_DATA_GET_OR_RETURN(obj, sd); 1025 EFL_UI_PROGRESSBAR_DATA_GET_OR_RETURN(obj, sd);
1043 1026
1044 sd->is_legacy_format_string = EINA_TRUE; 1027 sd->is_legacy_format_string = EINA_TRUE;
1045 efl_ui_format_string_set(obj, units); 1028 efl_ui_format_string_set(obj, units, EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
1046} 1029}
1047 1030
1048EAPI const char * 1031EAPI const char *
1049elm_progressbar_unit_format_get(const Evas_Object *obj) 1032elm_progressbar_unit_format_get(const Evas_Object *obj)
1050{ 1033{
1051 return efl_ui_format_string_get(obj); 1034 const char *fmt;
1035 efl_ui_format_string_get(obj, &fmt, NULL);
1036 return fmt;
1052} 1037}
1053 1038
1054EAPI void 1039EAPI void
diff --git a/src/lib/elementary/efl_ui_progressbar.eo b/src/lib/elementary/efl_ui_progressbar.eo
index 6a70844..ba8b3e3 100644
--- a/src/lib/elementary/efl_ui_progressbar.eo
+++ b/src/lib/elementary/efl_ui_progressbar.eo
@@ -58,7 +58,7 @@ class @beta Efl.Ui.Progressbar extends Efl.Ui.Layout_Base implements Efl.Ui.Rang
58 Efl.Ui.Range_Display.range_value { get; set; } 58 Efl.Ui.Range_Display.range_value { get; set; }
59 Efl.Ui.Range_Display.range_limits {get; set; } 59 Efl.Ui.Range_Display.range_limits {get; set; }
60 Efl.Ui.Layout_Orientable.orientation { get; set; } 60 Efl.Ui.Layout_Orientable.orientation { get; set; }
61 Efl.Ui.Format.format_cb { set; } 61 Efl.Ui.Format.apply_formatted_value;
62 Efl.Part.part_get; 62 Efl.Part.part_get;
63 Efl.Access.Value.value_and_text { get; } 63 Efl.Access.Value.value_and_text { get; }
64 Efl.Text.text { get; set; } 64 Efl.Text.text { get; set; }
diff --git a/src/lib/elementary/efl_ui_progressbar_private.h b/src/lib/elementary/efl_ui_progressbar_private.h
index 9abd57d..48b999b 100644
--- a/src/lib/elementary/efl_ui_progressbar_private.h
+++ b/src/lib/elementary/efl_ui_progressbar_private.h
@@ -38,9 +38,6 @@ struct _Efl_Ui_Progressbar_Data
38 38
39 Eina_List *progress_status; /**< The list of _Elm_Progress_Status. To save the progress value(in percentage) each part of given progress bar */ 39 Eina_List *progress_status; /**< The list of _Elm_Progress_Status. To save the progress value(in percentage) each part of given progress bar */
40 40
41 Efl_Ui_Format_Func_Cb format_cb;
42 Eina_Free_Cb format_free_cb;
43 void *format_cb_data;
44 Eina_Strbuf *format_strbuf; 41 Eina_Strbuf *format_strbuf;
45 42
46 Efl_Ui_Layout_Orientation dir; /**< Orientation of the progressbar */ 43 Efl_Ui_Layout_Orientation dir; /**< Orientation of the progressbar */
diff --git a/src/lib/elementary/efl_ui_spin.c b/src/lib/elementary/efl_ui_spin.c
index feb3f54..dddc869 100644
--- a/src/lib/elementary/efl_ui_spin.c
+++ b/src/lib/elementary/efl_ui_spin.c
@@ -5,6 +5,7 @@
5#define EFL_ACCESS_OBJECT_PROTECTED 5#define EFL_ACCESS_OBJECT_PROTECTED
6#define EFL_ACCESS_VALUE_PROTECTED 6#define EFL_ACCESS_VALUE_PROTECTED
7#define EFL_ACCESS_WIDGET_ACTION_PROTECTED 7#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
8#define EFL_UI_FORMAT_PROTECTED
8 9
9#include <Elementary.h> 10#include <Elementary.h>
10 11
@@ -15,142 +16,17 @@
15 16
16#define MY_CLASS_NAME "Efl.Ui.Spin" 17#define MY_CLASS_NAME "Efl.Ui.Spin"
17 18
18static Eina_Bool
19_is_valid_digit(char x)
20{
21 return ((x >= '0' && x <= '9') || (x == '.')) ? EINA_TRUE : EINA_FALSE;
22}
23
24static Efl_Ui_Spin_Format_Type
25_is_label_format_integer(const char *fmt)
26{
27 const char *itr = NULL;
28 const char *start = NULL;
29 Eina_Bool found = EINA_FALSE;
30 Efl_Ui_Spin_Format_Type ret_type = SPIN_FORMAT_INVALID;
31
32 start = strchr(fmt, '%');
33 if (!start) return SPIN_FORMAT_INVALID;
34
35 while (start)
36 {
37 if (found && start[1] != '%')
38 {
39 return SPIN_FORMAT_INVALID;
40 }
41
42 if (start[1] != '%' && !found)
43 {
44 found = EINA_TRUE;
45 for (itr = start + 1; *itr != '\0'; itr++)
46 {
47 if ((*itr == 'd') || (*itr == 'u') || (*itr == 'i') ||
48 (*itr == 'o') || (*itr == 'x') || (*itr == 'X'))
49 {
50 ret_type = SPIN_FORMAT_INT;
51 break;
52 }
53 else if ((*itr == 'f') || (*itr == 'F'))
54 {
55 ret_type = SPIN_FORMAT_FLOAT;
56 break;
57 }
58 else if (_is_valid_digit(*itr))
59 {
60 continue;
61 }
62 else
63 {
64 return SPIN_FORMAT_INVALID;
65 }
66 }
67 }
68 start = strchr(start + 2, '%');
69 }
70
71 return ret_type;
72}
73static void 19static void
74_label_write(Evas_Object *obj) 20_label_write(Evas_Object *obj, Efl_Ui_Spin_Data *sd)
75{ 21{
76 Efl_Ui_Spin_Special_Value *sv; 22 Eina_Strbuf *strbuf = eina_strbuf_new();
77 unsigned int i; 23 Eina_Value val = eina_value_double_init(sd->val);
78 Eina_Array_Iterator iterator; 24 efl_ui_format_formatted_value_get(obj, strbuf, val);
79 25
80 Efl_Ui_Spin_Data *sd = efl_data_scope_get(obj, MY_CLASS); 26 elm_layout_text_set(obj, "efl.text", eina_strbuf_string_get(strbuf));
81 27
82 EINA_ARRAY_ITER_NEXT(sd->special_values, i, sv, iterator) 28 eina_value_flush(&val);
83 { 29 eina_strbuf_free(strbuf);
84 if (sv->value == sd->val)
85 {
86 char buf[1024];
87 snprintf(buf, sizeof(buf), "%s", sv->label);
88 elm_layout_text_set(obj, "elm.text", buf);
89 sd->templates = sv->label;
90 return;
91 }
92 }
93
94 if (sd->format_cb)
95 {
96 const char *buf;
97 Eina_Value val;
98
99 if (sd->format_type == SPIN_FORMAT_INT)
100 {
101 eina_value_setup(&val, EINA_VALUE_TYPE_INT);
102 eina_value_set(&val, (int)sd->val);
103 }
104 else
105 {
106 eina_value_setup(&val, EINA_VALUE_TYPE_DOUBLE);
107 eina_value_set(&val, sd->val);
108 }
109 eina_strbuf_reset(sd->format_strbuf);
110 sd->format_cb(sd->format_cb_data, sd->format_strbuf, val);
111
112 buf = eina_strbuf_string_get(sd->format_strbuf);
113 eina_value_flush(&val);
114 elm_layout_text_set(obj, "efl.text", buf);
115 sd->templates = buf;
116 }
117 else
118 {
119 char buf[1024];
120 snprintf(buf, sizeof(buf), "%.0f", sd->val);
121 elm_layout_text_set(obj, "efl.text", buf);
122 evas_object_show(obj);
123 }
124}
125
126static int
127_decimal_points_get(const char *label)
128{
129 char result[16] = "0";
130 const char *start = strchr(label, '%');
131
132 while (start)
133 {
134 if (start[1] != '%')
135 {
136 start = strchr(start, '.');
137 if (start)
138 start++;
139 break;
140 }
141 else
142 start = strchr(start + 2, '%');
143 }
144
145 if (start)
146 {
147 const char *p = strchr(start, 'f');
148
149 if ((p) && ((p - start) < 15))
150 sscanf(start, "%[^f]", result);
151 }
152
153 return atoi(result);
154} 30}
155 31
156EOLIAN static void 32EOLIAN static void
@@ -188,48 +64,6 @@ _efl_ui_spin_efl_ui_widget_widget_input_event_handler(Eo *obj, Efl_Ui_Spin_Data
188 return EINA_TRUE; 64 return EINA_TRUE;
189} 65}
190 66
191EOLIAN static void
192_efl_ui_spin_special_value_set(Eo *obj, Efl_Ui_Spin_Data *sd, const Eina_Array *values)
193{
194 EINA_SAFETY_ON_NULL_RETURN(values);
195
196 unsigned int i;
197 Efl_Ui_Spin_Special_Value *sv;
198 Efl_Ui_Spin_Special_Value *temp;
199 Eina_Array_Iterator iterator;
200
201 if (eina_array_count(sd->special_values))
202 {
203 EINA_ARRAY_ITER_NEXT(sd->special_values, i, sv, iterator)
204 {
205 eina_stringshare_del(sv->label);
206 free(sv);
207 }
208 eina_array_clean(sd->special_values);
209 }
210
211 if (eina_array_count(values))
212 EINA_ARRAY_ITER_NEXT(values, i, temp, iterator)
213 {
214 sv = calloc(1, sizeof(*sv));
215 if (!sv) return;
216 sv->value = temp->value;
217 sv->label = eina_stringshare_add(temp->label);
218 eina_array_push(sd->special_values, sv);
219 }
220
221 _label_write(obj);
222}
223
224EOLIAN static const Eina_Array*
225_efl_ui_spin_special_value_get(const Eo *obj EINA_UNUSED, Efl_Ui_Spin_Data *sd)
226{
227 if (eina_array_count(sd->special_values))
228 return sd->special_values;
229 else
230 return NULL;
231}
232
233EOLIAN static Eo * 67EOLIAN static Eo *
234_efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd) 68_efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd)
235{ 69{
@@ -241,7 +75,6 @@ _efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd)
241 75
242 sd->val_max = 100.0; 76 sd->val_max = 100.0;
243 sd->step = 1.0; 77 sd->step = 1.0;
244 sd->special_values = eina_array_new(sizeof(Efl_Ui_Spin_Special_Value));
245 78
246 if (elm_widget_theme_object_set(obj, wd->resize_obj, 79 if (elm_widget_theme_object_set(obj, wd->resize_obj,
247 elm_widget_theme_klass_get(obj), 80 elm_widget_theme_klass_get(obj),
@@ -249,7 +82,7 @@ _efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd)
249 elm_widget_theme_style_get(obj)) == EFL_UI_THEME_APPLY_ERROR_GENERIC) 82 elm_widget_theme_style_get(obj)) == EFL_UI_THEME_APPLY_ERROR_GENERIC)
250 CRI("Failed to set layout!"); 83 CRI("Failed to set layout!");
251 84
252 _label_write(obj); 85 _label_write(obj, sd);
253 elm_widget_can_focus_set(obj, EINA_TRUE); 86 elm_widget_can_focus_set(obj, EINA_TRUE);
254 87
255 elm_layout_sizing_eval(obj); 88 elm_layout_sizing_eval(obj);
@@ -260,50 +93,13 @@ _efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd)
260EOLIAN static void 93EOLIAN static void
261_efl_ui_spin_efl_object_destructor(Eo *obj, Efl_Ui_Spin_Data *sd EINA_UNUSED) 94_efl_ui_spin_efl_object_destructor(Eo *obj, Efl_Ui_Spin_Data *sd EINA_UNUSED)
262{ 95{
263 Efl_Ui_Spin_Special_Value *sv;
264 Eina_Array_Iterator iterator;
265 unsigned int i;
266
267 efl_ui_format_cb_set(obj, NULL, NULL, NULL);
268
269 EINA_ARRAY_ITER_NEXT(sd->special_values, i, sv, iterator)
270 {
271 eina_stringshare_del(sv->label);
272 free(sv);
273 }
274 eina_array_free(sd->special_values);
275
276 efl_destructor(efl_super(obj, MY_CLASS)); 96 efl_destructor(efl_super(obj, MY_CLASS));
277} 97}
278 98
279EOLIAN static void 99EOLIAN static void
280_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) 100_efl_ui_spin_efl_ui_format_apply_formatted_value(Eo *obj, Efl_Ui_Spin_Data *sd EINA_UNUSED)
281{ 101{
282 if (sd->format_cb_data == func_data && sd->format_cb == func) 102 _label_write(obj, sd);
283 return;
284
285 if (sd->format_cb_data && sd->format_free_cb)
286 sd->format_free_cb(sd->format_cb_data);
287
288 sd->format_cb = func;
289 sd->format_cb_data = func_data;
290 sd->format_free_cb = func_free_cb;
291 if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
292
293 const char *format = efl_ui_format_string_get(obj);
294 if (format)
295 {
296 sd->format_type = _is_label_format_integer(format);
297 if (sd->format_type == SPIN_FORMAT_INVALID)
298 {
299 ERR("format:\"%s\" is invalid, cannot be set", format);
300 return;
301 }
302 else if (sd->format_type == SPIN_FORMAT_FLOAT)
303 sd->decimal_points = _decimal_points_get(format);
304 }
305
306 _label_write(obj);
307 elm_layout_sizing_eval(obj); 103 elm_layout_sizing_eval(obj);
308} 104}
309 105
@@ -325,7 +121,7 @@ _efl_ui_spin_efl_ui_range_display_range_limits_set(Eo *obj, Efl_Ui_Spin_Data *sd
325 if (sd->val < sd->val_min) sd->val = sd->val_min; 121 if (sd->val < sd->val_min) sd->val = sd->val_min;
326 if (sd->val > sd->val_max) sd->val = sd->val_max; 122 if (sd->val > sd->val_max) sd->val = sd->val_max;
327 123
328 _label_write(obj); 124 _label_write(obj, sd);
329} 125}
330 126
331EOLIAN static void 127EOLIAN static void
@@ -372,7 +168,7 @@ _efl_ui_spin_efl_ui_range_display_range_value_set(Eo *obj, Efl_Ui_Spin_Data *sd,
372 168
373 efl_event_callback_call(obj, EFL_UI_SPIN_EVENT_CHANGED, NULL); 169 efl_event_callback_call(obj, EFL_UI_SPIN_EVENT_CHANGED, NULL);
374 170
375 _label_write(obj); 171 _label_write(obj, sd);
376} 172}
377 173
378EOLIAN static double 174EOLIAN static double
diff --git a/src/lib/elementary/efl_ui_spin.eo b/src/lib/elementary/efl_ui_spin.eo
index 4fee3df..7f02d5a 100644
--- a/src/lib/elementary/efl_ui_spin.eo
+++ b/src/lib/elementary/efl_ui_spin.eo
@@ -1,36 +1,11 @@
1struct @beta Efl.Ui.Spin_Special_Value
2{
3 [[Special value]]
4 value: double; [[Target value]]
5 label: string; [[String to replace]]
6}
7
8class @beta Efl.Ui.Spin extends Efl.Ui.Layout_Base implements Efl.Ui.Range_Interactive, Efl.Ui.Format, 1class @beta Efl.Ui.Spin extends Efl.Ui.Layout_Base implements Efl.Ui.Range_Interactive, Efl.Ui.Format,
9 Efl.Access.Value, Efl.Access.Widget.Action 2 Efl.Access.Value, Efl.Access.Widget.Action
10{ 3{
11 [[A Spin. 4 [[A Spin.
12 5
13 This is a widget which allows the user to increase or decrease numeric values 6 This is a widget which allows the user to increase or decrease a numeric value
14 using user interactions. It's a basic type of widget for choosing and displaying values. 7 using arrow buttons. It's a basic type of widget for choosing and displaying values.
15 ]] 8 ]]
16 methods {
17 @property special_value {
18 [[Control special string to display in the place of the numerical value.
19
20 It's useful for cases when a user should select an item that is
21 better indicated by a label than a value. For example, weekdays or months.
22
23 Note: If another label was previously set to $value, it will be replaced
24 by the new label.]]
25 set {
26 }
27 get {
28 }
29 values {
30 values: const(array<ptr(Efl.Ui.Spin_Special_Value)>); [[The array of special values, or NULL if none]]
31 }
32 }
33 }
34 implements { 9 implements {
35 Efl.Object.constructor; 10 Efl.Object.constructor;
36 Efl.Object.destructor; 11 Efl.Object.destructor;
@@ -38,7 +13,7 @@ class @beta Efl.Ui.Spin extends Efl.Ui.Layout_Base implements Efl.Ui.Range_Inter
38 Efl.Ui.Range_Display.range_limits { get; set; } 13 Efl.Ui.Range_Display.range_limits { get; set; }
39 Efl.Ui.Range_Interactive.range_step { get; set; } 14 Efl.Ui.Range_Interactive.range_step { get; set; }
40 Efl.Ui.Range_Display.range_value { get; set; } 15 Efl.Ui.Range_Display.range_value { get; set; }
41 Efl.Ui.Format.format_cb { set; } 16 Efl.Ui.Format.apply_formatted_value;
42 } 17 }
43 events { 18 events {
44 changed: void; [[Called when spin changed]] 19 changed: void; [[Called when spin changed]]
diff --git a/src/lib/elementary/efl_ui_spin_button.c b/src/lib/elementary/efl_ui_spin_button.c
index 71eaec1..c356686 100644
--- a/src/lib/elementary/efl_ui_spin_button.c
+++ b/src/lib/elementary/efl_ui_spin_button.c
@@ -6,6 +6,7 @@
6#define EFL_ACCESS_VALUE_PROTECTED 6#define EFL_ACCESS_VALUE_PROTECTED
7#define EFL_ACCESS_WIDGET_ACTION_PROTECTED 7#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
8#define EFL_UI_FOCUS_COMPOSITION_PROTECTED 8#define EFL_UI_FOCUS_COMPOSITION_PROTECTED
9#define EFL_UI_FORMAT_PROTECTED
9 10
10#include <Elementary.h> 11#include <Elementary.h>
11 12
@@ -50,29 +51,20 @@ EFL_CALLBACKS_ARRAY_DEFINE(_inc_dec_button_cb,
50static void 51static void
51_entry_show(Evas_Object *obj) 52_entry_show(Evas_Object *obj)
52{ 53{
53 Efl_Ui_Spin_Special_Value *sv;
54 Eina_Array_Iterator iterator;
55 unsigned int i;
56 char buf[32], fmt[32] = "%0.f"; 54 char buf[32], fmt[32] = "%0.f";
57 55
58 Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); 56 Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS);
59 Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); 57 Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS);
60 58
61 EINA_ARRAY_ITER_NEXT(pd->special_values, i, sv, iterator) 59 const char *format_string;
62 { 60 efl_ui_format_string_get(obj, &format_string, NULL);
63 if (sv->value == pd->val)
64 {
65 snprintf(buf, sizeof(buf), "%s", sv->label);
66 elm_object_text_set(sd->ent, buf);
67 }
68 }
69 61
70 /* try to construct just the format from given label 62 /* try to construct just the format from given label
71 * completely ignoring pre/post words 63 * completely ignoring pre/post words
72 */ 64 */
73 if (pd->templates) 65 if (format_string)
74 { 66 {
75 const char *start = strchr(pd->templates, '%'); 67 const char *start = strchr(format_string, '%');
76 while (start) 68 while (start)
77 { 69 {
78 /* handle %% */ 70 /* handle %% */
@@ -103,10 +95,7 @@ _entry_show(Evas_Object *obj)
103 } 95 }
104 } 96 }
105 97
106 if (pd->format_type == SPIN_FORMAT_INT) 98 snprintf(buf, sizeof(buf), fmt, pd->val);
107 snprintf(buf, sizeof(buf), fmt, (int)pd->val);
108 else
109 snprintf(buf, sizeof(buf), fmt, pd->val);
110 99
111 elm_object_text_set(sd->ent, buf); 100 elm_object_text_set(sd->ent, buf);
112} 101}
@@ -115,20 +104,16 @@ static void
115_label_write(Evas_Object *obj) 104_label_write(Evas_Object *obj)
116{ 105{
117 Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); 106 Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS);
118
119 Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS); 107 Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS);
120 108
121 if (pd->templates) 109 Eina_Strbuf *strbuf = eina_strbuf_new();
122 { 110 Eina_Value val = eina_value_double_init(pd->val);
123 efl_text_set(sd->text_button, pd->templates); 111 efl_ui_format_formatted_value_get(obj, strbuf, val);
124 }
125 else
126 {
127 char buf[1024];
128 112
129 snprintf(buf, sizeof(buf), "%.0f", pd->val); 113 efl_text_set(sd->text_button, eina_strbuf_string_get(strbuf));
130 efl_text_set(sd->text_button, buf); 114
131 } 115 eina_value_flush(&val);
116 eina_strbuf_free(strbuf);
132} 117}
133 118
134static Eina_Bool 119static Eina_Bool
@@ -182,9 +167,6 @@ _entry_hide(Evas_Object *obj)
182static void 167static void
183_entry_value_apply(Evas_Object *obj) 168_entry_value_apply(Evas_Object *obj)
184{ 169{
185 Efl_Ui_Spin_Special_Value *sv;
186 Eina_Array_Iterator iterator;
187 unsigned int i;
188 const char *str; 170 const char *str;
189 double val; 171 double val;
190 char *end; 172 char *end;
@@ -200,10 +182,6 @@ _entry_value_apply(Evas_Object *obj)
200 str = elm_object_text_get(sd->ent); 182 str = elm_object_text_get(sd->ent);
201 if (!str) return; 183 if (!str) return;
202 184
203 EINA_ARRAY_ITER_NEXT(pd->special_values, i, sv, iterator)
204 if (sv->value == pd->val)
205 if (!strcmp(sv->label, str)) return;
206
207 val = strtod(str, &end); 185 val = strtod(str, &end);
208 if (((*end != '\0') && (!isspace(*end))) || (fabs(val - pd->val) < DBL_EPSILON)) return; 186 if (((*end != '\0') && (!isspace(*end))) || (fabs(val - pd->val) < DBL_EPSILON)) return;
209 efl_ui_range_value_set(obj, val); 187 efl_ui_range_value_set(obj, val);
@@ -267,14 +245,14 @@ static void
267_entry_accept_filter_add(Evas_Object *obj) 245_entry_accept_filter_add(Evas_Object *obj)
268{ 246{
269 Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS); 247 Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS);
270 Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS);
271 static Elm_Entry_Filter_Accept_Set digits_filter_data; 248 static Elm_Entry_Filter_Accept_Set digits_filter_data;
249 int decimal_places = efl_ui_format_decimal_places_get(obj);
272 250
273 if (!sd->ent) return; 251 if (!sd->ent) return;
274 252
275 elm_entry_markup_filter_remove(sd->ent, elm_entry_filter_accept_set, &digits_filter_data); 253 elm_entry_markup_filter_remove(sd->ent, elm_entry_filter_accept_set, &digits_filter_data);
276 254
277 if (pd->decimal_points > 0) 255 if (decimal_places > 0)
278 digits_filter_data.accepted = "-.0123456789"; 256 digits_filter_data.accepted = "-.0123456789";
279 else 257 else
280 digits_filter_data.accepted = "-0123456789"; 258 digits_filter_data.accepted = "-0123456789";
@@ -307,6 +285,7 @@ _min_max_validity_filter(void *data, Evas_Object *obj, char **text)
307 char *insert, *new_str = NULL; 285 char *insert, *new_str = NULL;
308 double val; 286 double val;
309 int max_len = 0, len; 287 int max_len = 0, len;
288 int decimal_places = efl_ui_format_decimal_places_get(data);
310 289
311 EINA_SAFETY_ON_NULL_RETURN(data); 290 EINA_SAFETY_ON_NULL_RETURN(data);
312 EINA_SAFETY_ON_NULL_RETURN(obj); 291 EINA_SAFETY_ON_NULL_RETURN(obj);
@@ -322,12 +301,12 @@ _min_max_validity_filter(void *data, Evas_Object *obj, char **text)
322 if (!new_str) return; 301 if (!new_str) return;
323 if (strchr(new_str, '-')) max_len++; 302 if (strchr(new_str, '-')) max_len++;
324 303
325 if (pd->format_type == SPIN_FORMAT_FLOAT) 304 if (decimal_places > 0)
326 { 305 {
327 point = strchr(new_str, '.'); 306 point = strchr(new_str, '.');
328 if (point) 307 if (point)
329 { 308 {
330 if ((int) strlen(point + 1) > pd->decimal_points) 309 if ((int) strlen(point + 1) > decimal_places)
331 { 310 {
332 *insert = 0; 311 *insert = 0;
333 goto end; 312 goto end;
diff --git a/src/lib/elementary/efl_ui_spin_private.h b/src/lib/elementary/efl_ui_spin_private.h
index 3d21e3d..3dbc06b 100644
--- a/src/lib/elementary/efl_ui_spin_private.h
+++ b/src/lib/elementary/efl_ui_spin_private.h
@@ -3,29 +3,11 @@
3 3
4#include "Elementary.h" 4#include "Elementary.h"
5 5
6typedef enum _Efl_Ui_Spin_Format_Type
7{
8 SPIN_FORMAT_FLOAT,
9 SPIN_FORMAT_INT,
10 SPIN_FORMAT_INVALID
11} Efl_Ui_Spin_Format_Type;
12
13typedef struct _Efl_Ui_Spin_Data Efl_Ui_Spin_Data; 6typedef struct _Efl_Ui_Spin_Data Efl_Ui_Spin_Data;
14struct _Efl_Ui_Spin_Data 7struct _Efl_Ui_Spin_Data
15{ 8{
16 const char *templates;
17 double val, val_min, val_max; 9 double val, val_min, val_max;
18 double step; /**< step for the value change. 1 by default. */ 10 double step; /**< step for the value change. 1 by default. */
19 int decimal_points;
20 Ecore_Timer *spin_timer; /**< a timer for a repeated spin value change on mouse down */
21 Efl_Ui_Spin_Format_Type format_type;
22
23 Efl_Ui_Format_Func_Cb format_cb;
24 Eina_Free_Cb format_free_cb;
25 void *format_cb_data;
26 Eina_Strbuf *format_strbuf;
27
28 Eina_Array *special_values;
29}; 11};
30 12
31#endif 13#endif
diff --git a/src/lib/elementary/efl_ui_tags.c b/src/lib/elementary/efl_ui_tags.c
index 12b56c1..34bc487 100644
--- a/src/lib/elementary/efl_ui_tags.c
+++ b/src/lib/elementary/efl_ui_tags.c
@@ -2,6 +2,8 @@
2# include "elementary_config.h" 2# include "elementary_config.h"
3#endif 3#endif
4 4
5#define EFL_UI_FORMAT_PROTECTED
6
5#include <Elementary.h> 7#include <Elementary.h>
6#include "elm_priv.h" 8#include "elm_priv.h"
7#include "efl_ui_tags_private.h" 9#include "efl_ui_tags_private.h"
@@ -75,7 +77,6 @@ _shrink_mode_set(Eo *obj,
75 77
76 EINA_LIST_FOREACH(sd->layouts, l, layout) 78 EINA_LIST_FOREACH(sd->layouts, l, layout)
77 { 79 {
78 char buf[32];
79 Evas_Coord w_label_count = 0, h = 0; 80 Evas_Coord w_label_count = 0, h = 0;
80 81
81 elm_box_pack_end(sd->box, layout); 82 elm_box_pack_end(sd->box, layout);
@@ -92,19 +93,12 @@ _shrink_mode_set(Eo *obj,
92 93
93 if (count > 0) 94 if (count > 0)
94 { 95 {
95 if (sd->format_cb) 96 Eina_Strbuf *strbuf = eina_strbuf_new();
96 { 97 eina_value_set(&val, count);
97 eina_strbuf_reset(sd->format_strbuf); 98 efl_ui_format_formatted_value_get(obj, strbuf, val);
98 eina_value_set(&val, count); 99 edje_object_part_text_escaped_set(sd->end, "efl.text",
99 sd->format_cb(sd->format_cb_data, sd->format_strbuf, val); 100 eina_strbuf_string_get(strbuf));
100 edje_object_part_text_escaped_set(sd->end, "efl.text", 101 eina_strbuf_free(strbuf);
101 eina_strbuf_string_get(sd->format_strbuf));
102 }
103 else
104 {
105 snprintf(buf, sizeof(buf), "+ %d", count);
106 edje_object_part_text_escaped_set(sd->end, "efl.text", buf);
107 }
108 102
109 edje_object_size_min_calc(sd->end, &w_label_count, NULL); 103 edje_object_size_min_calc(sd->end, &w_label_count, NULL);
110 elm_coords_finger_size_adjust(1, &w_label_count, 1, NULL); 104 elm_coords_finger_size_adjust(1, &w_label_count, 1, NULL);
@@ -112,23 +106,16 @@ _shrink_mode_set(Eo *obj,
112 106
113 if ((w < 0) || (w < w_label_count)) 107 if ((w < 0) || (w < w_label_count))
114 { 108 {
109 Eina_Strbuf *strbuf = eina_strbuf_new();
115 elm_box_unpack(sd->box, layout); 110 elm_box_unpack(sd->box, layout);
116 evas_object_hide(layout); 111 evas_object_hide(layout);
117 count++; 112 count++;
118 113
119 if (sd->format_cb) 114 eina_value_set(&val, count);
120 { 115 efl_ui_format_formatted_value_get(obj, strbuf, val);
121 eina_strbuf_reset(sd->format_strbuf); 116 edje_object_part_text_escaped_set(sd->end, "efl.text",
122 eina_value_set(&val, count); 117 eina_strbuf_string_get(strbuf));
123 sd->format_cb(sd->format_cb_data, sd->format_strbuf, val); 118 eina_strbuf_free(strbuf);
124 edje_object_part_text_escaped_set(sd->end, "efl.text",
125 eina_strbuf_string_get(sd->format_strbuf));
126 }
127 else
128 {
129 snprintf(buf, sizeof(buf), "+ %d", count);
130 edje_object_part_text_escaped_set(sd->end, "efl.text", buf);
131 }
132 119
133 edje_object_size_min_calc(sd->end, &w_label_count, &h); 120 edje_object_size_min_calc(sd->end, &w_label_count, &h);
134 elm_coords_finger_size_adjust(1, &w_label_count, 1, &h); 121 elm_coords_finger_size_adjust(1, &w_label_count, 1, &h);
@@ -1021,7 +1008,6 @@ _efl_ui_tags_efl_object_constructor(Eo *obj, Efl_Ui_Tags_Data *sd)
1021 sd->last_it_select = EINA_TRUE; 1008 sd->last_it_select = EINA_TRUE;
1022 sd->editable = EINA_TRUE; 1009 sd->editable = EINA_TRUE;
1023 sd->parent = obj; 1010 sd->parent = obj;
1024 sd->format_cb = NULL;
1025 sd->it_array = eina_array_new(4); 1011 sd->it_array = eina_array_new(4);
1026 1012
1027 _view_init(obj, sd); 1013 _view_init(obj, sd);
@@ -1054,9 +1040,6 @@ _efl_ui_tags_efl_object_destructor(Eo *obj, Efl_Ui_Tags_Data *sd)
1054 evas_object_del(sd->end); 1040 evas_object_del(sd->end);
1055 ecore_timer_del(sd->longpress_timer); 1041 ecore_timer_del(sd->longpress_timer);
1056 1042
1057 efl_ui_format_cb_set(obj, NULL, NULL, NULL);
1058 eina_strbuf_free(sd->format_strbuf);
1059
1060 efl_destructor(efl_super(obj, MY_CLASS)); 1043 efl_destructor(efl_super(obj, MY_CLASS));
1061} 1044}
1062 1045
@@ -1072,23 +1055,6 @@ _efl_ui_tags_efl_text_text_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *sd)
1072 return (sd->label_str ? sd->label_str : NULL); 1055 return (sd->label_str ? sd->label_str : NULL);
1073} 1056}
1074 1057
1075EOLIAN static void
1076_efl_ui_tags_efl_ui_format_format_cb_set(Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *sd, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb)
1077{
1078 if ((sd->format_cb_data == func_data) && (sd->format_cb == func))
1079 return;
1080
1081 if (sd->format_cb_data && sd->format_free_cb)
1082 sd->format_free_cb(sd->format_cb_data);
1083
1084 sd->format_cb = func;
1085 sd->format_cb_data = func_data;
1086 sd->format_free_cb = func_free_cb;
1087 if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
1088
1089 _view_update(sd);
1090}
1091
1092EOLIAN static Eina_Bool 1058EOLIAN static Eina_Bool
1093_efl_ui_tags_expanded_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *sd) 1059_efl_ui_tags_expanded_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *sd)
1094{ 1060{
@@ -1171,6 +1137,11 @@ _efl_ui_tags_items_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *sd)
1171 1137
1172 return sd->it_array; 1138 return sd->it_array;
1173} 1139}
1140EOLIAN static void
1141_efl_ui_tags_efl_ui_format_apply_formatted_value(Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *pd)
1142{
1143 _view_update(pd);
1144}
1174 1145
1175#define EFL_UI_TAGS_EXTRA_OPS \ 1146#define EFL_UI_TAGS_EXTRA_OPS \
1176 ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_tags), \ 1147 ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_tags), \
diff --git a/src/lib/elementary/efl_ui_tags.eo b/src/lib/elementary/efl_ui_tags.eo
index 86e83ab..6f8c739 100644
--- a/src/lib/elementary/efl_ui_tags.eo
+++ b/src/lib/elementary/efl_ui_tags.eo
@@ -47,7 +47,7 @@ class @beta Efl.Ui.Tags extends Efl.Ui.Layout_Base implements Efl.Text, Efl.Ui.F
47 Efl.Object.destructor; 47 Efl.Object.destructor;
48 Efl.Ui.Widget.widget_input_event_handler; 48 Efl.Ui.Widget.widget_input_event_handler;
49 Efl.Text.text { get; set; } 49 Efl.Text.text { get; set; }
50 Efl.Ui.Format.format_cb { set; } 50 Efl.Ui.Format.apply_formatted_value;
51 } 51 }
52 events { 52 events {
53 /* FIXME: Returning a basic type is not future-proof, better return a struct */ 53 /* FIXME: Returning a basic type is not future-proof, better return a struct */
diff --git a/src/lib/elementary/efl_ui_tags_private.h b/src/lib/elementary/efl_ui_tags_private.h
index 49d0a95..ef9fca6 100644
--- a/src/lib/elementary/efl_ui_tags_private.h
+++ b/src/lib/elementary/efl_ui_tags_private.h
@@ -34,11 +34,6 @@ struct _Efl_Ui_Tags_Data
34 Evas_Coord w_box, h_box; 34 Evas_Coord w_box, h_box;
35 int shrink; 35 int shrink;
36 36
37 Efl_Ui_Format_Func_Cb format_cb;
38 Eina_Free_Cb format_free_cb;
39 void *format_cb_data;
40 Eina_Strbuf *format_strbuf;
41
42 Eina_Bool last_it_select : 1; 37 Eina_Bool last_it_select : 1;
43 Eina_Bool editable : 1; 38 Eina_Bool editable : 1;
44 Eina_Bool focused : 1; 39 Eina_Bool focused : 1;
diff --git a/src/lib/elementary/elm_slider.c b/src/lib/elementary/elm_slider.c
index e57893c..8239e47 100644
--- a/src/lib/elementary/elm_slider.c
+++ b/src/lib/elementary/elm_slider.c
@@ -7,6 +7,7 @@
7#define EFL_ACCESS_VALUE_PROTECTED 7#define EFL_ACCESS_VALUE_PROTECTED
8#define ELM_LAYOUT_PROTECTED 8#define ELM_LAYOUT_PROTECTED
9#define EFL_PART_PROTECTED 9#define EFL_PART_PROTECTED
10#define EFL_UI_FORMAT_PROTECTED
10 11
11#include <Elementary.h> 12#include <Elementary.h>
12 13
@@ -953,7 +954,7 @@ _elm_slider_efl_object_constructor(Eo *obj, Elm_Slider_Data *priv)
953 954
954 elm_widget_can_focus_set(obj, EINA_TRUE); 955 elm_widget_can_focus_set(obj, EINA_TRUE);
955 956
956 efl_ui_format_string_set(efl_part(obj, "indicator"), "%0.2f"); 957 efl_ui_format_string_set(efl_part(obj, "indicator"), "%0.2f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
957 958
958 evas_object_event_callback_add 959 evas_object_event_callback_add
959 (sd->spacer, EVAS_CALLBACK_MOUSE_DOWN, _spacer_down_cb, obj); 960 (sd->spacer, EVAS_CALLBACK_MOUSE_DOWN, _spacer_down_cb, obj);
@@ -976,7 +977,7 @@ _elm_slider_efl_object_destructor(Eo *obj,
976 ELM_SAFE_FREE(sd->indi_template, eina_stringshare_del); 977 ELM_SAFE_FREE(sd->indi_template, eina_stringshare_del);
977 eina_strbuf_free(sd->indi_format_strbuf); 978 eina_strbuf_free(sd->indi_format_strbuf);
978 979
979 efl_ui_format_cb_set(obj, NULL, NULL, NULL); 980 efl_ui_format_func_set(obj, NULL, NULL, NULL);
980 eina_strbuf_free(sd->format_strbuf); 981 eina_strbuf_free(sd->format_strbuf);
981 982
982 efl_destructor(efl_super(obj, MY_CLASS)); 983 efl_destructor(efl_super(obj, MY_CLASS));
@@ -1004,7 +1005,7 @@ _elm_slider_class_constructor(Efl_Class *klass)
1004} 1005}
1005 1006
1006EOLIAN static void 1007EOLIAN static void
1007_elm_slider_efl_ui_format_format_cb_set(Eo *obj, Elm_Slider_Data *sd, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb) 1008_elm_slider_efl_ui_format_format_cb_set(Eo *obj, Elm_Slider_Data *sd, void *func_data, Efl_Ui_Format_Func func, Eina_Free_Cb func_free_cb)
1008{ 1009{
1009 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); 1010 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1010 1011
@@ -1076,7 +1077,7 @@ _elm_slider_efl_part_part_get(const Eo *obj, Elm_Slider_Data *sd EINA_UNUSED, co
1076} 1077}
1077 1078
1078EOLIAN static void 1079EOLIAN static void
1079_elm_slider_part_indicator_efl_ui_format_format_cb_set(Eo *obj, void *_pd EINA_UNUSED, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb) 1080_elm_slider_part_indicator_efl_ui_format_format_cb_set(Eo *obj, void *_pd EINA_UNUSED, void *func_data, Efl_Ui_Format_Func func, Eina_Free_Cb func_free_cb)
1080{ 1081{
1081 Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS); 1082 Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
1082 Elm_Slider_Data *sd = efl_data_scope_get(pd->obj, ELM_SLIDER_CLASS); 1083 Elm_Slider_Data *sd = efl_data_scope_get(pd->obj, ELM_SLIDER_CLASS);
@@ -1095,17 +1096,19 @@ _elm_slider_part_indicator_efl_ui_format_format_cb_set(Eo *obj, void *_pd EINA_U
1095 efl_canvas_group_change(pd->obj); 1096 efl_canvas_group_change(pd->obj);
1096} 1097}
1097 1098
1098static void 1099static Eina_Bool
1099_indi_default_format_cb(void *data, Eina_Strbuf *str, const Eina_Value value) 1100_indi_default_format_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
1100{ 1101{
1101 const Eina_Value_Type *type = eina_value_type_get(&value); 1102 const Eina_Value_Type *type = eina_value_type_get(&value);
1102 Elm_Slider_Data *sd = efl_data_scope_get(data, ELM_SLIDER_CLASS); 1103 Elm_Slider_Data *sd = efl_data_scope_get(data, ELM_SLIDER_CLASS);
1103 double v; 1104 double v;
1104 1105
1105 if (type != EINA_VALUE_TYPE_DOUBLE) return; 1106 if (type != EINA_VALUE_TYPE_DOUBLE) return EINA_FALSE;
1106 1107
1107 eina_value_get(&value, &v); 1108 eina_value_get(&value, &v);
1108 eina_strbuf_append_printf(str, sd->indi_template, v); 1109 eina_strbuf_append_printf(str, sd->indi_template, v);
1110
1111 return EINA_TRUE;
1109} 1112}
1110 1113
1111static void 1114static void
@@ -1129,7 +1132,7 @@ _elm_slider_part_indicator_efl_ui_format_format_string_set(Eo *obj, void *_pd EI
1129 if (!template) return; 1132 if (!template) return;
1130 eina_stringshare_replace(&sd->indi_template, template); 1133 eina_stringshare_replace(&sd->indi_template, template);
1131 1134
1132 efl_ui_format_cb_set(efl_part(pd->obj, "indicator"), pd->obj, _indi_default_format_cb, _indi_default_format_free_cb); 1135 efl_ui_format_func_set(efl_part(pd->obj, "indicator"), pd->obj, _indi_default_format_cb, _indi_default_format_free_cb);
1133} 1136}
1134 1137
1135EOLIAN static const char * 1138EOLIAN static const char *
@@ -1164,6 +1167,10 @@ _elm_slider_part_indicator_visible_mode_get(const Eo *obj, void *_pd EINA_UNUSED
1164 return sd->indicator_visible_mode; 1167 return sd->indicator_visible_mode;
1165} 1168}
1166 1169
1170void _elm_slider_part_indicator_efl_ui_format_apply_formatted_value(Eo *obj EINA_UNUSED, Elm_Part_Data *pd EINA_UNUSED)
1171{
1172}
1173
1167#include "elm_slider_part_indicator_eo.c" 1174#include "elm_slider_part_indicator_eo.c"
1168 1175
1169/* Efl.Part end */ 1176/* Efl.Part end */
@@ -1194,13 +1201,15 @@ elm_slider_span_size_get(const Evas_Object *obj)
1194EAPI void 1201EAPI void
1195elm_slider_unit_format_set(Evas_Object *obj, const char *units) 1202elm_slider_unit_format_set(Evas_Object *obj, const char *units)
1196{ 1203{
1197 efl_ui_format_string_set(obj, units); 1204 efl_ui_format_string_set(obj, units, EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
1198} 1205}
1199 1206
1200EAPI const char * 1207EAPI const char *
1201elm_slider_unit_format_get(const Evas_Object *obj) 1208elm_slider_unit_format_get(const Evas_Object *obj)
1202{ 1209{
1203 return efl_ui_format_string_get(obj); 1210 const char* fmt;
1211 efl_ui_format_string_get(obj, &fmt, NULL);
1212 return fmt;
1204} 1213}
1205 1214
1206EAPI void 1215EAPI void
@@ -1277,7 +1286,7 @@ typedef struct
1277 slider_freefunc_type format_free_cb; 1286 slider_freefunc_type format_free_cb;
1278} Slider_Format_Wrapper_Data; 1287} Slider_Format_Wrapper_Data;
1279 1288
1280static void 1289static Eina_Bool
1281_format_legacy_to_format_eo_cb(void *data, Eina_Strbuf *str, const Eina_Value value) 1290_format_legacy_to_format_eo_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
1282{ 1291{
1283 Slider_Format_Wrapper_Data *sfwd = data; 1292 Slider_Format_Wrapper_Data *sfwd = data;
@@ -1293,6 +1302,8 @@ _format_legacy_to_format_eo_cb(void *data, Eina_Strbuf *str, const Eina_Value va
1293 if (buf) 1302 if (buf)
1294 eina_strbuf_append(str, buf); 1303 eina_strbuf_append(str, buf);
1295 if (sfwd->format_free_cb) sfwd->format_free_cb(buf); 1304 if (sfwd->format_free_cb) sfwd->format_free_cb(buf);
1305
1306 return EINA_TRUE;
1296} 1307}
1297 1308
1298static void 1309static void
@@ -1310,7 +1321,7 @@ elm_slider_units_format_function_set(Evas_Object *obj, slider_func_type func, sl
1310 sfwd->format_cb = func; 1321 sfwd->format_cb = func;
1311 sfwd->format_free_cb = free_func; 1322 sfwd->format_free_cb = free_func;
1312 1323
1313 efl_ui_format_cb_set(obj, sfwd, _format_legacy_to_format_eo_cb, _format_legacy_to_format_eo_free_cb); 1324 efl_ui_format_func_set(obj, sfwd, _format_legacy_to_format_eo_cb, _format_legacy_to_format_eo_free_cb);
1314} 1325}
1315 1326
1316EAPI void 1327EAPI void
@@ -1369,13 +1380,15 @@ elm_slider_min_max_get(const Evas_Object *obj, double *min, double *max)
1369EAPI void 1380EAPI void
1370elm_slider_indicator_format_set(Evas_Object *obj, const char *indicator) 1381elm_slider_indicator_format_set(Evas_Object *obj, const char *indicator)
1371{ 1382{
1372 efl_ui_format_string_set(efl_part(obj, "indicator"), indicator); 1383 efl_ui_format_string_set(efl_part(obj, "indicator"), indicator, EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
1373} 1384}
1374 1385
1375EAPI const char * 1386EAPI const char *
1376elm_slider_indicator_format_get(const Evas *obj) 1387elm_slider_indicator_format_get(const Evas *obj)
1377{ 1388{
1378 return efl_ui_format_string_get(efl_part(obj, "indicator")); 1389 const char *fmt;
1390 efl_ui_format_string_get(efl_part(obj, "indicator"), &fmt, NULL);
1391 return fmt;
1379} 1392}
1380 1393
1381EAPI void 1394EAPI void
@@ -1386,9 +1399,9 @@ elm_slider_indicator_format_function_set(Evas_Object *obj, slider_func_type func
1386 sfwd->format_cb = func; 1399 sfwd->format_cb = func;
1387 sfwd->format_free_cb = free_func; 1400 sfwd->format_free_cb = free_func;
1388 1401
1389 efl_ui_format_cb_set(efl_part(obj, "indicator"), sfwd, 1402 efl_ui_format_func_set(efl_part(obj, "indicator"), sfwd,
1390 _format_legacy_to_format_eo_cb, 1403 _format_legacy_to_format_eo_cb,
1391 _format_legacy_to_format_eo_free_cb); 1404 _format_legacy_to_format_eo_free_cb);
1392} 1405}
1393 1406
1394EAPI void 1407EAPI void
@@ -1452,6 +1465,10 @@ elm_slider_indicator_visible_mode_get(const Evas_Object *obj)
1452 return elm_slider_part_indicator_visible_mode_get(efl_part(obj, "indicator")); 1465 return elm_slider_part_indicator_visible_mode_get(efl_part(obj, "indicator"));
1453} 1466}
1454 1467
1468void _elm_slider_efl_ui_format_apply_formatted_value(Eo *obj EINA_UNUSED, Elm_Slider_Data *pd EINA_UNUSED)
1469{
1470}
1471
1455/* Internal EO APIs and hidden overrides */ 1472/* Internal EO APIs and hidden overrides */
1456 1473
1457ELM_LAYOUT_CONTENT_ALIASES_IMPLEMENT(elm_slider) 1474ELM_LAYOUT_CONTENT_ALIASES_IMPLEMENT(elm_slider)
diff --git a/src/lib/elementary/elm_slider_eo.c b/src/lib/elementary/elm_slider_eo.c
index 12debee..5f3ecc2 100644
--- a/src/lib/elementary/elm_slider_eo.c
+++ b/src/lib/elementary/elm_slider_eo.c
@@ -29,7 +29,7 @@ void _elm_slider_efl_text_markup_markup_set(Eo *obj, Elm_Slider_Data *pd, const
29const char *_elm_slider_efl_text_markup_markup_get(const Eo *obj, Elm_Slider_Data *pd); 29const char *_elm_slider_efl_text_markup_markup_get(const Eo *obj, Elm_Slider_Data *pd);
30 30
31 31
32void _elm_slider_efl_ui_format_format_cb_set(Eo *obj, Elm_Slider_Data *pd, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb); 32void _elm_slider_efl_ui_format_format_cb_set(Eo *obj, Elm_Slider_Data *pd, void *func_data, Efl_Ui_Format_Func func, Eina_Free_Cb func_free_cb);
33 33
34 34
35void _elm_slider_efl_ui_l10n_l10n_text_set(Eo *obj, Elm_Slider_Data *pd, const char *label, const char *domain); 35void _elm_slider_efl_ui_l10n_l10n_text_set(Eo *obj, Elm_Slider_Data *pd, const char *label, const char *domain);
@@ -40,6 +40,7 @@ const char *_elm_slider_efl_ui_l10n_l10n_text_get(const Eo *obj, Elm_Slider_Data
40 40
41Efl_Object *_elm_slider_efl_part_part_get(const Eo *obj, Elm_Slider_Data *pd, const char *name); 41Efl_Object *_elm_slider_efl_part_part_get(const Eo *obj, Elm_Slider_Data *pd, const char *name);
42 42
43void _elm_slider_efl_ui_format_apply_formatted_value(Eo *obj, Elm_Slider_Data *pd);
43 44
44static Eina_Bool 45static Eina_Bool
45_elm_slider_class_initializer(Efl_Class *klass) 46_elm_slider_class_initializer(Efl_Class *klass)
@@ -63,7 +64,8 @@ _elm_slider_class_initializer(Efl_Class *klass)
63 EFL_OBJECT_OP_FUNC(efl_text_get, _elm_slider_efl_text_text_get), 64 EFL_OBJECT_OP_FUNC(efl_text_get, _elm_slider_efl_text_text_get),
64 EFL_OBJECT_OP_FUNC(efl_text_markup_set, _elm_slider_efl_text_markup_markup_set), 65 EFL_OBJECT_OP_FUNC(efl_text_markup_set, _elm_slider_efl_text_markup_markup_set),
65 EFL_OBJECT_OP_FUNC(efl_text_markup_get, _elm_slider_efl_text_markup_markup_get), 66 EFL_OBJECT_OP_FUNC(efl_text_markup_get, _elm_slider_efl_text_markup_markup_get),
66 EFL_OBJECT_OP_FUNC(efl_ui_format_cb_set, _elm_slider_efl_ui_format_format_cb_set), 67 EFL_OBJECT_OP_FUNC(efl_ui_format_func_set, _elm_slider_efl_ui_format_format_cb_set),
68 EFL_OBJECT_OP_FUNC(efl_ui_format_apply_formatted_value, _elm_slider_efl_ui_format_apply_formatted_value),
67 EFL_OBJECT_OP_FUNC(efl_ui_l10n_text_set, _elm_slider_efl_ui_l10n_l10n_text_set), 69 EFL_OBJECT_OP_FUNC(efl_ui_l10n_text_set, _elm_slider_efl_ui_l10n_l10n_text_set),
68 EFL_OBJECT_OP_FUNC(efl_ui_l10n_text_get, _elm_slider_efl_ui_l10n_l10n_text_get), 70 EFL_OBJECT_OP_FUNC(efl_ui_l10n_text_get, _elm_slider_efl_ui_l10n_l10n_text_get),
69 EFL_OBJECT_OP_FUNC(efl_part_get, _elm_slider_efl_part_part_get), 71 EFL_OBJECT_OP_FUNC(efl_part_get, _elm_slider_efl_part_part_get),
diff --git a/src/lib/elementary/elm_slider_part_indicator_eo.c b/src/lib/elementary/elm_slider_part_indicator_eo.c
index 915e1ce..5488294 100644
--- a/src/lib/elementary/elm_slider_part_indicator_eo.c
+++ b/src/lib/elementary/elm_slider_part_indicator_eo.c
@@ -7,7 +7,7 @@ Elm_Slider_Indicator_Visible_Mode _elm_slider_part_indicator_visible_mode_get(co
7 7
8EOAPI EFL_FUNC_BODY_CONST(elm_slider_part_indicator_visible_mode_get, Elm_Slider_Indicator_Visible_Mode, 0); 8EOAPI EFL_FUNC_BODY_CONST(elm_slider_part_indicator_visible_mode_get, Elm_Slider_Indicator_Visible_Mode, 0);
9 9
10void _elm_slider_part_indicator_efl_ui_format_format_cb_set(Eo *obj, void *pd, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb); 10void _elm_slider_part_indicator_efl_ui_format_format_cb_set(Eo *obj, void *pd, void *func_data, Efl_Ui_Format_Func func, Eina_Free_Cb func_free_cb);
11 11
12 12
13void _elm_slider_part_indicator_efl_ui_format_format_string_set(Eo *obj, void *pd, const char *units); 13void _elm_slider_part_indicator_efl_ui_format_format_string_set(Eo *obj, void *pd, const char *units);
@@ -15,6 +15,7 @@ void _elm_slider_part_indicator_efl_ui_format_format_string_set(Eo *obj, void *p
15 15
16const char *_elm_slider_part_indicator_efl_ui_format_format_string_get(const Eo *obj, void *pd); 16const char *_elm_slider_part_indicator_efl_ui_format_format_string_get(const Eo *obj, void *pd);
17 17
18void _elm_slider_part_indicator_efl_ui_format_apply_formatted_value(Eo *obj, Elm_Part_Data *pd);
18 19
19static Eina_Bool 20static Eina_Bool
20_elm_slider_part_indicator_class_initializer(Efl_Class *klass) 21_elm_slider_part_indicator_class_initializer(Efl_Class *klass)
@@ -30,9 +31,10 @@ _elm_slider_part_indicator_class_initializer(Efl_Class *klass)
30 EFL_OPS_DEFINE(ops, 31 EFL_OPS_DEFINE(ops,
31 EFL_OBJECT_OP_FUNC(elm_slider_part_indicator_visible_mode_set, _elm_slider_part_indicator_visible_mode_set), 32 EFL_OBJECT_OP_FUNC(elm_slider_part_indicator_visible_mode_set, _elm_slider_part_indicator_visible_mode_set),
32 EFL_OBJECT_OP_FUNC(elm_slider_part_indicator_visible_mode_get, _elm_slider_part_indicator_visible_mode_get), 33 EFL_OBJECT_OP_FUNC(elm_slider_part_indicator_visible_mode_get, _elm_slider_part_indicator_visible_mode_get),
33 EFL_OBJECT_OP_FUNC(efl_ui_format_cb_set, _elm_slider_part_indicator_efl_ui_format_format_cb_set), 34 EFL_OBJECT_OP_FUNC(efl_ui_format_func_set, _elm_slider_part_indicator_efl_ui_format_format_cb_set),
34 EFL_OBJECT_OP_FUNC(efl_ui_format_string_set, _elm_slider_part_indicator_efl_ui_format_format_string_set), 35 EFL_OBJECT_OP_FUNC(efl_ui_format_string_set, _elm_slider_part_indicator_efl_ui_format_format_string_set),
35 EFL_OBJECT_OP_FUNC(efl_ui_format_string_get, _elm_slider_part_indicator_efl_ui_format_format_string_get), 36 EFL_OBJECT_OP_FUNC(efl_ui_format_string_get, _elm_slider_part_indicator_efl_ui_format_format_string_get),
37 EFL_OBJECT_OP_FUNC(efl_ui_format_apply_formatted_value, _elm_slider_part_indicator_efl_ui_format_apply_formatted_value),
36 ELM_SLIDER_PART_INDICATOR_EXTRA_OPS 38 ELM_SLIDER_PART_INDICATOR_EXTRA_OPS
37 ); 39 );
38 opsp = &ops; 40 opsp = &ops;
@@ -50,4 +52,4 @@ static const Efl_Class_Description _elm_slider_part_indicator_class_desc = {
50 NULL 52 NULL
51}; 53};
52 54
53EFL_DEFINE_CLASS(elm_slider_part_indicator_class_get, &_elm_slider_part_indicator_class_desc, EFL_UI_LAYOUT_PART_CLASS, EFL_UI_FORMAT_MIXIN, NULL); 55EFL_DEFINE_CLASS(elm_slider_part_indicator_class_get, &_elm_slider_part_indicator_class_desc, EFL_UI_LAYOUT_PART_CLASS, EFL_UI_LEGACY_INTERFACE, EFL_UI_FORMAT_MIXIN, NULL);
diff --git a/src/lib/elementary/elm_widget_multibuttonentry.h b/src/lib/elementary/elm_widget_multibuttonentry.h
index 1da7166..83d5d49 100644
--- a/src/lib/elementary/elm_widget_multibuttonentry.h
+++ b/src/lib/elementary/elm_widget_multibuttonentry.h
@@ -103,7 +103,7 @@ struct _Elm_Multibuttonentry_Data
103 void *add_callback_data; 103 void *add_callback_data;
104 Ecore_Timer *longpress_timer; 104 Ecore_Timer *longpress_timer;
105 105
106 Efl_Ui_Format_Func_Cb format_cb; 106 Efl_Ui_Format_Func format_cb;
107 Eina_Free_Cb format_free_cb; 107 Eina_Free_Cb format_free_cb;
108 void *format_cb_data; 108 void *format_cb_data;
109 Eina_Strbuf *format_strbuf; 109 Eina_Strbuf *format_strbuf;
diff --git a/src/lib/elementary/elm_widget_slider.h b/src/lib/elementary/elm_widget_slider.h
index 1b9c85c..c12ed7c 100644
--- a/src/lib/elementary/elm_widget_slider.h
+++ b/src/lib/elementary/elm_widget_slider.h
@@ -35,12 +35,12 @@ struct _Elm_Slider_Data
35 35
36 Evas_Coord size; 36 Evas_Coord size;
37 37
38 Efl_Ui_Format_Func_Cb format_cb; 38 Efl_Ui_Format_Func format_cb;
39 Eina_Free_Cb format_free_cb; 39 Eina_Free_Cb format_free_cb;
40 void *format_cb_data; 40 void *format_cb_data;
41 Eina_Strbuf *format_strbuf; 41 Eina_Strbuf *format_strbuf;
42 42
43 Efl_Ui_Format_Func_Cb indi_format_cb; 43 Efl_Ui_Format_Func indi_format_cb;
44 Eina_Free_Cb indi_format_free_cb; 44 Eina_Free_Cb indi_format_free_cb;
45 void *indi_format_cb_data; 45 void *indi_format_cb_data;
46 Eina_Strbuf *indi_format_strbuf; 46 Eina_Strbuf *indi_format_strbuf;
diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build
index 9e88e4c..9807d46 100644
--- a/src/lib/elementary/meson.build
+++ b/src/lib/elementary/meson.build
@@ -180,6 +180,7 @@ pub_eo_files = [
180 'efl_ui_relative_layout.eo', 180 'efl_ui_relative_layout.eo',
181 'efl_ui_clickable.eo', 181 'efl_ui_clickable.eo',
182 'efl_ui_clickable_util.eo', 182 'efl_ui_clickable_util.eo',
183 'efl_ui_format.eo',
183] 184]
184 185
185foreach eo_file : pub_eo_files 186foreach eo_file : pub_eo_files
@@ -935,6 +936,7 @@ elementary_src = [
935 'efl_ui_relative_layout.c', 936 'efl_ui_relative_layout.c',
936 'efl_ui_clickable.c', 937 'efl_ui_clickable.c',
937 'efl_ui_clickable_util.c', 938 'efl_ui_clickable_util.c',
939 'efl_ui_format.c',
938] 940]
939 941
940elementary_deps = [emile, eo, efl, edje, ethumb, ethumb_client, emotion, ecore_imf, ecore_con, eldbus, efreet, efreet_mime, efreet_trash, eio, atspi, dl, intl] 942elementary_deps = [emile, eo, efl, edje, ethumb, ethumb_client, emotion, ecore_imf, ecore_con, eldbus, efreet, efreet_mime, efreet_trash, eio, atspi, dl, intl]
diff --git a/src/tests/elementary/spec/README b/src/tests/elementary/spec/README
index f98cb78..24fad543 100644
--- a/src/tests/elementary/spec/README
+++ b/src/tests/elementary/spec/README
@@ -27,3 +27,4 @@ Just add your widget name to the "test-widgets" array and recompile. Next run of
27== Adding a new test == 27== Adding a new test ==
28 28
29To add a new test you need to create the .c file and include the metadata comment at the top. 29To add a new test you need to create the .c file and include the metadata comment at the top.
30Remember to add the new .c file to the meson.build file.
diff --git a/src/tests/elementary/spec/efl_test_format.c b/src/tests/elementary/spec/efl_test_format.c
new file mode 100644
index 0000000..cd2e698
--- /dev/null
+++ b/src/tests/elementary/spec/efl_test_format.c
@@ -0,0 +1,174 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#define EFL_UI_FORMAT_PROTECTED /* To access internal methods */
6
7#include <Efl_Ui.h>
8#include "efl_ui_spec_suite.h"
9#include "suite_helpers.h"
10
11/* spec-meta-start
12 {"test-interface":"Efl.Ui.Format",
13 "test-widgets": ["Efl.Ui.Progressbar", "Efl.Ui.Calendar", "Efl.Ui.Tags", "Efl.Ui.Spin", "Efl.Ui.Spin_Button"]}
14 spec-meta-end */
15
16static const Efl_Ui_Format_Value values[] = {{15, "fifteen"}, {16, "sixteen"}, {17, "seventeen"}, {18, "eighteen"}};
17
18EFL_START_TEST(format_values)
19{
20 Eina_Strbuf *buf = eina_strbuf_new();
21 Eina_Value eina_val;
22
23 efl_ui_format_values_set(widget, EINA_C_ARRAY_ACCESSOR_NEW(values));
24 eina_val = eina_value_int_init(17);
25 efl_ui_format_formatted_value_get(widget, buf, eina_val);
26 ck_assert_str_eq(eina_strbuf_string_get(buf), "seventeen"); // Check that value works
27 eina_val = eina_value_float_init(16.f);
28 efl_ui_format_formatted_value_get(widget, buf, eina_val);
29 ck_assert_str_eq(eina_strbuf_string_get(buf), "sixteen"); // Check built-in conversion
30
31 eina_value_flush(&eina_val);
32 eina_strbuf_free(buf);
33}
34EFL_END_TEST
35
36static Eina_Bool
37_format_func(void *data, Eina_Strbuf *str, const Eina_Value value)
38{
39 int i = *(int *)data;
40 int v;
41 ck_assert_int_eq(i, 1234); // Check that data ptr is passed along correctly
42 if (eina_value_type_get(&value) != EINA_VALUE_TYPE_INT) return EINA_FALSE;
43 eina_value_get(&value, &v);
44 eina_strbuf_append_printf(str, "You said '%d'", v);
45
46 return EINA_TRUE;
47}
48
49static void
50_format_free_func(void *data)
51{
52 int i = *(int *)data;
53 ck_assert_int_eq(i, 1234); // Check that data ptr is passed along correctly
54 *(int *)data = 12345; // Change it to indicate that free func was called
55}
56
57EFL_START_TEST(format_func)
58{
59 int data = 1234;
60 Eina_Strbuf *buf = eina_strbuf_new();
61 Eina_Value eina_val;
62
63 efl_ui_format_func_set(widget, &data, _format_func, _format_free_func);
64 eina_val = eina_value_int_init(15);
65 efl_ui_format_formatted_value_get(widget, buf, eina_val);
66 ck_assert_str_eq(eina_strbuf_string_get(buf), "You said '15'"); // Check that format func works
67 efl_ui_format_func_set(widget, NULL, NULL, NULL);
68 ck_assert_int_eq(data, 12345); // Check that free func is called
69 eina_value_flush(&eina_val);
70
71 eina_strbuf_free(buf);
72}
73EFL_END_TEST
74
75EFL_START_TEST(format_string)
76{
77 Eina_Strbuf *buf = eina_strbuf_new();
78 Eina_Value eina_val;
79 struct tm t = { 0 };
80 const char *old_locale = setlocale(LC_TIME, NULL);
81
82#define CHECK(fmt_str, fmt_type, val, val_type, result) \
83 efl_ui_format_string_set(widget, fmt_str, fmt_type); \
84 eina_value_setup(&eina_val, val_type); \
85 eina_value_set(&eina_val, val); \
86 efl_ui_format_formatted_value_get(widget, buf, eina_val); \
87 ck_assert_str_eq(eina_strbuf_string_get(buf), result); \
88 eina_value_flush(&eina_val)
89
90 CHECK("%d", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "1234");
91 CHECK("%d", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234.f, EINA_VALUE_TYPE_FLOAT, "1234"); // built-in conversion
92 CHECK("%d units", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "1234 units"); // complex format
93
94 CHECK("%.0f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 12.34f, EINA_VALUE_TYPE_FLOAT, "12");
95 CHECK("%.1f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 12.34f, EINA_VALUE_TYPE_FLOAT, "12.3");
96 CHECK("%.2f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 12.34f, EINA_VALUE_TYPE_FLOAT, "12.34");
97 CHECK("%.2f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "1234.00"); // built-in conversion
98 CHECK("%.0f%%", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 75.f, EINA_VALUE_TYPE_FLOAT, "75%"); // complex format
99
100 CHECK("%s", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, "Hello!", EINA_VALUE_TYPE_STRING, "Hello!");
101 CHECK("%s", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "1234"); // built-in conversion
102 CHECK("He said '%s'", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, "Hello!", EINA_VALUE_TYPE_STRING, "He said 'Hello!'"); // complex format
103
104 CHECK("Static string", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "Static string");
105
106 strptime("2019 7 3 11:49:3", "%Y %m %d %H:%M:%S", &t);
107 setlocale(LC_TIME, "C");
108 CHECK("%F", EFL_UI_FORMAT_STRING_TYPE_TIME, t, EINA_VALUE_TYPE_TM, "2019-07-03");
109 CHECK("%T", EFL_UI_FORMAT_STRING_TYPE_TIME, t, EINA_VALUE_TYPE_TM, "11:49:03");
110 CHECK("%A", EFL_UI_FORMAT_STRING_TYPE_TIME, t, EINA_VALUE_TYPE_TM, "Wednesday");
111 CHECK("<%B %Y>", EFL_UI_FORMAT_STRING_TYPE_TIME, t, EINA_VALUE_TYPE_TM, "<July 2019>");
112 setlocale(LC_TIME, old_locale);
113
114 eina_strbuf_free(buf);
115#undef CHECK
116}
117EFL_END_TEST
118
119static Eina_Bool
120_partial_format_func(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value value)
121{
122 int v;
123 if (eina_value_type_get(&value) != EINA_VALUE_TYPE_INT) return EINA_FALSE;
124 eina_value_get(&value, &v);
125 if (v < 10)
126 {
127 eina_strbuf_append_printf(str, "You said '%d'", v);
128 return EINA_TRUE;
129 }
130 return EINA_FALSE;
131}
132
133EFL_START_TEST(format_mixed)
134{
135 Eina_Strbuf *buf = eina_strbuf_new();
136 Eina_Value eina_val;
137
138 // Now we check combinations of different options
139 // Each one should be used in turn when the previous one fails: values, func, string, fallback
140 efl_ui_format_values_set(widget, EINA_C_ARRAY_ACCESSOR_NEW(values));
141 efl_ui_format_func_set(widget, NULL, _partial_format_func, NULL);
142 efl_ui_format_string_set(widget, "%d rabbits", EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
143
144 eina_val = eina_value_int_init(1);
145 efl_ui_format_formatted_value_get(widget, buf, eina_val);
146 ck_assert_str_eq(eina_strbuf_string_get(buf), "You said '1'"); // Func
147 eina_value_set(&eina_val, 15);
148 efl_ui_format_formatted_value_get(widget, buf, eina_val);
149 ck_assert_str_eq(eina_strbuf_string_get(buf), "fifteen"); // Values
150 eina_value_set(&eina_val, 25);
151 efl_ui_format_formatted_value_get(widget, buf, eina_val);
152 ck_assert_str_eq(eina_strbuf_string_get(buf), "25 rabbits"); // Values
153
154 EXPECT_ERROR_START;
155 // This is an invalid format string (it has two placeholders) which should
156 // trigger the fallback mechanism
157 efl_ui_format_string_set(widget, "%d %d", EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
158 EXPECT_ERROR_END;
159 efl_ui_format_formatted_value_get(widget, buf, eina_val);
160 ck_assert_str_eq(eina_strbuf_string_get(buf), "25"); // Fallback
161
162 eina_value_flush(&eina_val);
163 eina_strbuf_free(buf);
164}
165EFL_END_TEST
166
167void
168efl_ui_format_behavior_test(TCase *tc)
169{
170 tcase_add_test(tc, format_values);
171 tcase_add_test(tc, format_func);
172 tcase_add_test(tc, format_string);
173 tcase_add_test(tc, format_mixed);
174}
diff --git a/src/tests/elementary/spec/efl_ui_spec_suite.h b/src/tests/elementary/spec/efl_ui_spec_suite.h
index 8389d81..666a40d 100644
--- a/src/tests/elementary/spec/efl_ui_spec_suite.h
+++ b/src/tests/elementary/spec/efl_ui_spec_suite.h
@@ -15,6 +15,7 @@ void efl_pack_linear_behavior_test(TCase *tc);
15void efl_content_behavior_test(TCase *tc); 15void efl_content_behavior_test(TCase *tc);
16void efl_gfx_arrangement_behavior_test(TCase *tc); 16void efl_gfx_arrangement_behavior_test(TCase *tc);
17void efl_ui_clickable_behavior_test(TCase *tc); 17void efl_ui_clickable_behavior_test(TCase *tc);
18void efl_ui_format_behavior_test(TCase *tc);
18 19
19void efl_test_container_content_equal(Efl_Ui_Widget **wid, unsigned int len); 20void efl_test_container_content_equal(Efl_Ui_Widget **wid, unsigned int len);
20void efl_test_container_expect_evt_content_added(Efl_Ui_Widget *widget, const Efl_Event_Description *ev, Eina_Bool *flag, void *event_data); 21void efl_test_container_expect_evt_content_added(Efl_Ui_Widget *widget, const Efl_Event_Description *ev, Eina_Bool *flag, void *event_data);
diff --git a/src/tests/elementary/spec/meson.build b/src/tests/elementary/spec/meson.build
index 0f72b54..00fe61c 100644
--- a/src/tests/elementary/spec/meson.build
+++ b/src/tests/elementary/spec/meson.build
@@ -5,6 +5,7 @@ efl_ui_suite_behavior_test_files = files([
5 'efl_test_content.c', 5 'efl_test_content.c',
6 'efl_test_gfx_arrangement.c', 6 'efl_test_gfx_arrangement.c',
7 'efl_test_clickable.c', 7 'efl_test_clickable.c',
8 'efl_test_format.c',
8]) 9])
9 10
10efl_ui_suite_behavior_src = files([ 11efl_ui_suite_behavior_src = files([