doryen_extra/
extenders.rs

1/* BSD 3-Clause License
2 *
3 * Copyright © 2019, Alexander Krivács Schrøder <alexschrod@gmail.com>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 *    this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 *    this list of conditions and the following disclaimer in the documentation
14 *    and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the copyright holder nor the names of its
17 *    contributors may be used to endorse or promote products derived from
18 *    this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33//! # Extenders for doryen-rs types.
34
35use crate::color::Color;
36use crate::{Position, Rectangle, USize};
37use doryen_rs::{Console, TextAlign};
38use ilyvion_util::ownership::Borrowned;
39use std::borrow::{Borrow, BorrowMut};
40use std::ops::{Deref, DerefMut};
41
42/// Extends the `Console` from `doryen-rs`.
43///
44/// Replaces most instances of x/y and w/h with `Position` and `USize` respectively, and makes use
45/// of `doryen-extra`'s `Color` type rather than `doryen-rs`'. Since the `ConsoleExtender` derefs
46/// to `Console`, it lets you both use the replaced/extended methods and the underlying methods
47/// that were not replaced with ease.
48#[allow(missing_debug_implementations)] // Console doesn't implement Debug
49pub struct ConsoleExtender<'b> {
50    console: Borrowned<'b, Console>,
51}
52
53impl<'b> ConsoleExtender<'b> {
54    /// Wraps the mutably borrowed console.
55    pub fn extend(console: &'b mut Console) -> Self {
56        Self {
57            console: Borrowned::Borrowed(console),
58        }
59    }
60
61    /// Creates a new offscreen console that you can blit on another console.
62    /// Size is in cells (characters), not pixels.
63    pub fn new(size: USize) -> Self {
64        Self {
65            console: Borrowned::Owned(Console::new(size.width, size.height)),
66        }
67    }
68
69    /// Wraps the owned console.
70    pub fn wrap(console: Console) -> Self {
71        Self {
72            console: Borrowned::Owned(console),
73        }
74    }
75}
76
77// The replaced methods
78impl ConsoleExtender<'_> {
79    /// Resizes the console.
80    pub fn resize(&mut self, size: USize) {
81        self.console.resize(size.width, size.height);
82    }
83
84    /// Associates a name with a color for this console.
85    pub fn register_color<S: AsRef<str>>(&mut self, name: S, value: Color) {
86        self.console.register_color(name.as_ref(), value.into());
87    }
88
89    /// Gets the background color of a cell.
90    pub fn back(&self, position: Position) -> Option<Color> {
91        self.console
92            .get_back(position.x, position.y)
93            .map(Into::into)
94    }
95
96    /// Gets the foreground color of a cell.
97    pub fn fore(&self, position: Position) -> Option<Color> {
98        self.console
99            .get_fore(position.x, position.y)
100            .map(Into::into)
101    }
102
103    /// Gets the ASCII code of a cell.
104    pub fn ascii(&self, position: Position) -> Option<u16> {
105        self.console.get_ascii(position.x, position.y)
106    }
107
108    /// Gets the background color of a cell with no boundary check.
109    pub fn back_unchecked(&self, position: Position) -> Color {
110        self.console.unsafe_get_back(position.x, position.y).into()
111    }
112
113    /// Gets the foreground color of a cell with no boundary check.
114    pub fn fore_unchecked(&self, position: Position) -> Color {
115        self.console.unsafe_get_fore(position.x, position.y).into()
116    }
117
118    /// Gets the ASCII code of a cell with no boundary check.
119    pub fn ascii_unchecked(&self, position: Position) -> u16 {
120        self.console.unsafe_get_ascii(position.x, position.y)
121    }
122
123    /// Sets the character at a specific position.
124    pub fn set_ascii(&mut self, position: Position, ascii: u16) {
125        self.console.ascii(position.x, position.y, ascii);
126    }
127
128    /// Sets the character color at a specific position.
129    pub fn set_fore(&mut self, position: Position, color: Color) {
130        self.console.fore(position.x, position.y, color.into());
131    }
132
133    /// Sets the background color at a specific position.
134    pub fn set_back(&mut self, position: Position, color: Color) {
135        self.console.back(position.x, position.y, color.into());
136    }
137
138    /// Sets the character at a specific position with no boundary check.
139    pub fn set_ascii_unchecked(&mut self, position: Position, ascii: u16) {
140        self.console.unsafe_ascii(position.x, position.y, ascii);
141    }
142
143    /// Sets the character color at a specific position with no boundary check.
144    pub fn set_fore_unchecked(&mut self, position: Position, color: Color) {
145        self.console
146            .unsafe_fore(position.x, position.y, color.into());
147    }
148
149    /// Sets the background color at a specific position  with no boundary check
150    pub fn set_back_unchecked(&mut self, position: Position, color: Color) {
151        self.console
152            .unsafe_back(position.x, position.y, color.into());
153    }
154
155    /// Fills the whole console with values
156    pub fn clear(&mut self, fore: Option<Color>, back: Option<Color>, fill_char: Option<u16>) {
157        self.console
158            .clear(fore.map(Into::into), back.map(Into::into), fill_char);
159    }
160
161    /// Writes a multi-color string. Foreground color is defined by #[color_name] patterns inside the string.
162    pub fn print_color<S: AsRef<str>>(
163        &mut self,
164        position: Position,
165        text: S,
166        align: TextAlign,
167        back: Option<Color>,
168    ) {
169        self.console.print_color(
170            position.x,
171            position.y,
172            text.as_ref(),
173            align,
174            back.map(Into::into),
175        )
176    }
177
178    /// Compute the length of a string containing color codes.
179    pub fn text_color_len<S: AsRef<str>>(text: S) -> usize {
180        Console::text_color_len(text.as_ref())
181    }
182
183    /// Writes a string. If the string reaches the border of the console, it's truncated.
184    /// If the string contains carriage return `"\n"`, multiple lines are printed.
185    pub fn print<S: AsRef<str>>(
186        &mut self,
187        position: Position,
188        text: S,
189        align: TextAlign,
190        fore: Option<Color>,
191        back: Option<Color>,
192    ) {
193        self.console.print(
194            position.x,
195            position.y,
196            text.as_ref(),
197            align,
198            fore.map(Into::into),
199            back.map(Into::into),
200        );
201    }
202
203    /// Draws a rectangle, possibly filling it with a character.
204    pub fn rectangle(
205        &mut self,
206        rectangle: Rectangle,
207        fore: Option<Color>,
208        back: Option<Color>,
209        fill_char: Option<u16>,
210    ) {
211        self.console.rectangle(
212            rectangle.position.x,
213            rectangle.position.y,
214            rectangle.size.width,
215            rectangle.size.height,
216            fore.map(Into::into),
217            back.map(Into::into),
218            fill_char,
219        );
220    }
221
222    /// Fills an area with values.
223    pub fn area(
224        &mut self,
225        rectangle: Rectangle,
226        fore: Option<Color>,
227        back: Option<Color>,
228        fill_char: Option<u16>,
229    ) {
230        self.console.area(
231            rectangle.position.x,
232            rectangle.position.y,
233            rectangle.size.width,
234            rectangle.size.height,
235            fore.map(Into::into),
236            back.map(Into::into),
237            fill_char,
238        );
239    }
240
241    /// Changes all the properties of a console cell at once.
242    pub fn cell(
243        &mut self,
244        position: Position,
245        ascii: Option<u16>,
246        fore: Option<Color>,
247        back: Option<Color>,
248    ) {
249        self.console.cell(
250            position.x,
251            position.y,
252            ascii,
253            fore.map(Into::into),
254            back.map(Into::into),
255        );
256    }
257
258    /// Blits (draw) a console onto another one.
259    pub fn blit(
260        &self,
261        position: Position,
262        destination: &mut Console,
263        fore_alpha: f32,
264        back_alpha: f32,
265        key_color: Option<Color>,
266    ) {
267        self.console.blit(
268            position.x,
269            position.y,
270            destination,
271            fore_alpha,
272            back_alpha,
273            key_color.map(Into::into),
274        );
275    }
276
277    /// Blits a region of this console onto another one.
278    pub fn blit_ex(
279        &self,
280        source_rectangle: Rectangle,
281        destination: &mut Console,
282        destination_position: Position,
283        fore_alpha: f32,
284        back_alpha: f32,
285        key_color: Option<Color>,
286    ) {
287        self.console.blit_ex(
288            source_rectangle.position.x,
289            source_rectangle.position.y,
290            source_rectangle.size.width as i32,
291            source_rectangle.size.height as i32,
292            destination,
293            destination_position.x,
294            destination_position.y,
295            fore_alpha,
296            back_alpha,
297            key_color.map(Into::into),
298        );
299    }
300}
301
302// The extended methods
303impl ConsoleExtender<'_> {
304    /// Returns the size of the console.
305    pub fn get_size(&self) -> USize {
306        USize::new(self.console.get_width(), self.console.get_height())
307    }
308
309    /// Draws a rectangle, possibly filling it with a character, possibly with a title centered
310    /// at the top.
311    pub fn print_frame<S: AsRef<str>>(
312        &mut self,
313        rectangle: Rectangle,
314        fore: Option<Color>,
315        back: Option<Color>,
316        fill: Option<u16>,
317        title: Option<S>,
318    ) {
319        self.rectangle(rectangle, fore, back, fill);
320
321        if let Some(title) = title {
322            let text = format!(" {} ", title.as_ref());
323            let Rectangle {
324                position: Position { x, y },
325                size: USize { width: w, .. },
326            } = rectangle;
327            self.print(
328                Position::new(x + (w / 2) as i32, y),
329                &text,
330                TextAlign::Center,
331                fore.map(Into::into),
332                back.map(Into::into),
333            );
334        }
335    }
336
337    /// Prints the provided character to the give position.
338    pub fn print_char(
339        &mut self,
340        position: Position,
341        character: char,
342        fore: Option<Color>,
343        back: Option<Color>,
344    ) {
345        self.cell(position, Some(character as u16), fore, back);
346    }
347}
348
349impl Deref for ConsoleExtender<'_> {
350    type Target = Console;
351
352    fn deref(&self) -> &Self::Target {
353        self.console.deref()
354    }
355}
356
357impl DerefMut for ConsoleExtender<'_> {
358    fn deref_mut(&mut self) -> &mut Self::Target {
359        self.console.deref_mut()
360    }
361}
362
363impl Borrow<Console> for ConsoleExtender<'_> {
364    fn borrow(&self) -> &Console {
365        self.console.borrow()
366    }
367}
368
369impl BorrowMut<Console> for ConsoleExtender<'_> {
370    fn borrow_mut(&mut self) -> &mut Console {
371        self.console.borrow_mut()
372    }
373}
374
375impl AsRef<Console> for ConsoleExtender<'_> {
376    fn as_ref(&self) -> &Console {
377        self.console.as_ref()
378    }
379}
380
381impl AsMut<Console> for ConsoleExtender<'_> {
382    fn as_mut(&mut self) -> &mut Console {
383        self.console.as_mut()
384    }
385}