Nevron Open Vision Documentation
Custom Themes

NOV makes it easy to create custom UI themes based on any of the existing ones. This lets you quickly change the appearance of one or more widgets in order to make your application look exactly the way you like. This topic will teach you how to create a custom theme and how to modify different aspects of the theme and its skins.

Create Custom Theme

A UI theme contains a lot of CSS-like rules that shape the appearance of the UI widgets available in NOV applications. To avoid the complexity of declaring all of these rules yourself, it is best to base your custom theme on one of the predefined UI themes of NOV. For example, to create a custom UI theme that extends the NWindows8Theme you can use the following piece of code:

Create custom theme
Copy Code
public class CustomTheme : NWindows8Theme
{
}
Override Widget Styles

Once you have created your custom theme you can override any of its Create...Styles methods to modify the appearance of a specific widget or set of widgets. In these method overrides you will typically use the GetRule and GetSkin methods to modify the appearance of a specific state of a widget. You can also use the GetSkinner method if you need to modify all states of a widget.

The following example demonstrates how to make the border of text boxes - red:

Modify text boxes' border
Copy Code
protected override void CreateTextBoxStyles()
{
    base.CreateTextBoxStyles();

    // Make text boxes border red
    NThemeSkin skin = GetSkin(NTextBox.NTextBoxSchema);
    ThinBorder(skin, NColor.Red);
}

To modify the appearance of widgets inside other widget, you should make sure that you've built a proper selector that matches the widget hierarchy exactly. You can use any of the In...Context selector parts to built the selector. The following example demonstrates how to set a border to image boxes placed in buttons:

Modify nested widgets appearance
Copy Code
protected override void CreateButtonStyles()
{
    base.CreateButtonStyles();

    // Skin the image box of a button
    // An image box for buttons that have both image and text is usually placed in a
    // pair box and then in a button, so to match it we need the following selector
    // "image box -> in parent -> in button"
    NThemeRule rule = GetRule(NImageBox.NImageBoxSchema, InParentContext, InButtonBaseContext);
    ThinBorder(rule, Colors.ControlDark);

    // To skin image boxes for buttons that contain only an image, i.e. the image box is
    // placed directly in the button, we need the following selector:
    // "image box -> in button"
    rule = GetRule(NImageBox.NImageBoxSchema, InButtonBaseContext);
    ThinBorder(rule, Colors.ControlDark);
}

When modifying the appearance of the widgets you can use any color, but it's best to use colors from the Colors collection of the theme.
Custom States and Contexts

Sometimes the predefined selector parts (states and contexts) may not be enough to create the selector that you want. In such cases you can create your own custom states and contexts using the helper method that the NTheme base class provides, for example CreateState, CreateChildOfTypeContext, etc.

Imagine the following scenario: you use a lot of OK and Cancel buttons in different dialogs of your application and you want to make these buttons to stand out by making the OK button's background fill green and that of the Cancel button - red. To achieve this you need to set the WindowResult property of the buttons in your code first like this:

Create an OK and a Cancel button
Copy Code
NButton okButton = new NButton("OK");
okButton.WindowResult = ENWindowResult.OK;
stack.Add(okButton);

NButton cancelButton = new NButton("Cancel");
cancelButton.WindowResult = ENWindowResult.Cancel;
stack.Add(cancelButton);

You can then create custom states in your theme that match a specific value of the WindowResult property and then use these states to set a specific appearance to each button in the theme:

Create and use custom theme states
Copy Code
protected override void CreateButtonStyles()
{
    base.CreateButtonStyles();

    // Declare some custom theme states
    NThemingState okButtonState = CreateState(delegate (NSelectorBuilder sb) { sb.ValueEquals(NButton.WindowResultProperty, ENWindowResult.OK); });
    NThemingState cancelButtonState = CreateState(delegate (NSelectorBuilder sb) { sb.ValueEquals(NButton.WindowResultProperty, ENWindowResult.Cancel); });

            
    // Skin the OK button
    NThemeRule rule = GetRule(NButton.NButtonSchema, okButtonState);
    Background(rule, NColor.LightGreen);

    // Skin the Cancel button
    rule = GetRule(NButton.NButtonSchema, cancelButtonState);
    Background(rule, NColor.OrangeRed);
}
Custom Skins

In some cases you might want to modify the skin for a specific widget in order to alter it's appearance in one or more of its states. To do so, you should simply get a reference to and modify the skins you are interested in (for example in the constructor of your custom theme). You can also create and assign a completely new skin. The following code example demonstrates both of the methods on the skins of the left and right spinner glyphs:

Modify skins
Copy Code
internal class CustomTheme : NWindows8Theme
{
    public CustomTheme()
    {
        // Modify spinner arrow glyph skins
        //
        // Method 1: Recreate the whole skins for the glyphs
        //
        // The code below demonstrates the original settings for the spinner glyphs of the Windows 8 theme
        // Feel free to modify the symbol or the colors as you wish
        NSize arrowSize = new NSize(4, 7);

        // Left arrow
        NColorSkin skin = new NColorSkin(4);
        skin.SetState(Normal, NSymbol.Create(ENSymbolShape.TriangleLeft, arrowSize, new NColorFill(new NColor(49, 49, 49)), null));
        skin.SetState(MouseOver, NSymbol.Create(ENSymbolShape.TriangleLeft, arrowSize, new NColorFill(new NColor(0, 102, 204)), null));
        skin.SetState(Pressed, skin.GetState(Normal));
        skin.SetState(Disabled, NSymbol.Create(ENSymbolShape.TriangleLeft, arrowSize, new NColorFill(new NColor(20, 20, 20, 102)), null));
        Skins.SpinnerLeftGlyph = skin;

        // Right arrow
        skin = new NColorSkin(4);
        skin.SetState(Normal, NSymbol.Create(ENSymbolShape.TriangleRight, arrowSize, new NColorFill(new NColor(49, 49, 49)), null));
        skin.SetState(MouseOver, NSymbol.Create(ENSymbolShape.TriangleRight, arrowSize, new NColorFill(new NColor(0, 102, 204)), null));
        skin.SetState(Pressed, skin.GetState(Normal));
        skin.SetState(Disabled, NSymbol.Create(ENSymbolShape.TriangleRight, arrowSize, new NColorFill(new NColor(20, 20, 20, 102)), null));
        Skins.SpinnerRightGlyph = skin;

        //
        // Method 2: Modify only some of the states of the skins
        //
        // If you don't need to modify all states, you can simply get and modify only the states you wish like this:
        NColorSkinState state = (NColorSkinState)Skins.SpinnerRightGlyph.GetState(Normal);
        state.Symbol = NSymbol.Create(ENSymbolShape.TriangleRight, arrowSize, new NColorFill(new NColor(49, 49, 49)), null);
    }

    // The following constants are used for skin states
    private const int Normal = 0;
    private const int MouseOver = 1;
    private const int Pressed = 2;
    private const int Disabled = 3;
    private const int Focused = 4;
    private const int Checked = 4;
    private const int CheckedMouseOver = 5;
    private const int CheckedPressed = 6;
    private const int CheckedDisabled = 7;
}

You can also modify symbols of skins, for example, the code below demonstrates how to make the check box symbol an X instead of a check and how to make the radio button filled circle blue:

Modify symbols
Copy Code
internal class CustomTheme : NWindows8Theme
{
    protected override void CreateCheckBoxStyles()
    {
        // Modify the checked state symbol to x instead of check
        NColorSkinState checkedState = (NColorSkinState)Skins.CheckBox.GetState(Checked);
        NSize symbolSize = checkedState.Symbol.DesiredSize - new NSize(1, 1);
        checkedState.Symbol = NSymbol.Create(ENSymbolShape.StrokedX, symbolSize, Colors.ControlText);

        // Call base to skin check boxes
        base.CreateCheckBoxStyles();
    }

    protected override void CreateRadioButtonStyles()
    {
        // Modify the checked state of the radio button skin
        NColorSkinState checkedState = (NColorSkinState)Skins.RadioButton.GetState(Checked);
        NFillableSymbolShape symbolShape = (NFillableSymbolShape)checkedState.Symbol[0];
        symbolShape.Fill = new NColorFill(NColor.Blue);

        // Call base to skin radio buttons
        base.CreateRadioButtonStyles();
    }
}
The NOV Themes are available in FULL SOURCE CODE upon request. Please contact us at support@nevron.com if you would like to receive them. The easiest way to build a custom theme is to simply modify one of the existing ones.
See Also
Send Feedback