pushrod/render/
widget_config.rs

1// Pushrod Rendering Library
2// Widget Configuration Store
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::render::{Points, Size};
17use sdl2::pixels::Color;
18use std::collections::HashMap;
19
20/// `Widget` Base `Color` key for `colors` `HashMap`.  This is the base fill color of a `Widget`
21/// that is in an unselected state.  This stored as a `Config::Color`.
22pub const CONFIG_COLOR_BASE: u8 = 0;
23
24/// `Widget` Hover `Color` key for `colors` `HashMap`.  This is the base fill color of a `Widget`
25/// that has a mouse hovering over the top of the `Widget`, or when a `mouse_entered` event is
26/// triggered.  This is optional; the `Widget` does not need to honor this color if it does not
27/// support a hover state.  This stored as a `Config::Color`.
28pub const CONFIG_COLOR_HOVER: u8 = 1;
29
30/// `Widget` Border `Color` key for `colors` `HashMap`.  This should be used for the color of the
31/// border, if the `Widget` draws a border.  This stored as a `Config::Color`.
32pub const CONFIG_COLOR_BORDER: u8 = 2;
33
34/// `Widget` Text `Color` key for `colors` `HashMap`.  This should be the color for the text being
35/// displayed inside the `Widget`.  This stored as a `Config::Color`.
36pub const CONFIG_COLOR_TEXT: u8 = 3;
37
38/// `Widget` Selected `Color` key for `colors` `HashMap`.  This is the color the `Widget` should
39/// display when in selected state.  This stored as a `Config::Color`.
40pub const CONFIG_COLOR_SELECTED: u8 = 4;
41
42/// `Widget` Secondary `Color` key for `colors` `HashMap`.  This is the color the `Widget` should
43/// display for any secondary properties, such as a fill color for a progress widget, a spinner,
44/// etc.  This stored as a `Config::Color`.
45pub const CONFIG_COLOR_SECONDARY: u8 = 5;
46
47/// `Widget` configuration to store its origin on the screen.  This is a `Config::Points` object in the
48/// config.
49pub const CONFIG_ORIGIN: u8 = 6;
50
51/// `Widget` configuration that stores the size of the `Widget`.  This is a `Config::Size` object
52/// in the config.
53pub const CONFIG_SIZE: u8 = 7;
54
55/// `Widget` configuration that stores the display border in pixels.  This is stored as a
56/// `Config::Numeric` value.
57pub const CONFIG_BORDER_WIDTH: u8 = 8;
58
59/// `Widget` text store, used to display text on the screen.  This is stored as a `Config::Text`
60/// value.
61pub const CONFIG_TEXT: u8 = 9;
62
63/// `Widget` image position direction, controls the position of an `Image` within the bounds of a
64/// `Widget`.  This is stored as a `Config::CompassPosition` value.
65pub const CONFIG_IMAGE_POSITION: u8 = 11;
66
67/// `TextWidget` font size control.  This is stored as a `Config::Numeric` value.
68pub const CONFIG_FONT_SIZE: u8 = 12;
69
70/// `PushButtonWidget` selected state.  This is stored as a `Config::Toggle` value.
71pub const CONFIG_SELECTED_STATE: u8 = 13;
72
73/// This enum is used by the `ImageWidget`, which controls the positioning of the image being
74/// rendered within the bounds of the `Widget`.
75#[derive(Clone, Debug, Copy)]
76pub enum CompassPosition {
77    /// Upper left-hand corner of the bounds.
78    NW,
79
80    /// Centered top of the bounds.
81    N,
82
83    /// Upper right-hand corner of the bounds.
84    NE,
85
86    /// Centered left side of the bounds.
87    W,
88
89    /// Center of the bounds.
90    Center,
91
92    /// Centered right side of the bounds.
93    E,
94
95    /// Lower left-hand corner of the bounds.
96    SW,
97
98    /// Bottom center of the bounds.
99    S,
100
101    /// Lower right-hand corner of the bounds.
102    SE,
103}
104
105/// This struct stores padding constraints.
106#[derive(Clone, Default, Debug, Copy)]
107pub struct PaddingConstraint {
108    pub top: i32,
109    pub bottom: i32,
110    pub left: i32,
111    pub right: i32,
112    pub spacing: i32,
113}
114
115/// Implementation to create a new `PaddingConstraint` object.
116impl PaddingConstraint {
117    pub fn new(top: i32, bottom: i32, left: i32, right: i32, spacing: i32) -> Self {
118        Self {
119            top,
120            bottom,
121            left,
122            right,
123            spacing,
124        }
125    }
126}
127
128/// Configuration object type - allows configurations to be set using `Piston`, `Pushrod`, or
129/// native types.
130#[derive(Clone, Debug)]
131pub enum Config {
132    /// This stores a `Points` type.
133    Points(Points),
134
135    /// This stores a `Size` type.
136    Size(Size),
137
138    /// This stores a `Color`.
139    Color(Color),
140
141    /// This stores a numeric value in the form of an `i32` value.
142    Numeric(i32),
143
144    /// This stores a `String` of text.
145    Text(String),
146
147    /// This stores a `true`/`false` boolean flag.
148    Toggle(bool),
149
150    /// This stores a `ComapssPosition`.
151    CompassPosition(CompassPosition),
152
153    /// This stores a `PaddingConstraint`.
154    PaddingConstraint(PaddingConstraint),
155}
156
157/// This is the store for the `WidgetConfig`, which each `Widget` object needs.  This stores
158/// information about the `Widget`.  It currently contains the point of origin, size, a `HashMap` of
159/// different `Color`s, a border width, and an invalidation flag.
160pub struct WidgetConfig {
161    /// The `HashMap` store for configuration objects.
162    pub config: HashMap<u8, Config>,
163
164    /// `Widget`'s hidden flag - any children that refer to this object as a `parent_id` will not
165    /// be drawn, and their events will not be received.
166    hidden: bool,
167
168    /// `Widget`'s enabled flag - any mouse events are ignored, but drawing is still performed.
169    enabled: bool,
170
171    /// `Widget`'s redraw flag.  Set `true` if the object needs to be redrawn, `false` otherwise.
172    invalidated: bool,
173}
174
175/// This is the implementation of the `WidgetConfig`.
176impl WidgetConfig {
177    /// Constructor - takes the X, Y, W, and H coordinates of the `Widget`, physically in the
178    /// main `Canvas`.
179    pub fn new(points: Points, size: Size) -> Self {
180        Self {
181            config: [
182                (CONFIG_ORIGIN, Config::Points(points)),
183                (CONFIG_SIZE, Config::Size(size)),
184                (CONFIG_COLOR_BASE, Config::Color(Color::RGB(255, 255, 255))),
185                (CONFIG_BORDER_WIDTH, Config::Numeric(0)),
186            ]
187            .iter()
188            .cloned()
189            .collect(),
190            hidden: false,
191            enabled: true,
192            invalidated: true,
193        }
194    }
195
196    /// Converts an X point to the physical X point on the `Canvas` plus the point of origin.
197    /// Returns `i32` containing the modified X coordinate.  This is a convenience method for the
198    /// `Widget` to draw based on a 0x0 point of origin.
199    pub fn to_x(&self, x: i32) -> i32 {
200        self.get_point(CONFIG_ORIGIN)[0] + x
201    }
202
203    /// Converts a Y point to the physical Y point on the `Canvas` plus the point of origin.
204    /// Returns `i32` containing the modified Y coordinate.  This is a convenience method for the
205    /// `Widget` to draw based on a 0x0 point of origin.
206    pub fn to_y(&self, y: i32) -> i32 {
207        self.get_point(CONFIG_ORIGIN)[1] + y
208    }
209
210    /// Sets the invalidation state of the `Widget`, telling the `Engine` that the `Widget`
211    /// contents has changed, and must be redrawn.  Setting the `flag` to `true` indicates that
212    /// the `Widget` needs to be redrawn on the screen, `false` indicates that it its state has
213    /// not changed, and its image can be pulled from a buffer if necessary, skipping the `draw`
214    /// call.
215    pub fn set_invalidated(&mut self, flag: bool) {
216        self.invalidated = flag;
217    }
218
219    /// Returns the `invalidation` state.  Returns a `bool` containing the state.
220    pub fn invalidated(&self) -> bool {
221        self.invalidated
222    }
223
224    /// Enables the `Widget` for interaction.
225    pub fn enable(&mut self) {
226        self.enabled = true;
227        self.invalidated = true;
228    }
229
230    /// Disables the `Widget`, preventing interaction.
231    pub fn disable(&mut self) {
232        self.enabled = false;
233        self.invalidated = true;
234    }
235
236    /// Indicates whether or not this `Widget` is enabled or disabled - `true` if enabled,
237    /// `false` otherwise.
238    pub fn is_enabled(&self) -> bool {
239        self.enabled
240    }
241
242    /// Prevents the `Widget` from being drawn on the screen, or being interacted with.  No events
243    /// are received by this `Widget` when hidden.
244    pub fn hide(&mut self) {
245        self.hidden = true;
246        self.invalidated = true;
247    }
248
249    /// Displays the `Widget` on the screen.
250    pub fn show(&mut self) {
251        self.hidden = false;
252        self.invalidated = true;
253    }
254
255    /// Indicates whether or not this `Widget` has been hidden from view - `true` if this `Widget`
256    /// is hidden, `false` otherwise.
257    pub fn is_hidden(&self) -> bool {
258        self.hidden
259    }
260
261    /// Sets a point for a configuration key.
262    pub fn set_point(&mut self, config: u8, x: i32, y: i32) {
263        self.config.insert(config, Config::Points(vec![x, y]));
264    }
265
266    /// Sets a size for a configuration key.
267    pub fn set_size(&mut self, config: u8, w: u32, h: u32) {
268        self.config.insert(config, Config::Size(vec![w, h]));
269    }
270
271    /// Sets a color for a configuration key.
272    pub fn set_color(&mut self, config: u8, color: Color) {
273        self.config.insert(config, Config::Color(color));
274    }
275
276    /// Sets a numeric value for a configuration key.
277    pub fn set_numeric(&mut self, config: u8, value: i32) {
278        self.config.insert(config, Config::Numeric(value));
279    }
280
281    /// Sets a text value for a configuration key.
282    pub fn set_text(&mut self, config: u8, text: String) {
283        self.config.insert(config, Config::Text(text));
284    }
285
286    /// Sets a toggle for a configuration key.
287    pub fn set_toggle(&mut self, config: u8, flag: bool) {
288        self.config.insert(config, Config::Toggle(flag));
289    }
290
291    /// Sets a compass position for a configuration key.
292    pub fn set_compass(&mut self, config: u8, value: CompassPosition) {
293        self.config.insert(config, Config::CompassPosition(value));
294    }
295
296    /// Applies a `PaddingConstraint`.
297    pub fn set_padding(&mut self, config: u8, value: PaddingConstraint) {
298        self.config.insert(config, Config::PaddingConstraint(value));
299    }
300
301    /// Retrieves a `Points` for a configuration key.  Returns `Points::default` if not set.
302    pub fn get_point(&self, k: u8) -> Points {
303        match self.config.get(&k) {
304            Some(Config::Points(point)) => point.clone(),
305            _ => Points::default(),
306        }
307    }
308
309    /// Retrieves a `Size` for a configuration key.  Returns a `Size::default` if not set.
310    pub fn get_size(&self, k: u8) -> Size {
311        match self.config.get(&k) {
312            Some(Config::Size(size)) => size.clone(),
313            _ => Size::default(),
314        }
315    }
316
317    /// Retrieves a `Color` for a configuration key.  Returns white if not set.
318    pub fn get_color(&self, k: u8) -> Color {
319        match self.config.get(&k) {
320            Some(Config::Color(color)) => *color,
321            _ => Color::RGB(255, 255, 255),
322        }
323    }
324
325    /// Retrieves a numeric value for a configuration key.  Returns 0 if not set.
326    pub fn get_numeric(&self, k: u8) -> i32 {
327        match self.config.get(&k) {
328            Some(Config::Numeric(numeric)) => *numeric,
329            _ => 0,
330        }
331    }
332
333    /// Retrieves text for a configuration key.  Returns a blank string if not set.
334    pub fn get_text(&self, k: u8) -> String {
335        match self.config.get(&k) {
336            Some(Config::Text(text)) => text.clone(),
337            _ => String::from(""),
338        }
339    }
340
341    /// Retrieves a boolean toggle for a configuration key.  Returns `false` if not set.
342    pub fn get_toggle(&self, k: u8) -> bool {
343        match self.config.get(&k) {
344            Some(Config::Toggle(toggle)) => *toggle,
345            _ => false,
346        }
347    }
348
349    /// Retrieves a `CompassPosition` toggle for a configuration key.  Returns `CompassPosition::W` if not set.
350    pub fn get_compass(&self, k: u8) -> CompassPosition {
351        match self.config.get(&k) {
352            Some(Config::CompassPosition(position)) => *position,
353            _ => CompassPosition::W,
354        }
355    }
356
357    /// Retrieves a `PaddingConstraint` toggle for a configuration key.  Returns empty `PaddingConstraint` if not set.
358    pub fn get_padding(&self, k: u8) -> PaddingConstraint {
359        match self.config.get(&k) {
360            Some(Config::PaddingConstraint(constraint)) => *constraint,
361            _ => PaddingConstraint::default(),
362        }
363    }
364}