Add custom beam cursor

In issue jwilm/asacritty#31 a few people complained about Beam cursor
being weird with their fonts, so to make all cursors uniform in
alacritty, a custom cursor has been added for the Beam too.

The beam cursor's height is always the full height of the monospace font
glyph bounding box. The width depends on the font size. It is calculated
using the width of the cell and dividing it by two. The block is always
aligned at the far-left of the cell.

The implementation is identical to the one of the underline cursor, but
it has been refactored so the glyphs are created in `lib.rs`, which can
be used by darwin/macos to implement these features too.

A small bug in the underline cursor has also been fixed, until now the
width was just using the width of the unicode character. Now it should
be using the full width of the monospace glyph bounding box with every
font.

Here are some screenshots for the Beam cursor:
![Small](https://u.teknik.io/v1QH3.png)
![Normal](https://u.teknik.io/RTlp2.png)
![Big](https://u.teknik.io/DLu2M.png)
![Huge](https://u.teknik.io/pSAFX.png)
This commit is contained in:
Christian Duerr 2017-12-07 21:52:50 +01:00 committed by Joe Wilm
parent 9f708146d9
commit d82c4f02b6
3 changed files with 85 additions and 30 deletions

View File

@ -24,7 +24,7 @@ use libc::c_uint;
pub mod fc;
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style, UNDERLINE_CURSOR_CHAR};
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};
struct FixedSize {
pixelsize: f64,
@ -294,37 +294,50 @@ impl FreeTypeRasterizer {
let (pixel_width, buf) = Self::normalize_buffer(&glyph.bitmap())?;
// Render a custom symbol for the underline cursor
if glyph_key.c == UNDERLINE_CURSOR_CHAR {
// Get the bottom of the bounding box
let size_metrics = face.ft_face.size_metrics()
.ok_or(Error::MissingSizeMetrics)?;
let descent = (size_metrics.descender / 64) as f32;
// Render a custom symbol for the underline and beam cursor
match glyph_key.c {
super::UNDERLINE_CURSOR_CHAR => {
// Get the bottom of the bounding box
let size_metrics = face.ft_face.size_metrics()
.ok_or(Error::MissingSizeMetrics)?;
let descent = (size_metrics.descender / 64) as i32;
// Create a new rectangle, the height is half the distance between
// bounding box bottom and the baseline
let height = f32::abs(descent / 2.) as i32;
let buf = vec![255u8; (pixel_width * height * 3) as usize];
// Get the width of the cell
let metrics = glyph.metrics();
let width = (metrics.vertAdvance as f32 / 128.).round() as i32;
// Create a custom glyph with the rectangle data attached to it
return Ok(RasterizedGlyph {
c: glyph_key.c,
top: descent as i32 + height,
left: glyph.bitmap_left(),
height,
width: pixel_width,
buf: buf,
});
// Return the new custom glyph
super::get_underline_cursor_glyph(descent, width)
},
super::BEAM_CURSOR_CHAR => {
// Get the top of the bounding box
let size_metrics = face.ft_face.size_metrics()
.ok_or(Error::MissingSizeMetrics)?;
let ascent = (size_metrics.ascender / 64) as i32 - 1;
// Get the height of the cell
let descent = (size_metrics.descender / 64) as i32;
let height = ascent - descent;
// Get the width of the cell
let metrics = glyph.metrics();
let width = (metrics.vertAdvance as f32 / 128.).round() as i32;
// Return the new custom glyph
super::get_beam_cursor_glyph(ascent, height, width)
},
_ => {
// If it's not a special char, return the normal glyph
Ok(RasterizedGlyph {
c: glyph_key.c,
top: glyph.bitmap_top(),
left: glyph.bitmap_left(),
width: pixel_width,
height: glyph.bitmap().rows(),
buf: buf,
})
}
}
Ok(RasterizedGlyph {
c: glyph_key.c,
top: glyph.bitmap_top(),
left: glyph.bitmap_left(),
width: pixel_width,
height: glyph.bitmap().rows(),
buf: buf,
})
}
fn ft_load_flags(pat: &fc::Pattern) -> freetype::face::LoadFlag {

View File

@ -65,6 +65,13 @@ pub const UNDERLINE_CURSOR_CHAR: char = '\u{10a3e2}';
#[cfg(target_os = "macos")]
pub const UNDERLINE_CURSOR_CHAR: char = '▁';
/// Character used for the beam cursor
#[cfg(not(target_os = "macos"))]
// This is part of the private use area and should not conflict with any font
pub const BEAM_CURSOR_CHAR: char = '\u{10a3e3}';
#[cfg(target_os = "macos")]
pub const BEAM_CURSOR_CHAR: char = '▎';
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FontDesc {
name: String,
@ -209,6 +216,41 @@ impl Default for RasterizedGlyph {
}
}
// Returns a custom underline cursor character
pub fn get_underline_cursor_glyph(descent: i32, width: i32) -> Result<RasterizedGlyph, Error> {
// Create a new rectangle, the height is half the distance between
// bounding box bottom and the baseline
let height = i32::abs(descent / 2);
let buf = vec![255u8; (width * height * 3) as usize];
// Create a custom glyph with the rectangle data attached to it
return Ok(RasterizedGlyph {
c: UNDERLINE_CURSOR_CHAR,
top: descent + height,
left: 0,
height,
width,
buf: buf,
});
}
// Returns a custom beam cursor character
pub fn get_beam_cursor_glyph(ascent: i32, height: i32, width: i32) -> Result<RasterizedGlyph, Error> {
// Create a new rectangle
let beam_width = (f64::from(width) / 5.) as i32;
let buf = vec![255u8; (beam_width * height * 3) as usize];
// Create a custom glyph with the rectangle data attached to it
return Ok(RasterizedGlyph {
c: BEAM_CURSOR_CHAR,
top: ascent,
left: 0,
height,
width: beam_width,
buf: buf,
});
}
struct BufDebugger<'a>(&'a [u8]);
impl<'a> fmt::Debug for BufDebugger<'a> {

View File

@ -181,7 +181,7 @@ impl<'a> RenderableCellsIter<'a> {
});
let cursor_color = self.text_cursor_color(&cursor_cell);
cursor_cell.c = '▎';
cursor_cell.c = font::BEAM_CURSOR_CHAR;
cursor_cell.fg = cursor_color;
self.cursor_cells.push_back(Indexed {
line: self.cursor.line,