turbo-vision 0.10.0

A Rust implementation of the classic Borland Turbo Vision text-mode UI framework
Documentation
// (C) 2025 - Enzo Lombardi

//! Indicator view - visual indicator for displaying scroll position or progress.

use crate::core::geometry::{Point, Rect};
use crate::core::event::Event;
use crate::core::draw::DrawBuffer;
use crate::core::palette::{Attr, TvColor};
use crate::terminal::Terminal;
use super::view::{View, write_line_to_terminal};

/// Indicator displays the current line and column position,
/// typically shown in the top-right corner of an editor window.
pub struct Indicator {
    bounds: Rect,
    location: Point,  // Line and column (1-based)
    modified: bool,   // Has the document been modified?
    owner: Option<*const dyn View>,
}

impl Indicator {
    pub fn new(bounds: Rect) -> Self {
        Self {
            bounds,
            location: Point::new(1, 1),
            modified: false,
            owner: None,
        }
    }

    pub fn set_value(&mut self, location: Point, modified: bool) {
        self.location = location;
        self.modified = modified;
    }
}

impl View for Indicator {
    fn bounds(&self) -> Rect {
        self.bounds
    }

    fn set_bounds(&mut self, bounds: Rect) {
        self.bounds = bounds;
    }

    fn draw(&mut self, terminal: &mut Terminal) {
        let width = self.bounds.width() as usize;
        let mut buf = DrawBuffer::new(width);

        // Format: " 12:34 " or " 12:34 * " (with modified star)
        let text = if self.modified {
            format!(" {}:{} * ", self.location.y, self.location.x)
        } else {
            format!(" {}:{} ", self.location.y, self.location.x)
        };

        // Right-align the indicator
        let text_len = text.len().min(width);
        let start_pos = width.saturating_sub(text_len);

        buf.move_char(0, ' ', Attr::new(TvColor::White, TvColor::LightGray), width);
        buf.move_str(start_pos, &text, Attr::new(TvColor::White, TvColor::LightGray));

        write_line_to_terminal(terminal, self.bounds.a.x, self.bounds.a.y, &buf);
    }

    fn handle_event(&mut self, _event: &mut Event) {
        // Indicator doesn't handle events
    }

    fn set_owner(&mut self, owner: *const dyn View) {
        self.owner = Some(owner);
    }

    fn get_owner(&self) -> Option<*const dyn View> {
        self.owner
    }

    fn get_palette(&self) -> Option<crate::core::palette::Palette> {
        None  // Indicator uses hardcoded dialog colors
    }
}