Feat: collapsible help

This commit is contained in:
2026-02-16 23:43:25 +01:00
parent 2d8abe4af9
commit f258358c8f
12 changed files with 597 additions and 119 deletions

View File

@@ -1,6 +1,8 @@
use crate::model::categories;
use crate::model::categories::{self, CatEntry, CATEGORIES};
use crate::state::{DictFocus, UiState};
use CatEntry::{Category, Section};
pub fn toggle_focus(ui: &mut UiState) {
ui.dict_focus = match ui.dict_focus {
DictFocus::Categories => DictFocus::Words,
@@ -11,17 +13,86 @@ pub fn toggle_focus(ui: &mut UiState) {
pub fn select_category(ui: &mut UiState, index: usize) {
if index < categories::category_count() {
ui.dict_category = index;
ui.dict_on_section = None;
}
}
#[derive(Clone, Copy)]
enum VisibleItem {
Category(usize),
Section(usize),
}
fn visible_items(collapsed: &[bool]) -> Vec<VisibleItem> {
let mut result = Vec::new();
let mut section_idx = 0usize;
let mut cat_idx = 0usize;
let mut skipping = false;
for entry in CATEGORIES.iter() {
match entry {
Section(_) => {
let is_collapsed = collapsed.get(section_idx).copied().unwrap_or(false);
if is_collapsed {
result.push(VisibleItem::Section(section_idx));
}
skipping = is_collapsed;
section_idx += 1;
}
Category(_) => {
if !skipping {
result.push(VisibleItem::Category(cat_idx));
}
cat_idx += 1;
}
}
}
result
}
fn find_current(items: &[VisibleItem], ui: &UiState) -> usize {
if let Some(s) = ui.dict_on_section {
items
.iter()
.position(|v| matches!(v, VisibleItem::Section(idx) if *idx == s))
.unwrap_or(0)
} else {
items
.iter()
.position(|v| matches!(v, VisibleItem::Category(idx) if *idx == ui.dict_category))
.unwrap_or(0)
}
}
fn apply_selection(ui: &mut UiState, item: VisibleItem) {
match item {
VisibleItem::Category(idx) => {
ui.dict_category = idx;
ui.dict_on_section = None;
}
VisibleItem::Section(idx) => {
ui.dict_on_section = Some(idx);
}
}
}
pub fn next_category(ui: &mut UiState) {
let count = categories::category_count();
ui.dict_category = (ui.dict_category + 1) % count;
let items = visible_items(&ui.dict_collapsed);
if items.is_empty() {
return;
}
let cur = find_current(&items, ui);
let next = (cur + 1) % items.len();
apply_selection(ui, items[next]);
}
pub fn prev_category(ui: &mut UiState) {
let count = categories::category_count();
ui.dict_category = (ui.dict_category + count - 1) % count;
let items = visible_items(&ui.dict_collapsed);
if items.is_empty() {
return;
}
let cur = find_current(&items, ui);
let next = (cur + items.len() - 1) % items.len();
apply_selection(ui, items[next]);
}
pub fn scroll_down(ui: &mut UiState, n: usize) {