aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.md
blob: 0ac7bec18a16a1b623ff670f36ba0f62fe9be552 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# Extending the file system explorer example

This tutorial shows how to extend the
[Filesystem Explorer Example](filesystemexplorer_example)
by adding a simple scheme manager. This feature will allow you to switch color
schemes during the application's runtime. The color schemes will be declared in
JSON format and made available through a custom Python-QML plugin.

![Extended Explorer GIF](resources/extendedexplorer.gif)

## Defining the color schemes

To define your color scheme, you can use the same color names as the original
example, so you don't have to rename every occurrence. The original colors are
defined in the `Colors.qml` file as follows:

```{literalinclude} resources/Colors.qml
---
language: QML
caption: true
linenos: true
lines: 7-22
---
```

The `schemes.json` file holds the color schemes. To start implementing this, you
can use the [Catppuccin](https://github.com/catppuccin/catppuccin) scheme.

```{literalinclude} schemes.json
---json
caption: true
linenos: true
start-at: "Catppuccin"
end-at: "},"
---
```

In addition to the "Catppuccin" color scheme, four other color schemes got
implemented: Nordic, One Dark, Gruvbox, and Solarized. However, feel free to get
creative and experiment with **your** schemes.

To define a new color scheme, copy the structure from above and provide your
color values

## Implement the scheme manager

After defining the color schemes, you can implement the actual scheme manager.
The manager will read the `schemes.json` file and provide QML bindings to switch
between schemes during runtime.

To implement the scheme manager, create a Python-QML plugin that exposes the
`SchemeManager` object to QML. This object will have methods to load the color
schemes from the `schemes.json` file and switch between them.

Create a new Python file called `schememanager.py` in your project directory. In
this file, define the **SchemeManager** class:

```{literalinclude} scheme_manager.py
---
language: python
caption: true
linenos: true
start-at: "QML_IMPORT_NAME"
end-at: "class SchemeManager"
---
```

To integrate smoothly into the already existing code, attach the SchemeManager
to the same QML module that's already present with
`QML_IMPORT_NAME = "FileSystemModule"`. Additionally, use the`@QmlNamedElement`
decorator to smoothly transition to using the custom plugin instead of the
`Colors.qml` file. With these changes, we can avoid editing all previous
assignments like:

```QML
import FileSystemModule
...
Rectangle {
    color: Colors.background
}
```

The constructor reads the `schemes.json` file once upon application start and
then calls the `setTheme` member function.

```{literalinclude} scheme_manager.py
---
language: python
caption: true
linenos: true
lines: 18-24
---
```

By adding the `SchemeManager` as a callable QML element named **Colors** to the
FileSystemModule, the class is now accessible in the code without the need to
import it each time or edit previous assignments. This, in turn, will streamline
the workflow.

After defining the schemes in the JSON format and making the `SchemeManager`
class a callable element from QML under the name **Colors**, there are two
remaining steps to fully integrate the new scheme manager in the example.

The **first step** is to create a function in the `SchemeManager` class that
loads a color scheme from the JSON file. The **second step** is to make the
individual colors available in QML with the *same name* as used before with the
syntax `Colors.<previousName>` as assignable properties.


```{literalinclude} scheme_manager.py
---
language: python
caption: true
linenos: true
lines: 26-31
---
```

The `setScheme` method is responsible for switching between color schemes. To
make this method accessible in QML, use the `@Slot(str)` decorator and specify
that it takes a string as its input parameter. In this method, we populate a
dictionary with the color values from the JSON file.

> Note: For simplicity reasons no other error checking is performed.
> You would probably want to validate the keys contained in the json.

```{literalinclude} scheme_manager.py
---
language: python
caption: true
linenos: true
start-at: "@Property(QColor"
end-at: "return"
---
```

To make the color property assignable in QML, use the `@Property` decorator.
We simply return the corresponding color value from the dictionary for each
property. This process is repeated for all other colors that are used in the
application.
At this point the application should start with the colors provided by the
active scheme in the constructor.

## Add the scheme switching to QML

To visualize the current scheme and enable interactive scheme switching, start
by adding a new entry to the `Sidebar.qml` file.

```{literalinclude} FileSystemModule/qml/Sidebar.qml
---
language: QML
caption: true
linenos: true
lines: 99-105
---
```

To update the main content area of the application to display the `ColorScheme`,
the logic that checks the active index from the Sidebar buttons needs to be
modified. The necessary changes will be made to the Main.qml file:

```{literalinclude} FileSystemModule/Main.qml
---
language: QML
caption: true
linenos: true
lines: 170-187
---
```

In addition, change the behavior of the application so that there are two
`StackLayouts`: one for the resizable navigation and one for the main content
area where we display our color scheme switching functionality. These changes
will also be made to the Main.qml file.

```{literalinclude} FileSystemModule/Main.qml
---
language: QML
caption: true
linenos: true
lines: 147-150
---
```

To complete our implementation, the `ColorScheme.qml` file needs to be created.
The implementation is straightforward and follows the same principles as in the
original example. If anything is unclear, please refer to the documentation
provided there. To display all colors and scheme names, use a `Repeater`. The
model for the Repeater is provided by our `scheme_manager.py`file as a
`QStringList`.

```{literalinclude} FileSystemModule/qml/ColorScheme.qml
---
language: QML
caption: true
linenos: true
lines: 97-111
---
```

When examining the code in more detail, you will notice that there are different
ways to retrieve the models. The `getKeys()` method is defined as a **Slot** and
therefore requires parentheses when called. On the other hand, the `currentColors`
model is defined as a **property** and is therefore assigned as a property in QML.
The reason for this is to receive notifications when the color scheme is switched
so that the colors displayed in the application can be updated. The keys for the
color schemes are loaded only once at application startup and do not rely on any
notifications.

![Extended Explorer GIF](resources/colorscheme.png)