tiled_json_rs/
object.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use crate::{
6    parsers::{parse_color, parse_property},
7    Color, TiledValue, Vec2,
8};
9use serde::{Deserialize, Deserializer};
10use std::collections::HashMap;
11
12#[derive(Deserialize, Debug, PartialEq, Clone)]
13pub struct Object {
14    // GID, only if object comes from a Tilemap
15    pub gid: Option<u32>,
16    /// Incremental id - unique across all objects
17    pub id: Option<u32>,
18    pub name: String,
19    #[serde(rename(deserialize = "type"), default)]
20    pub custom_type: String,
21    /// Angle in degrees clockwise
22    pub rotation: f32,
23    pub height: f32,
24    pub width: f32,
25    /// X coordinate in pixels
26    #[serde(default)]
27    pub x: f32,
28    /// Y coordinate in pixels
29    #[serde(default)]
30    pub y: f32,
31    #[serde(deserialize_with = "parse_property", default)]
32    pub properties: HashMap<String, TiledValue>,
33    /// An *almost* concrete type. Some types aren't included in this, eg; a square
34    /// which can be derived from the X/Y & Height/Width
35    ///
36    /// Types can be:
37    /// - Point
38    /// - Polygon
39    /// - Polyline
40    /// - Text
41    /// - Ellipse
42    /// - or None
43    #[serde(flatten)]
44    pub object_type: ObjectType,
45}
46
47#[derive(Deserialize, Debug, PartialEq, Clone)]
48pub struct Text {
49    /// 0000: off, 0001: bold, 0010:italic, 0100: wrap (1, 2, 4, 8)
50    pub flags: u8,
51    #[serde(deserialize_with = "parse_color", default)]
52    pub color: Color,
53    pub text: String,
54}
55
56/// Contains data for the object sub-types
57#[derive(Debug, PartialEq, Clone)]
58pub enum ObjectType {
59    Ellipse,
60    Point,
61    Polygon(Vec<Vec2<i32>>),
62    PolyLine(Vec<Vec2<i32>>),
63    Text(Text),
64    Template(String),
65    None,
66}
67
68impl ObjectType {
69    pub fn is_none(&self) -> bool {
70        *self == ObjectType::None
71    }
72
73    pub fn is_some(&self) -> bool {
74        *self != ObjectType::None
75    }
76}
77
78impl<'de> Deserialize<'de> for ObjectType {
79    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
80    where
81        D: Deserializer<'de>,
82    {
83        #[derive(Deserialize)]
84        #[serde(rename_all = "lowercase")]
85        enum Helper {
86            Ellipse(bool),
87            Point(bool),
88            Polygon(Vec<Vec2<i32>>),
89            Polyline(Vec<Vec2<i32>>),
90            Text {
91                bold: bool,
92                #[serde(deserialize_with = "parse_color", default)]
93                color: Color,
94                italic: bool,
95                text: String,
96                wrap: bool,
97            },
98        }
99
100        let v = serde_json::Value::deserialize(deserializer)?;
101        if let Ok(m) = Helper::deserialize(&v) {
102            return match m {
103                Helper::Ellipse(b) => {
104                    if b {
105                        Ok(ObjectType::Ellipse)
106                    } else {
107                        Ok(ObjectType::None)
108                    }
109                }
110                Helper::Point(b) => {
111                    if b {
112                        Ok(ObjectType::Point)
113                    } else {
114                        Ok(ObjectType::None)
115                    }
116                }
117                Helper::Polygon(data) => Ok(ObjectType::Polygon(data)),
118                Helper::Polyline(data) => Ok(ObjectType::PolyLine(data)),
119                Helper::Text {
120                    bold,
121                    color,
122                    italic,
123                    text,
124                    wrap,
125                } => {
126                    let mut flags = 0u8;
127                    if bold {
128                        flags |= 1
129                    }
130                    if italic {
131                        flags |= 2
132                    }
133                    if wrap {
134                        flags |= 4
135                    }
136                    Ok(ObjectType::Text(Text { flags, color, text }))
137                }
138            };
139        }
140        Ok(ObjectType::None)
141    }
142}