diff --git a/assets/tiled_group_layers.tmx b/assets/tiled_group_layers.tmx
new file mode 100644
index 00000000..b027a4e8
--- /dev/null
+++ b/assets/tiled_group_layers.tmx
@@ -0,0 +1,64 @@
+
+
diff --git a/examples/main.rs b/examples/main.rs
index 4269d8d5..5379f50d 100644
--- a/examples/main.rs
+++ b/examples/main.rs
@@ -30,11 +30,9 @@ fn main() {
println!("Infinite tile layer with {} chunks", data.chunks.len())
}
},
-
tiled::LayerType::ObjectLayer(layer) => {
println!("Object layer with {} objects", layer.data().objects.len())
- }
-
+ },
tiled::LayerType::ImageLayer(layer) => {
println!(
"Image layer with {}",
@@ -44,6 +42,12 @@ fn main() {
None => "no image".to_owned(),
}
)
+ },
+ tiled::LayerType::GroupLayer(layer) => {
+ println!(
+ "Group layer with {} sublayers",
+ layer.layers().len()
+ )
}
}
}
diff --git a/src/layers/group.rs b/src/layers/group.rs
new file mode 100644
index 00000000..940de753
--- /dev/null
+++ b/src/layers/group.rs
@@ -0,0 +1,121 @@
+use std::path::Path;
+use std::collections::HashMap;
+
+use crate:: {
+ layers::{LayerData, LayerTag},
+ error::TiledError,
+ properties::{parse_properties, Properties},
+ map::MapTilesetGid,
+ util::*,
+ MapWrapper, Layer, Map
+};
+
+#[derive(Debug, PartialEq, Clone)]
+pub struct GroupLayerData {
+ layers: Vec,
+}
+
+impl GroupLayerData {
+ pub(crate) fn new(
+ parser: &mut impl Iterator- ,
+ infinite: bool,
+ map_path: &Path,
+ tilesets: &[MapTilesetGid],
+ ) -> Result<(Self, Properties), TiledError> {
+ let mut properties = HashMap::new();
+ let mut layers = Vec::new();
+ parse_tag!(parser, "group", {
+ "layer" => |attrs| {
+ layers.push(LayerData::new(
+ parser,
+ attrs,
+ LayerTag::TileLayer,
+ infinite,
+ map_path,
+ &tilesets,
+ )?);
+ Ok(())
+ },
+ "imagelayer" => |attrs| {
+ layers.push(LayerData::new(
+ parser,
+ attrs,
+ LayerTag::ImageLayer,
+ infinite,
+ map_path,
+ &tilesets,
+ )?);
+ Ok(())
+ },
+ "objectgroup" => |attrs| {
+ layers.push(LayerData::new(
+ parser,
+ attrs,
+ LayerTag::ObjectLayer,
+ infinite,
+ map_path,
+ &tilesets,
+ )?);
+ Ok(())
+ },
+ "group" => |attrs| {
+ layers.push(LayerData::new(
+ parser,
+ attrs,
+ LayerTag::GroupLayer,
+ infinite,
+ map_path,
+ &tilesets,
+ )?);
+ Ok(())
+ },
+ "properties" => |_| {
+ properties = parse_properties(parser)?;
+ Ok(())
+ },
+ });
+ Ok((
+ Self { layers },
+ properties,
+ ))
+ }
+}
+
+pub type GroupLayer<'map> = MapWrapper<'map, GroupLayerData>;
+
+impl<'map> GroupLayer<'map> {
+ pub fn layers(&self) -> GroupLayerIter {
+ GroupLayerIter::new(self.map(), self.data())
+ }
+ pub fn get_layer(&self, index: usize) -> Option {
+ self.data().layers.get(index).map(|data| Layer::new(self.map(), data))
+ }
+}
+
+/// An iterator that iterates over all the layers in a group layer, obtained via [`GroupLayer::layers`].
+pub struct GroupLayerIter<'map> {
+ map: &'map Map,
+ group: &'map GroupLayerData,
+ index: usize,
+}
+
+impl<'map> GroupLayerIter<'map> {
+ fn new(map: &'map Map, group: &'map GroupLayerData) -> Self {
+ Self { map, group, index: 0 }
+ }
+}
+
+impl<'map> Iterator for GroupLayerIter<'map> {
+ type Item = Layer<'map>;
+ fn next(&mut self) -> Option {
+ let layer_data = self.group.layers.get(self.index)?;
+ self.index += 1;
+ Some(Layer::new(self.map, layer_data))
+ }
+}
+
+impl<'map> ExactSizeIterator for GroupLayerIter<'map> {
+ fn len(&self) -> usize {
+ self.group.layers.len() - self.index
+ }
+}
diff --git a/src/layers/mod.rs b/src/layers/mod.rs
index b05004a1..272b4967 100644
--- a/src/layers/mod.rs
+++ b/src/layers/mod.rs
@@ -10,13 +10,15 @@ mod object;
pub use object::*;
mod tile;
pub use tile::*;
+mod group;
+pub use group::*;
#[derive(Clone, PartialEq, Debug)]
pub enum LayerDataType {
TileLayer(TileLayerData),
ObjectLayer(ObjectLayerData),
ImageLayer(ImageLayerData),
- // TODO: Support group layers
+ GroupLayer(GroupLayerData),
}
#[derive(Clone, Copy)]
@@ -24,6 +26,7 @@ pub(crate) enum LayerTag {
TileLayer,
ObjectLayer,
ImageLayer,
+ GroupLayer,
}
#[derive(Clone, PartialEq, Debug)]
@@ -85,6 +88,10 @@ impl LayerData {
let (ty, properties) = ImageLayerData::new(parser, map_path)?;
(LayerDataType::ImageLayer(ty), properties)
}
+ LayerTag::GroupLayer => {
+ let (ty, properties) = GroupLayerData::new(parser, infinite, map_path, tilesets)?;
+ (LayerDataType::GroupLayer(ty), properties)
+ }
};
Ok(Self {
@@ -116,7 +123,7 @@ pub enum LayerType<'map> {
TileLayer(TileLayer<'map>),
ObjectLayer(ObjectLayer<'map>),
ImageLayer(ImageLayer<'map>),
- // TODO: Support group layers
+ GroupLayer(GroupLayer<'map>),
}
impl<'map> LayerType<'map> {
@@ -125,6 +132,7 @@ impl<'map> LayerType<'map> {
LayerDataType::TileLayer(data) => Self::TileLayer(TileLayer::new(map, data)),
LayerDataType::ObjectLayer(data) => Self::ObjectLayer(ObjectLayer::new(map, data)),
LayerDataType::ImageLayer(data) => Self::ImageLayer(ImageLayer::new(map, data)),
+ LayerDataType::GroupLayer(data) => Self::GroupLayer(GroupLayer::new(map, data)),
}
}
}
diff --git a/src/map.rs b/src/map.rs
index dddb7d2d..94974707 100644
--- a/src/map.rs
+++ b/src/map.rs
@@ -103,8 +103,8 @@ impl Map {
}
/// Get an iterator over all the layers in the map in ascending order of their layer index.
- pub fn layers(&self) -> LayerIter {
- LayerIter::new(self)
+ pub fn layers(&self) -> MapLayerIter {
+ MapLayerIter::new(self)
}
/// Returns the layer that has the specified index, if it exists.
@@ -114,18 +114,18 @@ impl Map {
}
/// An iterator that iterates over all the layers in a map, obtained via [`Map::layers`].
-pub struct LayerIter<'map> {
+pub struct MapLayerIter<'map> {
map: &'map Map,
index: usize,
}
-impl<'map> LayerIter<'map> {
+impl<'map> MapLayerIter<'map> {
fn new(map: &'map Map) -> Self {
Self { map, index: 0 }
}
}
-impl<'map> Iterator for LayerIter<'map> {
+impl<'map> Iterator for MapLayerIter<'map> {
type Item = Layer<'map>;
fn next(&mut self) -> Option {
@@ -135,7 +135,7 @@ impl<'map> Iterator for LayerIter<'map> {
}
}
-impl<'map> ExactSizeIterator for LayerIter<'map> {
+impl<'map> ExactSizeIterator for MapLayerIter<'map> {
fn len(&self) -> usize {
self.map.layers.len() - self.index
}
@@ -222,6 +222,17 @@ impl Map {
)?);
Ok(())
},
+ "group" => |attrs| {
+ layers.push(LayerData::new(
+ parser,
+ attrs,
+ LayerTag::GroupLayer,
+ infinite,
+ map_path,
+ &tilesets,
+ )?);
+ Ok(())
+ },
"properties" => |_| {
properties = parse_properties(parser)?;
Ok(())
diff --git a/tests/lib.rs b/tests/lib.rs
index 396e01c5..c43bf8cf 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -1,7 +1,7 @@
use std::path::PathBuf;
use tiled::{
Color, FilesystemResourceCache, FiniteTileLayerData, Layer, LayerDataType, LayerType, Map,
- ObjectLayer, PropertyValue, ResourceCache, TileLayer, TileLayerData,
+ ObjectLayer, PropertyValue, ResourceCache, TileLayer, TileLayerData, GroupLayer,
};
fn as_tile_layer<'map>(layer: Layer<'map>) -> TileLayer<'map> {
@@ -25,6 +25,13 @@ fn as_object_layer<'map>(layer: Layer<'map>) -> ObjectLayer<'map> {
}
}
+fn as_group_layer<'map>(layer: Layer<'map>) -> GroupLayer<'map> {
+ match layer.layer_type() {
+ LayerType::GroupLayer(x) => x,
+ _ => panic!("Not a group layer"),
+ }
+}
+
fn compare_everything_but_tileset_sources(r: &Map, e: &Map) {
assert_eq!(r.version, e.version);
assert_eq!(r.orientation, e.orientation);
@@ -196,10 +203,10 @@ fn test_object_group_property() {
let mut cache = FilesystemResourceCache::new();
let r = Map::parse_file("assets/tiled_object_groups.tmx", &mut cache).unwrap();
- let prop_value: bool = if let Some(&PropertyValue::BoolValue(ref v)) = r
- .layers()
- .nth(1)
- .unwrap()
+ let group_layer = r.get_layer(1).unwrap();
+ let group_layer = as_group_layer(group_layer);
+ let sub_layer = group_layer.get_layer(0).unwrap();
+ let prop_value: bool = if let Some(&PropertyValue::BoolValue(ref v)) = sub_layer
.data()
.properties
.get("an object group property")
@@ -338,3 +345,50 @@ fn test_tint_color() {
})
);
}
+
+#[test]
+fn test_group_layers() {
+ let mut cache = FilesystemResourceCache::new();
+
+ let r = Map::parse_file("assets/tiled_group_layers.tmx", &mut cache).unwrap();
+
+ // Depth = 0
+ let layer_tile_1 = r.get_layer(0).unwrap();
+ let layer_group_1 = r.get_layer(1).unwrap();
+ let layer_group_2 = r.get_layer(2).unwrap();
+
+ assert_eq!(
+ Some(&PropertyValue::StringValue("value1".to_string())),
+ layer_tile_1.data().properties.get("key")
+ );
+ assert_eq!(
+ Some(&PropertyValue::StringValue("value4".to_string())),
+ layer_group_1.data().properties.get("key")
+ );
+ assert_eq!(
+ Some(&PropertyValue::StringValue("value5".to_string())),
+ layer_group_2.data().properties.get("key")
+ );
+
+ // Depth = 1
+ let layer_group_1 = as_group_layer(layer_group_1);
+ let layer_tile_2 = layer_group_1.get_layer(0).unwrap();
+ let layer_group_2 = as_group_layer(layer_group_2);
+ let layer_group_3 = layer_group_2.get_layer(0).unwrap();
+ assert_eq!(
+ Some(&PropertyValue::StringValue("value2".to_string())),
+ layer_tile_2.data().properties.get("key")
+ );
+ assert_eq!(
+ Some(&PropertyValue::StringValue("value6".to_string())),
+ layer_group_3.data().properties.get("key")
+ );
+
+ // Depth = 2
+ let layer_group_3 = as_group_layer(layer_group_3);
+ let layer_tile_3 = layer_group_3.get_layer(0).unwrap();
+ assert_eq!(
+ Some(&PropertyValue::StringValue("value3".to_string())),
+ layer_tile_3.data().properties.get("key")
+ );
+}