orbtk icon indicating copy to clipboard operation
orbtk copied to clipboard

Widget property name during template building

Open uniformbuffer opened this issue 5 years ago • 4 comments

Context

In which context or scenario will your feature/widget be used? Hi, i look for a way to map a specific property of a widget to a property of an internal one.

Problem description & Solution

Describe your problem and possible solution here

An example code:

widget!(
    MyWidget<MyWidgetState>
    {
         value: usize
    }
)

impl Template for MyWidget {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("MyWidget")
        .child(TextBlock::new().text(id).build(ctx))
    }
}

I would like to link the property value of MyWidget with the property text of TextBlock. Unfortunatly they have different types and different names. I don't know if a way already exist, i searched a lot and i have not found it. If that is the case, sorry for the disturb. I know that is is possible to workaround this problem manipulating the fields from the update function of a State, but need more time and, if there are many properties to be transformed, very confusing.

Generally passing the entity id is the way to do this, but properties must have the same names and the same types. I have noticed that a PropertySource<T> cannot be passed because it does not implement IntoPropertySource<T>, so i have no idea how to do this. A solution could be make (Entity,&str,Fn(T)->K) valid for IntoPropertySource trait, where the Entity is the source entity, the &str is the name of source property names and the Fn is made to allow the insertion of a simple closure that can transform a T source type into a K destination type. I don't know how exactly this mechanism work, but if it is too complicated to implement, at least should be possible to link properties with the same type but different names, so the type to be valid for IntoPropertySource could be something like (Entity,&str) where the Entity is the source entity and the &str is the property name. My only fear is that this tuple could be already used by some other combinations.

Examples and MockUps

widget!(
    MyWidget<MyWidgetState>
    {
         value: usize
    }
)

impl Template for MyWidget {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("MyWidget")
        .child(
               TextBlock::new()
               .text((id,"value",|usize_value|{String16::new(usize_value.to_string())}))
               .build(ctx)
        )
    }
}

Thanks for the attention, Have a nice day

uniformbuffer avatar Jul 17 '20 15:07 uniformbuffer

Hi, i made some other tests today and maybe i found a solution that need to add only 3 lines to /crate/api/src/properties/mod.rs (still testing, but should work):

impl<P: Component + Debug> IntoPropertySource<P> for PropertySource<P>
{
    fn into_source(self) -> PropertySource<P> {self}
}

This allow a PropertySource<P> item to be passed to the properties setters that have the same type, but with different names. The precedent example with this modification look like:

widget!(
    MyWidget<MyWidgetState>
    {
         value: String16
    }
)

impl Template for MyWidget {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("MyWidget")
        .child(
               TextBlock::new()
               .text(PropertySource::KeySource("value",id))
               .build(ctx)
        )
    }
}

Still missing a way to set a "conversion" function, but just this solve half of the problem. Just to be clear, for "conversion" function i intend a function that transform a type A to type B, but there could be non real conversion effectively, for example a field reference, like

let function: Fn(A)->B = |A_object|
{
   A_object.field_of_type_B
}

Maybe, if you think that is good enough and that could be useful, i can open a PR. Thanks for the attention

uniformbuffer avatar Jul 17 '20 20:07 uniformbuffer

Maybe you could accept the Into trait in the conversion function: https://doc.rust-lang.org/std/convert/trait.Into.html

kivimango avatar Jul 18 '20 07:07 kivimango

Unfortunately I think that is not that easy. The problem is that if you inject an id in a property a shared component will be generated in DCES (the entity component system OrbTk based on). A property is stored only one time in the DCES. And a shared property only references the origin property. That means that it must have the same type. If we want to introduce a conversion we need to update it in DCES or we must store it outside of the Entity Component System. But I think we the conversion is a must features! Thank you for the input.

FloVanGH avatar Jul 18 '20 08:07 FloVanGH

Maybe you could accept the Into trait in the conversion function: https://doc.rust-lang.org/std/convert/trait.Into.html

Yes, that's surely a better way to do this, with Into trait there is no need to keep trace of the source type, and since the destination type P is provided by PropertySource< P >, everything is needed is already here.

uniformbuffer avatar Jul 18 '20 11:07 uniformbuffer