1use crate::core::{
38 algebra::Vector2, color::Color, num_traits::Euclid, reflect::prelude::*,
39 type_traits::prelude::*, visitor::prelude::*, ImmutableString,
40};
41use std::fmt::{Debug, Display, Formatter};
42
43use super::*;
44use tileset::*;
45
46#[derive(Clone, Default, Debug, Reflect, Visit)]
50pub struct TileSetColliderLayer {
51 pub uuid: Uuid,
53 pub name: ImmutableString,
55 pub color: Color,
57}
58
59#[derive(Clone, Default, Debug, Reflect, Visit)]
63pub struct TileSetPropertyLayer {
64 pub uuid: Uuid,
66 pub name: ImmutableString,
68 pub prop_type: TileSetPropertyType,
70 pub named_values: Vec<NamedValue>,
72}
73
74#[derive(Clone, Default, Debug, Reflect, Visit)]
78pub struct NamedValue {
79 pub name: String,
81 pub value: NamableValue,
83 pub color: Color,
85}
86
87#[derive(Copy, Clone, Debug, Reflect, Visit, PartialEq)]
90pub enum NamableValue {
91 I8(i8),
93 I32(i32),
95 F32(f32),
97}
98
99impl Display for NamableValue {
100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101 match self {
102 Self::I8(value) => write!(f, "{value}"),
103 Self::I32(value) => write!(f, "{value}"),
104 Self::F32(value) => write!(f, "{value}"),
105 }
106 }
107}
108
109impl Default for NamableValue {
110 fn default() -> Self {
111 Self::I32(0)
112 }
113}
114
115impl NamableValue {
116 pub fn matches(&self, other: &TileSetPropertyOptionValue) -> bool {
118 match (self, other) {
119 (Self::I32(x), TileSetPropertyOptionValue::I32(Some(y))) => *x == *y,
120 (Self::F32(x), TileSetPropertyOptionValue::F32(Some(y))) => *x == *y,
121 _ => false,
122 }
123 }
124}
125
126impl TileSetPropertyLayer {
127 pub fn value_to_name(&self, value: NamableValue) -> String {
129 self.named_values
130 .iter()
131 .find(|v| v.value == value)
132 .map(|v| v.name.clone())
133 .unwrap_or_else(|| format!("{value}"))
134 }
135 pub fn value_to_color(&self, value: NamableValue) -> Option<Color> {
137 self.named_values
138 .iter()
139 .find(|v| v.value == value)
140 .map(|v| v.color)
141 }
142 pub fn find_value_index_from_property(
144 &self,
145 value: &TileSetPropertyOptionValue,
146 ) -> Option<usize> {
147 self.named_values
148 .iter()
149 .position(|v| v.value.matches(value))
150 }
151 pub fn find_value_index(&self, value: NamableValue) -> Option<usize> {
153 self.named_values.iter().position(|v| v.value == value)
154 }
155 pub fn highlight_color(
161 &self,
162 position: Vector2<usize>,
163 value: &TileSetPropertyValue,
164 element_value: &TileSetPropertyValueElement,
165 ) -> Option<Color> {
166 use TileSetPropertyValue as PropValue;
167 use TileSetPropertyValueElement as Element;
168 if position != Vector2::new(1, 1) && !matches!(value, PropValue::NineSlice(_)) {
169 return None;
170 }
171 match (value, element_value) {
172 (&PropValue::I32(v0), &Element::I32(v1)) => {
173 self.value_to_color(NamableValue::I32(v0)).or({
174 if v0 == v1 {
175 Some(ELEMENT_MATCH_HIGHLIGHT_COLOR)
176 } else {
177 None
178 }
179 })
180 }
181 (&PropValue::F32(v0), &Element::F32(v1)) => {
182 self.value_to_color(NamableValue::F32(v0)).or({
183 if v0 == v1 {
184 Some(ELEMENT_MATCH_HIGHLIGHT_COLOR)
185 } else {
186 None
187 }
188 })
189 }
190 (PropValue::String(v0), Element::String(v1)) => {
191 if v0 == v1 {
192 Some(ELEMENT_MATCH_HIGHLIGHT_COLOR)
193 } else {
194 None
195 }
196 }
197 (PropValue::NineSlice(v0), &Element::I8(v1)) => {
198 let v = v0.value_at(position);
199 self.value_to_color(NamableValue::I8(v)).or({
200 if v == v1 {
201 Some(ELEMENT_MATCH_HIGHLIGHT_COLOR)
202 } else {
203 None
204 }
205 })
206 }
207 _ => None,
208 }
209 }
210}
211
212#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Reflect, Visit)]
216pub enum TileSetPropertyType {
217 #[default]
219 I32,
220 F32,
222 String,
224 NineSlice,
227}
228
229impl TileSetPropertyType {
230 pub fn default_value(&self) -> TileSetPropertyValue {
232 use TileSetPropertyType as PropType;
233 use TileSetPropertyValue as PropValue;
234 match self {
235 PropType::I32 => PropValue::I32(0),
236 PropType::F32 => PropValue::F32(0.0),
237 PropType::String => PropValue::String(ImmutableString::default()),
238 PropType::NineSlice => PropValue::NineSlice(NineI8::default()),
239 }
240 }
241 pub fn default_option_value(&self) -> TileSetPropertyOptionValue {
243 use TileSetPropertyOptionValue as PropValue;
244 use TileSetPropertyType as PropType;
245 match self {
246 PropType::I32 => PropValue::I32(None),
247 PropType::F32 => PropValue::F32(None),
248 PropType::String => PropValue::String(None),
249 PropType::NineSlice => PropValue::NineSlice([None; 9]),
250 }
251 }
252}
253
254#[derive(Clone, Debug, PartialEq, Reflect, Visit)]
256pub enum TileSetPropertyValue {
257 I32(i32),
259 F32(f32),
261 String(ImmutableString),
263 NineSlice(NineI8),
266}
267
268#[derive(Default, Clone, Copy, PartialEq, Reflect)]
274pub struct NineI8(pub [i8; 9]);
275
276impl Visit for NineI8 {
277 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
278 self.0.visit(name, visitor)
279 }
280}
281
282impl Debug for NineI8 {
283 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
284 let [v0, v1, v2, v3, v4, v5, v6, v7, v8] = self.0;
285 write!(f, "NineI8[{v0} {v1} {v2}/{v3} {v4} {v5}/{v6} {v7} {v8}]")
286 }
287}
288
289impl Display for NineI8 {
290 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
291 let [v0, v1, v2, v3, v4, v5, v6, v7, v8] = self.0;
292 write!(f, "[{v0} {v1} {v2}/{v3} {v4} {v5}/{v6} {v7} {v8}]")
293 }
294}
295
296impl From<[i8; 9]> for NineI8 {
297 fn from(value: [i8; 9]) -> Self {
298 NineI8(value)
299 }
300}
301
302impl From<NineI8> for [i8; 9] {
303 fn from(value: NineI8) -> Self {
304 value.0
305 }
306}
307
308impl NineI8 {
309 pub fn value_at(&self, position: Vector2<usize>) -> i8 {
316 let index = TileSetPropertyValue::nine_position_to_index(position);
317 self.0[index]
318 }
319 pub fn value_at_mut(&mut self, position: Vector2<usize>) -> &mut i8 {
326 let index = TileSetPropertyValue::nine_position_to_index(position);
327 &mut self.0[index]
328 }
329 pub fn swap(&mut self, a: Vector2<usize>, b: Vector2<usize>) {
331 let a_index = TileSetPropertyValue::nine_position_to_index(a);
332 let b_index = TileSetPropertyValue::nine_position_to_index(b);
333 self.0.swap(a_index, b_index);
334 }
335}
336
337#[derive(Clone, Debug, PartialEq)]
341pub enum TileSetPropertyValueElement {
342 I32(i32),
344 F32(f32),
346 String(ImmutableString),
348 I8(i8),
350}
351
352impl Default for TileSetPropertyValue {
353 fn default() -> Self {
354 Self::I32(0)
355 }
356}
357
358impl Default for TileSetPropertyValueElement {
359 fn default() -> Self {
360 Self::I32(0)
361 }
362}
363
364impl OrthoTransform for TileSetPropertyValue {
365 fn x_flipped(self) -> Self {
366 if let Self::NineSlice(mut v) = self {
367 fn pos(x: usize, y: usize) -> Vector2<usize> {
368 Vector2::new(x, y)
369 }
370 v.swap(pos(2, 0), pos(0, 0));
371 v.swap(pos(2, 1), pos(0, 1));
372 v.swap(pos(2, 2), pos(0, 2));
373 Self::NineSlice(v)
374 } else {
375 self
376 }
377 }
378
379 fn rotated(self, amount: i8) -> Self {
380 if let Self::NineSlice(mut v) = self {
381 let amount = amount.rem_euclid(4);
382 nine_rotate(&mut v, amount as usize * 2);
383 Self::NineSlice(v)
384 } else {
385 self
386 }
387 }
388}
389
390const fn nine_index(x: usize, y: usize) -> usize {
391 y * 3 + x
392}
393
394const NINE_ROTATE_LIST: [usize; 8] = [
395 nine_index(0, 0),
396 nine_index(1, 0),
397 nine_index(2, 0),
398 nine_index(2, 1),
399 nine_index(2, 2),
400 nine_index(1, 2),
401 nine_index(0, 2),
402 nine_index(0, 1),
403];
404
405fn nine_rotate(nine: &mut NineI8, amount: usize) {
406 let nine = &mut nine.0;
407 let copy = *nine;
408 for i in 0..(8 - amount) {
409 nine[NINE_ROTATE_LIST[i + amount]] = copy[NINE_ROTATE_LIST[i]];
410 }
411 for i in 0..amount {
412 nine[NINE_ROTATE_LIST[i]] = copy[NINE_ROTATE_LIST[8 - amount + i]];
413 }
414}
415
416impl TileSetPropertyValue {
417 pub fn make_default(&self) -> TileSetPropertyValue {
419 match self {
420 TileSetPropertyValue::I32(_) => TileSetPropertyValue::I32(0),
421 TileSetPropertyValue::F32(_) => TileSetPropertyValue::F32(0.0),
422 TileSetPropertyValue::String(_) => {
423 TileSetPropertyValue::String(ImmutableString::default())
424 }
425 TileSetPropertyValue::NineSlice(_) => {
426 TileSetPropertyValue::NineSlice(Default::default())
427 }
428 }
429 }
430 #[inline]
432 pub fn nine_position_to_index(position: Vector2<usize>) -> usize {
433 if position.y > 2 || position.x > 2 {
434 panic!("Illegal nine slice position: {:?}", position);
435 }
436 position.y * 3 + position.x
437 }
438 #[inline]
440 pub fn index_to_nine_position(index: usize) -> Vector2<usize> {
441 let (y, x) = index.div_rem_euclid(&3);
442 Vector2::new(x, y)
443 }
444 pub fn set_from(&mut self, value: &TileSetPropertyOptionValue) {
447 use TileSetPropertyOptionValue as OptValue;
448 use TileSetPropertyValue as PropValue;
449 match (self, value) {
450 (PropValue::I32(x0), OptValue::I32(Some(x1))) => *x0 = *x1,
451 (PropValue::F32(x0), OptValue::F32(Some(x1))) => *x0 = *x1,
452 (PropValue::String(x0), OptValue::String(Some(x1))) => *x0 = x1.clone(),
453 (PropValue::NineSlice(arr0), OptValue::NineSlice(arr1)) => {
454 for (x0, x1) in arr0.0.iter_mut().zip(arr1.iter()) {
455 if let Some(v) = x1 {
456 *x0 = *v;
457 }
458 }
459 }
460 _ => (),
461 }
462 }
463}
464
465#[derive(Clone, Debug, PartialEq, Reflect, Visit)]
468pub enum TileSetPropertyOptionValue {
469 I32(Option<i32>),
471 F32(Option<f32>),
473 String(Option<ImmutableString>),
475 NineSlice([Option<i8>; 9]),
478}
479
480impl Default for TileSetPropertyOptionValue {
481 fn default() -> Self {
482 Self::I32(None)
483 }
484}
485
486impl TryFrom<TileSetPropertyValue> for i32 {
487 type Error = TilePropertyError;
488
489 fn try_from(value: TileSetPropertyValue) -> Result<Self, Self::Error> {
490 use TilePropertyError::*;
491 use TileSetPropertyValue::*;
492 match value {
493 I32(v) => Ok(v),
494 F32(_) => Err(WrongType("Expected: i32, Found: f32")),
495 String(_) => Err(WrongType("Expected: i32, Found: ImmutableString")),
496 NineSlice(_) => Err(WrongType("Expected: i32, Found: NineI8")),
497 }
498 }
499}
500
501impl TryFrom<TileSetPropertyValue> for f32 {
502 type Error = TilePropertyError;
503
504 fn try_from(value: TileSetPropertyValue) -> Result<Self, Self::Error> {
505 use TilePropertyError::*;
506 use TileSetPropertyValue::*;
507 match value {
508 I32(_) => Err(WrongType("Expected: f32, Found: i32")),
509 F32(v) => Ok(v),
510 String(_) => Err(WrongType("Expected: f32, Found: ImmutableString")),
511 NineSlice(_) => Err(WrongType("Expected: f32, Found: NineI8")),
512 }
513 }
514}
515
516impl TryFrom<TileSetPropertyValue> for ImmutableString {
517 type Error = TilePropertyError;
518
519 fn try_from(value: TileSetPropertyValue) -> Result<Self, Self::Error> {
520 use TilePropertyError::*;
521 use TileSetPropertyValue::*;
522 match value {
523 I32(_) => Err(WrongType("Expected: ImmutableString, Found: i32")),
524 F32(_) => Err(WrongType("Expected: ImmutableString, Found: f32")),
525 String(v) => Ok(v),
526 NineSlice(_) => Err(WrongType("Expected: ImmutableString, Found: NineI8")),
527 }
528 }
529}
530
531impl TryFrom<TileSetPropertyValue> for NineI8 {
532 type Error = TilePropertyError;
533
534 fn try_from(value: TileSetPropertyValue) -> Result<Self, Self::Error> {
535 use TilePropertyError::*;
536 use TileSetPropertyValue::*;
537 match value {
538 I32(_) => Err(WrongType("Expected: NineI8, Found: i32")),
539 F32(_) => Err(WrongType("Expected: NineI8, Found: f32")),
540 String(_) => Err(WrongType("Expected: NineI8, Found: ImmutableString")),
541 NineSlice(v) => Ok(v),
542 }
543 }
544}
545
546impl From<TileSetPropertyValue> for TileSetPropertyOptionValue {
547 fn from(value: TileSetPropertyValue) -> Self {
548 use TileSetPropertyOptionValue as OValue;
549 use TileSetPropertyValue as Value;
550 match value {
551 Value::I32(x) => OValue::I32(Some(x)),
552 Value::F32(x) => OValue::F32(Some(x)),
553 Value::String(x) => OValue::String(Some(x)),
554 Value::NineSlice(arr) => OValue::NineSlice(arr.0.map(Some)),
555 }
556 }
557}
558
559impl From<TileSetPropertyOptionValue> for TileSetPropertyValue {
560 fn from(value: TileSetPropertyOptionValue) -> Self {
561 use TileSetPropertyOptionValue as OValue;
562 use TileSetPropertyValue as Value;
563 match value {
564 OValue::I32(x) => Value::I32(x.unwrap_or_default()),
565 OValue::F32(x) => Value::F32(x.unwrap_or_default()),
566 OValue::String(x) => Value::String(x.unwrap_or_default()),
567 OValue::NineSlice(arr) => Value::NineSlice(NineI8(arr.map(Option::unwrap_or_default))),
568 }
569 }
570}
571
572impl TileSetPropertyOptionValue {
573 pub fn intersect(&mut self, value: &TileSetPropertyValue) {
576 use TileSetPropertyOptionValue as OptValue;
577 use TileSetPropertyValue as PropValue;
578 match self {
579 OptValue::I32(x0) => {
580 if let Some(x) = x0 {
581 if *value != PropValue::I32(*x) {
582 *x0 = None
583 }
584 }
585 }
586 OptValue::F32(x0) => {
587 if let Some(x) = x0 {
588 if *value != PropValue::F32(*x) {
589 *x0 = None
590 }
591 }
592 }
593 OptValue::String(x0) => {
594 if let Some(x) = x0 {
595 if let PropValue::String(x1) = value {
596 if *x != *x1 {
597 *x0 = None
598 }
599 } else {
600 *x0 = None
601 }
602 }
603 }
604 OptValue::NineSlice(arr0) => {
605 if let PropValue::NineSlice(arr1) = value {
606 for (x0, x1) in arr0.iter_mut().zip(arr1.0.iter()) {
607 if let Some(x) = x0 {
608 if *x != *x1 {
609 *x0 = None
610 }
611 }
612 }
613 } else {
614 *arr0 = [None; 9];
615 }
616 }
617 }
618 }
619}