# Defining Visual Themes

## Overview

The 11g release of the IDE framework introduces a themes engine. The themes engine makes it easy to alter the color scheme and visual design of a product based on the IDE framework without editing code.

Editing and assembling a theme is very straightforward, and primarily involves modifying text and image files, and assembling them into a jar which can be deployed directly into a product based on the IDE framework.

The focus of this document is on theme providers - those who are defining the visual characteristics of the product by creating or modifying theme definitions. A separate document, Implementing Visual Themes is of interest to extension developers who want to use the theme engine to allow the visual design of their components to be customized. Note: this document is not yet available in the JDeveloper Technology Preview.

Note on Availability: The themes engine is not available in the version of the IDE framework used as the basis for Oracle SQL Developer 1.0 or 1.1. The earliest versions of Oracle products which support the themes engine are:

Product | Earliest Version Supported
--- | ---
JDeveloper | Oracle JDeveloper 11g Technology Preview (11.1.1)
SQL Developer | Oracle SQL Developer 2.0 (Not yet available)

You can determine whether a product based on the Oracle IDE Platform supports themes by looking for the directory `ide/themes` in its installation directory.

The theme engine and the syntax of themes.properties may undergo significant changes in the future as additional requirements evolve. There are therefore no guarantees that a theme which works in one version of an IDE-based product will continue to work in a future version of that product. Likewise, there's no guarantee that themes will be portable across products (e.g. that a theme for SQL Developer will work in JDeveloper).

## Anatomy of a Theme

A theme is defined in a file using the Java Properties syntax called `theme.properties`. The themes engine provides access to information in this file to extension writers and components in the core IDE platform, and this information is used to render the visual appearance of components.

Most of the property keys in `theme.properties` have a dot separated hierarchy. This section explains some of the keys which may be used in this file.

### Name

Every theme must have a `name` property, which defines the user-visible name of the theme as presented in the Themes drop down list on the Environment page in preferences. For example, here is a fragment from the fusion blue theme:

    name=Fusion Blue (Default)

Every theme should have a unique name.

### Color Scheme

A theme can control the look and feel color scheme used throughout the product by defining properties under the `colors` hierarchy.

The sub keys of `colors` correspond to values on the javax.swing.plaf.metal.MetalTheme API. You can take any method described in the javadoc for this class, remove the leading "get", convert the next letter to lowercase, and then use this as a subkey of `colors` to define that color value in the theme.

Here are some examples:

    colors.control=#a0a0a0
    colors.menuDisabledForeground=#505050

### Parts and States

Most of the properties in `theme.properties` are concerned with the visual appearance of parts. A part is an area of the user interface which has been exposed to the theme engine by the IDE platform or an extension writer.

The term "part" is deliberately used instead of "component", since component has a very specific meaning in Swing / AWT applications, and the theme engine does not necessarily require a one-to-one correspondence between parts and components. Sometimes, a single component may be made up of multiple parts from the point of view of the theme. A good example of this is a scrollbar, which is made up of several parts such as the track, the thumb, the gripper, and the scroll buttons.

Typically, the appearance of a part changes depending on some state that it has. For example, a button part might have a normal state, a disabled state, a mouseover state, and a pressed state. The themes engine doesn't define specific parts and states - it can flexibly support whatever parts and states are required by the implementation.

By convention, keys other than the color scheme and the name in `theme.properties` follow this pattern:

``

    part.state.propertyname

Here's an example which specifies that a part called `button` should be painted with a solid black background when disabled:

    button.disabled.bg.type=matte
    button.disabled.bg.color=#000000

## Painters

Painters are an important feature of the themes engine. Parts are often drawn using painters. Theme providers can customize the appearance of parts by describing which painters to use for parts in various states.

A painter is specified by setting the a `type` sub property to one of the six permitted types described in Painter Types. Many of the painters require additional subproperties that define how the painter operates.

This section describes each of the painters and the properties they require.

### Empty Painter (`empty`)

Required Properties:

None

Description:

The empty painter paints nothing at all. This can be useful when you want to make the background of a component invisible (transparent) in a particular state. A good example of this is a toolbar button when the mouse is not hovering over it.

Here's an example that sets the `bg` painter for the `normal` state of the `button` part to the empty painter:

    button.normal.bg.type=empty

### Centered Image Painter (`center`)

Required Properties:

Name | Type | Description
--- | --- | ---
`image` | ThemeImage | An image to paint

Description:

The `center` painter paints an image in the center of the part. It does not scale the image at all. If the image is larger than the current size of the part, then nothing is painted.

Example:

    button.normal.bg.type=center
    button.normal.bg.image=mybuttonimage.png

### Safely Stretched Image Painter (`stretch`)

Required Properties:

Name | Type | Description
--- | --- | ---
`image` | ThemeImage | An image to paint
`sizingmargin` | ThemeInsets | Describes the area of the image which may safely be stretched.

Description:

The `stretch` painter is a powerful painter that paints an image stretched to fit the area of the part. Rather than just crudely stretching the image uniformly across the whole area of the part, the `sizingmargin` insets are used to define the corners of the image (which are not stretched at all), and the top, left, bottom, and right edges (which are stretched only in one direction: horizontally for the top and bottom, and vertically for the left and right).

This stretching method allows the image to be scaled up to whatever size the part happens to be with a minimum of distortion.

The following diagram describes how to calculate the sizing margins for an image. Generally, it's advisable to make the sizing margins as small as possible while ensuring that they completely capture the corners which must not be resized.

Example:

    button.normal.bg.type=stretch
    button.normal.bg.image=mybuttonimage.png
    button.normal.bg.sizingmargin=2 2 2 2

### Gradient Painter (`gradient`)

Required Properties:

Name | Type | Description
--- | --- | ---
`startcolor` | ThemeColor | The start color for the gradient.
`endcolor` | ThemeColor | The end color for the gradient.
`direction` | ThemeDirection | The direction to paint the gradient (horizontal or vertical).

Description:

The `gradient` painter paints a linear gradient starting at the top of the part or the left of the part depending on whether the `direction` is `vertical` or `horizontal` respectively. The gradient will transition from the `startcolor` to the `endcolor`

Example:

    button.normal.bg.type=gradient
    button.normal.bg.startcolor=#ff0000
    button.normal.bg.endcolor=#ffffff
    button.normal.bg.direction=vertical

### Matte Painter (`matte`)

Required Properties:

Name | Type | Description
--- | --- | ---
`color` | ThemeColor | The fill color to use.

Description:

The `matte` painter fills the entire content area of the part with a single, solid color, defined by the `color` property value.

Example:

    button.normal.bg.type=matte
    button.normal.bg.color=#ff0000

### Edge Painter (`edge`)

Required Properties:

Name | Type | Description
--- | --- | ---
`image` | ThemeImage | The image to paint
`edge` | ThemeEdge | The edge of the part along which to stretch the painted image.

Description:

The `edge` painter draws an image along a single edge of the part, stretching it horizontally if the top or bottom edge is specified, or vertically if the left or right edge is specified.

Example:

    button.normal.bg.type=edge
    button.normal.bg.image=myimage.png
    button.normal.bg.edge=left

## Value Types

The themes engine recognizes several value types, which are particular expressions that can appear as the value of a property in `theme.properties`. The syntax of value types is described in this document using grammar notation similar to that introduced in §2.4 of the Java Language Specification.

### Colors

A ThemeColor value is specified as:

``

     LookAndFeelColorName:
           any symbolic color name in the look and feel UI defaults table
     ThemeColor:
           ui: LookAndFeelColorName
           DecodableString

Where DecodableString is defined in the javadoc for Integer.decode(String).

Some examples of valid color values are:

    # The color red
    firstcolor=#ff0000

    # Whatever the UI defaults table defines as the window background color ("window")
    secondcolor=ui:window

### Insets

A ThemeInsets value is specified as:

``

     Space:
          ' ' Spaceopt
     TopPixels:
          Digits
     LeftPixels:
          Digits
     BottomPixels:
          Digits
     RightPixels:
          Digits
     ThemeInsets:
          TopPixels
          TopPixels Space LeftPixels
          TopPixels Space LeftPixels Space BottomPixels
          TopPixels Space LeftPixels Space BottomPixels Space RightPixels

Where Digits is defined in §3.10.1 of the Java Language Specification.

Any omitted inset component is defaulted to 0.

Some examples of valid theme insets are:

    zeroinsets=0 0 0 0
    eveninsets=2 4 6 8
    twoabove=2

### Borders

A ThemeBorder value is specified as:

``

     BorderWidth:
           thin
           Digits px
     BorderStyle:
           solid
           none
           hidden
     BorderColor:
           DecodableString
     ThemeBorder:
           BorderWidth
           BorderWidth Space BorderStyle
           BorderWidth Space BorderStyle Space BorderColor

A `thin` BorderWidth is equivalent to `1px`, i.e. a one pixel thick border.

The default BorderStyle if not specified is `solid`. A `none` style border has no width (regardless of the BorderWidth value). A `hidden` style border reserves the space specified by BorderWidth, but is invisible (regardless of the color specified by the BorderColor value.

Some examples of valid borders are:

    # A simple 1 pixel wide black border
    firstborder=thin

    # A solid 5 pixel red border
    secondborder=5px solid #ff0000

    # An invisible 2 pixel border
    thirdborder=2px hidden

### Fonts

Unlike other properties in `theme.properties`, fonts are usually derived from existing fonts provided by the look and feel. Normatively, a derived font is specified by property keys which end with `font-weight` and `font-size`.

A ThemeFontWeight value is specified as:

``

     ThemeFontWeight:
           normal
           bold

A ThemeFontSize value is specified as:

``

     ThemeFontSize:
           Digits pt
           Digits %

A ThemeFontSize using a `pt` value specifies an exact point value to use for the font size.

The default values for these properties retain the existing weight and size of the base font.

By contrast a percentage value specified using `%` will derive the font size from the size of the original font. If the original font was 9pt, a derived font size specified as 150% would be 1.5 x 9pt = 13.5pt.

Some examples of valid font properties:

    # A bold font at 2pt.
    myfont.font-weight=bold
    myfont.font-size=12pt

    # A font at 50% of its base size, retaining the weight of the base font.
    myfont.font-size=50%

### Images

A ThemeImage value is specified as:

``

     ResourceChar:
           any character that is valid as a classpath resource name
     ResourceName:
           ResourceChar ResourceNameopt
     ThemeImage:
           ResourceName

A ThemeImage value specifies the location of an image file. The value is interpreted as a resource path. It is appended to a string containing the value of the global `imagebase` property and resolved using ClassLoader.getResource(String). Themes are loaded in a special classloading environment that does not necessarily have visibility to images outside the theme jar; see Classloading for details.

An example of a valid ThemeImage:

    mybackground=basic.png

### Direction

A ThemeDirection is specified as:

``

     ThemeDirection:
           horizontal
           vertical

The ThemeDirection type is currently used only by the gradient painter.

### Edge

A ThemeEdge is specified as:

``

     ThemeEdge:
           top
           left
           bottom
           right

The ThemeEdge type is currently used only by the edge painter.

### Painter Types

Painters describe compound operations that are used to graphically render a component. The themes engine defines several painter types. See Painters for more information.

A ThemePainterType is specified as:

``

     ThemePainterType:
           empty
           stretch
           center
           gradient
           matte
           edge

## Assembly and Deployment

A theme is packaged as a jar file with a simple structure. The `theme.properties` file must be located within the `META-INF` directory of the jar. The jar should contain any image resources referenced by image property values in `theme.properties`.

Here is an example of the contents of a simple theme jar:

    mytheme.jar/
    +- META-INF/
       +- theme.properties
    +- org/
       +- acme/
          +- images/
             +- tb.png
             +- cb.png

You can use the jar tool to assemble a theme jar as follows. First change into a directory matching the structure shown above for the contents of the theme jar, then type:

    jar cf mytheme.jar *

To deploy a theme, simply copy the theme jar into the `ide/themes` directory of a supported product. The theme will appear on the Environment page in Tools-Preferences after you restart the product.

## Classloading

When the IDE starts, it will look for a jar file in `ide/themes` corresponding to the currently selected theme. The IDE stores the name of the theme jar in persistent preferences (so it's a good idea not to rename a theme once it has shipped). If it successfully locates the theme, it creates an isolated classloading environment containing just that single theme jar, then loads the theme properties file and initializes the look and feel of the product based on that theme.

The ide will also scan the other jar files in the `ide/themes` directory in order to populate the "Theme" drop down list on the Environment page in Tools->Preferences.

For theme writers, the primary repercussion of the way themes are loaded is that they cannot refer to images outside the theme jar. A theme jar must be completely self contained.

## The Fusion Blue Theme

JDeveloper 11g ships with a default theme called "Fusion Blue". The easiest way to start creating your own theme is to copy the contents of the Fusion Blue theme and customize it. You can use the jar tool or a zip utility such as WinZip to extract the contents of the theme jar, which can be found in `ide/themes/fusionblue.jar`. This jar contains all of the images and the `theme.properties` file used by JDeveloper 11g out of the box.

If you create a theme based on Fusion Blue, remember to change its name to something else.