diff --git a/HIG/source/layout/gestures.rst b/HIG/source/layout/gestures.rst index a84a23c..ffabb92 100644 --- a/HIG/source/layout/gestures.rst +++ b/HIG/source/layout/gestures.rst @@ -1,68 +1,130 @@ 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. Principles ---------- Unless you create a game, you should avoid to use non standard gestures. Don't abuse the standard gestures to trigger none standard actions. For example don't use a pinch to delete an item, but only for scaling content. Avoid to interfer with system wide screen egde gestures like pulling down the top panel on plasma mobile. -Guidelines ----------- +Gestures +-------- + +These type of gestures are used commonly, both on desktop and on mobile. They +can be used to navigate, trigger actions, or manipulate content + + +Tab +~~~ + +.. raw:: html + + + +A tab is handled like a mouse click. It can be used to navigate, trigger +actions, or manipulate content. + +Long press +~~~~~~~~~~ + +Can trigger aditional actions on an item or a control. + +Swipe +~~~~~ + +.. raw:: html + + + +Navigate between views, activate actions on items. + +Pinch +~~~~~ -Common gestures -~~~~~~~~~~~~~~~ +.. raw:: html + + + +Scales content -These gestures are used commonly, both on desktop and on mobile. +Rotate +~~~~~~ + +.. raw:: html + + + +Rotate content -=============================== ======================= -Gesture Action -=============================== ======================= -Pinch Scales content -Rotate Rotate content -Tab Handled like a click -Swipe Navigate between views, activate actions on - items Desktop -^^^^^^^ +~~~~~~~ + +Aditionally to the common gestures, there a several gestures on Plasma Desktop +to invoke functionallity from the desktop enviroment. + +XXXX +^^^^ +Switch workspace -System -=============================== ======================= -Gesture Action -=============================== ======================= -XXXXX Switch workspace -XXXX Show app overview -... +XXXX +^^^^ +Show app overview Mobile -^^^^^^ +~~~~~~ + +Aditionally to the common gestures, there a several common gestures on Plamsa +Mobile. + + +Edge swipe top +^^^^^^^^^^^^^^ + +Pull down top panel + + +Edge swipe bottom +^^^^^^^^^^^^^^^^^ + +Pull up main menu + -System +In plasma mobile there a also aditional common gestures to be used in +applications. -=============================== ======================= -Gesture Action -=============================== ======================= -Edge swipe top Pull down top panel -Edge swipe bottom Pull up main menu +Edge swipe left +^^^^^^^^^^^^^^^ +.. raw:: html + + + +Open the global drawer. -Applications -=============================== ======================= -Gesture Action -=============================== ======================= -Edge swipe left Open the global drawer -Edge swipe right Open the context drawer +Edge swipe right +^^^^^^^^^^^^^^^^ +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..214ed73 100644 --- a/HIG/source/qml/files/Folder.qml +++ b/HIG/source/qml/files/Folder.qml @@ -1,86 +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 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 - } - } + icon: model.icon + label: model.name } } } diff --git a/HIG/source/qml/layout/gestures/Pinch.qml b/HIG/source/qml/layout/gestures/Pinch.qml index b64da30..273e1dc 100644 --- a/HIG/source/qml/layout/gestures/Pinch.qml +++ b/HIG/source/qml/layout/gestures/Pinch.qml @@ -1,126 +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.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 Rectangle { width: 320 height: 600 id: root Image { anchors.fill: root id: myImage - source: "../../../img/wallpaper/next.png" + source: "../../../img/wallpaper/Cluster.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.minimumRotation: 0 + pinch.maximumRotation: 0 pinch.minimumScale: 0.1 - pinch.maximumScale: 10 - pinch.dragAxis: Pinch.NoDrag - - // MouseArea { - // id: dragArea - // hoverEnabled: true - // anchors.fill: parent - // drag.target: img - // scrollGestureEnabled: false // 2-finger-flick gesture should pass through to the Flickable - // - // onWheel: { - // var scaleBefore = img.scale; - // img.scale += img.scale * wheel.angleDelta.y / 120 / 10; - // } - // } + pinch.maximumScale: 3 + pinch.dragAxis: Pinch.XAndYAxis onPinchFinished: function(event) { - console.log("pinching finished") - console.log(JSON.stringify(event)); - //console.log(event.previousScale); - } - - onPinchStarted: function(event) { - console.log("pinching started") - console.log(JSON.stringify(event)); - } - - onPinchUpdated: function(event) { - console.log("pinch updated") - console.log(JSON.stringify(event)); + behave.enabled = true + myImage.rotation = 0 + myImage.scale = 1 } } - } - -// MultiPointTouchArea { -// id: pinchArea -// anchors.fill: parent -// // touchPoints: [ -// // TouchPoint { id: point1 }, -// // TouchPoint { id: point2 } -// // ] -// -// onGestureStarted: function(gesture) { -// console.log("gesture"); -// console.log(gesture); -// } -// onPressed: function(gesture) { -// console.log("pressed"); -// } -// onReleased: function(gesture) { -// console.log("released"); -// } -// onUpdated: function(gesture) { -// console.log("updated"); -// } -// } - + } // HACK coordinates are only final after a small delay Timer { interval: 1000 repeat: false running: true onTriggered: { var a = new A.An(pinchArea); - //a.tree(); - a.pinch({x: +130, x: 0}); + a.pinch({ from: Qt.rect(0, 0, 20, 20), distance: 100}); } } -/* - Timer { - id: hideTimer - interval: 2000 - repeat: false - running: false - onTriggered: { - var a = new A.An(root); - a.find("swipelistitem").first().touch({x: 0, y: 0}); - } - }*/ } diff --git a/HIG/source/qml/layout/gestures/Swipe.qml b/HIG/source/qml/layout/gestures/Swipe.qml index 2b3b9f7..866f4e7 100644 --- a/HIG/source/qml/layout/gestures/Swipe.qml +++ b/HIG/source/qml/layout/gestures/Swipe.qml @@ -1,58 +1,58 @@ /* * 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 Rectangle { width: 320 height: 600 Addr.Addressbook { id: root } // 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: +130, fromY: 0, toX: -80, toY: 0}); + a.find("swipelistitem").first().swipe({fromX: +130, fromY: 0, toX: -120, toY: 0}); hideTimer.start(); } } Timer { id: hideTimer interval: 2000 repeat: false running: false onTriggered: { var a = new A.An(root); - a.find("swipelistitem").first().touch({x: 0, y: 0}); + a.find("swipelistitem").first().touch({x: -50, y: 0}); } } } diff --git a/HIG/source/qml/lib/Pinch.qml b/HIG/source/qml/lib/Pinch.qml index fb601cd..25f780c 100644 --- a/HIG/source/qml/lib/Pinch.qml +++ b/HIG/source/qml/lib/Pinch.qml @@ -1,103 +1,126 @@ /* * 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; - property int fromX - property int fromY + // 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; - Touch { - id: touch1 - fromX: canvas.fromX + 10 - fromY: canvas.fromY + 10 - toX: canvas.fromX + 100 - toY: canvas.fromY + 100 + VisualTouchPoint { + id: touchPointA; + x: from.right + y: from.top + dur: duration } - Touch { - id: touch2 - touchId: 1 - sequence: touch1.sequence - fromX: canvas.fromX - 10 - fromY: canvas.fromY - 10 - toX: canvas.fromX - 100 - toY: canvas.fromY - 100 + VisualTouchPoint { + id: touchPointB + x: from.left + y: from.bottom + dur: duration } TestEvent { id: event } + Timer { + id: swipeTimer + interval: 30 + repeat: true + running: false + onTriggered: { + // Move both touch pointer + i++; + sequence.move(1, canvas.parent, from.right + i * aStepX, from.top + i * aStepY); + sequence.move(2, canvas.parent, from.left + i * bStepX, from.bottom + i * bStepY); + sequence.commit(); + + if (i == 10) { + running = false; + touchPointA.moved(); + } + } + } + function pinch() { - console.log("starting pinch"); + 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 = (from.right - to.right) / 10 + aStepY = -1 * (from.top - to.top) / 10 + bStepX = (from.left - to.left) / 10 + bStepY = -1 * (from.bottom - to.bottom) / 10 - var sequence = event.touchEvent(canvas.parent); - sequence.press(0, canvas.parent, fromX - 20, fromY -20); - sequence.press(1, canvas.parent, fromX + 20, fromY + 20); - //sequence.press(2, canvas.parent, fromX + 20, fromY + 20); - sequence.commit(); - console.log("pressed"); - sequence.move(0, canvas.parent, fromX - 50, fromY - 50); - sequence.move(1, canvas.parent, fromX + 50, fromY + 50); - console.log("move 1"); - sequence.commit(); -// var stepX = 10; -// var stepY = 10; -// var i = 1; -// for (var i = 0; i < 10; i++) { -// sequence.move(0, canvas.parent, fromX + -1 * i * stepX, fromY); -// sequence.move(1, canvas.parent, fromX + i * stepX, fromY); -// } - delay(500, function() { - sequence.move(0, canvas.parent, fromX -100, fromY - 90); - sequence.move(1, canvas.parent, fromX + 200, fromY + 80); - //sequence.move(2, canvas.parent, fromX + 200, fromY + 80); + // 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("move 2"); + + // 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(); + }); - delay(500, function() { - sequence.release(0, canvas.parent, fromX - 100, fromY - 90); - sequence.release(1, canvas.parent, fromX + 200, fromY + 80); - sequence.commit(); - console.log("released"); - }); + // Release after swipes are done + touchPointA.moved.connect(function() { + touchPointA.state = "RELEASED"; + touchPointB.state = "RELEASED"; }); -// touch1.swipe(); -// touch2.swipe(); - } - - function myTimer() { - return Qt.createQmlObject("import QtQuick 2.2; Timer {}", root); - } - - function delay(delayTime, cb) { - var timer = new myTimer(); - timer.interval = delayTime; - timer.repeat = false; - timer.triggered.connect(cb); - timer.start(); + touchPointA.released.connect(function() { + sequence.release(1, canvas.parent, to.right, to.top); + sequence.release(2, canvas.parent, to.left, to.bottom); + 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 83cd47c..8d493c5 100644 --- a/HIG/source/qml/lib/Touch.qml +++ b/HIG/source/qml/lib/Touch.qml @@ -1,179 +1,117 @@ /* * 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 // 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 property int touchId: 0 - Rectangle { + VisualTouchPoint { + x: fromX; + y: fromY; id: touchPoint - - signal released() - signal pressed() - signal moved() - - state: "RELEASED" - - z: 1 - height: Kirigami.Units.iconSizes.small - width: height - color: "#331D99F3" - radius: height / 2 - border.width: 1 - border.color: "#1D99F3" - - Behavior on x { - id: animate - enabled: false - NumberAnimation {duration: dur} - } - Behavior on y { - enabled: animate.enabled - NumberAnimation {duration: dur} - } - - states: [ - State { - name: "PRESSED" - PropertyChanges { target: touchPoint; color: "#FF1D99F3"; 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() - } - } - } - ] } TestEvent { id: event } // HACK to slow down the gesture // needs to be synced with the animations of the touchPoint Timer { id: swipeTimer - interval: 10 + interval: 30 repeat: true running: false onTriggered: { // Move the touch pointer i++; var stepX = (toX - fromX) / 10 var stepY = (toY - fromY) / 10 sequence.move(touchId, canvas.parent, fromX + i * stepX, toY + i * stepY); - //console.log("move: " + (fromX + i * stepX) + "x" + (toY + i * stepY)) - //sequence.commit(); + sequence.commit(); if (i == 10) { running = false; touchPoint.moved(); } } } // Animate swipe function swipe() { - touchPoint.x = fromX; - touchPoint.y = fromY; - animate.enabled = true; + + 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); } -// console.log(sequence); -// console.log(touchId); sequence.press(touchId, canvas.parent, fromX, fromY); - console.log("press(" + touchId +"): " + fromX + "x" + fromY) - //sequence.commit(); + sequence.commit(); i = 0; swipeTimer.start(); }); // Finish touch event // Release touch pointer touchPoint.moved.connect(function() { sequence.release(touchId, canvas.parent, toX, toY); - console.log("release(" + touchId +"): " + toX + "x" + toY) - //console.log(sequence); - //console.log(touchId); - if (touchId == 1) { - console.log("commit"); - sequence.commit(); - } + sequence.commit(); touchPoint.state = "RELEASED"; }); touchPoint.state = "PRESSED" } function touch() { 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(); + touchPoint.state = "RELEASED" + }); + + touchPoint.released.connect(function() { sequence.release(touchId, canvas, toX, toY); sequence.commit(); - touchPoint.state = "RELEASED" }); touchPoint.state = "PRESSED" } } diff --git a/HIG/source/qml/lib/annotate.js b/HIG/source/qml/lib/annotate.js index d67e4a2..c451657 100644 --- a/HIG/source/qml/lib/annotate.js +++ b/HIG/source/qml/lib/annotate.js @@ -1,366 +1,412 @@ 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 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) { - 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 = pinch.createObject(root, {fromX: x, fromY: y}); + // 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..863833e 100644 --- a/HIG/source/qml/models/Files.qml +++ b/HIG/source/qml/models/Files.qml @@ -1,105 +1,105 @@ /* * 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" }, { "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) } }