Changeset View
Changeset View
Standalone View
Standalone View
kcms/keyboard/tastenbrett/qml/ShapeCanvas.qml
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | Copyright 2019 Harald Sitter <sitter@kde.org> | ||||
3 | | ||||
4 | This program is free software; you can redistribute it and/or | ||||
5 | modify it under the terms of the GNU General Public License as | ||||
6 | published by the Free Software Foundation; either version 2 of | ||||
7 | the License or (at your option) version 3 or any later version | ||||
8 | accepted by the membership of KDE e.V. (or its successor approved | ||||
9 | by the membership of KDE e.V.), which shall act as a proxy | ||||
10 | defined in Section 14 of version 3 of the license. | ||||
11 | | ||||
12 | This program is distributed in the hope that it will be useful, | ||||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
15 | GNU General Public License for more details. | ||||
16 | | ||||
17 | You should have received a copy of the GNU General Public License | ||||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
19 | */ | ||||
20 | | ||||
21 | import QtQuick 2.12 | ||||
22 | import QtQuick.Controls 2.5 | ||||
23 | | ||||
24 | Canvas { | ||||
25 | property QtObject shape | ||||
26 | property variant strokeSyle: "yellow" | ||||
27 | property variant fillStyle: "steelblue" | ||||
28 | // Only draw one outline. Outlines are tricky because xkb has no | ||||
29 | // concept of displaying text on top of the shapes. IOW: it | ||||
30 | // only thinks about blank keys. This means we have no layout | ||||
31 | // constraints for our text and as a result we'd have to figure out | ||||
32 | // where to put text so it doesn't conflict with any of the drawn | ||||
33 | // paths and is inside most/all of them. It's not worth the work... | ||||
34 | property int maxOutline: 1 | ||||
35 | // use a round number, we divide this by two to balance spacing | ||||
36 | property real lineWidth: 4.0 | ||||
37 | // scoot away from 0,0 to translation,translation | ||||
38 | property real translation: lineWidth / 2.0 | ||||
39 | // reduce the scale to account for the scoot of translation | ||||
40 | property real scale: Math.min((width - lineWidth) / width, (height - lineWidth) / height) | ||||
41 | | ||||
42 | id: canvas | ||||
43 | width: shape.bounds.width | ||||
44 | height: shape.bounds.height | ||||
45 | onStrokeSyleChanged: requestPaint() | ||||
46 | onFillStyleChanged: requestPaint() | ||||
47 | | ||||
48 | onPaint: { | ||||
49 | var ctx = getContext("2d") | ||||
50 | ctx.reset() | ||||
51 | ctx.lineWidth = lineWidth | ||||
52 | ctx.strokeStyle = strokeSyle | ||||
53 | ctx.fillStyle = fillStyle | ||||
54 | // Transform the context a bunch. The way strokes work is that | ||||
55 | // they extend to the left and right of the path, so with a | ||||
56 | // lineWidth of 8 we'll need the entire scene scooted so | ||||
57 | // 0,0 becomes 4,4. Since that also would screw up our absolute | ||||
58 | // cordinates towards the right (e.g. our width bounds as reported | ||||
59 | // by XKB) we also need to then adjust the scale so the entire | ||||
60 | // coordinate system so the scene leaves sufficient space at all | ||||
61 | // borders. | ||||
62 | // i.e. we move the scene so the top and right strokes are fully | ||||
63 | // visible and then shrink it so the left and bottom are fully visible. | ||||
64 | ctx.translate(translation, translation) | ||||
65 | ctx.scale(scale, scale) | ||||
66 | | ||||
67 | ctx.beginPath() | ||||
68 | | ||||
69 | for (var i in shape.outlines) { | ||||
70 | if (maxOutline && i >= maxOutline) { | ||||
71 | break; | ||||
72 | } | ||||
73 | | ||||
74 | var outline = shape.outlines[i] | ||||
75 | | ||||
76 | if (outline.points.length === 1) { // rect from 0,0 to point | ||||
77 | var point = outline.points[0] | ||||
78 | | ||||
79 | ctx.roundedRect(0, 0, | ||||
80 | point.x, point.y, | ||||
81 | outline.corner_radius, outline.corner_radius) | ||||
82 | } else if (outline.points.length === 2) { // rect from p1 to p2 | ||||
83 | var topLeftPoint = outline.points[0] | ||||
84 | var bottomRightPoint = outline.points[1] | ||||
85 | | ||||
86 | ctx.roundedRect(topLeftPoint.x, topLeftPoint.y, | ||||
87 | bottomRightPoint.x, bottomRightPoint.y, | ||||
88 | outline.corner_radius, outline.corner_radius) | ||||
89 | } else { // polygon point to point draw (used for doodads and non-rect keys such as Enter) | ||||
90 | for (var j in outline.points) { | ||||
91 | var anyPoint = outline.points[j] | ||||
92 | if (j < 1) { // move to first point | ||||
93 | ctx.moveTo(anyPoint.x, anyPoint.y) | ||||
94 | } else { // from there we draw point to point | ||||
95 | ctx.lineTo(anyPoint.x, anyPoint.y) | ||||
96 | } | ||||
97 | | ||||
98 | // TODO: should probably draw short of target and then arcTo over the target so we get a round corner? | ||||
99 | // Currently shapes are not rounded. | ||||
100 | } | ||||
101 | } | ||||
102 | } | ||||
103 | | ||||
104 | ctx.closePath() | ||||
105 | if (fillStyle) { | ||||
106 | ctx.fill() | ||||
107 | } | ||||
108 | ctx.stroke() | ||||
109 | } | ||||
110 | } |