iron_shapes/
text.rs

1// Copyright (c) 2018-2020 Thomas Kramer.
2// SPDX-FileCopyrightText: 2018-2022 Thomas Kramer
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! `Text` is used as labels associated with a point.
7
8use crate::point::Point;
9use crate::rect::Rect;
10use crate::traits::*;
11use num_traits::NumCast;
12use std::fmt;
13use std::hash::Hash;
14use std::ops::Deref;
15
16/// Trait for types that can be used as the text of this label.
17/// The most simple solution is to use `String`. However, in many cases
18/// where the same text is used in many labels it might be desirable to use 'string interning'
19/// for more efficient memory usage. Then an `Rc<String>` could be used for instance.
20pub trait TextType: Eq + Hash + Clone + fmt::Debug {}
21
22impl<T: Eq + Hash + Clone + fmt::Debug> TextType for T {}
23
24/// A text is a point associated with a string.
25/// This struct does not define how the text should be rendered on screen.
26#[derive(Debug, Clone, Hash, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28pub struct Text<T, S = String> {
29    /// Location of the label.
30    location: Point<T>,
31    /// Text content.
32    text: S,
33}
34
35/// Display format of the text label.
36impl<T, S> fmt::Display for Text<T, S>
37where
38    T: fmt::Display,
39    S: TextType + fmt::Display,
40{
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(f, "Text({}, {})", self.text, self.location)
43    }
44}
45
46impl<T, S> Deref for Text<T, S>
47where
48    S: Deref<Target = String>,
49{
50    type Target = String;
51
52    /// Dereference to String.
53    fn deref(&self) -> &Self::Target {
54        self.text.deref()
55    }
56}
57
58impl<T, S: TextType> Text<T, S> {
59    /// Create a new text object.
60    pub fn new(text: S, location: Point<T>) -> Self {
61        Text { location, text }
62    }
63
64    /// Get a reference to the text string.
65    pub fn text(&self) -> &S {
66        &self.text
67    }
68}
69
70impl<T: Copy, S: TextType> Text<T, S> {
71    /// Get location of the text label.
72    #[inline]
73    pub fn location(&self) -> Point<T> {
74        self.location
75    }
76
77    /// Get x-coordinate of the label location.
78    #[inline]
79    pub fn x(&self) -> T {
80        self.location.x
81    }
82
83    /// Get y-coordinate of the label location.
84    #[inline]
85    pub fn y(&self) -> T {
86        self.location.y
87    }
88}
89
90impl<T: Copy + PartialOrd, S> TryBoundingBox<T> for Text<T, S> {
91    fn try_bounding_box(&self) -> Option<Rect<T>> {
92        Some(Rect::new(self.location, self.location))
93    }
94}
95
96impl<T, Dst, S> TryCastCoord<T, Dst> for Text<T, S>
97where
98    T: Copy + NumCast,
99    Dst: Copy + NumCast,
100    S: Clone,
101{
102    type Output = Text<Dst, S>;
103
104    fn try_cast(&self) -> Option<Self::Output> {
105        self.location.try_cast().map(|loc| Text {
106            location: loc,
107            text: self.text.clone(),
108        })
109    }
110}
111
112/// Point wise transformation for a single point.
113impl<T, S> MapPointwise<T> for Text<T, S>
114where
115    T: Copy,
116    S: Clone,
117{
118    /// Point wise transformation.
119    #[inline]
120    fn transform<F>(&self, transformation: F) -> Self
121    where
122        F: Fn(Point<T>) -> Point<T>,
123    {
124        Text {
125            location: transformation(self.location),
126            text: self.text.clone(),
127        }
128    }
129}