Files
Cagire/src/state/options.rs
Raphaël Forment 6cd20732ed
All checks were successful
Deploy Website / deploy (push) Has been skipped
Feat: UI redesign and UX
2026-03-01 01:50:34 +01:00

165 lines
4.0 KiB
Rust

use super::CyclicEnum;
#[derive(Clone, Copy, PartialEq, Eq, Default)]
pub enum OptionsFocus {
#[default]
ColorScheme,
HueRotation,
RefreshRate,
RuntimeHighlight,
ShowScope,
ShowSpectrum,
ShowLissajous,
GainBoost,
NormalizeViz,
ShowCompletion,
ShowPreview,
PerformanceMode,
Font,
ZoomFactor,
WindowSize,
ResetOnboarding,
LoadDemoOnStartup,
}
impl CyclicEnum for OptionsFocus {
const VARIANTS: &'static [Self] = &[
Self::ColorScheme,
Self::HueRotation,
Self::RefreshRate,
Self::RuntimeHighlight,
Self::ShowScope,
Self::ShowSpectrum,
Self::ShowLissajous,
Self::GainBoost,
Self::NormalizeViz,
Self::ShowCompletion,
Self::ShowPreview,
Self::PerformanceMode,
Self::Font,
Self::ZoomFactor,
Self::WindowSize,
Self::ResetOnboarding,
Self::LoadDemoOnStartup,
];
}
const PLUGIN_ONLY: &[OptionsFocus] = &[
OptionsFocus::Font,
OptionsFocus::ZoomFactor,
OptionsFocus::WindowSize,
];
/// Section layout: header line, divider line, then option lines.
const FULL_LAYOUT: &[(OptionsFocus, usize)] = &[
// DISPLAY section: header=0, divider=1
(OptionsFocus::ColorScheme, 2),
(OptionsFocus::HueRotation, 3),
(OptionsFocus::RefreshRate, 4),
(OptionsFocus::RuntimeHighlight, 5),
(OptionsFocus::ShowScope, 6),
(OptionsFocus::ShowSpectrum, 7),
(OptionsFocus::ShowLissajous, 8),
(OptionsFocus::GainBoost, 9),
(OptionsFocus::NormalizeViz, 10),
(OptionsFocus::ShowCompletion, 11),
(OptionsFocus::ShowPreview, 12),
(OptionsFocus::PerformanceMode, 13),
(OptionsFocus::Font, 14),
(OptionsFocus::ZoomFactor, 15),
(OptionsFocus::WindowSize, 16),
// blank=17, ONBOARDING header=18, divider=19
(OptionsFocus::ResetOnboarding, 20),
(OptionsFocus::LoadDemoOnStartup, 21),
];
impl OptionsFocus {
fn is_plugin_only(self) -> bool {
PLUGIN_ONLY.contains(&self)
}
fn is_visible(self, plugin_mode: bool) -> bool {
if self.is_plugin_only() && !plugin_mode {
return false;
}
true
}
pub fn line_index(self, plugin_mode: bool) -> usize {
visible_layout(plugin_mode)
.iter()
.find(|(f, _)| *f == self)
.map(|(_, l)| *l)
.unwrap_or(0)
}
pub fn at_line(line: usize, plugin_mode: bool) -> Option<OptionsFocus> {
visible_layout(plugin_mode)
.iter()
.find(|(_, l)| *l == line)
.map(|(f, _)| *f)
}
}
/// Total number of rendered lines for the options view.
pub fn total_lines(plugin_mode: bool) -> usize {
visible_layout(plugin_mode)
.last()
.map(|(_, l)| *l + 1)
.unwrap_or(0)
}
fn visible_layout(plugin_mode: bool) -> Vec<(OptionsFocus, usize)> {
let mut offset: usize = 0;
// Font/Zoom/Window lines (14,15,16) hidden when !plugin_mode
if !plugin_mode {
offset += 3;
}
let mut result = Vec::new();
for &(focus, raw_line) in FULL_LAYOUT {
if !focus.is_visible(plugin_mode) {
continue;
}
let adjusted = if raw_line <= 13 {
raw_line
} else if !plugin_mode && raw_line <= 16 {
continue;
} else {
raw_line - offset
};
result.push((focus, adjusted));
}
result
}
#[derive(Default)]
pub struct OptionsState {
pub focus: OptionsFocus,
}
impl OptionsState {
pub fn next_focus(&mut self, plugin_mode: bool) {
let mut f = self.focus;
loop {
f = f.next();
if f.is_visible(plugin_mode) {
break;
}
}
self.focus = f;
}
pub fn prev_focus(&mut self, plugin_mode: bool) {
let mut f = self.focus;
loop {
f = f.prev();
if f.is_visible(plugin_mode) {
break;
}
}
self.focus = f;
}
}