diff --git a/crates/ui-egui/src/pivot_pane.rs b/crates/ui-egui/src/pivot_pane.rs index dc50b3e57..f205dc3ec 100644 --- a/crates/ui-egui/src/pivot_pane.rs +++ b/crates/ui-egui/src/pivot_pane.rs @@ -2,7 +2,7 @@ //! report. Ticking a field adds it (text → Rows, numbers → Values); each area lists its fields //! with move/remove menus. Everything runs `pivot.*` commands. -use egui::{Color32, Ui, vec2}; +use egui::{Ui, vec2}; use serde_json::{Value as Json, json}; use crate::SheetApp; @@ -88,7 +88,7 @@ pub fn show(app: &mut SheetApp, ui: &mut Ui) { let is_values = f == VALUES_FIELD; let b = ui.add( egui::Button::new(egui::RichText::new(format!("{f} ▾")).font(theme::ui_font(12.0))) - .fill(Color32::WHITE) + .fill(t.ribbon) .min_size(vec2(ui.available_width(), 20.0)), ); egui::Popup::menu(&b).show(|ui| { diff --git a/crates/ui-egui/tests/pivot_pane.rs b/crates/ui-egui/tests/pivot_pane.rs new file mode 100644 index 000000000..d08c0e076 --- /dev/null +++ b/crates/ui-egui/tests/pivot_pane.rs @@ -0,0 +1,58 @@ +//! Pivot field buttons use the surface color for the active theme. + +use egui::{Color32, RawInput, Rect, Shape, pos2, vec2}; +use gridcraft_engine::Session; +use gridcraft_ui_egui::{SheetApp, theme}; +use serde_json::json; + +fn render_pivot_field_buttons(dark: bool) -> Vec { + let mut session = Session::new(); + session.new_workbook(); + session.execute("range.setValues", json!({"range": "A1", "values": [["Region", "Sales"], ["East", 100], ["West", 80]]})).unwrap(); + session + .execute("insert.pivotTable", json!({"source": "Sheet1!A1:B3", "destination": "Sheet1!D3", "rows": ["Region"], "values": ["Sales"]})) + .unwrap(); + session.execute("selection.set", json!({"cell": "D3"})).unwrap(); + + let mut app = SheetApp::new(session, Default::default()); + app.ui.dark = dark; + let ctx = egui::Context::default(); + let mut output = egui::FullOutput::default(); + for _ in 0..6 { + output = ctx.run_ui(RawInput { screen_rect: Some(Rect::from_min_size(pos2(0.0, 0.0), vec2(1200.0, 800.0))), ..Default::default() }, |ui| { + let ctx = ui.ctx().clone(); + app.logic(&ctx); + app.ui(ui); + }); + output.textures_delta.clear(); + } + output.shapes.into_iter().map(|shape| shape.shape).collect() +} + +fn field_button_fill(shapes: &[Shape], label: &str) -> Color32 { + let text = shapes + .iter() + .find_map(|shape| match shape { + Shape::Text(text) if text.galley.text() == label => Some(text), + _ => None, + }) + .unwrap_or_else(|| panic!("pivot field button {label:?} was not painted")); + let text_rect = text.galley.rect.translate(text.pos.to_vec2()); + shapes + .iter() + .filter_map(|shape| match shape { + Shape::Rect(rect) if rect.rect.contains(text_rect.center()) => Some(rect), + _ => None, + }) + .min_by(|a, b| a.rect.area().total_cmp(&b.rect.area())) + .unwrap_or_else(|| panic!("pivot field button {label:?} has no painted background")) + .fill +} + +#[test] +fn pivot_field_button_surfaces_follow_the_active_theme() { + for (dark, expected) in [(false, theme::Tokens::light().ribbon), (true, theme::Tokens::dark().ribbon)] { + let shapes = render_pivot_field_buttons(dark); + assert_eq!(field_button_fill(&shapes, "Region ▾"), expected, "dark mode: {dark}"); + } +}