evas: Implement filter_data_set for textblock

This is a function that allows passing variables from C or EDC
to the filter's Lua code. Useful in particular for color classes
from EDC.

This data would be the global data but we could eventually add
a markup tag to specify a data value per filter instance. For now
a single data value per tb object should be more than enough though.
This commit is contained in:
Jean-Philippe Andre 2017-01-05 11:25:21 +09:00
parent 4453044d84
commit 1512741b48
4 changed files with 174 additions and 27 deletions

View File

@ -43,8 +43,9 @@ static const Filter_Image images_cloud[] = {
static const Filter templates[] = {
{ "Custom", NULL, NULL },
{ "Black shadow",
"if not myColor then myColor = color('yellow') end\n"
"blur { 6, ox = 2, oy = 2, color = 'black' }\n"
"blend {}", NULL },
"blend { color = myColor }", NULL },
{ "Fire glow",
"a = buffer { 'alpha' }\n"
"grow { 10, dst = a }\n"
@ -71,8 +72,8 @@ static const Filter templates[] = {
"blend { color = 'black' }\n"
"mask { input, b }\n", NULL },
{ "Rocking it",
"padding_set { 40 }\n"
"local len = state.scale * 10\n\n"
"padding_set { len * 2 }\n"
"a = buffer { 'alpha' }\n"
"grow { len / 2, dst = a }\n"
"blur { len * 2, oy = len, ox = len / 2, color = 'black', src = a }\n"
@ -221,12 +222,6 @@ _textblock_resize(void *data EINA_UNUSED, const Efl_Event *ev)
efl_gfx_size_hint_min_set(ev->object, w + l + r, h + t + b);
}
static Evas_Object *
_img_tooltip(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, Evas_Object *tt)
{
return efl_add(EFL_UI_TEXT_CLASS, tt, efl_text_set(efl_added, efl_name_get(tt)));
}
static void
_img_click(void *data, const Efl_Event *ev)
{
@ -274,6 +269,24 @@ _flip_click(void *data, const Efl_Event *ev EINA_UNUSED)
efl_ui_flip_go(flip, EFL_UI_FLIP_CROSS_FADE);
}
static void
_colsel_cb(void *data, const Efl_Event *ev)
{
Eo *win = data;
Eo *colsel = ev->object;
Eo *text, *tb;
int r = 0, g = 0, b = 0, a = 255;
char buf[64];
text = efl_key_wref_get(win, "text");
tb = efl_key_wref_get(win, "textblock");
elm_colorselector_color_get(colsel, &r, &g, &b, &a);
sprintf(buf, "color(%d, %d, %d, %d)", r, g, b, a);
efl_gfx_filter_data_set(text, efl_name_get(colsel), buf, 1);
efl_gfx_filter_data_set(tb, efl_name_get(colsel), buf, 1);
}
void
test_gfx_filters(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
@ -332,36 +345,63 @@ test_gfx_filters(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *eve
}
{
size_t k;
box2 = efl_add(EFL_UI_BOX_CLASS, win,
efl_orientation_set(efl_added, EFL_ORIENT_HORIZONTAL),
efl_gfx_size_hint_weight_set(efl_added, 1.0, 0.0),
efl_gfx_size_hint_align_set(efl_added, 0.0, 0.5),
efl_gfx_size_hint_align_set(efl_added, -1.0, 0.5),
efl_pack_padding_set(efl_added, 5, 5, 1),
efl_gfx_size_hint_margin_set(efl_added, 5, 5, 5, 5),
efl_pack_align_set(efl_added, 0, 0.5));
efl_pack(box, box2);
for (k = 0; k < EINA_C_ARRAY_LENGTH(images); k++)
for (size_t k = 0; k < EINA_C_ARRAY_LENGTH(images); k++)
{
char buf[PATH_MAX];
if (!images[k].path) break;
snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), images[k].path);
o = efl_add(EFL_UI_IMAGE_CLASS, win,
efl_gfx_size_hint_weight_set(efl_added, 1.0, 0.0),
efl_gfx_size_hint_weight_set(efl_added, 0.0, 0.0),
efl_gfx_size_hint_align_set(efl_added, 0.5, 0.5),
efl_gfx_size_hint_max_set(efl_added, ELM_SCALE_SIZE(48), ELM_SCALE_SIZE(48)),
efl_gfx_size_hint_min_set(efl_added, ELM_SCALE_SIZE(48), ELM_SCALE_SIZE(48)),
efl_file_set(efl_added, buf, NULL),
efl_name_set(efl_added, images[k].src_name),
elm_object_tooltip_text_set(efl_added, images[k].src_name),
efl_gfx_visible_set(efl_added, 1));
elm_object_tooltip_content_cb_set(o, _img_tooltip, NULL, NULL); // GRRRRR
efl_event_callback_add(o, EFL_UI_EVENT_CLICKED, _img_click, win);
efl_pack(box2, o);
}
const struct { int r, g, b, a; } colors[] = {
{ 255, 255, 255, 255 },
{ 0, 0, 0, 255 },
{ 64, 64, 64, 255 },
{ 128, 128, 128, 255 },
{ 196, 196, 196, 255 },
{ 255, 0, 0, 255 },
{ 0, 255, 0, 255 },
{ 0, 0, 255, 255 },
{ 255, 255, 0, 255 },
{ 255, 0, 255, 255 },
{ 0, 255, 255, 255 },
{ 0, 0, 0, 0 }
};
o = efl_add(ELM_COLORSELECTOR_CLASS, win,
efl_gfx_size_hint_weight_set(efl_added, 1.0, 0),
efl_gfx_size_hint_align_set(efl_added, -1.0, 0),
elm_colorselector_mode_set(efl_added, ELM_COLORSELECTOR_PALETTE),
efl_gfx_size_hint_max_set(efl_added, -1, ELM_SCALE_SIZE(48 * 2)),
efl_name_set(efl_added, "myColor"),
elm_object_tooltip_text_set(efl_added, "Pick a color to use as variable 'myColor'"),
efl_event_callback_add(efl_added, ELM_COLORSELECTOR_EVENT_CHANGED, _colsel_cb, win),
efl_gfx_visible_set(efl_added, 1));
efl_pack(box2, o);
for (size_t k = 0; k < EINA_C_ARRAY_LENGTH(colors); k++)
elm_colorselector_palette_color_add(o, colors[k].r, colors[k].g, colors[k].b, colors[k].a);
efl_gfx_visible_set(box2, 1);
}
@ -402,16 +442,16 @@ test_gfx_filters(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *eve
efl_pack_align_set(efl_added, 0.5, 0.5));
efl_pack(flip, box2);
const char *codes[] = {
"padding_set{20} blur{3} blend{}",
"blur{15,color='red'} blend{}",
"blend{}"
const struct { const char *name, *code; } programs [] = {
{ "one", "blur { 5, color = 'darkblue' } blend {}" },
{ "two", "blur { 15, color = 'red' } blend {}" },
{ "main", "blend {}" }
};
const char *names[] = {
"one",
"two",
"main"
const struct { const char *name, *value; int exec; } prg_data [] = {
{ "myColor", "color(255, 0, 255)", EINA_TRUE },
};
const char *tbtxt = "Classic <gfx_filter='one'>hello</> world!<br>"
"And <gfx_filter='two'>This filter over<br>"
"multiple lines</> :)<br/>"
@ -422,8 +462,10 @@ test_gfx_filters(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *eve
efl_event_callback_add(o, EFL_GFX_EVENT_RESIZE, _textblock_resize, NULL);
Evas_Textblock_Style *st = evas_textblock_style_new();
evas_textblock_style_set(st, "DEFAULT='font=Sans font_size=20 color=#FFF wrap=word'");
for (size_t k = 0; k < EINA_C_ARRAY_LENGTH(codes); k++)
efl_gfx_filter_program_set(o, codes[k], names[k]);
for (size_t k = 0; k < EINA_C_ARRAY_LENGTH(programs); k++)
efl_gfx_filter_program_set(o, programs[k].code, programs[k].name);
for (size_t k = 0; k < EINA_C_ARRAY_LENGTH(prg_data); k++)
efl_gfx_filter_data_set(o, prg_data[k].name, prg_data[k].value, prg_data[k].exec);
evas_object_textblock_style_set(o, st);
evas_object_textblock_text_markup_set(o, tbtxt);
efl_canvas_object_scale_set(o, elm_config_scale_get());

View File

@ -368,6 +368,7 @@ class Efl.Canvas.Text (Efl.Canvas.Object, Efl.Text, Efl.Canvas.Filter.Internal)
Efl.Canvas.Object.paragraph_direction { get; set; }
Efl.Text.text { get; set; }
Efl.Gfx.Filter.filter_program { get; set; }
Efl.Gfx.Filter.filter_data { get; set; }
Efl.Canvas.Filter.Internal.filter_dirty;
Efl.Canvas.Filter.Internal.filter_input_render;
Efl.Canvas.Filter.Internal.filter_state_prepare;

View File

@ -461,6 +461,7 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_source_set(Eo *eo_obj, Evas_Fi
eina_hash_add(fcow->sources, pb->name, pb);
evas_filter_program_source_set_all(fcow->chain, fcow->sources);
evas_filter_program_data_set_all(fcow->chain, fcow->data);
evas_filter_program_parse(fcow->chain, fcow->code);
// Update object
update:
@ -658,6 +659,7 @@ _efl_canvas_filter_internal_efl_gfx_filter_filter_data_set(Eo *eo_obj, Evas_Filt
fcow->data = eina_inlist_append(fcow->data, EINA_INLIST_GET(db));
}
evas_filter_program_data_set_all(fcow->chain, fcow->data);
evas_filter_program_parse(fcow->chain, fcow->code);
fcow->changed = 1;
}
FCOW_END(fcow, pd);

View File

@ -597,6 +597,7 @@ struct _Evas_Object_Textblock
} formatted, native;
struct {
Efl_Canvas_Text_Filter_Program *programs;
Evas_Filter_Data_Binding *data_bindings;
} gfx_filter;
Eina_Bool redraw : 1;
Eina_Bool changed : 1;
@ -4344,6 +4345,7 @@ _filter_program_find(Efl_Canvas_Text_Data *o, const char *name)
{
Efl_Canvas_Text_Filter_Program *prg;
if (!name) return NULL;
EINA_INLIST_FOREACH(o->gfx_filter.programs, prg)
{
if (eina_streq(name, prg->name))
@ -4361,9 +4363,11 @@ _format_filter_program_get(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Format
Evas_Filter_Program *pgm;
filter = fmt->gfx_filter;
if (!filter->name) return NULL;
if (!filter) return NULL;
program = _filter_program_find(o, filter->name);
if (!program) return NULL;
if (program->changed)
{
evas_filter_program_del(program->pgm);
@ -4372,8 +4376,8 @@ _format_filter_program_get(Efl_Canvas_Text_Data *o, Evas_Object_Textblock_Format
pgm = program->pgm;
if (!pgm)
{
// TODO: data set
pgm = evas_filter_program_new(program->name, EINA_FALSE);
evas_filter_program_data_set_all(pgm, EINA_INLIST_GET(o->gfx_filter.data_bindings));
if (!evas_filter_program_parse(pgm, program->code))
{
evas_filter_program_del(pgm);
@ -12844,13 +12848,34 @@ _efl_canvas_text_efl_object_destructor(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_
efl_destructor(efl_super(eo_obj, MY_CLASS));
}
// testing this macro...
#define EINA_INLIST_REMOVE(l,i) do { l = (__typeof__(l)) eina_inlist_remove(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
static void
evas_object_textblock_free(Evas_Object *eo_obj)
{
Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
Efl_Canvas_Text_Filter_Program *prg;
Evas_Filter_Data_Binding *db;
_evas_object_textblock_clear(eo_obj);
evas_object_textblock_style_set(eo_obj, NULL);
EINA_INLIST_FREE(o->gfx_filter.programs, prg)
{
EINA_INLIST_REMOVE(o->gfx_filter.programs, prg);
eina_stringshare_del(prg->name);
eina_stringshare_del(prg->code);
free(prg);
}
EINA_INLIST_FREE(o->gfx_filter.data_bindings, db)
{
EINA_INLIST_REMOVE(o->gfx_filter.data_bindings, db);
eina_stringshare_del(db->name);
eina_stringshare_del(db->value);
free(db);
}
while (evas_object_textblock_style_user_peek(eo_obj))
{
evas_object_textblock_style_user_pop(eo_obj);
@ -13659,10 +13684,10 @@ _efl_canvas_text_efl_gfx_filter_filter_program_set(Eo *eo_obj, Efl_Canvas_Text_D
}
eina_stringshare_replace(&prg->code, code);
prg->changed = EINA_TRUE;
pd->format_changed = EINA_TRUE;
_evas_textblock_invalidate_all(pd);
_evas_textblock_changed(pd, eo_obj);
evas_object_change(eo_obj, obj);
}
@ -13674,6 +13699,83 @@ _efl_canvas_text_efl_gfx_filter_filter_program_get(Eo *obj EINA_UNUSED, Efl_Canv
ERR("Invalid API definition for this object! 'name' needs to be an @in or @inout value!");
}
static Evas_Filter_Data_Binding *
_filter_data_binding_find(Efl_Canvas_Text_Data *pd, const char *name)
{
Evas_Filter_Data_Binding *db;
if (!name) return NULL;
EINA_INLIST_FOREACH(pd->gfx_filter.data_bindings, db)
if (!strcmp(db->name, name))
return db;
return NULL;
}
EOLIAN static void
_efl_canvas_text_efl_gfx_filter_filter_data_set(Eo *obj, Efl_Canvas_Text_Data *pd, const char *name, const char *value, Eina_Bool execute)
{
Efl_Canvas_Text_Filter_Program *prg;
Evas_Filter_Data_Binding *db;
if (!name) return;
db = _filter_data_binding_find(pd, name);
if (db)
{
if (eina_streq(db->value, value) && (db->execute == execute))
return;
if (!value)
{
EINA_INLIST_REMOVE(pd->gfx_filter.data_bindings, db);
eina_stringshare_del(db->name);
eina_stringshare_del(db->value);
free(db);
}
}
else if (!value)
{
return;
}
else
{
db = calloc(1, sizeof(*db));
pd->gfx_filter.data_bindings = (Evas_Filter_Data_Binding *)
eina_inlist_append(EINA_INLIST_GET(pd->gfx_filter.data_bindings), EINA_INLIST_GET(db));
db->name = eina_stringshare_add(name);
}
eina_stringshare_replace(&db->value, value);
db->execute = execute;
EINA_INLIST_FOREACH(pd->gfx_filter.programs, prg)
{
if (!prg->code) continue;
if (strstr(prg->code, name))
prg->changed = EINA_TRUE;
}
pd->format_changed = EINA_TRUE;
_evas_textblock_invalidate_all(pd);
_evas_textblock_changed(pd, obj);
evas_object_change(obj, efl_data_scope_get(obj, EFL_CANVAS_OBJECT_CLASS));
}
EOLIAN static void
_efl_canvas_text_efl_gfx_filter_filter_data_get(Eo *obj EINA_UNUSED, Efl_Canvas_Text_Data *pd, const char *name, const char **value, Eina_Bool *execute)
{
Evas_Filter_Data_Binding *db;
db = _filter_data_binding_find(pd, name);
if (!db)
{
if (value) *value = NULL;
if (execute) *execute = EINA_FALSE;
return;
}
if (value) *value = db->value;
if (execute) *execute = db->execute;
}
static void
evas_object_textblock_coords_recalc(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,