QML Worked Examples¶
In a nutshell
Worked QML snippets for common legacy skill-display patterns: Lottie animations, sliding images, paginated text, card list views, proportional/auto-fit layouts, slideshows, event handling, and resting (idle) faces. For the QML concepts and design guidelines these examples build on, see Mycroft-GUI QT5.
The OVOS GUI is deprecated: see Screens on OVOS Today for the full picture
These examples target the legacy Qt5/QML client. There is no generally usable OVOS GUI, and a replacement is Upcoming. See GUI Adapters for the rework.
Advanced skill displays using QML¶
Display Lottie Animations¶
You can use the LottieAnimation item just like any other QtQuick element, such as an Image and place it in your scene any way you please.
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
import org.kde.lottie 1.0
Mycroft.Delegate {
LottieAnimation {
id: fancyAnimation
anchors.fill: parent
source: Qt.resolvedUrl("animations/fancy_animation.json")
loops: Animation.Infinite
fillMode: Image.PreserveAspectFit
running: true
}
}
Display Sliding Images¶
Contains an image that scrolls slowly so it can be shown completely.
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
Mycroft.Delegate {
background: Mycroft.SlidingImage {
source: "foo.jpg"
running: bool //If true the sliding animation is active
speed: 1 //Animation speed in Kirigami.Units.gridUnit / second
}
}
Display Paginated Text¶
Takes a long text and breaks it down into pages that can be horizontally swiped
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
Mycroft.Delegate {
Mycroft.PaginatedText {
text: string //The text that should be displayed
currentIndex: 0 //The currently visible page number (starting from 0)
}
}
Display A Vertical ListView With Information Cards¶
Kirigami CardsListView is a ListView that can have AbstractCard as its delegate. It automatically assigns the proper spacing and margins around the cards, following the design guidelines.
Python Skill Example
...
def handle_food_places(self, message):
...
self.gui["foodPlacesBlob"] = results.json
self.gui.show_page("foodplaces.qml")
...
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
Mycroft.Delegate{
id: root
property var foodPlacesModel: sessionData.foodPlacesBlob
Kirigami.CardsListView {
id: restaurantsListView
Layout.fillWidth: true
Layout.fillHeight: true
model: foodPlacesModel
delegate: Kirigami.AbstractCard {
id: rootCard
implicitHeight: delegateItem.implicitHeight + Kirigami.Units.largeSpacing
contentItem: Item {
implicitWidth: parent.implicitWidth
implicitHeight: parent.implicitHeight
ColumnLayout {
id: delegateItem
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
spacing: Kirigami.Units.smallSpacing
Kirigami.Heading {
id: restaurantNameLabel
Layout.fillWidth: true
text: modelData.name
level: 3
wrapMode: Text.WordWrap
}
Kirigami.Separator {
Layout.fillWidth: true
}
RowLayout {
Layout.fillWidth: true
Layout.preferredHeight: form.implicitHeight
Image {
id: placeImage
source: modelData.image
Layout.fillHeight: true
Layout.preferredWidth: placeImage.implicitHeight + Kirigami.Units.gridUnit * 2
fillMode: Image.PreserveAspectFit
}
Kirigami.Separator {
Layout.fillHeight: true
}
Kirigami.FormLayout {
id: form
Layout.fillWidth: true
Layout.minimumWidth: aCard.implicitWidth
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
Label {
Kirigami.FormData.label: "Description:"
Layout.fillWidth: true
wrapMode: Text.WordWrap
elide: Text.ElideRight
text: modelData.restaurantDescription
}
Label {
Kirigami.FormData.label: "Phone:"
Layout.fillWidth: true
wrapMode: Text.WordWrap
elide: Text.ElideRight
text: modelData.phone
}
}
}
}
}
}
}
}
Using Proportional Delegate For Simple Display Skills & Auto Layout¶
ProportionalDelegate is a delegate which has proportional padding and a columnlayout as mainItem. The delegate supports a proportionalGridUnit, based on its size. Contents should scale proportionally to the delegate size, either directly or by using the proportionalGridUnit.
AutoFitLabel is a label that will always scale its text size according to the item size rather than the other way around
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
Mycroft.ProportionalDelegate {
id: root
Mycroft.AutoFitLabel {
id: monthLabel
font.weight: Font.Bold
Layout.fillWidth: true
Layout.preferredHeight: proportionalGridUnit * 40
text: sessionData.month
}
Mycroft.AutoFitLabel {
id: dayLabel
font.weight: Font.Bold
Layout.fillWidth: true
Layout.preferredHeight: proportionalGridUnit * 40
text: sessionData.day
}
}
Using Slideshow Component To Show Cards Slideshow¶
The Slideshow component lets you insert a slideshow with your custom delegate in any skill display. It can be tuned to autoplay and loop, and can also be scrolled or flicked manually by the user.
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
Mycroft.Delegate {
id: root
Mycroft.SlideShow {
id: simpleSlideShow
model: sessionData.exampleModel // model with slideshow data
anchors.fill: parent
interval: 5000 // time to switch between slides
running: true // can be set to false if one wants to swipe manually
loop: true // can be set to play through continously or just once
delegate: Kirigami.AbstractCard {
width: rootItem.width
height: rootItem.height
contentItem: ColumnLayout {
anchors.fill: parent
Kirigami.Heading {
Layout.fillWidth: true
wrapMode: Text.WordWrap
level: 3
text: modelData.Title
}
Kirigami.Separator {
Layout.fillWidth: true
Layout.preferredHeight: 1
}
Image {
Layout.fillWidth: true
Layout.preferredHeight: rootItem.height / 4
source: modelData.Image
fillMode: Image.PreserveAspectCrop
}
}
}
}
}
Event handling¶
Mycroft GUI API provides an Event Handling Protocol between the skill and QML display. It lets skill authors forward events in either direction to an event consumer. Skill authors can create any number of custom events. Event names that start with "system." are available to all skills, like previous/next/pick.
Simple Event Trigger Example From QML Display To Skill¶
Python Skill Example
def initialize(self):
# Initialize...
self.gui.register_handler('skill.foo.event', self.handle_foo_event)
...
def handle_foo_event(self, message):
self.speak(message.data["string"])
...
...
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
Mycroft.Delegate {
id: root
Button {
anchors.fill: parent
text: "Click Me"
onClicked: {
triggerGuiEvent("skill.foo.event", {"string": "Lorem ipsum dolor sit amet"})
}
}
}
Simple Event Trigger Example From Skill To QML Display¶
Python Skill Example
...
def handle_foo_intent(self, message):
self.gui['foobar'] = message.data.get("utterance")
self.gui['color'] = "blue"
self.gui.show_page("foo")
...
...
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
Mycroft.Delegate {
id: root
property var fooString: sessionData.foobar
onFooStringChanged: {
fooRect.color = sessionData.color
}
Rectangle {
id: fooRect
anchors.fill: parent
color: "#fff"
}
}
Resting Faces¶
The resting face API lets skill authors extend their skills to supply their own custom IDLE screens, displayed when there is no activity on the screen.
Simple Idle Screen Example¶
Python Skill Example
from ovos_workshop.decorators import resting_screen_handler
...
@resting_screen_handler('NameOfIdleScreen')
def handle_idle(self, message):
self.gui.clear()
self.log.info('Activating foo/bar resting page')
self.gui["exampleText"] = "This Is A Idle Screen"
self.gui.show_page('idle.qml')
QML Example
// standard imports (QtQuick, QtQuick.Controls, QtQuick.Layouts, Kirigami, Mycroft, see the imports block above)
Mycroft.Delegate {
id: root
property var fooString: sessionData.exampleText
Kirigami.Heading {
id: headerExample
anchors.centerIn: parent
text: fooString
}
}
Read next: Home Screen Related: Mycroft-GUI QT5 · OVOS Shell · GUI Protocol · Screens on OVOS Today