From adb2728deb5a5e97676cd6884678638fc1f4fb8f Mon Sep 17 00:00:00 2001 From: Federico Lolli <federico.lolli@skywarder.eu> Date: Thu, 10 Apr 2025 19:55:47 +0200 Subject: [PATCH] WIP --- Cargo.lock | 12 +- Cargo.toml | 1 + src/ui/panes/valve_control.rs | 82 +-- src/ui/panes/valve_control/ui.rs | 2 +- .../panes/valve_control/ui/shortcut_widget.rs | 9 +- .../valve_control/ui/valve_control_window.rs | 544 ++++++++++++++---- 6 files changed, 489 insertions(+), 161 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f65be72..28368be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1050,7 +1050,7 @@ checksum = "67756b63b283a65bd0534b0c2a5fb1a12a5768bb6383d422147cc93193d09cfc" dependencies = [ "ahash", "egui", - "itertools", + "itertools 0.13.0", "log", "serde", ] @@ -1827,6 +1827,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -3059,6 +3068,7 @@ dependencies = [ "egui_tiles", "enum_dispatch", "glam", + "itertools 0.14.0", "mavlink-bindgen", "mint", "profiling", diff --git a/Cargo.toml b/Cargo.toml index 8c2de1b..b049c64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ egui_plot = "0.31" egui_file = "0.22" enum_dispatch = "0.3" glam = { version = "0.29", features = ["serde", "mint"] } +itertools = "0.14.0" mint = "0.5.9" profiling = "1.0" ring-channel = "0.12.0" diff --git a/src/ui/panes/valve_control.rs b/src/ui/panes/valve_control.rs index 73289d7..ed6743b 100644 --- a/src/ui/panes/valve_control.rs +++ b/src/ui/panes/valve_control.rs @@ -33,7 +33,7 @@ use super::PaneBehavior; use commands::CommandSM; use icons::Icon; -use ui::{ShortcutCard, ValveControlWindow, map_key_to_shortcut}; +use ui::{ShortcutCard, ValveControlView, map_key_to_shortcut}; use valves::{Valve, ValveStateManager}; const DEFAULT_AUTO_REFRESH_RATE: Duration = Duration::from_secs(1); @@ -84,7 +84,7 @@ pub struct ValveControlPane { #[serde(skip)] valve_key_map: HashMap<Valve, Key>, #[serde(skip)] - valve_window: Option<ValveControlWindow>, + valve_view: Option<ValveControlView>, } impl Default for ValveControlPane { @@ -101,7 +101,7 @@ impl Default for ValveControlPane { last_refresh: None, is_settings_window_open: false, valve_key_map, - valve_window: None, + valve_view: None, } } } @@ -114,48 +114,48 @@ impl PaneBehavior for ValveControlPane { // Set this to at least double the maximum icon size used Icon::init_cache(ui.ctx(), (100, 100)); - let res = ui - .scope_builder(UiBuilder::new().sense(Sense::click_and_drag()), |ui| { - self.pane_ui()(ui); - ui.allocate_space(ui.available_size()); - }) - .response; - - // Show the menu when the user right-clicks the pane - res.context_menu(self.menu_ui()); - - // Check if the user started dragging the pane - if res.drag_started() { - pane_response.set_drag_started(); - } - - // capture actions from keyboard shortcuts - let action = self.keyboard_actions(shortcut_handler); + if let Some(valve_view) = &mut self.valve_view { + if let Some(command) = valve_view.ui(ui, shortcut_handler) { + self.commands.push(command.into()); + } - match action { - // Open the valve control window if the action is to open it - Some(PaneAction::OpenValveControl(valve)) => { - self.valve_window.replace(ValveControlWindow::new(valve)); + if valve_view.is_closed() { + self.valve_view = None; + } + } else { + let res = ui + .scope_builder(UiBuilder::new().sense(Sense::click_and_drag()), |ui| { + self.pane_ui()(ui); + ui.allocate_space(ui.available_size()); + }) + .response; + + // Show the menu when the user right-clicks the pane + res.context_menu(self.menu_ui()); + + // Check if the user started dragging the pane + if res.drag_started() { + pane_response.set_drag_started(); } - None => {} - } - Window::new("Settings") - .id(ui.auto_id_with("settings")) - .auto_sized() - .collapsible(true) - .movable(true) - .open(&mut self.is_settings_window_open) - .show(ui.ctx(), Self::settings_window_ui(&mut self.auto_refresh)); + // capture actions from keyboard shortcuts + let action = self.keyboard_actions(shortcut_handler); - if let Some(valve_window) = &mut self.valve_window { - if let Some(command) = valve_window.ui(ui, shortcut_handler) { - self.commands.push(command.into()); + match action { + // Open the valve control window if the action is to open it + Some(PaneAction::OpenValveControl(valve)) => { + self.valve_view.replace(ValveControlView::new(valve)); + } + None => {} } - if valve_window.is_closed() { - self.valve_window = None; - } + Window::new("Settings") + .id(ui.auto_id_with("settings")) + .auto_sized() + .collapsible(true) + .movable(true) + .open(&mut self.is_settings_window_open) + .show(ui.ctx(), Self::settings_window_ui(&mut self.auto_refresh)); } pane_response @@ -241,7 +241,7 @@ impl ValveControlPane { if response.clicked() { info!("Clicked on valve: {:?}", valve); - self.valve_window = Some(ValveControlWindow::new(valve)); + self.valve_view = Some(ValveControlView::new(valve)); } } ui.end_row(); @@ -381,7 +381,7 @@ impl ValveControlPane { let visuals = ui.style().interact(&response); let (fill_color, btn_fill_color, stroke) = if response.clicked() - || shortcut_key_is_down && self.valve_window.is_none() + || shortcut_key_is_down && self.valve_view.is_none() { let visuals = ui.visuals().widgets.active; (visuals.bg_fill, visuals.bg_fill, visuals.bg_stroke) diff --git a/src/ui/panes/valve_control/ui.rs b/src/ui/panes/valve_control/ui.rs index 2c5a1d3..6350f61 100644 --- a/src/ui/panes/valve_control/ui.rs +++ b/src/ui/panes/valve_control/ui.rs @@ -6,7 +6,7 @@ use egui::{Key, KeyboardShortcut, Modifiers}; // Re-export the modules for the UI modules use super::{commands, icons, valves}; -pub use {shortcut_widget::ShortcutCard, valve_control_window::ValveControlWindow}; +pub use {shortcut_widget::ShortcutCard, valve_control_window::ValveControlView}; #[inline] pub fn map_key_to_shortcut(key: Key) -> KeyboardShortcut { diff --git a/src/ui/panes/valve_control/ui/shortcut_widget.rs b/src/ui/panes/valve_control/ui/shortcut_widget.rs index 9bbc056..212d895 100644 --- a/src/ui/panes/valve_control/ui/shortcut_widget.rs +++ b/src/ui/panes/valve_control/ui/shortcut_widget.rs @@ -6,6 +6,7 @@ use egui::{ pub struct ShortcutCard { shortcut: KeyboardShortcut, text_size: f32, + margin: Margin, text_color: Option<Color32>, fill_color: Option<Color32>, } @@ -30,7 +31,7 @@ impl Widget for ShortcutCard { Frame::canvas(ui.style()) .fill(fill_color) .stroke(Stroke::NONE) - .inner_margin(Margin::same(5)) + .inner_margin(self.margin) .corner_radius(corner_radius) .show(ui, |ui| { Label::new(number).selectable(false).ui(ui); @@ -44,6 +45,7 @@ impl ShortcutCard { Self { shortcut, text_size: 20., + margin: Margin::same(5), text_color: None, fill_color: None, } @@ -63,4 +65,9 @@ impl ShortcutCard { self.fill_color = Some(fill_color); self } + + pub fn margin(mut self, margin: Margin) -> Self { + self.margin = margin; + self + } } diff --git a/src/ui/panes/valve_control/ui/valve_control_window.rs b/src/ui/panes/valve_control/ui/valve_control_window.rs index 13a2642..5fa463d 100644 --- a/src/ui/panes/valve_control/ui/valve_control_window.rs +++ b/src/ui/panes/valve_control/ui/valve_control_window.rs @@ -1,7 +1,8 @@ use egui::{ - Color32, DragValue, Frame, Key, Label, Modal, Modifiers, Response, RichText, Sense, Stroke, Ui, - UiBuilder, Vec2, Widget, + Align, Button, Color32, Direction, DragValue, FontId, Frame, Grid, Key, Label, Layout, Margin, + Modifiers, Response, RichText, Sense, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget, }; +use egui_extras::{Size, Strip, StripBuilder}; use tracing::info; use crate::ui::shortcuts::{ShortcutHandler, ShortcutMode}; @@ -12,29 +13,33 @@ use super::{ }; const WIGGLE_KEY: Key = Key::Minus; -const TIMING_KEY: Key = Key::Slash; -const APERTURE_KEY: Key = Key::Period; +/// Key used to focus on the aperture field +const FOCUS_APERTURE_KEY: Key = Key::Num1; +/// Key used to focus on the timing field +const FOCUS_TIMING_KEY: Key = Key::Num2; +/// Key used to set the parameter and loose focus on the field +const SET_PAR_KEY: Key = Key::Plus; #[derive(Debug, Clone, PartialEq)] -pub struct ValveControlWindow { +pub struct ValveControlView { valve: Valve, - state: ValveWindowState, + state: ValveViewState, timing_ms: u32, aperture_perc: f32, } -impl ValveControlWindow { - pub fn new(valve: Valve) -> ValveControlWindow { - ValveControlWindow { +impl ValveControlView { + pub fn new(valve: Valve) -> ValveControlView { + ValveControlView { valve, - state: ValveWindowState::Open, + state: ValveViewState::Open, timing_ms: 0, aperture_perc: 0.0, } } pub fn is_closed(&self) -> bool { - matches!(self.state, ValveWindowState::Closed) + matches!(self.state, ValveViewState::Closed) } #[profiling::function] @@ -47,27 +52,26 @@ impl ValveControlWindow { // Capture the keyboard shortcuts let mut action = self.keyboard_actions(shortcut_handler); - // Draw the window UI - Modal::new(ui.auto_id_with("valve_control")) - .show(ui.ctx(), self.draw_window_ui(&mut action)); + // Draw the view inside the pane + ui.scope(self.draw_view_ui(&mut action)); // Handle the actions self.handle_actions(action) } - fn draw_window_ui(&mut self, action: &mut Option<WindowAction>) -> impl FnOnce(&mut Ui) { + fn draw_view_ui(&mut self, action: &mut Option<WindowAction>) -> impl FnOnce(&mut Ui) { |ui: &mut Ui| { - let icon_size = Vec2::splat(25.); - let text_size = 16.; + let icon_size = Vec2::splat(20.); + let text_size = 14.; fn btn_ui<R>( - window_state: &ValveWindowState, + window_state: &ValveViewState, key: Key, add_contents: impl FnOnce(&mut Ui) -> R, ) -> impl FnOnce(&mut Ui) -> Response { move |ui| { - let wiggle_btn = Frame::canvas(ui.style()) - .inner_margin(ui.spacing().menu_margin) + let btn = Frame::canvas(ui.style()) + .inner_margin(Margin::same(4)) .corner_radius(ui.visuals().noninteractive().corner_radius); ui.scope_builder(UiBuilder::new().id_salt(key).sense(Sense::click()), |ui| { @@ -88,12 +92,11 @@ impl ValveControlWindow { (visuals.bg_fill.gamma_multiply(0.3), stroke) }; - wiggle_btn - .fill(fill_color) + btn.fill(fill_color) .stroke(stroke) .stroke(stroke) .show(ui, |ui| { - ui.set_width(200.); + ui.set_width(ui.available_width()); ui.horizontal(|ui| add_contents(ui)) }); @@ -105,84 +108,391 @@ impl ValveControlWindow { } } - let wiggle_btn_response = btn_ui(&self.state, WIGGLE_KEY, |ui| { - ShortcutCard::new(map_key_to_shortcut(WIGGLE_KEY)) - .text_color(ui.visuals().text_color()) - .fill_color(ui.visuals().widgets.inactive.bg_fill) - .text_size(20.) - .ui(ui); - ui.add( - Icon::Wiggle - .as_image(ui.ctx().theme()) - .fit_to_exact_size(icon_size), - ); - ui.add(Label::new(RichText::new("Wiggle").size(text_size)).selectable(false)); - })(ui); - - let aperture_btn_response = btn_ui(&self.state, APERTURE_KEY, |ui| { - ShortcutCard::new(map_key_to_shortcut(APERTURE_KEY)) - .text_color(ui.visuals().text_color()) - .fill_color(ui.visuals().widgets.inactive.bg_fill) - .text_size(20.) - .ui(ui); - ui.add( - Icon::Aperture - .as_image(ui.ctx().theme()) - .fit_to_exact_size(icon_size), - ); - ui.add(Label::new(RichText::new("Aperture: ").size(text_size)).selectable(false)); - let drag_value_id = ui.next_auto_id(); - ui.add( - DragValue::new(&mut self.aperture_perc) - .speed(0.5) - .range(0.0..=100.0) - .fixed_decimals(0) - .update_while_editing(false) - .suffix("%"), - ); - if matches!(&self.state, ValveWindowState::ApertureFocused) { - ui.ctx().memory_mut(|m| { - m.request_focus(drag_value_id); - }); + let valid_fill = ui + .visuals() + .widgets + .inactive + .bg_fill + .lerp_to_gamma(Color32::GREEN, 0.3); + let invalid_fill = ui + .visuals() + .widgets + .inactive + .bg_fill + .lerp_to_gamma(Color32::RED, 0.3); + + fn shortcut_ui(ui: &Ui, key: &Key) -> ShortcutCard { + let vis = ui.visuals(); + ShortcutCard::new(map_key_to_shortcut(*key)) + .text_color(vis.strong_text_color()) + .fill_color(vis.gray_out(vis.widgets.inactive.bg_fill)) + .margin(Margin::symmetric(5, 2)) + .text_size(12.) + } + + fn add_parameter_btn(ui: &mut Ui, key: Key) -> Response { + ui.scope_builder(UiBuilder::new().id_salt(key).sense(Sense::click()), |ui| { + Frame::canvas(ui.style()) + .inner_margin(Margin::symmetric(4, 2)) + .outer_margin(0) + .corner_radius(ui.visuals().noninteractive().corner_radius) + .fill(ui.visuals().widgets.inactive.bg_fill) + .stroke(Stroke::new(1., Color32::TRANSPARENT)) + .show(ui, |ui| { + ui.set_height(ui.available_height()); + ui.horizontal_centered(|ui| { + ui.set_height(21.); + ui.add_space(1.); + Label::new( + RichText::new("SET") + .size(16.) + .color(ui.visuals().widgets.inactive.text_color()), + ) + .selectable(false) + .ui(ui); + shortcut_ui(ui, &key).ui(ui); + }); + }); + }) + .response + } + + // set aperture and timing buttons + let aperture_btn: Box<dyn FnOnce(&mut Ui) -> Response> = match self.state { + ValveViewState::Open => Box::new(|ui| add_parameter_btn(ui, FOCUS_APERTURE_KEY)), + ValveViewState::ApertureFocused => { + Box::new(|ui| add_parameter_btn(ui, SET_PAR_KEY)) } - })(ui); - - let timing_btn_response = btn_ui(&self.state, TIMING_KEY, |ui| { - ShortcutCard::new(map_key_to_shortcut(TIMING_KEY)) - .text_color(ui.visuals().text_color()) - .fill_color(ui.visuals().widgets.inactive.bg_fill) - .text_size(20.) - .ui(ui); - ui.add( - Icon::Timing - .as_image(ui.ctx().theme()) - .fit_to_exact_size(icon_size), - ); - ui.add(Label::new(RichText::new("Timing: ").size(text_size)).selectable(false)); - let drag_value_id = ui.next_auto_id(); - ui.add( - DragValue::new(&mut self.timing_ms) - .speed(1) - .range(1..=10000) - .fixed_decimals(0) - .update_while_editing(false) - .suffix(" [ms]"), + ValveViewState::TimingFocused | ValveViewState::Closed => { + Box::new(|ui| ui.response()) + } + }; + + // set timing button + let timing_btn: Box<dyn FnOnce(&mut Ui) -> Response> = match self.state { + ValveViewState::Open => Box::new(|ui| add_parameter_btn(ui, FOCUS_TIMING_KEY)), + ValveViewState::TimingFocused => Box::new(|ui| add_parameter_btn(ui, SET_PAR_KEY)), + ValveViewState::ApertureFocused | ValveViewState::Closed => { + Box::new(|ui| ui.response()) + } + }; + + // wiggle button with shortcut + let wiggle_btn = |ui: &mut Ui| { + ui.scope_builder( + UiBuilder::new().id_salt(WIGGLE_KEY).sense(Sense::click()), + |ui| { + Frame::canvas(ui.style()) + .inner_margin(Margin::symmetric(4, 2)) + .outer_margin(0) + .corner_radius(ui.visuals().noninteractive().corner_radius) + .fill(ui.visuals().widgets.inactive.bg_fill) + .stroke(Stroke::new(1., Color32::TRANSPARENT)) + .show(ui, |ui| { + ui.set_height(ui.available_height()); + ui.horizontal_centered(|ui| { + ui.set_height(21.); + ui.add_space(1.); + Label::new( + RichText::new("WIGGLE") + .size(16.) + .color(ui.visuals().widgets.inactive.text_color()), + ) + .selectable(false) + .ui(ui); + ui.add( + Icon::Wiggle + .as_image(ui.ctx().theme()) + .fit_to_exact_size(Vec2::splat(22.)), + ); + shortcut_ui(ui, &WIGGLE_KEY).ui(ui); + }); + }); + }, ); - if matches!(&self.state, ValveWindowState::TimingFocused) { - ui.ctx().memory_mut(|m| { - m.request_focus(drag_value_id); + }; + + ui.with_layout(Layout::centered_and_justified(Direction::TopDown), |ui| { + ui.set_max_width(300.); + ui.set_min_height(50.); + StripBuilder::new(ui) + .size(Size::exact(5.)) + .sizes(Size::initial(5.), 3) + .vertical(|mut strip| { + strip.empty(); + // strip.cell(|ui| { + // // ui.add_sized( + // // Vec2::new(ui.available_width(), 0.0), + // // Button::new("Wiggle"), + // // ); + // let wiggle_btn_response = btn_ui(&self.state, WIGGLE_KEY, |ui| { + // shortcut_ui(ui, &WIGGLE_KEY).ui(ui); + // ui.add( + // Icon::Wiggle + // .as_image(ui.ctx().theme()) + // .fit_to_exact_size(icon_size), + // ); + // ui.add( + // Label::new(RichText::new("WIGGLE").size(text_size)) + // .selectable(false), + // ); + // })(ui); + // }); + strip.strip(|builder| { + builder + // .size(Size::exact(230.)) + .size(Size::initial(10.)) + .size(Size::exact(25.)) + .horizontal(|mut strip| { + strip.strip(|builder| { + builder + .size(Size::remainder()) + .size(Size::initial(5.)) + .size(Size::remainder()) + .vertical(|mut strip| { + strip.empty(); + strip.cell(|ui| { + ui.with_layout( + Layout::right_to_left(Align::Min), + |ui| { + Label::new( + RichText::new( + self.valve + .to_string() + .to_uppercase(), + ) + .color( + ui.visuals() + .strong_text_color(), + ) + .size(16.), + ) + .ui(ui); + Label::new( + RichText::new("VALVE: ").size(16.), + ) + .selectable(false) + .ui(ui); + }, + ); + }); + strip.empty(); + }); + }); + strip.cell(wiggle_btn); + }); + }); + strip.strip(|builder| { + builder + .sizes(Size::initial(85.), 4) + .horizontal(|mut strip| { + strip.strip(|builder| { + builder + .size(Size::remainder()) + .size(Size::initial(5.)) + .size(Size::remainder()) + .vertical(|mut strip| { + strip.empty(); + strip.cell(|ui| { + ui.with_layout( + Layout::right_to_left(Align::Min), + |ui| { + Label::new( + RichText::new("APERTURE:") + .size(16.), + ) + .selectable(false) + .ui(ui); + }, + ); + }); + strip.empty(); + }); + }); + strip.cell(|ui| { + Frame::canvas(ui.style()) + .outer_margin(0) + .inner_margin(Margin::symmetric(0, 3)) + .corner_radius( + ui.visuals().noninteractive().corner_radius, + ) + .fill(invalid_fill) + .stroke(Stroke::new(1., Color32::TRANSPARENT)) + .show(ui, |ui| { + Label::new( + RichText::new("0.813").size(14.).strong(), + ) + .ui(ui); + }); + }); + strip.cell(|ui| { + Frame::canvas(ui.style()) + .inner_margin(Margin::symmetric(0, 3)) + .outer_margin(0) + .corner_radius( + ui.visuals().noninteractive().corner_radius, + ) + .fill(ui.visuals().widgets.inactive.bg_fill) + .stroke(Stroke::new(1., Color32::TRANSPARENT)) + .show(ui, |ui| { + let res = ui.add_sized( + Vec2::new(ui.available_width(), 0.0), + DragValue::new(&mut self.aperture_perc) + .speed(0.5) + .range(0.0..=100.0) + .fixed_decimals(0) + .update_while_editing(false) + .suffix("%"), + ); + if res.gained_focus() { + self.state = ValveViewState::ApertureFocused; + } + }); + }); + strip.cell(|ui| { + aperture_btn(ui); + }); + }); + }); + strip.strip(|builder| { + builder + .sizes(Size::initial(85.), 4) + .horizontal(|mut strip| { + strip.strip(|builder| { + builder + .size(Size::remainder()) + .size(Size::initial(10.)) + .size(Size::remainder()) + .vertical(|mut strip| { + strip.empty(); + strip.cell(|ui| { + ui.with_layout( + Layout::right_to_left(Align::Min), + |ui| { + Label::new( + RichText::new("TIMING:").size(16.), + ) + .selectable(false) + .ui(ui); + }, + ); + }); + strip.empty(); + }); + }); + strip.cell(|ui| { + Frame::canvas(ui.style()) + .inner_margin(Margin::same(4)) + .corner_radius( + ui.visuals().noninteractive().corner_radius, + ) + .fill(valid_fill) + .stroke(Stroke::new(1., Color32::TRANSPARENT)) + .show(ui, |ui| { + Label::new( + RichText::new("650ms").size(14.).strong(), + ) + .ui(ui); + }); + }); + strip.cell(|ui| { + Frame::canvas(ui.style()) + .inner_margin(Margin::same(4)) + .corner_radius( + ui.visuals().noninteractive().corner_radius, + ) + .fill(ui.visuals().widgets.inactive.bg_fill) + .stroke(Stroke::new(1., Color32::TRANSPARENT)) + .show(ui, |ui| { + ui.add_sized( + Vec2::new(ui.available_width(), 0.0), + DragValue::new(&mut self.timing_ms) + .speed(1) + .range(1..=10000) + .fixed_decimals(0) + .update_while_editing(false) + .suffix(" [ms]"), + ); + }); + }); + strip.cell(|ui| { + timing_btn(ui); + }); + }); + }); }); - } - })(ui); - - // consider that action may be different that null if a keyboard shortcut was captured - if wiggle_btn_response.clicked() { - action.replace(WindowAction::Wiggle); - } else if aperture_btn_response.clicked() { - action.replace(WindowAction::SetAperture); - } else if timing_btn_response.clicked() { - action.replace(WindowAction::SetTiming); - } + }); + + // ui.horizontal(|ui| { + // let wiggle_btn_response = btn_ui(&self.state, WIGGLE_KEY, |ui| { + // shortcut_ui(ui, &WIGGLE_KEY).ui(ui); + // ui.add( + // Icon::Wiggle + // .as_image(ui.ctx().theme()) + // .fit_to_exact_size(icon_size), + // ); + // ui.add(Label::new(RichText::new("Wiggle").size(text_size)).selectable(false)); + // })(ui); + + // let aperture_btn_response = btn_ui(&self.state, APERTURE_KEY, |ui| { + // shortcut_ui(ui, &APERTURE_KEY).ui(ui); + // ui.add( + // Icon::Aperture + // .as_image(ui.ctx().theme()) + // .fit_to_exact_size(icon_size), + // ); + // ui.add( + // Label::new(RichText::new("Aperture: ").size(text_size)).selectable(false), + // ); + // let drag_value_id = ui.next_auto_id(); + // ui.add( + // DragValue::new(&mut self.aperture_perc) + // .speed(0.5) + // .range(0.0..=100.0) + // .fixed_decimals(0) + // .update_while_editing(false) + // .suffix("%"), + // ); + // if matches!(&self.state, ValveViewState::ApertureFocused) { + // ui.ctx().memory_mut(|m| { + // m.request_focus(drag_value_id); + // }); + // } + // })(ui); + + // let timing_btn_response = btn_ui(&self.state, TIMING_KEY, |ui| { + // shortcut_ui(ui, &TIMING_KEY).ui(ui); + // ui.add( + // Icon::Timing + // .as_image(ui.ctx().theme()) + // .fit_to_exact_size(icon_size), + // ); + // ui.add(Label::new(RichText::new("Timing: ").size(text_size)).selectable(false)); + // let drag_value_id = ui.next_auto_id(); + // ui.add( + // DragValue::new(&mut self.timing_ms) + // .speed(1) + // .range(1..=10000) + // .fixed_decimals(0) + // .update_while_editing(false) + // .suffix(" [ms]"), + // ); + // if matches!(&self.state, ValveViewState::TimingFocused) { + // ui.ctx().memory_mut(|m| { + // m.request_focus(drag_value_id); + // }); + // } + // })(ui); + + // // consider that action may be different that null if a keyboard shortcut was captured + // if wiggle_btn_response.clicked() { + // action.replace(WindowAction::Wiggle); + // } else if aperture_btn_response.clicked() { + // action.replace(WindowAction::SetAperture); + // } else if timing_btn_response.clicked() { + // action.replace(WindowAction::SetTiming); + // } + // }); } } @@ -190,11 +500,11 @@ impl ValveControlWindow { match action { // If the action close is called, close the window Some(WindowAction::CloseWindow) => { - self.state = ValveWindowState::Closed; + self.state = ValveViewState::Closed; None } Some(WindowAction::LooseFocus) => { - self.state = ValveWindowState::Open; + self.state = ValveViewState::Open; None } Some(WindowAction::Wiggle) => { @@ -206,7 +516,7 @@ impl ValveControlWindow { "Issued command to set timing for valve {:?} to {} ms", self.valve, self.timing_ms ); - self.state = ValveWindowState::Open; + self.state = ValveViewState::Open; Some(Command::set_atomic_valve_timing(self.valve, self.timing_ms)) } Some(WindowAction::SetAperture) => { @@ -214,18 +524,18 @@ impl ValveControlWindow { "Issued command to set aperture for valve {:?} to {}%", self.valve, self.aperture_perc ); - self.state = ValveWindowState::Open; + self.state = ValveViewState::Open; Some(Command::set_valve_maximum_aperture( self.valve, self.aperture_perc / 100., )) } Some(WindowAction::FocusOnTiming) => { - self.state = ValveWindowState::TimingFocused; + self.state = ValveViewState::TimingFocused; None } Some(WindowAction::FocusOnAperture) => { - self.state = ValveWindowState::ApertureFocused; + self.state = ValveViewState::ApertureFocused; None } _ => None, @@ -233,49 +543,49 @@ impl ValveControlWindow { } } -impl ValveControlWindow { +impl ValveControlView { #[profiling::function] fn keyboard_actions(&self, shortcut_handler: &mut ShortcutHandler) -> Option<WindowAction> { let mut key_action_pairs = Vec::new(); shortcut_handler.activate_mode(ShortcutMode::valve_control()); match self.state { - ValveWindowState::Open => { + ValveViewState::Open => { // A window is open, so we can map the keys to control the valve key_action_pairs.push((Modifiers::NONE, WIGGLE_KEY, WindowAction::Wiggle)); - key_action_pairs.push((Modifiers::NONE, TIMING_KEY, WindowAction::FocusOnTiming)); - key_action_pairs.push(( - Modifiers::NONE, - APERTURE_KEY, - WindowAction::FocusOnAperture, - )); + // key_action_pairs.push((Modifiers::NONE, TIMING_KEY, WindowAction::FocusOnTiming)); + // key_action_pairs.push(( + // Modifiers::NONE, + // APERTURE_KEY, + // WindowAction::FocusOnAperture, + // )); key_action_pairs.push((Modifiers::NONE, Key::Escape, WindowAction::CloseWindow)); } - ValveWindowState::TimingFocused => { + ValveViewState::TimingFocused => { // The timing field is focused, so we can map the keys to control the timing key_action_pairs.push((Modifiers::NONE, Key::Enter, WindowAction::SetTiming)); key_action_pairs.push((Modifiers::NONE, Key::Escape, WindowAction::LooseFocus)); } - ValveWindowState::ApertureFocused => { + ValveViewState::ApertureFocused => { // The aperture field is focused, so we can map the keys to control the aperture key_action_pairs.push((Modifiers::NONE, Key::Enter, WindowAction::SetAperture)); key_action_pairs.push((Modifiers::NONE, Key::Escape, WindowAction::LooseFocus)); } - ValveWindowState::Closed => {} + ValveViewState::Closed => {} } shortcut_handler.consume_if_mode_is(ShortcutMode::valve_control(), &key_action_pairs[..]) } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ValveWindowState { +enum ValveViewState { Closed, Open, TimingFocused, ApertureFocused, } -impl ValveWindowState { +impl ValveViewState { #[inline] fn is_open(&self) -> bool { matches!(self, Self::Open) -- GitLab