diff --git a/HIG/source/layout/gestures.rst b/HIG/source/layout/gestures.rst
new file mode 100644
index 0000000..545523f
--- /dev/null
+++ b/HIG/source/layout/gestures.rst
@@ -0,0 +1,144 @@
+Gestures
+========
+
+Purpose
+-------
+
+Gestures are a way to perform common tasks faster und more intuitively. They
+should never be the only way to perform an action, but rather be treated like a
+keybord shortcut or a context menu item.
+
+Principles
+----------
+
+Unless you are creating a video game, avoid using non-standard gestures.
+Don't abuse the standard gestures to trigger non-standard actions. For example
+don't use a pinch gesture to delete an item; only use that gesture for zooming or scaling content.
+
+Systemwide gestures
+--------------------
+
+Avoid interfering with systemwide screen edge gestures like pulling down the
+top panel on Plasma Mobile.
+
+Desktop
+~~~~~~~
+
+================== =================================
+Gesture Action
+================== =================================
+Switch workspace
+Show app overview
+================== =================================
+
+
+Mobile
+~~~~~~
+
+================== =================================
+Gesture Action
+================== =================================
+Edge swipe top Pull down the top panel
+================== =================================
+
+
+Application gestures
+--------------------
+
+Gestures are commonly used both on desktop and on mobile. They
+can be used to navigate, trigger actions, or manipulate content.
+
+Tap
+~~~
+
+.. raw:: html
+
+
+
+A tap is handled like a mouse click. It can be used to navigate, trigger
+actions, or manipulate content.
+
+Long press
+~~~~~~~~~~
+
+A Long press can trigger additional actions on an item or a control or enter a different mode.
+
+Swipe
+~~~~~
+
+Swipes can execute actions on list items and
+navigate between views.
+
+.. raw:: html
+
+
+
+Swipe navigation in a column view.
+
+Pinch
+~~~~~
+
+.. raw:: html
+
+
+
+Scales content
+
+Rotate
+~~~~~~
+
+.. raw:: html
+
+
+
+Rotate content.
+
+
+Mobile
+~~~~~~
+
+Aditionally to the common gestures, there a gestures especially for Plamsa
+Mobile.
+
+Swipe to reveal
+^^^^^^^^^^^^^^^
+
+.. raw:: html
+
+
+
+Reveal on-demand actions for list items.
+
+Edge swipe left
+^^^^^^^^^^^^^^^
+
+.. raw:: html
+
+
+
+Open the global drawer.
+
+Edge swipe right
+^^^^^^^^^^^^^^^^
+
+.. raw:: html
+
+
+
+Open the context drawer.
+
+
diff --git a/HIG/source/layout/index.rst b/HIG/source/layout/index.rst
index 1c7a84b..b4aed63 100644
--- a/HIG/source/layout/index.rst
+++ b/HIG/source/layout/index.rst
@@ -1,19 +1,21 @@
Layout
======
.. toctree::
:maxdepth: 1
:caption: Contents:
:titlesonly:
:hidden:
units
metrics
alignment
onehand
+ gestures
* :doc:`units`
* :doc:`metrics`
* :doc:`alignment`
* :doc:`onehand`
+* :doc:`gestures`
diff --git a/HIG/source/qml/files/Folder.qml b/HIG/source/qml/files/Folder.qml
index 1bd07be..7128d7a 100644
--- a/HIG/source/qml/files/Folder.qml
+++ b/HIG/source/qml/files/Folder.qml
@@ -1,86 +1,73 @@
/*
* Copyright 2018 Fabian Riethmayer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.6
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.2
import org.kde.kirigami 2.4 as Kirigami
Kirigami.ScrollablePage {
property alias currentIndex: list.currentIndex;
property var pagemodel;
property var pageroot;
Kirigami.Theme.colorSet: Kirigami.Theme.View
title: pagemodel.name
id: page
background: Rectangle {
color: Kirigami.Theme.backgroundColor
}
/*header: Rectangle {
clip: true
id: header
color: "#3daee9"
height: searchField.implicitHeight + 2 * Kirigami.Units.largeSpacing
width: root.width
//border.width: 1
//border.color: "#bdc3c7"
TextField {
id: searchField
placeholderText: "Search"
anchors.centerIn: parent
anchors.margins: Kirigami.Units.largeSpacing
width: parent.width - 2 * Kirigami.Units.largeSpacing
}
}*/
ListView {
currentIndex: -1
id: list
model: pagemodel.subfolder
delegate: Kirigami.BasicListItem {
onClicked: {
- pageroot.pageStack.push(Qt.resolvedUrl("Folder.qml"), {"pagemodel": pagemodel.subfolder.get(index), "pageroot": pageroot});
- }
-
- contentItem: Row {
- spacing: 2 * Kirigami.Units.largeSpacing
-
- Item {
- width: Kirigami.Units.iconSizes.medium
- height: width
-
- Kirigami.Icon {
- width: Kirigami.Units.iconSizes.medium
- height: width
- source: model.icon
- }
- }
- Label {
- anchors.verticalCenter: parent.verticalCenter
- text: model.name
- }
+ loadSubFolder(index);
}
+ icon: model.icon
+ label: model.name
}
}
+
+ function loadSubFolder(index) {
+ pageroot.pageStack.push(Qt.resolvedUrl("Folder.qml"), {"pagemodel": pagemodel.subfolder.get(index), "pageroot": pageroot});
+ }
}
diff --git a/HIG/source/qml/layout/gestures/Pinch.qml b/HIG/source/qml/layout/gestures/Pinch.qml
new file mode 100644
index 0000000..8a8a9ad
--- /dev/null
+++ b/HIG/source/qml/layout/gestures/Pinch.qml
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.3
+import QtQuick.Controls 2.3
+import org.kde.kirigami 2.7 as Kirigami
+import "../../lib/annotate.js" as A
+import "../../addr/" as Addr
+import "../../lib/" as HIG
+
+Rectangle {
+ width: 320
+ height: 600
+ id: root
+
+ Image {
+ z: 2
+ anchors.fill: parent
+ id: myImage
+ source: "../../../img/wallpaper/next.png"
+ fillMode: Image.PreserveAspectCrop
+ smooth: true
+
+ Behavior on rotation {
+ id: behave
+ enabled: false
+ NumberAnimation {duration: 300; easing.type: Easing.Linear}
+ }
+ Behavior on scale {
+ enabled: behave.enabled
+ NumberAnimation {duration: 300; easing.type: Easing.Linear}
+ }
+
+ PinchArea {
+ id: pinchArea
+ anchors.fill: parent
+ pinch.target: myImage
+
+ pinch.minimumRotation: 0
+ pinch.maximumRotation: 0
+ pinch.minimumScale: 0.1
+ pinch.maximumScale: 3
+ pinch.dragAxis: Pinch.XAndYAxis
+
+ onPinchFinished: function(event) {
+ behave.enabled = true
+ myImage.rotation = 0
+ myImage.scale = 1
+ }
+ }
+ }
+
+ HIG.FTimer {
+ running: true
+ onTick: function(frameCounter) {
+ if (frameCounter == 120) {
+ var a = new A.An(pinchArea);
+ a.pinch({ from: Qt.rect(0, 0, 20, 20), distance: 100});
+ }
+ }
+ }
+}
diff --git a/HIG/source/qml/layout/gestures/Rotate.qml b/HIG/source/qml/layout/gestures/Rotate.qml
new file mode 100644
index 0000000..22d19ea
--- /dev/null
+++ b/HIG/source/qml/layout/gestures/Rotate.qml
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.13
+import QtQuick.Layouts 1.2
+import QtQuick.Controls 2.2
+import org.kde.kirigami 2.4 as Kirigami
+import "../../lib/annotate.js" as A
+import "../../addr/" as Addr
+import "../../lib/" as HIG
+
+Rectangle {
+ width: 320
+ height: 600
+ id: root
+
+ Image {
+ anchors.fill: root
+ id: myImage
+ source: "../../../img/wallpaper/next.png"
+ fillMode: Image.PreserveAspectCrop
+ smooth: true
+
+ Behavior on rotation {
+ id: behave
+ enabled: false
+ NumberAnimation {duration: 300; easing.type: Easing.Linear}
+ }
+ Behavior on scale {
+ enabled: behave.enabled
+ NumberAnimation {duration: 300; easing.type: Easing.Linear}
+ }
+
+ PinchArea {
+ id: pinchArea
+ anchors.fill: parent
+ pinch.target: myImage
+
+ pinch.minimumRotation: -360
+ pinch.maximumRotation: 360
+ pinch.minimumScale: 1
+ pinch.maximumScale: 1
+ pinch.dragAxis: Pinch.XAndYAxis
+
+ onPinchFinished: function(event) {
+ behave.enabled = true
+ myImage.rotation = 0
+ myImage.scale = 1
+ }
+ }
+ }
+
+
+ // HACK coordinates are only final after a small delay
+ HIG.FTimer {
+ running: true
+ onTick: function(frameCounter) {
+ if (frameCounter == 90 ) {
+ var a = new A.An(pinchArea);
+ a.rotate({ from: Qt.point(0, 0), angle: -90});
+ }
+ }
+ }
+}
diff --git a/HIG/source/qml/layout/gestures/ShowContentDrawer.qml b/HIG/source/qml/layout/gestures/ShowContentDrawer.qml
new file mode 100644
index 0000000..e35c299
--- /dev/null
+++ b/HIG/source/qml/layout/gestures/ShowContentDrawer.qml
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.2
+import QtQuick.Layouts 1.2
+import QtQuick.Controls 2.2
+import org.kde.kirigami 2.4 as Kirigami
+import "../../lib/annotate.js" as A
+import "../../addr/" as Addr
+import "../../lib/" as HIG
+
+Rectangle {
+ width: 320
+ height: 600
+
+
+
+ Addr.Addressbook {
+ id: root
+ index: 2
+ }
+
+ HIG.FTimer {
+ running: true
+ onTick: function(frameCounter) {
+ if (frameCounter == 120) {
+ var a = new A.An(root);
+ a.swipe({fromX: 160, fromY: 120, toX: -160, toY: 0});
+ }
+ if (frameCounter == 240) {
+ var a = new A.An(root);
+ a.touch({x: -120, y: 120});
+ }
+ }
+ }
+}
diff --git a/HIG/source/qml/layout/gestures/ShowGlobalDrawer.qml b/HIG/source/qml/layout/gestures/ShowGlobalDrawer.qml
new file mode 100644
index 0000000..799783d
--- /dev/null
+++ b/HIG/source/qml/layout/gestures/ShowGlobalDrawer.qml
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.2
+import QtQuick.Layouts 1.2
+import QtQuick.Controls 2.2
+import org.kde.kirigami 2.4 as Kirigami
+import "../../lib/annotate.js" as A
+import "../../addr/" as Addr
+import "../../lib/" as HIG
+
+Rectangle {
+ width: 320
+ height: 600
+
+ Addr.Addressbook {
+ id: root
+ }
+
+ HIG.FTimer {
+ running: true
+ onTick: function(frameCounter) {
+ if (frameCounter == 120 ) {
+ var a = new A.An(root);
+ //a.tree();
+ a.swipe({fromX: -155, fromY: 120, toX: 120, toY: 0});
+ }
+ if (frameCounter == 300 ) {
+ var a = new A.An(root);
+ a.touch({x: 100, y: 120});
+ }
+ }
+ }
+}
diff --git a/HIG/source/qml/layout/gestures/Swipe.qml b/HIG/source/qml/layout/gestures/Swipe.qml
new file mode 100644
index 0000000..03f011f
--- /dev/null
+++ b/HIG/source/qml/layout/gestures/Swipe.qml
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.2
+import QtQuick.Layouts 1.2
+import QtQuick.Controls 2.2
+import org.kde.kirigami 2.4 as Kirigami
+import "../../lib/annotate.js" as A
+import "../../addr/" as Addr
+import "../../lib/" as HIG
+
+Rectangle {
+ width: 320
+ height: 600
+
+ Addr.Addressbook {
+ id: root
+ }
+
+ HIG.FTimer {
+ running: true
+ onTick: function(frameCounter) {
+ if (frameCounter == 120) {
+ var a = new A.An(root);
+ //a.tree();
+ a.find("swipelistitem").first().swipe({fromX: +130, fromY: 0, toX: -120, toY: 0});
+ }
+ if (frameCounter == 240) {
+ var a = new A.An(root);
+ a.find("swipelistitem").first().touch({x: -50, y: 0});
+ }
+ }
+ }
+}
diff --git a/HIG/source/qml/layout/gestures/SwipeNavigate.qml b/HIG/source/qml/layout/gestures/SwipeNavigate.qml
new file mode 100644
index 0000000..769084e
--- /dev/null
+++ b/HIG/source/qml/layout/gestures/SwipeNavigate.qml
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.2
+import org.kde.kirigami 2.4 as Kirigami
+import "../../models/" as Models
+import "../../files/" as Files
+import "../../lib/annotate.js" as A
+import "../../lib/" as HIG
+
+Kirigami.ApplicationItem {
+ width: 320
+ height: 600
+ id: root
+
+ property var mydata : Models.Files {
+ Component.onCompleted: {
+ rootFolder.pagemodel = mydata.get(0)
+ }
+ }
+
+ pageStack.initialPage: Files.Folder {
+ id: rootFolder
+ pageroot: root
+ }
+
+ pageStack.defaultColumnWidth: root.width < 320 ? root.width : 320
+ pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.Breadcrumb
+
+ HIG.FTimer {
+ running: true
+ onTick: function(frameCounter) {
+ if (frameCounter == 20 ) {
+ root.focus = true
+ var b = new A.An(root);
+ //b.touch({fromX: -120, fromY: 220});
+ rootFolder.loadSubFolder(1)
+ }
+ if (frameCounter == 120 ) {
+ var b = new A.An(root);
+ b.swipe({fromX: -120, toX: 220});
+ }
+ if (frameCounter == 300) {
+ var b = new A.An(root);
+ b.swipe({fromX: 120, toX: -220});
+ }
+ }
+ }
+}
diff --git a/HIG/source/qml/layout/gestures/Touch.qml b/HIG/source/qml/layout/gestures/Touch.qml
new file mode 100644
index 0000000..e3b72a4
--- /dev/null
+++ b/HIG/source/qml/layout/gestures/Touch.qml
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.2
+import org.kde.kirigami 2.4 as Kirigami
+import "../../models/" as Models
+import "../../files/" as Files
+import "../../lib/annotate.js" as A
+import "../../lib/" as HIG
+
+Kirigami.ApplicationItem {
+ width: 320
+ height: 600
+ id: root
+
+ property var mydata : Models.Files {
+ Component.onCompleted: {
+ rootFolder.pagemodel = mydata.get(0)
+ }
+ }
+
+ pageStack.initialPage: Files.Folder {
+ id: rootFolder
+ pageroot: root
+ }
+
+ pageStack.defaultColumnWidth: root.width < 320 ? root.width : 320
+ pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.Breadcrumb
+
+ HIG.FTimer {
+ running: true
+ onTick: function(frameCounter) {
+ if (frameCounter == 20) {
+ root.focus = true
+ }
+
+ if (frameCounter == 120) {
+ var a = new A.An(root);
+ a.find("basiclistitem").eq(0).touch();
+ }
+ if (frameCounter == 300) {
+ var node = root;
+ while (node.parent) {
+ node = node.parent
+ }
+ a = new A.An(node);;
+ a.find("privateactiontoolbutton").first().touch();
+ }
+ }
+ }
+}
diff --git a/HIG/source/qml/layout/gestures/config.json b/HIG/source/qml/layout/gestures/config.json
new file mode 100644
index 0000000..ae40141
--- /dev/null
+++ b/HIG/source/qml/layout/gestures/config.json
@@ -0,0 +1,44 @@
+{
+ "Pinch.qml": {
+ "type": "webm",
+ "controls": "mobile",
+ "delay": 1,
+ "duration": 4
+ },
+ "Rotate.qml": {
+ "type": "webm",
+ "controls": "mobile",
+ "delay": 1,
+ "duration": 4
+ },
+ "ShowGlobalDrawer.qml": {
+ "type": "webm",
+ "controls": "mobile",
+ "delay": 1,
+ "duration": 6
+ },
+ "Swipe.qml": {
+ "type": "webm",
+ "controls": "mobile",
+ "delay": 1,
+ "duration": 8
+ },
+ "Touch.qml": {
+ "type": "webm",
+ "controls": "mobile",
+ "delay": 1,
+ "duration": 6
+ },
+ "SwipeNavigate.qml": {
+ "type": "webm",
+ "controls": "mobile",
+ "delay": 1,
+ "duration": 7
+ },
+ "ShowContentDrawer.qml": {
+ "type": "webm",
+ "controls": "mobile",
+ "delay": 2,
+ "duration": 5
+ }
+}
diff --git a/HIG/source/qml/lib/DemoTouch.qml b/HIG/source/qml/lib/DemoTouch.qml
index 0b50e3e..f07176a 100644
--- a/HIG/source/qml/lib/DemoTouch.qml
+++ b/HIG/source/qml/lib/DemoTouch.qml
@@ -1,118 +1,118 @@
/*
* Copyright 2018 Fabian Riethmayer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.2
import org.kde.kirigami 2.4 as Kirigami
import "tools.js" as T
import "annotate.js" as A
Rectangle {
- width: 380
+ width: 640
height: 320
color: "white"
id: root
Row {
anchors.fill: parent
spacing: Kirigami.Units.largeSpacing
anchors.margins: Kirigami.Units.gridUnit * 2
ComboBox {
model: [ "Item1", "Item2", "Item3" ]
}
Component {
id: delegateComponent
Kirigami.SwipeListItem {
id: listItem
contentItem: RowLayout {
Label {
Layout.fillWidth: true
height: Math.max(implicitHeight, Kirigami.Units.iconSizes.smallMedium)
text: model.title
color: listItem.checked || (listItem.pressed && !listItem.checked && !listItem.sectionDelegate) ? listItem.activeTextColor : listItem.textColor
}
}
actions: [
Kirigami.Action {
iconName: "document-decrypt"
text: "Action 1"
onTriggered: showPassiveNotification(model.text + " Action 1 clicked")
},
Kirigami.Action {
iconName: "mail-reply-sender"
text: "Action 2"
onTriggered: showPassiveNotification(model.text + " Action 2 clicked")
}]
}
}
ListView {
width: 200
height: 200
id: mainList
Timer {
id: refreshRequestTimer
interval: 3000
onTriggered: page.refreshing = false
}
model: ListModel {
id: listModel
Component.onCompleted: {
for (var i = 0; i < 200; ++i) {
listModel.append({"title": "Item " + i,
"actions": [{text: "Action 1", icon: "document-decrypt"},
{text: "Action 2", icon: "mail-reply-sender"}]
})
}
}
}
moveDisplaced: Transition {
YAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
delegate: Kirigami.DelegateRecycler {
width: parent ? parent.width : implicitWidth
sourceComponent: delegateComponent
}
}
}
// HACK coordinates are only final after a small delay
Timer {
interval: 1000
repeat: false
running: true
onTriggered: {
var a = new A.An(root);
//a.tree();
a.find("swipelistitem").first().swipe({fromX: +90, fromY: 0, toX: -80, toY: 0});
}
}
// Draw helpers and anotation
Raster {
base: Kirigami.Units.gridUnit
desktop: true
}
}
diff --git a/HIG/source/qml/lib/FTimer.qml b/HIG/source/qml/lib/FTimer.qml
new file mode 100644
index 0000000..5011ae8
--- /dev/null
+++ b/HIG/source/qml/lib/FTimer.qml
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.2
+
+Item {
+ width: 1
+ height: 1
+ visible: false
+ signal tick(int frameCounter)
+
+ property int frameCounter: 0
+ property bool running : false
+
+ NumberAnimation on rotation {
+ from:0
+ to: 360
+ duration: 800
+ loops: Animation.Infinite
+ }
+ onRotationChanged: function() {
+ if (running) {
+ frameCounter++;
+ tick(frameCounter);
+ }
+ }
+
+ function start() {
+ frameCounter = 0;
+ running = true;
+ }
+
+ function stop() {
+ running = false;
+ }
+}
diff --git a/HIG/source/qml/lib/Pinch.qml b/HIG/source/qml/lib/Pinch.qml
new file mode 100644
index 0000000..3b38b4f
--- /dev/null
+++ b/HIG/source/qml/lib/Pinch.qml
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.2
+import org.kde.kirigami 2.4 as Kirigami
+import QtTest 1.2
+
+import "tools.js" as T
+
+// Show a touch event
+Item {
+ id: canvas
+ anchors.fill: parent;
+ z: 10000000000
+
+ // Define the pinch movement
+ property rect from
+ property rect to
+ property int duration : 300;
+
+ // For internal
+ property int i: 0
+ property real aStepX;
+ property real aStepY;
+ property real bStepX;
+ property real bStepY;
+ property var sequence;
+ property int frames: 0
+
+ VisualTouchPoint {
+ id: touchPointA;
+ x: from.right
+ y: from.top
+ dur: duration
+ }
+
+ VisualTouchPoint {
+ id: touchPointB
+ x: from.left
+ y: from.bottom
+ dur: duration
+ }
+
+ TestEvent {
+ id: event
+ }
+
+ FTimer {
+ id: swipeTimer
+ onTick: function(frameCounter) {
+ // Move both touch pointer
+ sequence.move(1, canvas.parent, from.right + frameCounter * aStepX, from.top + frameCounter * aStepY);
+ sequence.move(2, canvas.parent, from.left + frameCounter * bStepX, from.bottom + frameCounter * bStepY);
+ sequence.commit();
+ //console.log("M " + (from.right + frameCounter * aStepX) + " x " + (from.top + frameCounter * aStepY) + " - " + (from.left + frameCounter * bStepX) + " x " + (from.bottom + frameCounter * bStepY));
+
+ if (frameCounter >= frames) {
+ swipeTimer.stop();
+ touchPointA.moved();
+ }
+ }
+ }
+
+ function pinch() {
+ // Calculate how many frames the animation is running
+ frames = Math.floor(60 / 1000 * duration);
+ //console.log(frames)
+
+ touchPointA.animate = true;
+ touchPointB.animate = true;
+
+ // Calculate step size
+ // aStepX and aStepX should both > 0
+ // and bStepX and bStepY both < 0
+ // (or the other way around)
+ aStepX = -1 * (from.right - to.right) / frames
+ aStepY = -1 * (from.top - to.top) / frames
+ bStepX = -1 * (from.left - to.left) / frames
+ bStepY = -1 * (from.bottom - to.bottom) / frames
+
+
+ // Wait till both touch points are pressed
+ T.join([touchPointA.pressed, touchPointB.pressed], function() {
+ sequence = event.touchEvent(canvas.parent);
+ sequence.press(1, canvas.parent, from.right, from.top);
+ sequence.press(2, canvas.parent, from.left, from.bottom);
+ sequence.commit();
+ //console.log("P " + from.right + " x " + from.top + " - " + from.left + " x " + from.bottom);
+
+ // Move the visual touchpointer to the end
+ touchPointA.x = to.right;
+ touchPointA.y = to.top;
+ touchPointB.x = to.left;
+ touchPointB.y = to.bottom;
+
+
+ // Start the gesture
+ i = 0;
+ swipeTimer.start();
+ });
+
+ // Release after swipes are done
+ touchPointA.moved.connect(function() {
+ touchPointA.state = "RELEASED";
+ touchPointB.state = "RELEASED";
+ });
+
+ touchPointA.released.connect(function() {
+ sequence.release(1, canvas.parent, to.right, to.top);
+ sequence.release(2, canvas.parent, to.left, to.bottom);
+ sequence.commit();
+ //console.log("R " + to.right + " x " + to.top + " - " + to.left + " x " + to.bottom);
+ });
+
+ touchPointA.state = "PRESSED"
+ touchPointB.state = "PRESSED"
+ }
+}
diff --git a/HIG/source/qml/lib/Rotate.qml b/HIG/source/qml/lib/Rotate.qml
new file mode 100644
index 0000000..e7a8b62
--- /dev/null
+++ b/HIG/source/qml/lib/Rotate.qml
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.2
+import org.kde.kirigami 2.4 as Kirigami
+import QtTest 1.2
+
+import "tools.js" as T
+
+// Show a touch event
+Item {
+ id: canvas
+ anchors.fill: parent;
+ // Define the pinch movement
+ property rect from;
+ property int angle;
+ property int duration : 300;
+
+ // For internal
+ property int i: 0;
+ property real step;
+ property real offsetX : Math.floor(canvas.width / 2);
+ property real offsetY : Math.floor(canvas.height / 2);
+ property var sequence;
+ property int frames: 0;
+
+ Item {
+
+ anchors.fill: parent
+
+ VisualTouchPoint {
+ id: touchPointA;
+ x: from.right
+ y: from.top
+ dur: duration
+ }
+
+ VisualTouchPoint {
+ id: touchPointB
+ x: from.left
+ y: from.bottom
+ dur: duration
+ }
+
+ transform: Rotation {
+ id: rotateHelper
+
+ origin.x: canvas.width / 2
+ origin.y: canvas.height / 2
+
+ Behavior on angle {
+ NumberAnimation {duration: canvas.duration; easing.type: Easing.Linear}
+ }
+ }
+
+ }
+
+ TestEvent {
+ id: event
+ }
+
+ FTimer {
+ id: swipeTimer
+ onTick: function(frameCounter) {
+ // Move both touch pointer
+ var p = rotatePoint(Qt.point(from.right, from.top), frameCounter * step);
+ sequence.move(1, canvas.parent, p.x, p.y);
+ p = rotatePoint(Qt.point(from.left, from.bottom), frameCounter * step);
+ sequence.move(2, canvas.parent, p.x, p.y);
+ sequence.commit();
+
+ if (frameCounter >= frames) {
+ running = false;
+ touchPointA.moved();
+ }
+ }
+ }
+
+ // Rotate a point around the center of the canvas
+ function rotatePoint(point, angle) {
+ // to radian
+ angle = 2 * Math.PI / 360 * angle
+ // Translate point to 0/0 for rotation
+ var tPoint = Qt.point(
+ point.x - offsetX,
+ point.y - offsetY
+ );
+ tPoint = Qt.point(
+ tPoint.x * Math.cos(angle) - tPoint.y * Math.sin(angle),
+ tPoint.x * Math.sin(angle) + tPoint.y * Math.cos(angle)
+ );
+ return Qt.point(tPoint.x + offsetX, tPoint.y + offsetY);
+ }
+
+ function rotate() {
+ touchPointA.animate = true;
+ touchPointB.animate = true;
+
+ // Calculate how many frames the animation is running
+ frames = Math.floor(60 / 1000 * duration);
+
+ step = canvas.angle / frames;
+
+ // Wait till both touch points are pressed
+ T.join([touchPointA.pressed, touchPointB.pressed], function() {
+ sequence = event.touchEvent(canvas.parent);
+ sequence.press(1, canvas.parent, from.right, from.top);
+ sequence.press(2, canvas.parent, from.left, from.bottom);
+ sequence.commit();
+
+ // Rotate
+ rotateHelper.angle = canvas.angle
+
+ // Start the gesture
+ i = 0;
+ swipeTimer.start();
+ });
+
+ // Release after swipes are done
+ touchPointA.moved.connect(function() {
+ touchPointA.state = "RELEASED";
+ touchPointB.state = "RELEASED";
+ });
+
+ touchPointA.released.connect(function() {
+ var p = rotatePoint(Qt.point(from.right, from.top), canvas.angle);
+ sequence.release(1, canvas.parent, p.x, p.y);
+ p = rotatePoint(Qt.point(from.left, from.bottom), canvas.angle);
+ sequence.release(2, canvas.parent, p.x, p.y);
+ sequence.commit();
+ });
+
+ touchPointA.state = "PRESSED"
+ touchPointB.state = "PRESSED"
+ }
+}
diff --git a/HIG/source/qml/lib/Touch.qml b/HIG/source/qml/lib/Touch.qml
index 1ed2253..f9c7c5f 100644
--- a/HIG/source/qml/lib/Touch.qml
+++ b/HIG/source/qml/lib/Touch.qml
@@ -1,160 +1,118 @@
/*
* Copyright 2018 Fabian Riethmayer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.2
import org.kde.kirigami 2.4 as Kirigami
import QtTest 1.2
-// Drawing a brace between to obejcts to show the distance between them
+// Show a touch event
Item {
id: canvas
anchors.fill: parent;
property int fromX
property int fromY
property int toX
property int toY
property int dur: 300
property var sequence;
- property int i: 0
-
- /*MouseArea {
- anchors.fill: parent
- onPressed: {
- console.log(mouse.x + "x" + mouse.y)
- }
- }*/
-
- Rectangle {
- id: ind
- z: 1
- width: height
- height: Kirigami.Units.iconSizes.smallMedium
- color: "#331d99f3"
- radius: height / 2
- visible: false
- x: cursor.x
-
- NumberAnimation on width {
- id: indAnim
- duration: dur
- running: false
- }
- }
-
- Image {
- id: cursor
- source: "../../img/transform-browse.svg"
- visible: false
- width: Kirigami.Units.iconSizes.smallMedium
- height: Kirigami.Units.iconSizes.smallMedium
- z: 2
-
- NumberAnimation on x {
- id: xAnim
- duration: dur
- running: false
- }
- NumberAnimation on y {
- id: yAnim
- running: false
- duration: dur
- onStopped: {
- timer.start()
- }
- }
+ property int touchId: 0
+ property int frames: 0
+ z: 10000000000
+
+ VisualTouchPoint {
+ x: fromX;
+ y: fromY;
+ id: touchPoint
}
TestEvent {
id: event
}
- Timer {
- id: timer
- interval: 300
- repeat: false
- running: false
- onTriggered: {
- ind.visible = false;
- cursor.visible = false;
- swipeTimer.stop();
- }
- }
-
- Timer {
+ // needs to be synced with the animations of the touchPoint
+ FTimer {
id: swipeTimer
- interval: 30
- repeat: true
- running: false
- onTriggered: {
- i++;
- var stepX = (toX - fromX) / timer.interval * swipeTimer.interval
- var stepY = (toY - fromY) / timer.interval * swipeTimer.interval
- sequence.move(1, canvas.parent, fromX + i * stepX, toY + i * stepY);
- //console.log("move: " + (fromX + i * stepX) + "x" + (toY + i * stepY))
+ onTick: function(frameCounter) {
+ // Move the touch pointer
+ var stepX = (toX - fromX) / frames;
+ var stepY = (toY - fromY) / frames;
+ sequence.move(touchId, canvas.parent, fromX + frameCounter * stepX, toY + frameCounter * stepY);
sequence.commit();
+ //console.log("M " + (fromX + frameCounter * stepX) + " x " + ( toY + frameCounter * stepY));
+
+ if (frameCounter >= frames) {
+ swipeTimer.stop();
+ touchPoint.moved();
+ }
}
}
// Animate swipe
function swipe() {
- cursor.x = fromX - Kirigami.Units.iconSizes.smallMedium;
- cursor.y = fromY - Kirigami.Units.iconSizes.smallMedium;
- cursor.visible = true;
-
- ind.y = fromY;
- ind.visible = true;
-
- xAnim.to = toX;
- xAnim.start();
- yAnim.to = toY;
- yAnim.start();
- indAnim.to = Math.abs(fromX - toX);
- indAnim.start();
-
- sequence = event.touchEvent(canvas.parent);
- sequence.press(1, canvas.parent, fromX, fromY);
- //console.log("press: " + fromX + "x" + fromY)
- sequence.commit();
- i = 0;
-
- swipeTimer.start();
- timer.start();
-
- timer.triggered.connect(function() {
- sequence.release(1, canvas.parent, toX, toY);
- //console.log("release: " + toX + "x" + toY)
+ // Calculate how many frames the animation is running
+ frames = Math.floor(60 / 1000 * dur);
+
+ touchPoint.animate = true;
+ // Start swipe after animation is done
+ touchPoint.pressed.connect(function() {
+ touchPoint.x = toX;
+ touchPoint.y = toY;
+ if (!sequence) {
+ // Only create a new sequence if not 1 exists already
+ sequence = event.touchEvent(canvas.parent);
+ }
+ sequence.press(touchId, canvas.parent, fromX, fromY);
sequence.commit();
+ //console.log("P " + fromX + " x " + fromY);
+
+ swipeTimer.start();
});
-
+
+ // Finish touch event
+ // Release touch pointer
+ touchPoint.moved.connect(function() {
+ sequence.release(touchId, canvas.parent, toX, toY);
+ sequence.commit();
+ //console.log("R " + toX + " x " + toY);
+ touchPoint.state = "RELEASED";
+ });
+ touchPoint.state = "PRESSED"
}
function touch() {
- cursor.x = toX;
- cursor.y = toY;
- cursor.visible = true;
- timer.start()
- timer.triggered.connect(function() {
- sequence = event.touchEvent(canvas);
- sequence.press(1, canvas, toX, toY);
+ touchPoint.x = toX;
+ touchPoint.y = toY;
+
+ // Emit touch event after animation is done
+ touchPoint.pressed.connect(function() {
+ if (!sequence) {
+ sequence = event.touchEvent(canvas);
+ }
+ sequence.press(touchId, canvas, toX, toY);
sequence.commit();
- sequence.release(1, canvas, toX, toY);
+ touchPoint.state = "RELEASED"
+ });
+
+ touchPoint.released.connect(function() {
+ sequence.release(touchId, canvas, toX, toY);
sequence.commit();
});
+ touchPoint.state = "PRESSED"
}
}
diff --git a/HIG/source/qml/lib/VisualTouchPoint.qml b/HIG/source/qml/lib/VisualTouchPoint.qml
new file mode 100644
index 0000000..15658be
--- /dev/null
+++ b/HIG/source/qml/lib/VisualTouchPoint.qml
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 Fabian Riethmayer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.2
+import org.kde.kirigami 2.4 as Kirigami
+import QtTest 1.2
+
+// Visual touch point with pressed and release state
+Rectangle {
+ id: touchPoint
+
+ property int dur: 300
+ property alias animate : behave.enabled;
+
+ signal released()
+ signal pressed()
+ signal moved()
+
+ state: "RELEASED"
+
+ height: Kirigami.Units.iconSizes.small
+ width: height
+ color: "#668e44ad"
+ radius: height / 2
+ border.width: 1
+ border.color: "#8e44ad"
+
+ Behavior on x {
+ id: behave
+ enabled: false
+ NumberAnimation {duration: dur; easing.type: Easing.Linear;}
+ }
+ Behavior on y {
+ enabled: behave.enabled
+ NumberAnimation {duration: dur; easing.type: Easing.Linear}
+ }
+
+ states: [
+ State {
+ name: "PRESSED"
+ PropertyChanges { target: touchPoint; color: "#FF8e44ad"; visible: true }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "PRESSED"
+ to: "RELEASED"
+ SequentialAnimation {
+ ColorAnimation {target: touchPoint; duration: 300}
+ PropertyAction {target: touchPoint; property: "visible"; value: false}
+ ScriptAction {
+ script: touchPoint.released()
+ }
+ }
+ },
+ Transition {
+ from: "RELEASED"
+ to: "PRESSED"
+ SequentialAnimation {
+ PropertyAction {target: touchPoint; property: "visible"; value: true}
+ ColorAnimation {target: touchPoint; duration: 300}
+ ScriptAction {
+ script: touchPoint.pressed()
+ }
+ }
+ }
+ ]
+}
diff --git a/HIG/source/qml/lib/annotate.js b/HIG/source/qml/lib/annotate.js
index 0b2bfa4..f8725ba 100644
--- a/HIG/source/qml/lib/annotate.js
+++ b/HIG/source/qml/lib/annotate.js
@@ -1,346 +1,411 @@
var ruler = Qt.createComponent("Ruler.qml");
var brace = Qt.createComponent("Brace.qml");
var outline = Qt.createComponent("Outline.qml");
var messure = Qt.createComponent("Messure.qml");
var padding = Qt.createComponent("Padding.qml");
var mouse = Qt.createComponent("Mouse.qml");
var touch = Qt.createComponent("Touch.qml");
+var pinch = Qt.createComponent("Pinch.qml");
+var rotate = Qt.createComponent("Rotate.qml");
// get classname and strip _QML of the name
function getClassName(obj) {
var str = obj.toString();
str = str.substring(0, str.indexOf("("));
if (str.search(/_QML/) !== -1) {
str = str.substring(0, str.indexOf("_QML"));
}
return str.toLowerCase();
}
// Merge 2 objects of options
function getOpts(opts, choices) {
for (var choice in choices) {
opts[choice] = choices[choice];
}
return opts;
}
// An extended array of QML elements
function An(node) {
this.nodes = [];
if (typeof node === "undefined") {
this.nodes = []
}
else if (typeof node === "Array") {
this.nodes = node;
}
else {
this.nodes = [node];
}
}
// Find an An of QML elements from this point down the subtrees
An.prototype.find = function(selector) {
var result = new An();
if (typeof selector === "string") {
selector = new Select(selector);
}
/* for debugging
for (var member in this) {
if (typeof this[member] !== "function") {
console.log(member + ": " + this[member]);
}
}*/
// iterate threw the children
// apply the selector and traverse down the tree
for (var n = 0; n < this.nodes.length; n++) {
var node = this.nodes[n];
for (var i = 0; i < node.children.length; i++) {
if (selector.match(node.children[i])) {
// Add matching element to result
result.nodes.push(node.children[i]);
}
if (node.children[i].children.length) {
// Merge matching results of subrtree
var child = new An(node.children[i]);
result.concat(child.find(selector));
}
}
}
return result;
}
An.prototype.inspect = function() {
for (var member in this.nodes[0]) {
if (typeof this[member] !== "function") {
console.log(member + ": " + this[member]);
}
}
return this;
}
// Search only direct children
An.prototype.children = function(selector) {
var result = new An();
if (typeof selector === "string") {
selector = new Select(selector);
}
for (var n = 0; n < this.nodes.length; n++) {
var node = this.nodes[n];
for (var i = 0; i < node.children.length; i++) {
if (selector.match(node.children[i])) {
// Add matching element to result
result.nodes.push(node.children[i]);
}
}
}
return result;
}
An.prototype.concat = function(n) {
this.nodes = this.nodes.concat(n.nodes);
}
An.prototype.first = function() {
if (this.nodes.length > 0) {
return new An(this.nodes[0]);
}
return new An();
}
An.prototype.last = function() {
if (this.nodes.length > 0) {
return new An(this.nodes[this.nodes.length - 1]);
}
return new An();
}
An.prototype.eq = function(n) {
if (this.nodes.length > n) {
return new An(this.nodes[n]);
}
return new An();
}
/**
* Simulate a mouse click on the nodes
*/
An.prototype.click = function(opt) {
var options = getOpts({
x: 0,
y: 0
}, opt);
for (var n = 0; n < this.nodes.length; n++) {
var node = this.nodes[n];
var x = node.mapToItem(null, 0, 0).x + Math.floor(node.width / 2) + options.x;
var y = node.mapToItem(null, 0, 0).y + Math.floor(node.height / 2) + options.y;
var m = mouse.createObject(root, {px: x, py: y});
m.click();
}
return this;
}
/**
- * Simulate a touch the nodes
+ * Simulate a swipe the nodes
*/
An.prototype.touch = function(opt) {
var options = getOpts({
x: 0,
y: 0
}, opt);
-
for (var n = 0; n < this.nodes.length; n++) {
var node = this.nodes[n];
var x = node.mapToItem(null, 0, 0).x + Math.floor(node.width / 2) + options.x;
var y = node.mapToItem(null, 0, 0).y + Math.floor(node.height / 2) + options.y;
var m = touch.createObject(root, {toX: x, toY: y});
m.touch();
}
return this;
}
+/**
+ * Simulate a pinch the nodes
+ */
+An.prototype.pinch = function(opt) {
+ for (var n = 0; n < this.nodes.length; n++) {
+ var node = this.nodes[n];
+ // Translate rectangle to center of node
+ var oX = node.mapToItem(null, 0, 0).x + Math.floor(node.width / 2);
+ var oY = node.mapToItem(null, 0, 0).x + Math.floor(node.height / 2);
+ var width = opt.from.right - opt.from.left;
+ var height = opt.from.bottom - opt.from.top;
+
+ var from = Qt.rect(
+ opt.from.left + oX,
+ opt.from.top + oY,
+ width,
+ height
+ );
+ // Calculate to from the distance
+ var dig = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
+ var x = (opt.distance + dig) / dig;
+ var to = Qt.rect(
+ from.left - (width * x) / 2,
+ from.top - (height * x) / 2,
+ width * x,
+ height * x
+ );
+ // TODO add option for explicit to
+// var to = Qt.rect(
+// opt.to.left + oX,
+// opt.to.top + oY,
+// opt.to.right - opt.to.left,
+// opt.to.bottom - opt.to.top
+// );
+ var m = pinch.createObject(root, {from: from, to: to});
+ m.pinch();
+ }
+ return this;
+}
+
+/**
+ * Simulate a pinch/rotate the nodes
+ */
+An.prototype.rotate = function(opt) {
+ for (var n = 0; n < this.nodes.length; n++) {
+ var node = this.nodes[n];
+ // Translate rectangle to center of node
+ var oX = node.mapToItem(null, 0, 0).x + Math.floor(node.width / 2);
+ var oY = node.mapToItem(null, 0, 0).x + Math.floor(node.height / 2);
+ var width = opt.from.right - opt.from.left;
+ var height = opt.from.bottom - opt.from.top;
+
+ var from = Qt.rect(
+ oX - 40,
+ oY - 40,
+ 80,
+ 80
+ );
+ var m = rotate.createObject(root, {from: from, angle: opt.angle});
+ m.rotate();
+ }
+ return this;
+}
+
/**
* Simulate a mouse hover on the nodes
*/
An.prototype.hover = function(opt) {
var options = getOpts({
x: 0,
y: 0,
animate: true
}, opt);
for (var n = 0; n < this.nodes.length; n++) {
var node = this.nodes[n];
var x = node.mapToItem(null, 0, 0).x + Math.floor(node.width / 2) + options.x;
var y = node.mapToItem(null, 0, 0).y + Math.floor(node.height / 2) + options.y;
var m = mouse.createObject(root, {px: x, py: y, animate: options.animate});
m.hover();
}
return this;
}
/**
* Simulate a touch
*/
An.prototype.swipe = function(opt) {
var options = getOpts({
fromX: 0,
fromY: 0,
toX: 0,
toY: 0
}, opt);
for (var n = 0; n < this.nodes.length; n++) {
var node = this.nodes[n];
var x = node.mapToItem(null, 0, 0).x + Math.floor(node.width / 2) + options.fromX;
var y = node.mapToItem(null, 0, 0).y + Math.floor(node.height / 2) - Kirigami.Units.iconSizes.smallMedium / 2 + options.fromY;
var t = touch.createObject(root, {fromX: x, fromY: y, toX: x + options.toX, toY: y + options.toY});
t.swipe();
}
return this;
}
/**
* Draw a tree of all the elements
*/
An.prototype.tree = function(lvl) {
if (typeof lvl === "undefined") {
lvl = ""
}
/* for debug
for (var member in this.nodes) {
if (typeof this[member] !== "function") {
console.log("|" + lvl + " " + member + ": " + (typeof this[member]));
}
}*/
for (var n = 0; n < this.nodes.length; n++) {
var node = this.nodes[n];
console.log("|" + lvl + " " + getClassName(node) + " " + node.toString() + " " + node.children.length);
for (var i = 0; i < node.children.length; i++) {
var child = new An(node.children[i]);
child.tree(lvl + "--");
}
}
}
/**
* Drawing annotation on the nodes
*/
An.prototype.draw = function(obj) {
//console.log(this.nodes)
for (var n = 0; n < this.nodes.length; n++) {
var node = this.nodes[n];
var opt;
for (var type in obj) {
if (Array.isArray(obj[type])) {
for (var i = 0; i < obj[type].length; i++) {
this._draw(node, type, obj[type][i]);
}
}
else {
this._draw(node, type, obj[type]);
}
}
}
return this;
}
/**
* Internal method to draw
*/
An.prototype._draw = function(node, type, opt) {
//console.log("drawing " + type)
switch (type) {
case "outline":
// Create outline object
outline.createObject(root, {item: node, label: opt.label, aspectratio: opt.aspectratio});
break
case "ruler":
// Draw ruler to show alignment
if (opt.offset) {
// No need for left or top since these are the defaults
switch (opt.offset) {
case "center":
opt.offset = opt.horizontal ? node.mapToItem(null, 0, 0).y + node.height / 2 : node.mapToItem(null, 0, 0).x + node.width / 2
break;
case "bottom":
opt.offset = node.mapToItem(null, 0, 0).y + node.height
break;
case "right":
opt.offset = node.mapToItem(null, 0, 0).x + node.width
break;
}
}
var options = getOpts({
offset: opt.horizontal ? node.mapToItem(null, 0, 0).y : node.mapToItem(null, 0, 0).x,
horizontal: false
}, opt);
ruler.createObject(root, options);
break
case "padding":
// Show padding around an object
var options = getOpts({
padding: opt.padding
}, opt);
padding.createObject(root, {item: node, padding: options.padding});
break
case "brace":
// Create a brace between two objects
brace.createObject(root, {"from": node, "to": opt.to.nodes[0], "text": opt.text, "center": opt.center, "horizontal": opt.horizontal});
break
case "messure":
// Messure distance between two objects
messure.createObject(root, {"from": node, "to": opt.to.nodes[0], "type": opt.type});
break
}
}
/**
* Selector for qml elements
*/
function Select(str) {
// TODO support more complex syntax
// - multiple nodenames, hirachy, ...
if (str.search(/\{/) !== -1) {
this.nodeName = str.substring(0, str.indexOf("{"));
var members = str.match(/\{.+\}/);
try {
this.attrs = JSON.parse(members[0]);
}
catch(e) {
console.log("Could not parse attributes");
console.log(e);
}
}
else {
this.nodeName = str;
}
}
/**
* Check if the node matches the selector
*/
Select.prototype.match = function(node) {
if (this.nodeName === "*" || getClassName(node) === this.nodeName) {
if (typeof this.attrs !== "undefined") {
// TODO only return true if all attributes match
for (var attr in this.attrs) {
if (typeof node[attr] !== "undefined" && node[attr].toString() === this.attrs[attr]) {
return true;
}
}
}
else {
return true;
}
}
return false;
}
diff --git a/HIG/source/qml/lib/tools.js b/HIG/source/qml/lib/tools.js
index 4f6ea18..f853d9b 100644
--- a/HIG/source/qml/lib/tools.js
+++ b/HIG/source/qml/lib/tools.js
@@ -1,9 +1,52 @@
// get scale because e.g. annotation should not be scaled
function getScale(node) {
var scale = 1
while (node !== null) {
scale = scale * node.scale
node = node.parent
}
return scale;
}
+
+ function Timer() {
+ return Qt.createQmlObject("import QtQuick 2.2; Timer {}", root);
+}
+
+function sleep(delayTime, cb) {
+ var timer = new Timer();
+ timer.interval = delayTime;
+ timer.repeat = false;
+ timer.triggered.connect(cb);
+ timer.start();
+}
+
+function JoinSignals(signals, cb) {
+ this.signals = [];
+ this.cb = cb;
+ for (var i = 0; i < signals.length; i++) {
+ this.signals.push(new Signal(signals[i], this));
+ }
+}
+
+JoinSignals.prototype.check = function() {
+ for (var i = 0; i < this.signals.length; i++) {
+ if (!this.signals[i].fired) {
+ return;
+ }
+ }
+ this.cb();
+}
+
+function Signal(signal, join) {
+ this.fired = false;
+ var that = this;
+
+ signal.connect(function() {
+ that.fired = true;
+ join.check();
+ });
+}
+
+function join(signals, cb) {
+ var join = new JoinSignals(signals, cb);
+}
diff --git a/HIG/source/qml/models/Files.qml b/HIG/source/qml/models/Files.qml
index 64a5d9d..a0319d7 100644
--- a/HIG/source/qml/models/Files.qml
+++ b/HIG/source/qml/models/Files.qml
@@ -1,105 +1,112 @@
/*
* Copyright 2018 Fabian Riethmayer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.6
ListModel {
id: model
// Pattern
ListElement {
name: ""
icon: ""
subfolder: [
ListElement {
name: ""
icon: ""
subfolder: ListElement {
name: ""
icon: ""
subfolder: [
ListElement {
name: ""
icon: ""
subfolder: ListElement {
name: ""
icon: ""
}
}
]
}
}
]
}
Component.onCompleted: {
model.clear()
var data = [{
"name": "HIG",
"icon": "folder-development",
"subfolder": [{
"name": "build",
- "icon": "folder-blue"
+ "icon": "folder",
+ "subfolder": [{
+ "name": "doctrees",
+ "icon": "folder-text"
+ }, {
+ "name": "html",
+ "icon": "folder-internet"
+ }]
}, {
"name": "source",
"icon": "folder-development",
"subfolder": [{
"name": "components",
"icon": "folder-text"
}, {
"name": "img",
"icon": "folder-picture"
}, {
"name": "introduction",
"icon": "folder-text"
}, {
"name": "layout",
"icon": "folder-text"
}, {
"name": "patterns",
"icon": "folder-text"
}, {
"name": "qml",
- "icon": "folder-blue",
+ "icon": "folder",
"subfolder": [{
"name": "ui",
"icon": "folder-text"
}, {
"name": "lib",
"icon": "folder-text"
}, {
"name": "models",
"icon": "folder-text"
}]
}, {
"name": "resources",
"icon": "folder-text"
}, {
"name": "style",
- "icon": "folder-blue"
+ "icon": "folder"
}, {
"name": "video",
"icon": "folder-video"
}]
}]
}]
model.insert(0, data)
}
}