UbuntuUserInterfaceToolkit.ubuntu-theming-subtheming

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 Ubuntu.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.

import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
MainView {
width: units.gu(40)
height: units.gu(71)
applicationName: "subthemed"
// make sure the main theme is Ambiance
theme.name: "Ubuntu.Components.Themes.Ambiance"
Component {
id: dialogComponent
Dialog {
id: dialog
title: "Input dialog"
// the dialog and its children will use SuruDark
theme: ThemeSettings {
name: "Ubuntu.Components.Themes.SuruDark"
}
TextField {
placeholderText: "enter text"
}
Button {
text: "Close"
onClicked: PopupUtils.close(dialog)
}
}
}
Button {
text: "Open dialog"
onClicked: PopupUtils.open(dialogComponent)
}
}

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 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:

import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.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: UbuntuColors.blue
overlayText: "#BAFEDC"
}
selected {
fieldText: "brown"
foregroundText: Qt.rgba(0, 0, 1, 1)
overlayText: config.normal.overlayText
foreground: UbuntuColors.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 = "Ubuntu.Components.Themes.Ambiance"
}
Button {
text: "Set SuruDark theme"
onClicked: theme.name = "Ubuntu.Components.Themes.SuruDark"
}
Button {
text: "Open dialog"
onClicked: PopupUtils.open(dialogComponent)
}
}
}

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 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 config Palette instance, namely the foregroundText and overlayText of normal, as well as fieldText, foregroundText, overlayText and foreground on 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 Ubuntu.version() as follows:

import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.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: Ubuntu.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 = "Ubuntu.Components.Themes.Ambiance"
}
Button {
text: "Set SuruDark theme"
onClicked: theme.name = "Ubuntu.Components.Themes.SuruDark"
}
Button {
text: "Open dialog"
onClicked: PopupUtils.open(dialogComponent)
}
}
}

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 #ubuntu-app-devel IRC channel on freenode.

  • Themes