diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /env build *.qmlc +*.jsc diff --git a/source/img/edit-select.svg b/source/img/edit-select.svg new file mode 100644 --- /dev/null +++ b/source/img/edit-select.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/source/img/video-display.svg b/source/img/video-display.svg new file mode 100644 --- /dev/null +++ b/source/img/video-display.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/source/qml/lib/Brace.qml b/source/qml/lib/Brace.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/Brace.qml @@ -0,0 +1,150 @@ +/* + * 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 + +// Drawing a brace between to obejcts to show the distance between them +Item { + id: canvas + anchors.fill: parent; + property Item from + property Item to + property bool flip: false + property bool center: true + property string text + property string color: "rgba(236, 161, 169, 0.8)" + property bool horizontal: true; + + Rectangle { + id: prot + color: "#cc93cee9" + width: childrenRect.width + 10 + height: childrenRect.height + 10 + z: 2 + + Text { + x: 4 + id: label + color: "#000" + text: canvas.text + font.pointSize: 8 + lineHeight: 8 + height: 8 + } + } + + + Canvas { + anchors.fill: parent; + onPaint: { + // it might be necessary to calculate scale + // because annotation should not be scaled + // var scale = T.getScale(canvas.parent) + + var ctx = getContext("2d"); + ctx.strokeStyle = canvas.color; + ctx.beginPath(); + + var cfrom = from.mapToItem(canvas.parent, 0, 0); + var cto = to.mapToItem(canvas.parent, 0, 0); + + // Determine direction + // draw either horizontal or vertical + if (horizontal) { + + // Calculate anchor points for braces + if (!canvas.center) { + // Draw from closest borders + if (cfrom.x > cto.x) { + // If no label was provided calulate it + if (canvas.text == "") { + canvas.text = cfrom.x - cto.x - to.width; + } + cfrom.x = cfrom.x + Math.min(Math.floor(from.width / 2), 2 * Kirigami.Units.smallSpacing) + cto.x = cto.x + to.width - Math.min(Math.floor(to.width / 2), 2 * Kirigami.Units.smallSpacing) + } + else { + // If no label was provided calulate it + if (canvas.text == "") { + canvas.text = (cto.x - cfrom.x - from.width); + } + cfrom.x = cfrom.x + from.width - Math.min(Math.floor(from.width / 2), 2 * Kirigami.Units.smallSpacing) + cto.x = cto.x + Math.min(Math.floor(to.width / 2), 2 * Kirigami.Units.smallSpacing) + } + } + else { + // Draw from the center + cfrom.x = cfrom.x + from.width / 2; + cto.x = cto.x + to.width / 2; + } + + // Draw the brace + ctx.moveTo(cfrom.x, cfrom.y); + ctx.lineTo(cfrom.x, cfrom.y - Kirigami.Units.smallSpacing); + ctx.lineTo(cto.x, cfrom.y - Kirigami.Units.smallSpacing); + ctx.lineTo(cto.x, cfrom.y); + + // Position label + prot.x = (cfrom.x + cto.x) / 2 - prot.width / 2 + prot.y = cfrom.y - prot.height - 2 * Kirigami.Units.smallSpacing + } + else { + if (!canvas.center) { + // Draw from closest borders + if (cfrom.y > cto.y) { + // If no label was provided calulate it + if (canvas.text == "") { + canvas.text = (cto.y - cfrom.y + from.height); + } + cfrom.y = cfrom.y + Math.min(Math.floor(from.height / 2), 2 * Kirigami.Units.smallSpacing) + cto.y = cto.y + to.height - Math.min(Math.floor(to.height / 2), 2 * Kirigami.Units.smallSpacing) + + } + else { + // If no label was provided calulate it + if (canvas.text == "") { + canvas.text = (cto.y - cfrom.y - from.height); + } + cfrom.y = cfrom.y + from.height - Math.min(Math.floor(from.height / 2), 2 * Kirigami.Units.smallSpacing) + cto.y = cto.y + Math.min(Math.floor(to.height / 2), 2 * Kirigami.Units.smallSpacing) + } + } + else { + // Draw from the center + cfrom.y = cfrom.y + from.height / 2; + cto.y = cto.y + to.height / 2; + } + + // Draw the brace + ctx.moveTo(cfrom.x, cfrom.y); + ctx.lineTo(cfrom.x - Kirigami.Units.smallSpacing, cfrom.y); + ctx.lineTo(cfrom.x - Kirigami.Units.smallSpacing, cto.y); + ctx.lineTo(cfrom.x, cto.y); + + // Position label + prot.x = cfrom.x - prot.width - 2 * Kirigami.Units.smallSpacing + prot.y = (cfrom.y + cto.y ) / 2 - prot.height / 2 - 4 + } + + ctx.stroke(); + } + } +} diff --git a/source/qml/lib/Demo.qml b/source/qml/lib/Demo.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/Demo.qml @@ -0,0 +1,119 @@ +/* + * 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 "tools.js" as T +import "annotate.js" as A + +Rectangle { + width: 320 + height: 280 + color: "white" + + Item { + anchors.fill: parent + id: root + + Row { + spacing: Kirigami.Units.largeSpacing * 2 + x: Kirigami.Units.gridUnit * 2 + y: Kirigami.Units.gridUnit * 2 + + Rectangle { + id: left1 + width: Kirigami.Units.largeSpacing * 8 + height: Kirigami.Units.largeSpacing * 8 + color: "#27ae60" + } + + Rectangle { + id: right1 + width: Kirigami.Units.largeSpacing * 8 + height: Kirigami.Units.largeSpacing * 8 + color: "#27ae60" + anchors.top: parent.top; + } + } + + Row { + spacing: Kirigami.Units.smallSpacing * 8 + x: Kirigami.Units.gridUnit * 2 + y: Kirigami.Units.gridUnit * 8 + + Rectangle { + id: left2 + width: Kirigami.Units.largeSpacing * 8 + height: Kirigami.Units.largeSpacing * 8 + color: "#27ae60" + } + + Rectangle { + id: right2 + width: Kirigami.Units.largeSpacing * 12 + height: Kirigami.Units.largeSpacing * 12 + color: "#27ae60" + anchors.top: parent.top; + + Rectangle { + id: right3 + width: Kirigami.Units.largeSpacing * 4 + height: Kirigami.Units.largeSpacing * 4 + color: "black" + anchors.top: parent.top; + anchors.right: parent.right; + anchors.margins: Kirigami.Units.smallSpacing + } + } + } + + } + + // 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("qquickrectangle").first().draw({ + outline: {}, + ruler: {}, + brace: {to: new A.An(right2), text: "16px", center: false} + }); + + a.find("qquickrectangle").eq(2).draw({ + outline: {aspectratio: true}, + }); + + a.find("qquickrectangle").eq(3).draw({ + messure: { to: a.find("qquickrectangle").eq(4)} + }); + } + } + + // Draw helpers and anotation + Raster { + base: Kirigami.Units.gridUnit + mobile: true + desktop: true + } +} diff --git a/source/qml/lib/Messure.qml b/source/qml/lib/Messure.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/Messure.qml @@ -0,0 +1,125 @@ +/* + * 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 + +//window containing the application +Canvas { + anchors.fill: parent; + id: canvas + property string color: "rgba(218, 68, 83, 0.8)" + property Item from + property Item to + property string type: "left" + property int rx; + property int ry; + z: 3 + property string text + + Rectangle { + id: prot + color: "#cc93cee9" + width: childrenRect.width + 10 + height: childrenRect.height + 10 + z: 2 + + Text { + x: 4 + id: label + color: "#000" + text: canvas.text + font.pointSize: 8 + lineHeight: 8 + height: 8 + + } + } + + onPaint: { + var ctx = getContext("2d"); + ctx.strokeStyle = canvas.color; + ctx.lineWidth = 1 + ctx.beginPath(); + + var cFrom = from.mapToItem(canvas.parent, 0, 0); + var cTo = to.mapToItem(canvas.parent, 0, 0); + + // Horizontal messure + if (type == "left" || type == "right") { + var y; + if (canvas.ry) { + y = ry; + } + else { + if (from.height < to.height) { + y = cFrom.y + from.height / 2; + } + else { + y = cTo.y + to.height / 2; + } + } + if (type == "right") { + cFrom.x += from.width + cTo.x += to.width + } + ctx.moveTo(cFrom.x + 4, y); + ctx.lineTo(cTo.x - 4, y); + + // Write distance + // TODO center it for real + if (canvas.text == "") { + label.text = Math.abs(cTo.x - cFrom.x); + } + prot.x = cFrom.x + (cTo.x - cFrom.x) / 2 - 8 + prot.y = y - 16 + } + else { + var x; + if (canvas.rx) { + x = rx; + } + else { + if (from.width < to.width) { + x = cFrom.x + from.width / 2; + } + else { + x = cTo.x + to.width / 2; + } + + } + if (type == "bottom") { + cFrom.y += from.height + cTo.y += to.height + } + ctx.moveTo(x, cFrom.y + 4); + ctx.lineTo(x, cTo.y - 4); + + // Write distance + if (canvas.text == "") { + label.text = Math.abs(cTo.y - cFrom.y); + } + prot.y = cFrom.y + (cTo.y - cFrom.y) / 2 - 8 + prot.x = x + 8 + } + + ctx.stroke(); + } +} diff --git a/source/qml/lib/Outline.qml b/source/qml/lib/Outline.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/Outline.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.7 +import QtQuick.Controls 2.2 +import "tools.js" as T + +// Draw a frame around an element +Item { + anchors.fill: parent; + property string color: "rgba(236, 161, 169, 0.6)" + property bool label: true + property bool aspectratio: false + property Item item + property Item root : container.parent + z: 10 + id: container + + Rectangle { + id: prot + color: "#cc93cee9" + width: childrenRect.width + 10 + height: childrenRect.height + 10 + visible: false + z: 2 + + Text { + x: 4 + id: dim + color: "#000" + font.pointSize: 8 + lineHeight: 8 + height: 8 + + } + } + + Canvas { + anchors.fill: parent; + id: canvas + + onPaint: { + // get scale because annotation should not be scaled + var scale = T.getScale(container.parent) + + var ctx = getContext("2d"); + ctx.strokeStyle = container.color; + ctx.lineWidth = 4 / scale + ctx.beginPath(); + + // Draw an rectangle around the element + var offset = ctx.lineWidth / 2; + var cItem = item.mapToItem(container.root, 0, 0); + ctx.moveTo(cItem.x + offset, cItem.y + offset); + ctx.lineTo(cItem.x + offset, cItem.y + item.height - offset); + ctx.lineTo(cItem.x + item.width - offset, cItem.y + item.height - offset); + ctx.lineTo(cItem.x + item.width - offset, cItem.y + offset); + ctx.lineTo(cItem.x + offset, cItem.y + offset); + + if (container.aspectratio) { + // Write proportions of an object instead of dimensions / px + ctx.moveTo(cItem.x + offset, cItem.y + offset); + ctx.lineTo(cItem.x + item.width - offset, cItem.y + item.height - offset); + ctx.moveTo(cItem.x + item.width - offset, cItem.y + offset); + ctx.lineTo(cItem.x + offset, cItem.y + item.height - offset); + + var aspect = Math.round(item.width / item.height * 100) / 100 + // Well known aspect ratios + switch (aspect) { + case 1: + aspect = "1 x 1" + break; + case 1.33: + aspect = "4 x 3" + break; + case 1.5: + aspect = "3 x 2" + break; + case 1.78: + aspect = "16 x 9" + break; + } + dim.text = aspect + prot.visible = true; + prot.x = cItem.x + item.width / 2 - prot.width / 2 + prot.y = cItem.y + item.height / 2 - prot.height / 2 + + } + else { + // Write dimensions / px + if (container.label) { + dim.text = Math.round(item.width * 100) / 100 + " x " + Math.round(item.height * 100) / 100; + prot.visible = true; + prot.x = cItem.x + item.width / 2 - prot.width / 2 + prot.y = cItem.y + item.height / 2 - prot.height / 2 + } + } + + ctx.stroke(); + } + } +} diff --git a/source/qml/lib/Padding.qml b/source/qml/lib/Padding.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/Padding.qml @@ -0,0 +1,130 @@ +/* + * 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 + +// Show the padding of an element +Item { + anchors.fill: parent; + property string color: "rgba(147,206,233, 0.8)" + property bool label: false + property Item item + property Item root : container.parent + property string padding: "" + z: 10 + id: container + + Text { + id: top + color: "#da4453" + font.pointSize: 8 + lineHeight: 8 + height: 8 + z: 2 + } + Text { + id: right + color: "#da4453" + font.pointSize: 8 + lineHeight: 8 + height: 8 + z: 2 + } + Text { + id: bottom + color: "#da4453" + font.pointSize: 8 + lineHeight: 8 + height: 8 + z: 2 + } + Text { + id: left + color: "#da4453" + font.pointSize: 8 + lineHeight: 8 + height: 8 + z: 2 + } + + Canvas { + anchors.fill: parent; + id: canvas + + onPaint: { + // Determen padding + var padding = { + "top": item.topPadding, + "right": item.rightPadding, + "bottom": item.bottomPadding, + "left": item.leftPadding + } + + // setup drawing context + var offset; + var cItem = item.mapToItem(container.root, 0, 0); + var ctx = getContext("2d"); + ctx.strokeStyle = container.color; + ctx.beginPath(); + + // Draw top + ctx.lineWidth = padding.top; + offset = ctx.lineWidth / 2; + ctx.moveTo(cItem.x + offset, cItem.y + offset); + ctx.lineTo(cItem.x + item.width - offset, cItem.y + offset); + + // Draw right + ctx.lineWidth = padding.right; + offset = ctx.lineWidth / 2; + ctx.lineTo(cItem.x + item.width - offset, cItem.y + item.height - offset); + + // Draw bottom + ctx.lineWidth = padding.bottom; + offset = ctx.lineWidth / 2; + ctx.lineTo(cItem.x + offset, cItem.y + item.height - offset); + + // Draw left + ctx.lineWidth = padding.bottom; + offset = ctx.lineWidth / 2; + ctx.lineTo(cItem.x + offset, cItem.y + offset); + + ctx.stroke(); + + // Write labels + top.text = padding.top; + top.x = cItem.x + item.width / 2; + top.y = cItem.y - 4; + + right.text = padding.right; + right.x = cItem.x + item.width - right.width; + right.y = cItem.y + item.height / 2; + + bottom.text = padding.bottom; + bottom.x = cItem.x + item.width / 2; + bottom.y = cItem.y + item.height - bottom.height - 4; + + left.text = padding.left; + left.x = cItem.x; + left.y = cItem.x + item.height / 2; + + } + } +} diff --git a/source/qml/lib/Raster.qml b/source/qml/lib/Raster.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/Raster.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.7 +import QtQuick.Controls 2.2 +import org.kde.kirigami 2.4 as Kirigami + +// Drawing a semi transparent raster and a legend +Item { + anchors.fill: parent; + property int base: Kirigami.Units.gridUnit + property string color: "rgba(200, 200, 200, 0.7)" + property string label: "Units.gridUnit / 18px" + property bool touch: false; // Indicate touch support + property bool mobile: false; // Indicate mobile/small display support + property bool mouse: false; // Indicate mouse support + property bool desktop: false; // Indicate large display support + + // Painting the grid on a canvas + Canvas { + anchors.fill: parent; + id: canvas + onPaint: { + var ctx = getContext("2d"); + ctx.strokeStyle = color; + ctx.beginPath(); + + // Horizontal grid lines + var i = 0; + while (i < canvas.height / base) { + ctx.moveTo(0, i * base); + ctx.lineTo(canvas.width, i * base); + i++; + } + + // Vertical grid lines + i = 0; + while (i < canvas.width / base) { + ctx.moveTo(i * base, 0); + ctx.lineTo(i * base, canvas.height); + i++; + } + ctx.stroke(); + + // draw scale on the bottom right + // |---| + if (label != "") { + ctx.strokeStyle = "#da4453"; + ctx.beginPath(); + var left = canvas.width - 2 * base - canvas.width % base; + var top; + if (canvas.height % base > 2 * Kirigami.Units.smallSpacing) { + top = canvas.height - canvas.height % base; + } + else { + top = canvas.height - base - canvas.height % base; + } + + ctx.moveTo(left, top - Kirigami.Units.smallSpacing); + ctx.lineTo(left, top + Kirigami.Units.smallSpacing); + + ctx.moveTo(left, top); + ctx.lineTo(left + base, top); + + ctx.moveTo(left + base, top - Kirigami.Units.smallSpacing); + ctx.lineTo(left + base, top + Kirigami.Units.smallSpacing); + ctx.stroke(); + } + } + } + + Label { + id: lbl + text: label + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.bottomMargin: canvas.height % base > 2 * Kirigami.Units.smallSpacing ? canvas.height % base + Kirigami.Units.smallSpacing : base + canvas.height % base + Kirigami.Units.smallSpacing + anchors.rightMargin: base + color: "#da4453" + font.pixelSize: 10 + renderType: Text.QtRendering + } + + Row { + anchors.bottom: lbl.top + anchors.right: lbl.right + anchors.margins: Kirigami.Units.smallSpacing + spacing: Kirigami.Units.smallSpacing + Image { + visible: mouse + height: Kirigami.Units.iconSizes.medium; + width: Kirigami.Units.iconSizes.medium; + source: "../../img/edit-select.svg" + //smooth: true + } + Image { + visible: touch + height: Kirigami.Units.iconSizes.medium; + width: Kirigami.Units.iconSizes.medium; + source: "../../img/transform-browse.svg" + //smooth: true + } + Image { + visible: desktop + height: Kirigami.Units.iconSizes.medium; + width: Kirigami.Units.iconSizes.medium; + source: "../../img/video-display.svg" + //smooth: true + } + Image { + visible: mobile + height: Kirigami.Units.iconSizes.medium; + width: Kirigami.Units.iconSizes.medium; + source: "../../img/smartphone.svg" + //smooth: true + } + } +} diff --git a/source/qml/lib/Ruler.qml b/source/qml/lib/Ruler.qml new file mode 100644 --- /dev/null +++ b/source/qml/lib/Ruler.qml @@ -0,0 +1,66 @@ +/* + * 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 "tools.js" as T + +// Draw a ruler for highlighting alignment +Item { + id: canvas + anchors.fill: parent; + property int rx; + property int ry; + property bool horizontal: true; + property string stroke: "rgba(41,128,185, 1)" + property double scale: T.getScale(canvas) + + // using Rectangles because they scale smooth + Row { + y: canvas.ry + x: 0 + id: hackRow + visible: canvas.horizontal + spacing: Kirigami.Units.smallSpacing / scale + Repeater { + model: new Array(Math.floor(canvas.width / hackRow.spacing / 2)) + Rectangle { + width: Kirigami.Units.smallSpacing / scale + height: 2 / scale + color: "#2980b9" + } + } + } + Column { + x: canvas.rx + y: 0 + id: hackColumn + visible: !canvas.horizontal + spacing: Kirigami.Units.smallSpacing / scale + Repeater { + model: new Array(Math.floor(canvas.height / hackColumn.spacing / 2)) + Rectangle { + height: Kirigami.Units.smallSpacing / scale + width: 1 / scale + color: "#2980b9" + } + } + } +} diff --git a/source/qml/lib/annotate.js b/source/qml/lib/annotate.js new file mode 100644 --- /dev/null +++ b/source/qml/lib/annotate.js @@ -0,0 +1,222 @@ +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"); + +// 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(); +} + +// 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; +} + +// 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(); +} + + +/** + * 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()); + 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": + outline.createObject(root, {item: node, label: opt.label, aspectratio: opt.aspectratio}); + break + case "ruler": + ruler.createObject(root, {rx: node.mapToItem(null, 0, 0).x, horizontal: false}); + break + case "padding": + padding.createObject(root, {item: node}); + break + case "brace": + brace.createObject(root, {"from": node, "to": opt.to.nodes[0], "text": opt.text, "center": opt.center, "horizontal": opt.horizontal}); + break + case "messure": + 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/source/qml/lib/tools.js b/source/qml/lib/tools.js new file mode 100644 --- /dev/null +++ b/source/qml/lib/tools.js @@ -0,0 +1,9 @@ +// 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; +}