1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
// Configurable Implementation // New configuration module, as described by u/JayDepp on Reddit - THANKS!!! // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use piston_window::types::Color; use crate::core::point::Point; use crate::core::point::Size; /// Powerful macro that automatically creates a configuration object from a specified struct. /// Each struct has its own getter, setter, removal of a key (by its value), and checking to see /// if a key exists (by its value.) macro_rules! impl_configurable { ($($name:ty => $field:ident,)*) => { pub trait ConfigKey: private::ConfigKeyInner {} $( impl ConfigKey for $name {} )* mod private { use super::*; pub trait ConfigKeyInner: Sized { fn field(config: &Configurable) -> &Option<Self>; fn field_mut(config: &mut Configurable) -> &mut Option<Self>; } $( impl ConfigKeyInner for $name { fn field(config: &Configurable) -> &Option<Self> { &config.$field } fn field_mut(config: &mut Configurable) -> &mut Option<Self> { &mut config.$field } } )* } /// Default Configurable object, created for each struct represented in the /// `impl_configurable!` macro. #[derive(Default)] pub struct Configurable { $( $field: Option<$name>, )* } } } /// Existence of this object indicates that a `Widget` needs to be redrawn. pub struct Invalidate; /// Origin `Point` at which a `Widget` exists on the display window. pub struct Origin(pub Point); /// Physical size of the `Widget`. pub struct BodySize(pub Size); /// Color of the body of the `Widget`. pub struct MainColor(pub Color); /// Color of the border for the `BoxWidget` and any `Widget` objects that contain a border. pub struct BorderColor(pub Color); /// Width (in pixels) of the border for the `BoxWidget` or any `Widget` objects that contain a border. pub struct BorderWidth(pub u8); /// `Color` of text to be displayed in a `TextWidget`. pub struct TextColor(pub Color); /// This macro implements the availability of configuration items. The first value is the name /// of the `struct` that the configuration object applies, and the second value is the name of the /// private inner trait that is responsible for setting and getting values for that `struct` impl_configurable! { Invalidate => invalidate, Origin => origin, BodySize => body_size, MainColor => main_color, BorderColor => border_color, BorderWidth => border_width, TextColor => text_color, } /// Implementation of the default `Configurable` object. /// /// There are two ways in which configuration objects can be used: /// ``` /// # use pushrod::widget::config::*; /// # use pushrod::core::point::Point; /// # use pushrod::core::point::Size; /// fn main() { /// let mut config: Configurable = Configurable::new(); /// /// config.set(Origin(Point { x: 0, y: 100 })); /// config.set(BodySize(Size { w: 150, h: 150 })); /// /// // To get the value of the Origin, you can use type inference: /// let main_origin: &Origin = config.get().unwrap(); /// /// // Or you can use declared types with ::<> as such: /// let body_size = &config.get::<BodySize>().unwrap().0; /// } /// ``` impl Configurable { pub fn new() -> Self { Self::default() } pub fn set<T: ConfigKey>(&mut self, value: T) { *T::field_mut(self) = Some(value); } pub fn get<T: ConfigKey>(&self) -> Option<&T> { T::field(self).as_ref() } pub fn remove<T: ConfigKey>(&mut self) { *T::field_mut(self) = None; } pub fn contains_key<T: ConfigKey>(&self) -> bool { T::field(self).is_some() } }