Proposal for a Theme manager #691

Open
tito opened this Issue Sep 19, 2012 · 15 comments

Projects

None yet

8 participants

@tito
Member
tito commented Sep 19, 2012

On each release, we try to have generic Kv rules that use properties for expressing the theming.
I'm thinking from a long time about how theming could be configurable.

Proposal A: theme property in Widget + ThemeManager

The theme property would contain the name of a theme referenced by a ThemeManager. Then, instead of writing the default value manually, we could write in kv, and use the self.theme to get the theme name. Ie:

<Button>:
    background_normal: 'atlas://data/themes/%s/button-normal' % self.theme

Pro:

  • theme can be different per-widget
  • dynamic changes possible

Cons:

  • no custom kv

Proposal B: ThemeManager + kv + defaultvalues

I think that we could have a "theme" by giving the possibility to load a different set of default values, such as:

{
    'kivy.uix.widget.Widget': {
        'size': ('72pt', '72pt')
    },
    'kivy.uix.label.Label': {
        'font_size': '11pt'
    },
    'kivy.uix.button.Button': {
        'background_normal': 'mycustombutton.png'
    }
}

Plus, with the combinaison of the kv, you could specify a different font size for label or button (something you cannot do by changing just the defaultvalue, because it's shared between thoses 2 widgets).

The Kv could be generated automatically if the property we try to change in the json doesn't exist on the target class (like font_size on Button).

On the usage, i see:

  • a new theme property in the App
  • the App will automatically set the theme on ThemeManager
  • ThemeManager will load and apply default values on current widgets.
  • You can switch to another theme with ThemeManager.set('othertheme').
  • Themes would be stored in a specific directory.

Pro:

  • using defaultvalue is native, and doesn't require more processing
  • generating kv for property not owned by the class of the rule is good.

Cons:

  • no dynamic theme changes
  • manual theme switch

My thoughts

I'm in favor of proposal B. But i'm open to others solution.

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@tito tito was assigned Sep 19, 2012
@hansent
Contributor
hansent commented Sep 19, 2012

I think more the problem is that in the default kv, we dont have all resources cvonfigurable. e.g. look at Slider / Progress Bar:

<Slider>:
    canvas:
        Color:
            rgb: 1, 1, 1
        BorderImage:
            border: (0, 18, 0, 18) if self.orientation == 'horizontal' else (18, 0, 18, 0)
            pos: (self.x, self.center_y - 18) if self.orientation == 'horizontal' else (self.center_x - 18, self.y)
            size: (self.width, 37) if self.orientation == 'horizontal' else (37, self.height)
            source: 'atlas://data/images/defaulttheme/slider%s_background' % self.orientation[0]
        Rectangle:
            pos: (self.value_pos[0] - 16, self.center_y - 17) if self.orientation == 'horizontal' else (self.center_x - 16, self.value_pos[1] - 16)
            size: (32, 32)
            source: 'atlas://data/images/defaulttheme/slider_cursor'

<ProgressBar>:
    canvas:
        Color:
            rgb: 1, 1, 1
        BorderImage:
            border: (12, 12, 12, 12)
            pos: self.x, self.center_y - 12
            size: self.width, 24
            source: 'atlas://data/images/defaulttheme/progressbar_background'
        BorderImage:
            border: [int(min(self.width * (self.value / float(self.max)), 12))] * 4
            pos: self.x, self.center_y - 12
            size: self.width * (self.value / float(self.max)), 24
            source: 'atlas://data/images/defaulttheme/progressbar'

no way to change appearance without, completely overwriting canvas rule.

@hansent
Contributor
hansent commented Sep 19, 2012

Otherwise I aggree on second part...but why make it json, instead of just another KV to load?
we can install default style.kv into ~/.kivy/themes/default.kv which will be loaded by default, then user can have multiple kv files in this directory also and either load at start/runtime or whatever, or switch global theme on install by changing/symlinking .kivy/themes/default.kv to other theme file...

its just a matter of which file Builder loads as default right?

@tito
Member
tito commented Sep 19, 2012

Yes, few widget still need to have their theming exported into property.
About using Kv, you still have default value from Kivy, and then, you'll have more processing: if you change the default font_size of a Label, it's one rule that will be applied everytime a Label, Button etc.. is created. Plus the parsing from the start :/

Plus, you never really know that's the real default value, because it will be changed at each instance done. You might also have issue at initialization (like if you have a first rule that use self.font_size, it will be used. Then when the next rule is applied and change the font_size too, the associated callback will be called again) -> that can be avoided if the defaultvalue is good from the start.

That's why i wanted to seperate both.

@hansent
Contributor
hansent commented Sep 19, 2012

right, but anyway it will always load at least one default kv (right now data/style.kv) right? why not just make this the theme file and expose all settings via it. it's just a matter of user knowing where to look to change the values no?

if you want all image names, colors etc in one place, we can just use #set default_button_background_image "/atals/..." at the top of the file?

if you want to have default values to save performance..we can cache it in json like you suggest easily after processing kv once no? Just nbot sure about having seperate theme files in different format...users will be confused on how to change widget looks...whats theme vs widget style, rule etc...

@tito
Member
tito commented Sep 19, 2012

But if you do that, you loose the ability to have different themes right ?

@hansent
Contributor
hansent commented Sep 19, 2012

what do you mean no ability to have different theme? theme != default kv ?

@hansent
Contributor
hansent commented Sep 19, 2012

you mean individual application have different themes? can still be env var, command line option, or function call before builder is initialized?

@akshayaurora
Member

Using different style.kv for custtom themes sounds interesting and a straight forward approach to global themes.This would also give the user more control and be simple and intuitive.

As for individual app themes, maybe we could lookup app_dir/data/style.kv before loading kivy_install_dir/kivy/data/style.kv?

Not really sure I understand the propasal B clearly though.

@tito
Member
tito commented Oct 2, 2012

Mostly, the B approach involve the changes of default values of widget properties.
For example, if you want to change the background_normal + border in Button:

  • With Kv: you'll create a new rule that will be applied for each new Button + the rule will trigger properties callback if exist, because the value you're assigning is not the same as the default value
  • With default values: no rule need to be applied, and because it's now the default value, nothing need to be done.

Maybe we could create a type of rule for the "defaults" ? But it seem weird.

@CreamyCookie
Contributor

What about convention over configuration? If you don't have a 'theme' folder with 'theme.kv' and 'theme.atlas' in your main project directory, the default theme will be loaded from the installation directory. Otherwise the custom theme will be loaded from the 'theme' folder.

@tshirtman
Member

I like the convention over configuration approach, but what if you want to have different themes, and switching them, like gtk/qt themes, would kivy be able to do such thing? would we be able to provide a subset of rule that it's safe to redefine and not break existing applications?

@CreamyCookie
Contributor

We could allow for multiple themes by creating sub-directories in the 'theme' folder. (If there are none, the theme will be loaded normally from there.) Let's say we have the following:

  • main.py
  • theme/
    • 1/
      • theme.kv
      • theme.png
      • theme.atlas
    • 2/
      • theme.kv
      • theme.png
      • theme.atlas

If that's the case we either automatically load the theme which is returned by sorted(theme_subdirs)[0] when no theme configuration is set OR if the new configuration option "kivy:theme_dir: string" is set, we load the theme from the specified directory.

You'd also be able to change to a different theme while the application is running by calling "Builder.load_theme_from()".

^ I don't think this would break existing applications. Although it's a rough draft. What do you think?

>>> sorted(['2_nuts', '0_pretty', '1_cookie'])[0]
'0_pretty'
@Kovak
Contributor
Kovak commented Jun 11, 2013

It'd be nice to have the option to turn off the image based theme entirely. Often times, I end up loading an empty image into a subclass of button and then defining the style of my UI entirely with canvas drawing commands.

It'd be nice if I didn't have to load an image in for my buttons at all. Using canvas commands it becomes much easier to achieve a variety of button shapes and styles out of the box. Right now kivy will not allow background_normal or background_down on button to be None, which means that an empty 1 pixel image must be loaded.

uiexample1
uiexample2

@tito
Member
tito commented Jun 11, 2013

@Kovak If you set the background_normal/down to '', there is no 1px image loaded, the default texture (white square) will be binded instead... if you use the default rule. If not, nothing will be done.

@kuldeepdhaka

regarding default themes,
they can be sub divided into platform specific.
like, on android, the button looks more like android, and
on ios, it could give a more look and feel like ios.

usefulness:
on Desktop with mouse, buttons dont need to be that much large (compared to touchscreen's). so space can be utilized more efficiently.

@dessant dessant modified the milestone: 2.0, 2.0.0 Jan 7, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment