From 581ec772ac9c5cc35512d2b8ad25a05c715169e1 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Thu, 14 Mar 2024 02:45:47 -0700 Subject: [PATCH] guide: add multiple files and singletons sections to intro --- content/docs/configuration/intro.md | 290 +++++++++++++++++++++ content/docs/configuration/qml-overview.md | 4 +- flake.lock | 8 +- 3 files changed, 297 insertions(+), 5 deletions(-) diff --git a/content/docs/configuration/intro.md b/content/docs/configuration/intro.md index f481d06..2098080 100644 --- a/content/docs/configuration/intro.md +++ b/content/docs/configuration/intro.md @@ -514,3 +514,293 @@ ShellRoot { } } ``` + +## Multiple files + +In an example as small as this it isn't a problem, but as your project +gets bigger you may become annoyed having everything all +in one file. Luckily its easy to break a component out to a new file. + +Lets move the entire bar into a new file to make space for other widgets: +```qml {filename="shell.qml"} +import Quickshell + +ShellRoot { + Bar {} +} +``` + +```qml {filename="Bar.qml"} +import Quickshell +import Quickshell.Io +import QtQuick + +Scope { + property string time; + + Variants { + variants: Quickshell.screens.map(screen => ({ screen })) + + PanelWindow { + anchors { + top: true + left: true + right: true + } + + height: 30 + + Text { + anchors.centerIn: parent + + // now just time instead of root.time + text: time + } + } + } + + Process { + id: dateProc + command: ["date"] + running: true + + stdout: SplitParser { + // now just time instead of root.time + onRead: data => time = data + } + } + + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: dateProc.running = true + } +} +``` +See also: [Scope](/docs/types/quickshell/scope/) + +Any qml file that starts with an uppercase letter can be referenced this way. +We can bring in other folders as well using +[import statements](/docs/configuration/qml-overview/#explicit-imports). + +Now what about breaking out the clock? This is a bit more complex because +the clock component in the bar and the process and timer that make up the actual +clock both need to be dealt with. + +To start with let's move the clock to a new file. For now it's just a +single `Text` object but the same concepts apply regardless of complexity +(and you probably want a more complicated clock than this.) + +```qml {filename="ClockWidget.qml"} +import QtQuick + +// Item is a common base type for visual components +Item { + // make a property the creator of this type is required to set + required property string time + + // size the item to its children + width: childrenRect.width + height: childrenRect.height + + // use the default property to contain the clock + Text { + text: time + } +} +``` + +```qml {filename="Bar.qml"} +import Quickshell +import Quickshell.Io +import QtQuick + +Scope { + id: root + property string time; + + Variants { + variants: Quickshell.screens.map(screen => ({ screen })) + + PanelWindow { + anchors { + top: true + left: true + right: true + } + + height: 30 + + // the ClockWidget type we just created + ClockWidget { + anchors.centerIn: parent + // Warning: setting `time: time` will bind time to itself which is not what we want + time: root.time + } + } + } + + Process { + id: dateProc + command: ["date"] + running: true + + stdout: SplitParser { + onRead: data => time = data + } + } + + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: dateProc.running = true + } +} +``` + +While this example is larger than what we had before, we can now expand +on the clock widget without cluttering the bar file. + +Let's deal with the clock's update logic now: + +```qml {filename="Time.qml"} +import Quickshell +import Quickshell.Io +import QtQuick + +Scope { + property string time; + + Process { + id: dateProc + command: ["date"] + running: true + + stdout: SplitParser { + onRead: data => time = data + } + } + + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: dateProc.running = true + } +} +``` + +```qml {filename="Bar.qml"} +import Quickshell + +Scope { + // the Time type we just created + Time { id: timeSource } + + Variants { + variants: Quickshell.screens.map(screen => ({ screen })) + + PanelWindow { + anchors { + top: true + left: true + right: true + } + + height: 30 + + ClockWidget { + anchors.centerIn: parent + // now using the time from timeSource + time: timeSource.time + } + } + } +} +``` + +## Singletons + +Now you might be thinking, why do we need the `Time` type in +our bar file, and the answer is we don't. We can make `Time` +a [singleton](/docs/configuration/qml-overview/#singletons). + +A singleton object has only one instance, and is accessible from +any scope. + +```qml {filename="Time.qml"} +// with this line our type becomes a singleton +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick + +// your singletons should always have Singleton as the type +Singleton { + property string time; + + Process { + id: dateProc + command: ["date"] + running: true + + stdout: SplitParser { + onRead: data => time = data + } + } + + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: dateProc.running = true + } +} +``` + +```qml {filename="ClockWidget.qml"} +import QtQuick + +Item { + // we no longer need time as an input + + width: childrenRect.width + height: childrenRect.height + + Text { + // directly access the time property from the Time singleton + text: Time.time + } +} +``` + +```qml {filename="Bar.qml"} +import Quickshell + +Scope { + // no more time object + + Variants { + variants: Quickshell.screens.map(screen => ({ screen })) + + PanelWindow { + anchors { + top: true + left: true + right: true + } + + height: 30 + + ClockWidget { + anchors.centerIn: parent + + // no more time binding + } + } + } +} +``` diff --git a/content/docs/configuration/qml-overview.md b/content/docs/configuration/qml-overview.md index f0981f4..5b132c7 100644 --- a/content/docs/configuration/qml-overview.md +++ b/content/docs/configuration/qml-overview.md @@ -679,12 +679,14 @@ QML Types can be easily made into a singleton, meaning there is only one instanc of the type. To make a type a singleton, put `pragma Singleton` at the top of the file. +To ensure it behaves correctly with quickshell you should also make +[Singleton](/docs/types/quickshell/singleton) the root item of your type. ```qml pragma Singleton import ... -Item { ... } +Singleton { ... } ``` once a type is a singleton, its members can be accessed by name from neighboring diff --git a/flake.lock b/flake.lock index cea617a..786389f 100644 --- a/flake.lock +++ b/flake.lock @@ -22,11 +22,11 @@ ] }, "locked": { - "lastModified": 1710162131, - "narHash": "sha256-iaLK3zoKZ84VWvykaupB4Vk0i5xJxFkCR8xqsxiob3g=", + "lastModified": 1710400582, + "narHash": "sha256-Qr6Nt12Wi7t5X1wbij+FuXKJnHnH2E4KpGjc9XcqTaA=", "ref": "refs/heads/master", - "rev": "d11868c32f9c82c7e6f404f77ffe1137e8c093e0", - "revCount": 109, + "rev": "ffbdac9977588dd89ba6f077eb1f45890002663d", + "revCount": 115, "type": "git", "url": "https://git.outfoxxed.me/outfoxxed/quickshell" },