Skip to main content

par_term_render/cell_renderer/
cursor.rs

1use par_term_config::{color_u8_to_f32, color_u8x4_to_f32};
2
3use super::CellRenderer;
4
5/// Cursor position, style, colors, and visual enhancement settings.
6pub(crate) struct CursorState {
7    pub(crate) pos: (usize, usize),
8    pub(crate) opacity: f32,
9    pub(crate) style: par_term_emu_core_rust::cursor::CursorStyle,
10    /// Cursor color [R, G, B] as floats (0.0-1.0)
11    pub(crate) color: [f32; 3],
12    /// Text color under block cursor [R, G, B] as floats (0.0-1.0), or None for auto-contrast
13    pub(crate) text_color: Option<[f32; 3]>,
14    /// Hide cursor when cursor shader is active (let shader handle cursor rendering)
15    pub(crate) hidden_for_shader: bool,
16    /// Enable cursor guide (horizontal line at cursor row)
17    pub(crate) guide_enabled: bool,
18    /// Cursor guide color [R, G, B, A] as floats (0.0-1.0)
19    pub(crate) guide_color: [f32; 4],
20    /// Enable cursor shadow
21    pub(crate) shadow_enabled: bool,
22    /// Cursor shadow color [R, G, B, A] as floats (0.0-1.0)
23    pub(crate) shadow_color: [f32; 4],
24    /// Cursor shadow offset in pixels [x, y]
25    pub(crate) shadow_offset: [f32; 2],
26    /// Cursor shadow blur radius (not fully supported yet, but stores config)
27    pub(crate) shadow_blur: f32,
28    /// Cursor boost (glow) intensity (0.0-1.0)
29    pub(crate) boost: f32,
30    /// Cursor boost glow color [R, G, B] as floats (0.0-1.0)
31    pub(crate) boost_color: [f32; 3],
32    /// Unfocused cursor style (hollow, same, hidden)
33    pub(crate) unfocused_style: par_term_config::UnfocusedCursorStyle,
34}
35
36impl CellRenderer {
37    /// Update cursor position, opacity and style. Returns `true` if anything changed.
38    pub fn update_cursor(
39        &mut self,
40        pos: (usize, usize),
41        opacity: f32,
42        style: par_term_emu_core_rust::cursor::CursorStyle,
43    ) -> bool {
44        if self.cursor.pos != pos || self.cursor.opacity != opacity || self.cursor.style != style {
45            self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
46            self.cursor.pos = pos;
47            self.cursor.opacity = opacity;
48            self.cursor.style = style;
49            self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
50            return true;
51        }
52        false
53    }
54
55    pub fn clear_cursor(&mut self) -> bool {
56        let pos = self.cursor.pos;
57        let style = self.cursor.style;
58        self.update_cursor(pos, 0.0, style)
59    }
60
61    /// Update cursor color
62    pub fn update_cursor_color(&mut self, color: [u8; 3]) {
63        self.cursor.color = color_u8_to_f32(color);
64        self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
65    }
66
67    /// Update cursor text color (color of text under block cursor)
68    pub fn update_cursor_text_color(&mut self, color: Option<[u8; 3]>) {
69        self.cursor.text_color = color.map(color_u8_to_f32);
70        self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
71    }
72
73    /// Set whether cursor should be hidden when cursor shader is active.
74    /// Returns `true` if the value changed.
75    pub fn set_cursor_hidden_for_shader(&mut self, hidden: bool) -> bool {
76        if self.cursor.hidden_for_shader != hidden {
77            self.cursor.hidden_for_shader = hidden;
78            self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
79            return true;
80        }
81        false
82    }
83
84    /// Set window focus state (affects unfocused cursor rendering).
85    /// Returns `true` if the value changed.
86    pub fn set_focused(&mut self, focused: bool) -> bool {
87        if self.is_focused != focused {
88            self.is_focused = focused;
89            self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
90            return true;
91        }
92        false
93    }
94
95    /// Update cursor guide settings
96    pub fn update_cursor_guide(&mut self, enabled: bool, color: [u8; 4]) {
97        self.cursor.guide_enabled = enabled;
98        self.cursor.guide_color = color_u8x4_to_f32(color);
99        if enabled {
100            self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
101        }
102    }
103
104    /// Update cursor shadow settings
105    pub fn update_cursor_shadow(
106        &mut self,
107        enabled: bool,
108        color: [u8; 4],
109        offset: [f32; 2],
110        blur: f32,
111    ) {
112        self.cursor.shadow_enabled = enabled;
113        self.cursor.shadow_color = color_u8x4_to_f32(color);
114        self.cursor.shadow_offset = offset;
115        self.cursor.shadow_blur = blur;
116        if enabled {
117            self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
118        }
119    }
120
121    /// Update cursor boost settings
122    pub fn update_cursor_boost(&mut self, intensity: f32, color: [u8; 3]) {
123        self.cursor.boost = intensity.clamp(0.0, 1.0);
124        self.cursor.boost_color = color_u8_to_f32(color);
125        if intensity > 0.0 {
126            self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
127        }
128    }
129
130    /// Update unfocused cursor style
131    pub fn update_unfocused_cursor_style(&mut self, style: par_term_config::UnfocusedCursorStyle) {
132        self.cursor.unfocused_style = style;
133        if !self.is_focused {
134            self.dirty_rows[self.cursor.pos.1.min(self.grid.rows - 1)] = true;
135        }
136    }
137}