#2105: Highlight No Color sticks to the button (#2208)

No Color removed the highlight from the selection, but the Highlight
split button kept the colour picked before, so the next click on it
highlighted again. As in Word, No Color now becomes the button's choice
and the next click removes highlighting. The ribbon and the mini toolbar
share one highlight menu (the ribbon's copy is gone); No Color is
translated in the mini toolbar and no longer shows Ctrl+Alt+H beside it
in the ribbon.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-10-18 11:40:55 -04:00
1 parent e04dd0e785
commit 63ee34c557
4 files changed
+58 -23

No files matched your search

+2
View File
@@ -173,6 +173,7 @@ Imported Word 97–2003 `.doc`/`.dot` files now ask for a supported DOCX target
| 2026-10-15 | Hide Quick Access Toolbar (#1945): the toolbar's menu ends with Hide Quick Access Toolbar, as Word's does; the ribbon's right-click menu and Customize Ribbon › Quick Access Toolbar offer Show Quick Access Toolbar; kept between runs; `ui.quickAccessToolbar {"value"?}` for scripts and MCP |
| 2026-10-15 | Rulers: the numbers thin out as the page shrinks on screen (every 1, 2, 4… units, at least 30 px apart, the small ticks at least 4 px apart), give way to the indent, tab and column markers, and the margins get ticks only; both rulers span the caret's page at its own scale in One Page and Multiple Pages and follow the caret to another page (#1878) |
| 2026-10-15 | Spelling as you type no longer flags the word being typed; the squiggle comes when the word ends or the caret leaves it, as in Word (#1552) |
| 2026-10-15 | Text Highlight Color: No Color becomes the Highlight button's choice, as in Word, so the next click on the button removes highlighting instead of applying the colour picked before; the ribbon and the mini toolbar share one menu (#2105) |
|---|---|
| 2026-10-16 | Save Changes gives assistive technology a named alert dialog with the loss warning and any save failure; visual layout and save policy unchanged (#1015). Native screen-reader verification remains pending. |
| 2026-10-15 | The font family caches are bounded (4096 families for text, 1024 for math, names over 256 bytes aren't remembered), so a document naming thousands of missing fonts can't grow memory; equation fonts are looked up again after a font is added or removed instead of keeping the old choice (#1354) |
@@ -532,6 +533,7 @@ Imported Word 97–2003 `.doc`/`.dot` files now ask for a supported DOCX target
| 2026-10-15 | trivial | Progress log: Hide Quick Access Toolbar (#1945) |
| 2026-10-15 | trivial | Progress log: native ink nested in groups and drawing canvases kept on save |
| 2026-10-15 | trivial | Progress log: the word being typed gets no squiggle until the caret leaves it (#1552) |
| 2026-10-15 | trivial | Progress log: Highlight No Color sticks to the button (#2105) |
| 2026-10-14 | trivial | Progress log: row table border exceptions |
| 2026-10-12 | minor | Czech proofing review: short-word splits rank after deletion, NOSUGGEST excludes suggestions while accepting typed forms, affix comments apply only to headers, ratios keep spaces and repeated-word messages use Czech quotes; synthetic engine end-to-end and latency checks |
| 2026-10-12 | minor | Czech spelling from the installed Hunspell dictionary, runtime-table suggestions and generic checks; Czech interface writes cs-CZ documents; no Czech hyphenation patterns bundled; estimates unchanged |
+44 -4
View File
@@ -274,8 +274,10 @@ fn sep(ui: &mut egui::Ui, t: &Tokens) {
p.vline(r.center().x, r.y_range().shrink(4.0), egui::Stroke::new(1.0, t.border));
}
/// Highlight colour grid, matching the ribbon's.
fn highlight_menu(ui: &mut egui::Ui, app: &mut WordApp) {
/// Highlight colour grid and No Color, shared by the ribbon and the mini toolbar. The pick,
/// No Color too, becomes the split button's colour, as in Word: after No Color a click on the
/// button removes highlighting (#2105).
pub(crate) fn highlight_menu(ui: &mut egui::Ui, app: &mut WordApp) {
egui::Grid::new("mini_hl").spacing(Vec2::new(3.0, 3.0)).show(ui, |ui| {
for (i, h) in wordcraft_doc::props::Highlight::ALL.iter().enumerate().skip(1) {
let Some(c) = h.rgb() else { continue };
@@ -291,8 +293,10 @@ fn highlight_menu(ui: &mut egui::Ui, app: &mut WordApp) {
}
}
});
if ui.selectable_label(false, "No Color").clicked() {
let _ = app.run("format.highlight", json!({"color": "none"}));
let enabled = widgets::enabled(app, "format.highlight");
if ui.add_enabled(enabled, egui::Button::new(tl!("No Color")).min_size(Vec2::new(200.0, 0.0))).clicked() {
app.canvas.last_highlight = "none".into();
widgets::run_from_ribbon(app, "format.highlight", json!({"color": "none"}));
ui.close();
}
}
@@ -638,4 +642,40 @@ mod tests {
assert_eq!(format_state(&mut h).get("size").and_then(Value::as_f64), Some(20.0), "the bar's size list applied 20 pt");
assert!(visible(h.state()) && bar_layer(&h).is_some(), "the bar stays up after its own list is used");
}
/// #2105: No Color removed the highlight but the Highlight button kept the colour picked
/// before, so the next click on it highlighted again. As in Word, No Color becomes the
/// button's choice: the next click removes highlighting.
#[test]
fn no_color_becomes_the_highlight_buttons_choice() {
use egui_kittest::kittest::{By, Queryable};
let mut h = bar_over("brown fox");
h.state_mut().run("format.highlight", json!({"color": "yellow"})).unwrap();
steps(&mut h);
// The bar's split buttons are Highlight then Font Color; their arrows are 11 × 22.
let highlight_arrow = |h: &egui_kittest::Harness<'static, WordApp>| {
let [bar, _] = h.ctx.data(|d| d.get_temp::<[Rect; 2]>(shown_id())).expect("the bar is shown over a selection");
h.query_all(
By::new().predicate(|n| n.raw_bounds().is_some_and(|r| ((r.x1 - r.x0) - 11.0).abs() < 0.5 && ((r.y1 - r.y0) - 22.0).abs() < 0.5)),
)
.map(|n| n.rect())
.filter(|r| bar.contains_rect(*r))
.min_by(|a, b| a.min.x.total_cmp(&b.min.x))
.expect("the bar has the Highlight split button")
};
let arrow = highlight_arrow(&h);
click_at(&mut h, arrow.center());
let no_color = h.get(By::new().label_contains("No Color")).rect().center();
click_at(&mut h, no_color);
assert_eq!(format_state(&mut h).get("highlight"), Some(&Value::Null), "No Color removed the highlight");
assert_eq!(h.state().canvas.last_highlight, "none");
// Other highlighted text, then the button itself (left of its arrow): no highlight.
h.state_mut().run("select.text", json!({"text": "lazy"})).unwrap();
h.state_mut().run("format.highlight", json!({"color": "yellow"})).unwrap();
steps(&mut h);
let arrow = highlight_arrow(&h);
click_at(&mut h, pos2(arrow.min.x - 12.0, arrow.center().y));
assert_eq!(format_state(&mut h).get("highlight"), Some(&Value::Null), "the button applies No Color, not yellow again");
}
}
+11 -19
View File
@@ -1015,25 +1015,17 @@ fn home(app: &mut WordApp, ui: &mut Ui) {
mi(ui, app, "Double Strikethrough", "format.doubleStrikethrough", json!({}));
});
let hl = app.canvas.last_highlight.clone();
split(ui, app, "highlight", "Text Highlight Color", "format.highlight", json!({"color": hl}), false, None, |ui, app| {
let grid = wordcraft_doc::props::Highlight::ALL;
egui::Grid::new("hl").spacing(vec2(3.0, 3.0)).show(ui, |ui| {
for (i, h) in grid.iter().enumerate().skip(1) {
let c = h.rgb().unwrap_or(wordcraft_doc::Rgb::WHITE);
let (r, resp) = ui.allocate_exact_size(vec2(18.0, 18.0), Sense::click());
ui.painter().rect_filled(r, 2.0, egui::Color32::from_rgb(c.0, c.1, c.2));
if resp.on_hover_text(h.name()).clicked() {
app.canvas.last_highlight = h.ooxml().to_string();
let _ = app.run("format.highlight", json!({"color": h.ooxml()}));
ui.close();
}
if i % 5 == 0 {
ui.end_row();
}
}
});
mi(ui, app, "No Color", "format.highlight", json!({"color": "none"}));
});
split(
ui,
app,
"highlight",
"Text Highlight Color",
"format.highlight",
json!({"color": hl}),
false,
None,
crate::mini_toolbar::highlight_menu,
);
let fc = app.canvas.last_font_color.clone();
let sw = wordcraft_doc::Rgb::parse(&fc).map(crate::theme::c32);
split(ui, app, "fontcolor", "Font Color", "format.color", json!({"color": fc}), false, sw, |ui, app| {
+1
View File
@@ -98,6 +98,7 @@ Find selects the Results tab, including when it prefills selected text. Editing
| 2026-10-15 | trivial | Quick Access Toolbar: Hide Quick Access Toolbar at the end of its menu; Show Quick Access Toolbar on the ribbon's right-click menu and in Customize Ribbon › Quick Access Toolbar; kept between runs; `ui.quickAccessToolbar` (#1945) |
| 2026-10-15 | trivial | Rulers: numbers thin out with the zoom (every 1, 2, 4… units, at least 30 px apart; ticks at least 4 px apart), give way to the indent, tab and column markers, margins get ticks only; both rulers span the caret's page in every layout and follow the caret (#1878); Rulers 90% → 92% |
| 2026-10-15 | trivial | Spelling as you type: the word being typed has no red squiggle until the caret leaves it, by a key or a click; misspelled words already there keep theirs (#1552) |
| 2026-10-15 | trivial | Text Highlight Color: No Color becomes the Highlight button's choice, as in Word, so the next click on the button removes highlighting instead of applying the colour picked before; the ribbon and the mini toolbar share one menu (#2105) |
| 2026-10-13 | trivial | New/Modify Table Style: No Border on a part that inherits its lines hides them; emptying the font box makes the part's font inherited again (#1288) |
| 2026-10-14 | trivial | Tab stops edited on the ruler: corner kind selector, click to set, drag to move or off to clear, per-kind markers mirrored for RTL; each gesture one `para.tabs` call and one undo step; Rulers 85% → 90% |
| 2026-10-12 | trivial | Tables on the page: one selected cell (Select Cell, or a click along its left edge) is a cell selection when its border is dragged: the border moves in its row only (#962) |