glim-tui 0.1.0

A TUI for monitoring GitLab CI/CD pipelines and projects
use derive_builder::Builder;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::text::Line;
use ratatui::widgets::{Block, Borders, BorderType, Clear};
use ratatui::widgets::Widget;
use tachyonfx::{CellFilter, CellIterator, Duration, Effect, IntoEffect, Shader};
use crate::ui::widget::Shortcuts;

#[derive(Builder, Clone)]
#[builder(pattern = "owned")]
pub struct OpenWindow {
    title: Line<'static>,
    #[builder(default, setter(strip_option))]
    open_window_fx: Option<Effect>,
    #[builder(default, setter(strip_option))]
    parent_window_fx: Option<Effect>,
    border_style: Style,
    border_type: BorderType,
    background: Style,

    #[builder(default)]
    shortcuts: Option<Shortcuts<'static>>
}


impl From<OpenWindowBuilder> for Effect {
    fn from(value: OpenWindowBuilder) -> Self {
        value.build().unwrap().into_effect()
    }
}

impl OpenWindow {
    pub fn builder() -> OpenWindowBuilder {
        OpenWindowBuilder::default()
    }

    pub fn screen_area(&mut self, area: Rect) {
        if let Some(fx) = self.parent_window_fx.as_mut() {
            fx.set_area(area);
        }
    }

    fn window_block(&self) -> Block {
        let w = Block::new()
            .borders(Borders::ALL)
            .title_style(self.border_style)
            .title(self.title.clone())
            .border_style(self.border_style)
            .border_type(self.border_type)
            .style(self.background);

        match self.shortcuts.as_ref() {
            Some(shortcuts) => w.title_bottom(shortcuts.as_line()),
            None            => w,
        }
    }

    pub fn process_opening(&mut self, duration: Duration, buf: &mut Buffer, area: Rect) {
        if let Some(open_window_fx) = self.open_window_fx.as_mut() {
            open_window_fx.process(duration, buf, area);
            if open_window_fx.done() {
                self.open_window_fx = None;
            }
        }
    }
}

impl Shader for OpenWindow {
    fn name(&self) -> &'static str {
        "open_window"
    }

    fn process(
        &mut self,
        duration: Duration,
        buf: &mut Buffer,
        area: Rect
    ) -> Option<Duration> {
        let remaining = match self.parent_window_fx.as_mut() {
            Some(fx) => fx.process(duration, buf, area),
            None     => None
        };

        Clear.render(area, buf);
        self.window_block().render(area, buf);

        remaining
    }

    fn execute(&mut self, _alpha: f32, _area: Rect, _cell_iter: CellIterator) {}


    fn done(&self) -> bool {
        self.open_window_fx.is_none()
            || self.open_window_fx.as_ref().is_some_and(Effect::done)
    }

    fn clone_box(&self) -> Box<dyn Shader> {
        Box::new(self.clone())
    }

    fn area(&self) -> Option<Rect> {
        self.open_window_fx.as_ref()
            .map(Effect::area)
            .unwrap_or(None)
    }

    fn set_area(&mut self, area: Rect) {
        if let Some(open_window_fx) = self.open_window_fx.as_mut() {
            open_window_fx.set_area(area);
        }
    }

    fn set_cell_selection(&mut self, _strategy: CellFilter) {
        todo!()
    }
}