Skip to content
Jonathan Eiten edited this page May 16, 2018 · 9 revisions

ToDo: Finish the Creating a custom theme section.

This wiki discusses grid themes (or "skins"):

  • Applying a theme to a Hypergrid instance
  • Removing a theme
  • Applying a global theme to all instances
  • Removing the global theme
  • Registering themes — so they can be referenced by name
  • Persisting themes — so they can be saved and reloaded later

Advisory: A good understanding of the Hypergrid properties collection objects and the properties stack helps in understanding how themes work. The reader is urged to give the Grid Properties wiki a thorough read before proceeding!

What is a theme?

A theme object is a Hypergrid properties collection object, containing look & feel (or "LnF") properties that give the grid a particular appearance, such as halign, color, etc.

Themes should only contain look and feel properties. The following pseudo-properties are specifically ignored if they are included: cells, columnIndexes, columnNames, columns, features, gridRenderer, rows, subgrids, and theme itself (a theme cannot specify a theme).

Themes are applied by copying the properties of a theme object to the grid.theme "layer" of the _properties stack using the grid.applyTheme() method. The Hypergrid.defaults layer also serves as a global theme layer, set using the Hypergrid.applyTheme() function.

Properties of the theme layers are only visible when not masked by properties with the same names in upper layers. To expose a property in a theme layer (for example the grid.theme layer) that is being masked by a property of the same name in an upper layer (for example the grid.properties layer), remove the property from that specific upper layer. The delete operator won't work on certain properties of the grid.properties layer which are accessors (getters/setters). Instead, use the .properties.delete(propName) method. For example, because backgroundColor is not an accessor, grid.properties.delete('backgroundColor') is the same as delete grid.properties.backgroundColor. However, because gridRendereris a (non-configurable) accessor,delete grid.properties.gridRendererwould not work and you would have to use thedelete(propName)method. Rather than concerning yourself about which properties are accessors and when to use the method instead of the operator, it is easier to just _always_ use the method, which is available in allproperties` collections (as of Hypergrid 3.0.0).

The grid theme

Themes can be applied to grid instances at any time.

Given a grid instance:

var grid = new Hypergrid;

And a theme object:

var themeObject = {
    backgroundColor: 'black',
    color: 'lime'
};

The grid.applyTheme() grid method applies the theme to the grid. This method copies properties from the given themeObject to the permanent grid.theme layer.

grid.applyTheme(themeObject);
// or:
grid.theme = themeObject; // as of Hypergrid 3.0.0 you can also use this setter

The grid.properties.theme is another setter that invokes applyTheme(). This setter facilitates specifying theme in a grid state object (see Persisting Grid State) so a theme can be loaded along with the rest of the grid state properties. See below, Loading & Saving Themes.

To remove a theme from a grid instance:

grid.applyTheme(null); // you an also pass `{}` or `undefined` or nothing
// or:
grid.theme = null; // as of 3.0.0

The global theme

To set the global theme:

Hypergrid.applyTheme(themeObject);
// or:
Hypergrid.theme = themeObject;

This method copies properties from the given themeObject to the Hypergrid.defaults layer.

The global theme affects all grid instances on the page. Per the Grid Properties wiki, the global theme "layer" exists below the grid instance's theme layer, the properties of which will override those of the global theme.

To remove the global theme from all instances:

Hypergrid.applyTheme(null); // you an also pass `{}` or `undefined` or nothing
// or:
Hypergrid.theme = null; // as of 3.0.0

Under the covers, this just reapplies the 'default' theme to the defaults layer (a copy of the original defaults), thereby restoring it to its original state.

Naming themes

Themes can be named or anonymous. Embedding a name in a theme definition makes the theme easily identifiable later on:

themeObject.themeName = 'bob';
console.log('Current theme is', grid.theme.themeName); // logs: "Current theme is bob"

Registered themes

As of Hypergrid v2.0.0, themes can be "registered" and thereafter referred to by name. This facilitates easily switching among a set of predefined themes. As of Hypergrid v3.0.0, themes can also be unregistered.

Registering themes

There is a single global theme registry, set with Hypergrid.registerTheme and Hypergrid.registerThemes; and accessible to all grid instances via grid.applyTheme(themeName) and globally via Hypergrid.applyTheme(themeName).

To register a theme:

Hypergrid.registerTheme(themeObject); // `themeName` property required
// or:
Hypergrid.registerTheme(themeName, themeObject); // `themeName` param overrides `themeName` property

To register a whole collection of themes all at once:

Hypergrid.registerThemes(themeObjectsCollection); // collection keys override `themeName` properties

This makes registering a theme library trivial:

Hypergrid.registerThemes(require('./my-theme-library'));

Note that grids are unaffected when a currently applied theme is re-registered with a new theme object.

Unregistering themes

As of Hypergrid 3.0.0, themes can be unregistered.

To unregister a theme, use one of the following overloads of registerTheme:

Hypergrid.registerTheme(themeName); // as of 3.0.0

To unregister all themes:

Hypergrid.registerThemes(); // as of 3.0.0

Note that grids are unaffected when a currently applied theme is unregistered.

Applying named themes

Named themes are applied by applyTheme similarly to the way explicit theme objects were, except now we provide a theme name rather than an theme object:

grid.applyTheme(themeName); // string overload
// or:
grid.theme = themeName; // as of 3.0.0
// or:
grid.properties.theme = themeName;

To apply a registered them as the global theme:

Hypergrid.applyTheme(themeName);
// or:
Hypergrid.theme = themeName`

Note that any reference to a theme by name requires it to have been previously registered.

Determining the currently applied theme

Use gird.properties.themeName to determine what theme is currently applied. This will be one of:

  • When an instance theme is applied:
    • The theme name when known
    • Else undefined for anonymous themes (applied using the applyTheme(object) overload; registered themes cannot be anonymous)
  • Else, when a global theme is applied:
    • The global theme's name when known
    • Else undefined for an anonymous global theme
  • Else, when neither an instance theme nor a global them are applied: 'default'

Note that grid.properties.theme will generally also return the theme name, although it differs subtly from grid.theme.themeName in that it will never return 'default'; and when the applied theme is not a registered theme, it will return the theme object itself. The reason for this is that this property is engineered for persisting state. Specifically, it returns:

  1. undefined when theme is undefined (excluded entirely by JSON.stringify)
  2. Else, the theme name when the theme is registered; or
  3. Else, the theme object when the theme is unregistered.

If it is the theme name that is persisted, it is the application developer's responsibility to make sure the required themes are properly registered before the state is reloaded later.

Loading & Saving Themes

The theme grid property contains the currently applied theme. This will be:

  • A theme object for an anonymous or unregistered theme; or
  • A theme name (string) for a registered theme.

Therefore, an applied theme will be output with the grid state object (see grid.saveState()). It is not necessary to call applyTheme to load a theme with the rest of grid state,

var stateObject = {
    ..., // other properties
    theme: myTheme
};
var grid = new Hypergrid({ state: stateObject }); // either at grid instantiation
grid.loadState(stateObject); // or later, after instantiation

Creating a custom theme

[ This section needs to be finished. ]