https://github.com/fairybow/stylist
Stylist is a small, in-progress Qt C++ library adding an in-app system for live-styling QWidgets en masse.
https://github.com/fairybow/stylist
cpp cpp20 qss qt qt6 stylesheets
Last synced: about 2 months ago
JSON representation
Stylist is a small, in-progress Qt C++ library adding an in-app system for live-styling QWidgets en masse.
- Host: GitHub
- URL: https://github.com/fairybow/stylist
- Owner: fairybow
- License: gpl-3.0
- Created: 2024-12-01T18:57:00.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-03-08T16:42:26.000Z (over 1 year ago)
- Last Synced: 2025-03-08T17:28:39.859Z (over 1 year ago)
- Topics: cpp, cpp20, qss, qt, qt6, stylesheets
- Language: C++
- Homepage:
- Size: 9.32 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Stylist
Stylist is a small, in-progress Qt C++ library adding an in-app system for live-styling QWidgets en masse. It uses JSON-formatted themes compiled against template QSS sheets (variable replacement) and mass-applies the resulting QSS to user-defined widget type-groups.
A program using Stylist can give users a way to choose and customize themes without using QSS (on the user-side).
Stylist is being developed as a component of [Fernanda](https://github.com/fairybow/Fernanda).
## Usage
### Note
Stylist API functions follow this general format:
```cpp
m_stylist->setProperty("value");
auto value = m_stylist->property();
// If group was defined with the optional role parameter, it must be included:
m_stylist->setProperty("value", 1);
auto value = m_stylist->property(1);
// Or:
// m_stylist->setProperty(typeid(QWidgetT), "value");
// auto value = m_stylist->property(typeid(QWidgetT));
```
The type of widget is specified with `typeid(T)` or as a template parameter. The optional `role` parameter allows the creation of separate groups with the same type. So, a type-group is defined as `{ T, role = 0 }`.
### Include
```cpp
#include "Stylist/Stylist.h"
// To use the controller widget from Stylist's dialog (see below)
// #include "Stylist/Controller.h"
```
### Create Stylist and set it up to handle one or more types of QWidget
```cpp
Stylist* m_stylist = new Stylist(this);
```
(Stylist is a subclass of `QObject`.)
Define a type-group or -groups:
```cpp
m_stylist->setName("Windows");
m_stylist->setThemesTemplate(":/qrc/Window.stylist_template");
m_stylist->setThemesExtension(".window_theme");
m_stylist->setBaseQss(":/qrc/WindowBase.qss");
// Or:
// m_stylist->define(
// "Windows",
// ":/qrc/Window.stylist_template",
// ".window_theme",
// ":/qrc/WindowBase.qss");
```
Use `Stylist::setUseTheme(bool)` to toggle theme at runtime. When toggled off, only base QSS (or no QSS) will show.
### Add directories containing themes files with the pre-specified extension(s)
> [!IMPORTANT]
> Unique extensions are needed for each kind of theme.
```cpp
m_stylist->addThemesDirectory(":/qrc2/");
m_stylist->setCurrentTheme(":/qrc2/Dark.window_theme");
```
### Associate widgets with Stylist
"Yoking" (like with oxen) associates widgets with their pre-defined type-group or creates the group if it doesn't already exist.
```cpp
QTextEdit* MyMainWindow::newQTextEdit()
{
auto text_edit = new QTextEdit(this);
m_stylist->yoke(text_edit);
// Setup text edit...
return text_edit;
}
```
### Controlling Stylist
```cpp
// Open a dialog through Stylist:
m_stylist->showDialog();
// Or use Stylist::Controller to integrate the controls into something else:
// auto controller = new Stylist::Controller(m_stylist, this);
// window->setCentralWidget(controller);
```
A `Stylist::Controller` takes a required `Stylist` pointer on creation (and the usual optional `QWidget` parent pointer).
### Demo
See the [demo project](demo) for a more involved example.
## Adding Stylist to a project
Copy the `lib` and `include` folders to the target repo, and include `lib\Stylist.lib` in the compilation. Ensure `Stylist.dll` (in the `bin` folder) is also copied to the directory of the output `.exe`. Access via the `include\Stylist\Stylist.h` header.
## Limitations
### Qt style sheets
This tool is limited, of course, by any limitations of Qt Stylesheets. Of particular note, QWidgets will inherit style from their parents. For example, setting the following base QSS on a `QMainWindow` will also remove the `QSizeGrip` from its child windows:
```css
QSizeGrip
{
image: url(none);
}
```
### Widget Trees and Cascading
Stylist groups are effectively **widget trees**, not just flat collections. Because QSS cascades from parent to child, yoking a top-level window applies that group's styling to all of its descendants automatically. You don't need to yoke each child widget.
This means different top-level windows can belong to different groups, each with distinct styling for their child widgets:
```cpp
// Window A and its children get "Dark" styling
m_stylist->yoke(windowA);
m_stylist->setCurrentTheme("Dark.window_theme");
// Window B and its children get "Light" styling (different group via role)
m_stylist->yoke(windowB, 1);
m_stylist->setCurrentTheme("Light.window_theme", 1);
```
You can also create groups for specific widget types independent of their parent windows:
```cpp
m_stylist->define("Editors", ":/Editor.stylist_template", ".editor_theme");
m_stylist->yoke(someTextEdit);
```
**Caveat:** QSS cascading can cause conflicts. If a window group's QSS defines styles for `QTextEdit`, those rules may override styles from a separate `QTextEdit`-specific group, depending on selector specificity.