July 1, 2009

The new state system of EWL

Filed under: ewl — pfritz @ 23:04

Maybe you have already seen it, I started some weeks ago a branch for ewl in svn. Since the changes aren’t self explaining, I want to describe here how the new system works and also why it works that way.

The old system

Let’s start with some history about the old, but still current main trunk system. There are two different kinds of states:

  • One are for internal usage only. They are part of the Ewl_Flag enumeration and are set with macros like ewl_widget_state_add(). They are to keep track if a widget is pressed, has focus, etc.
  • The second kind is to keep the widget decoration informed about some evens. It is a tight wrapper around edje_object_signal_emit(). With “tight” I mean that it doesn’t provide any extra functionality besides that it can save one (and only one!) set state, so that the state will be applied if the widget is obscured and revealed again (this happens if the widget gets offscreen, or hidden for some time).

Losing states

This design has some flaws, because it ignores the fact that most ewl widgets are a composition of several widgets. For instance the label in a button need to know when the parent button container changes its appearance, in other words when it changes its state. On the first sight the solution seems to be obvious. Simply pass the state changes to the internal children.

But what happens if the label goes offscreen, but not the button? Or what happens if we create the label later than the button changed it theme? The label will not know about the state changes of the button. That means we need to keep track of all state changes so we can apply it to the children, when they are created or recreated. This list approach has also problems, for example if you apply “mouse,in”, you need to remove it from the list before you apply later “mouse,out”.

Having a state is different to getting a state

Another problem that exists with the current system is that we do not differ between retrieving a state and having a state. For example a themer might want to add a fancy animation when a checkbutton is checked, but on the other hand he maybe do not want an animation when the check is already applied, when the widget is new created or it is on-screen again. This issue is not inherent in the current system, and could probably also be solved in it. But it is something I had also in mind when I was going to switch to the new system.

The solution

I hope you understand now some of the issues that led me to change the current system. The first step is to remove the tight wrapping of edje_object_signal_emit(). I doubt it is possible to find a way that is not memory wasting and slow, but managed all the states in plain strings.

Like we already did it for the internal state management, states are now labeled by an enumeration. Every state in this enum reserves its own bit, so you can easily combine them with ORing. This atomatically solves the list problem. If the mouse enters the widget you simply add the EWL_STATE_MOUSE_IN bit and if the mouse later leaves you remove the state again.

Since old internal state keeping and the new state system works very similar, I simply merged them to one system, with the main difference that ewl_widget_state_add() will now inform the theme (actually the engine), that the state changed. If the widget isn’t already realized, the theme gets another information on realization, namely that the widget has this state. This solves the second problem.

The widget does not only save the directly applied states, but also the states that it inherits from the parent widget. Those are easily queried on realization and are kept up-to-date, if the state changes on the parent widget.

But the state enumeration is not enough. In some rare, but important cases, we still need custom states, that only makes sense for the given widget and are not general enough to be put into the enum. For those cases there is still a function that works as a tight wrapper around edje_object_signal_emit(). It is called ewl_widget_custom_state_set() and works like the old ewl_widget_state_set(), i.e. it does not inform the internal children about the change.

I hope I’ll write a second part of this blog discussing the changes from the view of a themer.

Blog at