use std::time::Duration;
use crossterm::style::ContentStyle;
use serde::{Deserialize, Serialize};
use tortuise::script::Operation;
use crate::ScriptContext;
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct Cell {
pub character: char,
pub foreground_color: Color,
pub background_color: Color,
pub underline_color: Color,
pub attributes: Attributes,
pub x: u16,
pub y: u16,
pub z: u8,
}
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct WindowSize {
pub rows: u16,
pub columns: u16,
}
#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize,
)]
pub enum Color {
/// Resets the terminal color.
#[default]
Reset,
/// Black color.
Black,
/// Dark grey color.
DarkGrey,
/// Light red color.
Red,
/// Dark red color.
DarkRed,
/// Light green color.
Green,
/// Dark green color.
DarkGreen,
/// Light yellow color.
Yellow,
/// Dark yellow color.
DarkYellow,
/// Light blue color.
Blue,
/// Dark blue color.
DarkBlue,
/// Light magenta color.
Magenta,
/// Dark magenta color.
DarkMagenta,
/// Light cyan color.
Cyan,
/// Dark cyan color.
DarkCyan,
/// White color.
White,
/// Grey color.
Grey,
/// An RGB color. See [RGB color model](https://en.wikipedia.org/wiki/RGB_color_model) for more info.
///
/// Most UNIX terminals and Windows 10 supported only.
/// See [Platform-specific notes](enum.Color.html#platform-specific-notes) for more info.
Rgb { r: u8, g: u8, b: u8 },
/// An ANSI color. See [256 colors - cheat sheet](https://jonasjacek.github.io/colors/) for more info.
///
/// Most UNIX terminals and Windows 10 supported only.
/// See [Platform-specific notes](enum.Color.html#platform-specific-notes) for more info.
AnsiValue(u8),
}
#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize,
)]
pub struct Attributes(u32);
pub enum Attribute {
/// Increases the text intensity.
Bold = 1,
/// Decreases the text intensity.
Dim = 2,
/// Emphasises the text.
Italic = 4,
/// Underlines the text.
Underlined = 8,
// Other types of underlining
/// Double underlines the text.
DoubleUnderlined = 16,
/// Undercurls the text.
Undercurled = 32,
/// Underdots the text.
Underdotted = 64,
/// Underdashes the text.
Underdashed = 128,
/// Makes the text blinking (< 150 per minute).
SlowBlink = 256,
/// Makes the text blinking (>= 150 per minute).
RapidBlink = 512,
/// Swaps foreground and background colors.
Reverse = 1024,
/// Hides the text (also known as Conceal).
Hidden = 2048,
/// Crosses the text.
CrossedOut = 4096,
/// Sets the [Fraktur](https://en.wikipedia.org/wiki/Fraktur) typeface.
///
/// Mostly used for [mathematical alphanumeric symbols](https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols).
Fraktur = 8192,
/// Makes the text framed.
Framed = 16384,
/// Makes the text encircled.
Encircled = 32768,
/// Draws a line at the top of the text.
OverLined = 65536,
}
impl Attributes {
pub fn none() -> Self {
Self(0)
}
pub fn with(self, attribute: Attribute) -> Self {
Self(self.0 | attribute as u32)
}
pub fn without(self, attribute: Attribute) -> Self {
Self(self.0 & !(attribute as u32))
}
pub fn set(&mut self, attribute: Attribute) {
self.0 |= attribute as u32;
}
pub fn unset(&mut self, attribute: Attribute) {
self.0 &= !(attribute as u32)
}
pub fn has(self, attribute: Attribute) -> bool {
self.0 & (attribute as u32) != 0
}
pub fn extend(&mut self, attributes: Attributes) {
self.0 |= attributes.0
}
pub fn is_empty(self) -> bool {
self.0 == 0
}
}
impl From<Color> for crossterm::style::Color {
fn from(value: Color) -> Self {
match value {
Color::Reset => crossterm::style::Color::Reset,
Color::Black => crossterm::style::Color::Black,
Color::DarkGrey => crossterm::style::Color::DarkGrey,
Color::Red => crossterm::style::Color::Red,
Color::DarkRed => crossterm::style::Color::DarkRed,
Color::Green => crossterm::style::Color::Green,
Color::DarkGreen => crossterm::style::Color::DarkGreen,
Color::Yellow => crossterm::style::Color::Yellow,
Color::DarkYellow => crossterm::style::Color::DarkYellow,
Color::Blue => crossterm::style::Color::Blue,
Color::DarkBlue => crossterm::style::Color::DarkBlue,
Color::Magenta => crossterm::style::Color::Magenta,
Color::DarkMagenta => crossterm::style::Color::DarkMagenta,
Color::Cyan => crossterm::style::Color::Cyan,
Color::DarkCyan => crossterm::style::Color::DarkCyan,
Color::White => crossterm::style::Color::White,
Color::Grey => crossterm::style::Color::Grey,
Color::Rgb { r, g, b } => crossterm::style::Color::Rgb { r, g, b },
Color::AnsiValue(v) => crossterm::style::Color::AnsiValue(v),
}
}
}
impl From<Attributes> for crossterm::style::Attributes {
fn from(value: Attributes) -> Self {
let mut new = crossterm::style::Attributes::none();
if value.has(Attribute::Bold) {
new.set(crossterm::style::Attribute::Bold);
}
if value.has(Attribute::Dim) {
new.set(crossterm::style::Attribute::Dim);
}
if value.has(Attribute::Italic) {
new.set(crossterm::style::Attribute::Italic);
}
if value.has(Attribute::Underlined) {
new.set(crossterm::style::Attribute::Underlined);
}
if value.has(Attribute::DoubleUnderlined) {
new.set(crossterm::style::Attribute::DoubleUnderlined);
}
if value.has(Attribute::Undercurled) {
new.set(crossterm::style::Attribute::Undercurled);
}
if value.has(Attribute::Underdotted) {
new.set(crossterm::style::Attribute::Underdotted);
}
if value.has(Attribute::Underdashed) {
new.set(crossterm::style::Attribute::Underdashed);
}
if value.has(Attribute::SlowBlink) {
new.set(crossterm::style::Attribute::SlowBlink);
}
if value.has(Attribute::RapidBlink) {
new.set(crossterm::style::Attribute::RapidBlink);
}
if value.has(Attribute::Reverse) {
new.set(crossterm::style::Attribute::Reverse);
}
if value.has(Attribute::Hidden) {
new.set(crossterm::style::Attribute::Hidden);
}
if value.has(Attribute::CrossedOut) {
new.set(crossterm::style::Attribute::CrossedOut);
}
if value.has(Attribute::Fraktur) {
new.set(crossterm::style::Attribute::Fraktur);
}
if value.has(Attribute::Framed) {
new.set(crossterm::style::Attribute::Framed);
}
if value.has(Attribute::Encircled) {
new.set(crossterm::style::Attribute::Encircled);
}
if value.has(Attribute::OverLined) {
new.set(crossterm::style::Attribute::OverLined);
}
new
}
}
impl ScriptContext<'_> {
pub fn add_cell(&mut self, cell: Cell) {
puffin::profile_function!();
self.0
.operation_queue
.push(Operation::AddCell(tortuise::buffer::Cell {
character: cell.character,
style: ContentStyle {
foreground_color: Some(cell.foreground_color.into()),
background_color: Some(cell.background_color.into()),
underline_color: Some(cell.underline_color.into()),
attributes: cell.attributes.into(),
},
x: cell.x,
y: cell.y,
z: cell.z,
}));
}
pub fn window_size(&self) -> WindowSize {
puffin::profile_function!();
let size = &self.0.buffer.window_size;
WindowSize {
rows: size.rows,
columns: size.columns,
}
}
pub fn set_framerate_limit(&mut self, limit: Option<u32>) {
puffin::profile_function!();
let limit = limit.map(|limit| Duration::from_nanos(1_000_000_000 / limit as u64));
self.0.operation_queue.push(Operation::SetFrameLimit(limit));
}
}
|