1 use std::ops::{BitOr, BitXor};
2 use super::{chtype, A_ALTCHARSET, A_BLINK, A_BOLD, A_CHARTEXT, A_DIM, A_INVIS, A_LEFTLINE};
3 use super::{A_ITALIC, A_OVERLINE, A_REVERSE, A_RIGHTLINE, A_STRIKEOUT, A_UNDERLINE};
4 use super::colorpair::ColorPair;
5 
6 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
7 pub enum Attribute {
8     AlternativeCharSet,
9     Bold,
10     Blink,
11     CharText,
12     Dim,
13     Leftline,
14     Invisible,
15     Italic,
16     Normal,
17     Overline,
18     Reverse,
19     Rightline,
20     Strikeout,
21     Underline,
22 }
23 
24 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
25 pub struct Attributes {
26     raw: chtype,
27     color_pair: ColorPair,
28 }
29 
30 macro_rules! attribute_setter {
31     ($name:ident, $attr:ident) => {
32         pub fn $name(&mut self, enabled: bool) {
33             if enabled {
34                 self.raw |= $attr;
35             } else {
36                 self.raw ^= $attr;
37             }
38         }
39     };
40 }
41 
42 impl Attributes {
new() -> Attributes43     pub fn new() -> Attributes {
44         Attributes {
45             raw: 0,
46             color_pair: ColorPair(0),
47         }
48     }
49 
is_alternative_char_set(&self) -> bool50     pub fn is_alternative_char_set(&self) -> bool {
51         (self.raw & A_ALTCHARSET) > 0
52     }
53     attribute_setter!(set_alternative_char_set, A_ALTCHARSET);
54 
is_bold(&self) -> bool55     pub fn is_bold(&self) -> bool {
56         (self.raw & A_BOLD) > 0
57     }
58     attribute_setter!(set_bold, A_BOLD);
59 
is_blink(&self) -> bool60     pub fn is_blink(&self) -> bool {
61         (self.raw & A_BLINK) > 0
62     }
63     attribute_setter!(set_blink, A_BLINK);
64 
is_char_text(&self) -> bool65     pub fn is_char_text(&self) -> bool {
66         (self.raw & A_CHARTEXT) > 0
67     }
68     attribute_setter!(set_char_text, A_CHARTEXT);
69 
is_dim(&self) -> bool70     pub fn is_dim(&self) -> bool {
71         (self.raw & A_DIM) > 0
72     }
73     attribute_setter!(set_dim, A_DIM);
74 
is_leftline(&self) -> bool75     pub fn is_leftline(&self) -> bool {
76         (self.raw & A_LEFTLINE) > 0
77     }
78     attribute_setter!(set_leftline, A_LEFTLINE);
79 
is_invisible(&self) -> bool80     pub fn is_invisible(&self) -> bool {
81         (self.raw & A_INVIS) > 0
82     }
83     attribute_setter!(set_invisible, A_INVIS);
84 
is_italic(&self) -> bool85     pub fn is_italic(&self) -> bool {
86         (self.raw & A_ITALIC) > 0
87     }
88     attribute_setter!(set_italic, A_ITALIC);
89 
is_normal(&self) -> bool90     pub fn is_normal(&self) -> bool {
91         self.raw == 0
92     }
set_normal(&mut self)93     pub fn set_normal(&mut self) {
94         self.raw = 0
95     }
96 
is_overline(&self) -> bool97     pub fn is_overline(&self) -> bool {
98         (self.raw & A_OVERLINE) > 0
99     }
100     attribute_setter!(set_overline, A_OVERLINE);
101 
is_reverse(&self) -> bool102     pub fn is_reverse(&self) -> bool {
103         (self.raw & A_REVERSE) > 0
104     }
105     attribute_setter!(set_reverse, A_REVERSE);
106 
is_rightline(&self) -> bool107     pub fn is_rightline(&self) -> bool {
108         (self.raw & A_RIGHTLINE) > 0
109     }
110     attribute_setter!(set_rightline, A_RIGHTLINE);
111 
is_strikeout(&self) -> bool112     pub fn is_strikeout(&self) -> bool {
113         (self.raw & A_STRIKEOUT) > 0
114     }
115     attribute_setter!(set_strikeout, A_STRIKEOUT);
116 
is_underline(&self) -> bool117     pub fn is_underline(&self) -> bool {
118         (self.raw & A_UNDERLINE) > 0
119     }
120     attribute_setter!(set_underline, A_UNDERLINE);
121 
color_pair(&self) -> ColorPair122     pub fn color_pair(&self) -> ColorPair {
123         self.color_pair
124     }
set_color_pair(&mut self, color_pair: ColorPair)125     pub fn set_color_pair(&mut self, color_pair: ColorPair) {
126         let color_chtype: chtype = color_pair.into();
127         self.raw = self.raw | color_chtype;
128         self.color_pair = color_pair;
129     }
130 }
131 
132 /// Implement the | operator for adding an Attribute to Attributes
133 ///
134 /// # Example
135 ///
136 /// ```
137 /// use pancurses::{Attribute, Attributes};
138 ///
139 /// let mut attributes = Attributes::new();
140 /// assert!(!attributes.is_bold());
141 /// attributes = attributes | Attribute::Bold;
142 /// assert!(attributes.is_bold());
143 /// ```
144 impl BitOr<Attribute> for Attributes {
145     type Output = Attributes;
146 
bitor(mut self, rhs: Attribute) -> Attributes147     fn bitor(mut self, rhs: Attribute) -> Attributes {
148         match rhs {
149             Attribute::AlternativeCharSet => self.set_alternative_char_set(true),
150             Attribute::Bold => self.set_bold(true),
151             Attribute::Blink => self.set_blink(true),
152             Attribute::CharText => self.set_char_text(true),
153             Attribute::Dim => self.set_dim(true),
154             Attribute::Leftline => self.set_leftline(true),
155             Attribute::Invisible => self.set_invisible(true),
156             Attribute::Italic => self.set_italic(true),
157             Attribute::Normal => self.set_normal(),
158             Attribute::Overline => self.set_overline(true),
159             Attribute::Reverse => self.set_reverse(true),
160             Attribute::Rightline => self.set_rightline(true),
161             Attribute::Strikeout => self.set_strikeout(true),
162             Attribute::Underline => self.set_underline(true),
163         }
164         self
165     }
166 }
167 
168 /// Implement the ^ operator for disabling an Attribute from Attributes
169 ///
170 /// # Example
171 ///
172 /// ```
173 /// use pancurses::{Attribute, Attributes};
174 ///
175 /// let mut attributes = Attributes::from(Attribute::Bold);
176 /// assert!(attributes.is_bold());
177 /// attributes = attributes ^ Attribute::Bold;
178 /// assert!(!attributes.is_bold());
179 /// ```
180 impl BitXor<Attribute> for Attributes {
181     type Output = Attributes;
182 
bitxor(mut self, rhs: Attribute) -> Attributes183     fn bitxor(mut self, rhs: Attribute) -> Attributes {
184         match rhs {
185             Attribute::AlternativeCharSet => self.set_alternative_char_set(false),
186             Attribute::Bold => self.set_bold(false),
187             Attribute::Blink => self.set_blink(false),
188             Attribute::CharText => self.set_char_text(false),
189             Attribute::Dim => self.set_dim(false),
190             Attribute::Leftline => self.set_leftline(false),
191             Attribute::Invisible => self.set_invisible(false),
192             Attribute::Italic => self.set_italic(false),
193             Attribute::Normal => (),
194             Attribute::Overline => self.set_overline(false),
195             Attribute::Reverse => self.set_reverse(false),
196             Attribute::Rightline => self.set_rightline(false),
197             Attribute::Strikeout => self.set_strikeout(false),
198             Attribute::Underline => self.set_underline(false),
199         }
200         self
201     }
202 }
203 
204 /// Implement the | operator for adding Attributes to Attributes
205 ///
206 /// # Example
207 ///
208 /// ```
209 /// use pancurses::{Attribute, Attributes};
210 ///
211 /// let mut attributes = Attributes::new() | Attribute::Bold;
212 /// let other = Attributes::new() | Attribute::Reverse;
213 /// attributes = attributes | other;
214 /// assert!(attributes.is_bold());
215 /// assert!(attributes.is_reverse());
216 /// assert!(!attributes.is_italic());
217 /// ```
218 impl BitOr for Attributes {
219     type Output = Attributes;
220 
bitor(self, rhs: Attributes) -> Attributes221     fn bitor(self, rhs: Attributes) -> Attributes {
222         Attributes {
223             raw: self.raw | rhs.raw,
224             color_pair: ColorPair(self.color_pair.0 | rhs.color_pair.0),
225         }
226     }
227 }
228 
229 /// Implement the ^ operator for removing Attributes from Attributes
230 ///
231 /// # Example
232 ///
233 /// ```
234 /// use pancurses::{Attribute, Attributes};
235 ///
236 /// let mut attributes = Attributes::new() | Attribute::Blink | Attribute::Bold;
237 /// let other = Attributes::new() | Attribute::Reverse | Attribute::Bold;
238 /// attributes = attributes ^ other;
239 /// assert!(!attributes.is_bold());
240 /// assert!(attributes.is_reverse());
241 /// assert!(attributes.is_blink());
242 /// ```
243 impl BitXor for Attributes {
244     type Output = Attributes;
245 
bitxor(self, rhs: Attributes) -> Attributes246     fn bitxor(self, rhs: Attributes) -> Attributes {
247         Attributes {
248             raw: self.raw ^ rhs.raw,
249             color_pair: ColorPair(self.color_pair.0 ^ rhs.color_pair.0),
250         }
251     }
252 }
253 
254 /// Implement the | operator for combining two 'Attribute's into Attributes
255 ///
256 /// # Example
257 ///
258 /// ```
259 /// use pancurses::{Attribute, Attributes};
260 ///
261 /// let attributes = Attribute::Blink | Attribute::Reverse;
262 /// assert!(!attributes.is_bold());
263 /// assert!(attributes.is_blink());
264 /// assert!(attributes.is_reverse());
265 /// ```
266 impl BitOr for Attribute {
267     type Output = Attributes;
268 
bitor(self, rhs: Attribute) -> Attributes269     fn bitor(self, rhs: Attribute) -> Attributes {
270         Attributes::new() | self | rhs
271     }
272 }
273 
274 /// Implement Default for Attributes
275 ///
276 /// # Example
277 ///
278 /// ```
279 /// use pancurses::Attributes;
280 /// let attributes: Attributes = Default::default();
281 /// assert_eq!(attributes, Attributes::new());
282 /// ```
283 impl Default for Attributes {
default() -> Self284     fn default() -> Self {
285         Self::new()
286     }
287 }
288 
289 impl From<Attribute> for Attributes {
from(attribute: Attribute) -> Attributes290     fn from(attribute: Attribute) -> Attributes {
291         Attributes::new() | attribute
292     }
293 }
294 
295 impl From<Attribute> for chtype {
from(attribute: Attribute) -> chtype296     fn from(attribute: Attribute) -> chtype {
297         chtype::from(Attributes::from(attribute))
298     }
299 }
300 
301 impl From<Attributes> for chtype {
from(attributes: Attributes) -> chtype302     fn from(attributes: Attributes) -> chtype {
303         attributes.raw
304     }
305 }
306