feat: add Axis::None for hidden dimensions with implicit aggregation
Categories on the None axis are excluded from the grid and cell keys. When evaluating cells, values across hidden dimensions are aggregated using a per-measure function (default SUM). Adds evaluate_aggregated to Model, none_cats to GridLayout, and 'n' shortcut in TileSelect. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -402,7 +402,8 @@ impl App {
|
||||
// yy = yank current cell
|
||||
('y', KeyCode::Char('y')) => {
|
||||
if let Some(key) = self.selected_cell_key() {
|
||||
self.yanked = self.model.evaluate(&key);
|
||||
let layout = GridLayout::new(&self.model, self.model.active_view());
|
||||
self.yanked = self.model.evaluate_aggregated(&key, &layout.none_cats);
|
||||
self.status_msg = "Yanked".to_string();
|
||||
}
|
||||
}
|
||||
@ -1111,6 +1112,19 @@ impl App {
|
||||
}
|
||||
self.mode = AppMode::Normal;
|
||||
}
|
||||
KeyCode::Char('n') => {
|
||||
if let Some(name) = cat_names.get(cat_idx) {
|
||||
command::dispatch(
|
||||
&mut self.model,
|
||||
&Command::SetAxis {
|
||||
category: name.clone(),
|
||||
axis: Axis::None,
|
||||
},
|
||||
);
|
||||
self.dirty = true;
|
||||
}
|
||||
self.mode = AppMode::Normal;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
@ -1386,7 +1400,7 @@ impl App {
|
||||
Some(k) => k,
|
||||
None => return false,
|
||||
};
|
||||
let s = match self.model.evaluate(&key) {
|
||||
let s = match self.model.evaluate_aggregated(&key, &layout.none_cats) {
|
||||
Some(CellValue::Number(n)) => format!("{n}"),
|
||||
Some(CellValue::Text(t)) => t,
|
||||
None => String::new(),
|
||||
@ -1608,7 +1622,7 @@ impl App {
|
||||
AppMode::CategoryAdd { .. } => "Enter:add & continue Tab:same Esc:done — type a category name",
|
||||
AppMode::ItemAdd { .. } => "Enter:add & continue Tab:same Esc:done — type an item name",
|
||||
AppMode::ViewPanel => "jk:nav Enter:switch n:new d:delete Esc:back",
|
||||
AppMode::TileSelect { .. } => "hl:select Enter:cycle r/c/p:set-axis Esc:back",
|
||||
AppMode::TileSelect { .. } => "hl:select Enter:cycle r/c/p/n:set-axis Esc:back",
|
||||
AppMode::CommandMode { .. } => ":q quit :w save :import :add-cat :formula :show-item :help",
|
||||
AppMode::ImportWizard => "Space:toggle c:cycle Enter:next Esc:cancel",
|
||||
_ => "",
|
||||
|
||||
@ -14,6 +14,7 @@ fn axis_display(axis: Axis) -> (&'static str, Color) {
|
||||
Axis::Row => ("Row ↕", Color::Green),
|
||||
Axis::Column => ("Col ↔", Color::Blue),
|
||||
Axis::Page => ("Page ☰", Color::Magenta),
|
||||
Axis::None => ("None ∅", Color::DarkGray),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -291,7 +291,7 @@ impl<'a> GridWidget<'a> {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let value = self.model.evaluate(&key);
|
||||
let value = self.model.evaluate_aggregated(&key, &layout.none_cats);
|
||||
|
||||
let cell_str = format_value(value.as_ref(), fmt_comma, fmt_decimals);
|
||||
let is_selected = ri == sel_row && ci == sel_col;
|
||||
@ -378,7 +378,7 @@ impl<'a> GridWidget<'a> {
|
||||
}
|
||||
let total: f64 = (0..layout.row_count())
|
||||
.filter_map(|ri| layout.cell_key(ri, ci))
|
||||
.map(|key| self.model.evaluate_f64(&key))
|
||||
.map(|key| self.model.evaluate_aggregated_f64(&key, &layout.none_cats))
|
||||
.sum();
|
||||
let total_str = format_f64(total, fmt_comma, fmt_decimals);
|
||||
buf.set_string(
|
||||
|
||||
@ -14,6 +14,7 @@ fn axis_display(axis: Axis) -> (&'static str, Color) {
|
||||
Axis::Row => ("↕", Color::Green),
|
||||
Axis::Column => ("↔", Color::Blue),
|
||||
Axis::Page => ("☰", Color::Magenta),
|
||||
Axis::None => ("∅", Color::DarkGray),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user