diff --git a/font/src/darwin/mod.rs b/font/src/darwin/mod.rs index a6deba3b..56685dd5 100644 --- a/font/src/darwin/mod.rs +++ b/font/src/darwin/mod.rs @@ -470,8 +470,8 @@ impl Font { let width = self.glyph_advance('0') as i32; // Return the new custom glyph return super::get_underline_cursor_glyph(descent, width); - }, - super::BEAM_CURSOR_CHAR => { + } + super::BEAM_CURSOR_CHAR | super::BOX_CURSOR_CHAR => { // Get the top of the bounding box let metrics = self.metrics(); let height = metrics.line_height; @@ -483,9 +483,13 @@ impl Font { // Get the width of the cell let width = self.glyph_advance('0') as i32; // Return the new custom glyph - return super::get_beam_cursor_glyph(ascent as i32, height as i32, width); - }, - _ => (), + if character == super::BEAM_CURSOR_CHAR { + return super::get_beam_cursor_glyph(ascent as i32, height as i32, width); + } else { + return super::get_box_cursor_glyph(ascent as i32, height as i32, width); + } + } + _ => () } let glyph_index = self.glyph_index(character) diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs index 765e8efb..44dc0be3 100644 --- a/font/src/ft/mod.rs +++ b/font/src/ft/mod.rs @@ -310,7 +310,7 @@ impl FreeTypeRasterizer { // Return the new custom glyph super::get_underline_cursor_glyph(descent, width) } - super::BEAM_CURSOR_CHAR => { + super::BEAM_CURSOR_CHAR | super::BOX_CURSOR_CHAR => { // Get the top of the bounding box let size_metrics = face.ft_face .size_metrics() @@ -326,7 +326,11 @@ impl FreeTypeRasterizer { let width = (metrics.vertAdvance as f32 / 128.).round() as i32; // Return the new custom glyph - super::get_beam_cursor_glyph(ascent, height, width) + if glyph_key.c == super::BEAM_CURSOR_CHAR { + super::get_beam_cursor_glyph(ascent, height, width) + } else { + super::get_box_cursor_glyph(ascent, height, width) + } } _ => { // If it's not a special char, return the normal glyph diff --git a/font/src/lib.rs b/font/src/lib.rs index f9eaaac6..68935e45 100644 --- a/font/src/lib.rs +++ b/font/src/lib.rs @@ -58,6 +58,9 @@ mod darwin; #[cfg(target_os = "macos")] pub use darwin::*; +/// Width/Height of the cursor relative to the font width +pub const CURSOR_WIDTH_PERCENTAGE: i32 = 15; + /// Character used for the underline cursor // This is part of the private use area and should not conflict with any font pub const UNDERLINE_CURSOR_CHAR: char = '\u{10a3e2}'; @@ -65,8 +68,10 @@ pub const UNDERLINE_CURSOR_CHAR: char = '\u{10a3e2}'; /// Character used for the beam cursor // This is part of the private use area and should not conflict with any font pub const BEAM_CURSOR_CHAR: char = '\u{10a3e3}'; -/// Width of the beam cursor relative to the font width -pub const BEAM_CURSOR_WIDTH_PERCENTAGE: i32 = 15; + +/// Character used for the empty box cursor +// This is part of the private use area and should not conflict with any font +pub const BOX_CURSOR_CHAR: char = '\u{10a3e4}'; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FontDesc { @@ -214,9 +219,8 @@ impl Default for RasterizedGlyph { // Returns a custom underline cursor character pub fn get_underline_cursor_glyph(descent: i32, width: i32) -> Result { - // Create a new rectangle, the height is half the distance between - // bounding box bottom and the baseline - let height = cmp::max(i32::abs(descent / 2), 1); + // Create a new rectangle, the height is relative to the font width + let height = cmp::max(width * CURSOR_WIDTH_PERCENTAGE / 100, 1); let buf = vec![255u8; (width * height * 3) as usize]; // Create a custom glyph with the rectangle data attached to it @@ -237,7 +241,7 @@ pub fn get_beam_cursor_glyph( width: i32, ) -> Result { // Create a new rectangle that is at least one pixel wide - let beam_width = cmp::max(width * BEAM_CURSOR_WIDTH_PERCENTAGE / 100, 1); + let beam_width = cmp::max(width * CURSOR_WIDTH_PERCENTAGE / 100, 1); let buf = vec![255u8; (beam_width * height * 3) as usize]; // Create a custom glyph with the rectangle data attached to it @@ -251,6 +255,37 @@ pub fn get_beam_cursor_glyph( }); } +// Returns a custom beam cursor character +pub fn get_box_cursor_glyph( + ascent: i32, + height: i32, + width: i32, +) -> Result { + // Create a new box outline rectangle + let border_width = cmp::max(width * CURSOR_WIDTH_PERCENTAGE / 100, 1); + let mut buf = Vec::with_capacity((width * height * 3) as usize); + for y in 0..height { + for x in 0..width { + if y < border_width || y >= height - border_width || + x < border_width || x >= width - border_width { + buf.append(&mut vec![255u8; 3]); + } else { + buf.append(&mut vec![0u8; 3]); + } + } + } + + // Create a custom glyph with the rectangle data attached to it + return Ok(RasterizedGlyph { + c: BOX_CURSOR_CHAR, + top: ascent, + left: 0, + height, + width, + buf: buf, + }); +} + struct BufDebugger<'a>(&'a [u8]); impl<'a> fmt::Debug for BufDebugger<'a> { diff --git a/src/display.rs b/src/display.rs index bfd62c32..8e3d8814 100644 --- a/src/display.rs +++ b/src/display.rs @@ -354,6 +354,7 @@ impl Display { // // TODO I wonder if the renderable cells iter could avoid the // mutable borrow + let window_focused = self.window.is_focused; self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| { // Clear screen to update whole background with new color if background_color_changed { @@ -361,7 +362,10 @@ impl Display { } // Draw the grid - api.render_cells(terminal.renderable_cells(config, selection), glyph_cache); + api.render_cells( + terminal.renderable_cells(config, selection, window_focused), + glyph_cache, + ); }); } diff --git a/src/event.rs b/src/event.rs index c8fb83e9..894777fa 100644 --- a/src/event.rs +++ b/src/event.rs @@ -330,6 +330,7 @@ impl Processor { processor.ctx.terminal.dirty = true; processor.ctx.terminal.next_is_urgent = Some(false); } else { + processor.ctx.terminal.dirty = true; *hide_cursor = false; } diff --git a/src/term/mod.rs b/src/term/mod.rs index 86115171..da59a037 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -118,6 +118,7 @@ impl<'a> RenderableCellsIter<'a> { config: &'b Config, selection: Option>, cursor_style: CursorStyle, + window_focused: bool, ) -> RenderableCellsIter<'b> { let cursor_index = Linear(cursor.line.0 * grid.num_cols().0 + cursor.col.0); @@ -132,10 +133,15 @@ impl<'a> RenderableCellsIter<'a> { config: config, colors: colors, cursor_cells: ArrayDeque::new(), - }.initialize(cursor_style) + }.initialize(cursor_style, window_focused) } - fn populate_block_cursor(&mut self) { + fn populate_block_cursor(&mut self, window_focused: bool) { + if !window_focused { + self.populate_cursor(font::BOX_CURSOR_CHAR, ' '); + return; + } + let (text_color, cursor_color) = if self.config.custom_cursor_colors() { ( Color::Named(NamedColor::CursorText), @@ -173,33 +179,14 @@ impl<'a> RenderableCellsIter<'a> { } fn populate_beam_cursor(&mut self) { - let mut cursor_cell = self.grid[self.cursor]; - self.cursor_cells.push_back(Indexed { - line: self.cursor.line, - column: self.cursor.col, - inner: cursor_cell, - }); - - let cursor_color = self.text_cursor_color(&cursor_cell); - cursor_cell.c = font::BEAM_CURSOR_CHAR; - cursor_cell.fg = cursor_color; - self.cursor_cells.push_back(Indexed { - line: self.cursor.line, - column: self.cursor.col, - inner: cursor_cell, - }); - - if self.is_wide_cursor(&cursor_cell) { - cursor_cell.c = ' '; - self.cursor_cells.push_back(Indexed { - line: self.cursor.line, - column: self.cursor.col + 1, - inner: cursor_cell, - }); - } + self.populate_cursor(font::BEAM_CURSOR_CHAR, ' '); } fn populate_underline_cursor(&mut self) { + self.populate_cursor(font::UNDERLINE_CURSOR_CHAR, font::UNDERLINE_CURSOR_CHAR); + } + + fn populate_cursor(&mut self, cursor: char, wide_cursor: char) { let mut cursor_cell = self.grid[self.cursor]; self.cursor_cells.push_back(Indexed { line: self.cursor.line, @@ -208,7 +195,7 @@ impl<'a> RenderableCellsIter<'a> { }); let cursor_color = self.text_cursor_color(&cursor_cell); - cursor_cell.c = font::UNDERLINE_CURSOR_CHAR; + cursor_cell.c = cursor; cursor_cell.fg = cursor_color; self.cursor_cells.push_back(Indexed { line: self.cursor.line, @@ -217,6 +204,7 @@ impl<'a> RenderableCellsIter<'a> { }); if self.is_wide_cursor(&cursor_cell) { + cursor_cell.c = wide_cursor; self.cursor_cells.push_back(Indexed { line: self.cursor.line, column: self.cursor.col + 1, @@ -243,11 +231,11 @@ impl<'a> RenderableCellsIter<'a> { }); } - fn initialize(mut self, cursor_style: CursorStyle) -> Self { + fn initialize(mut self, cursor_style: CursorStyle, window_focused: bool) -> Self { if self.cursor_is_visible() { match cursor_style { CursorStyle::Block => { - self.populate_block_cursor(); + self.populate_block_cursor(window_focused); }, CursorStyle::Beam => { self.populate_beam_cursor(); @@ -971,6 +959,7 @@ impl Term { &'b self, config: &'b Config, selection: Option<&'b Selection>, + window_focused: bool, ) -> RenderableCellsIter { let selection = selection.and_then(|s| s.to_span(self)) .map(|span| span.to_range()); @@ -983,6 +972,7 @@ impl Term { config, selection, self.cursor_style.unwrap_or(self.default_cursor_style), + window_focused, ) }