pub enum CatEntry { Section(&'static str), Category(&'static str), } use CatEntry::{Category, Section}; pub const CATEGORIES: &[CatEntry] = &[ // Forth core Section("Forth"), Category("Stack"), Category("Arithmetic"), Category("Comparison"), Category("Logic"), Category("Control"), Category("Variables"), Category("Probability"), Category("Definitions"), // Live coding Section("Live Coding"), Category("Sound"), Category("Time"), Category("Context"), Category("Music"), Category("LFO"), // Synthesis Section("Synthesis"), Category("Oscillator"), Category("Wavetable"), Category("Generator"), Category("Envelope"), Category("Sample"), // Effects Section("Effects"), Category("Filter"), Category("FM"), Category("Modulation"), Category("Mod FX"), Category("Lo-fi"), Category("Stereo"), Category("Delay"), Category("Reverb"), // External I/O Section("I/O"), Category("MIDI"), Category("Desktop"), ]; pub fn category_count() -> usize { CATEGORIES .iter() .filter(|e| matches!(e, Category(_))) .count() } pub fn get_category_name(index: usize) -> &'static str { CATEGORIES .iter() .filter_map(|e| match e { Category(name) => Some(*name), Section(_) => None, }) .nth(index) .unwrap_or("Unknown") } pub fn section_count() -> usize { CATEGORIES .iter() .filter(|e| matches!(e, Section(_))) .count() } pub fn section_index_for_category(cat_idx: usize) -> usize { let mut section: usize = 0; let mut cat: usize = 0; for entry in CATEGORIES.iter() { match entry { Section(_) => section += 1, Category(_) => { if cat == cat_idx { return section.saturating_sub(1); } cat += 1; } } } section.saturating_sub(1) } pub fn first_category_in_section(section_idx: usize) -> Option { let mut section: usize = 0; let mut cat: usize = 0; let mut in_target = false; for entry in CATEGORIES.iter() { match entry { Section(_) => { if in_target { return None; } if section == section_idx { in_target = true; } section += 1; } Category(_) => { if in_target { return Some(cat); } cat += 1; } } } None }