WIP df2w: an open empty panel is Some(vec![]), closed is None
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
@@ -42,11 +42,11 @@ pub struct RenderModel {
|
|||||||
pub categories: Vec<RenderCatRow>,
|
pub categories: Vec<RenderCatRow>,
|
||||||
/// Whether the panel is open, so the page does not decide.
|
/// Whether the panel is open, so the page does not decide.
|
||||||
pub category_panel_open: bool,
|
pub category_panel_open: bool,
|
||||||
/// The view panel's rows, **empty unless it is open** — the same rule the
|
/// The view panel's rows, **`None` when it is closed** and possibly empty
|
||||||
/// help overlay follows, so the page asks no question about the mode.
|
/// when open: an absence is not an empty list (improvise-df2w).
|
||||||
pub views: Vec<RenderViewRow>,
|
pub views: Option<Vec<RenderViewRow>>,
|
||||||
/// The formula panel's rows, empty unless it is open.
|
/// The formula panel's rows, on the same terms as `views`.
|
||||||
pub formulas: Vec<RenderFormulaRow>,
|
pub formulas: Option<Vec<RenderFormulaRow>>,
|
||||||
/// The tile bar, drawn on every frame as the TUI draws it. Which tile is
|
/// The tile bar, drawn on every frame as the TUI draws it. Which tile is
|
||||||
/// `selected` is the mode's answer, not the page's.
|
/// `selected` is the mode's answer, not the page's.
|
||||||
pub tiles: Vec<RenderTile>,
|
pub tiles: Vec<RenderTile>,
|
||||||
@@ -344,41 +344,39 @@ fn page_axes(state: &ClientState) -> Vec<RenderPageAxis> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The view panel's rows while it is open. The axis line is
|
/// The view panel's rows, or `None` while it is closed. The axis line is
|
||||||
/// `viewmodel::view_axis_summary`, which the TUI's own panel calls too.
|
/// `viewmodel::view_axis_summary`, which the TUI's own panel calls too.
|
||||||
fn view_rows(state: &ClientState) -> Vec<RenderViewRow> {
|
fn view_rows(state: &ClientState) -> Option<Vec<RenderViewRow>> {
|
||||||
if !state.view.view_panel_open {
|
state.view.view_panel_open.then(|| {
|
||||||
return Vec::new();
|
state
|
||||||
}
|
.views
|
||||||
state
|
.views
|
||||||
.views
|
.iter()
|
||||||
.views
|
.enumerate()
|
||||||
.iter()
|
.map(|(i, summary)| RenderViewRow {
|
||||||
.enumerate()
|
name: summary.name.clone(),
|
||||||
.map(|(i, summary)| RenderViewRow {
|
axes: improvise_protocol::viewmodel::view_axis_summary(summary),
|
||||||
name: summary.name.clone(),
|
active: summary.name == state.view.active_view,
|
||||||
axes: improvise_protocol::viewmodel::view_axis_summary(summary),
|
selected: i == state.view.view_panel_cursor,
|
||||||
active: summary.name == state.view.active_view,
|
})
|
||||||
selected: i == state.view.view_panel_cursor,
|
.collect()
|
||||||
})
|
})
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The formula panel's rows while it is open.
|
/// The formula panel's rows, or `None` while it is closed.
|
||||||
fn formula_rows(state: &ClientState) -> Vec<RenderFormulaRow> {
|
fn formula_rows(state: &ClientState) -> Option<Vec<RenderFormulaRow>> {
|
||||||
if !state.view.formula_panel_open {
|
state.view.formula_panel_open.then(|| {
|
||||||
return Vec::new();
|
state
|
||||||
}
|
.formulas
|
||||||
state
|
.formulas
|
||||||
.formulas
|
.iter()
|
||||||
.formulas
|
.enumerate()
|
||||||
.iter()
|
.map(|(i, text)| RenderFormulaRow {
|
||||||
.enumerate()
|
text: text.clone(),
|
||||||
.map(|(i, text)| RenderFormulaRow {
|
selected: i == state.view.formula_cursor,
|
||||||
text: text.clone(),
|
})
|
||||||
selected: i == state.view.formula_cursor,
|
.collect()
|
||||||
})
|
})
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The tile bar, always. Only the *selection* is conditional, exactly as
|
/// The tile bar, always. Only the *selection* is conditional, exactly as
|
||||||
@@ -800,34 +798,48 @@ mod tests {
|
|||||||
client
|
client
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An empty list is what says a panel is closed — the same rule the help
|
/// `None` is what says a panel is closed, so the page asks no question
|
||||||
/// overlay follows, so the page asks no question about the mode.
|
/// about the mode.
|
||||||
#[test]
|
#[test]
|
||||||
fn a_closed_panel_projects_no_rows_and_an_open_one_does() {
|
fn a_closed_panel_projects_no_rows_and_an_open_one_does() {
|
||||||
let mut client = client_with_panels();
|
let mut client = client_with_panels();
|
||||||
let closed = client.model();
|
let closed = client.model();
|
||||||
assert!(
|
assert!(closed.views.is_none(), "the cache is full but the panel is shut");
|
||||||
closed.views.is_empty(),
|
assert!(closed.formulas.is_none());
|
||||||
"the cache is full but the panel is shut"
|
|
||||||
);
|
|
||||||
assert!(closed.formulas.is_empty());
|
|
||||||
|
|
||||||
client.state_mut().view.view_panel_open = true;
|
client.state_mut().view.view_panel_open = true;
|
||||||
client.state_mut().view.formula_panel_open = true;
|
client.state_mut().view.formula_panel_open = true;
|
||||||
client.state_mut().view.view_panel_cursor = 1;
|
client.state_mut().view.view_panel_cursor = 1;
|
||||||
client.state_mut().view.active_view = "Default".into();
|
client.state_mut().view.active_view = "Default".into();
|
||||||
let open = client.model();
|
let open = client.model();
|
||||||
assert_eq!(open.views.len(), 2);
|
let (views, formulas) = (open.views.unwrap(), open.formulas.unwrap());
|
||||||
|
assert_eq!(views.len(), 2);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
open.views[0].axes, "R:Region",
|
views[0].axes, "R:Region",
|
||||||
"the axis line is the shared derivation, and _Dim is not part of it"
|
"the axis line is the shared derivation, and _Dim is not part of it"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
open.views[0].active,
|
views[0].active,
|
||||||
"active is ViewState's, not the cache's"
|
"active is ViewState's, not the cache's"
|
||||||
);
|
);
|
||||||
assert!(open.views[1].selected, "and selected is the panel cursor's");
|
assert!(views[1].selected, "and selected is the panel cursor's");
|
||||||
assert_eq!(open.formulas[0].text, "Profit = Revenue - Cost");
|
assert_eq!(formulas[0].text, "Profit = Revenue - Cost");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open with nothing in it is not closed: the page must be able to tell
|
||||||
|
/// them apart from the model alone (improvise-df2w).
|
||||||
|
#[test]
|
||||||
|
fn an_open_empty_panel_is_not_a_closed_one() {
|
||||||
|
let mut client = init();
|
||||||
|
let closed = client.model();
|
||||||
|
client.state_mut().view.formula_panel_open = true;
|
||||||
|
let formulas_open = client.model();
|
||||||
|
assert_ne!(formulas_open, closed, "an open, empty formula panel");
|
||||||
|
|
||||||
|
client.state_mut().view.formula_panel_open = false;
|
||||||
|
client.state_mut().view.view_panel_open = true;
|
||||||
|
let views_open = client.model();
|
||||||
|
assert_ne!(views_open, closed, "an open, empty view panel");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The tile bar is drawn always; only the *selection* waits for the mode,
|
/// The tile bar is drawn always; only the *selection* waits for the mode,
|
||||||
|
|||||||
+4
-4
@@ -594,12 +594,12 @@ function edit(td, row, col, seed) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A side panel. An empty row list is what says it is closed — the page asks
|
/** A side panel. `null` is what says it is closed, and `[]` is open and empty:
|
||||||
* no question about the mode, exactly as `paintHelp` does not. */
|
* two facts, never inferred from a count (improvise-df2w). */
|
||||||
function paintPanel(host, rows, build) {
|
function paintPanel(host, rows, build) {
|
||||||
host.hidden = rows.length === 0;
|
host.hidden = rows === null;
|
||||||
const list = document.createElement("ul");
|
const list = document.createElement("ul");
|
||||||
rows.forEach((row, index) => {
|
(rows ?? []).forEach((row, index) => {
|
||||||
const li = build(row);
|
const li = build(row);
|
||||||
li.dataset.index = String(index);
|
li.dataset.index = String(index);
|
||||||
list.appendChild(li);
|
list.appendChild(li);
|
||||||
|
|||||||
Reference in New Issue
Block a user