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.
This commit is contained in:
Xavi Artigas 2019-07-02 14:40:06 +02:00
parent 87cfde51d3
commit e776f5f0d7
36 changed files with 826 additions and 751 deletions

View File

@ -405,17 +405,18 @@ _cal_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev)
max_date.tm_year + 1900);
}
static void
static Eina_Bool
_cal_format_cb(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value value)
{
struct tm current_time;
//return if the value type is other than EINA_VALUE_TYPE_TM
if (eina_value_type_get(&value) != EINA_VALUE_TYPE_TM)
return;
return EINA_FALSE;
eina_value_get(&value, &current_time);
eina_strbuf_append_strftime(str, "<< %b %y >>", &current_time);
return EINA_TRUE;
}
void
@ -444,7 +445,7 @@ test_efl_ui_calendar(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void
efl_ui_calendar_date_max_set(efl_added, max_date),
efl_ui_calendar_date_set(efl_added, selected_date),
efl_event_callback_add(efl_added, EFL_UI_CALENDAR_EVENT_CHANGED, _cal_changed_cb, NULL),
efl_ui_format_string_set(efl_added, "%b"),
efl_ui_format_string_set(efl_added, "%b", EFL_UI_FORMAT_STRING_TYPE_TIME),
efl_pack(box, efl_added));
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
efl_ui_calendar_date_max_set(efl_added, max_date),
efl_ui_calendar_date_set(efl_added, selected_date),
efl_event_callback_add(efl_added, EFL_UI_CALENDAR_EVENT_CHANGED, _cal_changed_cb, NULL),
efl_ui_format_cb_set(efl_added, NULL, _cal_format_cb, NULL),
efl_ui_format_func_set(efl_added, NULL, _cal_format_cb, NULL),
efl_pack(box, efl_added));
efl_gfx_entity_size_set(win, EINA_SIZE2D(300, 300));

View File

@ -119,7 +119,7 @@ _win_delete_req_cb(void *d, const Efl_Event *ev EINA_UNUSED)
free(pd);
}
static void
static Eina_Bool
_custom_format_cb(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value value)
{
double v;
@ -129,6 +129,7 @@ _custom_format_cb(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value val
else if (v < 75.f) eina_strbuf_append_printf(str, "Getting there...");
else if (v < 100.f) eina_strbuf_append_printf(str, "Almost done...");
else eina_strbuf_append_printf(str, "Done!");
return EINA_TRUE;
}
static void
@ -204,7 +205,7 @@ test_ui_progressbar(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_inf
efl_pack(bx, efl_added),
efl_text_set(efl_added, "Custom string"),
efl_ui_range_limits_set(efl_added, 0, 100),
efl_ui_format_string_set(efl_added, "%d rabbits"),
efl_ui_format_string_set(efl_added, "%d rabbits", EFL_UI_FORMAT_STRING_TYPE_SIMPLE),
efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(250, 20))
);
@ -212,7 +213,7 @@ test_ui_progressbar(void *data EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_inf
efl_pack(bx, efl_added),
efl_text_set(efl_added, "Custom func"),
efl_ui_range_limits_set(efl_added, 0, 100),
efl_ui_format_cb_set(efl_added, NULL, _custom_format_cb, NULL),
efl_ui_format_func_set(efl_added, NULL, _custom_format_cb, NULL),
efl_gfx_hint_size_min_set(efl_added, EINA_SIZE2D(250, 20))
);

View File

@ -50,7 +50,7 @@ test_ui_spin(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_i
efl_ui_range_limits_set(efl_added, 0, 10),
efl_ui_range_value_set(efl_added, 6),
efl_ui_range_step_set(efl_added, 2),
efl_ui_format_string_set(efl_added, "test %d"),
efl_ui_format_string_set(efl_added, "test %d", EFL_UI_FORMAT_STRING_TYPE_SIMPLE),
efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_CHANGED,_spin_changed_cb, NULL),
efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_MIN_REACHED,_spin_min_reached_cb, NULL),
efl_event_callback_add(efl_added, EFL_UI_SPIN_EVENT_MAX_REACHED,_spin_max_reached_cb, NULL),

View File

@ -16,18 +16,12 @@ void
test_ui_spin_button(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Eo *win, *bx;
int i;
Eina_Array *array;
Efl_Ui_Spin_Special_Value values[12] = {
Efl_Ui_Format_Value special_values[] = {
{1, "January"}, {2, "February"}, {3, "March"}, {4, "April"},
{5, "May"}, {6, "June"}, {7, "July"}, {8, "August"},
{9, "September"}, {10, "October"}, {11, "November"}, {12, "December"}
};
array = eina_array_new(sizeof(Efl_Ui_Spin_Special_Value));
for (i = 0; i < NUM_OF_VALS; i++)
eina_array_push(array, &values[i]);
win = efl_add_ref(EFL_UI_WIN_CLASS, NULL,
efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_BASIC),
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 *
efl_add(EFL_UI_SPIN_BUTTON_CLASS, bx,
efl_ui_range_limits_set(efl_added, -100.0, 100.0),
efl_ui_range_value_set(efl_added, 0),
efl_ui_format_string_set(efl_added, "test float %0.2f"),
efl_ui_format_string_set(efl_added, "test float %0.2f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE),
efl_ui_spin_button_editable_set(efl_added, EINA_FALSE),
efl_pack(bx, efl_added));
@ -57,10 +51,9 @@ test_ui_spin_button(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *
efl_ui_range_limits_set(efl_added, 1, 12),
efl_ui_range_value_set(efl_added, 1),
efl_ui_spin_button_editable_set(efl_added, EINA_FALSE),
efl_ui_spin_special_value_set(efl_added, array),
efl_ui_format_values_set(efl_added, EINA_C_ARRAY_ACCESSOR_NEW(special_values)),
efl_ui_layout_orientation_set(efl_added, EFL_UI_LAYOUT_ORIENTATION_VERTICAL),
efl_pack(bx, efl_added));
eina_array_free(array);
efl_gfx_entity_size_set(win, EINA_SIZE2D(180, 140));
}

View File

@ -78,7 +78,7 @@ test_ui_tags(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_i
efl_event_callback_add(efl_added, EFL_UI_TAGS_EVENT_ITEM_ADDED, _item_added_cb, array),
efl_event_callback_add(efl_added, EFL_UI_TAGS_EVENT_ITEM_DELETED, _item_deleted_cb, array),
efl_text_set(efl_added, "To :"),
efl_ui_format_string_set(efl_added, "+ %d items"),
efl_ui_format_string_set(efl_added, "+ %d items", EFL_UI_FORMAT_STRING_TYPE_SIMPLE),
elm_object_part_content_set(layout, "multibuttonentry", efl_added));
efl_add(EFL_UI_BUTTON_CLASS, layout,

View File

@ -26,17 +26,19 @@ struct appData
auto wcal(cal._get_wref());
// FIXME: How does one figure out the argument types for the function?
auto cb_a = std::bind([=](
auto cb_a = std::bind([](
efl::eina::strbuf_wrapper& sb,
efl::eina::value_view const& value) {
efl::eina::value_view const& value) -> bool {
try {
sb.append_strftime("%b. %y", efl::eina::get<tm>(value));
} catch (std::system_error const&) {
sb.append(value.to_string());
}
std::cout << "Month: " << std::string(sb) << std::endl;
return true;
}, _1, _2);
cal.format_cb_set(cb_a);
// FIXME XAR: I broke this and I do not know how to fix it
// cal.format_func_set(cb_a);
}
void destroy() {

View File

@ -147,7 +147,6 @@ typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command;
#include "interfaces/efl_ui_property_bind.eo.h"
#include "interfaces/efl_ui_factory.eo.h"
#include "interfaces/efl_ui_factory_bind.eo.h"
#include "interfaces/efl_ui_format.eo.h"
#include "interfaces/efl_cached_item.eo.h"
/* Observable interface */

View File

@ -1,169 +0,0 @@
#include "config.h"
#include "Efl.h"
#define ERR(...) EINA_LOG_DOM_ERR(EINA_LOG_DOMAIN_DEFAULT, __VA_ARGS__)
#define DBG(...) EINA_LOG_DOM_DBG(EINA_LOG_DOMAIN_DEFAULT, __VA_ARGS__)
typedef enum _Format_Type
{
FORMAT_TYPE_INVALID,
FORMAT_TYPE_DOUBLE,
FORMAT_TYPE_INT,
FORMAT_TYPE_STRING,
FORMAT_TYPE_STATIC
} Format_Type;
typedef struct
{
const char *template;
Format_Type format_type;
} Efl_Ui_Format_Data;
static Eina_Bool
_is_valid_digit(char x)
{
return ((x >= '0' && x <= '9') || (x == '.')) ? EINA_TRUE : EINA_FALSE;
}
static Format_Type
_format_string_check(const char *fmt)
{
const char *itr;
Eina_Bool found = EINA_FALSE;
Format_Type ret_type = FORMAT_TYPE_STATIC;
for (itr = fmt; *itr; itr++)
{
if (itr[0] != '%') continue;
if (itr[1] == '%')
{
itr++;
if (ret_type == FORMAT_TYPE_STATIC)
ret_type = FORMAT_TYPE_STRING;
continue;
}
if (!found)
{
found = EINA_TRUE;
for (itr++; *itr; itr++)
{
// FIXME: This does not properly support int64 or unsigned.
if ((*itr == 'd') || (*itr == 'u') || (*itr == 'i') ||
(*itr == 'o') || (*itr == 'x') || (*itr == 'X'))
{
ret_type = FORMAT_TYPE_INT;
break;
}
else if ((*itr == 'f') || (*itr == 'F'))
{
ret_type = FORMAT_TYPE_DOUBLE;
break;
}
else if (*itr == 's')
{
ret_type = FORMAT_TYPE_STRING;
break;
}
else if (_is_valid_digit(*itr))
{
continue;
}
else
{
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);
found = EINA_FALSE;
break;
}
}
if (!(*itr)) break;
}
else
{
ret_type = FORMAT_TYPE_INVALID;
break;
}
}
if (ret_type == FORMAT_TYPE_INVALID)
{
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);
}
return ret_type;
}
static void
_default_format_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
{
Efl_Ui_Format_Data *sd = data;
Eina_Value copy;
if (sd->format_type == FORMAT_TYPE_DOUBLE)
{
double v = 0.0;
eina_value_setup(&copy, EINA_VALUE_TYPE_DOUBLE);
eina_value_convert(&value, &copy);
eina_value_get(&copy, &v);
eina_strbuf_append_printf(str, sd->template, v);
eina_value_flush(&copy);
}
else if (sd->format_type == FORMAT_TYPE_INT)
{
int v = 0;
eina_value_setup(&copy, EINA_VALUE_TYPE_INT);
eina_value_convert(&value, &copy);
eina_value_get(&copy, &v);
eina_strbuf_append_printf(str, sd->template, v);
eina_value_flush(&copy);
}
else if (sd->format_type == FORMAT_TYPE_STRING)
{
char *v = eina_value_to_string(&value);
eina_strbuf_append_printf(str, sd->template, v);
free(v);
}
else if (sd->format_type == FORMAT_TYPE_STATIC)
{
eina_strbuf_append(str, sd->template);
}
else
{
// Error: Discard format string and just print value.
DBG("Could not guess value type in format string: '%s'", sd->template);
char *v = eina_value_to_string(&value);
eina_strbuf_append(str, v);
free(v);
}
}
static void
_default_format_free_cb(void *data)
{
Efl_Ui_Format_Data *sd = data;
if (sd && sd->template)
{
eina_stringshare_del(sd->template);
sd->template = NULL;
}
}
EOLIAN static void
_efl_ui_format_format_string_set(Eo *obj, Efl_Ui_Format_Data *sd, const char *template)
{
if (!template) return;
eina_stringshare_replace(&sd->template, template);
sd->format_type = _format_string_check(sd->template);
efl_ui_format_cb_set(obj, sd, _default_format_cb, _default_format_free_cb);
}
EOLIAN static const char *
_efl_ui_format_format_string_get(const Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *sd)
{
return sd->template;
}
#include "interfaces/efl_ui_format.eo.c"

View File

@ -1,42 +0,0 @@
import eina_types;
function @beta Efl.Ui.Format_Func_Cb {
[[Function pointer for format function hook]]
params {
@in str: strbuf; [[the formated string to be appended by user.]]
@in value: const(any_value); [[The @Eina.Value passed by $obj.]]
}
};
mixin @beta Efl.Ui.Format
{
[[interface class for format_func]]
methods {
@property format_cb {
set @pure_virtual {
[[Set the format function pointer to format the string.
]]
}
values {
func: Efl.Ui.Format_Func_Cb; [[The format function callback]]
}
}
@property format_string {
[[Control the format string for a given units label
If $NULL is passed to $format, it will hide $obj's units
area completely. If not, it'll set the <b>format
string</b> for the units label text. The units label is
provided as a floating point value, so the units text can display
at most one floating point value. Note that the units label is
optional. Use a format string such as "%1.2f meters" for example.
Note: The default format string is an integer percentage,
as in $"%.0f %%".
]]
values {
units: string; [[The format string for $obj's units label.]]
}
}
}
}

View File

@ -94,7 +94,6 @@ pub_eo_files = [
'efl_observer.eo',
'efl_observable.eo',
'efl_ui_autorepeat.eo',
'efl_ui_format.eo',
'efl_gfx_color_class.eo',
'efl_gfx_text_class.eo',
'efl_gfx_size_class.eo',
@ -166,7 +165,6 @@ efl_src += files([
'efl_io_queue.c',
'efl_observer.c',
'efl_file.c',
'efl_ui_format.c',
'efl_ui_layout_orientable_readonly.c',
'efl_text_markup_util.c',
])

View File

@ -246,6 +246,7 @@ typedef Eo Efl_Ui_Active_View_Indicator;
# include <efl_ui_navigation_layout.eo.h>
# include <efl_ui_clickable.eo.h>
# include <efl_ui_clickable_util.eo.h>
# include <efl_ui_format.eo.h>
/**
* Initialize Elementary

View File

@ -5,6 +5,7 @@
#define EFL_UI_FOCUS_COMPOSITION_PROTECTED
#define EFL_UI_FOCUS_OBJECT_PROTECTED
#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
#define EFL_UI_FORMAT_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
@ -167,37 +168,17 @@ _disable(Efl_Ui_Calendar_Data *sd,
static void
_set_month_year(Efl_Ui_Calendar_Data *sd)
{
Eina_Strbuf *strbuf = eina_strbuf_new();
Eina_Value val;
sd->filling = EINA_TRUE;
if (sd->format_cb)
{
Eina_Value val;
const char *buf;
eina_value_setup(&val, EINA_VALUE_TYPE_TM);
eina_value_set(&val, sd->shown_date);
eina_strbuf_reset(sd->format_strbuf);
sd->format_cb(sd->format_cb_data, sd->format_strbuf, val);
buf = eina_strbuf_string_get(sd->format_strbuf);
eina_value_flush(&val);
if (buf)
elm_layout_text_set(sd->obj, "month_text", buf);
else
elm_layout_text_set(sd->obj, "month_text", "");
}
else
{
char *buf;
buf = eina_strftime(E_("%B %Y"), &sd->shown_date);
if (buf)
{
elm_layout_text_set(sd->obj, "month_text", buf);
free(buf);
}
else elm_layout_text_set(sd->obj, "month_text", "");
}
eina_value_setup(&val, EINA_VALUE_TYPE_TM);
eina_value_set(&val, sd->shown_date);
efl_ui_format_formatted_value_get(sd->obj, strbuf, val);
elm_layout_text_set(sd->obj, "month_text", eina_strbuf_string_get(strbuf));
eina_value_flush(&val);
eina_strbuf_free(strbuf);
sd->filling = EINA_FALSE;
}
@ -841,9 +822,6 @@ _efl_ui_calendar_efl_object_destructor(Eo *obj, Efl_Ui_Calendar_Data *sd)
ecore_timer_del(sd->update_timer);
efl_ui_format_cb_set(obj, NULL, NULL, NULL);
eina_strbuf_free(sd->format_strbuf);
for (i = 0; i < ELM_DAY_LAST; i++)
eina_stringshare_del(sd->weekdays[i]);
@ -919,7 +897,6 @@ _efl_ui_calendar_constructor_internal(Eo *obj, Efl_Ui_Calendar_Data *priv)
priv->today_it = -1;
priv->selected_it = -1;
priv->first_day_it = -1;
priv->format_cb = NULL;
edje_object_signal_callback_add
(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)
}
EOLIAN static void
_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)
_efl_ui_calendar_efl_ui_format_apply_formatted_value(Eo *obj, Efl_Ui_Calendar_Data *pd EINA_UNUSED)
{
if ((sd->format_cb_data == func_data) && (sd->format_cb == func))
return;
if (sd->format_cb_data && sd->format_free_cb)
sd->format_free_cb(sd->format_cb_data);
sd->format_cb = func;
sd->format_cb_data = func_data;
sd->format_free_cb = func_free_cb;
if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
evas_object_smart_changed(obj);
}
static void
_calendar_format_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
{
Efl_Ui_Calendar_Data *sd = data;
const Eina_Value_Type *type = eina_value_type_get(&value);
struct tm v;
if (type == EINA_VALUE_TYPE_TM)
{
eina_value_get(&value, &v);
eina_strbuf_append_strftime(str, sd->format_template, &v);
}
}
static void
_calendar_format_free_cb(void *data)
{
Efl_Ui_Calendar_Data *sd = data;
if (sd && sd->format_template)
{
eina_stringshare_del(sd->format_template);
sd->format_template = NULL;
}
}
EOLIAN static void
_efl_ui_calendar_efl_ui_format_format_string_set(Eo *obj, Efl_Ui_Calendar_Data *sd, const char *template)
{
if (!template) return;
eina_stringshare_replace(&sd->format_template, template);
efl_ui_format_cb_set(obj, sd, _calendar_format_cb, _calendar_format_free_cb);
}
EOLIAN static const char *
_efl_ui_calendar_efl_ui_format_format_string_get(const Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd)
{
return sd->format_template;
}
EOLIAN static void
_efl_ui_calendar_first_day_of_week_set(Eo *obj, Efl_Ui_Calendar_Data *sd, Efl_Ui_Calendar_Weekday day)
{

View File

@ -111,8 +111,7 @@ class @beta Efl.Ui.Calendar extends Efl.Ui.Layout_Base implements Efl.Ui.Focus.C
Efl.Ui.Focus.Object.on_focus_update;
Efl.Ui.Widget.widget_input_event_handler;
Efl.Access.Widget.Action.elm_actions { get; }
Efl.Ui.Format.format_cb { set; }
Efl.Ui.Format.format_string { set; get;}
Efl.Ui.Format.apply_formatted_value;
}
events {
changed: void; [[Emitted when the selected date in the calendar is changed]]

View File

@ -39,15 +39,9 @@ struct _Efl_Ui_Calendar_Data
Evas_Object *month_access;
Eo *items[42];
Efl_Ui_Calendar_Weekday first_week_day;
Efl_Ui_Calendar_Weekday first_week_day;
unsigned char first_day_it;
const char *format_template;
Efl_Ui_Format_Func_Cb format_cb;
Eina_Free_Cb format_free_cb;
void *format_cb_data;
Eina_Strbuf *format_strbuf;
Eina_Bool selected : 1;
Eina_Bool filling : 1;
Eina_Bool weekdays_set : 1;

View File

@ -0,0 +1,345 @@
#define EFL_UI_FORMAT_PROTECTED 1
#include "config.h"
#include "Efl_Ui.h"
#include "elm_priv.h" /* To be able to use elm_widget_is_legacy() */
typedef enum _Format_Type
{
/* When a format string is used, it is parsed to find out the expected data type */
FORMAT_TYPE_INVALID, /* Format description not understood */
FORMAT_TYPE_DOUBLE, /* double */
FORMAT_TYPE_INT, /* int */
FORMAT_TYPE_TM, /* struct tm, for time and date values */
FORMAT_TYPE_STRING, /* const char* */
FORMAT_TYPE_STATIC /* No value is passed, the format string IS the formatted output */
} Format_Type;
typedef struct
{
Efl_Ui_Format_Func format_func; /* User-supplied formatting function */
void *format_func_data; /* User data for the above function */
Eina_Free_Cb format_func_free; /* How to free the above data */
Eina_Inarray *format_values; /* Array of formatting values, owned by us */
const char *format_string; /* User-supplied formatting string, stringshare */
Format_Type format_string_type; /* Type of data expected in the above string */
} Efl_Ui_Format_Data;
static Eina_Bool
_is_valid_digit(char x)
{
return ((x >= '0' && x <= '9') || (x == '.')) ? EINA_TRUE : EINA_FALSE;
}
static Format_Type
_format_string_check(const char *fmt, Efl_Ui_Format_String_Type type)
{
const char *itr;
Eina_Bool found = EINA_FALSE;
Format_Type ret_type = FORMAT_TYPE_STATIC;
if (type == EFL_UI_FORMAT_STRING_TYPE_TIME) return FORMAT_TYPE_TM;
for (itr = fmt; *itr; itr++)
{
if (itr[0] != '%') continue;
if (itr[1] == '%')
{
itr++;
if (ret_type == FORMAT_TYPE_STATIC)
ret_type = FORMAT_TYPE_STRING;
continue;
}
if (!found)
{
found = EINA_TRUE;
for (itr++; *itr; itr++)
{
// FIXME: This does not properly support int64 or unsigned.
if ((*itr == 'd') || (*itr == 'u') || (*itr == 'i') ||
(*itr == 'o') || (*itr == 'x') || (*itr == 'X'))
{
ret_type = FORMAT_TYPE_INT;
break;
}
else if ((*itr == 'f') || (*itr == 'F'))
{
ret_type = FORMAT_TYPE_DOUBLE;
break;
}
else if (*itr == 's')
{
ret_type = FORMAT_TYPE_STRING;
break;
}
else if (_is_valid_digit(*itr))
{
continue;
}
else
{
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);
found = EINA_FALSE;
break;
}
}
if (!(*itr)) break;
}
else
{
ret_type = FORMAT_TYPE_INVALID;
break;
}
}
if (ret_type == FORMAT_TYPE_INVALID)
{
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);
}
return ret_type;
}
static Eina_Bool
_do_format_string(Efl_Ui_Format_Data *pd, Eina_Strbuf *str, const Eina_Value value)
{
switch (pd->format_string_type)
{
case FORMAT_TYPE_DOUBLE:
{
double v = 0.0;
eina_value_double_convert(&value, &v);
eina_strbuf_append_printf(str, pd->format_string, v);
break;
}
case FORMAT_TYPE_INT:
{
int v = 0;
eina_value_int_convert(&value, &v);
eina_strbuf_append_printf(str, pd->format_string, v);
break;
}
case FORMAT_TYPE_STRING:
{
char *v = eina_value_to_string(&value);
eina_strbuf_append_printf(str, pd->format_string, v);
free(v);
break;
}
case FORMAT_TYPE_STATIC:
{
eina_strbuf_append(str, pd->format_string);
break;
}
case FORMAT_TYPE_TM:
{
struct tm v;
char *buf;
eina_value_get(&value, &v);
buf = eina_strftime(pd->format_string, &v);
eina_strbuf_append(str, buf);
free(buf);
break;
}
default:
return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
_legacy_default_format_func(void *data, Eina_Strbuf *str, const Eina_Value value)
{
if (!_do_format_string(data, str, value))
{
/* Fallback to just printing the value if format string fails (legacy behavior) */
char *v = eina_value_to_string(&value);
eina_strbuf_append(str, v);
free(v);
}
return EINA_TRUE;
}
EOLIAN static void
_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)
{
if (pd->format_func_free)
pd->format_func_free(pd->format_func_data);
pd->format_func = func;
pd->format_func_data = func_data;
pd->format_func_free = func_free_cb;
if (efl_alive_get(obj))
efl_ui_format_apply_formatted_value(obj);
}
EOLIAN static Efl_Ui_Format_Func
_efl_ui_format_format_func_get(const Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *pd)
{
return pd->format_func;
}
static int
_value_compare(const Efl_Ui_Format_Value *val1, const Efl_Ui_Format_Value *val2)
{
return val1->value - val2->value;
}
EOLIAN static void
_efl_ui_format_format_values_set(Eo *obj, Efl_Ui_Format_Data *pd, Eina_Accessor *values)
{
Efl_Ui_Format_Value v;
int i;
if (pd->format_values)
{
Efl_Ui_Format_Value *vptr;
/* Delete previous values array */
EINA_INARRAY_FOREACH(pd->format_values, vptr)
{
eina_stringshare_del(vptr->text);
}
eina_inarray_free(pd->format_values);
pd->format_values = NULL;
}
if (values == NULL)
{
if (efl_alive_get(obj))
efl_ui_format_apply_formatted_value(obj);
return;
}
/* Copy the values to our internal array */
pd->format_values = eina_inarray_new(sizeof(Efl_Ui_Format_Value), 4);
EINA_ACCESSOR_FOREACH(values, i, v)
{
Efl_Ui_Format_Value vcopy = { v.value, eina_stringshare_add(v.text) };
eina_inarray_insert_sorted(pd->format_values, &vcopy, (Eina_Compare_Cb)_value_compare);
}
eina_accessor_free(values);
if (efl_alive_get(obj))
efl_ui_format_apply_formatted_value(obj);
}
EOLIAN static Eina_Accessor *
_efl_ui_format_format_values_get(const Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *pd)
{
if (!pd->format_values) return NULL;
return eina_inarray_accessor_new(pd->format_values);
}
EOLIAN static void
_efl_ui_format_format_string_set(Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *sd, const char *string, Efl_Ui_Format_String_Type type)
{
eina_stringshare_replace(&sd->format_string, string);
if (string)
sd->format_string_type = _format_string_check(sd->format_string, type);
else
sd->format_string_type = FORMAT_TYPE_INVALID;
/* In legacy, setting the format string installs a default format func.
Some widgets then override the format_func_set method so we keep that behavior. */
if (elm_widget_is_legacy(obj))
efl_ui_format_func_set(obj, sd, _legacy_default_format_func, NULL);
if (efl_alive_get(obj))
efl_ui_format_apply_formatted_value(obj);
}
EOLIAN static void
_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)
{
if (string) *string = sd->format_string;
if (type) *type = sd->format_string_type == FORMAT_TYPE_TM ?
EFL_UI_FORMAT_STRING_TYPE_TIME : EFL_UI_FORMAT_STRING_TYPE_SIMPLE;
}
EOLIAN static void
_efl_ui_format_formatted_value_get(Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *pd, Eina_Strbuf *str, const Eina_Value value)
{
char *v;
eina_strbuf_reset(str);
if (pd->format_values)
{
/* Search in the format_values array if we have one */
Efl_Ui_Format_Value v = { 0 };
int ndx;
eina_value_int_convert(&value, &v.value);
ndx = eina_inarray_search_sorted(pd->format_values, &v, (Eina_Compare_Cb)_value_compare);
if (ndx > -1) {
Efl_Ui_Format_Value *entry = eina_inarray_nth(pd->format_values, ndx);
eina_strbuf_append(str, entry->text);
return;
}
}
if (pd->format_func)
{
/* If we have a formatting function, try to use it */
if (pd->format_func(pd->format_func_data, str, value))
return;
}
if (pd->format_string)
{
/* If we have a formatting string, use it */
if (_do_format_string(pd, str, value))
return;
}
/* Fallback to just printing the value if everything else fails */
v = eina_value_to_string(&value);
eina_strbuf_append(str, v);
free(v);
}
EOLIAN static int
_efl_ui_format_decimal_places_get(Eo *obj EINA_UNUSED, Efl_Ui_Format_Data *pd)
{
char result[16] = "0";
const char *start;
/* This method can only be called if a format_string has been supplied */
if (!pd->format_string) return 0;
start = strchr(pd->format_string, '%');
while (start)
{
if (start[1] != '%')
{
start = strchr(start, '.');
if (start)
start++;
break;
}
else
start = strchr(start + 2, '%');
}
if (start)
{
const char *p = strchr(start, 'f');
if ((p) && ((p - start) < 15))
sscanf(start, "%[^f]", result);
}
return atoi(result);
}
EOLIAN static void
_efl_ui_format_efl_object_destructor(Eo *obj, Efl_Ui_Format_Data *pd EINA_UNUSED)
{
/* Legacy widgets keep their own formatting data and have their own destructors */
if (!elm_widget_is_legacy(obj))
{
/* Otherwise, free formatting data */
efl_ui_format_func_set(obj, NULL, NULL, NULL);
efl_ui_format_values_set(obj, NULL);
efl_ui_format_string_set(obj, NULL, 0);
}
efl_destructor(efl_super(obj, EFL_UI_FORMAT_MIXIN));
}
#include "efl_ui_format.eo.c"

View File

@ -0,0 +1,149 @@
import eina_types;
function @beta Efl.Ui.Format_Func
{
[[A function taking an @Eina.Value and producing its textual representation.
See @Efl.Ui.Format.format_func.
]]
params {
@in str: strbuf; [[Output formatted string. Its contents will be overwritten by this method.]]
@in value: const(any_value); [[The @Eina.Value to convert to text.]]
}
return: bool; [[Whether the conversion succeeded or not.]]
};
struct @beta Efl.Ui.Format_Value
{
[[A value which should always be displayed as a specific text string.
See @Efl.Ui.Format.format_values.
]]
value: int; [[Input value.]]
text: string; [[Text string to replace it.]]
}
enum @beta Efl.Ui.Format_String_Type
{
[[Type of formatting string.]]
simple, [[This is the simplest formatting mechanism, working pretty much like $printf.
Accepted formats are $s, $f, $F, $d, $u, $i, $o, $x and $X.
For example, "%1.2f meters", "%.0%%" or "%d items".
]]
time [[A strftime-style string used to format date and time values.
For example, "%A" for the full name of the day or "%y" for the year as a decimal number
without a century (range 00 to 99). Note that these are not the $printf formats.
See the man page for the $strftime function for the complete list.
]]
}
mixin @beta Efl.Ui.Format requires Efl.Object
{
[[Helper mixin that simplifies converting numerical values to text.
A number of widgets represent a numerical value but display a text representation.
For example, an @Efl.Ui.Progressbar can hold the number 0.75 but display the string "75%",
or an @Efl.Ui.Spin can hold numbers 1 to 7, but display the strings "Monday" thru "Sunday".
This conversion can be controlled through the @.format_func, @.format_values and @.format_string properties.
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.
If one mechanism fails to produce a valid string the others will be tried (if provided) in descending
order of priority.
If no user-provided mechanism works, a fallback is used that just displays the value.
Widgets including this mixin offer their users different properties to control how
@Eina.Value's are converted to text.
]]
methods {
@property format_func {
[[User-provided function which takes care of converting an @Eina.Value into a text string.
The user is then completely in control of how the string is generated, but it is the
most cumbersome method to use.
If the conversion fails the other mechanisms will be tried, according to their priorities.
]]
values {
func: Efl.Ui.Format_Func; [[User-provided formatting function.]]
}
}
@property format_values {
[[User-provided list of values which are to be rendered using specific text strings.
This is more convenient to use than @.format_func and is perfectly suited for cases
where the strings make more sense than the numerical values. For example, weekday names
("Monday", "Tuesday", ...) are friendlier than numbers 1 to 7.
If a value is not found in the list, the other mechanisms will be tried according to their priorities.
List members do not need to be in any particular order. They are sorted internally for
performance reasons.
]]
values {
values: accessor<Efl.Ui.Format_Value>; [[Accessor over a list of value-text pairs.
The method will dispose of the accessor, but not of
its contents.
For convenience, Eina offers a range of helper
methods to obtain accessors from Eina.Array,
Eina.List or even plain C arrays.
]]
}
}
@property format_string {
[[A user-provided, string used to format the numerical value.
For example, "%1.2f meters", "%.0%%" or "%d items".
This is the simplest formatting mechanism, working pretty much like $printf.
Different format specifiers (the character after the %) are available, depending on the
$type used. Use @Efl.Ui.Format_String_Type.simple for simple numerical values and
@Efl.Ui.Format_String_Type.time for time and date values.
For instance, %d means "integer" when the first type is used, but it means "day of the month
as a decimal number" in the second.
Pass $NULL to disable this mechanism.
]]
values {
string: string; [[Formatting string containing regular characters and format specifiers.]]
type: Efl.Ui.Format_String_Type(Efl.Ui.Format_String_Type.simple);
[[Type of formatting string, which controls how the
different format specifiers are to be traslated.]]
}
}
formatted_value_get @protected {
[[Internal method to be used by widgets including this mixin to perform the conversion
from the internal numerical value into the text representation (Users of these widgets
do not need to call this method).
@.formatted_value_get uses any user-provided mechanism to perform the conversion, according to their
priorities, and implements a simple fallback if all mechanisms fail.
]]
params {
@in str: strbuf; [[Output formatted string. Its contents will be overwritten by this method.]]
@in value: const(any_value); [[The @Eina.Value to convert to text.]]
}
}
decimal_places_get @protected {
[[Internal method to be used by widgets including this mixin.
It can only be used when a @.format_string has been supplied, and it returns the number
of decimal places that the format string will produce for floating point values.
For example, "%.2f" returns 2, and "%d" returns 0;
]]
return: int; [[Number of decimal places, or 0 for non-floating point types.]]
}
apply_formatted_value @pure_virtual @protected {
[[Internal method to be implemented by widgets including this mixin.
The mixin will call this method to signal the widget that the formatting has changed
and therefore the current value should be converted and rendered again.
Widgets must typically call @.formatted_value_get and display the returned string. This
is something they are already doing (whenever the value changes, for example) so there
should be no extra code written to implement this method.
]]
}
}
implements {
Efl.Object.destructor;
}
}

View File

@ -6,6 +6,7 @@
#define ELM_LAYOUT_PROTECTED
#define EFL_ACCESS_VALUE_PROTECTED
#define EFL_PART_PROTECTED
#define EFL_UI_FORMAT_PROTECTED
#include <Elementary.h>
@ -73,7 +74,7 @@ _units_set(Evas_Object *obj)
{
EFL_UI_PROGRESSBAR_DATA_GET(obj, sd);
if (sd->show_progress_label && sd->format_cb)
if (sd->show_progress_label)
{
Eina_Value val;
@ -84,8 +85,8 @@ _units_set(Evas_Object *obj)
if (sd->is_legacy_format_string && !sd->is_legacy_format_cb)
eina_value_set(&val, 100 * sd->val);
eina_strbuf_reset(sd->format_strbuf);
sd->format_cb(sd->format_cb_data, sd->format_strbuf, val);
if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
efl_ui_format_formatted_value_get(obj, sd->format_strbuf, val);
eina_value_flush(&val);
@ -361,7 +362,7 @@ _efl_ui_progressbar_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Progressbar_Data
free(group);
efl_ui_format_string_set(obj, "%.0f%%");
efl_ui_format_string_set(obj, "%.0f%%", EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
priv->spacer = evas_object_rectangle_add(evas_object_evas_get(obj));
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
}
}
efl_ui_format_cb_set(obj, NULL, NULL, NULL);
eina_strbuf_free(sd->format_strbuf);
sd->format_strbuf = NULL;
efl_canvas_group_del(efl_super(obj, MY_CLASS));
}
@ -610,32 +611,6 @@ _efl_ui_progressbar_efl_ui_range_display_range_value_get(const Eo *obj, Efl_Ui_P
return efl_ui_range_value_get(efl_part(obj, "efl.cur.progressbar"));
}
EOLIAN static void
_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)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
if (sd->format_cb_data == func_data && sd->format_cb == func)
return;
if (sd->format_cb_data && sd->format_free_cb)
sd->format_free_cb(sd->format_cb_data);
sd->format_cb = func;
sd->format_cb_data = func_data;
sd->format_free_cb = func_free_cb;
if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
if (elm_widget_is_legacy(obj))
elm_layout_signal_emit(obj, "elm,state,units,visible", "elm");
else
elm_layout_signal_emit(obj, "efl,state,units,visible", "efl");
edje_object_message_signal_process(wd->resize_obj);
_units_set(obj);
elm_layout_sizing_eval(obj);
}
EOLIAN static void
_efl_ui_progressbar_pulse_set(Eo *obj, Efl_Ui_Progressbar_Data *sd, Eina_Bool state)
{
@ -773,6 +748,12 @@ _efl_ui_progressbar_show_progress_label_get(const Eo *obj EINA_UNUSED, Efl_Ui_Pr
return pd->show_progress_label;
}
EOLIAN static void
_efl_ui_progressbar_efl_ui_format_apply_formatted_value(Eo *obj, Efl_Ui_Progressbar_Data *pd EINA_UNUSED)
{
_units_set(obj);
}
#include "efl_ui_progressbar_part.eo.c"
/* Efl.Part end */
@ -982,7 +963,7 @@ typedef struct
progressbar_freefunc_type format_free_cb;
} Pb_Format_Wrapper_Data;
static void
static Eina_Bool
_format_legacy_to_format_eo_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
{
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
if (buf)
eina_strbuf_append(str, buf);
if (pfwd->format_free_cb) pfwd->format_free_cb(buf);
return EINA_TRUE;
}
static void
@ -1018,8 +1001,8 @@ elm_progressbar_unit_format_function_set(Evas_Object *obj, progressbar_func_type
pfwd->format_free_cb = free_func;
sd->is_legacy_format_cb = EINA_TRUE;
efl_ui_format_cb_set(obj, pfwd, _format_legacy_to_format_eo_cb,
_format_legacy_to_format_eo_free_cb);
efl_ui_format_func_set(obj, pfwd, _format_legacy_to_format_eo_cb,
_format_legacy_to_format_eo_free_cb);
}
EAPI void
@ -1042,13 +1025,15 @@ elm_progressbar_unit_format_set(Evas_Object *obj, const char *units)
EFL_UI_PROGRESSBAR_DATA_GET_OR_RETURN(obj, sd);
sd->is_legacy_format_string = EINA_TRUE;
efl_ui_format_string_set(obj, units);
efl_ui_format_string_set(obj, units, EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
}
EAPI const char *
elm_progressbar_unit_format_get(const Evas_Object *obj)
{
return efl_ui_format_string_get(obj);
const char *fmt;
efl_ui_format_string_get(obj, &fmt, NULL);
return fmt;
}
EAPI void

View File

@ -58,7 +58,7 @@ class @beta Efl.Ui.Progressbar extends Efl.Ui.Layout_Base implements Efl.Ui.Rang
Efl.Ui.Range_Display.range_value { get; set; }
Efl.Ui.Range_Display.range_limits {get; set; }
Efl.Ui.Layout_Orientable.orientation { get; set; }
Efl.Ui.Format.format_cb { set; }
Efl.Ui.Format.apply_formatted_value;
Efl.Part.part_get;
Efl.Access.Value.value_and_text { get; }
Efl.Text.text { get; set; }

View File

@ -38,9 +38,6 @@ struct _Efl_Ui_Progressbar_Data
Eina_List *progress_status; /**< The list of _Elm_Progress_Status. To save the progress value(in percentage) each part of given progress bar */
Efl_Ui_Format_Func_Cb format_cb;
Eina_Free_Cb format_free_cb;
void *format_cb_data;
Eina_Strbuf *format_strbuf;
Efl_Ui_Layout_Orientation dir; /**< Orientation of the progressbar */

View File

@ -5,6 +5,7 @@
#define EFL_ACCESS_OBJECT_PROTECTED
#define EFL_ACCESS_VALUE_PROTECTED
#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
#define EFL_UI_FORMAT_PROTECTED
#include <Elementary.h>
@ -15,142 +16,17 @@
#define MY_CLASS_NAME "Efl.Ui.Spin"
static Eina_Bool
_is_valid_digit(char x)
{
return ((x >= '0' && x <= '9') || (x == '.')) ? EINA_TRUE : EINA_FALSE;
}
static Efl_Ui_Spin_Format_Type
_is_label_format_integer(const char *fmt)
{
const char *itr = NULL;
const char *start = NULL;
Eina_Bool found = EINA_FALSE;
Efl_Ui_Spin_Format_Type ret_type = SPIN_FORMAT_INVALID;
start = strchr(fmt, '%');
if (!start) return SPIN_FORMAT_INVALID;
while (start)
{
if (found && start[1] != '%')
{
return SPIN_FORMAT_INVALID;
}
if (start[1] != '%' && !found)
{
found = EINA_TRUE;
for (itr = start + 1; *itr != '\0'; itr++)
{
if ((*itr == 'd') || (*itr == 'u') || (*itr == 'i') ||
(*itr == 'o') || (*itr == 'x') || (*itr == 'X'))
{
ret_type = SPIN_FORMAT_INT;
break;
}
else if ((*itr == 'f') || (*itr == 'F'))
{
ret_type = SPIN_FORMAT_FLOAT;
break;
}
else if (_is_valid_digit(*itr))
{
continue;
}
else
{
return SPIN_FORMAT_INVALID;
}
}
}
start = strchr(start + 2, '%');
}
return ret_type;
}
static void
_label_write(Evas_Object *obj)
_label_write(Evas_Object *obj, Efl_Ui_Spin_Data *sd)
{
Efl_Ui_Spin_Special_Value *sv;
unsigned int i;
Eina_Array_Iterator iterator;
Eina_Strbuf *strbuf = eina_strbuf_new();
Eina_Value val = eina_value_double_init(sd->val);
efl_ui_format_formatted_value_get(obj, strbuf, val);
Efl_Ui_Spin_Data *sd = efl_data_scope_get(obj, MY_CLASS);
elm_layout_text_set(obj, "efl.text", eina_strbuf_string_get(strbuf));
EINA_ARRAY_ITER_NEXT(sd->special_values, i, sv, iterator)
{
if (sv->value == sd->val)
{
char buf[1024];
snprintf(buf, sizeof(buf), "%s", sv->label);
elm_layout_text_set(obj, "elm.text", buf);
sd->templates = sv->label;
return;
}
}
if (sd->format_cb)
{
const char *buf;
Eina_Value val;
if (sd->format_type == SPIN_FORMAT_INT)
{
eina_value_setup(&val, EINA_VALUE_TYPE_INT);
eina_value_set(&val, (int)sd->val);
}
else
{
eina_value_setup(&val, EINA_VALUE_TYPE_DOUBLE);
eina_value_set(&val, sd->val);
}
eina_strbuf_reset(sd->format_strbuf);
sd->format_cb(sd->format_cb_data, sd->format_strbuf, val);
buf = eina_strbuf_string_get(sd->format_strbuf);
eina_value_flush(&val);
elm_layout_text_set(obj, "efl.text", buf);
sd->templates = buf;
}
else
{
char buf[1024];
snprintf(buf, sizeof(buf), "%.0f", sd->val);
elm_layout_text_set(obj, "efl.text", buf);
evas_object_show(obj);
}
}
static int
_decimal_points_get(const char *label)
{
char result[16] = "0";
const char *start = strchr(label, '%');
while (start)
{
if (start[1] != '%')
{
start = strchr(start, '.');
if (start)
start++;
break;
}
else
start = strchr(start + 2, '%');
}
if (start)
{
const char *p = strchr(start, 'f');
if ((p) && ((p - start) < 15))
sscanf(start, "%[^f]", result);
}
return atoi(result);
eina_value_flush(&val);
eina_strbuf_free(strbuf);
}
EOLIAN static void
@ -188,48 +64,6 @@ _efl_ui_spin_efl_ui_widget_widget_input_event_handler(Eo *obj, Efl_Ui_Spin_Data
return EINA_TRUE;
}
EOLIAN static void
_efl_ui_spin_special_value_set(Eo *obj, Efl_Ui_Spin_Data *sd, const Eina_Array *values)
{
EINA_SAFETY_ON_NULL_RETURN(values);
unsigned int i;
Efl_Ui_Spin_Special_Value *sv;
Efl_Ui_Spin_Special_Value *temp;
Eina_Array_Iterator iterator;
if (eina_array_count(sd->special_values))
{
EINA_ARRAY_ITER_NEXT(sd->special_values, i, sv, iterator)
{
eina_stringshare_del(sv->label);
free(sv);
}
eina_array_clean(sd->special_values);
}
if (eina_array_count(values))
EINA_ARRAY_ITER_NEXT(values, i, temp, iterator)
{
sv = calloc(1, sizeof(*sv));
if (!sv) return;
sv->value = temp->value;
sv->label = eina_stringshare_add(temp->label);
eina_array_push(sd->special_values, sv);
}
_label_write(obj);
}
EOLIAN static const Eina_Array*
_efl_ui_spin_special_value_get(const Eo *obj EINA_UNUSED, Efl_Ui_Spin_Data *sd)
{
if (eina_array_count(sd->special_values))
return sd->special_values;
else
return NULL;
}
EOLIAN static Eo *
_efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd)
{
@ -241,7 +75,6 @@ _efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd)
sd->val_max = 100.0;
sd->step = 1.0;
sd->special_values = eina_array_new(sizeof(Efl_Ui_Spin_Special_Value));
if (elm_widget_theme_object_set(obj, wd->resize_obj,
elm_widget_theme_klass_get(obj),
@ -249,7 +82,7 @@ _efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd)
elm_widget_theme_style_get(obj)) == EFL_UI_THEME_APPLY_ERROR_GENERIC)
CRI("Failed to set layout!");
_label_write(obj);
_label_write(obj, sd);
elm_widget_can_focus_set(obj, EINA_TRUE);
elm_layout_sizing_eval(obj);
@ -260,50 +93,13 @@ _efl_ui_spin_efl_object_constructor(Eo *obj, Efl_Ui_Spin_Data *sd)
EOLIAN static void
_efl_ui_spin_efl_object_destructor(Eo *obj, Efl_Ui_Spin_Data *sd EINA_UNUSED)
{
Efl_Ui_Spin_Special_Value *sv;
Eina_Array_Iterator iterator;
unsigned int i;
efl_ui_format_cb_set(obj, NULL, NULL, NULL);
EINA_ARRAY_ITER_NEXT(sd->special_values, i, sv, iterator)
{
eina_stringshare_del(sv->label);
free(sv);
}
eina_array_free(sd->special_values);
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static void
_efl_ui_spin_efl_ui_format_format_cb_set(Eo *obj, Efl_Ui_Spin_Data *sd, void *func_data, Efl_Ui_Format_Func_Cb func, Eina_Free_Cb func_free_cb)
_efl_ui_spin_efl_ui_format_apply_formatted_value(Eo *obj, Efl_Ui_Spin_Data *sd EINA_UNUSED)
{
if (sd->format_cb_data == func_data && sd->format_cb == func)
return;
if (sd->format_cb_data && sd->format_free_cb)
sd->format_free_cb(sd->format_cb_data);
sd->format_cb = func;
sd->format_cb_data = func_data;
sd->format_free_cb = func_free_cb;
if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
const char *format = efl_ui_format_string_get(obj);
if (format)
{
sd->format_type = _is_label_format_integer(format);
if (sd->format_type == SPIN_FORMAT_INVALID)
{
ERR("format:\"%s\" is invalid, cannot be set", format);
return;
}
else if (sd->format_type == SPIN_FORMAT_FLOAT)
sd->decimal_points = _decimal_points_get(format);
}
_label_write(obj);
_label_write(obj, sd);
elm_layout_sizing_eval(obj);
}
@ -325,7 +121,7 @@ _efl_ui_spin_efl_ui_range_display_range_limits_set(Eo *obj, Efl_Ui_Spin_Data *sd
if (sd->val < sd->val_min) sd->val = sd->val_min;
if (sd->val > sd->val_max) sd->val = sd->val_max;
_label_write(obj);
_label_write(obj, sd);
}
EOLIAN static void
@ -372,7 +168,7 @@ _efl_ui_spin_efl_ui_range_display_range_value_set(Eo *obj, Efl_Ui_Spin_Data *sd,
efl_event_callback_call(obj, EFL_UI_SPIN_EVENT_CHANGED, NULL);
_label_write(obj);
_label_write(obj, sd);
}
EOLIAN static double

View File

@ -1,36 +1,11 @@
struct @beta Efl.Ui.Spin_Special_Value
{
[[Special value]]
value: double; [[Target value]]
label: string; [[String to replace]]
}
class @beta Efl.Ui.Spin extends Efl.Ui.Layout_Base implements Efl.Ui.Range_Interactive, Efl.Ui.Format,
Efl.Access.Value, Efl.Access.Widget.Action
{
[[A Spin.
This is a widget which allows the user to increase or decrease numeric values
using user interactions. It's a basic type of widget for choosing and displaying values.
This is a widget which allows the user to increase or decrease a numeric value
using arrow buttons. It's a basic type of widget for choosing and displaying values.
]]
methods {
@property special_value {
[[Control special string to display in the place of the numerical value.
It's useful for cases when a user should select an item that is
better indicated by a label than a value. For example, weekdays or months.
Note: If another label was previously set to $value, it will be replaced
by the new label.]]
set {
}
get {
}
values {
values: const(array<ptr(Efl.Ui.Spin_Special_Value)>); [[The array of special values, or NULL if none]]
}
}
}
implements {
Efl.Object.constructor;
Efl.Object.destructor;
@ -38,7 +13,7 @@ class @beta Efl.Ui.Spin extends Efl.Ui.Layout_Base implements Efl.Ui.Range_Inter
Efl.Ui.Range_Display.range_limits { get; set; }
Efl.Ui.Range_Interactive.range_step { get; set; }
Efl.Ui.Range_Display.range_value { get; set; }
Efl.Ui.Format.format_cb { set; }
Efl.Ui.Format.apply_formatted_value;
}
events {
changed: void; [[Called when spin changed]]

View File

@ -6,6 +6,7 @@
#define EFL_ACCESS_VALUE_PROTECTED
#define EFL_ACCESS_WIDGET_ACTION_PROTECTED
#define EFL_UI_FOCUS_COMPOSITION_PROTECTED
#define EFL_UI_FORMAT_PROTECTED
#include <Elementary.h>
@ -50,29 +51,20 @@ EFL_CALLBACKS_ARRAY_DEFINE(_inc_dec_button_cb,
static void
_entry_show(Evas_Object *obj)
{
Efl_Ui_Spin_Special_Value *sv;
Eina_Array_Iterator iterator;
unsigned int i;
char buf[32], fmt[32] = "%0.f";
Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS);
Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS);
EINA_ARRAY_ITER_NEXT(pd->special_values, i, sv, iterator)
{
if (sv->value == pd->val)
{
snprintf(buf, sizeof(buf), "%s", sv->label);
elm_object_text_set(sd->ent, buf);
}
}
const char *format_string;
efl_ui_format_string_get(obj, &format_string, NULL);
/* try to construct just the format from given label
* completely ignoring pre/post words
*/
if (pd->templates)
if (format_string)
{
const char *start = strchr(pd->templates, '%');
const char *start = strchr(format_string, '%');
while (start)
{
/* handle %% */
@ -103,10 +95,7 @@ _entry_show(Evas_Object *obj)
}
}
if (pd->format_type == SPIN_FORMAT_INT)
snprintf(buf, sizeof(buf), fmt, (int)pd->val);
else
snprintf(buf, sizeof(buf), fmt, pd->val);
snprintf(buf, sizeof(buf), fmt, pd->val);
elm_object_text_set(sd->ent, buf);
}
@ -115,20 +104,16 @@ static void
_label_write(Evas_Object *obj)
{
Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS);
Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS);
if (pd->templates)
{
efl_text_set(sd->text_button, pd->templates);
}
else
{
char buf[1024];
Eina_Strbuf *strbuf = eina_strbuf_new();
Eina_Value val = eina_value_double_init(pd->val);
efl_ui_format_formatted_value_get(obj, strbuf, val);
snprintf(buf, sizeof(buf), "%.0f", pd->val);
efl_text_set(sd->text_button, buf);
}
efl_text_set(sd->text_button, eina_strbuf_string_get(strbuf));
eina_value_flush(&val);
eina_strbuf_free(strbuf);
}
static Eina_Bool
@ -182,9 +167,6 @@ _entry_hide(Evas_Object *obj)
static void
_entry_value_apply(Evas_Object *obj)
{
Efl_Ui_Spin_Special_Value *sv;
Eina_Array_Iterator iterator;
unsigned int i;
const char *str;
double val;
char *end;
@ -200,10 +182,6 @@ _entry_value_apply(Evas_Object *obj)
str = elm_object_text_get(sd->ent);
if (!str) return;
EINA_ARRAY_ITER_NEXT(pd->special_values, i, sv, iterator)
if (sv->value == pd->val)
if (!strcmp(sv->label, str)) return;
val = strtod(str, &end);
if (((*end != '\0') && (!isspace(*end))) || (fabs(val - pd->val) < DBL_EPSILON)) return;
efl_ui_range_value_set(obj, val);
@ -267,14 +245,14 @@ static void
_entry_accept_filter_add(Evas_Object *obj)
{
Efl_Ui_Spin_Button_Data *sd = efl_data_scope_get(obj, MY_CLASS);
Efl_Ui_Spin_Data *pd = efl_data_scope_get(obj, EFL_UI_SPIN_CLASS);
static Elm_Entry_Filter_Accept_Set digits_filter_data;
int decimal_places = efl_ui_format_decimal_places_get(obj);
if (!sd->ent) return;
elm_entry_markup_filter_remove(sd->ent, elm_entry_filter_accept_set, &digits_filter_data);
if (pd->decimal_points > 0)
if (decimal_places > 0)
digits_filter_data.accepted = "-.0123456789";
else
digits_filter_data.accepted = "-0123456789";
@ -307,6 +285,7 @@ _min_max_validity_filter(void *data, Evas_Object *obj, char **text)
char *insert, *new_str = NULL;
double val;
int max_len = 0, len;
int decimal_places = efl_ui_format_decimal_places_get(data);
EINA_SAFETY_ON_NULL_RETURN(data);
EINA_SAFETY_ON_NULL_RETURN(obj);
@ -322,12 +301,12 @@ _min_max_validity_filter(void *data, Evas_Object *obj, char **text)
if (!new_str) return;
if (strchr(new_str, '-')) max_len++;
if (pd->format_type == SPIN_FORMAT_FLOAT)
if (decimal_places > 0)
{
point = strchr(new_str, '.');
if (point)
{
if ((int) strlen(point + 1) > pd->decimal_points)
if ((int) strlen(point + 1) > decimal_places)
{
*insert = 0;
goto end;

View File

@ -3,29 +3,11 @@
#include "Elementary.h"
typedef enum _Efl_Ui_Spin_Format_Type
{
SPIN_FORMAT_FLOAT,
SPIN_FORMAT_INT,
SPIN_FORMAT_INVALID
} Efl_Ui_Spin_Format_Type;
typedef struct _Efl_Ui_Spin_Data Efl_Ui_Spin_Data;
struct _Efl_Ui_Spin_Data
{
const char *templates;
double val, val_min, val_max;
double step; /**< step for the value change. 1 by default. */
int decimal_points;
Ecore_Timer *spin_timer; /**< a timer for a repeated spin value change on mouse down */
Efl_Ui_Spin_Format_Type format_type;
Efl_Ui_Format_Func_Cb format_cb;
Eina_Free_Cb format_free_cb;
void *format_cb_data;
Eina_Strbuf *format_strbuf;
Eina_Array *special_values;
};
#endif

View File

@ -2,6 +2,8 @@
# include "elementary_config.h"
#endif
#define EFL_UI_FORMAT_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_ui_tags_private.h"
@ -75,7 +77,6 @@ _shrink_mode_set(Eo *obj,
EINA_LIST_FOREACH(sd->layouts, l, layout)
{
char buf[32];
Evas_Coord w_label_count = 0, h = 0;
elm_box_pack_end(sd->box, layout);
@ -92,19 +93,12 @@ _shrink_mode_set(Eo *obj,
if (count > 0)
{
if (sd->format_cb)
{
eina_strbuf_reset(sd->format_strbuf);
eina_value_set(&val, count);
sd->format_cb(sd->format_cb_data, sd->format_strbuf, val);
edje_object_part_text_escaped_set(sd->end, "efl.text",
eina_strbuf_string_get(sd->format_strbuf));
}
else
{
snprintf(buf, sizeof(buf), "+ %d", count);
edje_object_part_text_escaped_set(sd->end, "efl.text", buf);
}
Eina_Strbuf *strbuf = eina_strbuf_new();
eina_value_set(&val, count);
efl_ui_format_formatted_value_get(obj, strbuf, val);
edje_object_part_text_escaped_set(sd->end, "efl.text",
eina_strbuf_string_get(strbuf));
eina_strbuf_free(strbuf);
edje_object_size_min_calc(sd->end, &w_label_count, NULL);
elm_coords_finger_size_adjust(1, &w_label_count, 1, NULL);
@ -112,23 +106,16 @@ _shrink_mode_set(Eo *obj,
if ((w < 0) || (w < w_label_count))
{
Eina_Strbuf *strbuf = eina_strbuf_new();
elm_box_unpack(sd->box, layout);
evas_object_hide(layout);
count++;
if (sd->format_cb)
{
eina_strbuf_reset(sd->format_strbuf);
eina_value_set(&val, count);
sd->format_cb(sd->format_cb_data, sd->format_strbuf, val);
edje_object_part_text_escaped_set(sd->end, "efl.text",
eina_strbuf_string_get(sd->format_strbuf));
}
else
{
snprintf(buf, sizeof(buf), "+ %d", count);
edje_object_part_text_escaped_set(sd->end, "efl.text", buf);
}
eina_value_set(&val, count);
efl_ui_format_formatted_value_get(obj, strbuf, val);
edje_object_part_text_escaped_set(sd->end, "efl.text",
eina_strbuf_string_get(strbuf));
eina_strbuf_free(strbuf);
edje_object_size_min_calc(sd->end, &w_label_count, &h);
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)
sd->last_it_select = EINA_TRUE;
sd->editable = EINA_TRUE;
sd->parent = obj;
sd->format_cb = NULL;
sd->it_array = eina_array_new(4);
_view_init(obj, sd);
@ -1054,9 +1040,6 @@ _efl_ui_tags_efl_object_destructor(Eo *obj, Efl_Ui_Tags_Data *sd)
evas_object_del(sd->end);
ecore_timer_del(sd->longpress_timer);
efl_ui_format_cb_set(obj, NULL, NULL, NULL);
eina_strbuf_free(sd->format_strbuf);
efl_destructor(efl_super(obj, MY_CLASS));
}
@ -1072,23 +1055,6 @@ _efl_ui_tags_efl_text_text_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *sd)
return (sd->label_str ? sd->label_str : NULL);
}
EOLIAN static void
_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)
{
if ((sd->format_cb_data == func_data) && (sd->format_cb == func))
return;
if (sd->format_cb_data && sd->format_free_cb)
sd->format_free_cb(sd->format_cb_data);
sd->format_cb = func;
sd->format_cb_data = func_data;
sd->format_free_cb = func_free_cb;
if (!sd->format_strbuf) sd->format_strbuf = eina_strbuf_new();
_view_update(sd);
}
EOLIAN static Eina_Bool
_efl_ui_tags_expanded_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *sd)
{
@ -1171,6 +1137,11 @@ _efl_ui_tags_items_get(const Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *sd)
return sd->it_array;
}
EOLIAN static void
_efl_ui_tags_efl_ui_format_apply_formatted_value(Eo *obj EINA_UNUSED, Efl_Ui_Tags_Data *pd)
{
_view_update(pd);
}
#define EFL_UI_TAGS_EXTRA_OPS \
ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_tags), \

View File

@ -47,7 +47,7 @@ class @beta Efl.Ui.Tags extends Efl.Ui.Layout_Base implements Efl.Text, Efl.Ui.F
Efl.Object.destructor;
Efl.Ui.Widget.widget_input_event_handler;
Efl.Text.text { get; set; }
Efl.Ui.Format.format_cb { set; }
Efl.Ui.Format.apply_formatted_value;
}
events {
/* FIXME: Returning a basic type is not future-proof, better return a struct */

View File

@ -34,11 +34,6 @@ struct _Efl_Ui_Tags_Data
Evas_Coord w_box, h_box;
int shrink;
Efl_Ui_Format_Func_Cb format_cb;
Eina_Free_Cb format_free_cb;
void *format_cb_data;
Eina_Strbuf *format_strbuf;
Eina_Bool last_it_select : 1;
Eina_Bool editable : 1;
Eina_Bool focused : 1;

View File

@ -7,6 +7,7 @@
#define EFL_ACCESS_VALUE_PROTECTED
#define ELM_LAYOUT_PROTECTED
#define EFL_PART_PROTECTED
#define EFL_UI_FORMAT_PROTECTED
#include <Elementary.h>
@ -953,7 +954,7 @@ _elm_slider_efl_object_constructor(Eo *obj, Elm_Slider_Data *priv)
elm_widget_can_focus_set(obj, EINA_TRUE);
efl_ui_format_string_set(efl_part(obj, "indicator"), "%0.2f");
efl_ui_format_string_set(efl_part(obj, "indicator"), "%0.2f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
evas_object_event_callback_add
(sd->spacer, EVAS_CALLBACK_MOUSE_DOWN, _spacer_down_cb, obj);
@ -976,7 +977,7 @@ _elm_slider_efl_object_destructor(Eo *obj,
ELM_SAFE_FREE(sd->indi_template, eina_stringshare_del);
eina_strbuf_free(sd->indi_format_strbuf);
efl_ui_format_cb_set(obj, NULL, NULL, NULL);
efl_ui_format_func_set(obj, NULL, NULL, NULL);
eina_strbuf_free(sd->format_strbuf);
efl_destructor(efl_super(obj, MY_CLASS));
@ -1004,7 +1005,7 @@ _elm_slider_class_constructor(Efl_Class *klass)
}
EOLIAN static void
_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)
_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)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
@ -1076,7 +1077,7 @@ _elm_slider_efl_part_part_get(const Eo *obj, Elm_Slider_Data *sd EINA_UNUSED, co
}
EOLIAN static void
_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)
_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)
{
Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
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
efl_canvas_group_change(pd->obj);
}
static void
static Eina_Bool
_indi_default_format_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
{
const Eina_Value_Type *type = eina_value_type_get(&value);
Elm_Slider_Data *sd = efl_data_scope_get(data, ELM_SLIDER_CLASS);
double v;
if (type != EINA_VALUE_TYPE_DOUBLE) return;
if (type != EINA_VALUE_TYPE_DOUBLE) return EINA_FALSE;
eina_value_get(&value, &v);
eina_strbuf_append_printf(str, sd->indi_template, v);
return EINA_TRUE;
}
static void
@ -1129,7 +1132,7 @@ _elm_slider_part_indicator_efl_ui_format_format_string_set(Eo *obj, void *_pd EI
if (!template) return;
eina_stringshare_replace(&sd->indi_template, template);
efl_ui_format_cb_set(efl_part(pd->obj, "indicator"), pd->obj, _indi_default_format_cb, _indi_default_format_free_cb);
efl_ui_format_func_set(efl_part(pd->obj, "indicator"), pd->obj, _indi_default_format_cb, _indi_default_format_free_cb);
}
EOLIAN static const char *
@ -1164,6 +1167,10 @@ _elm_slider_part_indicator_visible_mode_get(const Eo *obj, void *_pd EINA_UNUSED
return sd->indicator_visible_mode;
}
void _elm_slider_part_indicator_efl_ui_format_apply_formatted_value(Eo *obj EINA_UNUSED, Elm_Part_Data *pd EINA_UNUSED)
{
}
#include "elm_slider_part_indicator_eo.c"
/* Efl.Part end */
@ -1194,13 +1201,15 @@ elm_slider_span_size_get(const Evas_Object *obj)
EAPI void
elm_slider_unit_format_set(Evas_Object *obj, const char *units)
{
efl_ui_format_string_set(obj, units);
efl_ui_format_string_set(obj, units, EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
}
EAPI const char *
elm_slider_unit_format_get(const Evas_Object *obj)
{
return efl_ui_format_string_get(obj);
const char* fmt;
efl_ui_format_string_get(obj, &fmt, NULL);
return fmt;
}
EAPI void
@ -1277,7 +1286,7 @@ typedef struct
slider_freefunc_type format_free_cb;
} Slider_Format_Wrapper_Data;
static void
static Eina_Bool
_format_legacy_to_format_eo_cb(void *data, Eina_Strbuf *str, const Eina_Value value)
{
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
if (buf)
eina_strbuf_append(str, buf);
if (sfwd->format_free_cb) sfwd->format_free_cb(buf);
return EINA_TRUE;
}
static void
@ -1310,7 +1321,7 @@ elm_slider_units_format_function_set(Evas_Object *obj, slider_func_type func, sl
sfwd->format_cb = func;
sfwd->format_free_cb = free_func;
efl_ui_format_cb_set(obj, sfwd, _format_legacy_to_format_eo_cb, _format_legacy_to_format_eo_free_cb);
efl_ui_format_func_set(obj, sfwd, _format_legacy_to_format_eo_cb, _format_legacy_to_format_eo_free_cb);
}
EAPI void
@ -1369,13 +1380,15 @@ elm_slider_min_max_get(const Evas_Object *obj, double *min, double *max)
EAPI void
elm_slider_indicator_format_set(Evas_Object *obj, const char *indicator)
{
efl_ui_format_string_set(efl_part(obj, "indicator"), indicator);
efl_ui_format_string_set(efl_part(obj, "indicator"), indicator, EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
}
EAPI const char *
elm_slider_indicator_format_get(const Evas *obj)
{
return efl_ui_format_string_get(efl_part(obj, "indicator"));
const char *fmt;
efl_ui_format_string_get(efl_part(obj, "indicator"), &fmt, NULL);
return fmt;
}
EAPI void
@ -1386,9 +1399,9 @@ elm_slider_indicator_format_function_set(Evas_Object *obj, slider_func_type func
sfwd->format_cb = func;
sfwd->format_free_cb = free_func;
efl_ui_format_cb_set(efl_part(obj, "indicator"), sfwd,
_format_legacy_to_format_eo_cb,
_format_legacy_to_format_eo_free_cb);
efl_ui_format_func_set(efl_part(obj, "indicator"), sfwd,
_format_legacy_to_format_eo_cb,
_format_legacy_to_format_eo_free_cb);
}
EAPI void
@ -1452,6 +1465,10 @@ elm_slider_indicator_visible_mode_get(const Evas_Object *obj)
return elm_slider_part_indicator_visible_mode_get(efl_part(obj, "indicator"));
}
void _elm_slider_efl_ui_format_apply_formatted_value(Eo *obj EINA_UNUSED, Elm_Slider_Data *pd EINA_UNUSED)
{
}
/* Internal EO APIs and hidden overrides */
ELM_LAYOUT_CONTENT_ALIASES_IMPLEMENT(elm_slider)

View File

@ -29,7 +29,7 @@ void _elm_slider_efl_text_markup_markup_set(Eo *obj, Elm_Slider_Data *pd, const
const char *_elm_slider_efl_text_markup_markup_get(const Eo *obj, Elm_Slider_Data *pd);
void _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);
void _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);
void _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
Efl_Object *_elm_slider_efl_part_part_get(const Eo *obj, Elm_Slider_Data *pd, const char *name);
void _elm_slider_efl_ui_format_apply_formatted_value(Eo *obj, Elm_Slider_Data *pd);
static Eina_Bool
_elm_slider_class_initializer(Efl_Class *klass)
@ -63,7 +64,8 @@ _elm_slider_class_initializer(Efl_Class *klass)
EFL_OBJECT_OP_FUNC(efl_text_get, _elm_slider_efl_text_text_get),
EFL_OBJECT_OP_FUNC(efl_text_markup_set, _elm_slider_efl_text_markup_markup_set),
EFL_OBJECT_OP_FUNC(efl_text_markup_get, _elm_slider_efl_text_markup_markup_get),
EFL_OBJECT_OP_FUNC(efl_ui_format_cb_set, _elm_slider_efl_ui_format_format_cb_set),
EFL_OBJECT_OP_FUNC(efl_ui_format_func_set, _elm_slider_efl_ui_format_format_cb_set),
EFL_OBJECT_OP_FUNC(efl_ui_format_apply_formatted_value, _elm_slider_efl_ui_format_apply_formatted_value),
EFL_OBJECT_OP_FUNC(efl_ui_l10n_text_set, _elm_slider_efl_ui_l10n_l10n_text_set),
EFL_OBJECT_OP_FUNC(efl_ui_l10n_text_get, _elm_slider_efl_ui_l10n_l10n_text_get),
EFL_OBJECT_OP_FUNC(efl_part_get, _elm_slider_efl_part_part_get),

View File

@ -7,7 +7,7 @@ Elm_Slider_Indicator_Visible_Mode _elm_slider_part_indicator_visible_mode_get(co
EOAPI EFL_FUNC_BODY_CONST(elm_slider_part_indicator_visible_mode_get, Elm_Slider_Indicator_Visible_Mode, 0);
void _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);
void _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);
void _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
const char *_elm_slider_part_indicator_efl_ui_format_format_string_get(const Eo *obj, void *pd);
void _elm_slider_part_indicator_efl_ui_format_apply_formatted_value(Eo *obj, Elm_Part_Data *pd);
static Eina_Bool
_elm_slider_part_indicator_class_initializer(Efl_Class *klass)
@ -30,9 +31,10 @@ _elm_slider_part_indicator_class_initializer(Efl_Class *klass)
EFL_OPS_DEFINE(ops,
EFL_OBJECT_OP_FUNC(elm_slider_part_indicator_visible_mode_set, _elm_slider_part_indicator_visible_mode_set),
EFL_OBJECT_OP_FUNC(elm_slider_part_indicator_visible_mode_get, _elm_slider_part_indicator_visible_mode_get),
EFL_OBJECT_OP_FUNC(efl_ui_format_cb_set, _elm_slider_part_indicator_efl_ui_format_format_cb_set),
EFL_OBJECT_OP_FUNC(efl_ui_format_func_set, _elm_slider_part_indicator_efl_ui_format_format_cb_set),
EFL_OBJECT_OP_FUNC(efl_ui_format_string_set, _elm_slider_part_indicator_efl_ui_format_format_string_set),
EFL_OBJECT_OP_FUNC(efl_ui_format_string_get, _elm_slider_part_indicator_efl_ui_format_format_string_get),
EFL_OBJECT_OP_FUNC(efl_ui_format_apply_formatted_value, _elm_slider_part_indicator_efl_ui_format_apply_formatted_value),
ELM_SLIDER_PART_INDICATOR_EXTRA_OPS
);
opsp = &ops;
@ -50,4 +52,4 @@ static const Efl_Class_Description _elm_slider_part_indicator_class_desc = {
NULL
};
EFL_DEFINE_CLASS(elm_slider_part_indicator_class_get, &_elm_slider_part_indicator_class_desc, EFL_UI_LAYOUT_PART_CLASS, EFL_UI_FORMAT_MIXIN, NULL);
EFL_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);

View File

@ -103,7 +103,7 @@ struct _Elm_Multibuttonentry_Data
void *add_callback_data;
Ecore_Timer *longpress_timer;
Efl_Ui_Format_Func_Cb format_cb;
Efl_Ui_Format_Func format_cb;
Eina_Free_Cb format_free_cb;
void *format_cb_data;
Eina_Strbuf *format_strbuf;

View File

@ -35,12 +35,12 @@ struct _Elm_Slider_Data
Evas_Coord size;
Efl_Ui_Format_Func_Cb format_cb;
Efl_Ui_Format_Func format_cb;
Eina_Free_Cb format_free_cb;
void *format_cb_data;
Eina_Strbuf *format_strbuf;
Efl_Ui_Format_Func_Cb indi_format_cb;
Efl_Ui_Format_Func indi_format_cb;
Eina_Free_Cb indi_format_free_cb;
void *indi_format_cb_data;
Eina_Strbuf *indi_format_strbuf;

View File

@ -180,6 +180,7 @@ pub_eo_files = [
'efl_ui_relative_layout.eo',
'efl_ui_clickable.eo',
'efl_ui_clickable_util.eo',
'efl_ui_format.eo',
]
foreach eo_file : pub_eo_files
@ -935,6 +936,7 @@ elementary_src = [
'efl_ui_relative_layout.c',
'efl_ui_clickable.c',
'efl_ui_clickable_util.c',
'efl_ui_format.c',
]
elementary_deps = [emile, eo, efl, edje, ethumb, ethumb_client, emotion, ecore_imf, ecore_con, eldbus, efreet, efreet_mime, efreet_trash, eio, atspi, dl, intl]

View File

@ -27,3 +27,4 @@ Just add your widget name to the "test-widgets" array and recompile. Next run of
== Adding a new test ==
To add a new test you need to create the .c file and include the metadata comment at the top.
Remember to add the new .c file to the meson.build file.

View File

@ -0,0 +1,174 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#define EFL_UI_FORMAT_PROTECTED /* To access internal methods */
#include <Efl_Ui.h>
#include "efl_ui_spec_suite.h"
#include "suite_helpers.h"
/* spec-meta-start
{"test-interface":"Efl.Ui.Format",
"test-widgets": ["Efl.Ui.Progressbar", "Efl.Ui.Calendar", "Efl.Ui.Tags", "Efl.Ui.Spin", "Efl.Ui.Spin_Button"]}
spec-meta-end */
static const Efl_Ui_Format_Value values[] = {{15, "fifteen"}, {16, "sixteen"}, {17, "seventeen"}, {18, "eighteen"}};
EFL_START_TEST(format_values)
{
Eina_Strbuf *buf = eina_strbuf_new();
Eina_Value eina_val;
efl_ui_format_values_set(widget, EINA_C_ARRAY_ACCESSOR_NEW(values));
eina_val = eina_value_int_init(17);
efl_ui_format_formatted_value_get(widget, buf, eina_val);
ck_assert_str_eq(eina_strbuf_string_get(buf), "seventeen"); // Check that value works
eina_val = eina_value_float_init(16.f);
efl_ui_format_formatted_value_get(widget, buf, eina_val);
ck_assert_str_eq(eina_strbuf_string_get(buf), "sixteen"); // Check built-in conversion
eina_value_flush(&eina_val);
eina_strbuf_free(buf);
}
EFL_END_TEST
static Eina_Bool
_format_func(void *data, Eina_Strbuf *str, const Eina_Value value)
{
int i = *(int *)data;
int v;
ck_assert_int_eq(i, 1234); // Check that data ptr is passed along correctly
if (eina_value_type_get(&value) != EINA_VALUE_TYPE_INT) return EINA_FALSE;
eina_value_get(&value, &v);
eina_strbuf_append_printf(str, "You said '%d'", v);
return EINA_TRUE;
}
static void
_format_free_func(void *data)
{
int i = *(int *)data;
ck_assert_int_eq(i, 1234); // Check that data ptr is passed along correctly
*(int *)data = 12345; // Change it to indicate that free func was called
}
EFL_START_TEST(format_func)
{
int data = 1234;
Eina_Strbuf *buf = eina_strbuf_new();
Eina_Value eina_val;
efl_ui_format_func_set(widget, &data, _format_func, _format_free_func);
eina_val = eina_value_int_init(15);
efl_ui_format_formatted_value_get(widget, buf, eina_val);
ck_assert_str_eq(eina_strbuf_string_get(buf), "You said '15'"); // Check that format func works
efl_ui_format_func_set(widget, NULL, NULL, NULL);
ck_assert_int_eq(data, 12345); // Check that free func is called
eina_value_flush(&eina_val);
eina_strbuf_free(buf);
}
EFL_END_TEST
EFL_START_TEST(format_string)
{
Eina_Strbuf *buf = eina_strbuf_new();
Eina_Value eina_val;
struct tm t = { 0 };
const char *old_locale = setlocale(LC_TIME, NULL);
#define CHECK(fmt_str, fmt_type, val, val_type, result) \
efl_ui_format_string_set(widget, fmt_str, fmt_type); \
eina_value_setup(&eina_val, val_type); \
eina_value_set(&eina_val, val); \
efl_ui_format_formatted_value_get(widget, buf, eina_val); \
ck_assert_str_eq(eina_strbuf_string_get(buf), result); \
eina_value_flush(&eina_val)
CHECK("%d", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "1234");
CHECK("%d", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234.f, EINA_VALUE_TYPE_FLOAT, "1234"); // built-in conversion
CHECK("%d units", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "1234 units"); // complex format
CHECK("%.0f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 12.34f, EINA_VALUE_TYPE_FLOAT, "12");
CHECK("%.1f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 12.34f, EINA_VALUE_TYPE_FLOAT, "12.3");
CHECK("%.2f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 12.34f, EINA_VALUE_TYPE_FLOAT, "12.34");
CHECK("%.2f", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "1234.00"); // built-in conversion
CHECK("%.0f%%", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 75.f, EINA_VALUE_TYPE_FLOAT, "75%"); // complex format
CHECK("%s", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, "Hello!", EINA_VALUE_TYPE_STRING, "Hello!");
CHECK("%s", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "1234"); // built-in conversion
CHECK("He said '%s'", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, "Hello!", EINA_VALUE_TYPE_STRING, "He said 'Hello!'"); // complex format
CHECK("Static string", EFL_UI_FORMAT_STRING_TYPE_SIMPLE, 1234, EINA_VALUE_TYPE_INT, "Static string");
strptime("2019 7 3 11:49:3", "%Y %m %d %H:%M:%S", &t);
setlocale(LC_TIME, "C");
CHECK("%F", EFL_UI_FORMAT_STRING_TYPE_TIME, t, EINA_VALUE_TYPE_TM, "2019-07-03");
CHECK("%T", EFL_UI_FORMAT_STRING_TYPE_TIME, t, EINA_VALUE_TYPE_TM, "11:49:03");
CHECK("%A", EFL_UI_FORMAT_STRING_TYPE_TIME, t, EINA_VALUE_TYPE_TM, "Wednesday");
CHECK("<%B %Y>", EFL_UI_FORMAT_STRING_TYPE_TIME, t, EINA_VALUE_TYPE_TM, "<July 2019>");
setlocale(LC_TIME, old_locale);
eina_strbuf_free(buf);
#undef CHECK
}
EFL_END_TEST
static Eina_Bool
_partial_format_func(void *data EINA_UNUSED, Eina_Strbuf *str, const Eina_Value value)
{
int v;
if (eina_value_type_get(&value) != EINA_VALUE_TYPE_INT) return EINA_FALSE;
eina_value_get(&value, &v);
if (v < 10)
{
eina_strbuf_append_printf(str, "You said '%d'", v);
return EINA_TRUE;
}
return EINA_FALSE;
}
EFL_START_TEST(format_mixed)
{
Eina_Strbuf *buf = eina_strbuf_new();
Eina_Value eina_val;
// Now we check combinations of different options
// Each one should be used in turn when the previous one fails: values, func, string, fallback
efl_ui_format_values_set(widget, EINA_C_ARRAY_ACCESSOR_NEW(values));
efl_ui_format_func_set(widget, NULL, _partial_format_func, NULL);
efl_ui_format_string_set(widget, "%d rabbits", EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
eina_val = eina_value_int_init(1);
efl_ui_format_formatted_value_get(widget, buf, eina_val);
ck_assert_str_eq(eina_strbuf_string_get(buf), "You said '1'"); // Func
eina_value_set(&eina_val, 15);
efl_ui_format_formatted_value_get(widget, buf, eina_val);
ck_assert_str_eq(eina_strbuf_string_get(buf), "fifteen"); // Values
eina_value_set(&eina_val, 25);
efl_ui_format_formatted_value_get(widget, buf, eina_val);
ck_assert_str_eq(eina_strbuf_string_get(buf), "25 rabbits"); // Values
EXPECT_ERROR_START;
// This is an invalid format string (it has two placeholders) which should
// trigger the fallback mechanism
efl_ui_format_string_set(widget, "%d %d", EFL_UI_FORMAT_STRING_TYPE_SIMPLE);
EXPECT_ERROR_END;
efl_ui_format_formatted_value_get(widget, buf, eina_val);
ck_assert_str_eq(eina_strbuf_string_get(buf), "25"); // Fallback
eina_value_flush(&eina_val);
eina_strbuf_free(buf);
}
EFL_END_TEST
void
efl_ui_format_behavior_test(TCase *tc)
{
tcase_add_test(tc, format_values);
tcase_add_test(tc, format_func);
tcase_add_test(tc, format_string);
tcase_add_test(tc, format_mixed);
}

View File

@ -15,6 +15,7 @@ void efl_pack_linear_behavior_test(TCase *tc);
void efl_content_behavior_test(TCase *tc);
void efl_gfx_arrangement_behavior_test(TCase *tc);
void efl_ui_clickable_behavior_test(TCase *tc);
void efl_ui_format_behavior_test(TCase *tc);
void efl_test_container_content_equal(Efl_Ui_Widget **wid, unsigned int len);
void efl_test_container_expect_evt_content_added(Efl_Ui_Widget *widget, const Efl_Event_Description *ev, Eina_Bool *flag, void *event_data);

View File

@ -5,6 +5,7 @@ efl_ui_suite_behavior_test_files = files([
'efl_test_content.c',
'efl_test_gfx_arrangement.c',
'efl_test_clickable.c',
'efl_test_format.c',
])
efl_ui_suite_behavior_src = files([