jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=a13e61a37b6859b99a09bd3c33c5caa359459451
commit a13e61a37b6859b99a09bd3c33c5caa359459451 Author: Jean-Philippe Andre <[email protected]> Date: Thu Dec 14 17:25:37 2017 +0900 elm: Add "shadow" part to all widgets This makes it possible to very easily create drop shadows and glow effects on any widget. This is absolutely not optimized, though the main performance bottleneck is that the proxy images get redrawn after just moving. @feature --- src/Makefile_Elementary.am | 1 + src/lib/elementary/Elementary.h | 1 + src/lib/elementary/efl_ui_layout.c | 2 + src/lib/elementary/efl_ui_widget_part_shadow.eo | 35 ++++ src/lib/elementary/elm_widget.c | 267 ++++++++++++++++++++++++ src/lib/elementary/elm_widget.eo | 3 + src/lib/elementary/elm_widget.h | 1 + 7 files changed, 310 insertions(+) diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am index d95ddd9774..7f3d733ebd 100644 --- a/src/Makefile_Elementary.am +++ b/src/Makefile_Elementary.am @@ -74,6 +74,7 @@ elm_public_eolian_files = \ lib/elementary/efl_ui_textpath_part.eo \ lib/elementary/efl_ui_widget_part.eo \ lib/elementary/efl_ui_widget_part_bg.eo \ + lib/elementary/efl_ui_widget_part_shadow.eo \ lib/elementary/efl_ui_win_part.eo \ lib/elementary/efl_access.eo \ lib/elementary/efl_access_action.eo \ diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h index c1422ae838..95c54b35ac 100644 --- a/src/lib/elementary/Elementary.h +++ b/src/lib/elementary/Elementary.h @@ -284,6 +284,7 @@ EAPI extern Elm_Version *elm_version; # include <efl_config_global.eo.h> # include <efl_ui_widget_part.eo.h> # include <efl_ui_widget_part_bg.eo.h> +# include <efl_ui_widget_part_shadow.eo.h> # include <efl_ui_layout_part.eo.h> # include <efl_ui_layout_part_box.eo.h> # include <efl_ui_layout_part_content.eo.h> diff --git a/src/lib/elementary/efl_ui_layout.c b/src/lib/elementary/efl_ui_layout.c index 5981fc1a54..0eda685bad 100644 --- a/src/lib/elementary/efl_ui_layout.c +++ b/src/lib/elementary/efl_ui_layout.c @@ -2448,6 +2448,8 @@ _efl_ui_layout_efl_part_part(const Eo *obj, Efl_Ui_Layout_Data *sd EINA_UNUSED, return ELM_PART_IMPLEMENT(EFL_UI_LAYOUT_PART_BG_CLASS, obj, part); } + else if (eina_streq(part, "shadow")) + return efl_part(efl_super(obj, MY_CLASS), part); if (type >= EFL_CANVAS_LAYOUT_PART_TYPE_LAST) { diff --git a/src/lib/elementary/efl_ui_widget_part_shadow.eo b/src/lib/elementary/efl_ui_widget_part_shadow.eo new file mode 100644 index 0000000000..8947b9a0c7 --- /dev/null +++ b/src/lib/elementary/efl_ui_widget_part_shadow.eo @@ -0,0 +1,35 @@ +class Efl.Ui.Widget.Part_Shadow (Efl.Ui.Widget.Part, Efl.Gfx, + Efl.Gfx.Blur, Efl.Gfx.Filter) +{ + [[A drop-shadow or glow effect around any widget. + + A simple drop-shadow effect can be applied to any widget by setting the + color and blur radius on this part. + + For instance, a blue glow can be achieved with: + obj.shadow().color_set(0, 128, 255, 255); + obj.shadow().grow_set(2); + obj.shadow().radius_set(3, 3); + + As another example, here's a black drop-shadow: + obj.shadow().color_set(0, 0, 0, 255); + obj.shadow().grow_set(1); + obj.shadow().radius_set(5, 5); + obj.shadow().offset_set(5, 5); + + It is also possible to manually specify which @Efl.Gfx.Filter program to + use. + ]] + data: null; + implements { + Efl.Gfx.color { set; get; } + Efl.Gfx.Blur.radius { set; get; } + Efl.Gfx.Blur.offset { set; get; } + Efl.Gfx.Blur.grow { set; get; } + Efl.Gfx.Filter.filter_program { set; get; } + Efl.Gfx.Filter.filter_source { set; get; } + Efl.Gfx.Filter.filter_data { set; get; } + Efl.Gfx.Filter.filter_padding { get; } + Efl.Gfx.Filter.filter_state { set; get; } + } +} diff --git a/src/lib/elementary/elm_widget.c b/src/lib/elementary/elm_widget.c index 83437d604b..d67ec8008b 100644 --- a/src/lib/elementary/elm_widget.c +++ b/src/lib/elementary/elm_widget.c @@ -114,6 +114,7 @@ static void _on_sub_obj_del(void *data, const Efl_Event *event); static void _propagate_event(void *data, const Efl_Event *eo_event); static void _elm_widget_focus_tree_unfocusable_handle(Eo *obj); +static void _elm_widget_shadow_update(Elm_Widget *obj); EFL_CALLBACKS_ARRAY_DEFINE(elm_widget_subitems_callbacks, { EFL_EVENT_DEL, _on_sub_obj_del }); @@ -795,6 +796,8 @@ _smart_reconfigure(Elm_Widget_Smart_Data *sd) evas_object_move(sd->bg, sd->x, sd->y); evas_object_resize(sd->bg, sd->w, sd->h); } + if (sd->has_shadow) + _elm_widget_shadow_update(sd->obj); } EOLIAN static void @@ -5625,6 +5628,268 @@ elm_widget_signal_callback_del(Eo *obj, const char *emission, const char *source } +/* Widget Shadow Begin */ + +typedef struct _Widget_Shadow +{ + Eo *widget; + Eo *surface; + struct { + double rx, ry, ox, oy, grow; + int r, g, b, a; + } props; + Eina_Stringshare *code, *name; +} Widget_Shadow; + +static void _widget_shadow_update(Widget_Shadow *shadow); + +static void +_widget_shadow_del_cb(void *data, const Efl_Event *ev EINA_UNUSED) +{ + Widget_Shadow *shadow = data; + + efl_del(shadow->surface); + free(shadow); +} + +static void +_widget_shadow_event_cb(void *data, const Efl_Event *ev EINA_UNUSED) +{ + Widget_Shadow *shadow = data; + _widget_shadow_update(shadow); +} + +EFL_CALLBACKS_ARRAY_DEFINE(widget_shadow_cb, +{ EFL_EVENT_DEL, _widget_shadow_del_cb }, +{ EFL_GFX_EVENT_MOVE, _widget_shadow_event_cb }, +{ EFL_GFX_EVENT_RESIZE, _widget_shadow_event_cb }, +{ EFL_GFX_EVENT_RESTACK, _widget_shadow_event_cb }, +{ EFL_GFX_EVENT_HIDE, _widget_shadow_event_cb }, +{ EFL_GFX_EVENT_SHOW, _widget_shadow_event_cb }) + +static Widget_Shadow * +_widget_shadow_part_get(Eo *part_obj) +{ + Elm_Part_Data *pd = efl_data_scope_get(part_obj, EFL_UI_WIDGET_PART_CLASS); + Widget_Shadow *shadow; + Eo *widget = pd->obj; + + shadow = efl_key_data_get(widget, "__elm_shadow"); + if (!shadow) + { + shadow = calloc(1, sizeof(*shadow)); + shadow->widget = pd->obj; + efl_key_data_set(widget, "__elm_shadow", shadow); + efl_event_callback_array_add(widget, widget_shadow_cb(), shadow); + } + return shadow; +} + +static void +_widget_shadow_update(Widget_Shadow *ws) +{ + int l = 0, r = 0, t = 0, b = 0; + Eina_Rect srect, wrect, fill; + char filter[1024]; + +#define FILTER_FMT \ + "a = buffer { 'alpha' }" \ + "grow { %f, dst = a, alphaonly = true }" \ + "blur { src = a, rx = %f, ry = %f, color = color(%d,%d,%d,%d) }" + + if (!ws->surface) + { + ws->surface = efl_add(EFL_CANVAS_PROXY_CLASS, ws->widget); + efl_gfx_fill_auto_set(ws->surface, 1); + efl_canvas_proxy_source_clip_set(ws->surface, EINA_FALSE); + efl_canvas_proxy_source_events_set(ws->surface, EINA_FALSE); + efl_canvas_proxy_source_set(ws->surface, ws->widget); + } + + if (!ws->code) + { + snprintf(filter, sizeof(filter), FILTER_FMT, + ws->props.grow, ws->props.rx, ws->props.ry, + ws->props.r, ws->props.g, ws->props.b, ws->props.a); + } + + efl_gfx_filter_program_set(ws->surface, + ws->code ? ws->code : filter, + ws->name ? ws->name : "shadow"); + efl_gfx_filter_padding_get(ws->surface, &l, &r, &t, &b); + + wrect = efl_gfx_geometry_get(ws->widget); + srect.x = wrect.x + (int) (-l + ws->props.ox); + srect.y = wrect.y + (int) (-t + ws->props.oy); + srect.w = wrect.w + (int) (l + r); + srect.h = wrect.h + (int) (t + b); + fill.size = wrect.size; + fill.x = 0; + fill.y = 0; + + if ((!ws->props.a && !ws->code) || + !efl_gfx_visible_get(ws->widget)) + { + efl_gfx_visible_set(ws->surface, EINA_FALSE); + return; + } + + efl_canvas_object_clip_set(ws->surface, efl_canvas_object_clip_get(ws->widget)); + efl_canvas_group_member_add(efl_canvas_object_render_parent_get(ws->widget), ws->surface); + efl_gfx_geometry_set(ws->surface, srect); + efl_gfx_stack_below(ws->surface, ws->widget); + efl_gfx_visible_set(ws->surface, EINA_TRUE); +} + +static void +_elm_widget_shadow_update(Elm_Widget *obj) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + _widget_shadow_update(shadow); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_blur_offset_set(Eo *obj, void *_pd EINA_UNUSED, double ox, double oy) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + shadow->props.ox = ox; + shadow->props.oy = oy; + _widget_shadow_update(shadow); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_blur_offset_get(Eo *obj, void *_pd EINA_UNUSED, double *ox, double *oy) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + if (ox) *ox = shadow->props.ox; + if (oy) *oy = shadow->props.oy; +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_blur_radius_set(Eo *obj, void *_pd EINA_UNUSED, double rx, double ry) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + shadow->props.rx = rx; + shadow->props.ry = ry; + _widget_shadow_update(shadow); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_blur_radius_get(Eo *obj, void *_pd EINA_UNUSED, double *rx, double *ry) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + if (rx) *rx = shadow->props.rx; + if (ry) *ry = shadow->props.ry; +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_color_set(Eo *obj, void *_pd EINA_UNUSED, int r, int g, int b, int a) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + shadow->props.r = r; + shadow->props.g = g; + shadow->props.b = b; + shadow->props.a = a; + _widget_shadow_update(shadow); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_color_get(Eo *obj, void *_pd EINA_UNUSED, int *r, int *g, int *b, int *a) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + if (r) *r = shadow->props.r; + if (g) *g = shadow->props.g; + if (b) *b = shadow->props.b; + if (a) *a = shadow->props.a; +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_blur_grow_set(Eo *obj, void *_pd EINA_UNUSED, double radius) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + shadow->props.grow = radius; + _widget_shadow_update(shadow); +} + +EOLIAN static double +_efl_ui_widget_part_shadow_efl_gfx_blur_grow_get(Eo *obj, void *_pd EINA_UNUSED) +{ + Widget_Shadow *shadow = _widget_shadow_part_get(obj); + return shadow->props.grow; +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_program_set(Eo *obj, void *_pd EINA_UNUSED, const char *code, const char *name) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + eina_stringshare_replace(&ws->code, code); + eina_stringshare_replace(&ws->name, name); + _widget_shadow_update(ws); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_program_get(Eo *obj, void *_pd EINA_UNUSED, const char **code, const char **name) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + efl_gfx_filter_program_get(ws->surface, code, name); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_source_set(Eo *obj, void *_pd EINA_UNUSED, const char *name, Efl_Gfx *source) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + _widget_shadow_update(ws); + efl_gfx_filter_source_set(ws->surface, name, source); +} + +EOLIAN static Efl_Gfx * +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_source_get(Eo *obj, void *_pd EINA_UNUSED, const char *name) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + return efl_gfx_filter_source_get(ws->surface, name); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_data_set(Eo *obj, void *_pd EINA_UNUSED, const char *name, const char *value, Eina_Bool execute) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + _widget_shadow_update(ws); + efl_gfx_filter_data_set(ws->surface, name, value, execute); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_data_get(Eo *obj, void *_pd EINA_UNUSED, const char *name, const char **value, Eina_Bool *execute) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + efl_gfx_filter_data_get(ws->surface, name, value, execute); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_padding_get(Eo *obj, void *_pd EINA_UNUSED, int *l, int *r, int *t, int *b) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + efl_gfx_filter_padding_get(ws->surface, l, r, t, b); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_state_set(Eo *obj, void *_pd EINA_UNUSED, const char *cur_state, double cur_val, const char *next_state, double next_val, double pos) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + efl_gfx_filter_state_set(ws->surface, cur_state, cur_val, next_state, next_val, pos); +} + +EOLIAN static void +_efl_ui_widget_part_shadow_efl_gfx_filter_filter_state_get(Eo *obj, void *_pd EINA_UNUSED, const char **cur_state, double *cur_val, const char **next_state, double *next_val, double *pos) +{ + Widget_Shadow *ws = _widget_shadow_part_get(obj); + efl_gfx_filter_state_get(ws->surface, cur_state, cur_val, next_state, next_val, pos); +} + +#include "efl_ui_widget_part_shadow.eo.c" + +/* Widget Shadow End */ + + /* Efl.Part implementation */ EOLIAN static Efl_Object * @@ -5632,6 +5897,8 @@ _elm_widget_efl_part_part(const Eo *obj, Elm_Widget_Smart_Data *wd EINA_UNUSED, { if (eina_streq(part, "background")) return ELM_PART_IMPLEMENT(EFL_UI_WIDGET_PART_BG_CLASS, obj, part); + else if (eina_streq(part, "shadow")) + return ELM_PART_IMPLEMENT(EFL_UI_WIDGET_PART_SHADOW_CLASS, obj, part); return ELM_PART_IMPLEMENT(EFL_UI_WIDGET_PART_CLASS, obj, part); } diff --git a/src/lib/elementary/elm_widget.eo b/src/lib/elementary/elm_widget.eo index 92071374b5..b8c093af06 100644 --- a/src/lib/elementary/elm_widget.eo +++ b/src/lib/elementary/elm_widget.eo @@ -570,6 +570,9 @@ abstract Elm.Widget (Efl.Canvas.Group, Efl.Access, return: Efl.Ui.Focus.Manager; [[The focus manager.]] } } + parts { + shadow: Efl.Ui.Widget.Part_Shadow; + } implements { class.constructor; Efl.Object.constructor; diff --git a/src/lib/elementary/elm_widget.h b/src/lib/elementary/elm_widget.h index 23e1a5ec4c..b7975a45da 100644 --- a/src/lib/elementary/elm_widget.h +++ b/src/lib/elementary/elm_widget.h @@ -465,6 +465,7 @@ typedef struct _Elm_Widget_Smart_Data Eina_Bool on_destroy: 1; /**< This is true when the widget is on destruction(general widget destructor). */ Eina_Bool provider_lookup : 1; /**< This is true when efl_provider_find is currently walking the tree */ Eina_Bool legacy : 1; /**< Widget was created with a legacy API, not efl_add() */ + Eina_Bool has_shadow : 1; } Elm_Widget_Smart_Data; typedef Elm_Widget_Smart_Data Efl_Ui_Widget_Data; --
