Trying to clena the mess opened by plugins
Some checks failed
Deploy Website / deploy (push) Failing after 4m53s

This commit is contained in:
2026-02-21 01:03:55 +01:00
parent ac0ddc7fb9
commit 75a8fd4401
67 changed files with 1246 additions and 69 deletions

View File

@@ -309,6 +309,12 @@ impl App {
.editor
.set_completion_enabled(self.ui.show_completion);
}
AppCommand::SetFont(f) => self.ui.font = f,
AppCommand::SetZoomFactor(z) => self.ui.zoom_factor = z,
AppCommand::SetWindowSize(w, h) => {
self.ui.window_width = w;
self.ui.window_height = h;
}
AppCommand::ToggleLiveKeysFill => self.live_keys.flip_fill(),
// Panel
@@ -375,8 +381,8 @@ impl App {
AppCommand::AudioRefreshDevices => self.audio.refresh_devices(),
// Options page
AppCommand::OptionsNextFocus => self.options.next_focus(),
AppCommand::OptionsPrevFocus => self.options.prev_focus(),
AppCommand::OptionsNextFocus => self.options.next_focus(self.plugin_mode),
AppCommand::OptionsPrevFocus => self.options.prev_focus(self.plugin_mode),
AppCommand::OptionsSetFocus(focus) => self.options.focus = focus,
AppCommand::ToggleRefreshRate => self.audio.toggle_refresh_rate(),
AppCommand::ToggleScope => self.audio.config.show_scope = !self.audio.config.show_scope,

View File

@@ -30,7 +30,8 @@ impl App {
layout: self.audio.config.layout,
hue_rotation: self.ui.hue_rotation,
onboarding_dismissed: self.ui.onboarding_dismissed.clone(),
..Default::default()
font: self.ui.font.clone(),
zoom_factor: self.ui.zoom_factor,
},
link: crate::settings::LinkSettings {
enabled: link.is_enabled(),

View File

@@ -199,6 +199,9 @@ pub enum AppCommand {
SetHueRotation(f32),
ToggleRuntimeHighlight,
ToggleCompletion,
SetFont(String),
SetZoomFactor(f32),
SetWindowSize(u32, u32),
// Live keys
ToggleLiveKeysFill,

View File

@@ -88,6 +88,8 @@ pub fn init(args: InitArgs) -> Init {
app.ui.hue_rotation = settings.display.hue_rotation;
app.audio.config.layout = settings.display.layout;
app.ui.onboarding_dismissed = settings.display.onboarding_dismissed.clone();
app.ui.font = settings.display.font.clone();
app.ui.zoom_factor = settings.display.zoom_factor;
let palette = settings.display.color_scheme.to_palette();
let rotated =

View File

@@ -675,8 +675,9 @@ fn handle_options_click(ctx: &mut InputContext, col: u16, row: u16, area: Rect)
}
let focus = ctx.app.options.focus;
let focus_line = focus.line_index();
let total_lines = 35;
let plugin_mode = ctx.app.plugin_mode;
let focus_line = focus.line_index(plugin_mode);
let total_lines = if plugin_mode { 43 } else { 40 };
let max_visible = padded.height as usize;
let scroll_offset = if total_lines <= max_visible {
@@ -690,7 +691,7 @@ fn handle_options_click(ctx: &mut InputContext, col: u16, row: u16, area: Rect)
let relative_y = (row - padded.y) as usize;
let abs_line = scroll_offset + relative_y;
if let Some(new_focus) = OptionsFocus::at_line(abs_line) {
if let Some(new_focus) = OptionsFocus::at_line(abs_line, plugin_mode) {
ctx.dispatch(AppCommand::OptionsSetFocus(new_focus));
// Value area starts at prefix(2) + label(20) = offset 22 from padded.x

View File

@@ -26,6 +26,56 @@ pub(crate) fn cycle_option_value(ctx: &mut InputContext, right: bool) {
OptionsFocus::ShowSpectrum => ctx.dispatch(AppCommand::ToggleSpectrum),
OptionsFocus::ShowCompletion => ctx.dispatch(AppCommand::ToggleCompletion),
OptionsFocus::ShowPreview => ctx.dispatch(AppCommand::TogglePreview),
OptionsFocus::Font => {
const FONTS: &[&str] = &["6x13", "7x13", "8x13", "9x15", "9x18", "10x20"];
let pos = FONTS.iter().position(|f| *f == ctx.app.ui.font).unwrap_or(2);
let new_pos = if right {
(pos + 1) % FONTS.len()
} else {
(pos + FONTS.len() - 1) % FONTS.len()
};
ctx.dispatch(AppCommand::SetFont(FONTS[new_pos].to_string()));
}
OptionsFocus::ZoomFactor => {
const ZOOMS: &[f32] = &[0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0];
let pos = ZOOMS
.iter()
.position(|z| (z - ctx.app.ui.zoom_factor).abs() < 0.01)
.unwrap_or(4);
let new_pos = if right {
(pos + 1) % ZOOMS.len()
} else {
(pos + ZOOMS.len() - 1) % ZOOMS.len()
};
ctx.dispatch(AppCommand::SetZoomFactor(ZOOMS[new_pos]));
}
OptionsFocus::WindowSize => {
const WINDOW_SIZES: &[(u32, u32)] = &[
(900, 600), (1050, 700), (1200, 800), (1350, 900), (1500, 1000),
];
let pos = WINDOW_SIZES
.iter()
.position(|&(w, h)| w == ctx.app.ui.window_width && h == ctx.app.ui.window_height)
.unwrap_or_else(|| {
WINDOW_SIZES
.iter()
.enumerate()
.min_by_key(|&(_, &(w, h))| {
let dw = w as i64 - ctx.app.ui.window_width as i64;
let dh = h as i64 - ctx.app.ui.window_height as i64;
dw * dw + dh * dh
})
.map(|(i, _)| i)
.unwrap_or(2)
});
let new_pos = if right {
(pos + 1) % WINDOW_SIZES.len()
} else {
(pos + WINDOW_SIZES.len() - 1) % WINDOW_SIZES.len()
};
let (w, h) = WINDOW_SIZES[new_pos];
ctx.dispatch(AppCommand::SetWindowSize(w, h));
}
OptionsFocus::LinkEnabled => ctx.link.set_enabled(!ctx.link.is_enabled()),
OptionsFocus::StartStopSync => ctx
.link

View File

@@ -11,6 +11,9 @@ pub enum OptionsFocus {
ShowSpectrum,
ShowCompletion,
ShowPreview,
Font,
ZoomFactor,
WindowSize,
LinkEnabled,
StartStopSync,
Quantum,
@@ -35,6 +38,9 @@ impl CyclicEnum for OptionsFocus {
Self::ShowSpectrum,
Self::ShowCompletion,
Self::ShowPreview,
Self::Font,
Self::ZoomFactor,
Self::WindowSize,
Self::LinkEnabled,
Self::StartStopSync,
Self::Quantum,
@@ -50,6 +56,8 @@ impl CyclicEnum for OptionsFocus {
];
}
// Line indices when Font/ZoomFactor are shown (plugin mode).
// In terminal mode, Font/ZoomFactor are absent; all lines after ShowPreview shift up by 2.
const FOCUS_LINES: &[(OptionsFocus, usize)] = &[
(OptionsFocus::ColorScheme, 2),
(OptionsFocus::HueRotation, 3),
@@ -59,34 +67,51 @@ const FOCUS_LINES: &[(OptionsFocus, usize)] = &[
(OptionsFocus::ShowSpectrum, 7),
(OptionsFocus::ShowCompletion, 8),
(OptionsFocus::ShowPreview, 9),
(OptionsFocus::LinkEnabled, 13),
(OptionsFocus::StartStopSync, 14),
(OptionsFocus::Quantum, 15),
(OptionsFocus::MidiOutput0, 25),
(OptionsFocus::MidiOutput1, 26),
(OptionsFocus::MidiOutput2, 27),
(OptionsFocus::MidiOutput3, 28),
(OptionsFocus::MidiInput0, 32),
(OptionsFocus::MidiInput1, 33),
(OptionsFocus::MidiInput2, 34),
(OptionsFocus::MidiInput3, 35),
(OptionsFocus::ResetOnboarding, 39),
(OptionsFocus::Font, 10),
(OptionsFocus::ZoomFactor, 11),
(OptionsFocus::WindowSize, 12),
(OptionsFocus::LinkEnabled, 16),
(OptionsFocus::StartStopSync, 17),
(OptionsFocus::Quantum, 18),
(OptionsFocus::MidiOutput0, 28),
(OptionsFocus::MidiOutput1, 29),
(OptionsFocus::MidiOutput2, 30),
(OptionsFocus::MidiOutput3, 31),
(OptionsFocus::MidiInput0, 35),
(OptionsFocus::MidiInput1, 36),
(OptionsFocus::MidiInput2, 37),
(OptionsFocus::MidiInput3, 38),
(OptionsFocus::ResetOnboarding, 42),
];
const PLUGIN_ONLY: &[OptionsFocus] = &[OptionsFocus::Font, OptionsFocus::ZoomFactor, OptionsFocus::WindowSize];
impl OptionsFocus {
pub fn line_index(self) -> usize {
FOCUS_LINES
fn is_plugin_only(self) -> bool {
PLUGIN_ONLY.contains(&self)
}
pub fn line_index(self, plugin_mode: bool) -> usize {
let base = FOCUS_LINES
.iter()
.find(|(f, _)| *f == self)
.map(|(_, l)| *l)
.unwrap_or(0)
.unwrap_or(0);
if plugin_mode || base <= 9 {
base
} else {
base - 3
}
}
pub fn at_line(line: usize) -> Option<OptionsFocus> {
FOCUS_LINES
.iter()
.find(|(_, l)| *l == line)
.map(|(f, _)| *f)
pub fn at_line(line: usize, plugin_mode: bool) -> Option<OptionsFocus> {
FOCUS_LINES.iter().find_map(|(f, l)| {
if f.is_plugin_only() && !plugin_mode {
return None;
}
let effective = if plugin_mode || *l <= 9 { *l } else { *l - 3 };
if effective == line { Some(*f) } else { None }
})
}
}
@@ -96,11 +121,25 @@ pub struct OptionsState {
}
impl OptionsState {
pub fn next_focus(&mut self) {
self.focus = self.focus.next();
pub fn next_focus(&mut self, plugin_mode: bool) {
let mut f = self.focus;
loop {
f = f.next();
if !f.is_plugin_only() || plugin_mode {
break;
}
}
self.focus = f;
}
pub fn prev_focus(&mut self) {
self.focus = self.focus.prev();
pub fn prev_focus(&mut self, plugin_mode: bool) {
let mut f = self.focus;
loop {
f = f.prev();
if !f.is_plugin_only() || plugin_mode {
break;
}
}
self.focus = f;
}
}

View File

@@ -74,6 +74,10 @@ pub struct UiState {
pub prev_page: Page,
pub prev_show_title: bool,
pub onboarding_dismissed: Vec<String>,
pub font: String,
pub zoom_factor: f32,
pub window_width: u32,
pub window_height: u32,
}
impl Default for UiState {
@@ -117,6 +121,10 @@ impl Default for UiState {
prev_page: Page::default(),
prev_show_title: true,
onboarding_dismissed: Vec::new(),
font: "8x13".to_string(),
zoom_factor: 1.5,
window_width: 1200,
window_height: 800,
}
}
}

View File

@@ -113,7 +113,7 @@ pub fn render(frame: &mut Frame, app: &App, link: &LinkState, area: Rect) {
let onboarding_str = format!("{}/6 dismissed", app.ui.onboarding_dismissed.len());
let hue_str = format!("{}°", app.ui.hue_rotation as i32);
let lines: Vec<Line> = vec![
let mut lines: Vec<Line> = vec![
render_section_header("DISPLAY", &theme),
render_divider(content_width, &theme),
render_option_line(
@@ -168,7 +168,31 @@ pub fn render(frame: &mut Frame, app: &App, link: &LinkState, area: Rect) {
focus == OptionsFocus::ShowPreview,
&theme,
),
Line::from(""),
];
let zoom_str = format!("{:.0}%", app.ui.zoom_factor * 100.0);
let window_str = format!("{}x{}", app.ui.window_width, app.ui.window_height);
if app.plugin_mode {
lines.push(render_option_line(
"Font",
&app.ui.font,
focus == OptionsFocus::Font,
&theme,
));
lines.push(render_option_line(
"Zoom",
&zoom_str,
focus == OptionsFocus::ZoomFactor,
&theme,
));
lines.push(render_option_line(
"Window",
&window_str,
focus == OptionsFocus::WindowSize,
&theme,
));
}
lines.push(Line::from(""));
lines.extend([
link_header,
render_divider(content_width, &theme),
render_option_line(
@@ -217,12 +241,12 @@ pub fn render(frame: &mut Frame, app: &App, link: &LinkState, area: Rect) {
focus == OptionsFocus::ResetOnboarding,
&theme,
),
];
]);
let total_lines = lines.len();
let max_visible = padded.height as usize;
let focus_line = focus.line_index();
let focus_line = focus.line_index(app.plugin_mode);
let scroll_offset = if total_lines <= max_visible {
0