2010
24
Dec

Style sheets

OK, here's the initial result of my attempt at introducing themeable widgets in Umbra.

I haven't done the style sheet exterenalisation yet (well, actually, I did, but rolled back because I'd spent three days debugging it and failed miserably - apparently it was better to rewrite the code), but it can be hard coded. Of course, this may (and probably will) change drastically over time, but at the moment each widget has a style sheet with three properties: colour, backgroundColour and borderColour. Each property comes in three variants, representing the state of the mouse cursor: normal, hover and active.

The properties are relatively easy to add since I used a template there, so if I need to add a new property, say, padding, all I need to do is to add this line to the style sheet definition:

UmbraStyleSheetProperty <int> padding;

Now, in order to set the padding value, I can simply use the = operator:

myWidget->style.normal.padding = 2;

And when I need to retrieve the value, I can call:

int padding = myWidget->style.normal.padding.value();

Setting the three available properties can also be done using methods, but I don't like to have so many and will probably get rid of them and adopt a more flexible approach, perhaps a single method that accepts the property name as a string. Since it might be necessary to set more than one value at the same time, I'll probably go with chaining too:

myWidget->style
    .set("colour",TCODColor::red)
    .set("colour:hover",TCODColor::lightRed)
    .set("backgroundColour:active",TCODColor::green);

Of course, this is just the beginning. Real fun will start when the style sheets are externalised so that they can be modified on the fly, without recompiling, and in a rather flexible way, drawing from CSS: using tags, classes and IDs (there are already placeholders for that :)).

Currently, the style sheet is hard coded for testing purposes:

UmbraStyleSheet::UmbraStyleSheet () {
    //placeholder --- hardcoded values
    colour(TCODColor::white, "normal");
    colour(TCODColor::lighterGrey, "hover");
    colour(TCODColor::yellow, "active");
    backgroundColour(TCODColor::darkerRed, "normal");
    backgroundColour(TCODColor::darkRed, "hover");
    backgroundColour(TCODColor::red, "active");
    borderColour(TCODColor::blue, "normal");
    borderColour(TCODColor::lightBlue, "hover");
    borderColour(TCODColor::lighterBlue, "active");
}

OK, I know, this is a horrible choice of colours. But the fun part is that this already works out of the box. Here are the three states of a button in Umbra demo:

By the way, merry Christmas!

Comments

Merry Christmas, Mingos

Merry Christmas, Mingos :)

This is really good coding style, I like it! The overloaded = operator is a neat shortcut, how about doing the same thing for getting the property? You could overload the () operator, making it like a "callable" object, then your getting code could be:

int padding = myWidget->style.normal.padding();

Oh... my... God... This is

Oh... my... God... This is brilliant! Why didn't I think about it earlier! Thanks, Jotaf, as always, you're a walking pool of great ideas :). Yes, I will overload the () operator, it seems intuitive to use ot directly on the style property as if it was a method :).