├── AUTHORS.md
├── LICENSE
├── README.md
├── examples
├── app
│ ├── DialogsPage.qml
│ ├── app.pro
│ ├── app.qmlproject
│ ├── deployment.pri
│ ├── icons
│ │ ├── apps.svg
│ │ ├── arrow_back.svg
│ │ ├── done.svg
│ │ ├── hamburger.svg
│ │ └── more_vert.svg
│ ├── main.cpp
│ ├── main.qml
│ └── qml.qrc
└── examples.pro
├── modules
├── Mut
│ ├── AppBar.qml
│ ├── ApplicationWindow.qml
│ ├── Card.qml
│ ├── DebugOutline.qml
│ ├── Device.qml
│ ├── Dialog.qml
│ ├── Divider.qml
│ ├── Icon.qml
│ ├── Layouts
│ │ ├── ConditionalLayout.qml
│ │ ├── DeviceLayout.qml
│ │ ├── OrientationLayout.qml
│ │ └── qmldir
│ ├── ListItems
│ │ ├── DoubleLineItem.qml
│ │ ├── ListView.qml
│ │ ├── SingleLineItem.qml
│ │ ├── Tile.qml
│ │ └── qmldir
│ ├── NavDrawer.qml
│ ├── Page.qml
│ ├── Paper.qml
│ ├── Popup.qml
│ ├── Scrim.qml
│ ├── Styles
│ │ ├── ActionButtonStyle.qml
│ │ ├── BaseButtonStyle.qml
│ │ ├── BaseTextFieldStyle.qml
│ │ ├── CheckBoxStyle.qml
│ │ ├── FlatButtonStyle.qml
│ │ ├── FloatingTextFieldStyle.qml
│ │ ├── NormalTextFieldStyle.qml
│ │ ├── ProgressBarStyle.qml
│ │ ├── RaisedButtonStyle.qml
│ │ ├── SwitchStyle.qml
│ │ ├── ToolBarStyle.qml
│ │ ├── ToolButtonStyle.qml
│ │ └── qmldir
│ ├── Surface.qml
│ ├── TextField.qml
│ ├── Themes
│ │ ├── ButtonPalette.qml
│ │ ├── CheckBoxPalette.qml
│ │ ├── ElementPalette.qml
│ │ ├── Palette.qml
│ │ ├── SwitchPalette.qml
│ │ ├── TextFieldPalette.qml
│ │ ├── Theme.qml
│ │ └── qmldir
│ ├── ToolBar.qml
│ ├── qmldir
│ └── units.qml
└── modules.pro
├── mut.pro
└── tests
├── test.svg
├── tests.cpp
├── tests.pro
├── tests.qrc
├── tst_appbar.qml
├── tst_application_window.qml
├── tst_button_style.qml
├── tst_card.qml
├── tst_conditional_layout.qml
├── tst_device_layout.qml
├── tst_divider.qml
├── tst_icon.qml
├── tst_navdrawer.qml
├── tst_orientation_layout.qml
├── tst_page.qml
├── tst_paper.qml
├── tst_scrim.qml
├── tst_single_line_item.qml
├── tst_theme.qml
├── tst_tile.qml
├── tst_toolbar.qml
└── tst_units.qml
/AUTHORS.md:
--------------------------------------------------------------------------------
1 | Authors
2 | -------
3 |
4 | * Federico Frenguelli
5 | * Emanuele Palazzetti
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Evonove
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MUT
2 |
3 | **M**UT **U**i **T**oolkit is a Qt/QML components collection, based on Google [Material Design specifications][1].
4 | Using a theme centric approach you can improve the look and feel of your applications using the default material theme, or
5 | you can apply any customization according to your application brand.
6 |
7 | [1]: http://www.google.it/design/spec/material-design/introduction.html
8 |
9 | ## Implemented components
10 |
11 | At the moment, the following high-level components are provided:
12 |
13 | * [standard and floating buttons][2]
14 | * [cards][3]
15 | * [dialogs][4]
16 | * [list views with primary and secondary actions][5]
17 | * [menus][6]
18 | * [standard and floating labels textfield][7]
19 | * [actions toolbar][8]
20 |
21 | Any missing component will be released soon according to our roadmap.
22 |
23 | [2]: http://www.google.it/design/spec/components/buttons.html
24 | [3]: http://www.google.it/design/spec/components/cards.html
25 | [4]: http://www.google.it/design/spec/components/dialogs.html
26 | [5]: http://www.google.it/design/spec/components/lists.html
27 | [6]: http://www.google.it/design/spec/components/menus.html
28 | [7]: http://www.google.it/design/spec/components/text-fields.html
29 | [8]: http://www.google.it/design/spec/components/toolbars.html
30 |
31 | ## Roadmap
32 |
33 | * provide a high-level documentation for material components APIs
34 | * provide a step-by-step tutorial that shows how to install and configure MUT
35 | * provide a low-level documentation for material components (such as Tiles) for major customizations
36 | * provide all missing material components
37 |
38 | The project is currently in alpha stage and will be available for **release late 2015 - early 2016**.
39 |
40 | ## License
41 |
42 | MUT Ui Toolkit is released under the terms of the **MIT license**. Full details in `LICENSE` file.
43 |
--------------------------------------------------------------------------------
/examples/app/DialogsPage.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3 as Q
3 | import Mut 0.1
4 | import Mut.Styles 0.1
5 |
6 | Page {
7 | id: root
8 | title: qsTr("Dialogs")
9 |
10 | Paper {
11 | anchors.fill: parent
12 |
13 | Q.Button {
14 | text: "open dialog"
15 | style: RaisedButtonStyle {}
16 | onClicked: dialogRoot.open()
17 | }
18 | }
19 |
20 | Dialog {
21 | id: dialogRoot
22 |
23 | dialogComponent: Card {
24 | implicitWidth: __column.implicitWidth + Units.dp(48)
25 | implicitHeight: __column.implicitHeight + Units.dp(24)
26 |
27 | Column {
28 | id: __column
29 | anchors {
30 | fill: parent
31 | topMargin: Units.dp(24)
32 | leftMargin: Units.dp(24)
33 | rightMargin: Units.dp(24)
34 | }
35 | Text {
36 | text: qsTr("This is a dialog example")
37 | }
38 | TextField {
39 | id: nameField
40 | placeholderText: qsTr("Enter some text")
41 | style: NormalTextFieldStyle {}
42 | }
43 |
44 | Row {
45 | Q.Button {
46 | text: qsTr("ok")
47 | style: FlatButtonStyle {}
48 | onClicked: dialogRoot.close()
49 | }
50 | Q.Button {
51 | text: qsTr("cancel")
52 | style: FlatButtonStyle {}
53 | onClicked: dialogRoot.close()
54 | }
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/examples/app/app.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 |
3 | QT += qml quick widgets svg
4 |
5 | SOURCES += main.cpp
6 |
7 | RESOURCES += qml.qrc
8 |
9 | include(deployment.pri)
10 |
11 | QML_IMPORT_PATH += $$OUT_PWD/../../modules
12 |
--------------------------------------------------------------------------------
/examples/app/app.qmlproject:
--------------------------------------------------------------------------------
1 | /* File generated by Qt Creator */
2 |
3 | import QmlProject 1.1
4 |
5 | Project {
6 | mainFile: "main.qml"
7 |
8 | /* Include .qml, .js, and image files from current directory and subdirectories */
9 | QmlFiles {
10 | directory: "."
11 | }
12 | JavaScriptFiles {
13 | directory: "."
14 | }
15 | ImageFiles {
16 | directory: "."
17 | }
18 | /* List of plugin directories passed to QML runtime */
19 | importPaths: [ "../../modules" ]
20 | }
21 |
--------------------------------------------------------------------------------
/examples/app/deployment.pri:
--------------------------------------------------------------------------------
1 | android-no-sdk {
2 | target.path = /data/user/qt
3 | export(target.path)
4 | INSTALLS += target
5 | } else:android {
6 | x86 {
7 | target.path = /libs/x86
8 | } else: armeabi-v7a {
9 | target.path = /libs/armeabi-v7a
10 | } else {
11 | target.path = /libs/armeabi
12 | }
13 | export(target.path)
14 | INSTALLS += target
15 | } else:unix {
16 | isEmpty(target.path) {
17 | qnx {
18 | target.path = /tmp/$${TARGET}/bin
19 | } else {
20 | target.path = /opt/$${TARGET}/bin
21 | }
22 | export(target.path)
23 | }
24 | INSTALLS += target
25 | }
26 |
27 | export(INSTALLS)
28 |
--------------------------------------------------------------------------------
/examples/app/icons/apps.svg:
--------------------------------------------------------------------------------
1 |
2 |
55 |
--------------------------------------------------------------------------------
/examples/app/icons/arrow_back.svg:
--------------------------------------------------------------------------------
1 |
2 |
55 |
--------------------------------------------------------------------------------
/examples/app/icons/done.svg:
--------------------------------------------------------------------------------
1 |
2 |
55 |
--------------------------------------------------------------------------------
/examples/app/icons/hamburger.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/examples/app/icons/more_vert.svg:
--------------------------------------------------------------------------------
1 |
2 |
55 |
--------------------------------------------------------------------------------
/examples/app/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication app(argc, argv);
7 | QQmlApplicationEngine engine;
8 | engine.addImportPath(QApplication::applicationDirPath() + QStringLiteral("/../../modules"));
9 | engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
10 |
11 | return app.exec();
12 | }
13 |
--------------------------------------------------------------------------------
/examples/app/main.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import QtQuick.Layouts 1.1
4 |
5 | import Mut 0.1
6 | import Mut.Styles 0.1
7 | import Mut.Themes 0.1
8 | import Mut.Layouts 0.1
9 | import Mut.ListItems 0.1
10 |
11 |
12 | ApplicationWindow {
13 | id: app
14 |
15 | title: qsTr("Mut App")
16 | visible: true
17 |
18 | pageStack.initialItem: page1
19 | pageStack.onCurrentItemChanged: drawer.close()
20 | pageStack.focus: !drawer.opened
21 |
22 | Component.onCompleted: {
23 | Theme.imageAssetsPath = "qrc:///icons/";
24 | }
25 |
26 | property list actions: [
27 | Action {
28 | text: "Item 1"
29 | iconSource: Qt.resolvedUrl("./icons/apps.svg")
30 | onTriggered: {
31 | console.log("NavDrawer action 1");
32 | }
33 | },
34 | Action {
35 | text: "Item 2"
36 | iconSource: Qt.resolvedUrl("./icons/hamburger.svg")
37 | onTriggered: {
38 | console.log("NavDrawer action 2");
39 | }
40 | },
41 | Action {
42 | text: "Dialogs"
43 | iconSource: Qt.resolvedUrl("./icons/hamburger.svg")
44 | onTriggered: pageStack.push(Qt.resolvedUrl("DialogsPage.qml"))
45 | }
46 | ]
47 |
48 | NavDrawer {
49 | id: drawer
50 | focus: drawer.opened
51 |
52 | ListView {
53 | anchors.fill: parent
54 | model: app.actions
55 |
56 | delegate: SingleLineItem {
57 | text: model.text
58 | primaryAction: modelData
59 | }
60 | }
61 | }
62 |
63 | Component {
64 | id: page1
65 |
66 | Page {
67 | title: qsTr("NavDrawer")
68 |
69 | navAction: Action {
70 | iconSource: Qt.resolvedUrl("./icons/hamburger.svg")
71 | onTriggered: {
72 | drawer.toggle();
73 | }
74 | }
75 |
76 | actions: [
77 | Action {
78 | iconSource: Qt.resolvedUrl("./icons/apps.svg")
79 | },
80 | Action {
81 | iconSource: Qt.resolvedUrl("./icons/more_vert.svg")
82 | onTriggered: {
83 | push(page2);
84 | }
85 | },
86 | Action {
87 | iconSource: Qt.resolvedUrl("./icons/more_vert.svg")
88 | onTriggered: {
89 | push(page2a);
90 | }
91 | },
92 | Action {
93 | iconSource: Qt.resolvedUrl("./icons/more_vert.svg")
94 | onTriggered: {
95 | push(page3);
96 | }
97 | },
98 | Action {
99 | iconSource: Qt.resolvedUrl("./icons/more_vert.svg")
100 | onTriggered: {
101 | push(page4);
102 | }
103 | }
104 | ]
105 | }
106 | }
107 |
108 | Component {
109 | id: page2
110 |
111 | Page {
112 | title: qsTr("ListViews")
113 |
114 | Paper {
115 | anchors.fill: parent
116 |
117 | ListView {
118 | anchors.fill: parent
119 | model: 5
120 |
121 | delegate: SingleLineItem {
122 | text: "Single line item"
123 | primaryAction: Action {
124 | iconSource: Qt.resolvedUrl("./icons/apps.svg")
125 | onTriggered: {
126 | console.log("primary")
127 | }
128 | }
129 | secondaryAction: Action {
130 | iconSource: Qt.resolvedUrl("./icons/apps.svg")
131 | onTriggered: {
132 | console.log("secondary")
133 | }
134 | }
135 | }
136 | }
137 | }
138 | }
139 | }
140 |
141 | Component {
142 | id: page2a
143 |
144 | Page {
145 | title: qsTr("Double line items")
146 |
147 | Paper {
148 | anchors.fill: parent
149 |
150 | ListView {
151 | anchors.fill: parent
152 | model: 5
153 |
154 | delegate: DoubleLineItem {
155 | primaryText: "TEEXT"
156 | secondaryText: "teeeext really i'm a text and i will text you till the text "
157 | primaryAction: Action {
158 | iconSource: Qt.resolvedUrl("./icons/apps.svg")
159 | onTriggered: console.log("Primary action")
160 | }
161 | secondaryAction: Action {
162 | iconSource: Qt.resolvedUrl("./icons/apps.svg")
163 | onTriggered: console.log("Secondary action")
164 | }
165 | }
166 | }
167 | }
168 | }
169 | }
170 |
171 | Component {
172 | id: page3
173 |
174 | Page {
175 | title: qsTr("Components")
176 |
177 | Item {
178 | anchors.fill: parent
179 | anchors.margins: Units.dp(16)
180 | ColumnLayout {
181 | anchors.centerIn: parent
182 | spacing: Units.dp(24)
183 |
184 | TextField {
185 | placeholderText: "Enter your username"
186 | style: NormalTextFieldStyle {}
187 | }
188 |
189 | TextField {
190 | placeholderText: "Enter your password"
191 | hintText: "This is an hint"
192 | hasError: text === "error"
193 |
194 | style: FloatingTextFieldStyle {}
195 | }
196 |
197 | // flat button
198 | Button {
199 | text: qsTr("excellent")
200 | style: FlatButtonStyle {}
201 | onClicked: {
202 | pop();
203 | }
204 | }
205 |
206 | // raised button
207 | Button {
208 | text: qsTr("pupp")
209 | style: RaisedButtonStyle {}
210 | }
211 | // raised button
212 | Button {
213 | text: qsTr("foobar")
214 | style: RaisedButtonStyle {}
215 | enabled: false
216 | }
217 |
218 | Button {
219 | iconSource: Qt.resolvedUrl("./icons/apps.svg")
220 | style: ActionButtonStyle {}
221 | }
222 | Switch {
223 | style: SwitchStyle {}
224 | }
225 | Switch {
226 | enabled: false
227 | style: SwitchStyle {}
228 | }
229 | CheckBox {
230 | style: CheckBoxStyle {}
231 | text: "Enabled"
232 | }
233 | CheckBox {
234 | style: CheckBoxStyle {}
235 | enabled: false
236 | text: "Disabled"
237 | }
238 | CheckBox {
239 | style: CheckBoxStyle {}
240 | enabled: false
241 | checked: true
242 | text: "Disabled checked"
243 | }
244 | Rectangle {
245 | width: Units.dp(48); height: Units.dp(48)
246 | color: "blue"
247 | Icon {
248 | image.source: Qt.resolvedUrl("./icons/apps.svg")
249 | }
250 | }
251 | Icon {
252 | image.source: Qt.resolvedUrl("./icons/apps.svg")
253 | colorOverlay: 'red'
254 | }
255 | Paper {
256 | width: Units.dp(200); height: Units.dp(100)
257 | elevation: 2
258 |
259 | Surface {
260 | anchors.fill: parent
261 | }
262 | }
263 | Card {
264 | width: Units.dp(200); height: Units.dp(200)
265 | }
266 | }
267 | }
268 | }
269 | }
270 |
271 | Component {
272 | id: page4
273 |
274 | Page {
275 | id: layoutPage
276 | title: qsTr("Layouting")
277 |
278 | property int model: 3
279 |
280 | Component {
281 | id: layout_landscape
282 |
283 | RowLayout {
284 | anchors.margins: 20
285 |
286 | Repeater {
287 | model: layoutPage.model
288 | Rectangle {
289 | Layout.fillWidth: true
290 | Layout.fillHeight: true
291 | color: "#5d5b59"
292 |
293 | Label {
294 | anchors.centerIn: parent
295 | text: "I'm a box!"
296 | color: "white"
297 | }
298 | }
299 | }
300 | }
301 | }
302 |
303 | Component {
304 | id: layout_portrait
305 |
306 | ColumnLayout {
307 | anchors.margins: 20
308 |
309 | Repeater {
310 | model: layoutPage.model
311 |
312 | Rectangle {
313 | Layout.fillWidth: true
314 | Layout.fillHeight: true
315 | color: "#5d5b59"
316 |
317 | Label {
318 | anchors.centerIn: parent
319 | text: "I'm a box!"
320 | color: "white"
321 | }
322 | }
323 | }
324 | }
325 | }
326 |
327 | ConditionalLayout {
328 | anchors.fill: parent
329 | when: app.width > 600 ? 1 : 0
330 |
331 | layouts: [
332 | layout_portrait,
333 | layout_landscape
334 | ]
335 | }
336 | }
337 | }
338 | }
339 |
340 |
--------------------------------------------------------------------------------
/examples/app/qml.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | main.qml
4 | DialogsPage.qml
5 | icons/arrow_back.svg
6 | icons/apps.svg
7 | icons/more_vert.svg
8 | icons/hamburger.svg
9 | icons/done.svg
10 |
11 |
12 |
--------------------------------------------------------------------------------
/examples/examples.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = subdirs
2 | SUBDIRS += app
3 |
--------------------------------------------------------------------------------
/modules/Mut/AppBar.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Layouts 1.1
3 | import QtQuick.Controls 1.3
4 | import QtQuick.Window 2.2
5 |
6 | import Mut 0.1
7 | import Mut.Styles 0.1
8 | import Mut.Themes 0.1
9 |
10 |
11 | ToolBar {
12 | id: root
13 |
14 | property Page page
15 |
16 | property Action defaultNavAction: null
17 |
18 | implicitHeight: {
19 | if (Device.size >= Device.sizeLarge) {
20 | Units.dp(64);
21 | } else if (Device.primaryOrientation == Qt.PortraitOrientation) {
22 | Units.dp(56);
23 | } else {
24 | Units.dp(48);
25 | }
26 | }
27 |
28 | elevation: 2
29 | fillWidth: true
30 |
31 | RowLayout {
32 | width: parent.width
33 | anchors.verticalCenter: parent.verticalCenter
34 | spacing: Units.dp(1)
35 | Button {
36 | action: page && page.navAction ? page.navAction : root.defaultNavAction
37 | style: ToolButtonStyle {}
38 | }
39 | Text {
40 | id: title
41 | text: page ? page.title : ""
42 | elide: Text.ElideRight
43 | color: Theme.p.textPrimary
44 | font {
45 | pixelSize: Units.sp(20)
46 | weight: Font.DemiBold
47 | }
48 | Layout.fillWidth: true
49 | }
50 |
51 | Repeater {
52 | model: page ? page.actions : null
53 | Button {
54 | action: modelData
55 | style: ToolButtonStyle {}
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/modules/Mut/ApplicationWindow.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3 as Controls
3 | import QtQuick.Window 2.2
4 |
5 | import Mut 0.1
6 | import Mut.Themes 0.1
7 |
8 | /*! \qmltype ApplicationWindow
9 | \inqmlmodule Mut 0.1
10 | \ingroup applicationwindow
11 |
12 | \brief Provides a top-level application window.
13 |
14 | ApplicationWindow extends \l {QtQuick.Controls::ApplicationWindow} that adds
15 | convenience for sizing items and components.
16 |
17 | \qml
18 | import QtQuick 2.4
19 | import Mut 0.1
20 |
21 | ApplicationWindow {
22 | title: "Application Name"
23 |
24 | width: Units.dp(800)
25 | height: Units.dp(600)
26 | }
27 | \endqml
28 | */
29 | Controls.ApplicationWindow {
30 | id: app
31 |
32 | width: 800
33 | height: 600
34 |
35 | color: Theme.p.background
36 |
37 | /*!
38 | \qmlproperty AppBar ApplicationWindow::appBar
39 |
40 | This property holds the \l AppBar.
41 |
42 | By default, this value is set and the page property is bound to currentItem
43 | of the page stack.
44 |
45 | Note that the default toolBar property is bound to the appBar so developers
46 | should only interact with the appBar property.
47 | */
48 | property AppBar appBar: AppBar {
49 | id: appBar
50 | page: __stack.currentItem
51 | }
52 |
53 | toolBar: appBar
54 |
55 | property alias pageStack: __stack
56 |
57 | Controls.StackView {
58 | id: __stack
59 | anchors.fill: parent
60 |
61 | Keys.onReleased: {
62 | if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) {
63 | if (__stack.depth > 1) {
64 | __stack.pop();
65 | event.accepted = true;
66 | }
67 | }
68 | }
69 | }
70 |
71 | Component.onCompleted: {
72 | /* FIXME: both Units and Device should be implemented at C++
73 | level. It's easier to bind and change values from QScreen */
74 | Units.pixelDensity = Qt.binding(function() { return Screen.pixelDensity; });
75 | initDevice();
76 | }
77 |
78 | function initDevice() {
79 | Device.primaryOrientation = Qt.binding(function () { return Screen.primaryOrientation; });
80 | Device.size = Qt.binding(function() {
81 | var dpWidth = Units.pxToDp(Screen.width);
82 | var dpHeight = Units.pxToDp(Screen.height);
83 |
84 | var minLength = Math.min(dpWidth, dpHeight);
85 | var maxLength = Math.max(dpWidth, dpHeight);
86 |
87 | // set the device size
88 | if (maxLength >= "960" && minLength >= "720")
89 | return Device.sizeXLarge;
90 | else if (maxLength >= "640" && minLength >= "480")
91 | return Device.sizeLarge;
92 | else if (maxLength >= "470" && minLength >= "320")
93 | return Device.sizeNormal;
94 | else // if (maxLength >= "426" && minLength >= "320")
95 | return Device.sizeSmall;
96 | });
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/modules/Mut/Card.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | import Mut 0.1
4 |
5 | Paper {
6 | elevation: 1
7 | radius: Units.dp(2)
8 | }
9 |
--------------------------------------------------------------------------------
/modules/Mut/DebugOutline.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | Rectangle {
4 | id: dbg
5 | anchors.fill: parent
6 | color: "transparent"
7 | border.color: "red"
8 | }
9 |
--------------------------------------------------------------------------------
/modules/Mut/Device.qml:
--------------------------------------------------------------------------------
1 | pragma Singleton
2 |
3 | import QtQuick 2.4
4 | import QtQuick.Window 2.2
5 |
6 | import Mut 0.1
7 |
8 | Item {
9 | id: device
10 |
11 | property int size
12 | property int density
13 | property int primaryOrientation
14 |
15 | readonly property int sizeSmall: 0
16 | readonly property int sizeNormal: 1
17 | readonly property int sizeLarge: 2
18 | readonly property int sizeXLarge: 3
19 |
20 | readonly property int densityLDPI: 120
21 | readonly property int densityMDPI: 160
22 | readonly property int densityHDPI: 240
23 | readonly property int densityXHDPI: 320
24 | readonly property int densityXXHDPI: 480
25 | readonly property int densityXXXHDPI: 640
26 | }
27 |
--------------------------------------------------------------------------------
/modules/Mut/Dialog.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Window 2.2
3 |
4 | Item {
5 | id: root
6 | property Item __lastFocus
7 | property Item __dialogInstance
8 |
9 | function open() {
10 | __lastFocus = Window.activeFocusItem;
11 | __dialogInstance = __panel.createObject(Window.contentItem, {"focus": "true"});
12 | }
13 |
14 | function close() {
15 | __lastFocus.forceActiveFocus();
16 | __dialogInstance.destroy();
17 | }
18 |
19 | property Component __panel: Component {
20 | Scrim {
21 | id: __dialogRoot
22 | anchors.fill: parent
23 |
24 | onClicked: root.close()
25 |
26 | Loader {
27 | anchors.centerIn: parent
28 | sourceComponent: root.dialogComponent
29 | focus: true
30 | }
31 |
32 | Keys.onReleased: {
33 | if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) {
34 | root.close();
35 | event.accepted = true;
36 | }
37 | }
38 | }
39 | }
40 |
41 | property Component dialogComponent: null
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/modules/Mut/Divider.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | import Mut 0.1
4 | import Mut.Themes 0.1
5 |
6 | Rectangle {
7 | id: root
8 |
9 | height: Units.dp(1)
10 | color: Theme.p.divider
11 | }
12 |
--------------------------------------------------------------------------------
/modules/Mut/Icon.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtGraphicalEffects 1.0
3 |
4 | import Mut 0.1
5 |
6 | Item {
7 | implicitWidth: __image.implicitWidth
8 | implicitHeight: __image.implicitHeight
9 |
10 | property alias image: __image
11 | property color colorOverlay: "transparent"
12 |
13 | Image {
14 | id: __image
15 | smooth: false
16 | sourceSize {
17 | height: Units.dp(24)
18 | width: Units.dp(24)
19 | }
20 | anchors.centerIn: parent
21 |
22 | visible: false
23 | }
24 |
25 | ColorOverlay {
26 | id: __overlay
27 | anchors.fill: image
28 | source: image
29 | cached: true
30 |
31 | color: Qt.rgba(colorOverlay.r, colorOverlay.g, colorOverlay.b)
32 | opacity: colorOverlay.a
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/modules/Mut/Layouts/ConditionalLayout.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | /*! \qmltype ConditionalLayout
4 | \inqmlmodule Mut.Layout 0.1
5 |
6 | \brief Provides a layout that could change dinamically.
7 |
8 | ConditionalLayout uses a \l {QtQuick::Loader} that loads a layout
9 | dinamically according to the following properties:
10 | * `layouts`: contains a list of possible layouts that should be defined as a {QtQuick::Component}.
11 | * `when`: is a condition that should return the `layouts` index for the chosen layout
12 |
13 | ConditionalLayout provides a fallback system that chooses the nearest available layout
14 | so if the `when` property is set to 5 but `layouts` contains only 3 layouts, the
15 | rightmost element of the array will be used.
16 |
17 | \qml
18 | import QtQuick 2.4
19 | import Mut 0.1
20 | import Mut.Layouts 0.1
21 |
22 | Component {
23 | id: first_layout
24 | RowLayout {
25 | ...
26 | }
27 | }
28 |
29 | Component {
30 | id: second_layout
31 | ColumnLayout {
32 | ...
33 | }
34 | }
35 |
36 | ConditionalLayout {
37 | when: aReallyLongCondition ? 0 : 1
38 | layouts: [
39 | first_layout,
40 | second_layout
41 | ]
42 |
43 | }
44 | \endqml
45 | */
46 | FocusScope {
47 | id: root
48 |
49 | property list layouts
50 | property int when: -1
51 |
52 | property alias activeComponent: __layoutLoader.sourceComponent
53 | property alias activeLayout: __layoutLoader.item
54 |
55 | Loader {
56 | id: __layoutLoader
57 | anchors.fill: parent
58 | active: root.when >= 0
59 | sourceComponent: layoutSelection()
60 | }
61 |
62 | function layoutSelection () {
63 | var index = root.when;
64 | var layout;
65 |
66 | // manages layouts fallback
67 | while (typeof root.layouts[index] === 'undefined' && index > -1) {
68 | index -= 1;
69 | }
70 |
71 | // chooses the most similar layout available,
72 | // 'empty' otherwise (no layout will be loaded)
73 | if (index === -1) {
74 | layout = undefined;
75 | } else {
76 | layout = root.layouts[index];
77 | }
78 |
79 | return layout;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/modules/Mut/Layouts/DeviceLayout.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | import Mut 0.1
4 | import Mut.Layouts 0.1
5 |
6 | /*! \qmltype DeviceLayout
7 | \inqmlmodule Mut.Layout 0.1
8 |
9 | \brief Provides a layout that changes according to device screen size.
10 | Screen size values are defined in \l {Mut::Device} singleton
11 | having values in the range [0, 3].
12 |
13 | DeviceLayout makes use of the \l {Mut.Layouts::ConditionalLayout}
14 | fallback system so if only `sizeSmall` and `sizeNormal` layouts are defined
15 | but the current device requires a `sizeXLarge` layout, `sizeNormal` layout
16 | will be used.
17 |
18 | \qml
19 | import QtQuick 2.4
20 | import Mut 0.1
21 | import Mut.Layouts 0.1
22 |
23 | Component {
24 | id: small_layout
25 | ColumnLayout {
26 | ...
27 | }
28 | }
29 |
30 | Component {
31 | id: normal_layout
32 | ColumnLayout {
33 | ...
34 | }
35 | }
36 |
37 | Component {
38 | id: large_layout
39 | RowLayout {
40 | ...
41 | }
42 | }
43 |
44 | DeviceLayout {
45 | layouts: [
46 | small_layout,
47 | normal_layout,
48 | large_layout
49 | ]
50 |
51 | }
52 | \endqml
53 | */
54 | ConditionalLayout {
55 | when: Device.size
56 | }
57 |
--------------------------------------------------------------------------------
/modules/Mut/Layouts/OrientationLayout.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | import Mut 0.1
4 | import Mut.Layouts 0.1
5 |
6 | /*! \qmltype OrientationLayout
7 | \inqmlmodule Mut.Layout 0.1
8 |
9 | \brief Provides a layout that changes according to device orientation.
10 |
11 | \qml
12 | import QtQuick 2.4
13 | import Mut 0.1
14 | import Mut.Layouts 0.1
15 |
16 | Component {
17 | id: portrait_layout
18 | ColumnLayout {
19 | ...
20 | }
21 | }
22 |
23 | Component {
24 | id: landscape_layout
25 | RowLayout {
26 | ...
27 | }
28 | }
29 |
30 | OrientationLayout {
31 | layouts: [
32 | portrait_layout,
33 | landscape_layout
34 | ]
35 |
36 | }
37 | \endqml
38 | */
39 | ConditionalLayout {
40 | when: Device.primaryOrientation === Qt.PortraitOrientation ? 0 : 1
41 | }
42 |
--------------------------------------------------------------------------------
/modules/Mut/Layouts/qmldir:
--------------------------------------------------------------------------------
1 | module Mut.Layouts
2 | ConditionalLayout 0.1 ConditionalLayout.qml
3 | OrientationLayout 0.1 OrientationLayout.qml
4 | DeviceLayout 0.1 DeviceLayout.qml
5 |
--------------------------------------------------------------------------------
/modules/Mut/ListItems/DoubleLineItem.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 |
4 | import Mut 0.1
5 | import Mut.Themes 0.1
6 | import Mut.Styles 0.1
7 |
8 | Tile {
9 | id: root
10 | height: Units.dp(72)
11 |
12 | property string primaryText
13 | property string secondaryText
14 | property Action primaryAction
15 | property Action secondaryAction
16 |
17 | primaryComponent: Item {
18 | anchors.fill: parent
19 | Icon {
20 | id: __icon
21 | visible: root.primaryAction
22 |
23 | anchors {
24 | verticalCenter: parent.verticalCenter
25 | left: parent.left
26 | }
27 |
28 | image.source: root.primaryAction ? root.primaryAction.iconSource : ""
29 | colorOverlay: Theme.p.dark.icon
30 | }
31 |
32 | Column {
33 | anchors.verticalCenter: parent.verticalCenter
34 | width: secondaryAction ? parent.width - Units.dp(48) : parent.width
35 |
36 | Text {
37 | id: __primaryText
38 | elide: Text.ElideRight
39 | width: parent.width
40 |
41 | text: root.primaryText
42 | font.pixelSize: Units.sp(16)
43 | }
44 |
45 | Text {
46 | id: __secondaryText
47 | color: Theme.p.textSecondary
48 | width: parent.width
49 | elide: Text.ElideRight
50 |
51 | text: root.secondaryText
52 | font.pixelSize: Units.dp(14)
53 | }
54 | }
55 | }
56 |
57 | secondaryComponent: Button {
58 | visible: secondaryAction
59 | enabled: secondaryAction
60 |
61 | action: secondaryAction
62 | style: ToolButtonStyle {
63 | palette: Theme.p.flatButton
64 | }
65 | }
66 |
67 | Surface {
68 | anchors.fill: parent
69 | anchors.right: secondaryComponent.left
70 | onClicked: primaryAction.trigger()
71 | enabled: root.primaryAction
72 | visible: enabled
73 | }
74 | }
75 |
76 |
77 |
--------------------------------------------------------------------------------
/modules/Mut/ListItems/ListView.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4 as Q
2 |
3 | import Mut 0.1
4 | import Mut.Styles 0.1
5 | import Mut.Themes 0.1
6 |
7 | /*! \qmltype ListView
8 | \inqmlmodule Mut.ListItems 0.1
9 |
10 | \brief Provides a generic ListView component compliant to material design guidelines.
11 |
12 | ListView extends \l {QtQuick::ListView}
13 | */
14 | Q.ListView {
15 | id: root
16 |
17 | header: Q.Item {
18 | height: Units.dp(8)
19 | }
20 |
21 | footer: Q.Item {
22 | height: Units.dp(8)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/modules/Mut/ListItems/SingleLineItem.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 |
4 | import Mut 0.1
5 | import Mut.Styles 0.1
6 | import Mut.Themes 0.1
7 |
8 | /*! \qmltype SingleLineItem
9 | \inqmlmodule Mut.ListItems 0.1
10 |
11 | \brief Provides the single-line list component.
12 |
13 | SingleLineItem implements the text only item type, providing a Text
14 | component as a `primaryComponent` and a Button as a supplemental action.
15 | Exposed properties are:
16 | * `text`: is the `primaryComponent` text
17 | * `primaryAction`: defines the triggered action when users click the line; it
18 | should be a Qt.Action
19 | * `secondaryAction`: defines the icon and the triggered action for the
20 | supplemental action; it should be a Qt.Action
21 |
22 | SingleLineItem includes a material `Surface` area, which `onClicked` handler is
23 | bounded to `primaryAction.trigger` method.
24 |
25 | \qml
26 | import QtQuick 2.4
27 | import QtQuick.Controls 1.3
28 |
29 | import Mut 0.1
30 | import Mut.ListItems 0.1
31 |
32 | ListView {
33 | anchors.fill: parent
34 | model: 5
35 |
36 | delegate: SingleLineItem {
37 | text: "Single line item"
38 | primaryAction: Action {
39 | iconSource: Qt.resolvedUrl("./icons/folder.svg")
40 | onTriggered: {
41 | console.log("Primary action")
42 | }
43 | }
44 | secondaryAction: Action {
45 | iconSource: Qt.resolvedUrl("./icons/star.svg")
46 | onTriggered: {
47 | console.log("Secondary action")
48 | }
49 | }
50 | }
51 | }
52 | \endqml
53 | */
54 | Tile {
55 | id: root
56 |
57 | property string text
58 | property Action primaryAction
59 | property Action secondaryAction
60 |
61 | primaryComponent: Item {
62 | Row {
63 | anchors.fill: parent
64 |
65 | spacing: Units.dp(16)
66 | Icon {
67 | id: __icon
68 | visible: root.primaryAction
69 |
70 | anchors.verticalCenter: parent.verticalCenter
71 | image.source: root.primaryAction.iconSource
72 | colorOverlay: Theme.p.dark.icon
73 | }
74 |
75 | Text {
76 | id: __text
77 |
78 | anchors.verticalCenter: parent.verticalCenter
79 | width: parent.width - __icon.width
80 | text: root.text
81 | elide: Text.ElideRight
82 | font.pixelSize: Units.sp(16)
83 | }
84 | }
85 | }
86 |
87 | secondaryComponent: Button {
88 | visible: secondaryAction
89 | enabled: secondaryAction
90 |
91 | action: secondaryAction
92 | style: ToolButtonStyle {
93 | palette: Theme.p.flatButton
94 | }
95 | }
96 |
97 | Surface {
98 | anchors.fill: parent
99 | onClicked: primaryAction.trigger()
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/modules/Mut/ListItems/Tile.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | import Mut 0.1
4 | import Mut.Themes 0.1
5 |
6 | /*! \qmltype Tile
7 | \inqmlmodule Mut.ListItems 0.1
8 |
9 | \brief Provides the Tile component used in material lists.
10 |
11 | Tile component uses two \l {QtQuick::Loader} to render a primary component
12 | and a secondary component. Exposed properties are:
13 | * `backgroundColor`: defines the Tile background color
14 | * `primaryComponent`: is the Loader sourceComponent
15 | * `secondaryComponent`: is the Loader sourceComponent
16 |
17 | The primary component owns the majority of line space, while the secondary
18 | component should be considered as a right button that provides a
19 | supplemental action.
20 |
21 | Tile is a base component required to realize Lists Components such as
22 | `SingleLineItem`, `TwoLineItem`, `ThreeLineItem`
23 |
24 | \qml
25 | import QtQuick 2.4
26 | import QtQuick.Controls 1.3
27 |
28 | import Mut 0.1
29 | import Mut.Styles 0.1
30 | import Mut.Themes 0.1
31 |
32 | Tile {
33 | id: root
34 |
35 | primaryComponent: Text {
36 | text: "Hello world!"
37 | font.pixelSize: Units.sp(16)
38 | }
39 |
40 | secondaryComponent: Button {
41 | action: secondaryAction
42 | style: ToolButtonStyle {
43 | palette: Theme.p.flatButton
44 | }
45 | }
46 |
47 | Surface {
48 | anchors.fill: parent
49 | onClicked: "Are you clicking me?!"
50 | }
51 | }
52 | \endqml
53 | */
54 | FocusScope {
55 | id: tile
56 |
57 | implicitHeight: Units.dp(48)
58 | implicitWidth: parent.width
59 |
60 | property alias backgroundColor: background.color
61 | property alias primaryItem: __primary.item
62 | property alias secondaryItem: __secondary.item
63 | property Component primaryComponent
64 | property Component secondaryComponent
65 |
66 | Rectangle {
67 | id: background
68 | anchors.fill: parent
69 |
70 | color: "transparent"
71 | }
72 |
73 | Loader {
74 | id: __primary
75 |
76 | sourceComponent: primaryComponent
77 |
78 | anchors {
79 | left: parent.left
80 | right: __secondary.sourceComponent ? __secondary.left : parent.right
81 | leftMargin: Units.dp(16)
82 | rightMargin: Units.dp(16)
83 | verticalCenter: parent.verticalCenter
84 | }
85 | }
86 |
87 | Loader {
88 | id: __secondary
89 | width: Units.dp(48)
90 |
91 | sourceComponent: secondaryComponent
92 |
93 | anchors {
94 | verticalCenter: parent.verticalCenter
95 | right: parent.right
96 | leftMargin: Units.dp(16)
97 | rightMargin: Units.dp(16)
98 | }
99 |
100 | z: 1
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/modules/Mut/ListItems/qmldir:
--------------------------------------------------------------------------------
1 | module Mut.ListItems
2 | ListView 0.1 ListView.qml
3 | Tile 0.1 Tile.qml
4 | SingleLineItem 0.1 SingleLineItem.qml
5 | DoubleLineItem 0.1 DoubleLineItem.qml
6 |
--------------------------------------------------------------------------------
/modules/Mut/NavDrawer.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | import Mut 0.1
4 |
5 | /*! \qmltype NavDrawer
6 | \inqmlmodule Mut 0.1
7 |
8 | \brief Provides a `NavDrawer` that uses a `Scrim` to prevent any interaction with the components below
9 |
10 | `NavDrawer` component makes use of a \l {Mut::Scrim} as an overlay
11 | for all underlying components and uses a \l {Mut::Paper} as a main
12 | container for all `NavDrawer` children.
13 |
14 | As a default behavior, it provides two states:
15 | * `DRAWER_CLOSED`: the drawer `x` property is set to the far left, while the
16 | `Scrim` component has 0.0 opacity
17 | * `DRAWER_OPENED`: the drawer is visible to users, while the `Scrim` component
18 | has 1.0 opacity. The `Scrim` \l {QtQuick::MouseArea} catches keyboard and
19 | mouse inputs, preventing any interaction with the components below
20 |
21 | Even if a `NavDrawer` is flexible and can contain any kind of component, the
22 | Material Design specifications suggest following the keylines and metrics
23 | for lists.
24 |
25 | \qml
26 | import QtQuick 2.4
27 | import QtQuick.Controls 1.3
28 |
29 | import Mut 0.1
30 | import Mut.ListItems 0.1
31 |
32 | ApplicationWindow {
33 | id: app
34 |
35 | property list actions: [
36 | Action {
37 | text: "Item 1"
38 | iconSource: Qt.resolvedUrl("./icon1.svg")
39 | onTriggered: {
40 | console.log("NavDrawer action 1");
41 | }
42 | },
43 | Action {
44 | text: "Item 2"
45 | iconSource: Qt.resolvedUrl("./icon2.svg")
46 | onTriggered: {
47 | console.log("NavDrawer action 2");
48 | }
49 | }
50 | ]
51 |
52 | NavDrawer {
53 | id: drawer
54 |
55 | ListView {
56 | anchors.fill: parent
57 | model: app.actions
58 |
59 | delegate: SingleLineItem {
60 | text: model.text
61 | primaryAction: modelData
62 | }
63 | }
64 | }
65 | }
66 | \endqml
67 | */
68 | FocusScope {
69 | id: drawer
70 | state: "DRAWER_CLOSED"
71 |
72 | signal drawerOpened()
73 | signal drawerClosed()
74 |
75 | default property alias data: __paper.data
76 | property bool opened: state === "DRAWER_OPENED"
77 |
78 | implicitWidth: parent.width
79 | implicitHeight: parent.height
80 |
81 | Keys.onReleased: {
82 | if (event.key === Qt.Key_Back || event.key === Qt.Key_Escape) {
83 | if (drawer.opened) {
84 | drawer.close();
85 | event.accepted = true;
86 | }
87 | }
88 | }
89 |
90 | Scrim {
91 | id: __scrim
92 |
93 | anchors.fill: parent
94 | onClicked: drawer.close()
95 | }
96 |
97 | Paper {
98 | id: __paper
99 |
100 | implicitHeight: parent.height
101 | implicitWidth: Units.dp(320)
102 |
103 | elevation: 2
104 | }
105 |
106 | function open() {
107 | drawer.state = "DRAWER_OPENED";
108 | drawerOpened();
109 | }
110 |
111 | function close() {
112 | drawer.state = "DRAWER_CLOSED";
113 | drawerClosed();
114 | }
115 |
116 | function toggle() {
117 | if (drawer.opened) {
118 | drawer.close();
119 | } else {
120 | drawer.open();
121 | }
122 | }
123 |
124 | states: [
125 | State {
126 | name: "DRAWER_OPEN"
127 | PropertyChanges { target: __paper; x: 0; }
128 | PropertyChanges { target: __scrim; opacity: 1.0; }
129 | },
130 | State {
131 | name: "DRAWER_CLOSED"
132 | PropertyChanges { target: __paper; x: Units.dp(-320); }
133 | PropertyChanges { target: __scrim; opacity: 0.0; }
134 | }
135 | ]
136 |
137 | transitions: [
138 | Transition {
139 | to: "*"
140 | NumberAnimation { target: __paper; properties: "x"; duration: 450; easing.type: Easing.OutCubic; }
141 | NumberAnimation { target: __scrim; properties: "opacity"; duration: 100; easing.type: Easing.Linear; }
142 | }
143 | ]
144 | }
145 |
--------------------------------------------------------------------------------
/modules/Mut/Page.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import Mut 0.1
4 | import Mut.Themes 0.1
5 |
6 | FocusScope {
7 | id: root
8 |
9 | property string title
10 | property list actions
11 |
12 | property var navHandler: function () { root.pop(); };
13 | property Action navAction: Action {
14 | iconSource: Theme.image("arrow_back.svg")
15 | onTriggered: root.navHandler()
16 | }
17 |
18 | /*! Push a new component into the stack */
19 | function push(item) {
20 | return Stack.view.push(item);
21 | }
22 |
23 | /*! Pop this page from the stack */
24 | function pop() {
25 | if (Stack.view.currentItem === root)
26 | return Stack.view.pop();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/modules/Mut/Paper.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtGraphicalEffects 1.0
3 | import Mut 0.1
4 |
5 | /*! \qmltype Paper
6 | \inqmlmodule Mut
7 |
8 | \brief Provides a generic sheet of paper.
9 |
10 | Paper is the base building block of all the components
11 | of the application.
12 | */
13 | FocusScope {
14 | id: paper
15 |
16 | /*! \qmlproperty color Paper::backgroundColor
17 |
18 | This property holds the background color of the
19 | sheet of paper.
20 | */
21 | property alias backgroundColor: background.color
22 | property alias radius: background.radius
23 |
24 | /*! \qmlproperty real Paper::elevation
25 |
26 | This property holds the elevation level of the sheet
27 | paper and determines the appearance of its shadow.
28 | */
29 | property real elevation: 0
30 |
31 | property bool fillWidth: false
32 | property bool fillHeight: false
33 |
34 | property bool circular: false
35 |
36 | /*! \internal */
37 | property bool __hasShadow: paper.backgroundColor.a != 0 && elevation > 0
38 |
39 | /*! \internal */
40 | property real __effectWidth: paper.width + Units.dp(10) * paper.fillWidth
41 | /*! \internal */
42 | property real __effectHeight: paper.height + Units.dp(20) * paper.fillHeight
43 |
44 | RectangularGlow {
45 | visible: paper.__hasShadow && paper.circular
46 | //width: paper.__effectWidth; height: paper.__effectHeight
47 | width: paper.__effectWidth * .95; height: paper.__effectHeight * .95
48 |
49 | anchors.centerIn: parent
50 | anchors.verticalCenterOffset: Units.dp(paper.elevation * 1.5)
51 |
52 | glowRadius: Units.dp(0.75)
53 | opacity: 0.6
54 | spread: 0.7
55 | color: "black"
56 | cornerRadius: paper.radius
57 | }
58 |
59 | RectangularGlow {
60 | id: topEffect
61 | visible: paper.__hasShadow && !paper.circular
62 | width: paper.__effectWidth; height: paper.__effectHeight
63 | anchors.centerIn: parent
64 | anchors.verticalCenterOffset: Units.dp(paper.elevation * 3)
65 | glowRadius: Units.dp(paper.elevation * 3)
66 | spread: 0.05
67 | color: "black"
68 | opacity: 0.08 + (0.04 * paper.elevation)
69 | cornerRadius: paper.radius + glowRadius * 2.5
70 | }
71 |
72 | RectangularGlow {
73 | id: bottomEffect
74 | visible: paper.__hasShadow && !paper.circular
75 | width: paper.__effectWidth; height: paper.__effectHeight
76 | anchors.centerIn: parent
77 | anchors.verticalCenterOffset: Units.dp(paper.elevation * 2.5)
78 | glowRadius: Units.dp(paper.elevation)
79 | spread: 0.05
80 | color: "black"
81 | opacity: 0.25 - (0.01 * paper.elevation)
82 | cornerRadius: paper.radius + glowRadius * 2.5
83 | }
84 |
85 | Rectangle {
86 | id: background
87 | anchors.fill: parent
88 | color: "white"
89 | }
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/modules/Mut/Popup.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Window 2.2
3 |
4 | Item {
5 | id: root
6 | property Item __lastFocus
7 | property Item __popupInstance
8 |
9 | function open() {
10 | __lastFocus = Window.activeFocusItem;
11 | __popupInstance = root.content.createObject(Window.contentItem, {"focus": "true"});
12 | }
13 |
14 | function close() {
15 | __lastFocus.forceActiveFocus();
16 | __popupInstance.destroy();
17 | }
18 |
19 | property Component content: null
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/modules/Mut/Scrim.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | /*! \qmltype Scrim
4 | \inqmlmodule Mut 0.1
5 |
6 | \brief Provides a Scrim that creates an opacity overlay over all components
7 |
8 | Scrim implements an overlay over all components. By default, its opacity
9 | controls the `visible` and `enabled` properties so that when the component
10 | opacity is 0.0, the Scrim is disabled and not visible in the QML hierarchy.
11 | On the other hand, when its opacity is 1.0, the Scrim is enabled and its
12 | `hoverEnabled: true` property prevents any interaction with components
13 | below.
14 |
15 | To use this component, remember to set its `width`, `height` or `anchors`
16 | properties.
17 |
18 | \qml
19 | import QtQuick 2.4
20 |
21 | import Mut 0.1
22 |
23 | FocusScope {
24 | Scrim {
25 | anchors.fill: parent
26 | onClicked: console.log("Scrim is clicked!")
27 | }
28 | }
29 | \endqml
30 | */
31 | FocusScope {
32 | id: root
33 | visible: root.opacity != 0.0
34 | enabled: root.opacity != 0.0
35 |
36 | property alias background: __background
37 |
38 | signal clicked()
39 |
40 | MouseArea {
41 | id: __mouse
42 | anchors.fill: parent
43 | hoverEnabled: true
44 | onClicked: root.clicked()
45 | }
46 |
47 | Rectangle {
48 | id: __background
49 | color: "#000000"
50 | opacity: 0.54
51 | anchors.fill: parent
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/ActionButtonStyle.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import Mut 0.1
3 | import Mut.Styles 0.1
4 | import Mut.Themes 0.1
5 |
6 | BaseButtonStyle {
7 | id: root
8 | elevation: 1
9 | palette: Theme.p.actionButton
10 |
11 | background: Paper {
12 | implicitWidth: Units.dp(56)
13 | implicitHeight: Units.dp(56)
14 | radius: Units.dp(28)
15 | circular: true
16 |
17 | elevation: control.enabled ? root.elevation : 0
18 | backgroundColor: root.backgroundColor
19 | }
20 | label: Icon {
21 | image.source: control.iconSource
22 | colorOverlay: root.iconColor
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/BaseButtonStyle.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls.Styles 1.3 as Styles
3 |
4 | import Mut 0.1
5 | import Mut.Themes 0.1
6 |
7 | Styles.ButtonStyle {
8 | id: root
9 |
10 | property real elevation
11 |
12 | property ButtonPalette palette
13 |
14 | /*! \internal */
15 | property color backgroundColor: {
16 | if (!control.enabled)
17 | root.palette.disabled;
18 | else if (control.pressed)
19 | root.palette.pressed;
20 | else if (control.hovered)
21 | root.palette.hovered;
22 | else
23 | root.palette.normal;
24 | }
25 |
26 | property color iconColor: {
27 | control.enabled ? root.palette.icon : root.palette.textDisabled
28 | }
29 |
30 | /*! \internal */
31 | property color textColor: {
32 | control.enabled ? root.palette.text : root.palette.textDisabled
33 | }
34 |
35 | padding {
36 | left: Units.dp(12)
37 | right: Units.dp(12)
38 | top: 0
39 | bottom: 0
40 | }
41 | background: Item {
42 | id: background
43 | implicitWidth: Units.dp(88)
44 | implicitHeight: Units.dp(48)
45 |
46 | Paper {
47 | implicitWidth: background.width
48 | implicitHeight: Units.dp(36)
49 | anchors.centerIn: parent
50 | radius: Units.dp(1)
51 | elevation: control.enabled ? root.elevation : 0
52 | backgroundColor: root.backgroundColor
53 | }
54 | }
55 | label: Item {
56 | implicitWidth: row.implicitWidth
57 | implicitHeight: row.implicitHeight
58 |
59 | Row {
60 | id: row
61 | anchors.centerIn: parent
62 | spacing: 2
63 |
64 | Icon {
65 | id: icon
66 | anchors.verticalCenter: parent.verticalCenter
67 |
68 | image.source: control.iconSource
69 | colorOverlay: root.iconColor
70 | }
71 |
72 | Text {
73 | id: text
74 | anchors.verticalCenter: parent.verticalCenter
75 | text: control.text
76 |
77 | color: root.textColor
78 | font {
79 | capitalization: Font.AllUppercase
80 | pixelSize: Units.sp(14)
81 | weight: Font.DemiBold
82 | }
83 | }
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/BaseTextFieldStyle.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Layouts 1.1
3 | import QtQuick.Controls 1.3
4 | import QtQuick.Controls.Styles 1.3 as Styles
5 |
6 | import Mut 0.1
7 | import Mut.Themes 0.1
8 |
9 | Styles.TextFieldStyle {
10 | id: root
11 |
12 | property TextFieldPalette palette
13 |
14 | property bool floatingLabel: false
15 |
16 | // exposing internal properties
17 | property color textColor: palette.text
18 | property color normalColor: palette.normal
19 | property color pressedColor: palette.pressed
20 | property color errorColor: palette.error
21 | property color hintColor: palette.hint
22 | property color placeholderTextColor: "transparent"
23 |
24 | padding {
25 | left: 0
26 | right: 0
27 | top: Units.dp(16)
28 | bottom: Units.dp(8)
29 | }
30 |
31 | font.pixelSize: Units.sp(16)
32 |
33 | background: Item {
34 | id: __background
35 | implicitWidth: Units.dp(188)
36 | implicitHeight: Units.dp(48)
37 |
38 | Rectangle {
39 | id: underline
40 | height: control.activeFocus ? Units.dp(2) : Units.dp(1)
41 |
42 | color: control.hasError ? root.errorColor : control.activeFocus ? root.pressedColor : root.normalColor
43 |
44 | anchors {
45 | left: parent.left
46 | right: parent.right
47 | bottom: parent.bottom
48 | }
49 |
50 | Behavior on height {
51 | NumberAnimation { duration: 200 }
52 | }
53 |
54 | Behavior on color {
55 | ColorAnimation { duration: 200 }
56 | }
57 | }
58 |
59 | Label {
60 | id: __placeholder
61 |
62 | text: control.placeholderText
63 |
64 | anchors {
65 | verticalCenter: parent.verticalCenter
66 | margins: -Units.dp(8)
67 | }
68 |
69 | font.pixelSize: Units.sp(16)
70 |
71 | color: control.hasError ? root.errorColor : floatingLabel && control.text && control.activeFocus ? root.pressedColor : root.normalColor
72 |
73 | states: [
74 | State {
75 | name: "floating"
76 | when: control.displayText.length > 0 && root.floatingLabel
77 |
78 | AnchorChanges {
79 | target: __placeholder
80 | anchors {
81 | verticalCenter: undefined
82 | top: parent.top
83 | }
84 | }
85 |
86 | PropertyChanges {
87 | target: __placeholder
88 | font.pixelSize: Units.dp(12)
89 | }
90 | },
91 | State {
92 | name: "hidden"
93 | when: control.displayText.length > 0 && !root.floatingLabel
94 |
95 | PropertyChanges {
96 | target: __placeholder
97 | visible: false
98 | }
99 | }
100 | ]
101 |
102 | transitions: [
103 | Transition {
104 | id: transition
105 | enabled: false
106 |
107 | AnchorAnimation {
108 | duration: 200
109 | }
110 |
111 | NumberAnimation {
112 | duration: 200
113 | property: "font.pixelSize"
114 | }
115 | }
116 | ]
117 |
118 | Behavior on color {
119 | ColorAnimation { duration: 200 }
120 | }
121 |
122 | Component.onCompleted: transition.enabled = true
123 | }
124 |
125 | RowLayout {
126 | anchors {
127 | left: parent.left
128 | right: parent.right
129 | top: underline.top
130 | topMargin: Units.dp(4)
131 | }
132 |
133 | Label {
134 | id: __hint
135 | visible: control.hintText
136 | text: control.hintText
137 |
138 | font.pixelSize: Units.dp(12)
139 | color: control.hasError ? root.errorColor : root.hintColor
140 |
141 | Behavior on color {
142 | ColorAnimation { duration: 200 }
143 | }
144 | }
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/CheckBoxStyle.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.5
2 | import QtQuick.Controls.Styles 1.3
3 | import QtQuick.Controls 1.3
4 | import Mut 0.1
5 | import Mut.Themes 0.1
6 |
7 | CheckBoxStyle {
8 | id: root
9 |
10 | spacing: 0
11 | property CheckBoxPalette palette: Theme.p.checkBox
12 | property color backgroundColor: {
13 | control.checked ?
14 | control.enabled ? palette.backgroundSelected : palette.backgroundSelectedDisabled
15 | : palette.backgroundUnselected
16 | }
17 |
18 | property color borderColor: {
19 | control.checked ? palette.backgroundUnselected :
20 | control.enabled ? palette.borderEnabled : palette.borderDisabled
21 | }
22 |
23 | label: Rectangle {
24 | id: labelRectangle
25 | height: Units.dp(48)
26 |
27 | Text {
28 | id: text
29 | anchors.verticalCenter: parent.verticalCenter
30 | text: control.text
31 |
32 | MouseArea {
33 | anchors.fill: parent
34 | onClicked: control.checked = !control.checked
35 | }
36 | }
37 | }
38 |
39 | indicator: Item {
40 | id: parentRect
41 |
42 | implicitWidth: Units.dp(48)
43 | implicitHeight: Units.dp(48)
44 |
45 | Rectangle {
46 | id: indicatorRect
47 |
48 | color: root.backgroundColor
49 |
50 | anchors.centerIn: parent
51 |
52 | border.width: Units.dp(2)
53 | border.color: root.borderColor
54 |
55 | width: Units.dp(18)
56 | height: Units.dp(18)
57 | radius: Units.dp(2)
58 |
59 | Behavior on color {
60 | ColorAnimation {
61 | easing.type: Easing.InOutQuad
62 | duration: 200
63 | }
64 | }
65 |
66 | Icon {
67 | anchors.centerIn: parent
68 | image.source: Theme.image("check.svg")
69 | image.visible: true
70 | image.smooth: true
71 | image.opacity: control.checked ? 1 : 0
72 | image.width: Units.dp(18)
73 | image.height: Units.dp(18)
74 | colorOverlay: root.palette.iconOverlay
75 | }
76 | }
77 | }
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/FlatButtonStyle.qml:
--------------------------------------------------------------------------------
1 | import Mut 0.1
2 | import Mut.Themes 0.1
3 |
4 | BaseButtonStyle {
5 | elevation: 0
6 |
7 | palette: Theme.p.flatButton
8 | }
9 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/FloatingTextFieldStyle.qml:
--------------------------------------------------------------------------------
1 | import Mut 0.1
2 | import Mut.Themes 0.1
3 |
4 | BaseTextFieldStyle {
5 | palette: Theme.p.textField
6 |
7 | floatingLabel: true
8 | }
9 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/NormalTextFieldStyle.qml:
--------------------------------------------------------------------------------
1 | import Mut 0.1
2 | import Mut.Themes 0.1
3 |
4 | BaseTextFieldStyle {
5 | palette: Theme.p.textField
6 | }
7 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/ProgressBarStyle.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls.Styles 1.3 as Styles
3 | import Mut 0.1
4 | import Mut.Themes 0.1
5 |
6 | Styles.ProgressBarStyle {
7 | id: progressBarStyle
8 |
9 | property color color: Theme.p.primary
10 |
11 | background: Rectangle {
12 | implicitWidth: Units.dp(200)
13 | implicitHeight: Units.dp(4)
14 | color: progressBarStyle.color
15 | opacity: 0.2
16 | }
17 |
18 | progress: Rectangle {
19 | color: control.indeterminate ? "transparent" : progressBarStyle.color
20 |
21 | Rectangle {
22 | id: __progress
23 | visible: control.indeterminate
24 | property int end: 0
25 | width: end - x;
26 | height: parent.height
27 | color: progressBarStyle.color
28 | ParallelAnimation {
29 | running: control.width && control.indeterminate
30 | SequentialAnimation {
31 | loops: Animation.Infinite
32 | PauseAnimation {
33 | duration: 500
34 | }
35 |
36 | NumberAnimation{
37 | target: __progress; property: "x"
38 | from: 0; to: control.width
39 | duration: 2000
40 | easing.type: Easing.InCubic
41 | }
42 | }
43 | SequentialAnimation {
44 | loops: Animation.Infinite
45 | NumberAnimation {
46 | target: __progress; property: "end"
47 | from: 0; to: control.width
48 | duration: 2000
49 | }
50 | PauseAnimation {
51 | duration: 500
52 | }
53 | ScriptAction {
54 | script: __progress.x = 0
55 | }
56 | }
57 | }
58 | }
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/RaisedButtonStyle.qml:
--------------------------------------------------------------------------------
1 | import Mut 0.1
2 | import Mut.Themes 0.1
3 |
4 | BaseButtonStyle {
5 | elevation: 1
6 |
7 | palette: Theme.p.raisedButton
8 | }
9 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/SwitchStyle.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls.Styles 1.3
3 | import Mut 0.1
4 | import Mut.Themes 0.1
5 |
6 | SwitchStyle {
7 | id: style
8 |
9 | property SwitchPalette palette: Theme.p.switchToggle
10 |
11 | property color thumbColor: {
12 | control.enabled ?
13 | control.checked ? palette.thumbOn : palette.thumbOff
14 | : palette.thumbDisabled
15 | }
16 | property color trackColor: {
17 | control.enabled ?
18 | control.checked ? palette.trackOn : palette.trackOff
19 | : palette.trackDisabled
20 | }
21 |
22 | handle: Item {
23 | width: Units.dp(24)
24 | height: Units.dp(24)
25 | Paper {
26 | anchors.centerIn: parent
27 | width: control.pressed ? Units.dp(56) : Units.dp(24)
28 | height: width
29 |
30 | radius: width/2
31 |
32 | backgroundColor: style.trackColor
33 | opacity: control.pressed ? 0.4 : 0
34 |
35 | Behavior on width {
36 | NumberAnimation {duration: 500}
37 | }
38 | Behavior on opacity {
39 | NumberAnimation {duration: 500}
40 | }
41 | }
42 | Paper {
43 | anchors.centerIn: parent
44 | width: Units.dp(24)
45 | height: Units.dp(24)
46 | radius: width/2
47 | circular: true
48 |
49 | elevation: 1
50 | backgroundColor: style.thumbColor
51 | }
52 | }
53 |
54 | groove: Item {
55 | width: Units.dp(42)
56 | height: Units.dp(24)
57 |
58 | Rectangle {
59 | anchors.centerIn: parent
60 |
61 | width: parent.width - Units.dp(2)
62 | height: Units.dp(16)
63 |
64 | radius: height/2
65 |
66 | color: style.trackColor
67 |
68 | Behavior on color {
69 | ColorAnimation {duration: 200}
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/ToolBarStyle.qml:
--------------------------------------------------------------------------------
1 | import QtQuick.Window 2.2
2 | import QtQuick.Controls.Styles 1.3 as Styles
3 |
4 | import Mut 0.1
5 |
6 |
7 | Styles.ToolBarStyle {
8 | id: style
9 |
10 | padding {
11 | // FIXME: adjust paddings depending on device size
12 | left: Units.dp(4)
13 | right: Units.dp(4)
14 | top: 0
15 | bottom: 0
16 | }
17 | background: Paper {
18 | backgroundColor: control.backgroundColor
19 |
20 | fillWidth: control.fillWidth
21 | elevation: control.elevation
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/ToolButtonStyle.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import Mut 0.1
3 | import Mut.Styles 0.1
4 | import Mut.Themes 0.1
5 |
6 | BaseButtonStyle {
7 | id: root
8 | palette: Theme.p.toolButton
9 |
10 | background: Paper {
11 | implicitHeight: Units.dp(48)
12 |
13 | backgroundColor: root.backgroundColor
14 | }
15 | label: Icon {
16 | image.source: control.iconSource
17 | colorOverlay: root.iconColor
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/modules/Mut/Styles/qmldir:
--------------------------------------------------------------------------------
1 | module Mut.Styles
2 | ActionButtonStyle 0.1 ActionButtonStyle.qml
3 | BaseButtonStyle 0.1 BaseButtonStyle.qml
4 | FlatButtonStyle 0.1 FlatButtonStyle.qml
5 | ProgressBarStyle 0.1 ProgressBarStyle.qml
6 | RaisedButtonStyle 0.1 RaisedButtonStyle.qml
7 | ToolBarStyle 0.1 ToolBarStyle.qml
8 | ToolButtonStyle 0.1 ToolButtonStyle.qml
9 | BaseTextFieldStyle 0.1 BaseTextFieldStyle.qml
10 | NormalTextFieldStyle 0.1 NormalTextFieldStyle.qml
11 | FloatingTextFieldStyle 0.1 FloatingTextFieldStyle.qml
12 | SwitchStyle 0.1 SwitchStyle.qml
13 | CheckBoxStyle 0.1 CheckBoxStyle.qml
14 |
--------------------------------------------------------------------------------
/modules/Mut/Surface.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import Mut 0.1
3 |
4 | MouseArea {
5 | id: surface
6 | clip: true
7 |
8 | onPressed: {
9 | ripple.startX = mouse.x;
10 | ripple.startY = mouse.y;
11 | ripple.opacity = 1;
12 | }
13 | onCanceled: {
14 | ripple.opacity = 0;
15 | ripple.radius = 0;
16 | }
17 | onReleased: {
18 | ripple.opacity = 0;
19 | ripple.radius = 0;
20 | }
21 |
22 | Rectangle {
23 | id: background
24 | anchors.fill: parent
25 | color: Qt.rgba(0, 0, 0, 0.05)
26 | opacity: surface.pressed
27 |
28 | Behavior on opacity {
29 | NumberAnimation {}
30 | }
31 | }
32 | Rectangle {
33 | id: ripple
34 | property int startX;
35 | property int startY;
36 |
37 | x: startX - radius; y: startY - radius
38 | width: radius*2; height: radius*2
39 | radius: 0
40 |
41 | color: Qt.rgba(0, 0, 0, 0.05)
42 | opacity: 0
43 |
44 | Behavior on opacity {
45 | NumberAnimation {}
46 | }
47 | SmoothedAnimation on radius {
48 | to: Math.max(surface.width, surface.height)
49 | running: surface.pressed
50 | velocity: Units.dp(100)
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/modules/Mut/TextField.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3 as Controls
3 |
4 | Controls.TextField {
5 | id: textField
6 |
7 | property string hintText
8 | property bool hasError
9 | }
10 |
--------------------------------------------------------------------------------
/modules/Mut/Themes/ButtonPalette.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | QtObject {
4 | id: palette
5 |
6 | property color normal
7 | property color hovered
8 | property color pressed
9 | property color disabled
10 | property color icon
11 | property color text
12 | property color textDisabled
13 | }
14 |
--------------------------------------------------------------------------------
/modules/Mut/Themes/CheckBoxPalette.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | QtObject {
4 | id: checkbox
5 |
6 | property color backgroundSelected
7 | property color backgroundUnselected
8 | property color backgroundSelectedDisabled
9 |
10 | property color borderEnabled
11 | property color borderDisabled
12 |
13 | property color iconOverlay
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/modules/Mut/Themes/ElementPalette.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 |
4 | QtObject {
5 | property color text
6 | property color secondaryText
7 | property color icon
8 | property color hintText
9 | property color disabled
10 | property color divider
11 | }
12 |
--------------------------------------------------------------------------------
/modules/Mut/Themes/Palette.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | QtObject {
4 | id: palette
5 |
6 | /*! \qmlproperty color Palette::background
7 |
8 | Color that matches (as closely as possible) the window background.
9 | */
10 | property color background
11 |
12 | /*! \qmlproperty color Palette::primary
13 |
14 | The primary branding color for the app.
15 | By default, this is the color applied to the action bar background.
16 | */
17 | property color primary
18 | property color primaryLight
19 | property color primaryDark
20 |
21 | /*! \qmlproperty color Palette::accent
22 |
23 | Bright complement to the primary branding color.
24 | */
25 | property color accent
26 | property color accentLight
27 | property color accentDark
28 |
29 | /*! \qmlproperty color Palette::textPrimary
30 |
31 | The most prominent text color.
32 | */
33 | property color textPrimary
34 |
35 | /*! \qmlproperty color Palette::textSecondary
36 |
37 | Secondary text color.
38 | */
39 | property color textSecondary
40 | }
41 |
--------------------------------------------------------------------------------
/modules/Mut/Themes/SwitchPalette.qml:
--------------------------------------------------------------------------------
1 |
2 | import QtQuick 2.4
3 |
4 | QtObject {
5 | id: palette
6 |
7 | property color thumbOn
8 | property color thumbOff
9 | property color thumbDisabled
10 | property color trackOn
11 | property color trackOff
12 | property color trackDisabled
13 | }
14 |
--------------------------------------------------------------------------------
/modules/Mut/Themes/TextFieldPalette.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 |
3 | QtObject {
4 | property color text
5 | property color placeholder
6 | property color normal
7 | property color pressed
8 | property color hint
9 | property color error
10 | property color disabled
11 | }
12 |
--------------------------------------------------------------------------------
/modules/Mut/Themes/Theme.qml:
--------------------------------------------------------------------------------
1 | pragma Singleton
2 |
3 | import QtQuick 2.4
4 |
5 |
6 | QtObject {
7 | id: root
8 |
9 | property url imageAssetsPath
10 |
11 | /*! This is property allows the access to the general
12 | palette and other component-specific palettes.
13 | */
14 | property Palette p: Palette {
15 | id: palette
16 |
17 | background: "#eeeeee"
18 |
19 | primary: "#3f51b5"
20 | primaryLight: "#3949ab"
21 | primaryDark: "#303f9f"
22 |
23 | accent: "#ff4081"
24 | accentLight: "#f50057"
25 | accentDark: "#c51162"
26 |
27 | textPrimary: palette.light.text
28 | textSecondary: palette.dark.secondaryText
29 |
30 | property ElementPalette light: ElementPalette {
31 | text: "#ffffff"
32 | icon: "#ffffff"
33 | secondaryText: Qt.rgba(1, 1, 1, 0.7)
34 | hintText: Qt.rgba(1, 1, 1, 0.3)
35 | disabled: Qt.rgba(1, 1, 1, 0.3)
36 | divider: Qt.rgba(1, 1, 1, 0.12)
37 | }
38 |
39 | property ElementPalette dark: ElementPalette {
40 | text: Qt.rgba(0, 0, 0, 0.87)
41 | icon: Qt.rgba(0, 0, 0, 0.54)
42 | secondaryText: Qt.rgba(0, 0, 0, 0.54)
43 | hintText: Qt.rgba(0, 0, 0, 0.26)
44 | disabled: Qt.rgba(0, 0, 0, 0.26)
45 | divider: Qt.rgba(0, 0, 0, 0.12)
46 | }
47 |
48 | property color divider: palette.dark.divider
49 |
50 | property ButtonPalette flatButton: ButtonPalette {
51 | normal: "transparent"
52 | hovered: "#33999999"
53 | pressed: "#66999999"
54 | disabled: "transparent"
55 | icon: palette.dark.icon
56 | text: palette.dark.text
57 | textDisabled: palette.dark.disabled
58 | }
59 |
60 | property ButtonPalette raisedButton: ButtonPalette {
61 | normal: palette.primary
62 | hovered: palette.primaryLight
63 | pressed: palette.primaryDark
64 | disabled: "#1f000000"
65 | icon: palette.light.icon
66 | text: palette.light.text
67 | textDisabled: palette.dark.disabled
68 | }
69 |
70 | property ButtonPalette toolButton: ButtonPalette {
71 | normal: "transparent"
72 | hovered: "#33999999"
73 | pressed: "#66999999"
74 | disabled: "transparent"
75 | icon: palette.light.icon
76 | text: palette.light.text
77 | textDisabled: palette.light.disabled
78 | }
79 |
80 | property ButtonPalette actionButton: ButtonPalette {
81 | normal: palette.accent
82 | hovered: palette.accentLight
83 | pressed: palette.accentDark
84 | disabled: "#1f000000"
85 | icon: palette.light.icon
86 | text: palette.light.text
87 | textDisabled: palette.light.disabled
88 | }
89 |
90 | property TextFieldPalette textField: TextFieldPalette {
91 | text: palette.dark.text
92 | placeholder: palette.dark.hintText
93 | normal: palette.dark.hintText
94 | pressed: palette.primary
95 | hint: palette.dark.hintText
96 | error: "#f44336"
97 | disabled: palette.dark.disabled
98 | }
99 |
100 | property SwitchPalette switchToggle: SwitchPalette {
101 | thumbOn: palette.accent
102 | thumbOff: "#fafafa"
103 | thumbDisabled: "#bdbdbd"
104 |
105 | trackOn: Qt.rgba(thumbOn.r, thumbOn.g, thumbOn.b, 0.5)
106 | trackOff: palette.dark.disabled
107 | trackDisabled: palette.dark.divider
108 | }
109 |
110 | property CheckBoxPalette checkBox: CheckBoxPalette {
111 | backgroundSelected: palette.accent
112 | backgroundUnselected: "transparent"
113 | backgroundSelectedDisabled: palette.dark.disabled
114 |
115 | borderEnabled: palette.dark.secondaryText
116 | borderDisabled: palette.dark.disabled
117 |
118 | iconOverlay: palette.light.icon
119 | }
120 | }
121 |
122 | function image(name) {
123 | if (root.imageAssetsPath == "") {
124 | return "";
125 | }
126 | return Qt.resolvedUrl(root.imageAssetsPath + name);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/modules/Mut/Themes/qmldir:
--------------------------------------------------------------------------------
1 | module Mut.Themes
2 | CheckBoxPalette 0.1 CheckBoxPalette.qml
3 | ButtonPalette 0.1 ButtonPalette.qml
4 | ElementPalette 0.1 ElementPalette.qml
5 | TextFieldPalette 0.1 TextFieldPalette.qml
6 | SwitchPalette 0.1 SwitchPalette.qml
7 | Palette 0.1 Palette.qml
8 | singleton Theme 0.1 Theme.qml
9 |
--------------------------------------------------------------------------------
/modules/Mut/ToolBar.qml:
--------------------------------------------------------------------------------
1 | import QtQuick.Controls 1.2 as Controls
2 | import Mut 0.1
3 | import Mut.Styles 0.1
4 | import Mut.Themes 0.1
5 |
6 | /*! \qmltype ToolBar
7 | \inqmlmodule Mut 0.1
8 | \ingroup toolbar
9 |
10 | \brief Provides a generic toolbar component.
11 |
12 | ToolBar extends \l {QtQuick.Controls::ToolBar}
13 | */
14 | Controls.ToolBar {
15 | id: toolbar
16 |
17 | /*! \qmlproperty color ToolBar::backgroundColor
18 |
19 | The background color for the toolbar.
20 | */
21 | property color backgroundColor: Theme.p.primary
22 |
23 | /*! \qmlproperty color ToolBar::elevation
24 |
25 | The elevation level for the toolbar.
26 | Default elevation is 0.
27 | */
28 | property real elevation: 0
29 |
30 | property bool fillWidth: false
31 |
32 | style: ToolBarStyle {}
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/modules/Mut/qmldir:
--------------------------------------------------------------------------------
1 | module Mut
2 | AppBar 0.1 AppBar.qml
3 | ApplicationWindow 0.1 ApplicationWindow.qml
4 | DebugOutline 0.1 DebugOutline.qml
5 | Divider 0.1 Divider.qml
6 | Dialog 0.1 Dialog.qml
7 | singleton Device 0.1 Device.qml
8 | Icon 0.1 Icon.qml
9 | Page 0.1 Page.qml
10 | Paper 0.1 Paper.qml
11 | Popup 0.1 Popup.qml
12 | Card 0.1 Card.qml
13 | Surface 0.1 Surface.qml
14 | ToolBar 0.1 ToolBar.qml
15 | Scrim 0.1 Scrim.qml
16 | NavDrawer 0.1 NavDrawer.qml
17 | TextField 0.1 TextField.qml
18 | singleton Units 0.1 units.qml
19 |
--------------------------------------------------------------------------------
/modules/Mut/units.qml:
--------------------------------------------------------------------------------
1 | pragma Singleton
2 |
3 | import QtQuick 2.4
4 | import QtQuick.Window 2.2
5 |
6 | QtObject {
7 | id: units
8 |
9 | /*! Global font scale factor */
10 | property real fontScale: 1.0;
11 |
12 | /*! System pixel density. Usually this is Screen.pixelDensity */
13 | property real pixelDensity;
14 |
15 | function factor() {
16 | return (pixelDensity*25.4)/160;
17 | }
18 |
19 | /*! Method to compute component size using device independent pixels */
20 | function dp(number) {
21 | return Math.round(number*((pixelDensity*25.4)/160));
22 | }
23 |
24 | /*! Method to compute device independent pixels from real pixels */
25 | function pxToDp(number) {
26 | return number / Math.round(((pixelDensity*25.4)/160));
27 | }
28 |
29 | /*! Method to compute font sizes using device independent pixels
30 | and a global font scaling factor.
31 | */
32 | function sp(number) {
33 | return dp(number) * units.fontScale;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/modules/modules.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = aux
2 |
3 | deployment.files += \
4 | qmldir \
5 | *.qml \
6 | Mut
7 |
8 | INSTALLS += deployment
9 | OTHER_FILES += $$deployment.files
10 |
11 | isEmpty(DESTDIR) {
12 | DESTDIR = $$OUT_PWD
13 | }
14 |
15 | # does not work when template is subdirs
16 | !equals(_PRO_FILE_PWD_, $$OUT_PWD) {
17 | copy_modules.target = mymodule
18 | win32 {
19 | modulePath = $$PWD/Mut
20 | destPath = $$DESTDIR/Mut
21 | copy_modules.commands = \
22 | $(COPY_DIR) $$replace(modulePath, \/, \\) $$replace(destPath, \/, \\)
23 | } else {
24 | copy_modules.commands = $(COPY_DIR) $$PWD/Mut $$DESTDIR
25 | }
26 |
27 | QMAKE_EXTRA_TARGETS += copy_modules
28 | POST_TARGETDEPS += $$copy_modules.target
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/mut.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = subdirs
2 | SUBDIRS = modules
3 |
4 | !no-mut-examples {
5 | SUBDIRS += examples
6 | examples.depends = modules
7 | }
8 |
9 | !no-mut-tests {
10 | SUBDIRS += tests
11 | tests.depends = modules
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/tests/test.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/tests.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | QUICK_TEST_MAIN(Mut)
3 |
--------------------------------------------------------------------------------
/tests/tests.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 | TARGET = tst_mut
3 | CONFIG += qmltestcase
4 | SOURCES += tests.cpp
5 |
6 | IMPORTPATH = $$PWD/../modules
7 |
8 | RESOURCES += tests.qrc
9 |
10 | OTHER_FILES += \
11 | tst_appbar.qml \
12 | tst_application_window \
13 | tst_button_style.qml \
14 | tst_conditional_layout.qml \
15 | tst_device_layout.qml \
16 | tst_divider.qml \
17 | tst_icon.qml \
18 | tst_orientation_layout.qml \
19 | tst_page.qml \
20 | tst_paper.qml \
21 | tst_theme.qml \
22 | tst_toolbar.qml \
23 | tst_units.qml
24 |
25 |
--------------------------------------------------------------------------------
/tests/tests.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | test.svg
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/tests/tst_appbar.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 | import Mut.Themes 0.1
6 |
7 | TestCase {
8 | id: testCase
9 | name: "Tests_AppBar"
10 |
11 | function initTestCase() {
12 | Units.pixelDensity = 5.0;
13 | }
14 |
15 | /* tests that the default value of the properties are correct */
16 | function test_defaults() {
17 | var tmp = Qt.createQmlObject(
18 | 'import Mut 0.1; AppBar {id: appbar1}',
19 | testCase, '');
20 |
21 | compare(tmp.defaultNavAction, null);
22 | compare(tmp.elevation, 2);
23 | compare(tmp.fillWidth, true);
24 | tmp.destroy();
25 | }
26 |
27 | /* tests that appbar is resized properly when device size and
28 | screen orientation changes.
29 | */
30 | function test_implicitHeight() {
31 | var tmp = Qt.createQmlObject(
32 | 'import Mut 0.1; AppBar {id: appbar1}',
33 | testCase, '');
34 |
35 | Device.size = Device.sizeXLarge;
36 | compare(tmp.implicitHeight, Units.dp(64));
37 |
38 | Device.size = Device.sizeNormal;
39 | Device.primaryOrientation = Qt.PortraitOrientation;
40 | compare(tmp.implicitHeight, Units.dp(56));
41 |
42 | Device.primaryOrientation = Qt.LandscapeOrientation;
43 | compare(tmp.implicitHeight, Units.dp(48));
44 |
45 | tmp.destroy();
46 | }
47 |
48 | function test_defaultNavAction() {
49 | var tmp = Qt.createQmlObject(
50 | 'import QtQuick.Controls 1.3; import Mut 0.1;' +
51 | 'AppBar {id: appbar1; defaultNavAction: Action {}}',
52 | testCase, '');
53 | tmp.destroy();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/tst_application_window.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 |
6 | Item {
7 | id: container
8 | width: 300; height: 300
9 |
10 | Page {
11 | id: page1
12 | }
13 |
14 | Page {
15 | id: page2
16 | }
17 |
18 | ApplicationWindow {
19 | id: app
20 | }
21 |
22 | TestCase {
23 | id: testCase
24 | name: "Tests_ApplicationWindow"
25 | when: windowShown
26 | width: 300; height: 300
27 |
28 | function initTestCase() {
29 | Units.pixelDensity = 5.0;
30 | }
31 |
32 | /* tests that Device singleton is initialized when ApplicationWindow
33 | loading is completed
34 | */
35 | function test_deviceIsInitialized() {
36 | verify(Device.primaryOrientation !== 0, "primaryOrientation not set");
37 | verify(Device.size !== 0, "device size not set");
38 | }
39 |
40 | /* tests that the ESC button pops the last page */
41 | function test_esc_button() {
42 | app.pageStack.push(page1);
43 | app.pageStack.push(page2);
44 |
45 | keyClick(Qt.Key_Escape);
46 | // TODO: this test doesn't work; there is a problem with the ApplicationWindow focus
47 | // compare(app.pageStack.currentItem, page1);
48 |
49 | app.pageStack.clear();
50 | }
51 |
52 | /* tests that the back button pops the last page */
53 | function test_back_button() {
54 | app.pageStack.push(page1);
55 | app.pageStack.push(page2);
56 |
57 | keyClick(Qt.Key_Back);
58 | // TODO: this test doesn't work; there is a problem with the ApplicationWindow focus
59 | // compare(app.pageStack.currentItem, page1);
60 |
61 | app.pageStack.clear();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tests/tst_button_style.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import QtTest 1.0
4 |
5 | import Mut 0.1
6 | import Mut.Styles 0.1
7 | import Mut.Themes 0.1
8 |
9 | Item {
10 | id: container
11 | width: 300; height: 300
12 |
13 | Button {
14 | id: button
15 | style: BaseButtonStyle {
16 | id: style
17 | elevation: 1
18 | palette: ButtonPalette {
19 | normal: "#ff0000"
20 | hovered: "#00ff00"
21 | pressed: "#0000ff"
22 | disabled: "#aaaaaa"
23 | text: "#ffffff"
24 | textDisabled: "#eeeeee"
25 |
26 | }
27 | }
28 | }
29 |
30 | TestCase {
31 | id: testCase
32 | name: "Tests_ButtonStyle"
33 | when: windowShown
34 | width: 300; height: 300
35 |
36 | function initTestCase() {
37 | Units.pixelDensity = 5;
38 | }
39 |
40 | /* tests default elevation */
41 | function test_defaultElevation() {
42 | compare(button.__style.elevation, 1);
43 | }
44 |
45 | /* tests colors on normal state */
46 | function test_defaultColors() {
47 | compare(button.__style.backgroundColor, "#ff0000");
48 | compare(button.__style.textColor, "#ffffff");
49 | }
50 |
51 | /* tests colors on pressed state */
52 | function test_pressedColors() {
53 | mousePress(button);
54 | compare(button.__style.backgroundColor, "#0000ff");
55 | mouseRelease(button);
56 | }
57 |
58 | /* tests colors on hovered state */
59 | function test_hoveredColors() {
60 | mouseMove(button);
61 | compare(button.__style.backgroundColor, "#00ff00");
62 | }
63 |
64 | /* tests colors on disabled state */
65 | function test_disabledColors() {
66 | button.enabled = false;
67 | compare(button.__style.backgroundColor, "#aaaaaa");
68 | compare(button.__style.textColor, "#eeeeee");
69 | button.enabled = true;
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/tests/tst_card.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import QtTest 1.0
4 |
5 | import Mut 0.1
6 |
7 | Item {
8 | id: container
9 | width: 800; height: 600
10 |
11 | Card {
12 | id: card
13 | width: Units.dp(200); height: Units.dp(200)
14 | }
15 |
16 | TestCase {
17 | id: testCase
18 | name: "Tests_Card"
19 | when: windowShown
20 | width: 800; height: 600
21 |
22 | function initTestCase() {
23 | Units.pixelDensity = 5;
24 | }
25 |
26 | /* it should have a radius and an elevation */
27 | function test_state_default() {
28 | compare(card.elevation, 1);
29 | compare(card.radius, Units.dp(2));
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/tst_conditional_layout.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 | import Mut.Layouts 0.1
6 |
7 | Item {
8 | id: container
9 | width: 300; height: 300
10 |
11 | Component {
12 | id: first_layout
13 |
14 | Item {
15 | Rectangle { width: 80; height: 80; border.width: 1 }
16 | }
17 | }
18 |
19 | Component {
20 | id: second_layout
21 |
22 | Item {
23 | Rectangle { width: 80; height: 80; border.width: 1 }
24 | }
25 | }
26 |
27 | ConditionalLayout {
28 | id: layout
29 | }
30 |
31 | TestCase {
32 | id: testCase
33 | name: "Tests_ConditionalLayout"
34 | when: windowShown
35 | width: 300; height: 300
36 |
37 | function initTestCase() {
38 | Units.pixelDensity = 5;
39 | }
40 |
41 | /* it shouldn't draw any component */
42 | function test_no_components() {
43 | layout.layouts = []
44 | layout.when = -1
45 | compare(layout.activeComponent, null);
46 | }
47 |
48 | /* it should draw the first layout */
49 | function test_one_layout() {
50 | layout.layouts = [first_layout]
51 | layout.when = 0
52 | compare(layout.activeComponent, first_layout);
53 | }
54 |
55 | /* it should draw the first layout and the second when 'when' property changes */
56 | function test_layout_switching() {
57 | layout.layouts = [first_layout, second_layout]
58 | layout.when = 0
59 | compare(layout.activeComponent, first_layout);
60 | layout.when = 1
61 | compare(layout.activeComponent, second_layout);
62 | }
63 |
64 | /* it should fallback to a previous layout if the chosen is not available */
65 | function test_layout_fallback() {
66 | layout.layouts = [first_layout, second_layout]
67 | layout.when = 4
68 | compare(layout.activeComponent, second_layout);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/tst_device_layout.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 | import Mut.Layouts 0.1
6 |
7 | Item {
8 | id: container
9 | width: 300; height: 300
10 |
11 | Component {
12 | id: small
13 |
14 | Item {
15 | Rectangle { width: 80; height: 80; border.width: 1 }
16 | }
17 | }
18 |
19 | Component {
20 | id: normal
21 |
22 | Item {
23 | Rectangle { width: 80; height: 80; border.width: 1 }
24 | }
25 | }
26 |
27 | Component {
28 | id: large
29 |
30 | Item {
31 | Rectangle { width: 80; height: 80; border.width: 1 }
32 | }
33 | }
34 |
35 | DeviceLayout {
36 | id: layout
37 | }
38 |
39 | TestCase {
40 | id: testCase
41 | name: "Tests_DeviceLayout"
42 | when: windowShown
43 | width: 300; height: 300
44 |
45 | function initTestCase() {
46 | Units.pixelDensity = 5;
47 | layout.layouts = [small, normal, large]
48 | }
49 |
50 | /* it should use the right layout according to device size */
51 | function test_size_layout() {
52 | Device.size = Device.sizeSmall;
53 | compare(layout.activeComponent, small);
54 | Device.size = Device.sizeNormal;
55 | compare(layout.activeComponent, normal);
56 | Device.size = Device.sizeLarge;
57 | compare(layout.activeComponent, large);
58 | }
59 |
60 | /* it should use the layout that best fits the device size */
61 | function test_size_fallback_layout() {
62 | Device.size = Device.sizeXLarge;
63 | compare(layout.activeComponent, large);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/tst_divider.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 | import Mut.Themes 0.1
6 |
7 | TestCase {
8 | id: testCase
9 | name: "Tests_Divider"
10 |
11 | function initTestCase() {
12 | Units.pixelDensity = 5.0;
13 | }
14 |
15 | /* tests that the default value of the properties are correct */
16 | function test_defaults() {
17 | var tmp = Qt.createQmlObject(
18 | 'import Mut 0.1; Divider {id: divider1}',
19 | testCase, '');
20 | compare(tmp.height, Units.dp(1));
21 | Theme.p.divider = "blue";
22 | compare(tmp.color, "#0000ff");
23 | tmp.destroy();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/tst_icon.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 |
6 | Item {
7 | id: container
8 | width: 300; height: 300
9 |
10 | TestCase {
11 | id: testCase
12 | name: "Tests_Icon"
13 | when: windowShown
14 |
15 | function initTestCase() {
16 | Units.pixelDensity = 5.0;
17 | }
18 |
19 | /* tests that the default value of the properties are correct */
20 | function test_defaults() {
21 | var tmp = Qt.createQmlObject(
22 | 'import QtQuick 2.4; import Mut 0.1;' +
23 | 'Icon {id: icon1; image.source: Qt.resolvedUrl("test.svg")}',
24 | testCase, '');
25 | compare(tmp.image.visible, false);
26 | tmp.destroy();
27 | }
28 |
29 | function benchmark_overlayicon_transparent() {
30 | var tmp = Qt.createQmlObject(
31 | 'import QtQuick 2.4; import Mut 0.1;' +
32 | 'Icon {id: icon2; image.source: Qt.resolvedUrl("test.svg")}',
33 | testCase, '');
34 | tmp.destroy();
35 | }
36 | function benchmark_overlayicon_solid() {
37 | var tmp = Qt.createQmlObject(
38 | 'import QtQuick 2.4; import Mut 0.1;' +
39 | 'Icon {id: icon3; colorOverlay: "#ff0000";' +
40 | 'image.source: Qt.resolvedUrl("test.svg")}',
41 | testCase, '');
42 | tmp.destroy();
43 | }
44 | function benchmark_normal_image() {
45 | var tmp = Qt.createQmlObject(
46 | 'import QtQuick 2.4; import Mut 0.1;' +
47 | 'Image {' +
48 | 'sourceSize {height: Units.dp(24); width: Units.dp(24)}' +
49 | 'anchors.centerIn: parent; smooth: false;' +
50 | 'source: Qt.resolvedUrl("test.svg")}',
51 | testCase, '');
52 | tmp.destroy();
53 | }
54 | }
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/tests/tst_navdrawer.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import QtTest 1.0
4 |
5 | import Mut 0.1
6 |
7 | Item {
8 | id: container
9 | width: 800; height: 600
10 |
11 | NavDrawer {
12 | id: drawer
13 | focus: true
14 | }
15 |
16 | TestCase {
17 | id: testCase
18 | name: "Tests_NavDrawer"
19 | when: windowShown
20 | width: 800; height: 600
21 |
22 | function initTestCase() {
23 | Units.pixelDensity = 5;
24 | }
25 |
26 | /* it should be closed as default */
27 | function test_state_default() {
28 | compare(drawer.state, "DRAWER_CLOSED");
29 | }
30 |
31 | /* it should change the current state when open() is called */
32 | function test_state_open() {
33 | drawer.open();
34 | compare(drawer.state, "DRAWER_OPENED");
35 | drawer.state = "DRAWER_CLOSED";
36 | }
37 |
38 | /* it should change the current state when close() is called */
39 | function test_state_close() {
40 | drawer.state = "DRAWER_OPENED";
41 | drawer.close();
42 | compare(drawer.state, "DRAWER_CLOSED");
43 | }
44 |
45 | /* it should expose a toggle() state that opens and closes the component */
46 | function test_state_toggle() {
47 | drawer.toggle();
48 | compare(drawer.state, "DRAWER_OPENED");
49 | drawer.toggle();
50 | compare(drawer.state, "DRAWER_CLOSED");
51 | }
52 |
53 | /* it should close the component when the Scrim is clicked */
54 | function test_close_on_scrim_click() {
55 | drawer.state = "DRAWER_OPENED";
56 |
57 | // transitions require this wait otherwise the Scrim is not ready to
58 | // accept events
59 | wait(150);
60 |
61 | mouseClick(container);
62 | compare(drawer.state, "DRAWER_CLOSED");
63 | }
64 |
65 | /* it should expose two status getters */
66 | function test_state_getters() {
67 | drawer.state = "DRAWER_OPENED";
68 | verify(drawer.opened);
69 | drawer.state = "DRAWER_CLOSED";
70 | verify(!drawer.opened);
71 | }
72 |
73 | /* the ESC button should close the drawer */
74 | function test_esc_button() {
75 | drawer.state = "DRAWER_OPENED";
76 | keyClick(Qt.Key_Escape);
77 | compare(drawer.state, "DRAWER_CLOSED");
78 | }
79 |
80 | /* the mobile back button should close the drawer */
81 | function test_back_button() {
82 | drawer.state = "DRAWER_OPENED";
83 | keyClick(Qt.Key_Back);
84 | compare(drawer.state, "DRAWER_CLOSED");
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/tests/tst_orientation_layout.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 | import Mut.Layouts 0.1
6 |
7 | Item {
8 | id: container
9 | width: 300; height: 300
10 |
11 | Component {
12 | id: portrait
13 |
14 | Item {
15 | Rectangle { width: 80; height: 80; border.width: 1 }
16 | }
17 | }
18 |
19 | Component {
20 | id: landscape
21 |
22 | Item {
23 | Rectangle { width: 80; height: 80; border.width: 1 }
24 | }
25 | }
26 |
27 | OrientationLayout {
28 | id: layout
29 | }
30 |
31 | TestCase {
32 | id: testCase
33 | name: "Tests_OrientationLayout"
34 | when: windowShown
35 | width: 300; height: 300
36 |
37 | function initTestCase() {
38 | Units.pixelDensity = 5;
39 | layout.layouts = [portrait, landscape]
40 | }
41 |
42 | /* it should use the portrait layout when in portrait mode */
43 | function test_portrait_layout() {
44 | Device.primaryOrientation = Qt.PortraitOrientation
45 | compare(layout.activeComponent, portrait);
46 | }
47 |
48 | /* it should use the landscape layout when in landscape mode */
49 | function test_landscape_layout() {
50 | Device.primaryOrientation = Qt.LandscapeOrientation
51 | compare(layout.activeComponent, landscape);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/tests/tst_page.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import QtTest 1.0
4 |
5 | import Mut 0.1
6 |
7 | Item {
8 | width: Units.dp(100); height: Units.dp(200)
9 | StackView {
10 | id: stackView
11 | anchors.fill: parent
12 | }
13 | TestCase {
14 | id: testCase
15 | name: "Tests_Page"
16 | when: windowShown
17 |
18 | function initTestCase() {
19 | Units.pixelDensity = 5.0;
20 | }
21 |
22 | /* tests the api to push and pop pages */
23 | function test_pagePushPop() {
24 | var page = Qt.createQmlObject(
25 | 'import Mut 0.1; Page {id: page1}',
26 | testCase, '');
27 | var tmp = Qt.createQmlObject(
28 | 'import Mut 0.1; Page {id: page2}',
29 | testCase, '');
30 |
31 | stackView.push(page);
32 | page.push(tmp);
33 | compare(stackView.currentItem, tmp);
34 |
35 | tmp.pop();
36 | compare(stackView.currentItem, page);
37 |
38 | stackView.clear();
39 | page.destroy();
40 | tmp.destroy();
41 | }
42 |
43 | /* tests that the default navigation action pops the
44 | current page from the stack.
45 | */
46 | function test_defaultNavAction() {
47 | var page = Qt.createQmlObject(
48 | 'import Mut 0.1; Page {id: page1}',
49 | testCase, '');
50 | var tmp = Qt.createQmlObject(
51 | 'import Mut 0.1; Page {id: page1}',
52 | testCase, '');
53 |
54 | stackView.push(page);
55 | page.push(tmp);
56 | tmp.navAction.trigger();
57 | compare(stackView.currentItem, page);
58 |
59 | stackView.clear();
60 | page.destroy();
61 | tmp.destroy();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tests/tst_paper.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 |
6 |
7 | TestCase {
8 | id: testCase
9 | name: "Tests_Paper"
10 |
11 | function initTestCase() {
12 | Units.pixelDensity = 5.0;
13 | }
14 |
15 | /* tests that the default value of the properties are correct */
16 | function test_defaults() {
17 | var tmp = Qt.createQmlObject(
18 | 'import Mut 0.1; Paper {id: paper1}',
19 | testCase, '');
20 | compare(tmp.elevation, 0);
21 | compare(tmp.fillWidth, false);
22 | compare(tmp.fillHeight, false);
23 | tmp.destroy()
24 | }
25 |
26 | /* tests that effect's properties change accordingly to elevation
27 | * attribute */
28 | function test_elevation() {
29 | var tmp = Qt.createQmlObject(
30 | 'import Mut 0.1; Paper {id: paper1}',
31 | testCase, '');
32 | tmp.elevation = 0.0;
33 | compare(tmp.children[1].glowRadius, 0); // topEffect
34 | compare(tmp.children[2].glowRadius, 0); // bottomEffect
35 |
36 | tmp.elevation = 1.0;
37 | compare(tmp.children[1].glowRadius, 2.0); // topEffect
38 | compare(tmp.children[2].glowRadius, 1.0); // bottomEffect
39 |
40 | tmp.destroy();
41 | }
42 |
43 | /* tests that there is no shadow when elevation is 0 */
44 | function test_no_shadow_when_elevation_is_zero() {
45 | var tmp = Qt.createQmlObject(
46 | 'import Mut 0.1; ' +
47 | 'Paper {id: paper1; elevation: 0}',
48 | testCase, '');
49 | compare(tmp.__hasShadow, false);
50 | compare(tmp.children[0].visible, false);
51 | compare(tmp.children[1].visible, false);
52 | }
53 |
54 | /* tests that there is no shadow when paper background is
55 | * transparent */
56 | function test_no_shadow_when_transparent() {
57 | var tmp = Qt.createQmlObject(
58 | 'import Mut 0.1; ' +
59 | 'Paper {id: paper1; backgroundColor: "transparent"}',
60 | testCase, '');
61 | compare(tmp.__hasShadow, false);
62 | compare(tmp.children[0].visible, false);
63 | compare(tmp.children[1].visible, false);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tests/tst_scrim.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import QtTest 1.0
4 |
5 | import Mut 0.1
6 |
7 | Item {
8 | id: container
9 | width: 300; height: 300
10 |
11 | SignalSpy {
12 | id: button_spy
13 | target: button
14 | signalName: "clicked"
15 | }
16 |
17 | Button {
18 | id: button
19 | }
20 |
21 | Scrim {
22 | id: scrim
23 | anchors.fill: parent
24 | }
25 |
26 | TestCase {
27 | id: testCase
28 | name: "Tests_Scrim"
29 | when: windowShown
30 | width: 300; height: 300
31 |
32 | function initTestCase() {
33 | Units.pixelDensity = 5;
34 | }
35 |
36 | /* should capture all mouse events */
37 | function test_overlay_events_capture() {
38 | mouseClick(button);
39 | compare(button_spy.count, 0);
40 | button_spy.clear();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/tst_single_line_item.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import QtTest 1.0
4 |
5 | import Mut 0.1
6 | import Mut.Themes 0.1
7 | import Mut.ListItems 0.1
8 |
9 | Item {
10 | id: container
11 | width: 300; height: 300
12 |
13 | Action {
14 | id: primary_action
15 | onTriggered: {
16 | console.log("primary")
17 | }
18 | }
19 |
20 | Action {
21 | id: primary_action_with_icon
22 | iconSource: Qt.resolvedUrl("test.svg")
23 | onTriggered: {
24 | console.log("primary with icon")
25 | }
26 | }
27 |
28 | Action {
29 | id: secondary_action
30 | iconSource: Qt.resolvedUrl("test.svg")
31 | onTriggered: {
32 | console.log("secondary")
33 | }
34 | }
35 |
36 | SingleLineItem {
37 | id: single_line
38 | text: "Single line item"
39 |
40 | SignalSpy {
41 | id: primary_spy
42 | target: primary_action
43 | signalName: "triggered"
44 | }
45 |
46 | SignalSpy {
47 | id: secondary_spy
48 | target: secondary_action
49 | signalName: "triggered"
50 | }
51 |
52 | primaryAction: primary_action
53 | secondaryAction: secondary_action
54 | }
55 |
56 | TestCase {
57 | id: testCase
58 | name: "Tests_SingleLineItem"
59 | when: windowShown
60 | width: 300; height: 300
61 |
62 | function initTestCase() {
63 | Units.pixelDensity = 5;
64 | }
65 |
66 | /* it should trigger the surface action */
67 | function test_click_on_surface() {
68 | mouseClick(single_line);
69 | compare(primary_spy.count, 1);
70 | compare(secondary_spy.count, 0);
71 | primary_spy.clear();
72 | secondary_spy.clear();
73 | }
74 |
75 | /* it should trigger the supplemental action */
76 | function test_click_on_supplemental_action() {
77 | mouseClick(single_line, single_line.width - Units.dp(16));
78 | compare(primary_spy.count, 0);
79 | compare(secondary_spy.count, 1);
80 | primary_spy.clear();
81 | secondary_spy.clear();
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/tests/tst_theme.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 | import Mut.Themes 0.1
6 |
7 |
8 | TestCase {
9 | name: "Tests_Theme"
10 |
11 | /* tests image function returns the correct path
12 | based on the imageAssetsPath value
13 | */
14 | function test_image() {
15 | var result = Theme.image('foo.svg');
16 | compare(result, "");
17 |
18 | Theme.imageAssetsPath = "/assets/";
19 | result = Theme.image('foo.svg');
20 | compare(result, "file:///assets/foo.svg");
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/tests/tst_tile.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtQuick.Controls 1.3
3 | import QtTest 1.0
4 |
5 | import Mut 0.1
6 | import Mut.Themes 0.1
7 | import Mut.ListItems 0.1
8 |
9 | Item {
10 | id: container
11 | width: 300; height: 300
12 |
13 | Component {
14 | id: primary
15 |
16 | Text {
17 | text: "Hello world!"
18 | }
19 | }
20 |
21 | Component {
22 | id: secondary
23 |
24 | Button {
25 | action: Action {
26 | iconSource: Qt.resolvedUrl("test.svg")
27 | }
28 | }
29 | }
30 |
31 | Tile {
32 | id: tile
33 | primaryComponent: primary
34 | }
35 |
36 | TestCase {
37 | id: testCase
38 | name: "Tests_Tile"
39 | when: windowShown
40 | width: 300; height: 300
41 |
42 | function initTestCase() {
43 | Units.pixelDensity = 5;
44 | }
45 |
46 | /* default background color should be white */
47 | function test_background_default() {
48 | compare(tile.backgroundColor, Theme.p.background);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/tests/tst_toolbar.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 | import Mut.Themes 0.1
6 |
7 | TestCase {
8 | id: testCase
9 | name: "Tests_ToolBar"
10 |
11 | /* tests that the default value of the properties are correct */
12 | function test_defaults() {
13 | var tmp = Qt.createQmlObject(
14 | 'import Mut 0.1; ToolBar {id: toobar1}',
15 | testCase, '');
16 |
17 | Theme.p.primary = "blue";
18 | compare(tmp.backgroundColor, "#0000ff");
19 | Theme.p.primary = "red";
20 | compare(tmp.backgroundColor, "#ff0000");
21 |
22 | compare(tmp.elevation, 0);
23 | compare(tmp.fillWidth, false);
24 | tmp.destroy()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/tst_units.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.4
2 | import QtTest 1.0
3 |
4 | import Mut 0.1
5 |
6 |
7 | TestCase {
8 | name: "Tests_Units"
9 |
10 | /* tests dp computes correct component size */
11 | function test_dp() {
12 | Units.pixelDensity = 5;
13 | compare(Units.dp(10), 8);
14 |
15 | Units.pixelDensity = 10;
16 | compare(Units.dp(10), 16);
17 | }
18 |
19 | /* tests sp computes correct font size */
20 | function test_sp() {
21 | Units.pixelDensity = 5;
22 | compare(Units.sp(10), 8);
23 |
24 | Units.fontScale = 4;
25 | compare(Units.sp(10), 32)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------