diff --git a/source/qml/lib/Demo.qml b/source/qml/lib/Demo.qml --- a/source/qml/lib/Demo.qml +++ b/source/qml/lib/Demo.qml @@ -18,6 +18,7 @@ */ 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 diff --git a/source/qml/lib/DemoMouse.qml b/source/qml/lib/DemoMouse.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/DemoMouse.qml @@ -0,0 +1,128 @@ +/* + * 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 + 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 + } + } + } + + // Click on the ComboBox + Timer { + interval: 1000 + repeat: false + running: true + onTriggered: { + var a = new A.An(root); + a.find("qquickcombobox").click(); + } + } + + // Hover over the first swipelistitem + Timer { + interval: 1000 + repeat: false + running: false + onTriggered: { + var a = new A.An(root); + a.find("swipelistitem").first().hover(); + } + } + + // Draw helpers and anotation + Raster { + base: Kirigami.Units.gridUnit + desktop: true + } +} diff --git a/source/qml/lib/DemoTouch.qml b/source/qml/lib/DemoTouch.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/DemoTouch.qml @@ -0,0 +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 + 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/source/qml/lib/Mouse.qml b/source/qml/lib/Mouse.qml --- a/source/qml/lib/Mouse.qml +++ b/source/qml/lib/Mouse.qml @@ -93,4 +93,16 @@ yAnim.to = py; yAnim.start(); } + + function hover() { + cursor.x = px; + cursor.y = py; + cursor.visible = true; + if (qmlControler) { + qmlControler.hover(px, py); + } + else { + console.error("Can't find qmlControler."); + } + } } diff --git a/source/qml/lib/Surface.qml b/source/qml/lib/Surface.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/Surface.qml @@ -0,0 +1,74 @@ +/* + * 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.Controls 2.2 +import org.kde.kirigami 2.4 as Kirigami +import QtGraphicalEffects 1.0 +import QtQuick.Templates 2.0 as T + +// A breeze surface with shadows, rounded borders, blur +ItemDelegate { + id: root + default property alias contents: content.data + property string color : "#fcfcfc" + property int radius: 3 + property int elevation: 1 + property Item sourceItem; + + + background: Item { + anchors.fill: parent + id: background + + FastBlur{ + id: blur + anchors.fill: surface + // TODO visible: surface.isColorHasAlphaValue + source: ShaderEffectSource { + id: effectSource + sourceItem: root.sourceItem + sourceRect: Qt.rect(root.x * 2, root.y * 2, root.width, root.height) + } + radius: 32 + } + + Rectangle { + anchors.fill: parent + radius: root.radius + color: root.color + id: surface + } + } + + DropShadow { + anchors.fill: background + horizontalOffset: elevation < 2 ? 1 : 3 + verticalOffset: elevation < 2 ? 1 : 3 + radius: root.elevation * 4 + samples: root.elevation * 10 + color: "#92232627" + source: background + } + + Item { + anchors.fill: parent + id: content + } +} diff --git a/source/qml/lib/Mouse.qml b/source/qml/lib/Touch.qml copy from source/qml/lib/Mouse.qml copy to source/qml/lib/Touch.qml --- a/source/qml/lib/Mouse.qml +++ b/source/qml/lib/Touch.qml @@ -24,73 +24,79 @@ Item { id: canvas anchors.fill: parent; - property int px - property int py + property int fromX + property int fromY + property int toX + property int toY + property int dur: 600 Rectangle { id: ind - x: cursor.x - width / 2 - y: cursor.y - width / 2 + 5 z: 1 - width: Kirigami.Units.iconSizes.small - height: width - color: "#9911d116" - radius: width / 2 + width: height + height: Kirigami.Units.iconSizes.smallMedium + color: "#331d99f3" + radius: height / 2 visible: false + x: cursor.x NumberAnimation on width { id: indAnim - duration: 300 + duration: dur running: false - - onStopped: { - ind.visible = false; - if (qmlControler) { - qmlControler.click(px, py); - } - else { - console.error("Can't find qmlControler."); - } - - } } } Image { id: cursor - source: "../../img/left_ptr.png" + 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: 1000 + duration: dur running: false } NumberAnimation on y { id: yAnim running: false - duration: 1000 + duration: dur onStopped: { - ind.visible = true; - indAnim.to = Kirigami.Units.iconSizes.smallMedium; - indAnim.start(); + timer.start() } } } + Timer { + id: timer + interval: 1000 + repeat: false + running: false + onTriggered: { + ind.visible = false; + cursor.visible = false; + } + } - // Animate mouse to x/y and then click - function click() { - cursor.x = px - 60; - cursor.y = py + 60; + // Animate swipe + function swipe() { + cursor.x = fromX - Kirigami.Units.iconSizes.smallMedium; + cursor.y = fromY; cursor.visible = true; - xAnim.to = px; + ind.y = fromY; + ind.visible = true; + + xAnim.to = toX; xAnim.start(); - yAnim.to = py; + yAnim.to = toY; yAnim.start(); + indAnim.to = Math.abs(fromX - toX); + indAnim.start(); + + qmlControler.swipe(fromX, fromY, toX, toY); } } diff --git a/source/qml/lib/annotate.js b/source/qml/lib/annotate.js --- a/source/qml/lib/annotate.js +++ b/source/qml/lib/annotate.js @@ -4,6 +4,7 @@ var messure = Qt.createComponent("Messure.qml"); var padding = Qt.createComponent("Padding.qml"); var mouse = Qt.createComponent("Mouse.qml"); +var touch = Qt.createComponent("Touch.qml"); // get classname and strip _QML of the name function getClassName(obj) { @@ -126,7 +127,7 @@ } /** - * Drawing annotation on the nodes + * Simulate a mouse click on the nodes */ An.prototype.click = function(obj) { for (var n = 0; n < this.nodes.length; n++) { @@ -139,6 +140,38 @@ return this; } +/** + * Simulate a mouse hover on the nodes + */ +An.prototype.hover = 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.hover(); + } + return this; +} + +/** + * Simulate a touch + */ +An.prototype.swipe = function(obj) { + 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) + obj.fromX; + var y = node.mapToItem(null, 0, 0).y + Math.floor(node.height / 2) - Kirigami.Units.iconSizes.smallMedium / 2 + obj.fromY; + var t = touch.createObject(root, {fromX: x, fromY: y, toX: x + obj.toX, toY: y + obj.toY}); + t.swipe(); + } + return this; +} /** * Draw a tree of all the elements