render character under block cursor
This commit is contained in:
parent
0d42c85195
commit
eddb089f27
3 changed files with 66 additions and 19 deletions
|
@ -1023,9 +1023,9 @@ impl Editor {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape) {
|
pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
|
||||||
self.cursor_shape = cursor_shape;
|
self.cursor_shape = cursor_shape;
|
||||||
// TODO: Do we need to notify?
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> Vector2F {
|
pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> Vector2F {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use gpui::{
|
||||||
PathBuilder,
|
PathBuilder,
|
||||||
},
|
},
|
||||||
json::{self, ToJson},
|
json::{self, ToJson},
|
||||||
text_layout::{self, RunStyle, TextLayoutCache},
|
text_layout::{self, Line, RunStyle, TextLayoutCache},
|
||||||
AppContext, Axis, Border, Element, ElementBox, Event, EventContext, LayoutContext,
|
AppContext, Axis, Border, Element, ElementBox, Event, EventContext, LayoutContext,
|
||||||
MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
|
MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
|
||||||
};
|
};
|
||||||
|
@ -347,7 +347,7 @@ impl EditorElement {
|
||||||
|
|
||||||
let mut cursors = SmallVec::<[Cursor; 32]>::new();
|
let mut cursors = SmallVec::<[Cursor; 32]>::new();
|
||||||
for (replica_id, selections) in &layout.selections {
|
for (replica_id, selections) in &layout.selections {
|
||||||
let style = style.replica_selection_style(*replica_id);
|
let selection_style = style.replica_selection_style(*replica_id);
|
||||||
let corner_radius = 0.15 * layout.line_height;
|
let corner_radius = 0.15 * layout.line_height;
|
||||||
|
|
||||||
for selection in selections {
|
for selection in selections {
|
||||||
|
@ -355,7 +355,7 @@ impl EditorElement {
|
||||||
selection.start..selection.end,
|
selection.start..selection.end,
|
||||||
start_row,
|
start_row,
|
||||||
end_row,
|
end_row,
|
||||||
style.selection,
|
selection_style.selection,
|
||||||
corner_radius,
|
corner_radius,
|
||||||
corner_radius * 2.,
|
corner_radius * 2.,
|
||||||
layout,
|
layout,
|
||||||
|
@ -372,24 +372,49 @@ impl EditorElement {
|
||||||
let cursor_row_layout =
|
let cursor_row_layout =
|
||||||
&layout.line_layouts[(cursor_position.row() - start_row) as usize];
|
&layout.line_layouts[(cursor_position.row() - start_row) as usize];
|
||||||
let cursor_column = cursor_position.column() as usize;
|
let cursor_column = cursor_position.column() as usize;
|
||||||
|
|
||||||
let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
|
let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
|
||||||
let mut character_width =
|
let mut block_width =
|
||||||
cursor_row_layout.x_for_index(cursor_column + 1) - cursor_character_x;
|
cursor_row_layout.x_for_index(cursor_column + 1) - cursor_character_x;
|
||||||
// TODO: Is there a better option here for the character size
|
if block_width == 0.0 {
|
||||||
// at the end of the line?
|
block_width = layout.em_width;
|
||||||
// Default to 1/3 the line height
|
|
||||||
if character_width == 0.0 {
|
|
||||||
character_width = layout.line_height / 3.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let block_text =
|
||||||
|
if matches!(self.cursor_shape, CursorShape::Block) {
|
||||||
|
layout.snapshot.chars_at(cursor_position).next().and_then(
|
||||||
|
|character| {
|
||||||
|
let font_id =
|
||||||
|
cursor_row_layout.font_for_index(cursor_column)?;
|
||||||
|
let text = character.to_string();
|
||||||
|
|
||||||
|
Some(cx.text_layout_cache.layout_str(
|
||||||
|
&text,
|
||||||
|
cursor_row_layout.font_size(),
|
||||||
|
&[(
|
||||||
|
text.len(),
|
||||||
|
RunStyle {
|
||||||
|
font_id,
|
||||||
|
color: style.background,
|
||||||
|
underline: None,
|
||||||
|
},
|
||||||
|
)],
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let x = cursor_character_x - scroll_left;
|
let x = cursor_character_x - scroll_left;
|
||||||
let y = cursor_position.row() as f32 * layout.line_height - scroll_top;
|
let y = cursor_position.row() as f32 * layout.line_height - scroll_top;
|
||||||
cursors.push(Cursor {
|
cursors.push(Cursor {
|
||||||
color: style.cursor,
|
color: selection_style.cursor,
|
||||||
character_width,
|
block_width,
|
||||||
origin: content_origin + vec2f(x, y),
|
origin: content_origin + vec2f(x, y),
|
||||||
line_height: layout.line_height,
|
line_height: layout.line_height,
|
||||||
shape: self.cursor_shape,
|
shape: self.cursor_shape,
|
||||||
|
block_text,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1182,6 +1207,7 @@ fn layout_line(
|
||||||
while !line.is_char_boundary(len) {
|
while !line.is_char_boundary(len) {
|
||||||
len -= 1;
|
len -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
line.truncate(len);
|
line.truncate(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1242,16 +1268,17 @@ pub enum CursorShape {
|
||||||
|
|
||||||
impl Default for CursorShape {
|
impl Default for CursorShape {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CursorShape::Bar
|
CursorShape::Block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Cursor {
|
struct Cursor {
|
||||||
origin: Vector2F,
|
origin: Vector2F,
|
||||||
character_width: f32,
|
block_width: f32,
|
||||||
line_height: f32,
|
line_height: f32,
|
||||||
color: Color,
|
color: Color,
|
||||||
shape: CursorShape,
|
shape: CursorShape,
|
||||||
|
block_text: Option<Line>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cursor {
|
impl Cursor {
|
||||||
|
@ -1259,11 +1286,11 @@ impl Cursor {
|
||||||
let bounds = match self.shape {
|
let bounds = match self.shape {
|
||||||
CursorShape::Bar => RectF::new(self.origin, vec2f(2.0, self.line_height)),
|
CursorShape::Bar => RectF::new(self.origin, vec2f(2.0, self.line_height)),
|
||||||
CursorShape::Block => {
|
CursorShape::Block => {
|
||||||
RectF::new(self.origin, vec2f(self.character_width, self.line_height))
|
RectF::new(self.origin, vec2f(self.block_width, self.line_height))
|
||||||
}
|
}
|
||||||
CursorShape::Underscore => RectF::new(
|
CursorShape::Underscore => RectF::new(
|
||||||
self.origin + Vector2F::new(0.0, self.line_height - 2.0),
|
self.origin + Vector2F::new(0.0, self.line_height - 2.0),
|
||||||
vec2f(self.character_width, 2.0),
|
vec2f(self.block_width, 2.0),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1273,6 +1300,10 @@ impl Cursor {
|
||||||
border: Border::new(0., Color::black()),
|
border: Border::new(0., Color::black()),
|
||||||
corner_radius: 0.,
|
corner_radius: 0.,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if let Some(block_text) = &self.block_text {
|
||||||
|
block_text.paint(self.origin, bounds, self.line_height, cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ pub struct Run {
|
||||||
pub glyphs: Vec<Glyph>,
|
pub glyphs: Vec<Glyph>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Glyph {
|
pub struct Glyph {
|
||||||
pub id: GlyphId,
|
pub id: GlyphId,
|
||||||
pub position: Vector2F,
|
pub position: Vector2F,
|
||||||
|
@ -210,10 +210,14 @@ impl Line {
|
||||||
self.layout.width
|
self.layout.width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn font_size(&self) -> f32 {
|
||||||
|
self.layout.font_size
|
||||||
|
}
|
||||||
|
|
||||||
pub fn x_for_index(&self, index: usize) -> f32 {
|
pub fn x_for_index(&self, index: usize) -> f32 {
|
||||||
for run in &self.layout.runs {
|
for run in &self.layout.runs {
|
||||||
for glyph in &run.glyphs {
|
for glyph in &run.glyphs {
|
||||||
if glyph.index == index {
|
if glyph.index >= index {
|
||||||
return glyph.position.x();
|
return glyph.position.x();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,6 +225,18 @@ impl Line {
|
||||||
self.layout.width
|
self.layout.width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn font_for_index(&self, index: usize) -> Option<FontId> {
|
||||||
|
for run in &self.layout.runs {
|
||||||
|
for glyph in &run.glyphs {
|
||||||
|
if glyph.index >= index {
|
||||||
|
return Some(run.font_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn index_for_x(&self, x: f32) -> Option<usize> {
|
pub fn index_for_x(&self, x: f32) -> Option<usize> {
|
||||||
if x >= self.layout.width {
|
if x >= self.layout.width {
|
||||||
None
|
None
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue