File: lomiri-theming.qdoc

package info (click to toggle)
lomiri-ui-toolkit 1.3.5110%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 26,436 kB
  • sloc: cpp: 85,830; python: 5,537; sh: 1,344; javascript: 919; ansic: 573; makefile: 204
file content (526 lines) | stat: -rw-r--r-- 23,870 bytes parent folder | download
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
/*
 * Copyright 2015 Canonical Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*!
 * \page lomiri-theming.html
 * \title Introduction
 * \nextpage Styles
 *
 * Table of contents:
 * \list
 * \li \l Introduction
 * \li \l Styles
 * \li \l Themes
 * \li \l Sub-theming
 * \endlist
 *
 * \section2 Introduction
 * The \l{Styles}{style} defines the visuals, the implicit size of the component and may provide
 * additional logic for a given component. Some components have fixed style API the
 * component relies on, and yet some others do not have any restriction on what the
 * style contains or does. Components relying on a well defined API provide these
 * interfaces through Lomiri.Components.Styles module, and styles must implement these
 * interfaces.
 *
 * The implicit size of a component is driven by the style as well, but it is not
 * mandatory for a style to provide those values, and components can override these
 * values at any time. However each style component is anchor filled to the styled
 * component and positioned to be under child components declared within the component
 * itself.
 *
 * Styles can be declared as Components (like delegates), in a separate document
 * loaded dynamically using a Loader or Qt.createComponent(), or can be grouped
 * in \l{Themes}{themes}. When declared in themes, with some exceptions, each component's style
 * document name is compound of the component name having the \e Style word as postfix,
 * followed by the typical QML file name extension. In this way the Button component's
 * style is ButtonStyle. In addition to styles, themes can also provide custom palette
 * values. There are two themes in Lomiri, Ambiance and SuruDark themes, Ambiance
 * being the default theme. Both themes are declared in separate modules, in \c
 * Lomiri.Components.Themes.Ambiance as well as \c Lomiri.Components.Themes.SuruDark.
 * Application should define the theme name using this dotted name format.
 *
 * Applications can decide which theme they want to use or they can provide their
 * own themes. Also, applications can use multiple themes or set custom palette values.
 *
 * \qml
 * import QtQuick 2.4
 * import Lomiri.Components 1.3
 *
 * MainView {
 *     width: units,gu(40)
 *     height: units.gu(71)
 *
 *     theme.name: "Lomiri.Components.Themes.SuruDark"
 * }
 * \endqml
 */

/*!
 * \page lomiri-theming-styles.html
 * \title Styles
 * \previouspage Introduction
 * \nextpage Themes
 * \contentspage {Introduction} {Contents}
 *
 * \section2 Naming conventions
 * With few exception, each toolkit component is having StyledItem as its base
 * component. The component is aimed to be the base component for all styled
 * elements in the toolkit. Modules providing additional components to UI Toolkit
 * can also use this component as base, especially if they want to provide styling
 * capabilities.
 *
 * As mentioned, each styled component is having a style pair in a theme which is
 * implemented in a document named using the component name adding the \e Style word.
 * The \l {Button}'s style is implemented by \c ButtonStyle.qml document in the theme, and
 * \l Button is loading this style from the theme:
 * \qml
 * import QtQuick 2.4
 * import Lomiri.Components 1.3
 *
 * AbstractButton {
 *     id: button
 *     // [...]
 *     styleName: "ButtonStyle"
 * }
 * \endqml
 * Developers can override the style in two ways, depending on how they want to style
 * the component:
 * \list
 *  \li 1. by overriding the style using an other style component from the theme, or
 *  \li 2. by overriding the style with a custom style component.
 * \endlist
 * But let's see first how the styles are implemented.
 *
 * \section2 Creating styles
 * As mentioned before, styles are not restricted to only provide visuals to a component or
 * set of components, but can have also logic which drives the component functionality.
 * These kind of styles must implement the given component's style API, listed in
 * \c Lomiri.Components.Styles module.
 *
 * A good example of such a style is the ListItemStyle. The ListItem drives the style
 * animation through the \l ListItemStyle::animatePanels property, value being false when
 * the style is loaded during component creation, i.e. when the component requires some
 * visuals to be present at creation time. Also, ListItem informs the style when to
 * execute leading or trailing panel \l {ListItemStyle::rebound}{rebound}s and provides
 * the style the ability to overrule the \l {ListItemStyle::swipeEvent}{swipe} coordinates
 * calculated by the ListItem. On the other hand, the style must inform the component
 * about the position of the \l {ListItemStyle::dragPanel}{drag panel} so the dragging
 * (reordering of list items in a ListView) hot spot can be detected. A style implementation
 * must use the API provided by ListItemStyle, otherwise ListItem will fail to function
 * properly.
 *
 * Other styles are requested to provide additional \e content elements, which are then
 * positioned by the styled component separately from the main visuals given by the style.
 * A typical example of such a style API is the PullToRefresh component's style:
 * \snippet Styles/1.2/PullToRefreshStyle.qml 0
 * The default style implementation can be found under Lomiri.Components.Themes.Ambiance
 * theme \l {https://gitlab.com/ubports/development/core/lomiri-ui-toolkit/-/blob/main/src/imports/Components/Themes/Ambiance/1.3/PullToRefreshStyle.qml}
 * {src/imports/Components/Themes/Ambiance/1.3/PullToRefreshStyle.qml}.
 *
 * Beside these, component styles may provide default values for colors, fonts, widths,
 * margins, thicknesses.
 *
 * Each style component has a \c styledItem context property defined by the StyledItem,
 * which points to the StyledItem instance that uses the style. Style implementations can
 * access the actual styled item through this property.
 *
 * \section2 Overriding the default component style
 *
 * \section3 Override with a different style from the theme
 * Returning back to the ways to override a component's style, overriding by using a different
 * style from the theme can simply be done by assigning the document name to the \l {StyledItem::styleName}
 * {StyledItem.styleName} property as follows:
 * \qml
 * Button {
 *     id: button
 *     styleName: "SquaryButtonStyle"
 * }
 * \endqml
 * \note The document extension doesn't have to be specified, the style creation will automatically
 * append the .qml extension to it. This kind of style override assumes that the \c SquaryButtonStyle.qml
 * document is present in the theme.
 * This type of component styling makes sure the style will always have theme specific implementation
 * or coloring, however it also requires the style document to be present in all the themes
 * used by the application.
 *
 * \section3 Override with a custom component
 * The other way is to override the style with a local component not present in any theme.
 * The style component can be in-source (Component) or declared in a separate document,
 * loaded dynamically with Loader or Qt.createComponent(). This kind of override will make
 * sure the component will use the custom style no matter of the theme used. These styles
 * however can still use the theme palette to be in sync with the theme coloring.
 * \qml
 * Button {
 *     id: button
 *     style: Rectangle {
 *         implicitWidth: units.gu(12)
 *         implicitHeight: units.gu(5)
 *         color: styledItem.color
 *         border {
 *             width: units.dp(1)
 *             color: styledItem.strokeColor
 *         }
 *         Label {
 *             text: styledItem.text
 *             font: styledItem.font
 *         }
 *     }
 * }
 * \endqml
 * \note Specifying a component for the \l {StyledItem::style}{StyledItem.style} has precedence
 * over the \l {StyledItem::styleName}{StyledItem::styleName}. When both set, the stlke specified
 * \c style property will be used. When this property is set to undefined or null, the style specified
 * in \c styleName will be used. Obviously, when both properties are invalid, no style will be used.
 */

/*!
 * \page lomiri-theming-themes.html
 * \title Themes
 * \previouspage Styles
 * \nextpage Sub-theming
 * \contentspage {Introduction} {Contents}
 *
 * A theme is a collection of style implementations. The style component names are
 * typically built using the component name and the Style word, exceptions being
 * documented per component.
 *
 * In addition to the styles the theme can provide palette values used by the style
 * and components. The palette values are defined in \c Palette.qml file, which must
 * either be derived from \l Palette component or from a parent theme's Palette.
 *
 * There are two types of themes, shared themes and application themes. These themes
 * do not differ in structure but in the way they are exposed. Shared themes are
 * located either under \b QML2_IMPORT_PATH or \b XDG_DATA_DIR. Application themes
 * are located under the application's private folder, therefore they are typically
 * serving the application styling needs, and cannot be shared. Shared themes are also
 * presented as QML extension modules, giving the possibility for application themes
 * to extend them.
 *
 * \note Yet there is no possibility to install shared themes into the system through
 * app store, only by providing them as part of the system image.
 *
 * The system provides two shared themes, \b Ambiance and \b SuruDark, the latest derived
 * from Ambiance theme. Both themes can be used as base theme in application themes,
 * by importing the modules defining them. If you decide to create a shared theme
 * that can be used also as base for custom or application themes, it is recommended
 * to do the same approach as the system themes do.
 *
 * \section2 Theme structure
 * \image surudark-theme.png
 * The theme structure is similar to a QML extension module structure, and this applies
 * to both shared and application themes. Contains component style documents, palette
 * description document, \c qmldir file and a special file called \c parent_theme. All
 * these files are optional in a theme depending on context.
 *
 * \c parent_theme is a special file which defines the theme the current one is derifed from.
 * The parent theme must be a shared theme and its name must be specified in dotted format.
 * For example SuruDark theme is located under \c{$QML2_IMPORT_PATH/Lomiri/Components/Themes/SuruDark}
 * folder. This means that the theme name is identified by the \b Lomiri.Components.Themes.SuruDark
 * dotted format.
 *
 * In addition to the files mentioned, themes can provide components supporting the styling
 * (i.e. components providing common visuals in the style implementations). Style implementations
 * can also provide additional APIs alongside the standard style API. These additional APIs are
 * typically there to configure the style itself, or to turn on/off features provided by styles
 * in derived themes.
 *
 * Starting with Lomiri Components version 1.3, themes must provide versioned styles. This means
 * that themes must store the styles in subfolders, meaning that toolkit version 1.3 must have
 * the version specific styles under the theme's 1.3/ subfolder. The styling engine will look
 * for the styles based on the theme version used by the component. If the style is not found
 * with the requested version, it will fall back to the previous version of that style.
 * \image surudark-theme-13.png
 *
 * \section3 Standalone theme
 * A standalone theme is a theme which defines all style documents and theme palette,
 * and it is not derived from any theme. The only standalone theme UI Toolkit provides is
 * the Ambiance theme. Both shared and application themes can be standalone themes, however
 * Applications should make sure they implement all the styles used by the toolkit components
 * used in the application. \c qmldir file presence is mandatory only if the theme is
 * shared.
 *
 * \section3 Derived themes
 * As the name suggests derived themes are themes which use other themes (standalone or derived ones)
 * as base theme. These themes must have the \c parent_theme file which contains the
 * name of the theme they are derived from. These themes do not have to provide palette configuration
 * as long as they use the derived theme's palette values.
 *
 * Derived themes should only list those style components which overrule the derived style or
 * extend the derived style. The only requirement is to use the same document name as the parent theme
 * is having.
 *
 * Let's take SuruDark theme as en example. The theme is derived from Ambiance theme, and only
 * extends few style components. When theming engine loads the style components, it looks
 * after the styles starting from the current theme. If the style is not found there, it
 * tries to look after the style in the parent themes until it finds one.
 *
 * The extended (or even overridden) style component documents must follow the naming
 * convention, and must have the names implied by the components styled.
 *
 * The style imports the Ambiance theme module, and extends the Ambiance ListItemStyle
 * component. The same is done in the other style components. However, Palette defines
 * own values, and does not re-use Ambiance palette values.
 * \snippet Themes/SuruDark/1.3/Palette.qml 0
 *
 * \note If a theme derived from SuruDark wants to override style components not present
 * in SuruDark, they must import the SuruDark's parent theme in the style component.
 * As example, if FancyTheme would want to override the SwitchStyle, it would need to
 * import Ambiance module in the component as SuruDark doesn't have that style component
 * defined.
 * \qml
 * import QtQuick 2.4
 * import Lomiri.Components 1.3
 * import Lomiri.Components.Themes.Ambiance 1.3 as Ambiance
 * Ambiance.SwitchStyle {
 *     // [...]
 * }
 * \endqml
 *
 * \section2 Application themes
 * Application themes can also be standalone or derived themes. Usually applications
 * need slight differences on certain component styles, colors. These can be configured
 * in multiple ways, depending on the needs of the application. Applications can decide
 * to have their own theme, and override the palette value in the theme, or to use the
 * system themes and override few color values from the theme palette.
 *
 * Let's take an example of an application which changes some palette values of SuruDark
 * theme.
 *
 * First, the application has to define the theme, preferably in a separate folder (e.g.
 * theme). The folder should contain a \c parent_theme file with the content
 * \code
 * Lomiri.Components.Themes.SuruDark
 * \endcode
 * This will make sure theme engine will look after the style components that are not
 * defined by the application theme inside the parent theme. Remember, the parent themes
 * can have parent themes (SuruDark is derived from Ambiance) in which case the style components
 * will be looked up in all these themes.
 *
 * As shown next, the application can define the palette.
 * \snippet customtheme/theme/Palette.qml 0
 * Note that the palette uses the SuruDark palette as base, and changes few colors from it.
 *
 * The application can use its own theme in the following way:
 * \snippet customtheme/main.qml 0
 *
 * \note An application, which overrides multiple shared theme versions must provide separate
 * style versions in its theme so the styling engine can identify the proper styles for the
 * components. Note however that this is not mandatory, and it is up to the application developer
 * to decide whether the application should support multiple style versions or not.
 */

/*!
 * \page lomiri-theming-subtheming.html
 * \title Sub-theming
 * \previouspage Themes
 * \contentspage {Introduction} {Contents}
 *
 * There can be situations when an application has a design which combines styles from different
 * themes, which would not be possible or would be hard to be combined in a single theme. In these
 * situations developers can use different themes in the components and its child components.
 * This is called sub-theming, which was introduced in Lomiri.Components 1.3.
 * The only thing the application has to do is to define a ThemeSettings instance for the
 * component which is desired to use a different theme.
 * \qml
 * import QtQuick 2.4
 * import Lomiri.Components 1.3
 * import Lomiri.Components.Popups 1.3
 * MainView {
 *     width: units.gu(40)
 *     height: units.gu(71)
 *
 *     applicationName: "subthemed"
 *
 *     // make sure the main theme is Ambiance
 *     theme.name: "Lomiri.Components.Themes.Ambiance"
 *
 *     Component {
 *         id: dialogComponent
 *         Dialog {
 *             id: dialog
 *             title: "Input dialog"
 *             // the dialog and its children will use SuruDark
 *             theme: ThemeSettings {
 *                 name: "Lomiri.Components.Themes.SuruDark"
 *             }
 *             TextField {
 *                 placeholderText: "enter text"
 *             }
 *             Button {
 *                 text: "Close"
 *                 onClicked: PopupUtils.close(dialog)
 *             }
 *         }
 *     }
 *
 *     Button {
 *         text: "Open dialog"
 *         onClicked: PopupUtils.open(dialogComponent)
 *     }
 * }
 * \endqml
 *
 * Another use-case is when a different palette set is needed in the application.
 * One way to achieve that is to define a custom theme for the application, however
 * that theme must be derived from one particular theme, so the application will be
 * restricted to one given theme. If we want to have the same palette values to be used
 * no matter where the component is used, we can override the palette values we want to
 * change, by setting the theme palette to a \l Palette instance where only the desired
 * palette values are changed. This can be combined with sub-theming, which will make
 * sure that the palette values are applied only on a certain component sub-tree.
 *
 * The following example makes sure the Dialog and its child components will use a given
 * palette value:
 * \qml
 * import QtQuick 2.4
 * import Lomiri.Components 1.3
 * import Lomiri.Components.Themes 1.3
 *
 * MainView {
 *     width: units.gu(40)
 *     height: units.gu(71)
 *
 *     applicationName: "subthemed"
 *
 *     Component {
 *         id: dialogComponent
 *         Dialog {
 *             id: dialog
 *             title: "Input dialog"
 *             // make sure the dialog and its children will use the same
 *             // theme as the rest of the application
 *             theme: ThemeSettings {
 *                 name: parentTheme.name
 *                 palette: Palette {
 *                     id: config
 *                     normal {
 *                         foregroundText: LomiriColors.blue
 *                         overlayText: "#BAFEDC"
 *                     }
 *                     selected {
 *                         fieldText: "brown"
 *                         foregroundText: Qt.rgba(0, 0, 1, 1)
 *                         overlayText: config.normal.overlayText
 *                         foreground: LomiriColors.green
 *                     }
 *                 }
 *             }
 *             TextField {
 *                 placeholderText: "enter text"
 *             }
 *             Button {
 *                 text: "Close"
 *                 onClicked: PopupUtils.close(dialog)
 *             }
 *         }
 *     }
 *
 *     Column {
 *         spacing: units.gu(1)
 *         Button {
 *             text: "Set Ambiance theme"
 *             onClicked: theme.name = "Lomiri.Components.Themes.Ambiance"
 *         }
 *         Button {
 *             text: "Set SuruDark theme"
 *             onClicked: theme.name = "Lomiri.Components.Themes.SuruDark"
 *         }
 *         Button {
 *             text: "Open dialog"
 *             onClicked: PopupUtils.open(dialogComponent)
 *         }
 *     }
 * }
 * \endqml
 * \note Note the way the theme is changed! The first two buttons actually change the
 * name of the theme they inherit, which is the application's theme. This means that
 * the theme will actually be changed on the entire application, not only on the Button
 * itself.
 *
 * The Dialog uses the \l {ThemeSettings::parentTheme}{parentTheme} property to load
 * the same theme as its parent styled item is using, meaning that the Dialog will
 * also load the same theme as the application does, and will change the loaded palette
 * values with the ones defined in the \c config Palette instance, namely the \c
 * foregroundText and \c overlayText of \c normal, as well as \c fieldText, \c foregroundText,
 * \c overlayText and \c foreground on \c selected groups.
 *
 * There may be cases when a subset of components wants to use different style versions
 * than the one provided by the module version. Remember, using earlier minor versions
 * of the theme is perfectly fine while using newer versions may not work, as component
 * styles may use newer APIs of the component which is not present in the component, thus
 * the style will fail.
 *
 * Let's take the example above, and assume that we want to show the Dialog with the same
 * theme as the application but with an earlier version. We can do this by specifying the
 * theme version with \l {Lomiri::version}{Lomiri.version()} as follows:
 * \qml
 * import QtQuick 2.4
 * import Lomiri.Components 1.3
 * import Lomiri.Components.Themes 1.3
 *
 * MainView {
 *     width: units.gu(40)
 *     height: units.gu(71)
 *
 *     applicationName: "subthemed"
 *
 *     Component {
 *         id: dialogComponent
 *         Dialog {
 *             id: dialog
 *             title: "Input dialog"
 *             // make sure the dialog and its children will use the same
 *             // theme as the rest of the application
 *             theme: ThemeSettings {
 *                 name: parentTheme.name
 *                 // use version 1.2 of the theme
 *                 version: Lomiri.version(1, 2)
 *             }
 *             TextField {
 *                 placeholderText: "enter text"
 *             }
 *             Button {
 *                 text: "Close"
 *                 onClicked: PopupUtils.close(dialog)
 *             }
 *         }
 *     }
 *
 *     Column {
 *         spacing: units.gu(1)
 *         Button {
 *             text: "Set Ambiance theme"
 *             onClicked: theme.name = "Lomiri.Components.Themes.Ambiance"
 *         }
 *         Button {
 *             text: "Set SuruDark theme"
 *             onClicked: theme.name = "Lomiri.Components.Themes.SuruDark"
 *         }
 *         Button {
 *             text: "Open dialog"
 *             onClicked: PopupUtils.open(dialogComponent)
 *         }
 *     }
 * }
 * \endqml
 *
 * \section1 That's it
 * By now you should have learned what the styling means, what are the themes, what
 * kind of themes the toolkit has, how can you create shared or application themes, where should
 * you store them, how to extend styles, how to use multiple themes in an application
 * and how to set custom palette values runtime. If you have questions or need guidance,
 * you can contact us on \b{#lomiri-app-devel} IRC channel on freenode.
 */