use super::properties::WindowSize;
use crate::{
markdown::{
text::{WeightedLine, WeightedText},
text_style::{Color, Colors, TextStyle},
},
terminal::image::Image,
theme::{Alignment, Margin},
};
use std::{
fmt::Debug,
rc::Rc,
sync::{Arc, Mutex},
};
const DEFAULT_IMAGE_Z_INDEX: i32 = -2;
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct BlockLine {
pub(crate) prefix: WeightedText,
pub(crate) right_padding_length: u16,
pub(crate) repeat_prefix_on_wrap: bool,
pub(crate) text: WeightedLine,
pub(crate) block_length: u16,
pub(crate) block_color: Option<Color>,
pub(crate) alignment: Alignment,
}
#[derive(Clone, Debug)]
pub(crate) enum RenderOperation {
ClearScreen,
SetColors(Colors),
JumpToVerticalCenter,
JumpToRow { index: u16 },
JumpToBottomRow { index: u16 },
JumpToColumn { index: u16 },
RenderText { line: WeightedLine, alignment: Alignment },
RenderLineBreak,
RenderImage(Image, ImageRenderProperties),
RenderBlockLine(BlockLine),
RenderDynamic(Rc<dyn AsRenderOperations>),
RenderDynamicTopLevel(Rc<dyn AsRenderOperations>),
RenderAsync(Rc<dyn RenderAsync>),
InitColumnLayout { columns: Vec<u8>, grid: LayoutGrid },
EnterColumn { column: usize },
ExitLayout,
ApplyMargin(MarginProperties),
PopMargin,
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum LayoutGrid {
None,
Draw(TextStyle),
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct ImageRenderProperties {
pub(crate) z_index: i32,
pub(crate) size: ImageSize,
pub(crate) restore_cursor: bool,
pub(crate) background_color: Option<Color>,
pub(crate) position: ImagePosition,
}
impl Default for ImageRenderProperties {
fn default() -> Self {
Self {
z_index: DEFAULT_IMAGE_Z_INDEX,
size: Default::default(),
restore_cursor: false,
background_color: None,
position: ImagePosition::Center,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum ImagePosition {
Cursor,
Center,
Right,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub(crate) enum ImageSize {
#[default]
ShrinkIfNeeded,
Specific(u16, u16),
WidthScaled {
ratio: f64,
},
}
#[derive(Clone, Debug, Default)]
pub(crate) struct MarginProperties {
pub(crate) horizontal: Margin,
pub(crate) top: u16,
pub(crate) bottom: u16,
}
pub(crate) trait AsRenderOperations: Debug + 'static {
fn as_render_operations(&self, dimensions: &WindowSize) -> Vec<RenderOperation>;
fn diffable_content(&self) -> Option<&str> {
None
}
}
pub(crate) trait RenderAsync: AsRenderOperations {
fn pollable(&self) -> Box<dyn Pollable>;
fn start_policy(&self) -> RenderAsyncStartPolicy {
RenderAsyncStartPolicy::OnDemand
}
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum RenderAsyncStartPolicy {
Automatic,
OnDemand,
}
pub(crate) trait Pollable: Send + 'static {
fn poll(&mut self) -> PollableState;
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum PollableState {
Unmodified,
Modified,
Done,
Failed { error: String },
}
impl PollableState {
#[cfg(test)]
pub(crate) fn is_completed(&self) -> bool {
match self {
Self::Unmodified | Self::Modified => false,
Self::Done | Self::Failed { .. } => true,
}
}
}
pub(crate) struct ToggleState {
toggled: Arc<Mutex<bool>>,
}
impl ToggleState {
pub(crate) fn new(toggled: Arc<Mutex<bool>>) -> Self {
Self { toggled }
}
}
impl Pollable for ToggleState {
fn poll(&mut self) -> PollableState {
*self.toggled.lock().unwrap() = true;
PollableState::Done
}
}