raekna-ui 0.1.0

This crate contains functionality to draw a plain text calculator using wgpu.
Documentation
use std::time::Instant;

use super::{
    caret_position::CaretPosition, clear_indices, rectangle::Rectangle, update_indices,
    update_vertices,
};
use crate::{
    constants::{CARET_COLOR, CARET_PERIOD, CARET_WIDTH, TEXT_PADDING},
    coordinator::dimensions::Dimensions,
    graphics::vertex::Vertex,
};

pub struct Caret {
    last_visibility_update: Instant,
    should_show: bool,
    line: usize,
    column: usize,
    rect: Rectangle,
}

impl Caret {
    pub fn new(
        dimensions: &Dimensions,
        vertices: &mut Vec<Vertex>,
        indices: &mut Vec<u16>,
        caret_position: &CaretPosition,
    ) -> Self {
        let last_visibility_update = Instant::now();
        let should_show = true;
        let line = caret_position.line;
        let column = caret_position.column;
        let rect = Rectangle {
            color: CARET_COLOR,
            ..Default::default()
        };
        let mut caret = Self {
            last_visibility_update,
            should_show,
            line,
            column,
            rect,
        };
        caret.update(dimensions, vertices);
        update_indices(indices, 0);
        caret
    }

    pub fn update_time(&mut self, indices: &mut Vec<u16>) -> (bool, Option<Instant>) {
        let elapsed = self.last_visibility_update.elapsed().as_millis();
        let should_update_visibility = elapsed >= CARET_PERIOD as u128;
        if should_update_visibility {
            self.last_visibility_update = Instant::now();
            self.should_show = !self.should_show;
            if self.should_show {
                update_indices(indices, 0);
            } else {
                clear_indices(indices, 0)
            }
        }
        let last_visibility_update = if self.rect.bottom <= 1.0 && self.rect.top >= -1.0 {
            Some(self.last_visibility_update)
        } else {
            None
        };
        (should_update_visibility, last_visibility_update)
    }

    pub fn update_position(&mut self, caret_position: &CaretPosition, indices: &mut Vec<u16>) {
        self.line = caret_position.line;
        self.column = caret_position.column;
        self.set_visible(indices);
    }

    pub fn update(&mut self, dimensions: &Dimensions, vertices: &mut Vec<Vertex>) {
        let (top_px, bottom_px) = self.vertical_px(dimensions);
        let left_px = TEXT_PADDING + (self.column as f32 * dimensions.glyph_width());
        let right_px = left_px + CARET_WIDTH;

        self.rect.top = dimensions.as_y_vertex(top_px);
        self.rect.bottom = dimensions.as_y_vertex(bottom_px);
        self.rect.left = dimensions.as_x_vertex(left_px);
        self.rect.right = dimensions.as_x_vertex(right_px);

        update_vertices(self.rect, vertices, 0);
    }

    pub fn set_visible(&mut self, indices: &mut Vec<u16>) {
        self.last_visibility_update = Instant::now();
        self.should_show = true;
        update_indices(indices, 0);
    }

    pub fn vertical_px(&self, dimensions: &Dimensions) -> (f32, f32) {
        let top_px = TEXT_PADDING - dimensions.scroll()
            + (self.line as f32 * (dimensions.glyph_height() + TEXT_PADDING))
            + (dimensions.glyph_height() * 0.05);
        let bottom_px = top_px + (dimensions.glyph_height() * 0.9);
        (top_px, bottom_px)
    }
}