desck 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Rect.elm ADDED
@@ -0,0 +1,292 @@
1
+ module Rect exposing (..)
2
+
3
+ import Vec exposing (Vec2)
4
+
5
+
6
+ type alias Rect =
7
+ { pos : Vec2
8
+ , size : Vec2
9
+ }
10
+
11
+
12
+ type RectCoordinate
13
+ = PosX
14
+ | PosY
15
+ | SizeX
16
+ | SizeY
17
+
18
+
19
+ rect2 : Vec2 -> Vec2 -> Rect
20
+ rect2 pos size =
21
+ { pos = pos
22
+ , size = size
23
+ }
24
+
25
+
26
+ rect4 : Float -> Float -> Float -> Float -> Rect
27
+ rect4 x y w h =
28
+ rect2 (Vec.vec2 x y) (Vec.vec2 w h)
29
+
30
+
31
+ rightCorner : Rect -> Vec2
32
+ rightCorner rect =
33
+ Vec.add rect.pos rect.size
34
+
35
+
36
+ includeRect : Rect -> Rect -> Rect
37
+ includeRect r rect =
38
+ let
39
+ pos =
40
+ Vec.vec2 (min rect.pos.x r.pos.x) (min rect.pos.y r.pos.y)
41
+
42
+ corner =
43
+ Vec.max (rightCorner rect) (rightCorner r)
44
+ in
45
+ { pos = pos
46
+ , size = Vec.sub corner pos
47
+ }
48
+
49
+
50
+ includeVec : Rect -> Vec2 -> Rect
51
+ includeVec r v =
52
+ includeRect r (rect2 v Vec.zero)
53
+
54
+
55
+ toPoints : Rect -> List Vec2
56
+ toPoints r =
57
+ [ r.pos
58
+ , Vec.vec2 (r.pos.x + r.size.x) r.pos.y
59
+ , Vec.vec2 (r.pos.x + r.size.x) (r.pos.y + r.size.y)
60
+ , Vec.vec2 r.pos.x (r.pos.y + r.size.y)
61
+ ]
62
+
63
+
64
+ fromPoints : List Vec2 -> Rect
65
+ fromPoints points =
66
+ let
67
+ r =
68
+ rect2 (Vec.average points) Vec.zero
69
+ in
70
+ List.foldl (\p a -> includeVec a p) r points
71
+
72
+
73
+ enlarge : Float -> Rect -> Rect
74
+ enlarge f r =
75
+ let
76
+ v =
77
+ Vec.scale f Vec.one
78
+
79
+ v2 =
80
+ Vec.scale (f * 0.5) Vec.one
81
+ in
82
+ { pos = Vec.sub r.pos v2
83
+ , size = Vec.add r.size v
84
+ }
85
+
86
+
87
+ shrink : Float -> Rect -> Rect
88
+ shrink f r =
89
+ let
90
+ v =
91
+ Vec.scale f Vec.one
92
+
93
+ v2 =
94
+ Vec.scale (f * 0.5) Vec.one
95
+ in
96
+ { pos = Vec.add r.pos v2
97
+ , size = Vec.sub r.size v
98
+ }
99
+
100
+
101
+ changeSize : Vec2 -> Rect -> Rect
102
+ changeSize v r =
103
+ let
104
+ v2 =
105
+ Vec.scale 0.5 v
106
+ in
107
+ rect2 (Vec.add r.pos v2) (Vec.add r.size (Vec.scale -1.0 v))
108
+
109
+
110
+ scale : Float -> Rect -> Rect
111
+ scale f r =
112
+ let
113
+ size =
114
+ Vec.scale f r.size
115
+
116
+ change =
117
+ Vec.sub r.size size
118
+ in
119
+ changeSize change r
120
+
121
+
122
+ normalizeRect : Vec2 -> Vec2 -> Rect
123
+ normalizeRect a b =
124
+ let
125
+ pos =
126
+ Vec.min a b
127
+
128
+ corner =
129
+ Vec.max a b
130
+ in
131
+ rect2 pos (Vec.sub corner pos)
132
+
133
+
134
+ hasPoint : Vec2 -> Rect -> Bool
135
+ hasPoint p r =
136
+ r.pos.x <= p.x && r.pos.y <= p.y && r.pos.x + r.size.x >= p.x && r.pos.y + r.size.y >= p.y
137
+
138
+
139
+ hasRect : Rect -> Rect -> Bool
140
+ hasRect a b =
141
+ hasPoint b.pos a
142
+ && hasPoint (Vec.add b.pos b.size) a
143
+
144
+
145
+ overlaps : Rect -> Rect -> Bool
146
+ overlaps a b =
147
+ rectanglesIntersect ( a.pos.x, a.pos.y )
148
+ ( a.pos.x + a.size.x, a.pos.y + a.size.y )
149
+ ( b.pos.x, b.pos.y )
150
+ ( b.pos.x + b.size.x, b.pos.y + b.size.y )
151
+
152
+
153
+ rectangleContains : Vec2 -> Vec2 -> Vec2 -> Vec2 -> Bool
154
+ rectangleContains a1 b1 a2 b2 =
155
+ let
156
+ r =
157
+ normalizeRect a1 b1
158
+
159
+ c1 =
160
+ r.pos
161
+
162
+ d1 =
163
+ rightCorner r
164
+ in
165
+ c1.x < a2.x && d1.x > b2.x && c1.y < a2.y && d1.y > b2.y
166
+
167
+
168
+ rectanglesIntersect : ( Float, Float ) -> ( Float, Float ) -> ( Float, Float ) -> ( Float, Float ) -> Bool
169
+ rectanglesIntersect ( x1a, y1a ) ( x1b, y1b ) ( x2a, y2a ) ( x2b, y2b ) =
170
+ let
171
+ x1_min =
172
+ min x1a x1b
173
+
174
+ y1_min =
175
+ min y1a y1b
176
+
177
+ x1_max =
178
+ max x1a x1b
179
+
180
+ y1_max =
181
+ max y1a y1b
182
+
183
+ x2_min =
184
+ min x2a x2b
185
+
186
+ y2_min =
187
+ min y2a y2b
188
+
189
+ x2_max =
190
+ max x2a x2b
191
+
192
+ y2_max =
193
+ max y2a y2b
194
+ in
195
+ not (x1_max < x2_min || x2_max < x1_min || y1_max < y2_min || y2_max < y1_min)
196
+
197
+
198
+ modifyRect : Rect -> Rect -> RectCoordinate -> Float -> Rect
199
+ modifyRect rect factor rc v =
200
+ let
201
+ { pos, size } =
202
+ rect
203
+ in
204
+ case rc of
205
+ PosX ->
206
+ { rect | pos = Vec.setX (v * factor.pos.x) pos }
207
+
208
+ PosY ->
209
+ { rect | pos = Vec.setY (v * factor.pos.y) pos }
210
+
211
+ SizeX ->
212
+ { rect | size = Vec.setX (v * factor.size.x) size }
213
+
214
+ SizeY ->
215
+ { rect | size = Vec.setY (v * factor.size.y) size }
216
+
217
+
218
+ minSized : Vec2 -> Rect -> Rect
219
+ minSized minSize rect =
220
+ { rect | size = Vec.vec2 (max minSize.x rect.size.x) (max minSize.y rect.size.y) }
221
+
222
+
223
+ center : Rect -> Vec2
224
+ center r =
225
+ Vec.half r.size
226
+ |> Vec.add r.pos
227
+
228
+
229
+ rectString : Rect -> String
230
+ rectString r =
231
+ String.fromFloat r.pos.x
232
+ ++ " "
233
+ ++ String.fromFloat r.pos.y
234
+ ++ " "
235
+ ++ String.fromFloat r.size.x
236
+ ++ " "
237
+ ++ String.fromFloat r.size.y
238
+
239
+
240
+ showRect : Rect -> String
241
+ showRect r =
242
+ Vec.show r.pos ++ " : " ++ Vec.show r.size
243
+
244
+
245
+ area : Rect -> Float
246
+ area r =
247
+ r.size.x * r.size.y
248
+
249
+
250
+ fitToCenter : Vec2 -> Vec2 -> Rect
251
+ fitToCenter viewport window =
252
+ let
253
+ imgWidth =
254
+ viewport.x
255
+
256
+ imgHeight =
257
+ viewport.y
258
+
259
+ winWidth =
260
+ window.x
261
+
262
+ winHeight =
263
+ window.y
264
+
265
+ ratio =
266
+ min (winWidth / imgWidth) (winHeight / imgHeight)
267
+
268
+ w =
269
+ imgWidth * ratio
270
+
271
+ h =
272
+ imgHeight * ratio
273
+ in
274
+ { pos = Vec2 ((winWidth - w) / 2.0) ((winHeight - h) / 2.0), size = Vec2 w h }
275
+
276
+
277
+ clamp : Rect -> Vec2 -> Vec2
278
+ clamp r p =
279
+ Vec.vec2 (Basics.clamp r.pos.x (r.pos.x + r.size.x) p.x) (Basics.clamp r.pos.y (r.pos.y + r.size.y) p.y)
280
+
281
+
282
+ type alias Rotation =
283
+ { angle : Float
284
+ , pivot : Vec2
285
+ }
286
+
287
+
288
+ angled : Float -> Rotation
289
+ angled a =
290
+ { pivot = Vec.half Vec.one
291
+ , angle = a
292
+ }
@@ -0,0 +1,422 @@
1
+ module SaveFile exposing (..)
2
+
3
+ import Card exposing (Card)
4
+ import Deck exposing (encodeModel, modelDecoder)
5
+ import Json.Decode as D exposing (Decoder)
6
+ import Json.Decode.Pipeline exposing (optional, required)
7
+ import Json.Encode exposing (Value, bool, float, int, list, null, object, string)
8
+ import Palette exposing (Color(..), Palette, colorAsString, colorFromString)
9
+ import Project exposing (Project)
10
+ import Rect exposing (Rect, Rotation)
11
+ import Theme
12
+ import Util exposing (..)
13
+ import Vec exposing (Vec2)
14
+ import Zone exposing (Anchor, Arrow, Border, Grid, Head, Stamp, Text, Zone, headFromString, headString)
15
+
16
+
17
+
18
+ -- TODO implement version field
19
+
20
+
21
+ type alias Settings =
22
+ { embedSymbols : Bool
23
+ , stripData : Bool
24
+ , mapColors : Bool
25
+ , mapFont : Bool
26
+ , primaryFont : Maybe String
27
+ , secondaryFont : Maybe String
28
+ , heightPixels : Int
29
+ }
30
+
31
+
32
+ default_settings : Settings
33
+ default_settings =
34
+ { embedSymbols = True
35
+ , stripData = False
36
+ , mapColors = True
37
+ , mapFont = True
38
+ , primaryFont = Nothing
39
+ , secondaryFont = Nothing
40
+ , heightPixels = 128
41
+ }
42
+
43
+
44
+ type alias SaveFile =
45
+ { name : String
46
+ , project : Project
47
+ , palette : Palette
48
+ , settings : Settings
49
+ }
50
+
51
+
52
+
53
+ -- hsl : Float -> Float -> Float -> C.Color
54
+ -- hsl h s l =
55
+ -- C.fromHsla { hue = h, saturation = s, lightness = l, alpha = 1.0 }
56
+ -- colorDecoder : Decoder Color
57
+ -- colorDecoder =
58
+ -- D.map3 hsl
59
+ -- (D.field "h" D.float)
60
+ -- (D.field "s" D.float)
61
+ -- (D.field "l" D.float)
62
+
63
+
64
+ anchorDecoder : Decoder Anchor
65
+ anchorDecoder =
66
+ enumDecoder
67
+ (\s -> Just <| Zone.anchorFromString s)
68
+
69
+
70
+ paletteDecoder : Decoder Palette
71
+ paletteDecoder =
72
+ D.succeed Palette
73
+ |> required "black" D.string
74
+ |> required "white" D.string
75
+ |> required "red" D.string
76
+ |> required "orange" D.string
77
+ |> required "yellow" D.string
78
+ |> required "green" D.string
79
+ |> required "cyan" D.string
80
+ |> required "blue" D.string
81
+ |> required "violet" D.string
82
+ |> required "pink" D.string
83
+ |> required "darkGray" D.string
84
+ |> required "midGray" D.string
85
+ |> required "lightGray" D.string
86
+
87
+
88
+
89
+ -- encodeColor : C.Color -> Value
90
+ -- encodeColor c =
91
+ -- let
92
+ -- { hue, saturation, lightness } =
93
+ -- C.toHsla c
94
+ -- in
95
+ -- object
96
+ -- [ ( "h", float hue )
97
+ -- , ( "s", float saturation )
98
+ -- , ( "l", float lightness )
99
+ -- ]
100
+
101
+
102
+ encodePalette : Palette -> Value
103
+ encodePalette p =
104
+ object
105
+ [ ( "black", string p.black )
106
+ , ( "white", string p.white )
107
+ , ( "red", string p.red )
108
+ , ( "orange", string p.orange )
109
+ , ( "yellow", string p.yellow )
110
+ , ( "green", string p.green )
111
+ , ( "cyan", string p.cyan )
112
+ , ( "blue", string p.blue )
113
+ , ( "violet", string p.violet )
114
+ , ( "pink", string p.pink )
115
+ , ( "darkGray", string p.darkGray )
116
+ , ( "midGray", string p.midGray )
117
+ , ( "lightGray", string p.lightGray )
118
+ ]
119
+
120
+
121
+ color : Color -> Value
122
+ color c =
123
+ string <| colorAsString c
124
+
125
+
126
+ encodeArrow : Arrow -> Value
127
+ encodeArrow a =
128
+ object
129
+ [ ( "from", string a.from )
130
+ , ( "to", string a.to )
131
+ , ( "id", string a.id )
132
+ , ( "fill", color a.fill )
133
+ , ( "width", float a.width )
134
+ , ( "head", string <| headString a.head )
135
+ ]
136
+
137
+
138
+ fromResult : Result a b -> Decoder b
139
+ fromResult result =
140
+ case result of
141
+ Ok a ->
142
+ D.succeed a
143
+
144
+ Err _ ->
145
+ D.fail "error decoding"
146
+
147
+
148
+ vec2Decoder : Decoder Vec2
149
+ vec2Decoder =
150
+ D.map2 Vec2
151
+ (D.field "x" D.float)
152
+ (D.field "y" D.float)
153
+
154
+
155
+ rectDecoder : Decoder Rect
156
+ rectDecoder =
157
+ D.map2 Rect
158
+ (D.field "pos" vec2Decoder)
159
+ (D.field "size" vec2Decoder)
160
+
161
+
162
+ cardDecoder : Decoder Card
163
+ cardDecoder =
164
+ D.map7 Card
165
+ (D.field "model" modelDecoder)
166
+ (D.field "rect" rectDecoder)
167
+ (D.field "rot" rotDecoder)
168
+ (D.field "front" D.bool)
169
+ (D.field "highlight" D.bool)
170
+ (D.field "id" D.string)
171
+ (D.field "z" D.int)
172
+
173
+
174
+ paletteColorDecoder : Decoder Color
175
+ paletteColorDecoder =
176
+ D.string
177
+ |> D.andThen
178
+ (\str ->
179
+ D.succeed <| colorFromString str
180
+ )
181
+
182
+
183
+ borderDecode : Decoder Border
184
+ borderDecode =
185
+ D.map3 Border
186
+ (D.field "color" paletteColorDecoder)
187
+ (D.field "width" D.int)
188
+ (D.field "dash" D.int)
189
+
190
+
191
+ textDecoder : Decoder Text
192
+ textDecoder =
193
+ D.map5 Text
194
+ (D.field "label" D.string)
195
+ (D.field "color" paletteColorDecoder)
196
+ (D.field "size" D.int)
197
+ (D.field "primary" D.bool)
198
+ (D.field "anchor" anchorDecoder)
199
+
200
+
201
+ gridDecoder : Decoder Grid
202
+ gridDecoder =
203
+ D.map2 Grid
204
+ (D.field "rows" D.int)
205
+ (D.field "columns" D.int)
206
+
207
+
208
+ rotDecoder : Decoder Rotation
209
+ rotDecoder =
210
+ D.map2 Rotation
211
+ (D.field "angle" D.float)
212
+ (D.field "pivot" vec2Decoder)
213
+
214
+
215
+ zoneDecoder : Decoder Zone
216
+ zoneDecoder =
217
+ D.map7 Zone
218
+ (D.field "rect" rectDecoder)
219
+ (D.field "rot" rotDecoder)
220
+ (D.field "id" D.string)
221
+ (D.field "fill" paletteColorDecoder)
222
+ (D.field "border" borderDecode)
223
+ (D.field "text" textDecoder)
224
+ (D.field "grid" gridDecoder)
225
+
226
+
227
+ headDecoder : Decoder Head
228
+ headDecoder =
229
+ enumDecoder
230
+ (\s -> Just <| headFromString s)
231
+
232
+
233
+ arrowDecoder : Decoder Arrow
234
+ arrowDecoder =
235
+ D.map6 Arrow
236
+ (D.field "from" D.string)
237
+ (D.field "to" D.string)
238
+ (D.field "id" D.string)
239
+ (D.field "fill" paletteColorDecoder)
240
+ (D.field "width" D.float)
241
+ (D.field "head" headDecoder)
242
+
243
+
244
+ settingsDecoder : Decoder Settings
245
+ settingsDecoder =
246
+ D.succeed Settings
247
+ |> optional "embedSymbols" D.bool False
248
+ |> optional "stripData" D.bool False
249
+ |> optional "mapColors" D.bool True
250
+ |> optional "mapFont" D.bool True
251
+ |> optional "primaryFont" (D.nullable D.string) Nothing
252
+ |> optional "secondaryFont" (D.nullable D.string) Nothing
253
+ |> optional "heightPixels" D.int 128
254
+
255
+
256
+ stampDecoder : Decoder Stamp
257
+ stampDecoder =
258
+ D.map5 Stamp
259
+ (D.field "pos" vec2Decoder)
260
+ (D.field "id" D.string)
261
+ (D.field "text" textDecoder)
262
+ (D.field "fill" paletteColorDecoder)
263
+ (D.field "radius" D.float)
264
+
265
+
266
+ projectDecoder : Decoder Project
267
+ projectDecoder =
268
+ D.succeed Project
269
+ |> required "description" D.string
270
+ |> required "background" paletteColorDecoder
271
+ |> required "viewport" rectDecoder
272
+ |> required "cards" (D.list cardDecoder)
273
+ |> required "zones" (D.list zoneDecoder)
274
+ |> required "arrows" (D.list arrowDecoder)
275
+ |> required "stamps" (D.list stampDecoder)
276
+
277
+
278
+ saveFileDecoder : Decoder SaveFile
279
+ saveFileDecoder =
280
+ D.succeed SaveFile
281
+ |> required "name" D.string
282
+ |> required "project" projectDecoder
283
+ |> optional "palette" paletteDecoder Theme.default
284
+ |> optional "settings" settingsDecoder default_settings
285
+
286
+
287
+ decodeSaveFile : String -> Result D.Error SaveFile
288
+ decodeSaveFile s =
289
+ D.decodeString saveFileDecoder s
290
+
291
+
292
+ encodeVec2 : Vec2 -> Value
293
+ encodeVec2 p =
294
+ object
295
+ [ ( "x", float <| p.x )
296
+ , ( "y", float <| p.y )
297
+ ]
298
+
299
+
300
+ encodeRect : Rect -> Value
301
+ encodeRect r =
302
+ object
303
+ [ ( "pos", encodeVec2 r.pos )
304
+ , ( "size", encodeVec2 r.size )
305
+ ]
306
+
307
+
308
+ encodeRot : Rotation -> Value
309
+ encodeRot r =
310
+ object
311
+ [ ( "angle", float r.angle )
312
+ , ( "pivot", encodeVec2 r.pivot )
313
+ ]
314
+
315
+
316
+ encodeCard : Card -> Value
317
+ encodeCard c =
318
+ object
319
+ [ ( "model", encodeModel c.model )
320
+ , ( "rect", encodeRect c.rect )
321
+ , ( "rot", encodeRot c.rot )
322
+ , ( "front", bool c.front )
323
+ , ( "highlight", bool c.highlight )
324
+ , ( "id", string c.id )
325
+ , ( "z", int c.z )
326
+ ]
327
+
328
+
329
+ encodeBorder : Border -> Value
330
+ encodeBorder b =
331
+ object
332
+ [ ( "color", color b.color )
333
+ , ( "width", int b.width )
334
+ , ( "dash", int b.dash )
335
+ ]
336
+
337
+
338
+ encodeGrid : Grid -> Value
339
+ encodeGrid g =
340
+ object
341
+ [ ( "rows", int g.rows )
342
+ , ( "columns", int g.columns )
343
+ ]
344
+
345
+
346
+ encodeAnchor : Anchor -> Value
347
+ encodeAnchor a =
348
+ string <| Zone.anchorString a
349
+
350
+
351
+ encodeText : Text -> Value
352
+ encodeText t =
353
+ object
354
+ [ ( "label", string t.label )
355
+ , ( "color", color t.color )
356
+ , ( "size", int t.size )
357
+ , ( "primary", bool t.primary )
358
+ , ( "anchor", encodeAnchor t.anchor )
359
+ ]
360
+
361
+
362
+ encodeZone : Zone -> Value
363
+ encodeZone z =
364
+ object
365
+ [ ( "id", string z.id )
366
+ , ( "rect", encodeRect z.rect )
367
+ , ( "rot", encodeRot z.rot )
368
+ , ( "fill", color z.fill )
369
+ , ( "border", encodeBorder z.border )
370
+ , ( "text", encodeText z.text )
371
+ , ( "grid", encodeGrid z.grid )
372
+ ]
373
+
374
+
375
+ encodeStamp : Stamp -> Value
376
+ encodeStamp s =
377
+ object
378
+ [ ( "pos", encodeVec2 s.pos )
379
+ , ( "id", string s.id )
380
+ , ( "text", encodeText s.text )
381
+ , ( "fill", color s.fill )
382
+ , ( "radius", float s.radius )
383
+ ]
384
+
385
+
386
+ encodeSettings : Settings -> Value
387
+ encodeSettings settings =
388
+ object
389
+ [ ( "embedSymbols", bool settings.embedSymbols )
390
+ , ( "stripData", bool settings.stripData )
391
+ , ( "mapColors", bool settings.mapColors )
392
+ , ( "mapFont", bool settings.mapFont )
393
+ , ( "primaryFont"
394
+ , Maybe.map string settings.primaryFont |> Maybe.withDefault null
395
+ )
396
+ , ( "secondaryFont"
397
+ , Maybe.map string settings.secondaryFont |> Maybe.withDefault null
398
+ )
399
+ ]
400
+
401
+
402
+ encodeProject : Project -> Value
403
+ encodeProject project =
404
+ object
405
+ [ ( "description", string project.description )
406
+ , ( "background", color project.background )
407
+ , ( "viewport", encodeRect project.viewport )
408
+ , ( "cards", list encodeCard project.cards )
409
+ , ( "zones", list encodeZone project.zones )
410
+ , ( "arrows", list encodeArrow project.arrows )
411
+ , ( "stamps", list encodeStamp project.stamps )
412
+ ]
413
+
414
+
415
+ encodeSaveFile : SaveFile -> Value
416
+ encodeSaveFile pf =
417
+ object
418
+ [ ( "name", string pf.name )
419
+ , ( "project", encodeProject pf.project )
420
+ , ( "palette", encodePalette pf.palette )
421
+ , ( "settings", encodeSettings pf.settings )
422
+ ]