Nova Flow OS
KDE Developer Platform
KDE Developer Platform
  • KDE Developer Platform
    • Getting started
      • Building KDE software
        • KDE software
        • Where to find the development team
        • Learning more
        • Choose what to work on
        • Source code cross-referencing
        • Installing build dependencies
        • Set up a development environment
        • Building KDE software with kdesrc-build
        • Basic troubleshooting
        • Tips and tricks
        • IDE Configuration
          • Setting up an IDE for KDE development
          • Visual Studio Code
          • Qt Creator
          • Kate
          • KDevelop
          • CLion
          • Sublime Text
        • Building KDE software manually
        • Building KDE software with distrobox and podman
      • Kirigami
        • KDE is ours
        • Setting up and getting started
        • Explaining pages
        • Layouts, ListViews, and Cards
        • Adding actions
        • Adding a dialog
        • Using separate files
        • Next steps
        • Colors and themes in Kirigami
        • Typography
        • Actions based components
        • Page rows and page stacks
        • Scrollable pages and list views
        • Cards
        • Drawers
        • Chips
        • Dialog types
        • Controls and interactive elements
        • Form layouts
        • Inline messages
        • Action toolbars
        • Progress bars and indicators
        • List views
        • Understanding CMakeLists
        • Figuring out main.cpp
        • Connect logic to your QML user interface
        • Connect models to your QML user interface
        • About page
        • Introduction to Kirigami Addons
        • FormCard About pages
        • Form delegates in your settings pages
      • KXmlGui
        • Getting started with KXmlGui
        • Hello World!
        • Creating the main window
        • Using actions
        • Saving and loading
        • Command line interface
      • Python with Kirigami
        • Apps with QML and Python
        • Your first Python + Kirigami application
        • Creating a Python package
        • Creating a Flatpak
      • Common programming mistakes
      • Adding a new KDE project
    • Features
      • Icons
      • Configuration
        • The KConfig Framework
        • Introduction to KConfig
        • Using KConfig XT
        • KDE Frameworks 6 porting guide
        • Settings module (KCM) development
        • KConfigDialog
      • D-Bus
        • What is D-Bus practically useful for?
        • Introduction to D-Bus
        • Accessing D-Bus interfaces
        • Intermediate D-Bus
        • Creating D-Bus interfaces
        • Using custom types with D-Bus
        • D-Bus autostart services
      • Create your own mouse cursor theme
      • Session management
      • Archives
      • Desktop file
      • KAuth
        • Privilege Escalation
        • Using actions in your applications
      • KIdleTime
      • Akonadi: personal information management
        • Debugging Akonadi Resources
        • Using Akonadi in applications
      • Concurrent programming
      • Solid
      • Sonnet
    • Plasma themes and plugins
      • Getting started
      • Plasma Widget tutorial
        • How to create a plasmoid
        • Setup
        • Porting Plasmoids to KF6
        • Testing
        • QML
        • Plasma's QML API
        • Widget Properties
        • Configuration
        • Translations / i18n
        • Examples
        • C++ API
      • KWin Effects
      • Plasma Desktop scripting
        • Javascript Interaction With Plasma Shells
        • Templates
        • Examples
        • API documentation
        • Configuration keys
      • Plasma Style tutorial
        • Creating a Plasma Style quickstart
        • Understanding Plasma Styles
        • SVG elements and Inkscape
        • Background SVG format
        • System and accent colors
        • Theme elements reference
        • Porting themes to Plasma 5
        • Porting themes to Plasma 6
      • Aurorae window decorations
      • KWin scripting tutorial
        • Quick start
        • KWin scripting API
      • Wallpapers
      • Plasma comic
        • Tutorial
        • Testing and debugging
        • Examples
      • Create a custom Window Switcher
      • KRunner C++ Plugin
        • Basic Anatomy of a Runner
        • KRunner metadata format
    • Applications
      • Creating sensor faces
      • Dolphin
        • Creating Dolphin service menus
      • Kate
        • Kate plugin tutorial
      • KMines
        • Making a KMines theme
      • Writing tests
        • Appium automation testing
    • Packaging
      • Android
        • KDE on Android
        • Building applications for Android
        • Packaging and publishing applications for Android
        • Publishing on Google Play
          • Introduction
          • Packaging your app
          • Adding your app to Google Play
          • Publishing your app
          • Releasing new versions of old apps
        • Porting applications to Android
          • Basic porting
          • Making applications run well on Android
          • Metadata
      • Windows
        • Packaging and publishing applications for Windows
        • Publish your app in the Microsoft Store
          • Packaging your app for the Microsoft Store
          • Submitting your app to the Microsoft Store
      • Plasma Mobile
        • KDE on mobile devices
        • Porting a new device to Plasma Mobile
        • KDE Telephony stack
          • General Overview
          • Kernel layer
          • System daemons
            • General overview
            • Developing Telephony functionality
            • ModemManager Telephony functions
          • Session daemons
          • QML declarative plugin layer
          • KDE application layer
        • Execute applications
      • Distributing KDE software as Flatpak
        • Your first Flatpak
        • Extending your package
        • Nightly Flatpaks and Flathub
        • Testing your Flatpak
    • System administration
      • Shell scripting with KDE dialogs
      • Kiosk: Simple configuration management for large deployment
        • Abstract
        • Introduction to Kiosk
        • Kiosk keys
    • Contribute to the documentation
    • About
      • Readme
      • License
        • Creative Commons Attribution-ShareAlike 4.0 International
        • GNU General Public License 3.0 or later
Powered by GitBook
On this page
  • Configurable icon
  • Configurable panel widget width/height
  • Time DataSource
  • Solar DataSource
  • Avoid widget resize on text change
  1. KDE Developer Platform
  2. Plasma themes and plugins
  3. Plasma Widget tutorial

Examples

Resizable popup, clock, bundle icon and other simple examples. There are also several examples in the plasma-framework repo:

PreviousTranslations / i18nNextC++ API

Last updated 8 months ago

Configurable icon

To get your panel icon to be configurable like the we need to:

  • Create a new string config key (plasmoid.configuration.icon)

  • Set Plasmoid.icon to plasmoid.configuration.icon

  • Copy the icon selector control from the Application Launcher widget to a reusable ConfigIcon.qml file.

  • Add a ConfigIcon button to our ConfigGeneral.qml tab, and bind it to a cfg_icon property.

contents/config/main.xml

<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
    <kcfgfile name=""/>

    <group name="General">
        <entry name="icon" type="string">
            <default>plasma</default>
        </entry>
    </group>
</kcfg>

contents/ui/main.qml

import QtQuick 2.0
import org.kde.plasma.plasmoid 2.0

Item {
    id: widget
    Plasmoid.icon: plasmoid.configuration.icon
}

contents/ui/ConfigIcon.qml

import QtQuick 2.5
import QtQuick.Controls 2.5
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons
import org.kde.ksvg 1.0 as KSvg

Button {
    id: configIcon

    property string defaultValue: ''
    property string value: ''

    implicitWidth: previewFrame.width + PlasmaCore.Units.smallSpacing * 2
    implicitHeight: previewFrame.height + PlasmaCore.Units.smallSpacing * 2

    KQuickAddons.IconDialog {
        id: iconDialog
        onIconNameChanged: configIcon.value = iconName || configIcon.defaultValue
    }

    onPressed: iconMenu.opened ? iconMenu.close() : iconMenu.open()

    KSvg.FrameSvgItem {
        id: previewFrame
        anchors.centerIn: parent
        imagePath: plasmoid.location === PlasmaCore.Types.Vertical || plasmoid.location === PlasmaCore.Types.Horizontal
                 ? "widgets/panel-background" : "widgets/background"
        width: PlasmaCore.Units.iconSizes.large + fixedMargins.left + fixedMargins.right
        height: PlasmaCore.Units.iconSizes.large + fixedMargins.top + fixedMargins.bottom

        PlasmaCore.IconItem {
            anchors.centerIn: parent
            width: PlasmaCore.Units.iconSizes.large
            height: width
            source: configIcon.value
        }
    }

    Menu {
        id: iconMenu

        // Appear below the button
        y: +parent.height

        MenuItem {
            text: i18ndc("plasma_applet_org.kde.plasma.kickoff", "@item:inmenu Open icon chooser dialog", "Choose...")
            icon.name: "document-open-folder"
            onClicked: iconDialog.open()
        }
        MenuItem {
            text: i18ndc("plasma_applet_org.kde.plasma.kickoff", "@item:inmenu Reset icon to default", "Clear Icon")
            icon.name: "edit-clear"
            onClicked: configIcon.value = configIcon.defaultValue
        }
    }
}

contents/ui/ConfigGeneral.qml

import QtQuick 2.0
import QtQuick.Controls 2.5
import org.kde.kirigami 2.4 as Kirigami

Item {
    id: page
    width: childrenRect.width
    height: childrenRect.height

    property alias cfg_icon: configIcon.value

    Kirigami.FormLayout {
        anchors.left: parent.left
        anchors.right: parent.right

        ConfigIcon {
            id: configIcon
            Kirigami.FormData.label: i18nd("plasma_applet_org.kde.plasma.kickoff", "Icon:")
        }
    }
}

contents/config/config.qml

import QtQuick 2.0
import org.kde.plasma.configuration 2.0

ConfigModel {
    ConfigCategory {
        name: i18n("General")
        icon: "configure"
        source: "ConfigGeneral.qml"
    }
}

Configurable panel widget width/height

While the user can resize the popup window temporarily with Alt+RightClick+Drag, it will reset when the user relogs. To allow the user to permanently configure the popup size in a panel widget, or the size of the compact view in the panel, we'll need a store the width/height in the config.

So we change to our hardcoded sizes:

contents/ui/main.qml

Item {
    id: widget
    Plasmoid.fullRepresentation: Item {
        Layout.preferredWidth: 640 * PlasmaCore.Units.devicePixelRatio
        Layout.preferredHeight: 480 * PlasmaCore.Units.devicePixelRatio
    }
}

into this:

contents/ui/main.qml

Item {
    id: widget
    Plasmoid.fullRepresentation: Item {
        Layout.preferredWidth: plasmoid.configuration.width * PlasmaCore.Units.devicePixelRatio
        Layout.preferredHeight: plasmoid.configuration.height * PlasmaCore.Units.devicePixelRatio
    }
}

Make sure you still multiply the stored width/height by PlasmaCore.Units.devicePixelRatio, otherwise your popup will look smaller by default on HiDPI/4k monitors.

To simplify testing, I added Plasmoid.hideOnWindowDeactivate: false to prevent the popup from closing when you focus the config window.

Next we register the config keys and their default values in the config/main.xml.

Lastly we register the General config tab in config/config.qml.

contents/ui/main.qml

Item {
    id: widget
    Plasmoid.fullRepresentation: Item {
        id: popupView
        Layout.preferredWidth: plasmoid.configuration.width * PlasmaCore.Units.devicePixelRatio
        Layout.preferredHeight: plasmoid.configuration.height * PlasmaCore.Units.devicePixelRatio
        Plasmoid.hideOnWindowDeactivate: false
        ColumnLayout {
            id: layout
            anchors.fill: parent
            PlasmaComponents.Label {
                text: i18n("Size: %1 x %2", popupView.width, popupView.height)
            }
        }
    }
}

contents/config/main.xml

<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
    <kcfgfile name=""/>

    <group name="General">
        <entry name="width" type="int">
            <default>640</default>
        </entry>
        <entry name="height" type="int">
            <default>480</default>
        </entry>
    </group>
</kcfg>

contents/ui/configGeneral.qml

import QtQuick 2.0
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
import org.kde.kirigami 2.4 as Kirigami

Item {
    id: page
    width: childrenRect.width
    height: childrenRect.height

    property alias cfg_width: widthSpinBox.value
    property alias cfg_height: heightSpinBox.value

    Kirigami.FormLayout {
        anchors.left: parent.left
        anchors.right: parent.right

        RowLayout {
            Kirigami.FormData.label: i18n("Size:")
            SpinBox {
                id: widthSpinBox
                from: 0
                to: 2147483647 // 2^31-1
            }
            Label {
                text: " x "
            }
            SpinBox {
                id: heightSpinBox
                from: 0
                to: 2147483647 // 2^31-1
            }
        }
    }
}

contents/config/config.qml

// config/config.qml
import QtQuick 2.0
import org.kde.plasma.configuration 2.0

ConfigModel {
    ConfigCategory {
        name: i18n("General")
        icon: "configure"
        source: "configGeneral.qml"
    }
}

Time DataSource

contents/ui/main.qml

import QtQuick 2.0
import QtQuick.Layouts 1.1

import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.calendar 2.0 as PlasmaCalendar

Item {
    id: root

    readonly property date currentDateTime: dataSource.data.Local ? dataSource.data.Local.DateTime : new Date()

    width: PlasmaCore.Units.gridUnit * 10
    height: PlasmaCore.Units.gridUnit * 4

    Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation

    Plasmoid.toolTipMainText: Qt.formatTime(currentDateTime)
    Plasmoid.toolTipSubText: Qt.formatDate(currentDateTime, Qt.locale().dateFormat(Locale.LongFormat))

    PlasmaCore.DataSource {
        id: dataSource
        engine: "time"
        connectedSources: ["Local"]
        interval: 60000
        intervalAlignment: PlasmaCore.Types.AlignToMinute
    }

    Plasmoid.compactRepresentation: FuzzyClock { }

    Plasmoid.fullRepresentation: PlasmaCalendar.MonthView {
        Layout.minimumWidth: PlasmaCore.Units.gridUnit * 20
        Layout.minimumHeight: PlasmaCore.Units.gridUnit * 20

        today: currentDateTime
    }
}

Solar DataSource

  • Install plasma-sdk then open the Plasma Engine Explorer.

  • Select the time dataengine.

  • Enter something like the following into the source name: UTC-04:00|Solar|Latitude=43.68|Longitude=79.63|DateTime=2021-03-23T19:00:00 The above example is for Toronto, Canada.

  • Click "Request Source", then scroll down to the bottom to find the new data.

Examples:

Type
Key
Value

double

Azimuth

69.6342657428925

double

Corrected Elevation

-18.092120068676486

QDateTime

DateTime

Tue Mar 23 19:00:00 2021

int

Offset

UTC-04:00

QString

Timezone

UTC-04:00

QString

Timezone Abbreviation

UTC-04:00

QString

Timezone City

UTC-04:00

double

Zenith

108.10976492154272

{{< /section-right >}}

{{< /sections >}}

Avoid widget resize on text change

contents/ui/main.qml

import QtQuick 2.4
import QtQuick.Layouts 1.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.plasmoid 2.0

Item {
    id: widget
    property int value: 0
    property int maxValue: 100
    function formatText(n) {
        return "" + n + "%"
    }

    Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation

    Plasmoid.compactRepresentation: PlasmaComponents.Label {
        id: label
        Layout.minimumWidth: textMetrics.width
        Layout.minimumHeight: textMetrics.height

        text: widget.formatText(value)

        font.pointSize: 40
        horizontalAlignment: Text.AlignHCenter

        TextMetrics {
            id: textMetrics
            font.family: label.font.family
            font.pointSize: label.font.pointSize
            text: widget.formatText(100)
        }

        // Since we overrode the default compactRepresentation,
        // we need to setup the click to toggle the popup.
        MouseArea {
            anchors.fill: parent
            onClicked: plasmoid.expanded = !plasmoid.expanded
        }
    }

    Plasmoid.fullRepresentation: Item {
        Layout.preferredWidth: 640 * PlasmaCore.Units.devicePixelRatio
        Layout.preferredHeight: 480 * PlasmaCore.Units.devicePixelRatio

        Rectangle {
            id: popup
            anchors.left: parent.left
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            width: parent.width * (widget.value / 100)
            color: PlasmaCore.Theme.highlightColor
        }
    }

    Timer {
        interval: 100
        running: true
        repeat: true
        onTriggered: widget.value = (widget.value + 1) % (widget.maxValue+1)
    }
}

Then create a configuration form in ui/configGeneral.qml. We use and set the max value to .

An extremely simple example of this can be found in the "fuzzy clock" widget in the kdeplasma-addons repo ().

The new Date() should be familiar if you come from a javascript background. We could use a Timer with the Date type, but we want to precisely sync all clock widgets so they all show the same time on all screens. This is where Plasma's DataEngines come in. They are used to share data between widgets. There are for notifications, plugged in usb drives (hotplug), and event the weather data so it only has to fetch the data once to show it in all widgets on each screen.

To use the "time" data engine, we use to connect to it. The "time" needs us to connect to our "Local" timezone. Once connected, it gives us a DateTime object we can access using dataSource.data.Local.DateTime. This property will update every 60000 milliseconds, or every 1 minute.

We also tell the data engine to align these updates to the next minute. If we want to modify this to update every second, we'd change the interval to interval: 1000 (1 second), then remove the intervalAlignment assignment since there isn't an "AlignToSecond", just a .

A clock can then use Qt's Qt.formatTime(currentDateTime) to display the time in a human readable format. You can read more about that function on the Qt documentation for .

Solar is part of the "time" dataengine. It provides the sun's , , and "Corrected Elevation" for a longitude and latitude at a specific time of day.

The the Solar dataengine to check if the "Corrected Elevation" to start using nighttime icons.

We use to calculate the size of the label when it is the widest/maximum value of 100%. {{< /section-left >}} {{< section-right >}}

SpinBox
the maximum signed integer value in QML
link
various dataengines
PlasmaCore.DataSource
PlasmaCore.Types.NoAlignment
Qt.formatDateTime(...)
Azimuth
Zenith
EnvCanada Weather Source uses
is below zero
TextMetrics
Text
Application Launcher widget
examples/applets · master · Plasma / libplasma · GitLabGitLab
Logo