From 87fd6a16203f9f302ecf4381993832254a4e4739 Mon Sep 17 00:00:00 2001 From: Edward Langley Date: Wed, 1 Apr 2026 00:40:22 -0700 Subject: [PATCH] refactor: mystery model #2 --- src/main.rs | 168 ++++++++++++++++++++-------------------------------- 1 file changed, 64 insertions(+), 104 deletions(-) diff --git a/src/main.rs b/src/main.rs index 58526be..8e2f0cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -346,18 +346,13 @@ fn draw_title(f: &mut Frame, area: Rect, app: &App) { fn draw_content(f: &mut Frame, area: Rect, app: &App) { let side_open = app.formula_panel_open || app.category_panel_open || app.view_panel_open; - if side_open { + let grid_area = if side_open { let side_w = 32u16; let chunks = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Min(40), Constraint::Length(side_w)]) .split(area); - f.render_widget( - GridWidget::new(&app.model, &app.mode, &app.search_query), - chunks[0], - ); - let side = chunks[1]; let panel_count = [ app.formula_panel_open, @@ -366,39 +361,36 @@ fn draw_content(f: &mut Frame, area: Rect, app: &App) { ] .iter() .filter(|&&b| b) - .count() as u16; - let ph = side.height / panel_count.max(1); - let mut y = side.y; + .count(); + + let constraints: Vec = std::iter::repeat(Constraint::Fill(1)) + .take(panel_count) + .collect(); + let panel_areas = Layout::default() + .direction(Direction::Vertical) + .constraints(constraints) + .split(side); + let mut slots = panel_areas.iter().copied(); if app.formula_panel_open { - let a = Rect::new(side.x, y, side.width, ph); - f.render_widget( - FormulaPanel::new(&app.model, &app.mode, app.formula_cursor), - a, - ); - y += ph; + f.render_widget(FormulaPanel::new(&app.model, &app.mode, app.formula_cursor), slots.next().unwrap()); } if app.category_panel_open { - let a = Rect::new(side.x, y, side.width, ph); - f.render_widget( - CategoryPanel::new(&app.model, &app.mode, app.cat_panel_cursor), - a, - ); - y += ph; + f.render_widget(CategoryPanel::new(&app.model, &app.mode, app.cat_panel_cursor), slots.next().unwrap()); } if app.view_panel_open { - let a = Rect::new(side.x, y, side.width, ph); - f.render_widget( - ViewPanel::new(&app.model, &app.mode, app.view_panel_cursor), - a, - ); + f.render_widget(ViewPanel::new(&app.model, &app.mode, app.view_panel_cursor), slots.next().unwrap()); } + + chunks[0] } else { - f.render_widget( - GridWidget::new(&app.model, &app.mode, &app.search_query), - area, - ); - } + area + }; + + f.render_widget( + GridWidget::new(&app.model, &app.mode, &app.search_query), + grid_area, + ); } fn draw_tile_bar(f: &mut Frame, area: Rect, app: &App) { @@ -490,6 +482,37 @@ fn draw_export_prompt(f: &mut Frame, area: Rect, app: &App) { ); } +#[derive(Copy, Clone)] +enum LineKind { + Intro, + Header, + Command, + Example, + Plain, +} + +const WELCOME_LINES: &[(&str, LineKind)] = &[ + ("Multi-dimensional data modeling — in your terminal.", LineKind::Intro), + ("", LineKind::Plain), + ("Getting started", LineKind::Header), + ("", LineKind::Plain), + (":import Import a JSON file", LineKind::Command), + (":add-cat Add a category (dimension)", LineKind::Command), + (":add-item Add an item to a category", LineKind::Command), + (":formula Add a formula, e.g.:", LineKind::Command), + (" Profit = Revenue - Cost", LineKind::Example), + (":w Save your model", LineKind::Command), + ("", LineKind::Plain), + ("Navigation", LineKind::Header), + ("", LineKind::Plain), + ("F C V Open panels (Formulas/Categories/Views)", LineKind::Plain), + ("T Tile-select: pivot rows ↔ cols ↔ page", LineKind::Plain), + ("i Enter Edit a cell", LineKind::Plain), + ("[ ] Cycle the page-axis filter", LineKind::Plain), + ("? or :help Full key reference", LineKind::Plain), + (":q Quit", LineKind::Plain), +]; + fn draw_welcome(f: &mut Frame, area: Rect, _app: &App) { let w = 58u16.min(area.width.saturating_sub(4)); let h = 20u16.min(area.height.saturating_sub(2)); @@ -506,83 +529,20 @@ fn draw_welcome(f: &mut Frame, area: Rect, _app: &App) { let inner = block.inner(popup); f.render_widget(block, popup); - let lines: &[(&str, Style)] = &[ - ( - "Multi-dimensional data modeling — in your terminal.", - Style::default().fg(Color::White), - ), - ("", Style::default()), - ( - "Getting started", - Style::default() - .fg(Color::Blue) - .add_modifier(Modifier::BOLD), - ), - ("", Style::default()), - ( - ":import Import a JSON file", - Style::default().fg(Color::Cyan), - ), - ( - ":add-cat Add a category (dimension)", - Style::default().fg(Color::Cyan), - ), - ( - ":add-item Add an item to a category", - Style::default().fg(Color::Cyan), - ), - ( - ":formula Add a formula, e.g.:", - Style::default().fg(Color::Cyan), - ), - ( - " Profit = Revenue - Cost", - Style::default().fg(Color::Green), - ), - ( - ":w Save your model", - Style::default().fg(Color::Cyan), - ), - ("", Style::default()), - ( - "Navigation", - Style::default() - .fg(Color::Blue) - .add_modifier(Modifier::BOLD), - ), - ("", Style::default()), - ( - "F C V Open panels (Formulas/Categories/Views)", - Style::default(), - ), - ( - "T Tile-select: pivot rows ↔ cols ↔ page", - Style::default(), - ), - ("i Enter Edit a cell", Style::default()), - ( - "[ ] Cycle the page-axis filter", - Style::default(), - ), - ( - "? or :help Full key reference", - Style::default(), - ), - (":q Quit", Style::default()), - ]; - - for (i, (text, style)) in lines.iter().enumerate() { + for (i, (text, kind)) in WELCOME_LINES.iter().enumerate() { if i >= inner.height as usize { break; } + let style = match kind { + LineKind::Intro => Style::default().fg(Color::White), + LineKind::Header => Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD), + LineKind::Command => Style::default().fg(Color::Cyan), + LineKind::Example => Style::default().fg(Color::Green), + LineKind::Plain => Style::default(), + }; f.render_widget( - Paragraph::new(*text).style(*style), - Rect::new( - inner.x + 1, - inner.y + i as u16, - inner.width.saturating_sub(2), - 1, - ), + Paragraph::new(*text).style(style), + Rect::new(inner.x + 1, inner.y + i as u16, inner.width.saturating_sub(2), 1), ); } }