Merge PR #1180: fix(ui): menu items highlight under the pointer (#1174)

crates/ui-egui/src/grid.rs: list picker button combines frame_when_inactive(false) with main's LIST_PICKER_ROW_H min size.
This commit is contained in:
aiongg
2026-10-22 02:37:42 +00:00
3 changed files with 75 additions and 4 deletions
+3 -3
View File
@@ -2981,7 +2981,7 @@ fn context_menu(app: &mut SheetApp, ui: &mut egui::Ui) {
ui.separator();
continue;
}
if ui.add(egui::Button::new(lang.tr(label)).frame(false).min_size(vec2(190.0, 20.0))).clicked() {
if ui.add(egui::Button::new(lang.tr(label)).frame_when_inactive(false).min_size(vec2(190.0, 20.0))).clicked() {
close = true;
match id {
"ui:pasteSpecial" => app.open_dialog("pasteSpecial", json!({})),
@@ -3214,7 +3214,7 @@ fn list_picker(app: &mut SheetApp, ui: &mut egui::Ui, geo: &Geo, was_open: bool)
ui.set_min_width(r.width().max(100.0));
egui::ScrollArea::vertical().max_height(height).min_scrolled_height(height).show(ui, |ui| {
for it in &items {
if ui.add(egui::Button::new(it.as_str()).frame(false).min_size(vec2(r.width().max(100.0), LIST_PICKER_ROW_H))).clicked() {
if ui.add(egui::Button::new(it.as_str()).frame_when_inactive(false).min_size(vec2(r.width().max(100.0), LIST_PICKER_ROW_H))).clicked() {
app.run_or_alert("cell.set", json!({"cell": c.a1(), "input": it}));
close = true;
}
@@ -3277,7 +3277,7 @@ fn header_menu(app: &mut SheetApp, ui: &mut egui::Ui, was_open: bool) {
ui.separator();
continue;
}
if ui.add(egui::Button::new(lang.tr(label)).frame(false).min_size(vec2(180.0, 20.0))).clicked() {
if ui.add(egui::Button::new(lang.tr(label)).frame_when_inactive(false).min_size(vec2(180.0, 20.0))).clicked() {
close = true;
match id {
"ui:insertPaste" => app.open_dialog("insertPaste", json!({})),
+1 -1
View File
@@ -492,7 +492,7 @@ fn menu_items(app: &mut SheetApp, ui: &mut Ui, items: &[(&str, &str, serde_json:
continue;
}
let lang = app.ui.language;
let response = ui.add(egui::Button::new(lang.tr(label)).frame(false).min_size(vec2(220.0, 22.0)));
let response = ui.add(egui::Button::new(lang.tr(label)).frame_when_inactive(false).min_size(vec2(220.0, 22.0)));
if let Some(sequence) = keytip_table::item_letter(app.keytips.prefix().unwrap_or_default(), id) {
keytip(app, ui, sequence, pos2(response.rect.right() - 10.0, response.rect.center().y));
}
+71
View File
@@ -0,0 +1,71 @@
//! Menu items highlight under the pointer, as in Excel (#1174): no background at rest, the hover
//! background while the pointer is on an item.
use egui::{Event, Modifiers, PointerButton, Pos2, Shape, accesskit::Role};
use egui_kittest::kittest::Queryable as _;
use gridcraft_engine::Session;
use gridcraft_engine::core::CellRef;
use gridcraft_ui_egui::{SheetApp, grid};
type Harness = egui_kittest::Harness<'static, SheetApp>;
fn harness() -> Harness {
let mut s = Session::new();
s.new_workbook();
let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state(
|ui, app: &mut SheetApp| {
app.logic(ui.ctx());
app.ui(ui);
},
SheetApp::new(s, Default::default()),
);
h.run_steps(4);
h
}
fn cell_center(h: &Harness, cell: &str) -> egui::Rect {
let app = h.state();
let sh = app.session.active().unwrap().wb.active().unwrap();
let geo = grid::Geo::new(sh, app.grid.rect.unwrap(), app.view().scroll);
geo.cell_rect(sh, CellRef::parse(cell).unwrap())
}
fn right_click(h: &mut Harness, pos: Pos2) {
h.input_mut().events.push(Event::PointerMoved(pos));
for pressed in [true, false] {
h.input_mut().events.push(Event::PointerButton { pos, button: PointerButton::Secondary, pressed, modifiers: Modifiers::NONE });
h.run_steps(2);
}
}
/// Is a filled rectangle in the hovered-widget colour painted under `at`?
fn hover_fill_under(h: &Harness, at: Pos2) -> bool {
let fill = h.ctx.global_style().visuals.widgets.hovered.weak_bg_fill;
h.output().shapes.iter().any(|s| matches!(&s.shape, Shape::Rect(r) if r.fill == fill && r.rect.contains(at)))
}
fn check_item(h: &mut Harness, label: &str) {
let at = h.get_by_role_and_label(Role::Button, label).rect().center();
assert!(!hover_fill_under(h, at), "{label} has no background before the pointer is on it");
h.input_mut().events.push(Event::PointerMoved(at));
h.run_steps(2);
assert!(hover_fill_under(h, at), "{label} is highlighted under the pointer");
}
#[test]
fn cell_menu_items_highlight_under_the_pointer() {
let mut h = harness();
let pos = cell_center(&h, "C5").center();
right_click(&mut h, pos);
assert!(h.state().grid.context_menu.is_some());
check_item(&mut h, "Copy");
}
#[test]
fn header_menu_items_highlight_under_the_pointer() {
let mut h = harness();
let c1 = cell_center(&h, "C1");
right_click(&mut h, egui::pos2(c1.center().x, c1.top() - 6.0));
assert!(h.state().grid.header_menu.is_some());
check_item(&mut h, "Copy");
}