Page MenuHomePhabricator

Base background object
Closed, ResolvedPublic

Description

Similar to the existing Efl.Ui.Win "background" part, we want to have custom backgrounds in various widgets. Those would likely be one of:

  • Solid color (rectangle)
  • Rounded rectangle (evas vg)
  • Image (evas or elm image)

The "background" part shall be accessed through the API efl_part(obj, "background") (or "bg", TBD), which means we can provide a set of convenience functions to support direct APIs like efl_file_set for image or efl_gfx_color_set for solid backgrounds.

See also D3625 (deprecated).

jpeg assigned this task to taxi2se.Jul 17 2017, 12:10 AM
jpeg added a comment.Jul 30 2017, 10:23 PM

To quote myself:

I have done some similar work for Efl.Ui.Win but it is incomplete, and does not use shareable code.
I think we need to work on 3 things:

  1. A common way in EDC to share the background features (swallow? external? subgroup?)
  2. A common class implementation for Efl.Part (quite easy)
  3. Modify the theme to use the common background, so either:
    • change the default style to accept a background (probably quite hard to manage well)
    • create a new style, basically for uses with EO

      #3 will be a lot of work, and for #1 I'm not sure what's the best thing to do. Maybe edje external is the easiest solution here?

IMO, swallow part would be enough for background features.
For BG, I guess using GROUP part as a subgroup cannot make significant line changes,
but may reduce readability beacuse state has to be defined in bg group and part in widget group respectively.

I agree that using Efl.Part Interface can be nice, but it could be bad when we have to make subclasses and subclasses for subclasses.

For example, if we use Efl.Part then the usage will be like this.

_efl_ui_XXX_internal_part_efl_gfx_color_set()
{
   if (eina_streq(part, "background"))
     { }
   else if (eina_streq(part, "other_part"))
     { }
}
_efl_ui_XXX_internal_part_efl_gfx_color_get()
_efl_ui_XXX_internal_part_efl_file_file_set()
_efl_ui_XXX_internal_part_efl_file_file_set()

and more...

Then let us suppose, we have to create a class "YYY" which inherits "XXX".
This has a part "other_part" but need to call more or different APIs to change color, and files.
For that, we have to write _efl_ui_YYY_internal_part_efl_gfx_color_set().

It will be look like this I guess.

_efl_ui_YYY_internal_part_efl_gfx_color_set()
{
   if (eina_streq(part, "background"))
     { }
   else if (eina_streq(part, "other_part"))
     { }
}
_efl_ui_YYY_internal_part_efl_gfx_color_get()
_efl_ui_YYY_internal_part_efl_file_file_set()
_efl_ui_YYY_internal_part_efl_file_file_set()

The same code for background has to be literally copied to both _internal_part
and IMO, this is not good for background.
If most of the widgets will have background, they should not be implemented and implemented in each widgets.

One solution I can think of would be to create a bg interface.
If extended feature for bg is needed, another interface of bg can be added.
I just commited rough draft of that idea in D5055.

I might misunderstand Efl.Part, but I think bg can be a property rather than part if most of the widgets will have background.

Please share your opinion.

jpeg added a comment.Aug 1 2017, 12:58 AM

As discussed IRL I think this case can be solved by this pseudo code:

Solution 1: override hack

_subclass_button_efl_part_part(Eo *obj, const char *part) {
  if (!eina_streq(part, "my_special_part")) return efl_part(efl_super(obj, MY_CLASS), part);

  Eo *eo_part = efl_part(efl_super(obj, MY_CLASS), part);
  efl_object_override(eo_part, efl_text_set, _my_subclass_part_text_set);
  return eo_part;
}

OR, solution 2: special part class:

_subclass_button_efl_part_part(Eo *obj, const char *part) {
  if (!eina_streq(part, "my_special_part")) return efl_part(efl_super(obj, MY_CLASS), part);
  return efl_add(MY_SUBCLASS_BUTTON_PART_CLASS, obj);
}

static void
_my_subclass_button_part_efl_text_text_set(Eo *eo_obj, const char *text) {
  My_Subclass_Button_Part_Data *dt = efl_data_scope_get(eo_obj, ...);

  // This function can do anything:
  _my_subclass_button_text_set(dt->object, dt->partname, text);
}
jpeg added a subscriber: raster.Aug 1 2017, 1:20 AM

Back to the original topic.

We can use subgroup, external, or swallow to achieve this purpose.
Externals & subgroup can both be instantiated from EDC and modified from there as well.
Externals require elementary module interaction. This may make them a bit more complex. Right now they are not in a very nice state, feature wise (pretty much unmaintained).
Subgroups require more infrastructure work.

Subgroup infra work, if done by @raster, can provide the necessary features:

  • Source subgroups from another EDC file.
  • Source subgroups from another EDJ file, so that run time overrides can be made.
  • Subgroups need to receive and send messages / signals to their parent group, for event handling.
  • Ability to override most things from a subgroup. Example for a button:
    • BG subgroup's "color_class" name needs to be changed. The name itself, not just the value of the color class, so that the color be defined by the class "efl/button" and not "efl/bg".
    • Same applies to the border image, border value, etc...

The question thus becomes how to allow those overrides. It seems this needs to work at run time not only compile time.

jpeg added a comment.Aug 1 2017, 1:32 AM

The button EDC group would then be a skeletton including:

  • subgroup "efl.bg" { custom color class, custom border, custom image, custom }
  • textblock "efl.text" { custom color class, custom text class }
  • subgroup "efl.fg"

Some more problems exist as we need to handle states like "disabled", "pressed", "hover". The list of which depends on each widget.

In T5716#93285, @jpeg wrote:

The button EDC group would then be a skeletton including:

  • subgroup "efl.bg" { custom color class, custom border, custom image, custom }
  • textblock "efl.text" { custom color class, custom text class }
  • subgroup "efl.fg" Some more problems exist as we need to handle states like "disabled", "pressed", "hover". The list of which depends on each widget.

If each subgroup will have states for events,
I think we have to discuss with @Jaehyun_Cho also.

In T5337 animation framework might support:

efl_canvas_object_event_animation_set(btn, EFL_ANIMATION_EVENT_TYPE_SHOW, anim);
efl_canvas_object_event_animation_set(btn, EFL_ANIMATION_EVENT_TYPE_CLICKED, anim2);

Should "visible" or "clicked" state of "efl.bg" of a button be affected by this animation?
How can "efl.bg" check whether widget implements "efl.ui.clickable" interface.

raster added a comment.Aug 6 2017, 6:42 PM

i think we need to be careful here. what is "background". if my buttons lets say have rounded corners and use some vg part to do that, you want to then use that vg part as a CLIP for the background object you might swallow - right? if the button has a shadow then when you set background does shadow go away or does background replace the solid "Rectangular" part and keep the shadow? i think in all cases setting background involves the theme needing to clip, underlay, overlay or otherwise add decoration, shading, masking/clipping to whatever object is used as the background.

asking for this clipping/masking/decorating to stop and become empty/plain is a different matter.

so this leads me to the conclusion that backgrouns, foreground etc. things should be swallows always. the theme will decide how to clip/mask/decorate. if you want no decoration then perhaps we should provide an "empty" style. perhaps we should by default always offer an empty style that contains only absolutely minimal content and any decorating and imagery has to be provided by this part interface. imagine more complex setups like a slider. what is the background? it's certainly not the "bar" that shows the level. it's not the slider "knob". is it what fills the area the bar might take up at 100%? is it just the entire area o the slider behind this? these are important questions to consider as it will impact design here, naming schemes and conventions.

also to make this work changes in state need to be propagated to all objects you swallow so they can also change their look to match. button being disabled or normal, pressed or released, focused, etc. etc. ... and which states are mutually exclusive and which are "bitmasks" that can have multiple states at once.

Event propagation to swallowed object in edc group may not be needed if a handle of each part can be acquired easily.
For example:

it = efl_part_iterate(obj);
EINA_ITERATOR_FOREACH(it. part)
   part.set_state("pressed");

Also, we might say a widget is in XXX state if every parts of the widget is in XXX state.
If we plan to extend part interface to every component of a widget, this can be used extensively.

I think the feature relating to setting states should be handled and decided by more people.
It requires some infra such as data structure to store descriptions for each state, and policy decision
such as how to check sth is in which states or which state is prior to which state.

I commited experimental codes: D5147, D5151.

These enables background creation, modification by

efl_gfx_color_set(efl_part(obj, "background"), r, g, b, a);
efl_content_set(efl_part(obj, "background"), subobj);
efl_file_set(efl_part(obj, "background"), filename);

Workflow is like this.

  1. Create an object class which will be used as common background. (I extended elm_bg to efl_ui_bg here)
  2. Create singleton bg object when APIs for "background" part is called in a widget. This is becuase most widgets have transparent background, and previous elm themes are compatible.
  3. The bg, created in 1., will be swallowed to reserved SWALLOW part.(I temporarilly used elm.swallow.background)

Works which must be considered can be this. Please add comment if you have more idea on this.

  • As mentioned in comments above, infra for state, such as set_state, set_state_description, should be added.
  • An way to set default color must be prepared. For example, efl_ui_button and efl_ui_check will have a background but they might have different default background color.
jpeg added a comment.Dec 11 2017, 6:04 PM

@taxi2se please note the commit IDs related to part background, as well as your current work in progress. We should be able to close this ticket soon.

jpeg raised the priority of this task from Wishlist to Normal.Jan 18 2018, 12:51 AM

Most of this has already been implemented. Good!

Only remaining thing to implement is signal / state passing. Basically just be able to handle multiple states (normal, disabled, pressed, highlighted?) from code.

zmike edited projects, added Restricted Project; removed efl.Jun 11 2018, 6:57 AM
bu5hm4n edited projects, added efl: widgets; removed Restricted Project.Jun 11 2018, 9:15 AM
zmike added a subscriber: zmike.Jan 17 2019, 11:37 AM

What's going on with this?

bu5hm4n added a subscriber: bu5hm4n.Oct 4 2019, 3:06 AM

I think we do not want to have state passing for disabled things etc. on the background, as the background is just a passiv static thing floating arround in the widget ? So i think this is done ?

zmike closed this task as Resolved.Oct 4 2019, 6:17 AM

It inherits from widget anyway, so it does have the ability to do this.

raster added a comment.EditedOct 5 2019, 5:50 AM

we do want the background to know and be able to react to being disabled. you want a widget tree (imagine you disable a scroller that has a table of buttons, checkboxes and has a background behind it). you want to be able to "grey out" a background if that is the visual paradigm. as default backgrounds are already grey it's kind of pointless, but perhaps dim it or fade out any swallowed image or rgb solid color set to mute it and make it more "grey" to indicate that whole area is part of a disabled tree. in the case of a window you can disable the whole window as well and thus all content in it... :)