chain word and better save/load UI

This commit is contained in:
2026-01-23 23:36:23 +01:00
parent 42ad77d9ae
commit 3bb19cbda8
20 changed files with 775 additions and 132 deletions

View File

@@ -77,6 +77,45 @@ impl Default for AudioConfig {
}
}
pub struct ListSelectState {
pub cursor: usize,
pub scroll_offset: usize,
}
impl ListSelectState {
pub fn move_up(&mut self) {
if self.cursor > 0 {
self.cursor -= 1;
if self.cursor < self.scroll_offset {
self.scroll_offset = self.cursor;
}
}
}
pub fn move_down(&mut self, item_count: usize) {
if self.cursor + 1 < item_count {
self.cursor += 1;
if self.cursor >= self.scroll_offset + 5 {
self.scroll_offset = self.cursor - 4;
}
}
}
pub fn page_up(&mut self) {
self.cursor = self.cursor.saturating_sub(5);
if self.cursor < self.scroll_offset {
self.scroll_offset = self.cursor;
}
}
pub fn page_down(&mut self, item_count: usize) {
self.cursor = (self.cursor + 5).min(item_count.saturating_sub(1));
if self.cursor >= self.scroll_offset + 5 {
self.scroll_offset = self.cursor.saturating_sub(4);
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Default)]
pub enum AudioFocus {
#[default]
@@ -127,6 +166,8 @@ pub struct AudioSettings {
pub focus: AudioFocus,
pub output_devices: Vec<AudioDeviceInfo>,
pub input_devices: Vec<AudioDeviceInfo>,
pub output_list: ListSelectState,
pub input_list: ListSelectState,
pub restart_pending: bool,
pub error: Option<String>,
}
@@ -138,6 +179,8 @@ impl Default for AudioSettings {
focus: AudioFocus::default(),
output_devices: doux::audio::list_output_devices(),
input_devices: doux::audio::list_input_devices(),
output_list: ListSelectState { cursor: 0, scroll_offset: 0 },
input_list: ListSelectState { cursor: 0, scroll_offset: 0 },
restart_pending: false,
error: None,
}
@@ -184,25 +227,7 @@ impl AudioSettings {
};
}
pub fn next_output_device(&mut self) {
if self.output_devices.is_empty() {
return;
}
let current_idx = self.current_output_device_index();
let next_idx = (current_idx + 1) % self.output_devices.len();
self.config.output_device = Some(self.output_devices[next_idx].name.clone());
}
pub fn prev_output_device(&mut self) {
if self.output_devices.is_empty() {
return;
}
let current_idx = self.current_output_device_index();
let prev_idx = (current_idx + self.output_devices.len() - 1) % self.output_devices.len();
self.config.output_device = Some(self.output_devices[prev_idx].name.clone());
}
fn current_output_device_index(&self) -> usize {
pub fn current_output_device_index(&self) -> usize {
match &self.config.output_device {
Some(name) => self
.output_devices
@@ -217,25 +242,7 @@ impl AudioSettings {
}
}
pub fn next_input_device(&mut self) {
if self.input_devices.is_empty() {
return;
}
let current_idx = self.current_input_device_index();
let next_idx = (current_idx + 1) % self.input_devices.len();
self.config.input_device = Some(self.input_devices[next_idx].name.clone());
}
pub fn prev_input_device(&mut self) {
if self.input_devices.is_empty() {
return;
}
let current_idx = self.current_input_device_index();
let prev_idx = (current_idx + self.input_devices.len() - 1) % self.input_devices.len();
self.config.input_device = Some(self.input_devices[prev_idx].name.clone());
}
fn current_input_device_index(&self) -> usize {
pub fn current_input_device_index(&self) -> usize {
match &self.config.input_device {
Some(name) => self
.input_devices
@@ -264,29 +271,6 @@ impl AudioSettings {
self.config.refresh_rate = self.config.refresh_rate.toggle();
}
pub fn current_output_device_name(&self) -> &str {
match &self.config.output_device {
Some(name) => name,
None => self
.output_devices
.iter()
.find(|d| d.is_default)
.map(|d| d.name.as_str())
.unwrap_or("Default"),
}
}
pub fn current_input_device_name(&self) -> &str {
match &self.config.input_device {
Some(name) => name,
None => self
.input_devices
.iter()
.find(|d| d.is_default)
.map(|d| d.name.as_str())
.unwrap_or("None"),
}
}
pub fn add_sample_path(&mut self, path: PathBuf) {
if !self.config.sample_paths.contains(&path) {