Document Information

Last modified:
2007/05/31 18:39 by fjakobs

Appearance

qooxdoo comes with an advanced system that allows you to control the appearance of widgets. Learn here how to use this feature. For some more background information you might be interested why_we_use_appearance_instead_of_css.

Short overview

  • qooxdoo includes support for so-called appearance themes. Theses themes allow you to completely select the appearance of “all” widgets. It even supports switching the entire look of your application at runtime. To go further take a look at this article: Create a Custom Appearance
  • Each widget in qooxdoo has its own property “appearance”. This property corresponds to the appearance “id” of identical name in the appearance theme class. The values of this appearance property could for example be “checkbox”, “button”, “button-special”, ...
  • If you want to style a whole group of identical widgets (like some special buttons that look different than the regular buttons) the best would be to define your own widget class (e.g. “SpecialButton”) by deriving from the already existing class (e.g. “Button”) and change the appearance (e.g. to “button-special”) through a changeProperty call (which is preferred over using setApperance inside the constructor of the new class). Your appearance theme needs to have an entry for your custom widgets (e.g. “button-special”).
qx.OO.changeProperty({ name : "appearance", type : "string", defaultValue : "button-special" });

Included themes

qooxdoo currently includes one default appearance theme (Classic). This theme is responsible for the Microsoft Windows look of the qooxdoo examples.

It is important to note that qooxdoo widgets do not have to look like Windows controls at all. The styling of the widgets is independent from the class that defines a widget. Other appearance themes could provide a MacOS X user interface or even a traditional web page look that does not look like any native OS user interface. Such a custom appearance them could easily resemble your corporate design or the individual CDs of your clients.

To demonstrate the power and independence of the appearance themes, it would be great to include another theme into qooxdoo. It would be great if the community could contribute such a theme (like the already mentioned MacOS X theme).

You can find the appearance theme in the source distribution under the path: /qx/theme/appearance/Classic.js inside the framework source directory.

Adding new appearances

If you want to add new apperances to the default (or any other) theme please follow these steps:

Get the reference of the currently selected theme (AppearanceManager API):

theme = qx.manager.object.AppearanceManager.getInstance().getAppearanceTheme();

After this you can define new appearances in the same style as inside the theme file itself.

A typical theme entry looks like this (in this example for qx.ui.form.label):

theme.registerAppearance("label",
{
  setup : function()
  {
    this.color_disabled = new qx.renderer.color.ColorObject("graytext");
    this.font = new qx.renderer.font.Font(11, '"Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif');
  },
 
  initial : function(vTheme)
  {
    return {
      font: this.font,
      wrap : false
    };
  },
 
  state : function(vTheme, vStates)
  {
    return {
      color : vStates.disabled ? this.color_disabled : null
    };
  }
});

Basically you add a new javascript hash (the base javascript data object which consists of simple key-value pairs) named “label” in this case:

theme.registerAppearance(”label”, {});

This hash allows three keys:

  • setup: Setup of environment, create multiple-times used objects
  • initial: Initial appearance of the widget
  • state: State appearance of the widget

where each value is a function.

If you redefine an appearance using registerAppearance the apperance is not inherited from the default apperance. This is unlike the bahaviour of CSS rules.

Setup

setup is different from the others. It has no reference to the widget or even the theme. The setup method for each appearance will be executed on the first use of this appearance and not for each widget which uses it. This allows you to define complex objects only once and use them in multiple instances of widgets which use this appearance. For example you can create custom border styles or fonts there.

setup: function() 
{
  return 
  { 
    this.font = new qx.renderer.font.Font(11, "Verdana");
 
    this.border = new qx.renderer.border.Border(2, "outset");
    this.border.setBottomWidth(0);
  };
}

Initial and State

In the case of initial and state the functions should return a new hash, which defines the properties to setup with the corresponding values. In these two functions you have also references to the widget, to which the appearance will be applied, and the theme. The reference to the widget is can be useful to react on some property settings inside the widget.

The initial function should only apply the appearance settings which are completely independent of any state changes. I will give you a simple example:

initial: function(vTheme) 
{
  return 
  { 
    color : "red",
    width : 100,
    height : 100
  };
}

The state function instead should only define properties which change on some state change (for example over, selected, focused, ...). You get an additional (third) argument here. This is again a hash which has keys for each currently applied state. The value is always true. For example you can apply a mouseover effect for a widget using the following code:

state: function(vTheme, vStates) {
  return { backgroundColor : vStates.over ? "red" : null };
}

This makes the background of the widgets which use this appearance red if you move the mouse cursor over them.

Changing an existing appearance

Here is an example of changing the default appearance, so that the text field that has the focus shows a different background color:

function updateTheme() {
  var theme =  qx.manager.object.AppearanceManager.getInstance().getAppearanceTheme();
  var apar = theme.getAppearance('text-field');
  if (!apar) {
     return;
  }
  var backColorFocused = new qx.renderer.color.ColorObject("#EEF");
  var backColor = new qx.renderer.color.ColorObject("#FFF");
  var oldState = apar.state;
  apar.state = function(vTheme, vStates) {
    var res = oldState ? oldState.apply(this, arguments):{};
    if (vStates.focused) {
  	res.backgroundColor = this.backColorFocused;
    } else if (!res.backgroundColor) {
    	res.backgroundColor = this.backColor;
    }
    return res;
  }
}

Observe that we don’t need a setup function, because we use closures. The backColor object is created just once.

Possibilities

As we use JavaScript and not simple CSS, we can do all the fancy things we can do with JavaScript. You can combine different states, for example focused and mouseover together looks different from mouseover only.

Inheritance

We have also built in a way to inherit between different appearances. This inheritence is completely separated from the widget inheritance. For example you can inherit from the button appearance even for a completely different widget.

To load styles from another appearance you have the following methods inside your theme reference (given as vTheme in the above examples):

  • initialFrom: For getting the initial hash of another appearance
  • stateFrom: For getting the state hash of another appearance

These methods returns the return value of the inherited appearance. This is a simple hash as already explained before. You can merge this with local settings or simply return it.

  • Simple return
initial: function(vTheme) {
  return vTheme.initialFrom("label");
}
  • Return with local changes:
initial: function(vTheme) 
{
  var orig = vTheme.initialFrom("label");
  orig.backgroundColor = "red";
  return orig;
}
  • More compact (same result as above):
initial: function(vTheme) {
  return qx.lang.Object.mergeObjectWith(vTheme.initialFrom("label"), { backgroundColor : "red" });
}

qx.lang.Object.mergeObjectWith merges all keys of the second given object inside the first one. This means it does not create a new object, but modifies the first one and return this afterwards. The values of the second object have priority.

Information

Last modified:
2007/05/31 18:39 by fjakobs

Account

Not logged in

 
 

Job Offers

To further improve qooxdoo we are seeking javascript developers. Read more...

Rich Ajax Platform (RAP)

RAP uses qooxdoo, Java and the Eclipse development model to build rich web applications. Read more...

qooxdoo Web Toolkit (QWT)

Similar to GWT this framework allows to create impressive qooxdoo applications just using Java. Read more...

Pustefix

Pustefix is a MVC-based web application framework using Java and XML/XSLT. Read more...

 
SourceForge.net Logo

Bad Behavior has blocked 0 potential spam attempts in the last 7 days.