plotters_unstable/style/
size.rs1use crate::coord::CoordTranslate;
2use crate::drawing::DrawingArea;
3use plotters_backend::DrawingBackend;
4
5pub trait HasDimension {
10 fn dim(&self) -> (u32, u32);
12}
13
14impl<D: DrawingBackend, C: CoordTranslate> HasDimension for DrawingArea<D, C> {
15 fn dim(&self) -> (u32, u32) {
16 self.dim_in_pixel()
17 }
18}
19
20impl HasDimension for (u32, u32) {
21 fn dim(&self) -> (u32, u32) {
22 *self
23 }
24}
25
26pub trait SizeDesc {
29 fn in_pixels<T: HasDimension>(&self, parent: &T) -> i32;
34}
35
36impl SizeDesc for i32 {
37 fn in_pixels<D: HasDimension>(&self, _parent: &D) -> i32 {
38 *self
39 }
40}
41
42impl SizeDesc for u32 {
43 fn in_pixels<D: HasDimension>(&self, _parent: &D) -> i32 {
44 *self as i32
45 }
46}
47
48pub enum RelativeSize {
53 Height(f64),
55 Width(f64),
57 Smaller(f64),
59}
60
61impl RelativeSize {
62 pub fn min(self, min_sz: i32) -> RelativeSizeWithBound {
67 RelativeSizeWithBound {
68 size: self,
69 min: Some(min_sz),
70 max: None,
71 }
72 }
73
74 pub fn max(self, max_sz: i32) -> RelativeSizeWithBound {
79 RelativeSizeWithBound {
80 size: self,
81 max: Some(max_sz),
82 min: None,
83 }
84 }
85}
86
87impl SizeDesc for RelativeSize {
88 fn in_pixels<D: HasDimension>(&self, parent: &D) -> i32 {
89 let (w, h) = parent.dim();
90 match self {
91 RelativeSize::Width(p) => *p * f64::from(w),
92 RelativeSize::Height(p) => *p * f64::from(h),
93 RelativeSize::Smaller(p) => *p * f64::from(w.min(h)),
94 }
95 .round() as i32
96 }
97}
98
99pub trait AsRelative: Into<f64> {
101 fn percent_width(self) -> RelativeSize {
103 RelativeSize::Width(self.into() / 100.0)
104 }
105 fn percent_height(self) -> RelativeSize {
107 RelativeSize::Height(self.into() / 100.0)
108 }
109 fn percent(self) -> RelativeSize {
111 RelativeSize::Smaller(self.into() / 100.0)
112 }
113}
114
115impl<T: Into<f64>> AsRelative for T {}
116
117pub struct RelativeSizeWithBound {
119 size: RelativeSize,
120 min: Option<i32>,
121 max: Option<i32>,
122}
123
124impl RelativeSizeWithBound {
125 pub fn min(mut self, min_sz: i32) -> RelativeSizeWithBound {
130 self.min = Some(min_sz);
131 self
132 }
133
134 pub fn max(mut self, max_sz: i32) -> RelativeSizeWithBound {
139 self.max = Some(max_sz);
140 self
141 }
142}
143
144impl SizeDesc for RelativeSizeWithBound {
145 fn in_pixels<D: HasDimension>(&self, parent: &D) -> i32 {
146 let size = self.size.in_pixels(parent);
147 let size_lower_capped = self.min.map_or(size, |x| x.max(size));
148 self.max.map_or(size_lower_capped, |x| x.min(size))
149 }
150}
151
152#[cfg(test)]
153mod test {
154 use super::*;
155 #[test]
156 fn test_relative_size() {
157 let size = (10).percent_height();
158 assert_eq!(size.in_pixels(&(100, 200)), 20);
159
160 let size = (10).percent_width();
161 assert_eq!(size.in_pixels(&(100, 200)), 10);
162
163 let size = (-10).percent_width();
164 assert_eq!(size.in_pixels(&(100, 200)), -10);
165
166 let size = (10).percent_width().min(30);
167 assert_eq!(size.in_pixels(&(100, 200)), 30);
168 assert_eq!(size.in_pixels(&(400, 200)), 40);
169
170 let size = (10).percent();
171 assert_eq!(size.in_pixels(&(100, 200)), 10);
172 assert_eq!(size.in_pixels(&(400, 200)), 20);
173 }
174}