bracket_terminal/consoles/
command_buffer.rs

1// This package implements an alternate style of drawing to the console,
2// designed to be used safely from within ECS systems in a potentially
3// multi-threaded environment.
4
5use crate::prelude::{BTerm, FontCharType, TextAlign};
6use crate::BResult;
7use bracket_color::prelude::{ColorPair, RGBA};
8use bracket_geometry::prelude::{Point, PointF, Radians, Rect};
9use object_pool::{Pool, Reusable};
10use parking_lot::Mutex;
11use std::convert::TryInto;
12use std::sync::Arc;
13
14lazy_static! {
15    static ref COMMAND_BUFFER: Mutex<Vec<(usize, Vec<DrawCommand>)>> =
16        Mutex::new(Vec::with_capacity(100));
17}
18
19lazy_static! {
20    static ref BUFFER_POOL: Arc<Pool<DrawBatch>> = Arc::new(Pool::new(128, || DrawBatch {
21        batch: Vec::with_capacity(5000),
22        z_count: 0,
23        needs_sort: false
24    }));
25}
26
27/// Clears the global command buffer. This is called internally by BTerm at the end of each
28/// frame. You really shouldn't need to call this yourself.
29pub fn clear_command_buffer() -> BResult<()> {
30    COMMAND_BUFFER.lock().clear();
31    Ok(())
32}
33
34/// Represents a buffered drawing command that can be asynchronously submitted to the drawing
35/// buffer, for application at the end of the frame.
36#[derive(Clone)]
37pub enum DrawCommand {
38    ClearScreen,
39    ClearToColor {
40        color: RGBA,
41    },
42    SetTarget {
43        console: usize,
44    },
45    Set {
46        pos: Point,
47        color: ColorPair,
48        glyph: FontCharType,
49    },
50    SetBackground {
51        pos: Point,
52        bg: RGBA,
53    },
54    Print {
55        pos: Point,
56        text: String,
57    },
58    PrintColor {
59        pos: Point,
60        text: String,
61        color: ColorPair,
62    },
63    PrintRight {
64        pos: Point,
65        text: String,
66    },
67    PrintColorRight {
68        pos: Point,
69        text: String,
70        color: ColorPair,
71    },
72    PrintCentered {
73        y: i32,
74        text: String,
75    },
76    PrintColorCentered {
77        y: i32,
78        text: String,
79        color: ColorPair,
80    },
81    PrintCenteredAt {
82        pos: Point,
83        text: String,
84    },
85    PrintColorCenteredAt {
86        pos: Point,
87        text: String,
88        color: ColorPair,
89    },
90    Printer {
91        pos: Point,
92        text: String,
93        align: TextAlign,
94        background: Option<RGBA>,
95    },
96    Box {
97        pos: Rect,
98        color: ColorPair,
99    },
100    HollowBox {
101        pos: Rect,
102        color: ColorPair,
103    },
104    DoubleBox {
105        pos: Rect,
106        color: ColorPair,
107    },
108    HollowDoubleBox {
109        pos: Rect,
110        color: ColorPair,
111    },
112    FillRegion {
113        pos: Rect,
114        color: ColorPair,
115        glyph: FontCharType,
116    },
117    BarHorizontal {
118        pos: Point,
119        width: i32,
120        n: i32,
121        max: i32,
122        color: ColorPair,
123    },
124    BarVertical {
125        pos: Point,
126        height: i32,
127        n: i32,
128        max: i32,
129        color: ColorPair,
130    },
131    SetClipping {
132        clip: Option<Rect>,
133    },
134    SetFgAlpha {
135        alpha: f32,
136    },
137    SetBgAlpha {
138        alpha: f32,
139    },
140    SetAllAlpha {
141        fg: f32,
142        bg: f32,
143    },
144    SetFancy {
145        position: PointF,
146        z_order: i32,
147        rotation: Radians,
148        color: ColorPair,
149        glyph: FontCharType,
150        scale: PointF,
151    },
152}
153
154/// Represents a batch of drawing commands, designed to be submitted together.
155pub struct DrawBatch {
156    batch: Vec<(u32, DrawCommand)>,
157    z_count: u32,
158    needs_sort: bool,
159}
160
161impl DrawBatch {
162    /// Obtain a new, empty draw batch
163    pub fn new() -> Reusable<'static, DrawBatch> {
164        let mut result = BUFFER_POOL.pull(|| panic!("No pooling!"));
165        result.z_count = 0;
166        result.needs_sort = false;
167        result
168    }
169
170    fn next_z(&mut self) -> u32 {
171        let result = self.z_count;
172        self.z_count += 1;
173        result
174    }
175
176    /// Submits a batch to the global drawing buffer, and empties the batch.
177    pub fn submit(&mut self, z_order: usize) -> BResult<()> {
178        if self.needs_sort {
179            self.batch.sort_by(|a, b| a.0.cmp(&b.0));
180        }
181        let mut new_batch = Vec::with_capacity(self.batch.len());
182        self.batch.drain(0..).for_each(|(_, b)| new_batch.push(b));
183        COMMAND_BUFFER.lock().push((z_order, new_batch));
184        Ok(())
185    }
186
187    /// Adds a CLS (clear screen) to the drawing batch
188    pub fn cls(&mut self) -> &mut Self {
189        let z = self.next_z();
190        self.batch.push((z, DrawCommand::ClearScreen));
191        self
192    }
193
194    /// Adds a CLS (clear screen) to the drawing batch
195    pub fn cls_color<COLOR>(&mut self, color: COLOR) -> &mut Self
196    where
197        COLOR: Into<RGBA>,
198    {
199        let z = self.next_z();
200        self.batch.push((
201            z,
202            DrawCommand::ClearToColor {
203                color: color.into(),
204            },
205        ));
206        self
207    }
208
209    /// Sets the target console for rendering
210    pub fn target(&mut self, console: usize) -> &mut Self {
211        let z = self.next_z();
212        self.batch.push((z, DrawCommand::SetTarget { console }));
213        self
214    }
215
216    /// Sets an individual cell glyph
217    pub fn set<G: TryInto<FontCharType>>(
218        &mut self,
219        pos: Point,
220        color: ColorPair,
221        glyph: G,
222    ) -> &mut Self {
223        let z = self.next_z();
224        self.batch.push((
225            z,
226            DrawCommand::Set {
227                pos,
228                color,
229                glyph: glyph.try_into().ok().expect("Must be u16 convertible"),
230            },
231        ));
232        self
233    }
234
235    /// Sets an individual cell glyph with a specified ordering within the batch
236    pub fn set_with_z<G: TryInto<FontCharType>>(
237        &mut self,
238        pos: Point,
239        color: ColorPair,
240        glyph: G,
241        z: u32,
242    ) -> &mut Self {
243        self.batch.push((
244            z,
245            DrawCommand::Set {
246                pos,
247                color,
248                glyph: glyph.try_into().ok().expect("Must be u16 convertible"),
249            },
250        ));
251        self.needs_sort = true;
252        self
253    }
254
255    /// Pushes a fancy terminal character
256    pub fn set_fancy<ANGLE: Into<Radians>, Z: TryInto<i32>, G: TryInto<FontCharType>>(
257        &mut self,
258        position: PointF,
259        z_order: Z,
260        rotation: ANGLE,
261        scale: PointF,
262        color: ColorPair,
263        glyph: G,
264    ) -> &mut Self {
265        let z = self.next_z();
266        self.batch.push((
267            z,
268            DrawCommand::SetFancy {
269                position,
270                z_order: z_order.try_into().ok().expect("Must be i32 convertible"),
271                rotation: rotation.into(),
272                color,
273                glyph: glyph.try_into().ok().expect("Must be u16 convertible"),
274                scale,
275            },
276        ));
277        self
278    }
279
280    /// Sets an individual cell glyph
281    pub fn set_bg<COLOR>(&mut self, pos: Point, bg: COLOR) -> &mut Self
282    where
283        COLOR: Into<RGBA>,
284    {
285        let z = self.next_z();
286        self.batch
287            .push((z, DrawCommand::SetBackground { pos, bg: bg.into() }));
288        self
289    }
290
291    /// Sets an individual cell glyph with specified render order
292    pub fn set_bg_with_z<COLOR>(&mut self, pos: Point, bg: COLOR, z: u32) -> &mut Self
293    where
294        COLOR: Into<RGBA>,
295    {
296        self.batch
297            .push((z, DrawCommand::SetBackground { pos, bg: bg.into() }));
298        self.needs_sort = true;
299        self
300    }
301
302    /// Prints formatted text, using the doryen_rs convention. For example:
303    /// "#[blue]This blue text contains a #[pink]pink#[] word"
304    pub fn printer<S: ToString>(
305        &mut self,
306        pos: Point,
307        text: S,
308        align: TextAlign,
309        background: Option<RGBA>,
310    ) -> &mut Self {
311        let z = self.next_z();
312        self.batch.push((
313            z,
314            DrawCommand::Printer {
315                pos,
316                text: text.to_string(),
317                align,
318                background,
319            },
320        ));
321        self
322    }
323
324    /// Prints formatted text, using the doryen_rs convention. For example:
325    /// "#[blue]This blue text contains a #[pink]pink#[] word"
326    /// You can specify the render order.
327    pub fn printer_with_z<S: ToString>(
328        &mut self,
329        pos: Point,
330        text: S,
331        align: TextAlign,
332        background: Option<RGBA>,
333        z: u32,
334    ) -> &mut Self {
335        self.batch.push((
336            z,
337            DrawCommand::Printer {
338                pos,
339                text: text.to_string(),
340                align,
341                background,
342            },
343        ));
344        self.needs_sort = true;
345        self
346    }
347
348    /// Prints text in the default colors at a given location
349    pub fn print<S: ToString>(&mut self, pos: Point, text: S) -> &mut Self {
350        let z = self.next_z();
351        self.batch.push((
352            z,
353            DrawCommand::Print {
354                pos,
355                text: text.to_string(),
356            },
357        ));
358        self
359    }
360
361    /// Prints text in the default colors at a given location & render order
362    pub fn print_with_z<S: ToString>(&mut self, pos: Point, text: S, z: u32) -> &mut Self {
363        self.batch.push((
364            z,
365            DrawCommand::Print {
366                pos,
367                text: text.to_string(),
368            },
369        ));
370        self.needs_sort = true;
371        self
372    }
373
374    /// Prints text in the default colors at a given location
375    pub fn print_color<S: ToString>(&mut self, pos: Point, text: S, color: ColorPair) -> &mut Self {
376        let z = self.next_z();
377        self.batch.push((
378            z,
379            DrawCommand::PrintColor {
380                pos,
381                text: text.to_string(),
382                color,
383            },
384        ));
385        self
386    }
387
388    /// Prints text in the default colors at a given location & render order
389    pub fn print_color_with_z<S: ToString>(
390        &mut self,
391        pos: Point,
392        text: S,
393        color: ColorPair,
394        z: u32,
395    ) -> &mut Self {
396        self.batch.push((
397            z,
398            DrawCommand::PrintColor {
399                pos,
400                text: text.to_string(),
401                color,
402            },
403        ));
404        self.needs_sort = true;
405        self
406    }
407
408    /// Prints text, centered to the whole console width, at vertical location y.
409    pub fn print_centered<S: ToString, Y: TryInto<i32>>(&mut self, y: Y, text: S) -> &mut Self {
410        let z = self.next_z();
411        self.batch.push((
412            z,
413            DrawCommand::PrintCentered {
414                y: y.try_into().ok().expect("Must be i32 convertible"),
415                text: text.to_string(),
416            },
417        ));
418        self
419    }
420
421    /// Prints text, centered to the whole console width, at vertical location y.
422    pub fn print_centered_with_z<S: ToString, Y: TryInto<i32>>(
423        &mut self,
424        y: Y,
425        text: S,
426        z: u32,
427    ) -> &mut Self {
428        self.batch.push((
429            z,
430            DrawCommand::PrintCentered {
431                y: y.try_into().ok().expect("Must be i32 convertible"),
432                text: text.to_string(),
433            },
434        ));
435        self.needs_sort = true;
436        self
437    }
438
439    /// Prints text, centered to the whole console width, at vertical location y.
440    pub fn print_color_centered<S: ToString, Y: TryInto<i32>>(
441        &mut self,
442        y: Y,
443        text: S,
444        color: ColorPair,
445    ) -> &mut Self {
446        let z = self.next_z();
447        self.batch.push((
448            z,
449            DrawCommand::PrintColorCentered {
450                y: y.try_into().ok().expect("Must be i32 convertible"),
451                text: text.to_string(),
452                color,
453            },
454        ));
455        self
456    }
457
458    /// Prints text, centered to the whole console width, at vertical location y.
459    pub fn print_color_centered_with_z<S: ToString, Y: TryInto<i32>>(
460        &mut self,
461        y: Y,
462        text: S,
463        color: ColorPair,
464        z: u32,
465    ) -> &mut Self {
466        self.batch.push((
467            z,
468            DrawCommand::PrintColorCentered {
469                y: y.try_into().ok().expect("Must be i32 convertible"),
470                text: text.to_string(),
471                color,
472            },
473        ));
474        self.needs_sort = true;
475        self
476    }
477
478    /// Prints text, centered to the whole console width, at vertical location y.
479    pub fn print_centered_at<S: ToString>(&mut self, pos: Point, text: S) -> &mut Self {
480        let z = self.next_z();
481        self.batch.push((
482            z,
483            DrawCommand::PrintCenteredAt {
484                pos,
485                text: text.to_string(),
486            },
487        ));
488        self
489    }
490
491    /// Prints text, centered to the whole console width, at vertical location y with render order.
492    pub fn print_centered_at_with_z<S: ToString>(
493        &mut self,
494        pos: Point,
495        text: S,
496        z: u32,
497    ) -> &mut Self {
498        self.batch.push((
499            z,
500            DrawCommand::PrintCenteredAt {
501                pos,
502                text: text.to_string(),
503            },
504        ));
505        self.needs_sort = true;
506        self
507    }
508
509    /// Prints text, centered to the whole console width, at vertical location y.
510    pub fn print_color_centered_at<S: ToString>(
511        &mut self,
512        pos: Point,
513        text: S,
514        color: ColorPair,
515    ) -> &mut Self {
516        let z = self.next_z();
517        self.batch.push((
518            z,
519            DrawCommand::PrintColorCenteredAt {
520                pos,
521                text: text.to_string(),
522                color,
523            },
524        ));
525        self
526    }
527
528    /// Prints text, centered to the whole console width, at vertical location y with render order.
529    pub fn print_color_centered_at_with_z<S: ToString>(
530        &mut self,
531        pos: Point,
532        text: S,
533        color: ColorPair,
534        z: u32,
535    ) -> &mut Self {
536        self.batch.push((
537            z,
538            DrawCommand::PrintColorCenteredAt {
539                pos,
540                text: text.to_string(),
541                color,
542            },
543        ));
544        self.needs_sort = true;
545        self
546    }
547
548    /// Prints right aligned text
549    pub fn print_right<S: ToString>(&mut self, pos: Point, text: S) -> &mut Self {
550        let z = self.next_z();
551        self.batch.push((
552            z,
553            DrawCommand::PrintRight {
554                pos,
555                text: text.to_string(),
556            },
557        ));
558        self
559    }
560
561    /// Prints right aligned text with render order
562    pub fn print_right_z<S: ToString>(&mut self, pos: Point, text: S, z: u32) -> &mut Self {
563        self.batch.push((
564            z,
565            DrawCommand::PrintRight {
566                pos,
567                text: text.to_string(),
568            },
569        ));
570        self.needs_sort = true;
571        self
572    }
573
574    /// Prints right aligned text
575    pub fn print_color_right<S: ToString>(
576        &mut self,
577        pos: Point,
578        text: S,
579        color: ColorPair,
580    ) -> &mut Self {
581        let z = self.next_z();
582        self.batch.push((
583            z,
584            DrawCommand::PrintColorRight {
585                pos,
586                text: text.to_string(),
587                color,
588            },
589        ));
590        self
591    }
592
593    /// Prints right aligned text with render order
594    pub fn print_color_right_with_z<S: ToString>(
595        &mut self,
596        pos: Point,
597        text: S,
598        color: ColorPair,
599        z: u32,
600    ) -> &mut Self {
601        self.batch.push((
602            z,
603            DrawCommand::PrintColorRight {
604                pos,
605                text: text.to_string(),
606                color,
607            },
608        ));
609        self.needs_sort = true;
610        self
611    }
612
613    /// Draws a box, starting at x/y with the extents width/height using CP437 line characters
614    pub fn draw_box(&mut self, pos: Rect, color: ColorPair) -> &mut Self {
615        let z = self.next_z();
616        self.batch.push((z, DrawCommand::Box { pos, color }));
617        self
618    }
619
620    /// Draws a box, starting at x/y with the extents width/height using CP437 line characters. With render order.
621    pub fn draw_box_with_z(&mut self, pos: Rect, color: ColorPair, z: u32) -> &mut Self {
622        self.batch.push((z, DrawCommand::Box { pos, color }));
623        self.needs_sort = true;
624        self
625    }
626
627    /// Draws a non-filled (hollow) box, starting at x/y with the extents width/height using CP437 line characters
628    pub fn draw_hollow_box(&mut self, pos: Rect, color: ColorPair) -> &mut Self {
629        let z = self.next_z();
630        self.batch.push((z, DrawCommand::HollowBox { pos, color }));
631        self
632    }
633
634    /// Draws a non-filled (hollow) box, starting at x/y with the extents width/height using CP437 line characters. With render order.
635    pub fn draw_hollow_box_with_z(&mut self, pos: Rect, color: ColorPair, z: u32) -> &mut Self {
636        self.batch.push((z, DrawCommand::HollowBox { pos, color }));
637        self.needs_sort = true;
638        self
639    }
640
641    /// Draws a double-lined box, starting at x/y with the extents width/height using CP437 line characters
642    pub fn draw_double_box(&mut self, pos: Rect, color: ColorPair) -> &mut Self {
643        let z = self.next_z();
644        self.batch.push((z, DrawCommand::DoubleBox { pos, color }));
645        self
646    }
647
648    /// Draws a double-lined box, starting at x/y with the extents width/height using CP437 line characters
649    pub fn draw_double_box_with_z(&mut self, pos: Rect, color: ColorPair, z: u32) -> &mut Self {
650        self.batch.push((z, DrawCommand::DoubleBox { pos, color }));
651        self.needs_sort = true;
652        self
653    }
654
655    /// Draws a non-filled (hollow) double-lined box, starting at x/y with the extents width/height using CP437 line characters
656    pub fn draw_hollow_double_box(&mut self, pos: Rect, color: ColorPair) -> &mut Self {
657        let z = self.next_z();
658        self.batch
659            .push((z, DrawCommand::HollowDoubleBox { pos, color }));
660        self
661    }
662
663    /// Draws a non-filled (hollow) double-lined box, starting at x/y with the extents width/height using CP437 line characters
664    pub fn draw_hollow_double_box_with_z(
665        &mut self,
666        pos: Rect,
667        color: ColorPair,
668        z: u32,
669    ) -> &mut Self {
670        self.batch
671            .push((z, DrawCommand::HollowDoubleBox { pos, color }));
672        self.needs_sort = true;
673        self
674    }
675
676    /// Fills a region with a glyph/color combination.
677    pub fn fill_region<G: TryInto<FontCharType>>(
678        &mut self,
679        pos: Rect,
680        color: ColorPair,
681        glyph: G,
682    ) -> &mut Self {
683        let z = self.next_z();
684        self.batch.push((
685            z,
686            DrawCommand::FillRegion {
687                pos,
688                color,
689                glyph: glyph.try_into().ok().expect("Must be u16 convertible"),
690            },
691        ));
692        self
693    }
694
695    /// Fills a region with a glyph/color combination.
696    pub fn fill_region_with_z<G: TryInto<FontCharType>>(
697        &mut self,
698        pos: Rect,
699        color: ColorPair,
700        glyph: G,
701        z: u32,
702    ) -> &mut Self {
703        self.batch.push((
704            z,
705            DrawCommand::FillRegion {
706                pos,
707                color,
708                glyph: glyph.try_into().ok().expect("Must be u16 convertible"),
709            },
710        ));
711        self.needs_sort = true;
712        self
713    }
714
715    /// Draw a horizontal progress bar
716    pub fn bar_horizontal<W, N, MAX>(
717        &mut self,
718        pos: Point,
719        width: W,
720        n: N,
721        max: MAX,
722        color: ColorPair,
723    ) -> &mut Self
724    where
725        W: TryInto<i32>,
726        N: TryInto<i32>,
727        MAX: TryInto<i32>,
728    {
729        let z = self.next_z();
730        self.batch.push((
731            z,
732            DrawCommand::BarHorizontal {
733                pos,
734                width: width.try_into().ok().expect("Must be i32 convertible"),
735                n: n.try_into().ok().expect("Must be i32 convertible"),
736                max: max.try_into().ok().expect("Must be i32 convertible"),
737                color,
738            },
739        ));
740        self
741    }
742
743    /// Draw a horizontal progress bar
744    pub fn bar_horizontal_with_z<W, N, MAX>(
745        &mut self,
746        pos: Point,
747        width: W,
748        n: N,
749        max: MAX,
750        color: ColorPair,
751        z: u32,
752    ) -> &mut Self
753    where
754        W: TryInto<i32>,
755        N: TryInto<i32>,
756        MAX: TryInto<i32>,
757    {
758        self.batch.push((
759            z,
760            DrawCommand::BarHorizontal {
761                pos,
762                width: width.try_into().ok().expect("Must be i32 convertible"),
763                n: n.try_into().ok().expect("Must be i32 convertible"),
764                max: max.try_into().ok().expect("Must be i32 convertible"),
765                color,
766            },
767        ));
768        self.needs_sort = true;
769        self
770    }
771
772    /// Draw a horizontal progress bar
773    pub fn bar_vertical<H, N, MAX>(
774        &mut self,
775        pos: Point,
776        height: H,
777        n: N,
778        max: MAX,
779        color: ColorPair,
780    ) -> &mut Self
781    where
782        H: TryInto<i32>,
783        N: TryInto<i32>,
784        MAX: TryInto<i32>,
785    {
786        let z = self.next_z();
787        self.batch.push((
788            z,
789            DrawCommand::BarVertical {
790                pos,
791                height: height.try_into().ok().expect("Must be i32 convertible"),
792                n: n.try_into().ok().expect("Must be i32 convertible"),
793                max: max.try_into().ok().expect("Must be i32 convertible"),
794                color,
795            },
796        ));
797        self
798    }
799
800    /// Draw a horizontal progress bar
801    pub fn bar_vertical_with_z<H, N, MAX>(
802        &mut self,
803        pos: Point,
804        height: H,
805        n: N,
806        max: MAX,
807        color: ColorPair,
808        z: u32,
809    ) -> &mut Self
810    where
811        H: TryInto<i32>,
812        N: TryInto<i32>,
813        MAX: TryInto<i32>,
814    {
815        self.batch.push((
816            z,
817            DrawCommand::BarVertical {
818                pos,
819                height: height.try_into().ok().expect("Must be i32 convertible"),
820                n: n.try_into().ok().expect("Must be i32 convertible"),
821                max: max.try_into().ok().expect("Must be i32 convertible"),
822                color,
823            },
824        ));
825        self.needs_sort = true;
826        self
827    }
828
829    /// Sets a clipping rectangle for the current console
830    pub fn set_clipping(&mut self, clip: Option<Rect>) -> &mut Self {
831        let z = self.next_z();
832        self.batch.push((z, DrawCommand::SetClipping { clip }));
833        self
834    }
835
836    /// Apply an alpha channel value to all cells' foregrounds in the current terminal.
837    pub fn set_all_fg_alpha(&mut self, alpha: f32) -> &mut Self {
838        let z = self.next_z();
839        self.batch.push((z, DrawCommand::SetFgAlpha { alpha }));
840        self
841    }
842
843    /// Apply an alpha channel value to all cells' backgrounds in the current terminal.
844    pub fn set_all_bg_alpha(&mut self, alpha: f32) -> &mut Self {
845        let z = self.next_z();
846        self.batch.push((z, DrawCommand::SetBgAlpha { alpha }));
847        self
848    }
849
850    /// Apply fg/bg alpha channel values to all cells in the current terminal.
851    pub fn set_all_alpha(&mut self, fg: f32, bg: f32) -> &mut Self {
852        let z = self.next_z();
853        self.batch.push((z, DrawCommand::SetAllAlpha { fg, bg }));
854        self
855    }
856}
857
858/// Submits the current batch to the BTerm buffer and empties it
859pub fn render_draw_buffer(bterm: &mut BTerm) -> BResult<()> {
860    let mut buffer = COMMAND_BUFFER.lock();
861    buffer.sort_unstable_by(|a, b| a.0.cmp(&b.0));
862    buffer.iter().for_each(|(_, batch)| {
863        batch.iter().for_each(|cmd| match cmd {
864            DrawCommand::ClearScreen => bterm.cls(),
865            DrawCommand::ClearToColor { color } => bterm.cls_bg(*color),
866            DrawCommand::SetTarget { console } => bterm.set_active_console(*console),
867            DrawCommand::Set { pos, color, glyph } => {
868                bterm.set(pos.x, pos.y, color.fg, color.bg, *glyph)
869            }
870            DrawCommand::SetBackground { pos, bg } => bterm.set_bg(pos.x, pos.y, *bg),
871            DrawCommand::Print { pos, text } => bterm.print(pos.x, pos.y, &text),
872            DrawCommand::PrintColor { pos, text, color } => {
873                bterm.print_color(pos.x, pos.y, color.fg, color.bg, &text)
874            }
875            DrawCommand::PrintCentered { y, text } => bterm.print_centered(*y, &text),
876            DrawCommand::PrintColorCentered { y, text, color } => {
877                bterm.print_color_centered(*y, color.fg, color.bg, &text)
878            }
879            DrawCommand::PrintCenteredAt { pos, text } => {
880                bterm.print_centered_at(pos.x, pos.y, &text)
881            }
882            DrawCommand::PrintColorCenteredAt { pos, text, color } => {
883                bterm.print_color_centered_at(pos.x, pos.y, color.fg, color.bg, &text)
884            }
885            DrawCommand::PrintRight { pos, text } => bterm.print_right(pos.x, pos.y, text),
886            DrawCommand::PrintColorRight { pos, text, color } => {
887                bterm.print_color_right(pos.x, pos.y, color.fg, color.bg, text)
888            }
889            DrawCommand::Printer {
890                pos,
891                text,
892                align,
893                background,
894            } => bterm.printer(pos.x, pos.y, text, *align, *background),
895            DrawCommand::Box { pos, color } => bterm.draw_box(
896                pos.x1,
897                pos.y1,
898                pos.width(),
899                pos.height(),
900                color.fg,
901                color.bg,
902            ),
903            DrawCommand::HollowBox { pos, color } => bterm.draw_hollow_box(
904                pos.x1,
905                pos.y1,
906                pos.width(),
907                pos.height(),
908                color.fg,
909                color.bg,
910            ),
911            DrawCommand::DoubleBox { pos, color } => bterm.draw_box_double(
912                pos.x1,
913                pos.y1,
914                pos.width(),
915                pos.height(),
916                color.fg,
917                color.bg,
918            ),
919            DrawCommand::HollowDoubleBox { pos, color } => bterm.draw_hollow_box_double(
920                pos.x1,
921                pos.y1,
922                pos.width(),
923                pos.height(),
924                color.fg,
925                color.bg,
926            ),
927            DrawCommand::FillRegion { pos, color, glyph } => {
928                bterm.fill_region::<RGBA, RGBA, FontCharType>(*pos, *glyph, color.fg, color.bg)
929            }
930            DrawCommand::BarHorizontal {
931                pos,
932                width,
933                n,
934                max,
935                color,
936            } => bterm.draw_bar_horizontal(pos.x, pos.y, *width, *n, *max, color.fg, color.bg),
937            DrawCommand::BarVertical {
938                pos,
939                height,
940                n,
941                max,
942                color,
943            } => bterm.draw_bar_vertical(pos.x, pos.y, *height, *n, *max, color.fg, color.bg),
944            DrawCommand::SetClipping { clip } => bterm.set_clipping(*clip),
945            DrawCommand::SetFgAlpha { alpha } => bterm.set_all_fg_alpha(*alpha),
946            DrawCommand::SetBgAlpha { alpha } => bterm.set_all_fg_alpha(*alpha),
947            DrawCommand::SetAllAlpha { fg, bg } => bterm.set_all_alpha(*fg, *bg),
948            DrawCommand::SetFancy {
949                position,
950                z_order,
951                color,
952                glyph,
953                rotation,
954                scale,
955            } => {
956                bterm.set_fancy(
957                    *position, *z_order, *rotation, *scale, color.fg, color.bg, *glyph,
958                );
959            }
960        })
961    });
962    buffer.clear();
963    Ok(())
964}