Development/Tutorials/Plasma4/QML/GettingStarted: Difference between revisions

From KDE TechBase
(add anchor part of QML howto)
 
(45 intermediate revisions by 13 users not shown)
Line 1: Line 1:
== Abstract ==
== Abstract ==


Writing a plasma applet in QML is very easy, in fact, with KDE 4.6 and Qt 4.7 it just works.
Writing a Plasma applet in QML is very easy, in fact, with Workspaces 4.6 and Qt 4.7 it just works.


== QML Basics ==
== QML Basics ==
It is recommended that you have read through the [http://qt-project.org/doc/qt-4.8/qtquick.html Qt QML Tutorials], as there are quite a few and they are explained thoroughly. There is also a list of all [http://qt-project.org/doc/qt-4.8/qdeclarativeelements.html standard QML elements].
Essentially, most of the content is the same. The exceptions to be noted are how data is gathered... since we use Data Engines, it is a bit different. Text color and font should be made to use PlasmaCore.Theme.
See the [https://projects.kde.org/projects/kde/kdeexamples/repository KDE Examples] repository for more KDE-related helpful resources. Also of use (which use QML and Plasma) are: [https://projects.kde.org/projects/playground/base/plasma-mobile/repository Plasma Mobile], [https://projects.kde.org/projects/playground/base/declarative-plasmoids/repository Declarative Plasmoids (playground)], for WIP ports of C++ originals.
=== Root Item ===
The root item can be anything that inherits QGraphicsItem. For example, in this case it is QGraphicsWidget which is a plasmoid. It can also simply be an Item. I also noticed that PathView does not respond to mouse inputs automatically (so flicking doesn't work). Probably because events are being intercepted. So take note, it'll have to be e.g. an Item, for that case.


=== Layouts ===
=== Layouts ===


==== Row and Column ====
==== Row and Column ====
Coloums and Rows are very easy way to grouping items and is very simular to the "normal layout management" with [http://doc.qt.digia.com/stable/qhboxlayout.html QHBoxLayout] and [http://doc.qt.digia.com/stable/qvboxlayout.html  QVBoxLayout]. In QML these are named:
* Column arranges its children in a column
* Row arranges its children in a row
* Grid arranges its children in a grid
* Flow arranges its children like words on a page
They have a special property '''spacing'''(int) to define the distance in pixels between two children.
For furture help please look at [http://qt-project.org/doc/qt-4.8/qml-positioners.html Using QML Positioner and Repeater Items from qt-project.org]
Some example:
<syntaxhighlight lang="javascript">
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore


Item {
        Column{
                spacing: 10
                Row { 
                        spacing: 5
                        Text{text: 'Local'}
                        Text {
                                id: local
                                text: "XX:XX:XX"
                        }
                }
                Row { 
                        spacing: 5
                        Text{text: 'UTC'}
                        Text {
                                id: utc
                                text: "XX:XX:XX"
                        }
                }
        }
}
</syntaxhighlight>
==== Anchors ====
==== Anchors ====
Anchor layouts offer a nice way of grouping UI elements nicely together. The idea is that you connect edges or corners of one element to the edge or corner of another widget.
Anchor layouts offer a nice way of grouping UI elements nicely together. The idea is that you connect edges or corners of one element to the edge or corner of another widget. Available anchors are:
* left
* horizontalCenter
* right
* top
* verticalCenter
* baseline, and bottom.
 
 
Some examples:
Some examples:
<nowiki>
<syntaxhighlight lang="javascript">
import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore


import Qt 4.7
import org.kde.plasma.graphicswidgets 0.1 as PlasmaWidgets
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.graphicslayouts 4.7 as GraphicsLayouts


QGraphicsWidget {
Item {
     preferredSize: "200x300"
     width: 200
    height: 300
 


     Text {
     Text {
         id: first
         id: first
         text: i18n("1st line")
         text: i18n("1st line")
         anchors { top: parent.top;
         anchors {  
                  left: parent.left;
            top: parent.top;
                  right: parent.right;
            left: parent.left;
            right: parent.right;
         }
         }
     }
     }
Line 33: Line 89:
         id: second
         id: second
         text: i18n("2nd line")
         text: i18n("2nd line")
         anchors { top: first.bottom;
         anchors {
                  left: parent.left;
            top: first.bottom;
                  right: parent.right;
            left: parent.left;
                  bottom: parent.bottom;
            right: parent.right;
            bottom: parent.bottom;
         }
         }
     }
     }
}
}
</nowiki>
</syntaxhighlight>
 
Keep in mind, that you can only use elements that are a parent or a sibling.
 
Here a WRONG example ('first'' and ''second'' are no siblings):
 
<syntaxhighlight lang="javascript">
    Text {
        id: first
        text: i18n("1st line")
    }
    Item{
        id: breakIt
        Text {
            id: second
            text: i18n("2nd line")
            anchors {
                top: first.bottom;
            }
        }
    }
</syntaxhighlight>
Plasmoidviewer will show you the following explanation:
 
    file:///XXXX/contents/ui/main.qml:69:9: QML Text: Cannot anchor to an item that isn't a parent or sibling.
 
 
More examples you will find on the  [http://qt-project.org/doc/qt-4.8/qml-anchor-layout.html Anchor-based Layout in QML from the qt-project.org].


=== Buttons ===
=== Buttons ===
Line 46: Line 130:


=== Animations ===
=== Animations ===


== Package Structure ==
== Package Structure ==


You create a .desktop file and the .qml file. They have to be in the usual plasma package structure.
You create a .desktop file and the .qml file. They have to be in the usual Plasma package structure:


plasmoid-qml/metadata.desktop
* plasmoid-qml/metadata.desktop
plasmoid-qml/contents/ui/main.qml
* plasmoid-qml/contents/ui/main.qml


=== <tt>metadata.desktop</tt> ===
=== <tt>metadata.desktop</tt> ===
<code ini>
<syntaxhighlight lang="ini">
[Desktop Entry]
[Desktop Entry]
Name=Hello QML
Name=Hello QML
Line 79: Line 161:
X-KDE-ServiceTypes=Plasma/Applet
X-KDE-ServiceTypes=Plasma/Applet
Type=Service
Type=Service
</code>
</syntaxhighlight>
 
The line below indicates the default size of the plasmoid. The applet's starting size will be this, when added to a scene:
 
<syntaxhighlight lang="ini">
X-Plasma-DefaultSize=200,100
</syntaxhighlight>


===  <tt>main.qml</tt> ===
===  <tt>main.qml</tt> ===
<code javascript>
<syntaxhighlight lang="javascript">
import Qt 4.7
import QtQuick 1.0


Text {
Text {
     text: "Hello world!";
     text: "Hello world!";
}
}
</code>
</syntaxhighlight>


== Installing ==
== Installing ==
You can install your plasmoid:
You can install your plasmoid, though obviously this is just temporary. CMake, below, is recommended:
<syntaxhighlight lang="bash">
plasmapkg --install plasmoid-qml
plasmapkg --install plasmoid-qml
</syntaxhighlight>
=== Installation through CMake ===
In your CMakeLists.txt:
<syntaxhighlight lang="cmake">
project(helloqml)
find_package(KDE4 REQUIRED)
include(KDE4Defaults)
install(DIRECTORY package/
        DESTINATION ${DATA_INSTALL_DIR}/plasma/plasmoids/org.kde.plasma.applet.myapplet)
install(FILES package/metadata.desktop
        DESTINATION ${SERVICES_INSTALL_DIR} RENAME plasma-applet-myapplet.desktop)
</syntaxhighlight>
Your directory structure should now be as follows:
<syntaxhighlight lang="bash">
myproject/CMakeLists.txt
myproject/package/
myproject/package/metadata.desktop
myproject/package/contents/
myproject/package/contents/ui/
myproject/package/contents/ui/helloworld.qml
</syntaxhighlight>
(if you have a configuration file (.ui file) to load the right-click 'plasmoid settings' menu, then your structure will also have myproject/package/contents/config/config.ui, or so)


== plasmoidviewer ==
== plasmoidviewer ==
Line 107: Line 227:
and use everything up to org of that path.
and use everything up to org of that path.


Hovewer it's '''strongly discouraged''' to use qmlviewer to develop plasmoids, because some features won't be available there:
Hovewer it's '''strongly discouraged''' to use qmlviewer to develop plasmoids, because '''some features won't be available there, like the following''':
* localization with i18n()
* localization with i18n()
* access to the global ''plasmoid'' object
* access to the global ''plasmoid'' object
* device specific qml files imported with plasmapackage:// urls
* device specific qml files imported with plasmapackage:// urls
* bindings for qicons, KJobs, services and KConfig
* bindings for qicons, KJobs, services and KConfig
* retrieving data from a DataEngine
Therefore, it is recommended to simply use '''plasmoidviewer'''


= Features only available in Plasma widgets =
= Features only available in Plasma widgets =
In order to have a better integration with the KDE platform and to reach an higher degree of expressivity, the stock features of QML have been expanded with the following features, that strictly follow the Plasmoid JavaScript API:
In order to have a better integration with the KDE platform and to reach an higher degree of expressivity, the stock features of QML have been expanded with the following features, that strictly follow the Plasmoid JavaScript API:
== Minimum size ==
if the root object of the plasmoid has the properties minimumWidth and minimumHeight, they will be used as the minimum size for the plasmoid. If they will change during the plasmoid execution, the plasmoid minimum size will be updated accordingly.
<syntaxhighlight lang="javascript">
import QtQuick 1.0
Text {
    property int minimumWidth: paintedWidth
    property int minimumHeight: paintedHeight
    text: "Hello world!";
}
</syntaxhighlight>
In the above example, the minimum size is bound to the paintedWidth/paintedHeight properties of the Text element, ensuring there will always be enough room for the whole text to be displayed.


== Plasmoid object ==
== Plasmoid object ==
Every QML plasmoid will have an object called ''plasmoid'', that will give access to the configuration, the formfactor, immutability and so on. It offers the same api as the object with the same name in the Javascript API.
Every QML plasmoid will have an object called ''plasmoid'', that will give access to the configuration, the formfactor, immutability and so on. It offers the same api as the object with the same name in the Javascript API.
For specific info on this, see [http://techbase.kde.org/Development/Tutorials/Plasma/JavaScript/API-PlasmoidObject Javascript API-Plasmoid Object]


== Localization ==
== Localization ==
It's possible to localize strings with the usual i18n(), i18nc(), i18np() global functions
It is possible to localize strings with the usual i18n(), i18nc(), i18np() global functions.


== Extra types ==
== Extra types ==
Some extra types are available from withing JavaScript, namely
Some extra types are available from withing JavaScript, namely


* KConfigGroup: it's an object with its cnfig keys readable and writable as properties
* KConfigGroup: it's an object with its config keys readable and writable as properties
* QIcon: can be constructed with QIcon("fdo name") such as QIcon("konqueror")
* QIcon: can be constructed with QIcon("fdo name") such as QIcon("konqueror")
* KJob
* KJob
* Plasma Service api
* Plasma Service api


= Plasma specific imports =
= Plasma specific imports =
To use some Plasma specific features is necessary to use some particular QML imports.
To use some Plasma specific features and to take advantage of them in order for your applet to become a true Plasma applet, it is necessary to use some particular QML imports. See [http://techbase.kde.org/Development/Tutorials/Plasma/QML/API Plasma QML API].
 
== Plasma Core ==
org.kde.plasma.core
This is the import that lets you access to the most important Plasma Core features.
 
=== DataSource ===
Used to connect to a dataengine
 
=== DataModel ===
Attaches to a DataSource, makes possible to use a dataengine as a model for a QML ListView, GridView, PathView and so on
 
=== Svg ===
Loads a Plasma Svg, it's not the visual item
 
=== SvgItem ===
Visual item that paints a Svg
 
=== FrameSvg ===
Loads a Plasma FrameSvg, it's not the visual item.
 
=== FrameSvgItem ===
Visual item that displays a Plasma FrameSvg


== Extra Qt features ==
== Extra Qt features ==
org.kde.qtextraimports
org.kde.qtextraimports
To use, do:
<syntaxhighlight lang="javascript">
import org.kde.qtextracomponents 0.1 as QtExtraComponents
</syntaxhighlight>


* QPixmapItem
* QPixmapItem
Line 164: Line 285:


== Plasma Widgets in QML ==
== Plasma Widgets in QML ==
To use plasma widgets, you simply add an import line for them.
To use standard plasma widgets (e.g. Plasma::LineEdit, etc.), you simply add an import line for them.
All properties, signals and slots from ordinary Plasma widgets are available there.
All properties, signals and slots from ordinary Plasma widgets are available there.
Those widgets are provided as a transition tool, intended to be replaced by the Plasma version of QtComponents.
'''These widgets are provided as a transition tool, intended to be replaced by the Plasma version of QtComponents''', which is currently in development by a gsoc. (note that the Plasma QtComponents have nothing to do with the QtExtraComponents module described above)


<code javascript>
<syntaxhighlight lang="javascript">
import Qt 4.7
import QtQuick 1.0
import org.kde.plasma.graphicswidgets 0.1 as PlasmaWidgets
import org.kde.plasma.graphicswidgets 0.1 as PlasmaWidgets


Line 181: Line 302:
     }
     }
}
}
</code>
</syntaxhighlight>
To get a list of icons installed on system, run the command:
$ kdialog --geticon actions

Latest revision as of 23:27, 11 September 2014

Abstract

Writing a Plasma applet in QML is very easy, in fact, with Workspaces 4.6 and Qt 4.7 it just works.

QML Basics

It is recommended that you have read through the Qt QML Tutorials, as there are quite a few and they are explained thoroughly. There is also a list of all standard QML elements.

Essentially, most of the content is the same. The exceptions to be noted are how data is gathered... since we use Data Engines, it is a bit different. Text color and font should be made to use PlasmaCore.Theme.

See the KDE Examples repository for more KDE-related helpful resources. Also of use (which use QML and Plasma) are: Plasma Mobile, Declarative Plasmoids (playground), for WIP ports of C++ originals.

Root Item

The root item can be anything that inherits QGraphicsItem. For example, in this case it is QGraphicsWidget which is a plasmoid. It can also simply be an Item. I also noticed that PathView does not respond to mouse inputs automatically (so flicking doesn't work). Probably because events are being intercepted. So take note, it'll have to be e.g. an Item, for that case.

Layouts

Row and Column

Coloums and Rows are very easy way to grouping items and is very simular to the "normal layout management" with QHBoxLayout and QVBoxLayout. In QML these are named:

  • Column arranges its children in a column
  • Row arranges its children in a row
  • Grid arranges its children in a grid
  • Flow arranges its children like words on a page

They have a special property spacing(int) to define the distance in pixels between two children.

For furture help please look at Using QML Positioner and Repeater Items from qt-project.org

Some example:

import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore

Item { 
        Column{
                spacing: 10
                Row {  
                         spacing: 5
                        Text{text: 'Local'}
                        Text { 
                                id: local
                                text: "XX:XX:XX"
                        }
                }
                Row {  
                         spacing: 5
                        Text{text: 'UTC'}
                        Text { 
                                id: utc
                                text: "XX:XX:XX"
                        }
                }
        }
}

Anchors

Anchor layouts offer a nice way of grouping UI elements nicely together. The idea is that you connect edges or corners of one element to the edge or corner of another widget. Available anchors are:

  • left
  • horizontalCenter
  • right
  • top
  • verticalCenter
  • baseline, and bottom.


Some examples:

import QtQuick 1.0
import org.kde.plasma.core 0.1 as PlasmaCore


Item {
    width: 200
    height: 300


    Text {
        id: first
        text: i18n("1st line")
        anchors { 
            top: parent.top;
            left: parent.left;
            right: parent.right;
        }
    }
    Text {
        id: second
        text: i18n("2nd line")
        anchors {
            top: first.bottom;
            left: parent.left;
            right: parent.right;
            bottom: parent.bottom;
        }
    }
}

Keep in mind, that you can only use elements that are a parent or a sibling.

Here a WRONG example ('first and second are no siblings):

    Text {
        id: first
        text: i18n("1st line")
    }
    Item{
         id: breakIt
        Text {
            id: second
            text: i18n("2nd line")
            anchors {
                 top: first.bottom;
            }
        }
    }

Plasmoidviewer will show you the following explanation:

   file:///XXXX/contents/ui/main.qml:69:9: QML Text: Cannot anchor to an item that isn't a parent or sibling.


More examples you will find on the Anchor-based Layout in QML from the qt-project.org.

Buttons

Animations

Package Structure

You create a .desktop file and the .qml file. They have to be in the usual Plasma package structure:

  • plasmoid-qml/metadata.desktop
  • plasmoid-qml/contents/ui/main.qml

metadata.desktop

[Desktop Entry]
Name=Hello QML
Comment=A hello world widget in QML
Icon=chronometer

X-Plasma-API=declarativeappletscript
X-Plasma-MainScript=ui/main.qml
X-Plasma-DefaultSize=200,100

X-KDE-PluginInfo-Author=Frederik Gladhorn
X-KDE-PluginInfo-Email=[email protected]
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Examples
X-KDE-PluginInfo-Name=org.kde.hello-qml
X-KDE-PluginInfo-Version=0.0

X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-KDE-ServiceTypes=Plasma/Applet
Type=Service

The line below indicates the default size of the plasmoid. The applet's starting size will be this, when added to a scene:

X-Plasma-DefaultSize=200,100

main.qml

import QtQuick 1.0

Text {
    text: "Hello world!";
}

Installing

You can install your plasmoid, though obviously this is just temporary. CMake, below, is recommended:

plasmapkg --install plasmoid-qml

Installation through CMake

In your CMakeLists.txt:

project(helloqml)

find_package(KDE4 REQUIRED)

include(KDE4Defaults)

install(DIRECTORY package/
        DESTINATION ${DATA_INSTALL_DIR}/plasma/plasmoids/org.kde.plasma.applet.myapplet)

install(FILES package/metadata.desktop
        DESTINATION ${SERVICES_INSTALL_DIR} RENAME plasma-applet-myapplet.desktop)

Your directory structure should now be as follows:

myproject/CMakeLists.txt
myproject/package/
myproject/package/metadata.desktop
myproject/package/contents/
myproject/package/contents/ui/
myproject/package/contents/ui/helloworld.qml

(if you have a configuration file (.ui file) to load the right-click 'plasmoid settings' menu, then your structure will also have myproject/package/contents/config/config.ui, or so)

plasmoidviewer

You can run it in plasmoidviewer as usual: plasmoidviewer plasmoid-qml

qmlviewer

It's possible to use Plasma specific imports in qml files loaded by qmlviewer:

qmlviewer -I /usr/lib/kde4/imports/ plasmoid-qml/contents/qml/main.qml

Where the -I is the path to the plasma plugin for qml. Try to look for the path of /usr/lib/kde4/imports/org/kde/plasma/graphicswidgets/libgraphicswidgetsbindingsplugin.so and use everything up to org of that path.

Hovewer it's strongly discouraged to use qmlviewer to develop plasmoids, because some features won't be available there, like the following:

  • localization with i18n()
  • access to the global plasmoid object
  • device specific qml files imported with plasmapackage:// urls
  • bindings for qicons, KJobs, services and KConfig
  • retrieving data from a DataEngine

Therefore, it is recommended to simply use plasmoidviewer

Features only available in Plasma widgets

In order to have a better integration with the KDE platform and to reach an higher degree of expressivity, the stock features of QML have been expanded with the following features, that strictly follow the Plasmoid JavaScript API:

Minimum size

if the root object of the plasmoid has the properties minimumWidth and minimumHeight, they will be used as the minimum size for the plasmoid. If they will change during the plasmoid execution, the plasmoid minimum size will be updated accordingly.

import QtQuick 1.0

Text {
    property int minimumWidth: paintedWidth
    property int minimumHeight: paintedHeight
    text: "Hello world!";
}

In the above example, the minimum size is bound to the paintedWidth/paintedHeight properties of the Text element, ensuring there will always be enough room for the whole text to be displayed.

Plasmoid object

Every QML plasmoid will have an object called plasmoid, that will give access to the configuration, the formfactor, immutability and so on. It offers the same api as the object with the same name in the Javascript API.

For specific info on this, see Javascript API-Plasmoid Object

Localization

It is possible to localize strings with the usual i18n(), i18nc(), i18np() global functions.

Extra types

Some extra types are available from withing JavaScript, namely

  • KConfigGroup: it's an object with its config keys readable and writable as properties
  • QIcon: can be constructed with QIcon("fdo name") such as QIcon("konqueror")
  • KJob
  • Plasma Service api

Plasma specific imports

To use some Plasma specific features and to take advantage of them in order for your applet to become a true Plasma applet, it is necessary to use some particular QML imports. See Plasma QML API.

Extra Qt features

org.kde.qtextraimports To use, do:

import org.kde.qtextracomponents 0.1 as QtExtraComponents
  • QPixmapItem
  • QImageItem
  • QIconItem

Plasma Widgets in QML

To use standard plasma widgets (e.g. Plasma::LineEdit, etc.), you simply add an import line for them. All properties, signals and slots from ordinary Plasma widgets are available there. These widgets are provided as a transition tool, intended to be replaced by the Plasma version of QtComponents, which is currently in development by a gsoc. (note that the Plasma QtComponents have nothing to do with the QtExtraComponents module described above)

import QtQuick 1.0
import org.kde.plasma.graphicswidgets 0.1 as PlasmaWidgets

Item {
    width: 64
    height: 64
    PlasmaWidgets.IconWidget {
        id: icon
        Component.onCompleted: setIcon("flag-red")
        anchors.centerIn: parent
    }
}

To get a list of icons installed on system, run the command:

$ kdialog --geticon actions