core: Fix caret and selection rendering
This commit fixes issues with caret and selection rendering: 1. They had the wrong height and were rendered lower than expected for some fonts and sizes. 2. The caret was not being rendered at all when there was no text, but only when the text was set earlier and then deleted. 3. The selection was rendered with translate_x=-1, which caused overlap over some glyphs.
This commit is contained in:
parent
6b7bca1fd6
commit
5ece6981ce
|
@ -934,7 +934,7 @@ impl<'gc> EditText<'gc> {
|
||||||
&& visible_selection.end() <= *end
|
&& visible_selection.end() <= *end
|
||||||
&& Utc::now().timestamp_subsec_millis() / 500 == 0
|
&& Utc::now().timestamp_subsec_millis() / 500 == 0
|
||||||
{
|
{
|
||||||
Some((visible_selection.start() - start, end - start))
|
Some(visible_selection.start() - start)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -958,8 +958,11 @@ impl<'gc> EditText<'gc> {
|
||||||
if let Some((text, _tf, font, params, color)) =
|
if let Some((text, _tf, font, params, color)) =
|
||||||
lbox.as_renderable_text(edit_text.text_spans.displayed_text())
|
lbox.as_renderable_text(edit_text.text_spans.displayed_text())
|
||||||
{
|
{
|
||||||
let baseline_adjustment =
|
let baseline = font.get_baseline_for_height(params.height());
|
||||||
font.get_baseline_for_height(params.height()) - params.height();
|
let descent = font.get_descent_for_height(params.height());
|
||||||
|
let baseline_adjustment = baseline - params.height();
|
||||||
|
let caret_height = baseline + descent;
|
||||||
|
let mut caret_x = Twips::ZERO;
|
||||||
font.evaluate(
|
font.evaluate(
|
||||||
text,
|
text,
|
||||||
self.text_transform(color, baseline_adjustment),
|
self.text_transform(color, baseline_adjustment),
|
||||||
|
@ -967,29 +970,18 @@ impl<'gc> EditText<'gc> {
|
||||||
|pos, transform, glyph: &Glyph, advance, x| {
|
|pos, transform, glyph: &Glyph, advance, x| {
|
||||||
if let Some(glyph_shape_handle) = glyph.shape_handle(context.renderer) {
|
if let Some(glyph_shape_handle) = glyph.shape_handle(context.renderer) {
|
||||||
// If it's highlighted, override the color.
|
// If it's highlighted, override the color.
|
||||||
match visible_selection {
|
if matches!(visible_selection, Some(visible_selection) if visible_selection.contains(start + pos)) {
|
||||||
Some(visible_selection) if visible_selection.contains(start + pos) => {
|
|
||||||
// Draw black selection rect
|
// Draw black selection rect
|
||||||
let selection_box = context.transform_stack.transform().matrix
|
self.render_selection(context, x, advance, caret_height);
|
||||||
* Matrix::create_box(
|
|
||||||
advance.to_pixels() as f32,
|
|
||||||
params.height().to_pixels() as f32,
|
|
||||||
0.0,
|
|
||||||
x + Twips::from_pixels(-1.0),
|
|
||||||
Twips::from_pixels(2.0),
|
|
||||||
);
|
|
||||||
context.commands.draw_rect(Color::BLACK, selection_box);
|
|
||||||
|
|
||||||
// Set text color to white
|
// Set text color to white
|
||||||
context.transform_stack.push(&Transform {
|
context.transform_stack.push(&Transform {
|
||||||
matrix: transform.matrix,
|
matrix: transform.matrix,
|
||||||
color_transform: ColorTransform::IDENTITY,
|
color_transform: ColorTransform::IDENTITY,
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
_ => {
|
|
||||||
context.transform_stack.push(transform);
|
context.transform_stack.push(transform);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Render glyph.
|
// Render glyph.
|
||||||
context
|
context
|
||||||
|
@ -998,31 +990,21 @@ impl<'gc> EditText<'gc> {
|
||||||
context.transform_stack.pop();
|
context.transform_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((caret_pos, length)) = caret {
|
// Update caret position
|
||||||
if caret_pos == pos {
|
if let Some(caret) = caret {
|
||||||
let caret = context.transform_stack.transform().matrix
|
if pos == caret {
|
||||||
* Matrix::create_box(
|
caret_x = x;
|
||||||
1.0,
|
} else if caret > 0 && pos == caret - 1 {
|
||||||
params.height().to_pixels() as f32,
|
// The caret may be rendered at the end, after all glyphs.
|
||||||
0.0,
|
caret_x = x + advance;
|
||||||
x + Twips::from_pixels(-1.0),
|
|
||||||
Twips::from_pixels(2.0),
|
|
||||||
);
|
|
||||||
context.commands.draw_rect(color, caret);
|
|
||||||
} else if pos == length - 1 && caret_pos == length {
|
|
||||||
let caret = context.transform_stack.transform().matrix
|
|
||||||
* Matrix::create_box(
|
|
||||||
1.0,
|
|
||||||
params.height().to_pixels() as f32,
|
|
||||||
0.0,
|
|
||||||
x + advance,
|
|
||||||
Twips::from_pixels(2.0),
|
|
||||||
);
|
|
||||||
context.commands.draw_rect(color, caret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if caret.is_some() {
|
||||||
|
self.render_caret(context, caret_x, caret_height, color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(drawing) = lbox.as_renderable_drawing() {
|
if let Some(drawing) = lbox.as_renderable_drawing() {
|
||||||
|
@ -1032,6 +1014,43 @@ impl<'gc> EditText<'gc> {
|
||||||
context.transform_stack.pop();
|
context.transform_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_selection(
|
||||||
|
self,
|
||||||
|
context: &mut RenderContext<'_, 'gc>,
|
||||||
|
x: Twips,
|
||||||
|
width: Twips,
|
||||||
|
height: Twips,
|
||||||
|
) {
|
||||||
|
let selection_box = context.transform_stack.transform().matrix
|
||||||
|
* Matrix::create_box(
|
||||||
|
width.to_pixels() as f32,
|
||||||
|
height.to_pixels() as f32,
|
||||||
|
0.0,
|
||||||
|
x,
|
||||||
|
Twips::ZERO,
|
||||||
|
);
|
||||||
|
context.commands.draw_rect(Color::BLACK, selection_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_caret(
|
||||||
|
self,
|
||||||
|
context: &mut RenderContext<'_, 'gc>,
|
||||||
|
x: Twips,
|
||||||
|
height: Twips,
|
||||||
|
color: Color,
|
||||||
|
) {
|
||||||
|
let cursor_width = Twips::from_pixels(1.0);
|
||||||
|
let caret = context.transform_stack.transform().matrix
|
||||||
|
* Matrix::create_box(
|
||||||
|
cursor_width.to_pixels() as f32,
|
||||||
|
height.to_pixels() as f32,
|
||||||
|
0.0,
|
||||||
|
x - cursor_width,
|
||||||
|
Twips::ZERO,
|
||||||
|
);
|
||||||
|
context.commands.draw_rect(color, caret);
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempts to bind this text field to a property of a display object.
|
/// Attempts to bind this text field to a property of a display object.
|
||||||
/// If we find a parent display object matching the given path, we register oursevles and a property name with it.
|
/// If we find a parent display object matching the given path, we register oursevles and a property name with it.
|
||||||
/// `set_text` will be called by the stage object whenever the property changes.
|
/// `set_text` will be called by the stage object whenever the property changes.
|
||||||
|
@ -1977,19 +1996,9 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
||||||
&& visible_selection.start() == 0
|
&& visible_selection.start() == 0
|
||||||
&& Utc::now().timestamp_subsec_millis() / 500 == 0
|
&& Utc::now().timestamp_subsec_millis() / 500 == 0
|
||||||
{
|
{
|
||||||
let caret = context.transform_stack.transform().matrix
|
let format = edit_text.text_spans.default_format();
|
||||||
* Matrix::create_box(
|
let caret_height = format.size.map(Twips::from_pixels).unwrap_or_default();
|
||||||
1.0,
|
self.render_caret(context, Twips::ZERO, caret_height, Color::BLACK);
|
||||||
edit_text
|
|
||||||
.text_spans
|
|
||||||
.default_format()
|
|
||||||
.size
|
|
||||||
.unwrap_or_default() as f32,
|
|
||||||
0.0,
|
|
||||||
Twips::from_pixels(-1.0),
|
|
||||||
Twips::from_pixels(2.0),
|
|
||||||
);
|
|
||||||
context.commands.draw_rect(Color::BLACK, caret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue