Skip to main content

How styling works?

There are two parts to styling.

  1. Layout
  2. Painting : Colors, text color, etc

Painting

The regular styles such as text color, font-size, font weight etc are achieved using Qt's stylesheet. We just call Qt's setStyleSheet method on the native widget and pass in the styles as a string.

This method is implemented as part of QWIDGET_WRAPPED_METHODS_DECLARATION in qwidget_macro.h. So all widgets using this macro will get the setStyleSheet method.

Layout

Layouting is basically positioning widgets on the screen. It takes into account everything from margins, paddings, positions etc. Our main focus will be Flex layouting. For flex layout we are using yoga library from facebook. This is the same library used by React Native. Before looking at flaxlayout in this libarary I recommend browsing Yoga's C API doc here: deps/yoga/doc.md

In case nodegui. I have implemented a custom Qt layout by extending QLayout, hence Qt is able to take over automagically when window is resized or any other layouting event occurs. You can find the implementation at src/cpp/core/FlexLayout/flexlayout.h.

The c++ api provided by this custom layout looks like this:

    // FlexLayout is a custom Layout built for QT. This layout will be used to layout qt widgets using facebook's yoga library.
// Thus giving ability to layout Qt Widgets using Flexbox.
// Usage:
QWidget *container = new QWidget();
YGNodeRef root = YGNodeNew();
YGNodeRef child1 = YGNodeNew();
YGNodeRef child2 = YGNodeNew();
FlexLayout * flayout = new FlexLayout(container,root);
// or FlexLayout * flayout = new FlexLayout(container);
// or FlexLayout *flayout = new FlexLayout();

flayout->addWidget(btn1, child1);
flayout->addWidget(btn2, child2);

This layout is exported to Javascript side via src/cpp/core/FlexLayout/flexlayout_wrap.h

The JS Api looks like this:

const view = new QWidget(rootView);

const flayout = new FlexLayout(); // Create layout
flayout.setFlexNode(view.getFlexNode()); // Set widget's flex as layout's flex node.

view.setLayout(flayout); // set layout as view's layout

const label = new QLabel(view);
label.setText("Hello12321");

const label2 = new QLabel(view);
label2.setText("SECOND LABEL");

flayout.addWidget(label2, label2.getFlexNode()); // Add child to layout
flayout.addWidget(label, label.getFlexNode()); // Add child to layout

Implementation

  1. Every widget that wants to use flex layout should extend from flexItem found at src/cpp/core/FlexLayout/flexitem.h. For example, see nlabel.h at src/cpp/QtWidgets/QLabel/nlabel.h

    NLabel inherits from NodeWidget which inherits from YogaWidget which inturn inherits from FlexItem

    • FlexItem adds a YogaNode to every widget.
    • YogaWidget adds Yoga specific q-properties to the widget, which is useful to assign yoga properties via qstylesheet. More on this below.
    • NodeWidget adds layout support via YogaWidget and event handling support via EventWidget

FlexItem

FlexItem : src/cpp/core/FlexLayout/flexitem.h add flexnode to each widget. FlexItem adds methods like getFlexNode.

YogaWidget

Qt StyleSheet allows you to specify style properties just like in web. You could specify font-size, margin, padding, etc. Qt StyleSheet also allows custom style properties via Qt's q-property system.

So in order to enable yoga based properties like alignItems, justifyContent, flex, etc via qt's stylesheet we declare and define q properties for each of those custom properties we want. This allows us to use something like:

view.setStyleSheet(`
background-color:green;
qproperty-flex: 1;
qproperty-alignItems: 'center';
`);

Notice qproperty- prefix? These are the custom q-properties we defined in YogaWidget.h. We do not need to prefix qproperty- if a stylehsheet string is passed through StyleSheet.create(). StyleSheet.create has an autoprefixer which will do the right thing.

NodeWidget

Every widget we implement should inherit from NodeWidget. This helps us add all the properties we want in the widgets via a single class. NodeWidget is the class that contains properties and methods shared by all widgets. This class allows us to add features to all widgets easily.