src/components/canvas.rs (65 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under both the MIT license found in the * LICENSE-MIT file in the root directory of this source tree and the Apache * License, Version 2.0 found in the LICENSE-APACHE file in the root directory * of this source tree. */ //! The root component which manages all other components. //! This is a fake component since it 1) manages state and 2) cannot be made by users and 3) is heavily coupled with [`superconsole`](crate::SuperConsole). //! Do not make this somewhere down the component hierarchy unless you have a good reason for it. use std::{cell::Cell, convert::TryInto}; use crossterm::{ cursor::{MoveToColumn, MoveUp}, queue, terminal::{Clear, ClearType}, }; use crate::{ components::{Blank, Dimensions, DrawMode}, Component, Line, State, }; /// The root components which manages all other components. #[derive(Debug)] pub(crate) struct Canvas { child: Box<dyn Component>, // used to overwrite previous canvas buffer len: Cell<u16>, } impl Default for Canvas { fn default() -> Self { Self { child: Box::new(Blank), len: Cell::default(), } } } impl Component for Canvas { /// A passthrough method that resizes the Canvas to reflect the size of the root. /// Allows dynamic resizing. /// Cuts off any lines that are too for long a single row fn draw_unchecked( &self, state: &State, dimensions: Dimensions, mode: DrawMode, ) -> anyhow::Result<Vec<Line>> { let output = self.child.draw(state, dimensions, mode)?; self.set_last_canvas_size(output.len())?; Ok(output) } } impl Canvas { /// Canvas only has a single child. /// It essentially functions as a passthrough - an invisible window which handles sizing and re-drawing correctly. pub(crate) fn new(child: Box<dyn Component>) -> Self { Self { child, ..Default::default() } } /// The first half of drawing. It moves the buffer up to be overwritten and sets the length to 0. /// This is used to clear the scratch area so that any possibly emitted messages can write over it. pub(crate) fn move_up(&self, writer: &mut Vec<u8>) -> anyhow::Result<()> { let len = self.len.take(); queue!(writer, MoveUp(len), MoveToColumn(0),)?; Ok(()) } /// Clears the canvas. pub fn clear(&self, writer: &mut Vec<u8>) -> anyhow::Result<()> { self.move_up(writer)?; queue!(writer, Clear(ClearType::FromCursorDown),)?; Ok(()) } /// helper method that downcasts a usize canvas size to u16 fn set_last_canvas_size(&self, new_size: usize) -> anyhow::Result<()> { self.len.set(new_size.try_into()?); Ok(()) } }