author | unC0Rr |
Sun, 01 Dec 2024 21:08:03 +0100 | |
branch | transitional_engine |
changeset 16073 | 5c941f5deeec |
parent 16072 | adb44a2d8226 |
permissions | -rw-r--r-- |
16072 | 1 |
import QtQuick |
2 |
import QtQuick.Controls |
|
3 |
import QtQuick.Layouts |
|
4 |
import QtQuick.Shapes |
|
5 |
||
6 |
Window { |
|
7 |
id: control |
|
8 |
||
9 |
width: 1024 |
|
10 |
height: 768 |
|
11 |
visible: true |
|
12 |
title: qsTr("Map Templates") |
|
13 |
||
14 |
property bool hasError: false |
|
15 |
||
16 |
Page { |
|
17 |
id: page |
|
18 |
anchors.fill: parent |
|
19 |
||
20 |
Rectangle { |
|
21 |
id: mapContainer |
|
22 |
||
16073
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
23 |
property int spaceForCode: Math.max(250, parent.height * 0.6) |
16072 | 24 |
property int mapWidth: 2048 |
25 |
property int mapHeight: 1024 |
|
26 |
property real aspectRatio: mapWidth / mapHeight |
|
27 |
property bool fitWidth: aspectRatio > (parent.width / (parent.height - spaceForCode)) |
|
28 |
||
29 |
implicitWidth: fitWidth ? parent.width : (parent.height - spaceForCode) * aspectRatio |
|
30 |
implicitHeight: fitWidth ? parent.width / aspectRatio : (parent.height - spaceForCode) |
|
31 |
||
32 |
x: (parent.width - width) / 2 |
|
33 |
||
34 |
border.width: 2 |
|
35 |
border.color: hasError ? "red" : "black" |
|
36 |
} |
|
37 |
||
38 |
Shape { |
|
39 |
id: shape |
|
40 |
||
41 |
anchors.fill: mapContainer |
|
42 |
} |
|
43 |
||
16073
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
44 |
MouseArea { |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
45 |
id: mouseArea |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
46 |
anchors.fill: mapContainer |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
47 |
hoverEnabled: true |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
48 |
} |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
49 |
|
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
50 |
Label { |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
51 |
text: mouseArea.containsMouse ? "(%1, %2)".arg(Math.floor(mouseArea.mouseX / mouseArea.width * mapContainer.mapWidth)).arg(Math.floor(mouseArea.mouseY / mouseArea.height * mapContainer.mapHeight)) : "" |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
52 |
} |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
53 |
|
16072 | 54 |
Rectangle { |
55 |
anchors.fill: codeInput |
|
56 |
color: "gray" |
|
57 |
} |
|
58 |
||
59 |
TextEdit { |
|
60 |
id: codeInput |
|
61 |
||
62 |
anchors.bottom: parent.bottom |
|
63 |
anchors.left: parent.left |
|
64 |
anchors.right: parent.right |
|
65 |
height: parent.height - mapContainer.height |
|
66 |
||
67 |
text: " - |
|
68 |
width: 3072 |
|
69 |
height: 1424 |
|
70 |
can_flip: false |
|
71 |
can_invert: false |
|
72 |
can_mirror: true |
|
73 |
is_negative: false |
|
74 |
put_girders: true |
|
75 |
max_hedgehogs: 18 |
|
76 |
outline_points: |
|
77 |
- |
|
78 |
- {x: 748, y: 1424, w: 1, h: 1} |
|
79 |
- {x: 636, y: 1252, w: 208, h: 72} |
|
80 |
- {x: 898, y: 1110, w: 308, h: 60} |
|
81 |
- {x: 1128, y: 1252, w: 434, h: 40} |
|
82 |
- {x: 1574, y: 1112, w: 332, h: 40} |
|
83 |
- {x: 1802, y: 1238, w: 226, h: 36} |
|
84 |
- {x: 1930, y: 1424, w: 1, h: 1} |
|
85 |
- |
|
86 |
- {x: 2060, y: 898, w: 111, h: 111} |
|
87 |
- {x: 1670, y: 876, w: 34, h: 102} |
|
88 |
- {x: 1082, y: 814, w: 284, h: 132} |
|
89 |
- {x: 630, y: 728, w: 126, h: 168} |
|
90 |
- {x: 810, y: 574, w: 114, h: 100} |
|
91 |
- {x: 1190, y: 572, w: 352, h: 120} |
|
92 |
- {x: 1674, y: 528, w: 60, h: 240} |
|
93 |
- {x: 1834, y: 622, w: 254, h: 116} |
|
94 |
fill_points: |
|
95 |
- {x: 1423, y: 0} |
|
96 |
" |
|
97 |
||
98 |
onTextChanged: { |
|
99 |
const template = parseInput() |
|
100 |
||
101 |
if (template) { |
|
102 |
mapContainer.mapWidth = Number(template.width) |
|
103 |
mapContainer.mapHeight = Number(template.height) |
|
104 |
||
105 |
shape.data = renderTemplate(template) |
|
106 |
} |
|
107 |
} |
|
108 |
} |
|
109 |
} |
|
110 |
||
111 |
function parseInput() { |
|
112 |
let code = codeInput.text.split('\n') |
|
113 |
||
114 |
if(code[0] !== " -") { |
|
115 |
hasError = true |
|
116 |
return |
|
117 |
} |
|
118 |
||
119 |
code = code.slice(1) |
|
120 |
code.push("") |
|
121 |
||
122 |
let parsed = ({}) |
|
123 |
let polygonAccumulator = [] |
|
124 |
let pointAccumulator = [] |
|
125 |
let key = "" |
|
126 |
code.forEach(line => { |
|
127 |
let newKey |
|
128 |
if (line === " outline_points:") { |
|
129 |
newKey = "outline_points" |
|
130 |
} |
|
131 |
||
16073
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
132 |
if (line === " walls:") { |
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
133 |
newKey = "walls" |
16072 | 134 |
} |
135 |
||
136 |
if (line === " fill_points:") { |
|
137 |
newKey = "fill_points" |
|
138 |
} |
|
139 |
||
140 |
if (line === "") { |
|
141 |
newKey = "_" |
|
142 |
} |
|
143 |
||
144 |
if (key === "fill_points" && line.startsWith(" - {")) { |
|
145 |
// ignore |
|
146 |
return |
|
147 |
} |
|
148 |
||
149 |
if (newKey) { |
|
150 |
if (key.length > 0) { |
|
151 |
polygonAccumulator.push(pointAccumulator) |
|
152 |
parsed[key] = polygonAccumulator |
|
153 |
} |
|
154 |
||
155 |
key = newKey |
|
156 |
polygonAccumulator = [] |
|
157 |
pointAccumulator = [] |
|
158 |
||
159 |
return |
|
160 |
} |
|
161 |
||
162 |
if (line === " -") { |
|
163 |
if (pointAccumulator.length > 0) { |
|
164 |
polygonAccumulator.push(pointAccumulator) |
|
165 |
pointAccumulator = [] |
|
166 |
} |
|
167 |
||
168 |
return |
|
169 |
} |
|
170 |
||
171 |
const matchValue = line.match(/^\s{4}(\w+):\s(.+)$/); |
|
172 |
||
173 |
if (matchValue) { |
|
174 |
parsed[matchValue[1]] = matchValue[2] |
|
175 |
return |
|
176 |
} |
|
177 |
||
178 |
const matchPoint = line.match(/^\s{8}-\s\{([^}]+)\}$/); |
|
179 |
||
180 |
if (matchPoint) { |
|
181 |
const point = matchPoint[1].split(", ").reduce((obj, pair) => { |
|
182 |
const [key, value] = pair.split(": "); |
|
183 |
obj[key] = isNaN(value) ? value : parseInt(value); |
|
184 |
return obj; |
|
185 |
}, {}) |
|
186 |
pointAccumulator.push(point) |
|
187 |
return |
|
188 |
} |
|
189 |
||
190 |
console.log("Unrecognized: " + JSON.stringify(line)) |
|
191 |
hasError = true |
|
192 |
throw "" |
|
193 |
}) |
|
194 |
||
195 |
hasError = false |
|
196 |
||
197 |
return parsed |
|
198 |
} |
|
199 |
||
200 |
Component { |
|
201 |
id: shapePathComponent |
|
202 |
||
203 |
ShapePath { |
|
204 |
fillColor: "transparent" |
|
205 |
scale: Qt.size(mapContainer.width / mapContainer.mapWidth, mapContainer.height / mapContainer.mapHeight) |
|
206 |
strokeWidth: 3 |
|
207 |
} |
|
208 |
} |
|
209 |
||
210 |
Component { |
|
211 |
id: pathLineComponent |
|
212 |
PathLine { |
|
213 |
} |
|
214 |
} |
|
215 |
||
216 |
function polygons2shapes(polygons, lineColor, rectColor) { |
|
217 |
if (!Array.isArray(polygons)) { |
|
218 |
return [] |
|
219 |
} |
|
220 |
||
221 |
let rectangles = [] |
|
222 |
||
223 |
polygons.forEach(polygon => polygon.forEach(r => { |
|
224 |
let shapePath = shapePathComponent.createObject(shape) |
|
225 |
shapePath.strokeWidth = 1 |
|
226 |
shapePath.strokeColor = rectColor |
|
227 |
||
228 |
shapePath.startX = r.x |
|
229 |
shapePath.startY = r.y |
|
230 |
shapePath.pathElements = [ |
|
231 |
pathLineComponent.createObject(shapePath, {x: r.x, y: r.y + r.h}), |
|
232 |
pathLineComponent.createObject(shapePath, {x: r.x + r.w, y: r.y + r.h}), |
|
233 |
pathLineComponent.createObject(shapePath, {x: r.x + r.w, y: r.y}), |
|
234 |
pathLineComponent.createObject(shapePath, {x: r.x, y: r.y}) |
|
235 |
] |
|
236 |
||
237 |
rectangles.push(shapePath) |
|
238 |
})) |
|
239 |
let polygonShapes = polygons.map(polygon => { |
|
240 |
let points = polygon.map(r => ({x: r.x + r.w / 2, y: r.y + r.h / 2})) |
|
241 |
let shapePath = shapePathComponent.createObject(shape) |
|
242 |
let start = points[points.length - 1] |
|
243 |
||
244 |
shapePath.strokeColor = lineColor |
|
245 |
shapePath.startX = start.x |
|
246 |
shapePath.startY = start.y |
|
247 |
shapePath.pathElements = points.map(p => pathLineComponent.createObject(shapePath, p)) |
|
248 |
||
249 |
return shapePath |
|
250 |
}) |
|
251 |
||
252 |
return rectangles.concat(polygonShapes) |
|
253 |
} |
|
254 |
||
255 |
function renderTemplate(template) { |
|
16073
5c941f5deeec
* Introduce concept of invizible walls to constrain outline map generation
unC0Rr
parents:
16072
diff
changeset
|
256 |
return polygons2shapes(template.outline_points, "red", "black").concat(polygons2shapes(template.walls, "gray", "gray")) |
16072 | 257 |
} |
258 |
} |