iced icon indicating copy to clipboard operation
iced copied to clipboard

Simplifying StyleSheet implementations

Open TimUntersberger opened this issue 5 years ago • 7 comments

Right now any StyleSheet has a list of functions without a default implementation. Implementing a StyleSheet is really annoying, because you have to override all of the functions and not just the thing you want to change.

I recently wanted to just change the border_radius of a text_input and I had to write the following code.

impl StyleSheet for Styles {
    fn active(&self) -> Style {
        Style {
            border_radius: 0,
            ..Style::default()
        }
    }

    fn focused(&self) -> Style {
        Style {
            border_color: Color::from_rgb(0.5, 0.5, 0.5),
            ..self.active()
        }
    }

    fn placeholder_color(&self) -> Color {
        Color::from_rgb(0.7, 0.7, 0.7)
    }

    fn value_color(&self) -> Color {
        Color::from_rgb(0.3, 0.3, 0.3)
    }

    fn selection_color(&self) -> Color {
        Color::from_rgb(0.8, 0.8, 1.0)
    }
}

As you can see I mostly just copied your sourcecode.

If StyleSheets would have these default styles as default implementation like this:

trait StyleSheet {
    fn active(&self) -> Style {
        Style {
            background: Background::Color(Color::WHITE),
            border_radius: 0,
            border_width: 1.0,
            border_color: Color::from_rgb(0.7, 0.7, 0.7),
        }
    }

    fn focused(&self) -> Style {
        Style {
            border_color: Color::from_rgb(0.5, 0.5, 0.5),
            ..self.active()
        }
    }

    fn placeholder_color(&self) -> Color {
        Color::from_rgb(0.7, 0.7, 0.7)
    }

    fn value_color(&self) -> Color {
        Color::from_rgb(0.3, 0.3, 0.3)
    }

    fn selection_color(&self) -> Color {
        Color::from_rgb(0.8, 0.8, 1.0)
    }
}

Implementing StyleSheets would be way more easy. Changing the border_radius would now only require the following code:

impl StyleSheet for Styles {
    fn active(&self) -> Style {
        Style {
            border_radius: 0,
            ..Style::default()
        }
    }
}

Is there a reason why StyleSheets are implemented like this right now?

TimUntersberger avatar Mar 01 '21 11:03 TimUntersberger

I think it's a good idea.

Is there a reason why StyleSheets are implemented like this right now?

No particular reason. In fact, the button::StyleSheet trait already does it.

If anyone wants to give this a shot, feel free!

hecrj avatar Mar 02 '21 00:03 hecrj

I will open a PR for this later this week.

TimUntersberger avatar Mar 02 '21 19:03 TimUntersberger

How would you want to do default styles which can be extended?

What if any function that returns a Style receives the default style as argument?

TimUntersberger avatar Mar 04 '21 10:03 TimUntersberger

I don't think that is how button::Stylesheet does it. I'm not against different techniques though, why do you think that that would be better?

13r0ck avatar Mar 15 '21 19:03 13r0ck

I'm not against different techniques though, why do you think that that would be better?

If you are talking about my previous comment then because I don't know how to override the active style of a button for example without having to set each field.

Example:

impl button::StyleSheet for Style {
  fn active(&self) -> button::Style {
    // here I have to create the whole button::Style struct which requires me to know about the default values
  }
}

After thinking about this some more I discovered that button::Default exists. Maybe making the Default styles accessible to the users would we a solution?

Example:

impl button::StyleSheet for Style {
  fn active(&self) -> button::Style {
    let mut style = button::DefaultStyle.active(); // renamed to DefaultStyle for clarity
    // do something with style
    style
  }
}

TimUntersberger avatar Mar 15 '21 21:03 TimUntersberger

Maybe this is something that could be solved with code generation? Like from your first comment, you are basically setting what you want, then copying and pasting the rest from iced's source. Which code generation could totally do

Something like?

#[derive(Styles)]
impl StyleSheet for Styles {
    fn active(&self) -> Style {
        Style {
            border_radius: 0,
            ..Style::default()
        }
    }
}

13r0ck avatar Mar 16 '21 01:03 13r0ck

I created a draft PR which prototypes the idea I mentioned above using a button.

TimUntersberger avatar Mar 16 '21 12:03 TimUntersberger

@hecrj I think thi should be closed because of #1362, as #781 was for the same reason.

13r0ck avatar Sep 25 '22 13:09 13r0ck