mirror of
https://github.com/emilk/egui.git
synced 2026-06-28 07:23:13 -04:00
Enables every combination of TextEdit and LayoutJob alignments (#7831)
<!-- Please read the "Making a PR" section of [`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md) before opening a Pull Request! * Keep your PR:s small and focused. * The PR title is what ends up in the changelog, so make it descriptive! * If applicable, add a screenshot or gif. * If it is a non-trivial addition, consider adding a demo for it to `egui_demo_lib`, or a new example. * Do NOT open PR:s from your `master` branch, as that makes it hard for maintainers to test and add commits to your PR. * Remember to run `cargo fmt` and `cargo clippy`. * Open the PR as a draft until you have self-reviewed it and run `./scripts/check.sh`. * When you have addressed a PR comment, mark it as resolved. Please be patient! I will review your PR, but my time is limited! --> This is a fix/improvement that makes all kinds of alignments work in `TextEdit` when a custom `LayoutJob` with halign is used. I used the simplest approach possible to avoid unwanted bugs as I wasn't sure what's safe to change, but there's potentially better ways to achieve this. In particular, I'm not sure I fully understand the rationale behind aligning rows in a `Galley` based on the latter's leftmost border, considering the size is what's ultimately used in widgets (in `TextEdit` at least). Regardless, here's a demo of this PR: https://github.com/user-attachments/assets/5d9801d7-73af-4576-80c5-47f169700462 * [x] I have followed the instructions in the PR template --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
@@ -820,7 +820,11 @@ impl TextEdit<'_> {
|
||||
paint_text_selection(&mut galley, ui.visuals(), &cursor_range, None);
|
||||
}
|
||||
|
||||
painter.galley(galley_pos, Arc::clone(&galley), text_color);
|
||||
painter.galley(
|
||||
galley_pos - vec2(galley.rect.left(), 0.0),
|
||||
Arc::clone(&galley),
|
||||
text_color,
|
||||
);
|
||||
|
||||
if has_focus && let Some(cursor_range) = state.cursor.range(&galley) {
|
||||
let primary_cursor_rect = cursor_rect(&galley, &cursor_range.primary, row_height)
|
||||
|
||||
@@ -1047,7 +1047,7 @@ impl Galley {
|
||||
return self.end_pos();
|
||||
};
|
||||
|
||||
let x = row.x_offset(layout_cursor.column);
|
||||
let x = row.x_offset(layout_cursor.column) + row.pos.x - self.rect.left();
|
||||
Rect::from_min_max(pos2(x, row.min_y()), pos2(x, row.max_y()))
|
||||
}
|
||||
|
||||
@@ -1092,7 +1092,7 @@ impl Galley {
|
||||
if is_pos_within_row || y_dist < best_y_dist {
|
||||
best_y_dist = y_dist;
|
||||
// char_at is `Row` not `PlacedRow` relative which means we have to subtract the pos.
|
||||
let column = row.char_at(pos.x - row.pos.x);
|
||||
let column = row.char_at(pos.x - row.pos.x + self.rect.left());
|
||||
let prefer_next_row = column < row.char_count_excluding_newline();
|
||||
cursor = CCursor {
|
||||
index: ccursor_index + column,
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use egui::ScrollArea;
|
||||
use egui::accesskit::Role;
|
||||
use egui::epaint::Shape;
|
||||
use egui::style::ScrollAnimation;
|
||||
use egui::text::{LayoutJob, TextWrapping};
|
||||
use egui::{
|
||||
Align, Color32, Image, Label, Layout, RichText, ScrollArea, Sense, TextWrapMode, include_image,
|
||||
Align, Color32, FontFamily, FontId, Image, Label, Layout, RichText, Sense, TextBuffer,
|
||||
TextFormat, TextWrapMode, Ui, include_image, vec2,
|
||||
};
|
||||
use egui_kittest::Harness;
|
||||
use egui_kittest::kittest::Queryable as _;
|
||||
@@ -66,6 +71,53 @@ fn text_edit_rtl() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_edit_halign() {
|
||||
let mut harness = Harness::builder().with_size((212.0, 212.0)).build_ui(|ui| {
|
||||
ui.spacing_mut().item_spacing = vec2(2.0, 2.0);
|
||||
|
||||
fn layouter(halign: Align) -> impl FnMut(&Ui, &dyn TextBuffer, f32) -> Arc<egui::Galley> {
|
||||
move |ui: &egui::Ui, buf: &dyn egui::TextBuffer, wrap_width: f32| {
|
||||
let mut job = LayoutJob {
|
||||
wrap: TextWrapping {
|
||||
max_rows: 4,
|
||||
max_width: wrap_width,
|
||||
..Default::default()
|
||||
},
|
||||
halign,
|
||||
..Default::default()
|
||||
};
|
||||
job.append(
|
||||
buf.as_str(),
|
||||
0.0,
|
||||
TextFormat::simple(FontId::new(13.0, FontFamily::Proportional), Color32::GRAY),
|
||||
);
|
||||
ui.fonts_mut(|f| f.layout_job(job))
|
||||
}
|
||||
}
|
||||
|
||||
for widget_alignment in [Align::Min, Align::Center, Align::Max] {
|
||||
ui.horizontal(|ui| {
|
||||
for text_alignment in [Align::LEFT, Align::Center, Align::RIGHT] {
|
||||
ui.add_sized(
|
||||
vec2(64.0, 64.0),
|
||||
egui::TextEdit::multiline(&mut format!(
|
||||
"{widget_alignment:?}\n+\n{text_alignment:?}",
|
||||
))
|
||||
.layouter(&mut layouter(text_alignment))
|
||||
.vertical_align(widget_alignment)
|
||||
.horizontal_align(widget_alignment),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
harness.get_by_value("Center\n+\nCenter").focus();
|
||||
harness.step();
|
||||
harness.snapshot("text_edit_halign");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_edit_delay() {
|
||||
let mut text = String::new();
|
||||
|
||||
3
tests/egui_tests/tests/snapshots/text_edit_halign.png
Normal file
3
tests/egui_tests/tests/snapshots/text_edit_halign.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:502607c803b884e4e1640d39c97b03b0a40df93c2da328f889168e386f837f36
|
||||
size 13261
|
||||
Reference in New Issue
Block a user