mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 02:36:48 -06:00
Merge PR #2369
This commit is contained in:
@@ -22,7 +22,7 @@ pub fn restore(app: &mut SheetApp, ui: Option<&str>, prefs: Option<&str>) {
|
||||
{
|
||||
// No usable saved language: keep the browser's, as the desktop keeps the system's.
|
||||
let language = gridcraft_ui_egui::i18n::saved_language(&json).unwrap_or(app.ui.language);
|
||||
app.ui = state;
|
||||
app.ui = state.at_startup();
|
||||
app.ui.language = language;
|
||||
}
|
||||
if let Some(s) = prefs.filter(readable)
|
||||
|
||||
@@ -111,7 +111,7 @@ fn load_prefs(app: &mut SheetApp) {
|
||||
{
|
||||
let saved = serde_json::from_slice(&b).ok().and_then(|v| gridcraft_ui_egui::i18n::saved_language(&v));
|
||||
let language = saved.unwrap_or(app.ui.language);
|
||||
app.ui = ui;
|
||||
app.ui = ui.at_startup();
|
||||
app.ui.language = language;
|
||||
}
|
||||
if let Ok(b) = std::fs::read(dir.join("prefs.json"))
|
||||
|
||||
@@ -117,6 +117,14 @@ impl Default for UiState {
|
||||
}
|
||||
|
||||
impl UiState {
|
||||
/// The state saved by an earlier run, as the app starts with it. The ribbon tab is written to
|
||||
/// the preferences but not restored: Excel opens on Home every launch, so a contextual tab
|
||||
/// (Table Design) cannot come back with nothing selected to justify it.
|
||||
pub fn at_startup(mut self) -> Self {
|
||||
self.ribbon_tab = "Home".into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn theme_preference(&self) -> egui::ThemePreference {
|
||||
if self.system_theme {
|
||||
egui::ThemePreference::System
|
||||
|
||||
@@ -204,6 +204,11 @@ pub fn show(app: &mut SheetApp, ui: &mut Ui) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let collapsed = app.ui.ribbon_collapsed;
|
||||
let h = if collapsed { 34.0 } else { 34.0 + 92.0 };
|
||||
// A contextual tab exists only while its object is selected (Excel hides Table Design once the
|
||||
// cell leaves the table); a remembered one that is gone would draw an empty ribbon.
|
||||
if CONTEXTUAL_TABS.contains(&app.ui.ribbon_tab.as_str()) && !contextual_tabs(app).contains(&app.ui.ribbon_tab.as_str()) {
|
||||
app.ui.ribbon_tab = "Home".to_string();
|
||||
}
|
||||
egui::Panel::top("ribbon")
|
||||
.exact_size(h)
|
||||
.frame(egui::Frame::NONE.fill(t.window).inner_margin(egui::Margin { left: 10, right: 10, top: 0, bottom: 6 }))
|
||||
@@ -322,6 +327,8 @@ fn theme_choices(app: &mut SheetApp, ui: &mut Ui) {
|
||||
}
|
||||
}
|
||||
|
||||
const CONTEXTUAL_TABS: [&str; 3] = ["Table Design", "Chart Design", crate::paper_view::TAB];
|
||||
|
||||
fn contextual_tabs(app: &SheetApp) -> Vec<&'static str> {
|
||||
let mut v = Vec::new();
|
||||
if let Some(d) = app.session.active()
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
//! A contextual ribbon tab (Table Design, Chart Design) only exists while its object is selected.
|
||||
//! The tab remembered in the saved UI state, or left behind when the selection moves away, must
|
||||
//! not leave the ribbon blank: it falls back to Home.
|
||||
|
||||
use egui::vec2;
|
||||
use gridcraft_engine::Session;
|
||||
use gridcraft_ui_egui::SheetApp;
|
||||
use serde_json::json;
|
||||
|
||||
type Harness = egui_kittest::Harness<'static, SheetApp>;
|
||||
|
||||
fn harness(session: Session) -> Harness {
|
||||
let mut h = egui_kittest::Harness::builder().with_size(vec2(1200.0, 800.0)).build_ui_state(
|
||||
|ui, app: &mut SheetApp| {
|
||||
let ctx = ui.ctx().clone();
|
||||
app.logic(&ctx);
|
||||
app.ui(ui);
|
||||
},
|
||||
SheetApp::new(session, Default::default()),
|
||||
);
|
||||
h.run_steps(4);
|
||||
h
|
||||
}
|
||||
|
||||
fn session_with_table() -> Session {
|
||||
let mut session = Session::new();
|
||||
session.new_workbook();
|
||||
session.execute("range.setValues", json!({"range": "A1", "values": [["Name", "Qty"], ["a", 1], ["b", 2]]})).unwrap();
|
||||
session.execute("insert.table", json!({"range": "A1:B3", "header": true})).unwrap();
|
||||
session.execute("selection.set", json!({"range": "A2"})).unwrap();
|
||||
session
|
||||
}
|
||||
|
||||
fn app_restored_on(tab: &str, session: Session) -> Harness {
|
||||
let mut app = SheetApp::new(session, Default::default());
|
||||
app.ui.ribbon_tab = tab.into();
|
||||
let mut h = egui_kittest::Harness::builder().with_size(vec2(1200.0, 800.0)).build_ui_state(
|
||||
|ui, app: &mut SheetApp| {
|
||||
let ctx = ui.ctx().clone();
|
||||
app.logic(&ctx);
|
||||
app.ui(ui);
|
||||
},
|
||||
app,
|
||||
);
|
||||
h.run_steps(4);
|
||||
h
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_saved_table_design_tab_without_a_table_opens_on_home() {
|
||||
let mut session = Session::new();
|
||||
session.new_workbook();
|
||||
let h = app_restored_on("Table Design", session);
|
||||
assert_eq!(h.state().ui.ribbon_tab, "Home");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_saved_chart_design_tab_without_a_chart_opens_on_home() {
|
||||
let mut session = Session::new();
|
||||
session.new_workbook();
|
||||
let h = app_restored_on("Chart Design", session);
|
||||
assert_eq!(h.state().ui.ribbon_tab, "Home");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leaving_the_table_while_on_table_design_returns_to_home() {
|
||||
let mut h = harness(session_with_table());
|
||||
h.state_mut().ui.ribbon_tab = "Table Design".into();
|
||||
h.run_steps(2);
|
||||
assert_eq!(h.state().ui.ribbon_tab, "Table Design", "the tab stays while the cell is in the table");
|
||||
h.state_mut().session.execute("selection.set", json!({"range": "D10"})).unwrap();
|
||||
h.run_steps(2);
|
||||
assert_eq!(h.state().ui.ribbon_tab, "Home");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn startup_opens_on_home_not_the_saved_tab() {
|
||||
let saved = gridcraft_ui_egui::UiState { ribbon_tab: "Table Design".into(), dark: true, ..Default::default() };
|
||||
let json = serde_json::to_string(&saved).unwrap();
|
||||
assert!(json.contains(r#""ribbonTab":"Table Design""#), "{json}");
|
||||
let restored = serde_json::from_str::<gridcraft_ui_egui::UiState>(&json).unwrap().at_startup();
|
||||
assert_eq!(restored.ribbon_tab, "Home", "the saved tab is not restored");
|
||||
assert!(restored.dark, "the other preferences are");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_ordinary_tab_stays_put_in_a_session() {
|
||||
let mut session = Session::new();
|
||||
session.new_workbook();
|
||||
let mut h = harness(session);
|
||||
h.state_mut().ui.ribbon_tab = "Data".into();
|
||||
h.run_steps(3);
|
||||
assert_eq!(h.state().ui.ribbon_tab, "Data");
|
||||
}
|
||||
Reference in New Issue
Block a user