├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── controls └── UC │ ├── ApplicationWindow.qml │ ├── BackgroundRectangle.qml │ ├── BusyIndicator.qml │ ├── Button.qml │ ├── ComboBox.qml │ ├── Dialog.qml │ ├── IconButton.qml │ ├── Label.qml │ ├── Menu.qml │ ├── MenuItem.qml │ ├── Page.qml │ ├── PageHeader.qml │ ├── PageStatus.js │ ├── PlatformFlickable.qml │ ├── PlatformImagePicker.qml │ ├── PlatformListView.qml │ ├── PlatformVideoPicker.qml │ ├── Popup.qml │ ├── ProgressBar.qml │ ├── Screen.qml │ ├── ScrollBar.qml │ ├── SearchField.qml │ ├── SectionHeader.qml │ ├── Slider.qml │ ├── Switch.qml │ ├── TextArea.qml │ ├── TextField.qml │ ├── TextSwitch.qml │ ├── TopMenu.qml │ ├── VerticalScrollDecorator.qml │ ├── menu.svg │ ├── qmldir │ └── style.js ├── docs └── api_spec.rst ├── glacier └── UC │ └── qmldir ├── main_qmldir ├── silica └── UC │ ├── ApplicationWindow.qml │ ├── BackgroundRectangle.qml │ ├── BusyIndicator.qml │ ├── Button.qml │ ├── ComboBox.qml │ ├── Dialog.qml │ ├── IconButton.qml │ ├── Label.qml │ ├── Menu.qml │ ├── MenuItem.qml │ ├── Page.qml │ ├── PageHeader.qml │ ├── PageStatus.js │ ├── PlatformFlickable.qml │ ├── PlatformImagePicker.qml │ ├── PlatformListView.qml │ ├── PlatformVideoPicker.qml │ ├── Popup.qml │ ├── ProgressBar.qml │ ├── Screen.qml │ ├── ScrollBar.qml │ ├── SearchField.qml │ ├── SectionHeader.qml │ ├── Slider.qml │ ├── Switch.qml │ ├── TextArea.qml │ ├── TextField.qml │ ├── TextSwitch.qml │ ├── TopMenu.qml │ ├── VerticalScrollDecorator.qml │ └── qmldir ├── sync_qmldir.sh ├── tests ├── README.rst └── tst_button.qml └── ubuntu └── UC ├── Button.qml ├── Label.qml ├── Page.qml ├── PlatformFlickable.qml ├── Slider.qml ├── Switch.qml ├── TextArea.qml ├── TextField.qml ├── VerticalScrollDecorator.qml └── qmldir /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.qmlc 3 | 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014, Martin Kolman 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | BACKEND=controls 3 | 4 | test: 5 | qmltestrunner -import ${BACKEND} -input tests/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Universal Components 2 | ==================== 3 | 4 | The Universal Components provide a QtQuick 2.0 component set 5 | with a single interface that can use different backends. 6 | 7 | Like application GUI code can be used written once and used 8 | everywhere where one of the supported backends is available. 9 | 10 | The backends take care of a native look, so the application 11 | should not only run on the given platform but also look 12 | reasonably good. 13 | 14 | Backends 15 | -------- 16 | 17 | * QtQuick Controls 2 - fully supported 18 | 19 | The QtQuick Controls are part of Qt 5 since 5.7 and are a 20 | fully supported UC backend. Therefore any application 21 | using UC should run with just Qt 5.7+ being available. 22 | 23 | * Sailfish Silica - fully supported 24 | 25 | The default component set of Sailfish OS by Jolla. 26 | 27 | * Nemo Mobile Glacier - planed 28 | 29 | 30 | How does it work 31 | ---------------- 32 | 33 | Universal Components provide a unified interface with all supported backends. 34 | This is represented by a qmldir file and the elements themselves. 35 | 36 | All individual backends have the same qmldirs and the same elements that 37 | also provide the same properties and function. 38 | 39 | All platform specific functionality that is deemed worthwhile & doable 40 | is reimplemented in the other backends so that it can be part of the 41 | unified interface. 42 | 43 | Usage 44 | ----- 45 | 46 | First you need to make sure the UC directory you want to use is in your 47 | QML plugin search path. Uhen just import the UC plugin and use the provided 48 | elements: 49 | 50 | import UC 1.0 51 | 52 | If you can't manipulate your QML plugin import path, you can also import the 53 | UC plugin directly: 54 | 55 | import "./UC" 56 | 57 | API Documentation 58 | ----------------- 59 | 60 | Universal Components API documentation is available in the [docs/api_spec.rst](docs/api_spec.rst) 61 | file. 62 | 63 | Component usage notes 64 | --------------------- 65 | 66 | **PlatformFlickable** and **PlatformListView** 67 | 68 | These two components provide access to enhanced platform specific Flickables 69 | and ListViews (SilicaListView has fast scroll support, etc.). 70 | With backends that don't have such enhancements a normal Flickable or ListView 71 | is used. 72 | 73 | **TopMenu** 74 | 75 | The TopMenu element provides a multi platform menu that will generally be shown 76 | somewhere at the top of a Page using the appropriate native presentation method. 77 | Currently this translates to a PullDownMenu with with the Silica backend and to 78 | a Menu in popup mode with Controls. In the future the advanced Glacier pull down 79 | menu should also be supported. 80 | 81 | The easiest way to use the TopMenu is to place PageHeader on top of your Page 82 | and assing the TopMenu into its *menu* property: 83 | 84 | ```QML 85 | import UC 1.0 86 | Page { 87 | PageHeader { 88 | anchors.top : parent.top 89 | menu : TopMenu { 90 | MenuItem { 91 | text : "option 1" 92 | onClicked : {console.log("1 clicked!")} 93 | } 94 | MenuItem { 95 | text : "option 2" 96 | onClicked : {console.log("2 clicked!")} 97 | } 98 | } 99 | } 100 | } 101 | ``` 102 | 103 | The top menu makes sure that the TopMenu can be activated when needed, either in a 104 | platform specific way (pull down gesture with Silica) or by showing a button 105 | (with Controls). 106 | 107 | The TopMenu can be also used inside the PlatformFlickable or PlatformListView, 108 | but users will need to provide custom triggering for the TopMenu (calling its popup() method) 109 | when not using the Silica backend. 110 | 111 | 112 | Applications using Universal Components 113 | ------------------------------------- 114 | 115 | * [modRana flexible navigation system](https://github.com/M4rtinK/modrana) 116 | * [Tsubame flexible Twitter client](https://github.com/M4rtinK/tsubame) 117 | * [the Tensor Matrix client](https://github.com/davidar/tensor) 118 | 119 | 120 | TODO 121 | ---- 122 | 123 | * Glacier backend 124 | 125 | 126 | LICENSE 127 | ------- 128 | 129 | Universal Components are distributed under the terms of the [3-clause BSD license](http://opensource.org/licenses/BSD-3-Clause). 130 | -------------------------------------------------------------------------------- /controls/UC/ApplicationWindow.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | import QtQuick.Window 2.0 3 | 4 | import "style.js" as S 5 | 6 | ApplicationWindow { 7 | id : appWindow 8 | // report if the application wide window is in portrait 9 | property bool inPortrait : Screen.orientation == Qt.PortraitOrientation || 10 | Screen.orientation == Qt.InvertedPortraitOrientation 11 | 12 | // report if the application wide window is in an inverted orientation 13 | property bool inverted : Screen.orientation == Qt.InvertedPortraitOrientation || 14 | Screen.orientation == Qt.InvertedLandscape 15 | 16 | // The whole QtQuick Controls ApplicationWindow rotates on orientation change. 17 | // This is a difference from for example the Sailfish Silica ApplicationWindow, 18 | // where only the pages on the stack rotate, which creates some serious difficulties 19 | // for implementation of top level content, such as notification bubbles. 20 | property bool rotatesOnOrientationChange : true 21 | 22 | //property alias initialPage : pageStack.initialItem 23 | property alias pageStack : pageStack 24 | 25 | property int hiDPI : 0 26 | 27 | StackView { 28 | anchors.fill : parent 29 | id : pageStack 30 | 31 | 32 | onCurrentItemChanged: { 33 | //currentItem.forceActiveFocus() 34 | currentItem.focus = true 35 | } 36 | } 37 | 38 | function pushPage(pageInstance, pageProperties, animate) { 39 | // the Controls page stack disables animations when 40 | // false is passed as the third argument, but we want to 41 | // have a more logical interface, so just invert the value 42 | // before passing it to the page stack 43 | pageStack.push(pageInstance, pageProperties, !animate) 44 | return pageInstance 45 | } 46 | 47 | // reload the style table if the hiDPI setting is changed 48 | // NOTE: this should probably happen before the elements 49 | // start using the style table 50 | onHiDPIChanged : { 51 | S.style = S.getStyle(appWindow.hiDPI) 52 | } 53 | } -------------------------------------------------------------------------------- /controls/UC/BackgroundRectangle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | import "style.js" as S 4 | 5 | MouseArea { 6 | id : bMouse 7 | property string highlightedColor: "darkblue" 8 | property string normalColor : "#92aaf3" 9 | property int cornerRadius : S.style.listView.cornerRadius 10 | // make it possible to simulate pressed state even if not physically pressed 11 | property bool pressed_override : false 12 | property int borderWidth : 0 13 | property color borderColor : "lightgray" 14 | 15 | implicitHeight: S.style.dialog.item.height 16 | Rectangle { 17 | anchors.fill : parent 18 | property bool clickable : false 19 | color: bMouse.pressed || pressed_override ? highlightedColor : normalColor 20 | border.width : borderWidth 21 | border.color : borderColor 22 | radius : cornerRadius 23 | antialiasing : cornerRadius != 0 24 | } 25 | } -------------------------------------------------------------------------------- /controls/UC/BusyIndicator.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | BusyIndicator{} -------------------------------------------------------------------------------- /controls/UC/Button.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | import QtQuick.Controls.Styles 1.0 3 | 4 | Button{ 5 | //style: ButtonStyle {} 6 | } -------------------------------------------------------------------------------- /controls/UC/ComboBox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | import "style.js" as S 4 | 5 | Column { 6 | id : comboColumn 7 | property alias label : comboLabel.text 8 | property alias model : cBox.model 9 | property alias item : cBox.item 10 | property alias currentItem : cBox.currentItem 11 | property alias currentIndex : cBox.currentIndex 12 | property string description : "" 13 | width : parent.width 14 | 15 | Row { 16 | // no spacing if the label is empty, so that the combobox 17 | // can be used as a standalone label-less combobox 18 | spacing : comboLabel.text ? S.style.main.spacing : 0 19 | property var bar : S.foo 20 | Label { 21 | id : comboLabel 22 | } 23 | ComboBox { 24 | id : cBox 25 | textRole : "text" 26 | displayText : qsTranslate("ComboBox", currentText) 27 | anchors.verticalCenter : comboLabel.verticalCenter 28 | // selected item, only assigned if user 29 | // clicks on an item in the context menu, 30 | // not if changing the current item index 31 | property var item 32 | // changes active item 33 | // without triggering the 34 | // the on current item changed signal 35 | property int currentItem 36 | 37 | property bool _skipNext : false 38 | 39 | onModelChanged : { 40 | _skipNext = true 41 | } 42 | 43 | onCurrentItemChanged : { 44 | // skip next onCurrentIndexChanged 45 | _skipNext = true 46 | currentIndex = currentItem 47 | } 48 | 49 | onCurrentIndexChanged: { 50 | // currentIndex is changed if a new model 51 | // is assigned, so we need to ignore the signal 52 | // once every time a new model is assigned 53 | if (_skipNext) { 54 | _skipNext = false 55 | } else { 56 | // assign selected item to the item 57 | // property, so that the onItemChanged 58 | // signal is triggered 59 | cBox.item = cBox.model.get(currentIndex) 60 | } 61 | } 62 | } 63 | } 64 | Label { 65 | text : comboColumn.description 66 | wrapMode : Text.Wrap 67 | width : parent.width 68 | font.italic : true 69 | } 70 | } -------------------------------------------------------------------------------- /controls/UC/Dialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | Dialog { 4 | } -------------------------------------------------------------------------------- /controls/UC/IconButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | import QtQuick.Controls.Styles 1.0 3 | 4 | Button{ 5 | style: ButtonStyle {} 6 | } -------------------------------------------------------------------------------- /controls/UC/Label.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | Label { 4 | } -------------------------------------------------------------------------------- /controls/UC/Menu.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | Menu{ 4 | function popup() { 5 | open() 6 | } 7 | } -------------------------------------------------------------------------------- /controls/UC/MenuItem.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | MenuItem{ 4 | signal clicked 5 | onTriggered : { 6 | clicked() 7 | } 8 | } -------------------------------------------------------------------------------- /controls/UC/Page.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | 4 | Page { 5 | property bool isActive : StackView.status == StackView.Active 6 | property bool isInactive : StackView.status == StackView.Inactive 7 | property bool isActivating : StackView.status == StackView.Activating 8 | property bool isDeactivating : StackView.status == StackView.Deactivating 9 | // true if the page ever was on the page stack, if manually 10 | // set to false will be set to true next time the page lands 11 | // on the page stack 12 | property bool wasOnPageStack : false 13 | // true if the page is currently on the page stack 14 | property bool isOnPageStack : StackView.view != null 15 | onIsOnPageStackChanged : { 16 | if (!wasOnPageStack && isOnPageStack) { 17 | wasOnPageStack = true 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /controls/UC/PageHeader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | import "style.js" as S 4 | 5 | Label { 6 | id : headerLabel 7 | property string title : "" 8 | text : title 9 | property int titlePixelSize : 48 * S.style.m 10 | property int headerHeight : height/8.0 11 | property real backButtonW : menu ? headerHeight * 0.8 : headerHeight * 0.8 * 2 12 | property bool _fitsIn : (paintedWidth <= (parent.width-backButtonW+(40 * S.style.m))) 13 | anchors.verticalCenter : parent.verticalCenter 14 | x: _fitsIn ? 0 : backButtonW + 24 * S.style.m 15 | width : _fitsIn ? parent.width : parent.width - backButtonW - 40 * S.style.m 16 | anchors.right : parent.right 17 | anchors.topMargin : S.style.main.spacing 18 | anchors.bottomMargin : S.style.main.spacing 19 | font.pixelSize : titlePixelSize 20 | textFormat : Text.StyledText 21 | wrapMode : Text.NoWrap 22 | horizontalAlignment : _fitsIn ? Text.AlignHCenter : Text.AlignLeft 23 | property var menu : null 24 | property bool menuButtonEnabled : true 25 | signal _openMenu 26 | Button { 27 | visible : menuButtonEnabled && headerLabel.menu 28 | anchors.right : parent.right 29 | anchors.rightMargin : 8 * S.style.m 30 | anchors.verticalCenter : parent.verticalCenter 31 | width : backButtonW 32 | height : backButtonW 33 | Image { 34 | smooth : true 35 | source : "menu.svg" 36 | anchors.verticalCenter : parent.verticalCenter 37 | anchors.horizontalCenter : parent.horizontalCenter 38 | width : backButtonW * 0.6 39 | height : backButtonW * 0.6 40 | } 41 | onClicked : { 42 | if (headerLabel.menu) { 43 | headerLabel.menu.popup() 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /controls/UC/PageStatus.js: -------------------------------------------------------------------------------- 1 | var Inactive = 0 2 | var Activating = 1 3 | var Active = 2 4 | var Deactivating = 3 5 | var foo = ".harmattan/" 6 | -------------------------------------------------------------------------------- /controls/UC/PlatformFlickable.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | 4 | Flickable { 5 | } -------------------------------------------------------------------------------- /controls/UC/PlatformImagePicker.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Dialogs 1.0 4 | 5 | FileDialog { 6 | id : imagePicker 7 | 8 | folder : shortcuts.pictures 9 | 10 | property var selectedFiles : [] 11 | 12 | onAccepted: { 13 | console.log("PlatformImagePicker: you chose: " + imagePicker.fileUrls) 14 | selectedFiles = imagePicker.fileUrls 15 | } 16 | onRejected: { 17 | console.log("PlatformImagePicker: canceled") 18 | } 19 | 20 | function run() { 21 | // similar to old-school dialogs with their 22 | // own exposed mainloop, let's just start this 23 | // thing with a run() method 24 | imagePicker.visible = true 25 | } 26 | } -------------------------------------------------------------------------------- /controls/UC/PlatformListView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | 4 | ListView { 5 | ScrollBar.vertical : ScrollBar {} 6 | } -------------------------------------------------------------------------------- /controls/UC/PlatformVideoPicker.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Dialogs 1.0 4 | 5 | FileDialog { 6 | id : imagePicker 7 | 8 | folder : shortcuts.movies 9 | 10 | property var selectedFiles : [] 11 | 12 | onAccepted: { 13 | console.log("PlatformVideoPicker: you chose: " + imagePicker.fileUrls) 14 | selectedFiles = imagePicker.fileUrls 15 | } 16 | onRejected: { 17 | console.log("PlatformVideoPicker: canceled") 18 | } 19 | 20 | function run() { 21 | // similar to old-school dialogs with their 22 | // own exposed mainloop, let's just start this 23 | // thing with a run() method 24 | imagePicker.visible = true 25 | } 26 | } -------------------------------------------------------------------------------- /controls/UC/Popup.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import "style.js" as S 3 | 4 | MouseArea { 5 | id: popup 6 | anchors.top: parent.top 7 | anchors.horizontalCenter: parent.horizontalCenter 8 | width: parent.width 9 | height: message.paintedHeight + (S.style.main.spacingBig * 1) 10 | property alias title: message.text 11 | property alias timeout: hideTimer.interval 12 | property alias background: bg.color 13 | visible: opacity > 0 14 | opacity: 0.0 15 | 16 | property color _defaultColor : "orange" 17 | 18 | Behavior on opacity { 19 | // the FadeAnimation silica equals to this 20 | NumberAnimation { 21 | duration: 200 22 | easing.type: Easing.InOutQuad 23 | property: "opacity" 24 | } 25 | } 26 | 27 | Rectangle { 28 | id: bg 29 | anchors.fill: parent 30 | } 31 | 32 | Timer { 33 | id: hideTimer 34 | triggeredOnStart: false 35 | repeat: false 36 | interval: 5000 37 | onTriggered: popup.hide() 38 | } 39 | 40 | function hide() { 41 | if (hideTimer.running) 42 | hideTimer.stop() 43 | popup.opacity = 0.0 44 | } 45 | 46 | function show() { 47 | popup.opacity = 1.0 48 | hideTimer.restart() 49 | } 50 | 51 | function notify(text, color) { 52 | popup.title = text 53 | if (color && (typeof(color) != "undefined")) 54 | bg.color = color 55 | else 56 | bg.color = Qt.rgba(_defaultColor.r, _defaultColor.g, _defaultColor.b, 0.9) 57 | show() 58 | } 59 | 60 | Label { 61 | id: message 62 | anchors.verticalCenter: popup.verticalCenter 63 | font.pixelSize: 32 64 | anchors.left: parent.left 65 | anchors.leftMargin: S.style.spacingBig 66 | anchors.right: parent.right 67 | anchors.rightMargin: S.style.spacing 68 | horizontalAlignment: Text.AlignHCenter 69 | elide: Text.ElideRight 70 | wrapMode: Text.Wrap 71 | } 72 | 73 | onClicked: hide() 74 | } 75 | -------------------------------------------------------------------------------- /controls/UC/ProgressBar.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | ProgressBar{ 4 | } -------------------------------------------------------------------------------- /controls/UC/Screen.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | 4 | Item{ 5 | width : 800 6 | height : 600 7 | } -------------------------------------------------------------------------------- /controls/UC/ScrollBar.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | 4 | ScrollBar { 5 | } -------------------------------------------------------------------------------- /controls/UC/SearchField.qml: -------------------------------------------------------------------------------- 1 | //SearchField.qml 2 | 3 | import QtQuick.Controls 2.0 4 | 5 | TextField{ 6 | } -------------------------------------------------------------------------------- /controls/UC/SectionHeader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | 4 | Label { 5 | text : sectionHeader.text 6 | font.bold : true 7 | anchors.horizontalCenter : parent.horizontalCenter 8 | } 9 | -------------------------------------------------------------------------------- /controls/UC/Slider.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | Slider{ 4 | id : slider 5 | property string valueText : "" 6 | property alias minimumValue : slider.from 7 | property alias maximumValue : slider.to 8 | } -------------------------------------------------------------------------------- /controls/UC/Switch.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 // needs Qt 5.2 2 | 3 | Switch{ 4 | } -------------------------------------------------------------------------------- /controls/UC/TextArea.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | TextArea{ 4 | } -------------------------------------------------------------------------------- /controls/UC/TextField.qml: -------------------------------------------------------------------------------- 1 | import QtQuick.Controls 2.0 2 | 3 | TextField{ 4 | } -------------------------------------------------------------------------------- /controls/UC/TextSwitch.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | import "style.js" as S 4 | 5 | Item { 6 | id: container 7 | 8 | height: label.height 9 | width : parent.width 10 | 11 | property alias text: label.text 12 | property alias checked: switcher.checked 13 | 14 | Label { 15 | id: label 16 | anchors { 17 | top: parent.top 18 | left: parent.left 19 | right: switcher.left 20 | rightMargin: S.style.main.spacingBig 21 | } 22 | } 23 | 24 | Switch { 25 | id: switcher 26 | anchors { 27 | right: parent.right 28 | verticalCenter: parent.verticalCenter 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /controls/UC/TopMenu.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | 4 | Menu { 5 | x : parent.width - width 6 | modal : true 7 | function popup() { 8 | open() 9 | } 10 | } -------------------------------------------------------------------------------- /controls/UC/VerticalScrollDecorator.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQuick.Controls 2.0 3 | 4 | // A scroll decorator working in a similar way to the Silica VerticalStrollDecorator, 5 | // but based on the QtQuick Controls 2 Scroll bar (which, like other new QQC2 elements 6 | // really looks to be Silica inspired). 7 | // 8 | // NOTE: This is just scroll decorator. If you want to scroll bar that can be dragged to 9 | // move the view content use the ScrollBar UC element. 10 | 11 | ScrollBar { 12 | function findFlickable(item) { 13 | var parentItem = item.parent 14 | while (parentItem) { 15 | if (parentItem.maximumFlickVelocity) { 16 | return parentItem 17 | } 18 | parentItem = parentItem.parent 19 | } 20 | return null 21 | } 22 | 23 | id: vbar 24 | hoverEnabled: true 25 | active: hovered || pressed || flickable.flickingVertically 26 | orientation: Qt.Vertical 27 | size: flickable.height / flickable.contentHeight 28 | anchors.top: parent.top 29 | anchors.right: parent.right 30 | anchors.bottom: parent.bottom 31 | property Flickable flickable : findFlickable(vbar) 32 | 33 | 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /controls/UC/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 44 | 46 | 47 | 49 | image/svg+xml 50 | 52 | 53 | 54 | 55 | 56 | 61 | 65 | 70 | 73 | 76 | 80 | 86 | 87 | 88 | 89 | 90 | 95 | 98 | 101 | 105 | 111 | 112 | 113 | 114 | 115 | 120 | 123 | 126 | 130 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /controls/UC/qmldir: -------------------------------------------------------------------------------- 1 | module UC 2 | Button 1.0 Button.qml 3 | IconButton 1.0 IconButton.qml 4 | ApplicationWindow 1.0 ApplicationWindow.qml 5 | Page 1.0 Page.qml 6 | PageHeader 1.0 PageHeader.qml 7 | Screen 1.0 Screen.qml 8 | ProgressBar 1.0 ProgressBar.qml 9 | Slider 1.0 Slider.qml 10 | Switch 1.0 Switch.qml 11 | TextSwitch 1.0 TextSwitch.qml 12 | Label 1.0 Label.qml 13 | TextArea 1.0 TextArea.qml 14 | TextField 1.0 TextField.qml 15 | SearchField 1.0 SearchField.qml 16 | Dialog 1.0 Dialog.qml 17 | PageStatus 1.0 PageStatus.js 18 | ComboBox 1.0 ComboBox.qml 19 | Menu 1.0 Menu.qml 20 | TopMenu 1.0 TopMenu.qml 21 | MenuItem 1.0 MenuItem.qml 22 | BackgroundRectangle 1.0 BackgroundRectangle.qml 23 | VerticalScrollDecorator 1.0 VerticalScrollDecorator.qml 24 | Popup 1.0 Popup.qml 25 | PlatformFlickable 1.0 PlatformFlickable.qml 26 | PlatformListView 1.0 PlatformListView.qml 27 | PlatformImagePicker 1.0 PlatformImagePicker.qml 28 | PlatformVideoPicker 1.0 PlatformVideoPicker.qml 29 | ScrollBar 1.0 ScrollBar.qml 30 | SectionHeader 1.0 SectionHeader.qml 31 | BusyIndicator 1.0 BusyIndicator.qml 32 | -------------------------------------------------------------------------------- /controls/UC/style.js: -------------------------------------------------------------------------------- 1 | .pragma library 2 | 3 | var hiDPI = 0 4 | var style = getStyle(hiDPI) 5 | 6 | function getStyle(i) { 7 | return { 8 | "m" : [1, 2][i], // approximate size multiplier 9 | "main" : { 10 | "multiplier" : [1, 2][i], 11 | "spacing" : [8, 16][i], 12 | "spacingBig" : [16, 32][i] 13 | }, 14 | "dialog" : { 15 | "item" : { 16 | "height" : [80, 160][i] 17 | } 18 | }, 19 | "listView" : { 20 | "spacing" : [8, 16][i], 21 | "cornerRadius" : [8, 16][i], 22 | "itemBorder" : [20, 40][i], 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docs/api_spec.rst: -------------------------------------------------------------------------------- 1 | Universal Components API reference 2 | ********************************** 3 | 4 | .. contents:: 5 | :depth: 2 6 | 7 | Introduction 8 | ============ 9 | 10 | This document specifies the unified API provided by Universal Components. 11 | Names of the provided elements as well as their properties, signals and methods are listed. 12 | 13 | If a backend provides all elements listed in this document with all listed properties, 14 | signals and methods it can be considered as fully supporting the UC API. 15 | 16 | 17 | Elements 18 | ======== 19 | 20 | Button 21 | ------ 22 | 23 | A button with text label. 24 | 25 | Properties 26 | ^^^^^^^^^^ 27 | 28 | **text** : string 29 | The button label. 30 | 31 | **pressed** : bool 32 | True if button is pressed, else false. 33 | 34 | Signals 35 | ^^^^^^^ 36 | 37 | **clicked()** 38 | Triggered when the button has been clicked. 39 | 40 | 41 | IconButton 42 | ---------- 43 | 44 | A button with an image instead of text. 45 | 46 | Properties 47 | ^^^^^^^^^^ 48 | 49 | **iconSource** : url 50 | URL to the icon image to be shown on the button. 51 | 52 | **pressed** : bool 53 | True if button is pressed, else false. 54 | 55 | Signals 56 | ^^^^^^^ 57 | 58 | **clicked()** 59 | Triggered when the button has been clicked. 60 | 61 | 62 | ApplicationWindow 63 | ----------------- 64 | 65 | The main application window. 66 | 67 | Properties 68 | ^^^^^^^^^^ 69 | 70 | **title** : string 71 | Window title - will be displayed on window header on platforms that have one. 72 | 73 | **inProtrait** : bool 74 | True if the application window is in portrait, else false (landscape). 75 | 76 | **inverted** : bool 77 | True if the application window is in inverted portrait or inverted landscape, else false. 78 | 79 | **rotatesOnOrientationChange** : bool 80 | True if the *ApplicationWindow* itself rotates on device orientation change, else not. 81 | 82 | In general even if the *ApplicationWindow* does not rotate, the page stack and it's content does. 83 | 84 | At the moment: 85 | 86 | - QtQuick Controls *ApplicationWindow* rotates 87 | - Sailfish silica *ApplicationWindow* does not rotate 88 | 89 | **pageStack** : native page stack 90 | This property provides access to the native page stack - currently *StackView* 91 | for the Controls backend and *PageStack* for the Silica backend. 92 | While both elements share a considerable amount of properties and methods 93 | (push(), pop(), clear(), find(), the busy property, etc.), they are not 94 | 100% API compatible and even the method signatures might differ. 95 | And it is also possible that a future backend might introduce yet another 96 | page stack implementation with yet another slightly different API. 97 | 98 | 99 | Methods 100 | ^^^^^^^ 101 | 102 | **pushPage**\(Item *pageInstance*, object *pageProperties*, bool *animate*) 103 | Push *pageInstance* to the page stack. The optional *properties* parameter specifies 104 | a map of properties to be set on the page. The *animate* parameter controls if the 105 | page push should be animated (true) or not (false). 106 | Also note that the **pushPage()** method returns the page instance that has been pushed. 107 | 108 | 109 | Page 110 | ---- 111 | 112 | The Page type provides a container for the contents of a single page within an application. 113 | 114 | Properties 115 | ^^^^^^^^^^ 116 | 117 | **isActive** : bool 118 | This property reports if the given page is the current active page - it is visible 119 | and can be interacted with. 120 | A few things to note about the **isActive** property: 121 | 122 | - stays true even if device screen is turned off with Silica backend 123 | - it has not yet been tested if the same thing happens with Controls 2 on Android 124 | 125 | If you want stop processing when *the application* is not active, use the 126 | *Qt.application.state* property, possibly combined with the **isActive** 127 | page property. 128 | 129 | **isInactive** : bool 130 | If true the page is not the active page, is not visible and can't be interacted with. 131 | 132 | **isActivating** : bool 133 | If true the page is about to become the currently active page. 134 | 135 | **isDeactivating** : bool 136 | If true the page is about to become inactive. 137 | 138 | **wasOnPageStack** : bool 139 | If true the page was at least once on the application page stack. If reset from 140 | true to false will be true agan next time the page is put on the page stack. 141 | 142 | **isOnPageStack** : bool 143 | If true the page is currently on the application page stack. 144 | 145 | PageHeader 146 | ---------- 147 | 148 | A header for use in a Page. 149 | 150 | Properties 151 | ^^^^^^^^^^ 152 | 153 | **title** : string 154 | The text to display in the header. 155 | 156 | **color** : color 157 | Header color. 158 | 159 | **titlePixelSize** : int 160 | Pixel size of the title text. 161 | 162 | **headerHeight**: int 163 | Height of the header in pixels. 164 | 165 | NOTE: The **color**, **headerHeight** and **titlePixelSize** properties currently 166 | don't do anything effect with the Silica backend and are provided for compatibility 167 | with the Controls backed PageHeader, where all these properties are effective. 168 | 169 | 170 | Screen 171 | ------ 172 | 173 | Provides device display attributes. 174 | 175 | Properties 176 | ^^^^^^^^^^ 177 | 178 | **width** : int 179 | Display width. 180 | 181 | **heigh** : int 182 | Display height. 183 | 184 | NOTE: Currently with the Controls backend **width** is always 800 185 | and **height** is always 600. 186 | 187 | 188 | ProgressBar 189 | ----------- 190 | 191 | A progress indicator. 192 | 193 | Properties 194 | ^^^^^^^^^^ 195 | 196 | **indeterminate** : real 197 | This property toggles indeterminate mode. When the actual progress is unknown, 198 | use this option. The progress bar will be animated as a busy indicator instead. 199 | The default value is false. 200 | 201 | **maximumValue** : real 202 | The maximum value of the progress bar (default: 1.0). 203 | 204 | **minimumValue** : real 205 | The minimum value of the progress bar (default: 0.0) 206 | 207 | **value** : real 208 | The current value of the progress bar. 209 | 210 | BusyIndicator 211 | ------------- 212 | 213 | Indicates background activity, for example, while content is being loaded. 214 | 215 | Properties 216 | ^^^^^^^^^^ 217 | 218 | **running** : bool 219 | This property holds whether the busy indicator is currently indicating activity. 220 | 221 | Slider 222 | ------ 223 | 224 | A horizontal slider. 225 | 226 | Properties 227 | ^^^^^^^^^^ 228 | 229 | **maximumValue** : real 230 | This property holds the maximum value of the slider. The default value is 1.0. 231 | 232 | **minimumValue** : real 233 | This property holds the minimum value of the slider. The default value is 0.0. 234 | 235 | **stepSize** : real 236 | This property indicates the slider step size. 237 | 238 | A value of 0 indicates that the value of the slider operates in a continuous range between minimumValue and maximumValue. 239 | 240 | Any non 0 value indicates a discrete stepSize. The following example will generate a slider with integer values in the range [0-5]. 241 | 242 | :: 243 | 244 | Slider { 245 | maximumValue: 5.0 246 | stepSize: 1.0 247 | } 248 | 249 | The default value is 0.0. 250 | 251 | **value**: real 252 | This property holds the current value of the slider. The default value is 0.0. 253 | 254 | **pressed** : bool 255 | True if the slider is being pressed, else false. 256 | 257 | 258 | Switch 259 | ------ 260 | 261 | A Switch is a toggle button that can be switched on (checked) or off (unchecked). 262 | 263 | Properties 264 | ^^^^^^^^^^ 265 | 266 | **checked** : bool 267 | This property is true if the control is checked. The default value is false. 268 | 269 | 270 | TextSwitch 271 | ---------- 272 | 273 | Like a **Switch**, but with a text label. 274 | 275 | Properties 276 | ^^^^^^^^^^ 277 | 278 | **checked** : bool 279 | This property is true if the control is checked. The default value is false. 280 | 281 | **text** : string 282 | The text shown alongside the switch. 283 | 284 | 285 | Label 286 | ----- 287 | 288 | In addition to the normal QtQuick 2 **Text** element, Label follows the font and color scheme of the given platform. 289 | Use the text property to assign a text to the label. For other properties check the **Text** element. 290 | 291 | Properties 292 | ^^^^^^^^^^ 293 | 294 | **text** : string 295 | Text to be displayed on the label. 296 | 297 | SectionHeader 298 | ------------- 299 | 300 | Heading text for the start of a section on a page. Uses the **SectionHeader** element with Silica backend 301 | and a bold horizontally centered **Label** with the Controls backend. 302 | 303 | Properties 304 | ^^^^^^^^^^ 305 | 306 | **text** : string 307 | Text to be displayed on the section header. 308 | 309 | TextArea 310 | -------- 311 | 312 | Displays multiple lines of editable formatted text. 313 | 314 | The **TextArea** width and height should generally be set, otherwise the area will be sized to fit the entered text. 315 | 316 | Properties 317 | ^^^^^^^^^^ 318 | 319 | **text** : string 320 | The text to be displayed in the **TextArea**. 321 | 322 | **readOnly** : bool 323 | Holds whether the text field is in read-only mode. 324 | If set to true, the user cannot edit the text. 325 | 326 | **validator** : Validator 327 | A Validator that validates any entered text. By default, a text field does not have a validator. 328 | 329 | **acceptableInput** : bool 330 | Returns true if the text field contains acceptable text. 331 | 332 | If a validator was set, this property will return true if the current text satisfies the validator as a final string (not as an intermediate string). 333 | 334 | The default value is true. 335 | 336 | **wrapMode** : enumeration 337 | Set this property to wrap the text to the TextEdit item's width. The text will only wrap if an explicit width has been set. 338 | 339 | - **TextEdit.NoWrap** - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width. 340 | - **TextEdit.WordWrap** - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width. 341 | - **TextEdit.WrapAnywhere** - wrapping is done at any point on a line, even if it occurs in the middle of a word. 342 | - **TextEdit.Wrap** - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word. 343 | 344 | The default is **TextEdit.NoWrap**. If you set a width, consider using **TextEdit.Wrap**. 345 | 346 | **selectByMouse** : bool 347 | If true, the user can use the mouse to select text in some platform-specific way. 348 | 349 | NOTE: The selectByMouse property has no effect on Sailfish OS, but can be safely set 350 | for compatibility purposes. 351 | 352 | The default value is false. 353 | 354 | TODO: The *assured* API currently provided by UC for the **TextArea** is quite basic at the moment and it would 355 | be a good idea to extend it in the future - while keeping requirements realistic given backend variations. 356 | 357 | 358 | TextField 359 | --------- 360 | 361 | Displays a single line of editable plain text. 362 | 363 | 364 | Properties 365 | ^^^^^^^^^^ 366 | 367 | **text** : string 368 | The text to be displayed in the **TextField** 369 | 370 | **placeholderText** : string 371 | This property contains the text that is shown in the text field when the text field is empty. 372 | 373 | **readOnly** : bool 374 | Holds whether the text field is in read-only mode. 375 | If set to true, the user cannot edit the text. 376 | 377 | **validator** : Validator 378 | A Validator that validates any entered text. By default, a text field does not have a validator. 379 | 380 | **acceptableInput** : bool 381 | Returns true if the text field contains acceptable text. 382 | 383 | If a validator was set, this property will return true if the current text satisfies the validator 384 | as a final string (not as an intermediate string). 385 | 386 | The default value is true. 387 | 388 | 389 | TODO: The *assured* API currently provided by UC for the **TextField** is quite basic at the moment and it would 390 | be a good idea to extend it in the future - while keeping requirements realistic given backend variations. 391 | 392 | 393 | SearchField 394 | ----------- 395 | 396 | A text field for entering a text search query. 397 | 398 | NOTE: Currently this provides access to a native **SearchField** (has a search & clear buttons) on Silica and is 399 | just a normal **TextField** on Controls. It might be a good idea to add the clear buttons also on Controls and 400 | other backends that don't provide a native **SearchField** equivalent. 401 | 402 | Properties 403 | ^^^^^^^^^^ 404 | 405 | **text** : string 406 | The text to be displayed in the **TextField** 407 | 408 | **readOnly** : bool 409 | Holds whether the text field is in read-only mode. 410 | If set to true, the user cannot edit the text. 411 | 412 | **validator** : Validator 413 | A Validator that validates any entered text. By default, a text field does not have a validator. 414 | 415 | **acceptableInput** : bool 416 | Returns true if the text field contains acceptable text. 417 | 418 | If a validator was set, this property will return true if the current text satisfies the validator 419 | as a final string (not as an intermediate string). 420 | 421 | The default value is true. 422 | 423 | 424 | Dialog 425 | ------ 426 | 427 | A dialog element. 428 | 429 | TODO: Specify a common UC dialog API. 430 | 431 | Properties 432 | ^^^^^^^^^^ 433 | 434 | **TBD** 435 | 436 | Signals 437 | ^^^^^^^ 438 | 439 | **TBD** 440 | 441 | Methods 442 | ^^^^^^^ 443 | 444 | **TBD** 445 | 446 | 447 | ComboBox 448 | -------- 449 | 450 | A combo box control for selecting from a list of options. 451 | 452 | Menu items are added with a **ListModel** to the 453 | model property, which dynamically adds them to the 454 | context menu. Once an item is clicked, its underlying 455 | **ListElement** is returned so *onCurrentItemChanged* 456 | is triggered. 457 | 458 | Example: 459 | 460 | :: 461 | 462 | ComboBox { 463 | currentIndex: 2 464 | model: ListModel { 465 | id: cbItems 466 | ListElement { text: "Banana"; color: "Yellow" } 467 | ListElement { text: "Apple"; color: "Green" } 468 | ListElement { text: "Coconut"; color: "Brown" } 469 | } 470 | width: 200 471 | onCurrentIndexChanged: console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) 472 | } 473 | 474 | The Universal Components **ComboBox** also supports localization via the *QT_TRANSLATE_NOOP* macro 475 | with a *"ComboBox"* context. Using just the *QT_TR_NOOP* macro would give the string context 476 | of the file where it has been found, which would not work as the **ComboBox** element is defined 477 | in a different file. 478 | 479 | **ComboBox** localization example: 480 | 481 | :: 482 | 483 | ComboBox { 484 | currentIndex: 1 485 | model: ListModel { 486 | id: cbItems 487 | ListElement { text: QT_TRANSLATE_NOOP("ComboBox", "foo"); color: "white" } 488 | ListElement { text: QT_TRANSLATE_NOOP("ComboBox", "bar"); color: "black" } 489 | } 490 | width: 200 491 | onCurrentIndexChanged: console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) 492 | } 493 | 494 | Two strings - "foo" and "bar" will be marked for translation with the *"ComboBox"* context, 495 | which makes sure the qsTranslate() call in the **ComboBox** implementation matches them correctly. 496 | 497 | Properties 498 | ^^^^^^^^^^ 499 | 500 | **label** : string 501 | A short single-line label describing the combobox. 502 | 503 | **description** : string 504 | A longer (possibly multi-line) description of the combo-box. Can be useful 505 | for describing the currently selected element by switching between description 506 | texts when the selected item changes. 507 | 508 | **model** : var 509 | Data model for the **ComboBox**. 510 | 511 | **currentIndex** : int 512 | Index of the selected item in the data model. 513 | 514 | **currentItem** : var 515 | Currently selected item. 516 | 517 | 518 | TopMenu 519 | ------- 520 | 521 | The **TopMenu** element provides a multi platform menu that will generally be shown somewhere 522 | at the top of a Page using the appropriate native presentation method. 523 | Currently this translates to a **PullDownMenu** with with the Silica backend and to a Menu in popup 524 | mode with Controls. In the future the advanced Glacier pull down menu should also be supported. 525 | 526 | The easiest way to use the **TopMenu** is to place **PageHeader** into a **PlatformFlickable** or 527 | **PlatformListView** in your **Page** and assign the **TopMenu** into its menu property: 528 | 529 | :: 530 | 531 | import UC 1.0 532 | Page { 533 | PlatformFlickable { 534 | PageHeader { 535 | anchors.top : parent.top 536 | menu : TopMenu { 537 | MenuItem { 538 | text : "option 1" 539 | onClicked : {console.log("1 clicked!")} 540 | } 541 | MenuItem { 542 | text : "option 2" 543 | onClicked : {console.log("2 clicked!")} 544 | } 545 | } 546 | } 547 | } 548 | } 549 | 550 | The top menu makes sure that the **TopMenu** can be activated when needed, 551 | either in a platform specific way (pull down gesture with Silica) or by showing a 552 | button (with Controls). 553 | 554 | The **TopMenu** can be also used inside a standalone **PlatformFlickable** or **PlatformListView**, 555 | but users will need to provide custom triggering for the **TopMenu** (calling its popup() method) 556 | when not using the Silica backend. 557 | 558 | Methods 559 | ^^^^^^^ 560 | 561 | **popup**\() 562 | Opens the menu. 563 | 564 | NOTE: Only actually does something on the Controls backend and is currently provided 565 | in onther backends only due to API compatibility. 566 | 567 | 568 | MenuItem 569 | -------- 570 | 571 | A menu item for use with the **TopMenu**. 572 | 573 | Properties 574 | ^^^^^^^^^^ 575 | 576 | **text** : string 577 | Text displayed in the menu item. 578 | 579 | Signals 580 | ^^^^^^^ 581 | 582 | **clicked()** 583 | Triggered when the Menu item has been clicked. 584 | 585 | 586 | BackgroundRectangle 587 | ------------------- 588 | 589 | A simple item inheriting **MouseArea** that can be used as 590 | as a clickable background item with press highlighting for 591 | items in a **ListView**, special buttons or other interactive 592 | user interface elements. 593 | 594 | When when preset, the color of the **BackgroundRectangle** 595 | will switch to **highlightedColor** and back to **NormalColor** 596 | when no longer pressed. 597 | 598 | Properties 599 | ^^^^^^^^^^ 600 | 601 | **highlightedColor** : color 602 | Color used when the background rectangle is pressed. 603 | 604 | **normalColor** : color 605 | Color used when the background rectangle is not pressed. 606 | 607 | **borderColor** : color 608 | Color of the background rectangle border (if any). 609 | 610 | **borderWidth** : int 611 | Width of the border rectangle border. 612 | 613 | The default value is 0 (no border). 614 | 615 | **cornerRadius** : int 616 | Radius of the background rectangle corner radius. 617 | 618 | NOTE: cornerRadius != 0 enables antialiasing for the given background rectangle, 619 | which is generally needed to make round corners look reasonably good in 620 | most cases 621 | 622 | The default value is 0 (right angle corners). 623 | 624 | **pressed_override** : bool 625 | Makes it possible to simulate pressed state even if background rectangle is not physically pressed. 626 | 627 | VerticalScrollDecorator 628 | ----------------------- 629 | 630 | Adds a vertical scroll decorator to flickables and list views. 631 | 632 | Example: 633 | 634 | :: 635 | 636 | ListView { 637 | id: listView 638 | model: myModel 639 | delegate: myDelegate 640 | 641 | VerticalScrollDecorator {} 642 | } 643 | 644 | Scrollbar 645 | --------- 646 | 647 | Adds a vertical scroll decorator to flickables and list views. 648 | 649 | NOTE: Currently only provides functional scroll bar with the Controls backend, 650 | the Silica implementation is just an API compatible shim without any functionality. 651 | 652 | Example: 653 | 654 | :: 655 | 656 | ListView { 657 | id: listView 658 | model: myModel 659 | delegate: myDelegate 660 | 661 | VerticalScrollDecorator {} 662 | } 663 | 664 | Properties 665 | ^^^^^^^^^^ 666 | 667 | **horizontal** : Scrollbar 668 | Used to automatically attach a horizontal Scrollbar to a Flickable. 669 | 670 | **vertical** : Scrollbar 671 | Used to automatically attach a horizontal Scrollbar to a Flickable. 672 | 673 | Popup 674 | ----- 675 | 676 | A notification popup. 677 | 678 | NOTE: The popup will automatically close when clicked. 679 | 680 | Properties 681 | ^^^^^^^^^^ 682 | 683 | **title** : string 684 | Text of the notification popup. 685 | 686 | **timeout** : int 687 | How long should the popup by displayed in milliseconds. 688 | The default value is 5000 milliseconds. 689 | 690 | **background** : color 691 | Color of the notification popup background. 692 | 693 | Methods 694 | ^^^^^^^ 695 | 696 | **hide**\() 697 | Hides the popup. 698 | 699 | **show**\() 700 | Shows the popup. 701 | 702 | **notify**\(text, color) 703 | A shortcut function for showing a popup notification with given **text** and **color**. 704 | 705 | 706 | PlatformFlickable 707 | ----------------- 708 | 709 | This element provide access to an enhanced platform specific flickable (**SilicaFlickable** can have a pull-down menu attached, etc.). 710 | With backends that don't have such enhancements a normal Flickable is used. 711 | 712 | 713 | PlatformListView 714 | ---------------- 715 | 716 | This element provide access to an enhanced platform specific list view (**SilicaListView** has fast scroll support, etc.). 717 | With backends that don't have such enhancements a normal ListView is used. 718 | 719 | PlatformImagePicker 720 | ------------------- 721 | 722 | This element provides access to a platform specific multiple image picker. A common API is provided, but applications 723 | might in some cases want to use the detailed platforms specific API that might not always be possible to fully abstract. 724 | 725 | **selectedFiles** : array 726 | An array containing *file://* URLs of the selected files. 727 | 728 | **selectMultiple** : bool 729 | Controls if multiple images can be selected. The default value is false. 730 | 731 | Methods 732 | ^^^^^^^ 733 | 734 | **run**\() 735 | Shows the image picker. Depending on the platform, this might manifest as separate picker dialog window showing up 736 | or a picker page being pushed to the page stack. 737 | 738 | 739 | PlatformVideoPicker 740 | ------------------- 741 | 742 | This element provides access to a platform specific multiple video picker. A common API is provided, but applications 743 | might in some cases want to use the detailed platforms specific API that might not always be possible to fully abstract. 744 | 745 | **selectedFiles** : array 746 | An array containing *file://* URLs of the selected files. 747 | 748 | **selectMultiple** : bool 749 | Controls if multiple videos can be selected. The default value is false. 750 | 751 | Methods 752 | ^^^^^^^ 753 | 754 | **run**\() 755 | Shows the video picker. Depending on the platform, this might manifest as separate picker dialog window showing up 756 | or a picker page being pushed to the page stack. 757 | 758 | 759 | Adding a new element 760 | ==================== 761 | 762 | When a new element is to be added to Universal Components, the following actions should be done: 763 | 764 | - add the element to all backends or at least to as many as possible 765 | - add the element the **qmldir** files for all backend where it was added 766 | - add the element specification to this document, but only if supported by all non-experimental backends 767 | 768 | Backends currently considered non-experimental: 769 | 770 | - Controls 771 | - Silica 772 | 773 | Experimental backends: 774 | 775 | - Glacier 776 | - Ubuntu Components 777 | 778 | 779 | Adding a new element property/signal/method 780 | =========================================== 781 | 782 | When a new property/signal/method is to be added to the Universal Component API, 783 | it should be added to the element in all backends if possible. 784 | 785 | If should be also added to this document, but only if implemented by all non-experimental 786 | backends (see the section above for a list of non-experimental backends). 787 | -------------------------------------------------------------------------------- /glacier/UC/qmldir: -------------------------------------------------------------------------------- 1 | module UC 2 | Button 1.0 Button.qml 3 | IconButton 1.0 IconButton.qml 4 | ApplicationWindow 1.0 ApplicationWindow.qml 5 | Page 1.0 Page.qml 6 | PageHeader 1.0 PageHeader.qml 7 | Screen 1.0 Screen.qml 8 | ProgressBar 1.0 ProgressBar.qml 9 | Slider 1.0 Slider.qml 10 | Switch 1.0 Switch.qml 11 | TextSwitch 1.0 TextSwitch.qml 12 | Label 1.0 Label.qml 13 | TextArea 1.0 TextArea.qml 14 | TextField 1.0 TextField.qml 15 | SearchField 1.0 SearchField.qml 16 | Dialog 1.0 Dialog.qml 17 | PageStatus 1.0 PageStatus.js 18 | ComboBox 1.0 ComboBox.qml 19 | Menu 1.0 Menu.qml 20 | TopMenu 1.0 TopMenu.qml 21 | MenuItem 1.0 MenuItem.qml 22 | BackgroundRectangle 1.0 BackgroundRectangle.qml 23 | VerticalScrollDecorator 1.0 VerticalScrollDecorator.qml 24 | Popup 1.0 Popup.qml 25 | PlatformFlickable 1.0 PlatformFlickable.qml 26 | PlatformListView 1.0 PlatformListView.qml 27 | -------------------------------------------------------------------------------- /main_qmldir: -------------------------------------------------------------------------------- 1 | module UC 2 | Button 1.0 Button.qml 3 | IconButton 1.0 IconButton.qml 4 | ApplicationWindow 1.0 ApplicationWindow.qml 5 | Page 1.0 Page.qml 6 | PageHeader 1.0 PageHeader.qml 7 | Screen 1.0 Screen.qml 8 | ProgressBar 1.0 ProgressBar.qml 9 | Slider 1.0 Slider.qml 10 | Switch 1.0 Switch.qml 11 | TextSwitch 1.0 TextSwitch.qml 12 | Label 1.0 Label.qml 13 | TextArea 1.0 TextArea.qml 14 | TextField 1.0 TextField.qml 15 | SearchField 1.0 SearchField.qml 16 | Dialog 1.0 Dialog.qml 17 | PageStatus 1.0 PageStatus.js 18 | ComboBox 1.0 ComboBox.qml 19 | Menu 1.0 Menu.qml 20 | TopMenu 1.0 TopMenu.qml 21 | MenuItem 1.0 MenuItem.qml 22 | BackgroundRectangle 1.0 BackgroundRectangle.qml 23 | VerticalScrollDecorator 1.0 VerticalScrollDecorator.qml 24 | Popup 1.0 Popup.qml 25 | PlatformFlickable 1.0 PlatformFlickable.qml 26 | PlatformListView 1.0 PlatformListView.qml 27 | -------------------------------------------------------------------------------- /silica/UC/ApplicationWindow.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | ApplicationWindow{ 4 | property bool inPortrait : deviceOrientation == Orientation.Portrait || 5 | deviceOrientation == Orientation.PortraitInverted 6 | property bool inverted : deviceOrientation == Orientation.PortraitInverted || 7 | deviceOrientation == Orientation.LandscapeInverted 8 | 9 | // The whole Silica ApplicationWindow does not rotate on orientation change. 10 | // This is a difference from for example the Qt Quick Controls ApplicationWindow, 11 | // where the whole Window rotates. 12 | property bool rotatesOnOrientationChange : false 13 | 14 | cover : null 15 | 16 | function orientationToString(o) { 17 | switch (o) { 18 | case Orientation.Portrait: 19 | return "portrait" 20 | case Orientation.Landscape: 21 | return "landscape" 22 | case Orientation.PortraitInverted: 23 | return "inverted portrait" 24 | case Orientation.LandscapeInverted: 25 | return "inverted landscape" 26 | } 27 | return "unknown" 28 | } 29 | 30 | onDeviceOrientationChanged : { 31 | var orientationName = orientationToString(deviceOrientation) 32 | console.log("device orientation changed to: " + orientationName + " (" + deviceOrientation + ")") 33 | } 34 | 35 | // this property is provided for API compatibility 36 | // as the Silica UC backend uses the Silica built-in 37 | // element sizing 38 | property int hiDPI : 0 39 | 40 | // the Silica ApplicationWindow 41 | // does not inherit the Window element, 42 | // so we need to add some properties 43 | // for a common API with Controls 44 | property string title 45 | property var visibility : 5 46 | 47 | function pushPage(pageInstance, pageProperties, animate) { 48 | var animateFlag 49 | if (animate) { 50 | animateFlag = PageStackAction.Animated 51 | } else { 52 | animateFlag = PageStackAction.Immediate 53 | } 54 | pageStack.push(pageInstance, pageProperties, animateFlag) 55 | return pageInstance 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /silica/UC/BackgroundRectangle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | MouseArea { 4 | id : bMouse 5 | property color highlightedColor: Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity) 6 | property string normalColor : "transparent" 7 | property alias cornerRadius : bRectangle.radius 8 | // make it possible to simulate pressed state even if not physically pressed 9 | property bool pressed_override : false 10 | property int borderWidth : 0 11 | property color borderColor : Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity) 12 | implicitHeight: Theme.itemSizeSmall 13 | Rectangle { 14 | id :bRectangle 15 | anchors.fill : parent 16 | property bool clickable : false 17 | color: bMouse.pressed || pressed_override ? highlightedColor : normalColor 18 | border.width : borderWidth 19 | border.color : borderColor 20 | radius : cornerRadius 21 | antialiasing : cornerRadius != 0 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /silica/UC/BusyIndicator.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | BusyIndicator {} -------------------------------------------------------------------------------- /silica/UC/Button.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | Button {} -------------------------------------------------------------------------------- /silica/UC/ComboBox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | 4 | ComboBox { 5 | id : cBox 6 | labelMargin : 0 7 | // selected item, only assigned if user 8 | // clicks on an item in the context menu, 9 | // not if changing the current item index 10 | property var item 11 | 12 | menu : ContextMenu { 13 | id : cMenu 14 | Repeater { 15 | id : cRepeater 16 | model : cBox.model 17 | MenuItem { 18 | text : qsTranslate("ComboBox", model.text) 19 | onClicked : { 20 | cBox.currentItem = model 21 | } 22 | } 23 | } 24 | } 25 | property var model 26 | // how does this work ? 27 | // 28 | // Menu items are added with a ListModel to the 29 | // model property, which dynamically adds them to the 30 | // context menu. Once an item is clicked, its underlying 31 | // ListElement is returned so onCurrentItemChanged 32 | // is triggered. 33 | 34 | onCurrentIndexChanged: { 35 | // assign selected item to the item 36 | // property, so that the onItemChanged 37 | // signal is triggered 38 | cBox.item = cBox.model.get(currentIndex) 39 | } 40 | } -------------------------------------------------------------------------------- /silica/UC/Dialog.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | Dialog { 3 | } -------------------------------------------------------------------------------- /silica/UC/IconButton.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | IconButton { 4 | property string iconSource : "" 5 | property bool checkable : false 6 | property bool checked : false 7 | onIconSourceChanged : { 8 | icon.source = iconSource 9 | } 10 | } -------------------------------------------------------------------------------- /silica/UC/Label.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | Label { 3 | } -------------------------------------------------------------------------------- /silica/UC/Menu.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | ContextMenu{ 4 | } -------------------------------------------------------------------------------- /silica/UC/MenuItem.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | MenuItem{ 4 | } -------------------------------------------------------------------------------- /silica/UC/Page.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | Page { 4 | allowedOrientations : Orientation.All 5 | property bool isActive : status == PageStatus.Active 6 | property bool isInactive : status == PageStatus.Inactive 7 | property bool isActivating : status == PageStatus.Activating 8 | property bool isDeactivating : status == PageStatus.Deactivating 9 | // track if page page ever was and still is on the page stack 10 | property bool wasOnPageStack : false 11 | property bool isOnPageStack : pageContainer != null 12 | onIsOnPageStackChanged : { 13 | if (!wasOnPageStack && isOnPageStack) { 14 | wasOnPageStack = true 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /silica/UC/PageHeader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | 4 | PageHeader { 5 | id : pageHeader 6 | // NOTE: The color, headerHeight and titlePixelSize 7 | // properties actually don't have effect and 8 | // are provided for compatibility with the 9 | // Controls backed PageHeader where all these 10 | // properties *are* effective. 11 | property color color 12 | property int headerHeight 13 | property int titlePixelSize 14 | property bool menuButtonEnabled : true 15 | // NOTE: The PageHeader needs to be placed in a PlatformFlickable 16 | // or PlatformListView for the menu to work correctly. 17 | property alias menu : pageHeader.children 18 | } -------------------------------------------------------------------------------- /silica/UC/PageStatus.js: -------------------------------------------------------------------------------- 1 | var Inactive = 0 2 | var Activating = 1 3 | var Active = 2 4 | var Deactivating = 3 5 | //TODO: check if the values are 6 | // match the Silica page status 7 | -------------------------------------------------------------------------------- /silica/UC/PlatformFlickable.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | SilicaFlickable { 3 | } -------------------------------------------------------------------------------- /silica/UC/PlatformImagePicker.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Pickers 1.0 3 | 4 | Item { 5 | id : imagePicker 6 | 7 | property var selectedFiles : [] 8 | property bool selectMultiple : false 9 | 10 | Component { 11 | id: multiImagePickerDialog 12 | MultiImagePickerDialog { 13 | onAccepted: { 14 | var urls = [] 15 | for (var i = 0; i < selectedContent.count; ++i) { 16 | var url = selectedContent.get(i).url 17 | // Handle url upload 18 | urls.push(selectedContent.get(i).url) 19 | } 20 | selectedFiles = urls 21 | } 22 | 23 | onRejected: selectedFiles = [] 24 | } 25 | } 26 | 27 | Component { 28 | id: singleImagePickerDialog 29 | ImagePickerPage { 30 | onSelectedContentPropertiesChanged: { 31 | var urls = [] 32 | urls.push(selectedContentProperties.filePath) 33 | selectedFiles = urls 34 | } 35 | } 36 | } 37 | 38 | function run() { 39 | // similar to old-school dialogs with their 40 | // own exposed mainloop, let's just start this 41 | // thing with a run() method 42 | if (selectMultiple) { 43 | rWin.pushPage(multiImagePickerDialog) 44 | } else { 45 | rWin.pushPage(singleImagePickerDialog) 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /silica/UC/PlatformListView.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | SilicaListView { 3 | VerticalScrollDecorator {} 4 | } -------------------------------------------------------------------------------- /silica/UC/PlatformVideoPicker.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Pickers 1.0 3 | 4 | Item { 5 | id : imagePicker 6 | 7 | property var selectedFiles : [] 8 | property bool selectMultiple : false 9 | 10 | Component { 11 | id: multiVideoPickerDialog 12 | MultiVideoPickerDialog { 13 | onAccepted: { 14 | var urls = [] 15 | for (var i = 0; i < selectedContent.count; ++i) { 16 | var url = selectedContent.get(i).url 17 | urls.push(selectedContent.get(i).url) 18 | } 19 | selectedFiles = urls 20 | } 21 | 22 | onRejected: selectedFiles = [] 23 | } 24 | } 25 | 26 | Component { 27 | id: singleVideoPickerDialog 28 | VideoPickerPage { 29 | onSelectedContentPropertiesChanged: { 30 | var urls = [] 31 | urls.push(selectedContentProperties.filePath) 32 | selectedFiles = urls 33 | } 34 | } 35 | } 36 | 37 | function run() { 38 | // similar to old-school dialogs with their 39 | // own exposed mainloop, let's just start this 40 | // thing with a run() method 41 | if (selectMultiple) { 42 | rWin.pushPage(multiVideoPickerDialog) 43 | } else { 44 | rWin.pushPage(singleVideoPickerDialog) 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /silica/UC/Popup.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import Sailfish.Silica 1.0 3 | 4 | MouseArea { 5 | id: popup 6 | anchors.top: parent.top 7 | anchors.horizontalCenter: parent.horizontalCenter 8 | width: parent.width 9 | height: message.paintedHeight + (Theme.paddingLarge * 2) 10 | property alias title: message.text 11 | property alias timeout: hideTimer.interval 12 | property alias background: bg.color 13 | visible: opacity > 0 14 | opacity: 0.0 15 | 16 | Behavior on opacity { 17 | FadeAnimation {} 18 | } 19 | 20 | Rectangle { 21 | id: bg 22 | anchors.fill: parent 23 | } 24 | 25 | Timer { 26 | id: hideTimer 27 | triggeredOnStart: false 28 | repeat: false 29 | interval: 5000 30 | onTriggered: popup.hide() 31 | } 32 | 33 | function hide() { 34 | if (hideTimer.running) 35 | hideTimer.stop() 36 | popup.opacity = 0.0 37 | } 38 | 39 | function show() { 40 | popup.opacity = 1.0 41 | hideTimer.restart() 42 | } 43 | 44 | function notify(text, color) { 45 | popup.title = text 46 | if (color && (typeof(color) != "undefined")) 47 | bg.color = color 48 | else 49 | bg.color = Theme.rgba(Theme.secondaryHighlightColor, 0.9) 50 | show() 51 | } 52 | 53 | Label { 54 | id: message 55 | anchors.verticalCenter: popup.verticalCenter 56 | anchors.left: parent.left 57 | anchors.leftMargin: Theme.paddingLarge 58 | anchors.right: parent.right 59 | anchors.rightMargin: Theme.paddingRight 60 | horizontalAlignment: Text.AlignHCenter 61 | elide: Text.ElideRight 62 | wrapMode: Text.Wrap 63 | } 64 | 65 | onClicked: hide() 66 | } -------------------------------------------------------------------------------- /silica/UC/ProgressBar.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | ProgressBar{ 3 | } -------------------------------------------------------------------------------- /silica/UC/Screen.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | Screen{ 3 | } -------------------------------------------------------------------------------- /silica/UC/ScrollBar.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | Item { 4 | property var horizontal 5 | property var vertical 6 | 7 | //TODO: implement this (this could actually be pretty useful as other than the rudimentary 8 | // fast scroll bar there is nothing comparable to a scroll bar in Silica) 9 | } -------------------------------------------------------------------------------- /silica/UC/SearchField.qml: -------------------------------------------------------------------------------- 1 | //SearchField.qml 2 | 3 | import Sailfish.Silica 1.0 4 | 5 | SearchField{ 6 | } -------------------------------------------------------------------------------- /silica/UC/SectionHeader.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | SectionHeader{} -------------------------------------------------------------------------------- /silica/UC/Slider.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | Slider{ 3 | } -------------------------------------------------------------------------------- /silica/UC/Switch.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | Switch{ 3 | } -------------------------------------------------------------------------------- /silica/UC/TextArea.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | TextArea{ 3 | property bool selectByMouse : false 4 | } -------------------------------------------------------------------------------- /silica/UC/TextField.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | TextField{ 3 | } -------------------------------------------------------------------------------- /silica/UC/TextSwitch.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | TextSwitch{ 4 | } -------------------------------------------------------------------------------- /silica/UC/TopMenu.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | PullDownMenu { 4 | 5 | // The popup function does nothing and is only there 6 | // for API compatibility - the Controls TopMenu needs 7 | // popup() to be called if used without a PageHeader 8 | // to open the menu. So we also provide a dummy popup() 9 | // function here with silica so that code that expects 10 | // that TopMenu has a popup() method does not break. 11 | function popup() {} 12 | } -------------------------------------------------------------------------------- /silica/UC/VerticalScrollDecorator.qml: -------------------------------------------------------------------------------- 1 | import Sailfish.Silica 1.0 2 | 3 | VerticalScrollDecorator{ 4 | } 5 | -------------------------------------------------------------------------------- /silica/UC/qmldir: -------------------------------------------------------------------------------- 1 | module UC 2 | Button 1.0 Button.qml 3 | IconButton 1.0 IconButton.qml 4 | ApplicationWindow 1.0 ApplicationWindow.qml 5 | Page 1.0 Page.qml 6 | PageHeader 1.0 PageHeader.qml 7 | Screen 1.0 Screen.qml 8 | ProgressBar 1.0 ProgressBar.qml 9 | Slider 1.0 Slider.qml 10 | Switch 1.0 Switch.qml 11 | TextSwitch 1.0 TextSwitch.qml 12 | Label 1.0 Label.qml 13 | TextArea 1.0 TextArea.qml 14 | TextField 1.0 TextField.qml 15 | SearchField 1.0 SearchField.qml 16 | Dialog 1.0 Dialog.qml 17 | PageStatus 1.0 PageStatus.js 18 | ComboBox 1.0 ComboBox.qml 19 | Menu 1.0 Menu.qml 20 | TopMenu 1.0 TopMenu.qml 21 | MenuItem 1.0 MenuItem.qml 22 | BackgroundRectangle 1.0 BackgroundRectangle.qml 23 | VerticalScrollDecorator 1.0 VerticalScrollDecorator.qml 24 | Popup 1.0 Popup.qml 25 | PlatformFlickable 1.0 PlatformFlickable.qml 26 | PlatformListView 1.0 PlatformListView.qml 27 | PlatformImagePicker 1.0 PlatformImagePicker.qml 28 | PlatformVideoPicker 1.0 PlatformVideoPicker.qml 29 | ScrollBar 1.0 ScrollBar.qml 30 | SectionHeader 1.0 SectionHeader.qml 31 | BusyIndicator 1.0 BusyIndicator.qml 32 | -------------------------------------------------------------------------------- /sync_qmldir.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # The universal components provide 3 | # a set of platform specific compatibility modules 4 | # that all need to have the exact same qmldir file. 5 | # This script copies the main qmldir to the all the 6 | # platform specific modules, so they don't have to be 7 | # kept in sync manually. 8 | # 9 | # 10 | # Note: If you add a new compatibility module, 11 | # add it here. 12 | 13 | cp main_qmldir controls/UC/qmldir 14 | cp main_qmldir silica/UC/qmldir 15 | cp main_qmldir glacier/UC/qmldir 16 | cp main_qmldir ubuntu/UC/qmldir 17 | -------------------------------------------------------------------------------- /tests/README.rst: -------------------------------------------------------------------------------- 1 | Running tests 2 | ============= 3 | 4 | This file documents how to run the unit tests for different backends. 5 | 6 | Controls 7 | -------- 8 | 9 | First make sure you have make and qmltestrunner installed. 10 | 11 | Then just run: 12 | 13 | :: 14 | 15 | make test 16 | 17 | 18 | Silica 19 | ------ 20 | 21 | At the moment we expect the unit tests to be run on a Sailfish OS 22 | device. First become root ad install the needed dependencies: 23 | 24 | :: 25 | 26 | pkcon install make qt5-qtdeclarative-qtquicktest qt5-qtdeclarative-import-qttest qt5-qtdeclarative-devel-tools 27 | 28 | Then run the tests via the makefile & pointing to the silica backend: 29 | 30 | :: 31 | 32 | make test BACKEND=silica 33 | -------------------------------------------------------------------------------- /tests/tst_button.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtTest 1.1 3 | import UC 1.0 4 | 5 | TestCase { 6 | name: "Test the Button" 7 | 8 | Button { 9 | id : button 10 | text : "foo" 11 | onClicked : { 12 | console.log("foo") 13 | } 14 | } 15 | 16 | function test_Button() { 17 | compare(button.text, "foo") 18 | compare(button.pressed, false) 19 | // check the onClicked property exists 20 | verify(button.onClicked) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ubuntu/UC/Button.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | 3 | Button {} 4 | -------------------------------------------------------------------------------- /ubuntu/UC/Label.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | Label { 3 | } 4 | -------------------------------------------------------------------------------- /ubuntu/UC/Page.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | 3 | Page { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ubuntu/UC/PlatformFlickable.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | 3 | Flickable { 4 | clip: true 5 | } 6 | -------------------------------------------------------------------------------- /ubuntu/UC/Slider.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | Slider{ 3 | } 4 | -------------------------------------------------------------------------------- /ubuntu/UC/Switch.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | Switch{ 3 | } 4 | -------------------------------------------------------------------------------- /ubuntu/UC/TextArea.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | 3 | TextArea { 4 | } 5 | -------------------------------------------------------------------------------- /ubuntu/UC/TextField.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | TextField{ 3 | } 4 | -------------------------------------------------------------------------------- /ubuntu/UC/VerticalScrollDecorator.qml: -------------------------------------------------------------------------------- 1 | import Ubuntu.Components 1.3 2 | 3 | Scrollbar { 4 | flickableItem: parent 5 | align: Qt.AlignTrailing 6 | } 7 | -------------------------------------------------------------------------------- /ubuntu/UC/qmldir: -------------------------------------------------------------------------------- 1 | module UC 2 | Button 1.0 Button.qml 3 | Page 1.0 Page.qml 4 | Slider 1.0 Slider.qml 5 | Switch 1.0 Switch.qml 6 | Label 1.0 Label.qml 7 | TextArea 1.0 TextArea.qml 8 | TextField 1.0 TextField.qml 9 | VerticalScrollDecorator 1.0 VerticalScrollDecorator.qml 10 | PlatformFlickable 1.0 PlatformFlickable.qml 11 | 12 | --------------------------------------------------------------------------------