On-page text boxes keep a dark caret on their white backgrounds in the dark theme (#655) (#734)

* Text editor on the page keeps a dark caret on its white box in the dark theme (#655)

* Form fields, typed fill text and added text keep a dark caret on their white boxes in the dark theme (#655)

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
MarekSpodBiedry 2026-10-11 20:42:14 +02:00 committed by GitHub
parent 2ec7102035
commit 8983f05c78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 24 additions and 2 deletions

View File

@ -337,6 +337,8 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad
let memo = &view.content.undrawable;
egui::Area::new(egui::Id::new(("added-text", view.id.0))).order(egui::Order::Foreground).fixed_pos(r.min).show(ctx, |ui| {
let Some(t) = view.content.draft.as_mut() else { return };
// The box is white in every theme, so the caret must not follow the theme (pale in dark mode) (#655).
ui.visuals_mut().text_cursor.stroke.color = crate::edit_text_ui::caret_color_on(Color32::WHITE);
let [cr, cg, cb] = t.style.color.map(|v| (v.clamp(0.0, 1.0) * 255.0) as u8);
ui.horizontal_top(|ui| {
ui.spacing_mut().item_spacing.x = 4.0;

View File

@ -561,7 +561,7 @@ pub(crate) fn overlay(ctx: &egui::Context, view: &mut DocView, info: &DocInfo) -
// banner, #913): then a dark box, with a caret that shows on it.
let fill = editor_fill(text_color);
egui::Frame::NONE.fill(fill).stroke(Stroke::new(1.5, ACCENT)).inner_margin(egui::Margin::symmetric(2, 0)).show(ui, |ui| {
ui.visuals_mut().text_cursor.stroke.color = if fill == Color32::WHITE { Color32::BLACK } else { Color32::WHITE };
ui.visuals_mut().text_cursor.stroke.color = caret_color_on(fill);
let rows = ed.text.lines().count().max(1);
let r = ui.add(
egui::TextEdit::multiline(&mut ed.text)
@ -601,6 +601,12 @@ pub(crate) fn overlay(ctx: &egui::Context, view: &mut DocView, info: &DocInfo) -
}
}
/// Caret colour that stays visible on a field filled with `fill`: black on light fills, white on dark ones.
pub(crate) fn caret_color_on(fill: Color32) -> Color32 {
let luma = 299 * u32::from(fill.r()) + 587 * u32::from(fill.g()) + 114 * u32::from(fill.b());
if luma > 127_500 { Color32::BLACK } else { Color32::WHITE }
}
#[cfg(test)]
mod tests {
use super::*;
@ -617,4 +623,12 @@ mod tests {
assert_eq!(editor_fill(dark), Color32::WHITE, "{dark:?}");
}
}
#[test]
fn caret_contrasts_with_its_fill() {
assert_eq!(caret_color_on(Color32::WHITE), Color32::BLACK);
assert_eq!(caret_color_on(Color32::from_rgb(0xFF, 0xFF, 0xF4)), Color32::BLACK);
assert_eq!(caret_color_on(Color32::BLACK), Color32::WHITE);
assert_eq!(caret_color_on(DARK_EDITOR_FILL), Color32::WHITE);
}
}

View File

@ -471,6 +471,8 @@ pub(crate) fn type_box(ctx: &egui::Context, view: &mut DocView, info: &DocInfo,
let mut cancel = false;
egui::Area::new(egui::Id::new(("fill-text", view.id.0))).order(egui::Order::Foreground).fixed_pos(pos).show(ctx, |ui| {
let Some(t) = view.fill_text.as_mut() else { return };
// The box is white in every theme, so the caret must not follow the theme (pale in dark mode) (#655).
ui.visuals_mut().text_cursor.stroke.color = crate::edit_text_ui::caret_color_on(Color32::WHITE);
let width = ((t.text.chars().count().max(8) as f32) * TEXT_SIZE as f32 * 0.6 * zoom).clamp(60.0, 600.0);
// The area's max rect is last frame's size, which caps the edit's width; widen it so the
// box grows as text is typed.

View File

@ -12,6 +12,8 @@ use crate::canvas::{DocView, PageXform};
use crate::theme::Tokens;
const FOCUS_BLUE: Color32 = Color32::from_rgb(0x14, 0x73, 0xE6);
/// Background of the in-place text field editor, the same in every theme.
const FIELD_FILL: Color32 = Color32::from_rgb(0xFF, 0xFF, 0xF4);
/// The field being edited.
#[derive(Clone, Debug, PartialEq)]
@ -295,11 +297,13 @@ pub(crate) fn overlay(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, f
egui::Area::new(egui::Id::new(("form-editor", view.id.0))).order(egui::Order::Foreground).fixed_pos(rect.min).show(ctx, |ui| {
ui.set_min_size(rect.size());
let Some(fx) = view.forms.focus.as_mut() else { return };
// The field is pale yellow in every theme, so the caret must not follow the theme (pale in dark mode) (#655).
ui.visuals_mut().text_cursor.stroke.color = crate::edit_text_ui::caret_color_on(FIELD_FILL);
let mut te = if multiline { egui::TextEdit::multiline(&mut fx.text) } else { egui::TextEdit::singleline(&mut fx.text) };
te = te
.desired_width(rect.width() - 6.0)
.font(egui::FontId::proportional(font))
.background_color(Color32::from_rgb(0xFF, 0xFF, 0xF4))
.background_color(FIELD_FILL)
.text_color(Color32::BLACK)
.margin(egui::Margin::symmetric(3, 1))
.password(f.has(field_flags::PASSWORD))