@@ -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
35209extension 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}
0 commit comments