/
common.nim
447 lines (356 loc) · 11.9 KB
/
common.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
import std/hashes
import std/sets
import std/strformat
import std/strutils
import std/tables
import koi
import nanovg
import semver
import utils/rect
const
ProjectHomeUrl* = "https://gridmonger.johnnovak.net/"
AppVersion* = parseVersion(staticRead("../CURRENT_VERSION").strip)
CompileYear* = CompileDate[0..3]
BuildGitHash* = strutils.strip(staticExec("git rev-parse --short HEAD"))
VersionString* = fmt"Version {AppVersion} ({BuildGitHash})"
FullVersionString* = fmt"Gridmonger {VersionString} [{hostOS}/{hostCPU}]"
CompiledAt* = fmt"Compiled at {CompileDate} {CompileTime}"
DevelopedBy* = fmt"Developed by John Novak, 2020-{CompileYear}"
const
EnDash* = "\u2013"
TextVertAlignFactor* = 0.55
MaxLabelWidthInCells* = 15
MinWindowWidth* = 640
MinWindowHeight* = 520
type
Location* = object
levelId*: Natural
row*, col*: Natural
CardinalDir* = enum
dirN = "North"
dirE = "East"
dirS = "South"
dirW = "West"
Direction* = set[CardinalDir]
Orientation* = enum
Horiz = (0, "horizontal")
Vert = (1, "vertical")
const
North* = {dirN}
NorthEast* = {dirN, dirE}
East* = {dirE}
SouthEast* = {dirS, dirE}
South* = {dirS}
SouthWest* = {dirS, dirW}
West* = {dirW}
NorthWest* = {dirN, dirW}
func orientation*(dir: CardinalDir): Orientation =
case dir
of dirE, dirW: Horiz
of dirN, dirS: Vert
func opposite*(o: Orientation): Orientation =
case o
of Horiz: Vert
of Vert: Horiz
type
Map* = ref object
title*: string
game*: string
author*: string
creationTime*: string
notes*: string
levels*: OrderedTable[Natural, Level]
levelsDirty*: bool
coordOpts*: CoordinateOptions
links*: Links
sortedLevelIds*: seq[Natural]
sortedLevelNames*: seq[string]
Links* = object
srcToDest*: OrderedTable[Location, Location]
destToSrcs*: OrderedTable[Location, HashSet[Location]]
CoordinateOptions* = object
origin*: CoordinateOrigin
rowStyle*, columnStyle*: CoordinateStyle
rowStart*, columnStart*: int
CoordinateOrigin* = enum
coNorthWest = 0
coSouthWest = 1
CoordinateStyle* = enum
csNumber = 0
csLetter = 1
Level* = ref object
# Internal ID, never written to disk
id*: Natural
locationName*: string
levelName*: string
elevation*: int
notes*: string
overrideCoordOpts*: bool
coordOpts*: CoordinateOptions
# Note that Regions *can* contain region data even if regions are disabled
# (regionOpts.enabled = false). This is to preserve the region names and
# notes when regions are temporarily disabled. Also, we always write the
# region data into the map file, even if regions are disabled.
regionOpts*: RegionOptions
regions*: Regions
annotations*: Annotations
cellGrid*: CellGrid
dirty*: bool
RegionOptions* = object
enabled*: bool
colsPerRegion*: Natural
rowsPerRegion*: Natural
perRegionCoords*: bool
Regions* = object
regionsByCoords*: OrderedTable[RegionCoords, Region]
sortedRegionIds*: seq[Natural]
sortedRegionNames*: seq[string]
# The top-left region has region coordinate (0,0)
RegionCoords* = object
row*, col*: Natural
Region* = object
name*: string
notes*: string
CellGrid* = ref object
cols*: Natural
rows*: Natural
# Cells are stored in row-major order; (0,0) is the top-left cell
cells*: seq[Cell]
Cell* = object
floor*: Floor
floorOrientation*: Orientation
floorColor*: byte
wallN*, wallW*: Wall
trail*: bool
Floor* = enum
fEmpty = ( 0, "none")
fBlank = ( 1, "blank")
fDoor = (20, "open door")
fLockedDoor = (21, "locked door")
fArchway = (22, "archway")
fSecretDoorBlock = (23, "secret door (block)")
fSecretDoor = (24, "secret door")
fOneWayDoor1 = (25, "one-way door")
fOneWayDoor2 = (26, "one-way door")
fPressurePlate = (30, "pressure plate")
fHiddenPressurePlate = (31, "hidden pressure plate")
fClosedPit = (40, "closed pit")
fOpenPit = (41, "open pit")
fHiddenPit = (42, "hidden pit")
fCeilingPit = (43, "ceiling pit")
fStairsDown = (50, "stairs down")
fStairsUp = (51, "stairs up")
fEntranceDoor = (52, "entrance door")
fExitDoor = (53, "exit door")
fSpinner = (60, "spinner")
fTeleportSource = (70, "teleport")
fTeleportDestination = (71, "teleport destination")
fInvisibleBarrier = (80, "invisible barrier")
fBridge = (90, "bridge")
fColumn = (100, "column")
fStatue = (110, "statue")
Wall* = enum
wNone = ( 0, "none")
wWall = (10, "wall")
wIllusoryWall = (11, "illusory wall")
wInvisibleWall = (12, "invisible wall")
wDoor = (20, "open door")
wLockedDoor = (21, "locked door")
wArchway = (22, "archway")
wSecretDoor = (23, "secret door")
wOneWayDoorNE = (24, "one-way door")
wOneWayDoorSW = (25, "one-way door")
wLeverNE = (30, "lever")
wLeverSW = (31, "lever")
wNicheNE = (40, "niche")
wNicheSW = (41, "niche")
wStatueNE = (50, "statue")
wStatueSW = (51, "statue")
wKeyhole = (60, "keyhole")
wWritingNE = (70, "writing")
wWritingSW = (71, "writing")
Annotations* = ref object
cols*, rows*: Natural
annotations*: OrderedTable[Natural, Annotation]
dirty*: bool
AnnotationKind* = enum
akComment = 0
akIndexed = 1
akCustomId = 2
akIcon = 3
akLabel = 4
Annotation* = object
text*: string
case kind*: AnnotationKind
of akComment: discard
of akIndexed: index*, indexColor*: Natural
of akCustomId: customId*: string
of akIcon: icon*: Natural
of akLabel: labelColor*: Natural
func isLabel*(a: Annotation): bool =
a.kind == akLabel
func isNote*(a: Annotation): bool =
not a.isLabel
const
SpecialWalls* = @[
wDoor,
wLockedDoor,
wArchway,
wSecretDoor,
wOneWayDoorNE,
wIllusoryWall,
wInvisibleWall,
wLeverSW,
wNicheSW,
wStatueSW,
wKeyhole,
wWritingSW
]
type
# Selections always have the same dimensions as the level the selection was
# made in. The actual selection rectangle is then retrieved with the
# boundingBox() method.
#
# (0,0) is the top-left cell of the selection
Selection* = ref object
rows*, cols*: Natural
cells*: seq[bool]
SelectionRect* = object
startRow*: Natural
startCol*: Natural
rect*: Rect[Natural]
selected*: bool
SelectionBuffer* = object
level*: Level
selection*: Selection
type
LineWidth* = enum
lwThin = (0, "Thin")
lwNormal = (1, "Normal")
GridStyle* = enum
gsNone = (0, "None")
gsSolid = (1, "Solid")
gsLoose = (2, "Loose")
gsCross = (3, "Cross")
OutlineStyle* = enum
osNone = (0, "None")
osCell = (1, "Cell")
osSquareEdges = (2, "Square Edges")
osRoundedEdges = (3, "Rounded Edges")
osRoundedEdgesFilled = (4, "Filled Rounded Edges")
OutlineFillStyle* = enum
ofsSolid = (0, "Solid")
ofsHatched = (1, "Hatched")
NoteBackgroundShape* = enum
nbsCircle = (0, "Circle")
nbsRectangle = (1, "Rectangle")
const
LinkPitSources* = {fClosedPit, fOpenPit, fHiddenPit}
LinkPitDestinations* = {fCeilingPit}
LinkTeleports* = {fTeleportSource, fTeleportDestination}
LinkStairs* = {fStairsDown, fStairsUp}
LinkDoors* = {fEntranceDoor, fExitDoor}
LinkSources* = LinkPitSources + LinkTeleports + LinkStairs + LinkDoors
func linkFloorToString*(f: Floor): string =
if f in LinkPitSources: return "pit"
elif f in LinkPitDestinations: return "pit"
elif f in LinkStairs: return "stairs"
elif f in LinkDoors: return "door"
elif f in LinkTeleports: return "teleport"
func hash*(rc: RegionCoords): Hash =
var h: Hash = 0
h = h !& hash(rc.row)
h = h !& hash(rc.col)
!$h
func hash*(l: Location): Hash =
var h: Hash = 0
h = h !& hash(l.levelId)
h = h !& hash(l.row)
h = h !& hash(l.col)
!$h
func `<`*(a, b: Location): bool =
if a.levelId < b.levelId: true
elif a.levelId > b.levelId: false
elif a.row < b.row: true
elif a.row > b.row: false
elif a.col < b.col: true
else: false
type
WindowTheme* = ref object
borderColor*: Color
backgroundColor*: Color
backgroundImage*: string
titleBackgroundColor*: Color
titleBackgroundInactiveColor*: Color
titleColor*: Color
titleInactiveColor*: Color
buttonColor*: Color
buttonHoverColor*: Color
buttonDownColor*: Color
buttonInactiveColor*: Color
modifiedFlagColor*: Color
modifiedFlagInactiveColor*: Color
StatusBarTheme* = ref object
backgroundColor*: Color
textColor*: Color
warningTextColor*: Color
errorTextColor*: Color
coordinatesColor*: Color
commandBackgroundColor*: Color
commandTextColor*: Color
NotesPaneTheme* = ref object
textColor*: Color
indexColor*: Color
indexBackgroundColor*: array[4, Color]
ToolbarPaneTheme* = ref object
buttonNormalColor*: Color
buttonHoverColor*: Color
LevelTheme* = ref object
lineWidth*: LineWidth
backgroundColor*: Color
cursorColor*: Color
cursorGuidesColor*: Color
linkMarkerColor*: Color
selectionColor*: Color
trailNormalColor*: Color
trailCursorColor*: Color
pastePreviewColor*: Color
foregroundNormalNormalColor*: Color
foregroundNormalCursorColor*: Color
foregroundLightNormalColor*: Color
foregroundLightCursorColor*: Color
coordinatesNormalColor*: Color
coordinatesHighlightColor*: Color
regionBorderNormalColor*: Color
regionBorderEmptyColor*: Color
backgroundHatchEnabled*: bool
backgroundHatchColor*: Color
backgroundHatchWidth*: float
backgroundHatchSpacingFactor*: float
gridBackgroundStyle*: GridStyle
gridBackgroundGridColor*: Color
gridFloorStyle*: GridStyle
gridFloorGridColor*: Color
outlineStyle*: OutlineStyle
outlineFillStyle*: OutlineFillStyle
outlineColor*: Color
outlineWidthFactor*: float
outlineOverscan*: bool
shadowInnerColor*: Color
shadowInnerWidthFactor*: float
shadowOuterColor*: Color
shadowOuterWidthFactor*: float
floorTransparent*: bool
floorBackgroundColor*: array[10, Color]
noteMarkerNormalColor*: Color
noteMarkerCursorColor*: Color
noteCommentColor*: Color
noteBackgroundShape*: NoteBackgroundShape
noteIndexBackgroundColor*: array[4, Color]
noteIndexColor*: Color
noteTooltipBackgroundColor*: Color
noteTooltipTextColor*: Color
noteTooltipCornerRadius*: float
noteTooltipShadowStyle*: ShadowStyle
labelTextColor*: array[4, Color]
# vim: et:ts=2:sw=2:fdm=marker