Skip to content

Commit 51d59ec

Browse files
authored
feat!: turning List<Property> into CustomProperties (#55)
1 parent 3c75b03 commit 51d59ec

File tree

15 files changed

+283
-47
lines changed

15 files changed

+283
-47
lines changed

packages/tiled/lib/src/common/property.dart

Lines changed: 193 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,218 @@ part of tiled;
1212
/// (default string is “”, default number is 0, default boolean is “false”,
1313
/// default color is #00000000, default file is “.” (the current file’s
1414
/// parent directory))
15-
class Property {
15+
class Property<T> {
1616
String name;
1717
PropertyType type;
18-
// TODO(luan): support other property types
19-
String value;
18+
T value;
2019

2120
Property({
2221
required this.name,
2322
required this.type,
2423
required this.value,
2524
});
2625

27-
Property.parse(Parser parser)
28-
: this(
29-
name: parser.getString('name'),
30-
type: parser.getPropertyType('type', defaults: PropertyType.string),
31-
value: parser.getString('value'),
26+
static Property<Object> parse(Parser parser) {
27+
final name = parser.getString('name');
28+
final type = parser.getPropertyType('type', defaults: PropertyType.string);
29+
30+
switch (type) {
31+
case PropertyType.object:
32+
return ObjectProperty(
33+
name: name,
34+
value: parser.getInt('value', defaults: 0),
35+
);
36+
37+
case PropertyType.color:
38+
return ColorProperty(
39+
name: name,
40+
value: parser.getColor('value', defaults: const Color(0x00000000)),
41+
hexValue: parser.getString('value', defaults: '#00000000'),
42+
);
43+
44+
case PropertyType.bool:
45+
return BoolProperty(
46+
name: name,
47+
value: parser.getBool('value', defaults: false),
48+
);
49+
50+
case PropertyType.float:
51+
return FloatProperty(
52+
name: name,
53+
value: parser.getDouble('value', defaults: 0),
54+
);
55+
56+
case PropertyType.int:
57+
return IntProperty(
58+
name: name,
59+
value: parser.getInt('value', defaults: 0),
60+
);
61+
62+
case PropertyType.file:
63+
return FileProperty(
64+
name: name,
65+
value: parser.getString('value', defaults: '.'),
66+
);
67+
68+
case PropertyType.string:
69+
final value = parser.formatSpecificParsing((json) {
70+
return json.getString('value', defaults: '');
71+
}, (xml) {
72+
final attrString = parser.getStringOrNull('value');
73+
if (attrString != null) {
74+
return attrString;
75+
} else {
76+
// In tmx files, multi-line text property values can be stored
77+
// inside the <property> node itself instead of in the 'value'
78+
// attribute
79+
return xml.element.innerText;
80+
}
81+
});
82+
83+
return StringProperty(
84+
name: name,
85+
value: value,
3286
);
87+
}
88+
}
89+
}
90+
91+
/// A wrapper for a Tiled property set
92+
///
93+
/// Accessing an int value
94+
/// ```dart
95+
/// properties.get<int>('foo') == 3
96+
/// ```
97+
///
98+
/// Accessing an int property:
99+
/// ```dart
100+
/// properties.getProperty<IntProperty>('foo') ==
101+
/// IntProperty(name: 'foo', value: 3);
102+
/// ```
103+
///
104+
/// You can also use an accessor:
105+
/// ```dart
106+
/// properties['foo'] == IntProperty(name: 'foo', value: 3);
107+
/// ```
108+
class CustomProperties extends Iterable<Property<Object>> {
109+
static const empty = CustomProperties({});
110+
111+
/// The properties, indexed by name
112+
final Map<String, Property<Object>> byName;
113+
114+
const CustomProperties(this.byName);
115+
116+
/// Get a property value by its name.
117+
///
118+
/// [T] must be the type of the value, which depends on the property type.
119+
/// The following Tiled properties map to the follow Dart types:
120+
/// - int property -> int
121+
/// - float property -> double
122+
/// - boolean property -> bool
123+
/// - string property -> string
124+
/// - color property -> ui.Color
125+
/// - file property -> string (path)
126+
/// - object property -> int (ID)
127+
T? getValue<T>(String name) {
128+
return getProperty(name)?.value as T?;
129+
}
130+
131+
/// Get a typed property by its name
132+
T? getProperty<T extends Property<Object>>(String name) {
133+
return byName[name] as T?;
134+
}
135+
136+
/// Get a property by its name
137+
Property<Object>? operator [](String name) {
138+
return byName[name];
139+
}
140+
141+
/// Returns whether or not a property with [name] exists.
142+
bool has(String name) {
143+
return byName.containsKey(name);
144+
}
145+
146+
@override
147+
Iterator<Property<Object>> get iterator => byName.values.iterator;
148+
}
149+
150+
/// [value] is the ID of the object
151+
class ObjectProperty extends Property<int> {
152+
ObjectProperty({
153+
required super.name,
154+
required super.value,
155+
}) : super(type: PropertyType.object);
156+
}
157+
158+
/// [value] is the color
159+
class ColorProperty extends Property<Color> {
160+
final String hexValue;
161+
162+
ColorProperty({
163+
required super.name,
164+
required super.value,
165+
required this.hexValue,
166+
}) : super(type: PropertyType.color);
167+
}
168+
169+
/// [value] is the string text
170+
class StringProperty extends Property<String> {
171+
StringProperty({
172+
required super.name,
173+
required super.value,
174+
}) : super(type: PropertyType.string);
175+
}
176+
177+
/// [value] is the path to the file
178+
class FileProperty extends Property<String> {
179+
FileProperty({
180+
required super.name,
181+
required super.value,
182+
}) : super(type: PropertyType.file);
183+
}
184+
185+
/// [value] is the integer number
186+
class IntProperty extends Property<int> {
187+
IntProperty({
188+
required super.name,
189+
required super.value,
190+
}) : super(type: PropertyType.int);
191+
}
192+
193+
/// [value] is the double-percision floating-point number
194+
class FloatProperty extends Property<double> {
195+
FloatProperty({
196+
required super.name,
197+
required super.value,
198+
}) : super(type: PropertyType.float);
199+
}
200+
201+
/// [value] is the boolean
202+
class BoolProperty extends Property<bool> {
203+
BoolProperty({
204+
required super.name,
205+
required super.value,
206+
}) : super(type: PropertyType.bool);
33207
}
34208

35209
extension PropertiesParser on Parser {
36-
List<Property> getProperties() {
37-
return formatSpecificParsing(
210+
CustomProperties getProperties() {
211+
final properties = formatSpecificParsing(
38212
(json) => json.getChildrenAs('properties', Property.parse),
39213
(xml) =>
40214
xml
41215
.getSingleChildOrNull('properties')
42216
?.getChildrenAs('property', Property.parse) ??
43217
[],
44218
);
219+
220+
// NOTE: two properties should never have the same name, if they do
221+
// one will simply override the other
222+
final byName =
223+
properties.groupFoldBy((prop) => prop.name, (previous, element) {
224+
return element;
225+
});
226+
227+
return CustomProperties(byName);
45228
}
46229
}

packages/tiled/lib/src/layer.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ abstract class Layer {
9090
bool visible;
9191

9292
/// List of [Property].
93-
List<Property> properties;
93+
CustomProperties properties;
9494

9595
Layer({
9696
this.id,
@@ -109,7 +109,7 @@ abstract class Layer {
109109
this.tintColor,
110110
this.opacity = 1,
111111
this.visible = true,
112-
this.properties = const [],
112+
this.properties = CustomProperties.empty,
113113
});
114114

115115
static Layer parse(Parser parser) {

packages/tiled/lib/src/objects/tiled_object.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class TiledObject {
6565

6666
List<Point> polygon;
6767
List<Point> polyline;
68-
List<Property> properties;
68+
CustomProperties properties;
6969

7070
/// The "Class" property, a.k.a "Type" prior to Tiled 1.9.
7171
/// Will be same as [type].
@@ -89,7 +89,7 @@ class TiledObject {
8989
this.visible = true,
9090
this.polygon = const [],
9191
this.polyline = const [],
92-
this.properties = const [],
92+
this.properties = CustomProperties.empty,
9393
});
9494

9595
bool get isPolyline => polyline.isNotEmpty;

packages/tiled/lib/src/tiled_map.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class TiledMap {
8989
RenderOrder renderOrder;
9090

9191
List<EditorSetting> editorSettings;
92-
List<Property> properties;
92+
CustomProperties properties;
9393

9494
// only for hexagonal maps:
9595
int? hexSideLength;
@@ -118,7 +118,7 @@ class TiledMap {
118118
this.staggerAxis,
119119
this.staggerIndex,
120120
this.editorSettings = const [],
121-
this.properties = const [],
121+
this.properties = CustomProperties.empty,
122122
});
123123

124124
/// Takes a string [contents] and converts it to a [TiledMap] with the help of

packages/tiled/lib/src/tileset/terrain.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ part of tiled;
1212
class Terrain {
1313
String name;
1414
int tile;
15-
List<Property> properties;
15+
CustomProperties properties;
1616

1717
Terrain({
1818
required this.name,
1919
required this.tile,
20-
this.properties = const [],
20+
this.properties = CustomProperties.empty,
2121
});
2222

2323
Terrain.parse(Parser parser)

packages/tiled/lib/src/tileset/tile.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Tile {
2929
TiledImage? image;
3030
Layer? objectGroup;
3131
List<Frame> animation;
32-
List<Property> properties;
32+
CustomProperties properties;
3333

3434
Tile({
3535
required this.localId,
@@ -39,7 +39,7 @@ class Tile {
3939
this.image,
4040
this.objectGroup,
4141
this.animation = const [],
42-
this.properties = const [],
42+
this.properties = CustomProperties.empty,
4343
});
4444

4545
bool get isEmpty => localId == -1;

packages/tiled/lib/src/tileset/tileset.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class Tileset {
6060
TiledImage? image;
6161
TileOffset? tileOffset;
6262
Grid? grid;
63-
List<Property> properties = [];
63+
CustomProperties properties;
6464
List<Terrain> terrains = [];
6565
List<WangSet> wangSets = [];
6666

@@ -85,7 +85,7 @@ class Tileset {
8585
this.image,
8686
this.tileOffset,
8787
this.grid,
88-
this.properties = const [],
88+
this.properties = CustomProperties.empty,
8989
this.terrains = const [],
9090
this.wangSets = const [],
9191
this.version = '1.0',
@@ -185,7 +185,7 @@ class Tileset {
185185
tileWidth = tileset.tileWidth ?? tileWidth;
186186
transparentColor = tileset.transparentColor ?? transparentColor;
187187
// Add List-Attributes
188-
properties.addAll(tileset.properties);
188+
properties.byName.addAll(tileset.properties.byName);
189189
terrains.addAll(tileset.terrains);
190190
tiles.addAll(tileset.tiles);
191191
wangSets.addAll(tileset.wangSets);

packages/tiled/lib/src/tileset/wang/wang_color.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ class WangColor {
1919
int tile;
2020
double probability;
2121

22-
List<Property> properties;
22+
CustomProperties properties;
2323

2424
WangColor({
2525
required this.name,
2626
required this.color,
2727
required this.tile,
2828
this.probability = 0,
29-
this.properties = const [],
29+
this.properties = CustomProperties.empty,
3030
});
3131

3232
WangColor.parse(Parser parser)

packages/tiled/lib/src/tileset/wang/wang_set.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ class WangSet {
2121
List<WangColor> cornerColors;
2222
List<WangColor> edgeColors;
2323
List<WangTile> wangTiles;
24-
List<Property> properties;
24+
CustomProperties properties;
2525

2626
WangSet({
2727
required this.name,
2828
required this.tile,
2929
this.cornerColors = const [],
3030
this.edgeColors = const [],
3131
this.wangTiles = const [],
32-
this.properties = const [],
32+
this.properties = CustomProperties.empty,
3333
});
3434

3535
factory WangSet.parse(Parser parser) {

packages/tiled/test/fixtures/test.tmx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22
<map version="1.2" tiledversion="1.2.1" orientation="orthogonal" renderorder="right-down" width="10" height="10" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1" backgroundcolor="#ccddaaff">
33
<tileset firstgid="1" name="basketball" tilewidth="32" tileheight="32" tilecount="2" columns="1">
44
<properties>
5-
<property name="test_property" value="test_value"/>
5+
<property name="string property" value="test_value"/>
6+
<property name="multiline string">Hello,
7+
World</property>
8+
<property name="integer property" type="int" value="42"/>
9+
<property name="bool property" type="bool" value="true"/>
10+
<property name="color property" type="color" value="#00112233"/>
11+
<property name="float property" type="float" value="1.56"/>
12+
<property name="file property" type="file" value="./icons.png"/>
13+
<property name="object property" type="object" value="32"/>
614
</properties>
715
<image source="icons.png" width="32" height="32"/>
816
<tile id="0" class="tile0Class">

0 commit comments

Comments
 (0)