Commit 2ba27475 authored by Fabian Riethmayer's avatar Fabian Riethmayer

added qml tools to annotate qml scenes

Summary:
Added tools to annotate qml sceens with  grids, outlines, messuremens, lines for alignemnt.
Added a Demo.qml to demonstate some of the annotation tools.

Reviewers: mart

Reviewed By: mart

Subscribers: mart

Differential Revision: https://phabricator.kde.org/D14293
parent c9d5a70e
/env
build
*.qmlc
*.jsc
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#4d4d4d;
}
</style>
</defs>
<path
style="fill:currentColor;fill-opacity:1;stroke:none"
d="M6 3A1 1 0 0 0 5 4 1 1 0 0 0 6 5 1 1 0 0 0 7 4 1 1 0 0 0 6 3M7 6L7.00586 19 10.900391 14.300781 17 14 7 6"
class="ColorScheme-Text"
/>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64"
version="1.1"
height="64"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="video-display.svg">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1019"
id="namedview73"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="17.857647"
inkscape:cy="39.371751"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs5455">
<linearGradient
inkscape:collect="always"
id="linearGradient4159">
<stop
style="stop-color:#2a2c2f"
id="stop4161" />
<stop
offset="1"
style="stop-color:#424649"
id="stop4163" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4250"
xlink:href="#linearGradient4159"
y1="536.79797"
y2="503.798"
gradientUnits="userSpaceOnUse"
x2="0"
gradientTransform="matrix(1.0833331 0 0 1.0909092 -34.04753 -49.799908)" />
<linearGradient
inkscape:collect="always"
id="linearGradient4272"
xlink:href="#linearGradient4303"
y1="547.79797"
y2="536.79797"
gradientUnits="userSpaceOnUse"
x2="0"
gradientTransform="matrix(1.1666674 0 0 1.0909092 -68.09551 -49.799906)" />
<linearGradient
inkscape:collect="always"
id="linearGradient4303">
<stop
style="stop-color:#c6cdd1"
id="stop4305" />
<stop
offset="1"
style="stop-color:#e0e5e7"
id="stop4307" />
</linearGradient>
</defs>
<metadata
id="metadata5458">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1"
transform="matrix(1 0 0 1 -376.57144 -491.79797)">
<path
inkscape:connector-curvature="0"
style="stroke-opacity:0.550265;fill:url(#linearGradient4272);stroke-width:2.8"
id="rect4254"
d="m 401.57143,535.79797 0,7.63636 0,2.18182 0,2.18182 14,0 0,-2.18182 0,-2.18182 0,-7.63636 z" />
<rect
width="51.999989"
x="382.57144"
y="499.79797"
height="39.27273"
style="stroke-opacity:0.550265;fill:url(#linearGradient4250);stroke-width:2.8"
id="rect4173" />
<rect
width="23.999969"
x="396.57144"
y="546.79797"
height="1.00002"
style="stroke-opacity:0.550265;fill:#99a1a7;stroke-width:2.8"
id="rect4295" />
<rect
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect3401"
width="48.203388"
height="35.796612"
x="384.57144"
y="501.62848" />
</g>
</svg>
/*
* 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
Label {
x: Kirigami.Units.smallSpacing
y: Kirigami.Units.smallSpacing
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();
}
}
}
/*
* 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
}
}
/*
* 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
Label {
x: Kirigami.Units.smallSpacing
y: Kirigami.Units.smallSpacing
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();
}
}
/*
* 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
Label {
x: Kirigami.Units.smallSpacing
y: Kirigami.Units.smallSpacing
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();
}
}
}
/*
* 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