//! Convert a cursor into an iterator of rects. use alacritty_terminal::vte::ansi::CursorShape; use crate::display::color::Rgb; use crate::display::content::RenderableCursor; use crate::display::SizeInfo; use crate::renderer::rects::RenderRect; /// Trait for conversion into the iterator. pub trait IntoRects { /// Consume the cursor for an iterator of rects. fn rects(self, size_info: &SizeInfo, thickness: f32) -> CursorRects; } impl IntoRects for RenderableCursor { fn rects(self, size_info: &SizeInfo, thickness: f32) -> CursorRects { let point = self.point(); let x = point.column.0 as f32 * size_info.cell_width() + size_info.padding_x(); let y = point.line as f32 * size_info.cell_height() + size_info.padding_y(); let mut width = size_info.cell_width(); let height = size_info.cell_height(); let thickness = (thickness * width).round().max(1.); width *= self.width().get() as f32; let crosshairs = crosshair(x, y, size_info); let mut shape = match self.shape() { CursorShape::Beam => beam(x, y, height, thickness, self.color()), CursorShape::Underline => underline(x, y, width, height, thickness, self.color()), CursorShape::HollowBlock => hollow(x, y, width, height, thickness, self.color()), _ => CursorRects::default(), }; // shape.append(&mut crosshairs); let mut i = 0; let mut ci = 0; while i < shape.rects.len() && ci < crosshairs.len() { match shape.rects[i] { None => { shape.rects[i] = Some(crosshairs[ci]); ci = ci + 1; } Some(_) => {} } i = i + 1; } shape } } fn abs_rect(x0: f32, y0: f32, x1: f32, y1: f32, color: Rgb, opacity: f32) -> Option { if x0 >= x1 || y0 >= y1 { None } else { Some(RenderRect::new(x0, y0, x1 - x0, y1 - y0, color, opacity)) } } fn crosshair(x: f32, y: f32, size_info: &SizeInfo) -> Vec { let width = size_info.cell_width(); let height = size_info.cell_height(); let y_inner_padding = 2.; // config.y_inner_padding as f32; let x_inner_padding = 4.; // config.x_inner_padding as f32; let opacity = 0.05; // config.opacity.as_f32(); let color = Rgb::new(255,255,255); // config.color; let crosshair_max_height = 20. * size_info.cell_height(); let crosshair_max_width = 40. * size_info.cell_width(); (vec![ abs_rect( x, (y - crosshair_max_height).max(0.), x + width, y - (size_info.cell_height() * y_inner_padding), color, opacity, ), abs_rect( x, y + size_info.cell_height() * (y_inner_padding + 1.), x + width, size_info.height().min(y + crosshair_max_height + height), color, opacity, ), abs_rect( (x - crosshair_max_width).max(0.), y, x - (size_info.cell_width() * x_inner_padding), y + height, color, opacity, ), abs_rect( x + size_info.cell_width() * (x_inner_padding + if x_inner_padding > 0. { 1. } else { 0. }), y, size_info.width().min(x + crosshair_max_width + width), y + height, color, opacity, ), ]) .into_iter() .flatten() .collect::>() } /// Cursor rect iterator. #[derive(Default)] pub struct CursorRects { rects: [Option; 8], index: usize, } impl From for CursorRects { fn from(rect: RenderRect) -> Self { Self { rects: [Some(rect), None, None, None, None, None, None, None], index: 0 } } } impl Iterator for CursorRects { type Item = RenderRect; fn next(&mut self) -> Option { let rect = self.rects.get_mut(self.index)?; self.index += 1; rect.take() } } /// Create an iterator yielding a single beam rect. fn beam(x: f32, y: f32, height: f32, thickness: f32, color: Rgb) -> CursorRects { RenderRect::new(x, y, thickness, height, color, 1.).into() } /// Create an iterator yielding a single underline rect. fn underline(x: f32, y: f32, width: f32, height: f32, thickness: f32, color: Rgb) -> CursorRects { let y = y + height - thickness; RenderRect::new(x, y, width, thickness, color, 1.).into() } /// Create an iterator yielding a rect for each side of the hollow block cursor. fn hollow(x: f32, y: f32, width: f32, height: f32, thickness: f32, color: Rgb) -> CursorRects { let top_line = RenderRect::new(x, y, width, thickness, color, 1.); let vertical_y = y + thickness; let vertical_height = height - 2. * thickness; let left_line = RenderRect::new(x, vertical_y, thickness, vertical_height, color, 1.); let bottom_y = y + height - thickness; let bottom_line = RenderRect::new(x, bottom_y, width, thickness, color, 1.); let right_x = x + width - thickness; let right_line = RenderRect::new(right_x, vertical_y, thickness, vertical_height, color, 1.); CursorRects { rects: [Some(top_line), Some(bottom_line), Some(left_line), Some(right_line), None, None, None, None], index: 0, } }