Using CSS Style Sheets on C++ Applications
February 8, 2022

Using CSS Style Sheets on C++ Applications

Coding Best Practices
Design

Using CSS style sheets, UI designers and developers have the power to easily brand and style their applications. 

Views Style Sheets, available as part of the Visualization C++ software, follow the HTML Cascading Style Sheets (CSS) standard. They provide an easy to use mechanism for customizing the appearance of the Views Gadgets, enabling you to style your C++ application the way you want it to look. 

This blog looks at two common applications:

Introduction to Style Sheets

Style sheets are simple text files that specify CSS directives to style Views 7.0 gadgets. Styles are defined by providing a CSS style sheet with directives on how to style gadgets in your Views 7.0 application. The following is a simple example of a CSS file that changes the background and foreground colors of an IlvButton.

IlvButton {
  color: blue;
  background-color: white;
}

Views 7.0 Style Sheets are much more powerful, flexible and easier to use than the previous way of overriding Views look and feel handlers through the IlvObjectLFHandler class.

Style sheets are managed by Views 7.0 stylist objects and are responsible for applying CSS styles to stylable objects, such as gadgets. Style sheets can be set for the entire Views 7.0 application or at the gadget level through the stylist used by the gadget. To set a style for the whole application, specify the style sheet to use on the global stylist managed by the Views 7.0 IlvDisplay. IlvDisplay directly inherits from IlvStylist and applies the stylist globally for all gadgets in the application. Each gadget also has access to a stylist which can be used to apply styling on the gadget level..

IlvHierarchicalSheet Example

This example shows how to quickly and easily modify the look and feel of an IlvHierarchicalSheet by changing the color for the expand button of the tree items from light blue to light green, simply by modifying the Views Style Sheet. No extra coding or recompiling is required to achieve this change in appearance. Only a single item in the associated Views Style Sheet needs to be changed.

The Views Style Sheet is loaded with the following code:

// Tell the display to load a stylesheet
std::ifstream css_sheet("ilvHierarchicalSheet.css");
display->addStyleSheet(css_sheet);

ilvHierarchicalSheet.cpp Source Code

#include <ilviews/css.h>
#include <ilviews/looks/css.h>
#include <ilviews/gadgets/gadcont.h>
#include <ilviews/gadgets/hsheet.h>
#include <ilviews/bitmaps/png.h>

#include <string>
#include <iostream>
#include <fstream>

// --------------------------------------------------------------------------
// Callback function for window exit events.
static void Quit(IlvView* view, IlAny)
{
    // Cleaning up the display.
    delete view->getDisplay();
    // Exiting the application.
    IlvExit(0);
}


// **************************************************************************
// Entry point
// **************************************************************************
int main(int argc, char* argv[])
{
    // Creating a new Views display object.
    // This is a connection between the Views framework and the operating system.
    IlvDisplay* display = new IlvDisplay("css_sample", "", argc, argv);

    // Checking if initialization succeeded, otherwise exiting gracefully.
    if (display->isBad()) {
        IlvFatalError("Can't open display...");
        delete display;
        return 1;
    }

    // Creating a view to house our gadgets.
    IlvGadgetContainer* container = new IlvGadgetContainer(
            display,                                 // The display object we created before.
            "IlvHierarchicalSheet_css_sample",       // The name for this instance.
            "IlvHierarchicalSheet CSS Sample",       // The title for the window.
            IlvRect(100, 100, 350, 500));            // The size and position for the window.

    // Tell the display to select CSS Look and Feel.
    display->setLookFeelHandler(display->getLookFeelHandler(IlGetSymbol(ILV_CSS_LFNAME)));
   
    // Tell the display to load a stylesheet
    std::ifstream css_sheet("ilvHierarchicalSheet.css");
    display->addStyleSheet(css_sheet);

    // Make window top bar close button work by adding a callback to handle exit events.
    container->setDestroyCallback(Quit);

    // Create an IlvHierarchicalSheet.
    IlvHierarchicalSheet* sheet = new IlvHierarchicalSheet(display,
                         IlvRect(50, 40, 250, 400),  // The size and place for the 
     // IlvHierarchicalSheet.
                         2,                          // Number of columns
                         0,                          // Initial number of rows. We will add 
     // rows later.
                         100,                        // Initial width of the grid cells.
                         22,                         // Height of the grid cells.
                         IlvDefaultGadgetThickness,  // Default thickness.
                         IlFalse, IlFalse);          // No scrollbars.

    // Automatic column size mode.
    sheet->autoFitToSize(IlTrue);

    // Allow to select whole row.
    sheet->setAutoLineSelect(IlTrue);

    // Allow to select only one row at a time.
    sheet->setExclusive(IlTrue);

    // Show the tree lines connecting items to their parents.
    sheet->showLines(IlTrue);

    // Enable grid.
    sheet->showGrid(IlTrue);

    // Default value of spacing is 1px. Set spacing to 0px. 
    sheet->setSpacing(0);

    // Adding header to "Property" column of the sheet.
    sheet->set(0, 0, new IlvLabelMatrixItem(display->getMessage("Property")));
    sheet->setItemRelief(0, 0, IlTrue);
    sheet->setItemReadOnly(0, 0, IlTrue);
    sheet->setItemSensitive(0, 0, IlFalse);
    sheet->setItemGrayed(0, 0, IlFalse);

    // Adding header to "Value" column of the sheet.
    sheet->set(1, 0, new IlvLabelMatrixItem(display->getMessage("Value")));
    sheet->setItemRelief(1, 0, IlTrue);
    sheet->setItemReadOnly(1, 0, IlTrue);
    sheet->setItemSensitive(1, 0, IlFalse);
    sheet->setItemGrayed(1, 0, IlFalse);

    // Creating tree nodes.
    IlvBitmap* img = display->getBitmap("icon/disk.png", true);

    IlvTreeGadgetItem* rootNode = new IlvTreeGadgetItem("Root node", img);

    IlvTreeGadgetItem* leaf1 = new IlvTreeGadgetItem("Leaf 1", img);
    IlvTreeGadgetItem* leaf2 = new IlvTreeGadgetItem("Leaf 2");
    IlvTreeGadgetItem* leaf3 = new IlvTreeGadgetItem("Leaf 3");

    IlvTreeGadgetItem* leaf11 = new IlvTreeGadgetItem("Leaf 11");
    IlvTreeGadgetItem* leaf12 = new IlvTreeGadgetItem("Leaf 12");
    IlvTreeGadgetItem* leaf13 = new IlvTreeGadgetItem("Leaf 13", img);
    IlvTreeGadgetItem* leaf14 = new IlvTreeGadgetItem("Leaf 14");

    IlvTreeGadgetItem* leaf131 = new IlvTreeGadgetItem("Leaf 131", img);
    IlvTreeGadgetItem* leaf1311 = new IlvTreeGadgetItem("Leaf 1311");

    // Adding tree nodes to sheet.
    sheet->addItem(0, rootNode);

    sheet->addItem(rootNode, leaf1);
    sheet->addItem(rootNode, leaf2);
    sheet->addItem(rootNode, leaf3);

    sheet->addItem(leaf1, leaf11);
    sheet->addItem(leaf1, leaf12);
    sheet->addItem(leaf1, leaf13);
    sheet->addItem(leaf1, leaf14);

    sheet->addItem(leaf13, leaf131);
    sheet->addItem(leaf131, leaf1311);

    sheet->shrinkItem(leaf13);
    sheet->shrinkItem(leaf131);

    // Adding nodes "Value" column of the sheet.
    for (int row = 1 ; row < sheet->rows(); row++) {
        sheet->set(1, row, new IlvIntMatrixItem(row*row));
    }

    // Add the sheet to the view.
    container->addObject(sheet);

    // Tell views to run the message loop.
    IlvMainLoop();

    return 0;
}

ilvHierarchicalSheet.css Views Style Sheet

/* Set border and background style for IlvHierarchicalSheet */
IlvHierarchicalSheet {
    Background-color: white;
    border: none;
}

/* 
 * Set border and background style for Content box of IlvHierarchicalSheet 
 * (The area where the sheet cells are drawn and displayed).
 */
IlvHierarchicalSheet > Content {
    background-color: white;
    border: none; 
}

/* 
* Set style for sheet items. Use *MatrixItem because IlvHierarchicalSheet is derived from IlvMatrix.
* Use IlvTreeGadgetItem for styling tree items. 
*/
IlvHierarchicalSheet > IlvIntMatrixItem, 
IlvHierarchicalSheet > IlvTreeGadgetItem,
IlvHierarchicalSheet > IlvLabelMatrixItem {
    color: black;
    background-color: white;
    border: none; 
}

IlvHierarchicalSheet > IlvIntMatrixItem:active,
IlvHierarchicalSheet > IlvTreeGadgetItem:active {
    color: white;
    background-color: lightblue;
}

/* 
*  Relief items (set with IlvHierarchicalSheet::setItemRelief) have a CSS class relief. 
*  Styling selected state is done with pseudoclass :active.  
*/
IlvHierarchicalSheet > IlvLabelMatrixItem.relief {
    border: 2px white outset;
    background-color: #f6f4e9;
}
/* Styling sheet grid line (if IlvHierarchicalSheet::showGrid is set to true) */
IlvHierarchicalSheet > Grid {
    border: 1px solid whitesmoke;
}

/* 
*  Style for the sheet items editors. 
*  This is an IlvTextField for editing table items.
*  This is an IlvEditItemView > IlvEditionTextField for editing tree items.
*/

IlvEditItemView {
    background-color: white;
    border: none;
}  

IlvEditItemView > IlvEditionTextField,
IlvHierarchicalSheet > IlvTextField{
    background-color: whitesmoke;
    color: black;
    border: 1px solid gray;
}

IlvEditItemView > IlvEditionTextField > Text,
IlvHierarchicalSheet > IlvTextField > Text{
    border: none;
}  

/* Style for the line drawn between tree items */
IlvHierarchicalSheet > Line {
    border: 1px solid gray;
}

/* Style for the expand button of tree item */
IlvHierarchicalSheet > Button {
    background-image: url(css/views/plus-sign9x9.png);
    background-position: center center;
    background-size: 100% 100%;
    width: 9px;
    height: 9px;
    background-color: LightBlue;
    border: 1px solid gray;
}

/* Style for the shrink button of tree item */
IlvHierarchicalSheet > Button:active {
    background-image: url(css/views/minus-sign9x9.png);
}

/* Style for relief lines */
IlvHierarchicalSheet > MatrixRelief,
IlvHierarchicalSheet > TitleRelief,
IlvHierarchicalSheet > RowRelief,
IlvHierarchicalSheet > ColumnRelief {
    border: none;
}

IlvHierarchicalSheet CSS Sample

IlvHierarchicalSheet CSS Sample 1

We can easily modify the look-and-feel to change the color of the expand button of the tree items from light blue to light green simply by modifying the Views Style Sheet as follows:

/* Style for the expand button of tree item */
IlvHierarchicalSheet > Button {
    background-image: url(css/views/plus-sign9x9.png);
    background-position: center center;
    background-size: 100% 100%;
    width: 9px;
    height: 9px;
    background-color: LightGreen;
    border: 1px solid gray;
}

The IlvHierarchicalSheet CSS Sample now looks like this:

IlvHierarchicalSheet CSS Sample 2

Calculator Application Example

This example uses a calculator application and 3 CSS style sheets to dynamically change the look and feel of the application while it is running.

IlvButton + IlvButton {
  color: blue;
  background-color: white;
}

Here is the callback function for the ilvToggle button we use to change the look and feel when Style Sheet 1 is selected:

static void styleSheet1CB(IlvGraphic* g, IlAny data)
{
    // Graphic is the callback originator
     // data is the pointer to any user set data
     // In this case it is an IlvGadgetContainer
    IlvGadgetContainer* container = static_cast<IlvGadgetContainer*>(data);

    // As a sample callback action, we change the window title.
    container->setTitle("Style Sheet 1");

    std::ifstream css_sheet("calc_stylesheet1.css");
    container->addStyleSheet(css_sheet);

    //refresh views to see stylesheet changes
    container->getDisplay()->refreshAllViews();
}

Calculator With No Style Sheet Applied

Calculator with No Styling CSS Style Sheet
IlvButton {
	color: black;
}

IlvNumberField {
	color: black;
}

IlvToggle{
		padding-left: 5px;
		background: #f0f0f0;
}

IlvToggle > CheckBox{
	border: 1px solid black;
	background: #f0f0f0;
	margin: 3px;
	margin-left: 80px;
	width: 12px;
	height: 12px;
}

IlvToggle:checked > CheckBox{
	background: black;
}

Calculator With Style Sheet 1 Applied

Calculator with Style Sheet 1 Applied
IlvButton {
	border: 2px solid black;
	color: blue;
}

IlvNumberField {
	border: 2px solid black;
	color: blue;
}

IlvToggle{
	padding-left: 5px;
	background: #f0f0f0;
}

IlvToggle > CheckBox{
	border: 1px solid black;
	background: #f0f0f0;
	margin: 3px;
	margin-left: 80px;
	width: 12px;
	height: 12px;
}

IlvToggle:checked > CheckBox{
	background: black;
}

Calculator With Style Sheet 2 Applied

Calculator with Style Sheet 2 Applied
IlvButton {
	border: 2px solid black;
	padding: 5px;
    margin: 1px;
	color: green;
	background-color: white;
}

IlvNumberField {
	border: 2px solid black;
	margin: 1px;
	color: green;
	background-color: white;
}

IlvToggle{
	padding-left: 5px;
	background: #f0f0f0;
}

IlvToggle > CheckBox{
	border: 1px solid black;
	background: #f0f0f0;
	margin: 3px;
	margin-left: 80px;
	width: 12px;
	height: 12px;
}

IlvToggle:checked > CheckBox{
	background: black;
}

Easily Update the Look and Feel of Your Application

The ability to utilize CSS style sheets to style your Views C++ application gives UI designer and developers the power to easily brand and style their applications. Switch between light and dark themes, add branding, and modernize the look and feel of applications quickly, allows teams to increase efficiency and time to market.

Interested in learning more about Visualization tools for your application development? 

Contact Us

More information: