From 5aa29ff83650aefc575fa2b66a29d5c4683ffc98 Mon Sep 17 00:00:00 2001 From: Emilia Date: Sun, 23 Nov 2025 20:22:55 -0500 Subject: [PATCH] Add volume and scroll wheel functionality for numeric values --- plate-tool-eframe/src/extra_widgets.rs | 37 ++++++++++ plate-tool-eframe/src/lib.rs | 1 + plate-tool-eframe/src/transfer_menu.rs | 95 ++++++++++++++++++-------- 3 files changed, 103 insertions(+), 30 deletions(-) create mode 100644 plate-tool-eframe/src/extra_widgets.rs diff --git a/plate-tool-eframe/src/extra_widgets.rs b/plate-tool-eframe/src/extra_widgets.rs new file mode 100644 index 0000000..4187d41 --- /dev/null +++ b/plate-tool-eframe/src/extra_widgets.rs @@ -0,0 +1,37 @@ +use eframe::egui; + +pub fn drag_value_with_scroll( + ui: &mut egui::Ui, + value: &mut T, + range: std::ops::RangeInclusive, + speed_drag: f64, + speed_scroll: f64, +) -> egui::Response +where + T: egui::emath::Numeric + std::ops::Add + std::fmt::Debug +{ + let drag = egui::DragValue::new(value) + .speed(speed_drag) + .range(range.clone()); + + let response = ui.add(drag); + + if response.hovered() { + let scroll_diff = ui.input(|i| i.smooth_scroll_delta.y); + + const THRESHOLD: f32 = 10.0; + if scroll_diff > THRESHOLD { + *value = clamp_partial(*value + T::from_f64(speed_scroll), *range.start(), *range.end()); + } else if scroll_diff < -THRESHOLD { + *value = clamp_partial(*value + T::from_f64(-speed_scroll), *range.start(), *range.end()); + } + } + + response +} + +fn clamp_partial(val: T, min: T, max: T) -> T { + if val < min { min } + else if val > max { max } + else { val } +} diff --git a/plate-tool-eframe/src/lib.rs b/plate-tool-eframe/src/lib.rs index 26426f3..5462cd6 100644 --- a/plate-tool-eframe/src/lib.rs +++ b/plate-tool-eframe/src/lib.rs @@ -7,4 +7,5 @@ mod modals; mod styling; mod file_handling; mod upper_menu; +mod extra_widgets; pub use app::PlateToolEframe; diff --git a/plate-tool-eframe/src/transfer_menu.rs b/plate-tool-eframe/src/transfer_menu.rs index 7ca6673..9967e98 100644 --- a/plate-tool-eframe/src/transfer_menu.rs +++ b/plate-tool-eframe/src/transfer_menu.rs @@ -3,6 +3,7 @@ use plate_tool_lib::transfer_region::{self, Region, TransferRegion}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::sync::{Arc, Mutex}; +use crate::extra_widgets; use crate::main_state::{self, MainState}; pub type CurrentTransferState = Arc>; @@ -140,18 +141,30 @@ impl CurrentTransferStateInterior { None } - pub fn convert_to_transfer(&self, ms: &MainState) -> Option { + pub fn convert_to_transfer( + &self, + ms: &MainState, + ) -> Option { let source_plate_uuid = ms.get_current_source_uuid()?; let destination_plate_uuid = ms.get_current_destination_uuid()?; - let source_plate_instance = ms.source_plates.iter().find(|x| x.get_uuid() == source_plate_uuid)?; - let destination_plate_instance = ms.destination_plates.iter().find(|x| x.get_uuid() == destination_plate_uuid)?; + let source_plate_instance = ms + .source_plates + .iter() + .find(|x| x.get_uuid() == source_plate_uuid)?; + let destination_plate_instance = ms + .destination_plates + .iter() + .find(|x| x.get_uuid() == destination_plate_uuid)?; let transfer = Some(plate_tool_lib::transfer::Transfer::new( source_plate_instance.clone(), destination_plate_instance.clone(), self.generate_transfer_region(), self.transfer_name.clone(), )); - transfer.map(|mut x| {x.volume = plate_tool_lib::transfer_volume::TransferVolume::Single(self.volume); x}) + transfer.map(|mut x| { + x.volume = plate_tool_lib::transfer_volume::TransferVolume::Single(self.volume); + x + }) } } @@ -170,7 +183,7 @@ impl Default for TransferMenuState { } } impl TransferMenuState { - fn new_from_cts(cts: &CurrentTransferState) -> Self { + fn _new_from_cts(cts: &CurrentTransferState) -> Self { let cts = cts.lock().unwrap(); let source_region_string = cts.source_region.to_string(); let destination_region_string = cts.destination_region.to_string(); @@ -188,7 +201,7 @@ pub fn transfer_menu( main_state: &mut MainState, ) { // Can we reduce the length of this lock pls - let cts = state; + let _cts = state; let mut state = state.lock().unwrap(); ui.horizontal(|ui| { @@ -200,6 +213,17 @@ pub fn transfer_menu( ); }); + ui.horizontal(|ui| { + ui.add(egui::Label::new("Volume")); + extra_widgets::drag_value_with_scroll( + ui, + &mut state.volume, + 0.0..=f32::INFINITY, + 0.5, + 1.0, + ); + }); + ui.horizontal(|ui| { ui.add(egui::Label::new("Source Region")); let resp = ui.add( @@ -245,18 +269,20 @@ pub fn transfer_menu( ui.label("Source Interleave"); ui.horizontal(|ui| { ui.label("Row: "); - ui.add( - egui::DragValue::new(&mut state.source_row_interleave) - .fixed_decimals(0) - .range(1..=30) - .speed(0.1), + extra_widgets::drag_value_with_scroll( + ui, + &mut state.source_row_interleave, + 0..=30, + 0.1, + 1.0, ); ui.label("Col: "); - ui.add( - egui::DragValue::new(&mut state.source_column_interleave) - .fixed_decimals(0) - .range(1..=30) - .speed(0.1), + extra_widgets::drag_value_with_scroll( + ui, + &mut state.source_column_interleave, + 0..=30, + 0.1, + 1.0, ); }); }); @@ -265,18 +291,20 @@ pub fn transfer_menu( ui.label("Destination Interleave"); ui.horizontal(|ui| { ui.label("Row: "); - ui.add( - egui::DragValue::new(&mut state.destination_row_interleave) - .fixed_decimals(0) - .range(0..=30) - .speed(0.1), + extra_widgets::drag_value_with_scroll( + ui, + &mut state.destination_row_interleave, + 0..=30, + 0.1, + 1.0, ); ui.label("Col: "); - ui.add( - egui::DragValue::new(&mut state.destination_column_interleave) - .fixed_decimals(0) - .range(0..=30) - .speed(0.1), + extra_widgets::drag_value_with_scroll( + ui, + &mut state.destination_column_interleave, + 0..=30, + 0.1, + 1.0, ); }); }); @@ -285,12 +313,17 @@ pub fn transfer_menu( if ui.button("Save").clicked() { if let Some(transfer_uuid) = main_state.get_current_transfer_uuid() { log::info!("should change transfer"); - if let Some(mut transfer) = main_state.transfers.iter_mut().find(|x| x.id == transfer_uuid) { + if let Some(transfer) = main_state + .transfers + .iter_mut() + .find(|x| x.id == transfer_uuid) + { transfer.transfer_region = state.generate_transfer_region(); transfer.name = state.transfer_name.clone(); main_state.transfer_region_cache.invalidate(&transfer); } - } else { // Need to make a new transfer + } else { + // Need to make a new transfer if state.transfer_name.is_empty() { state.transfer_name = "New Transfer".to_string(); } @@ -298,8 +331,10 @@ pub fn transfer_menu( log::info!("{:?}", new_transfer); if let Some(new_transfer) = new_transfer { main_state.transfers.push(new_transfer); - let new_transfer = main_state.transfers.last() - .expect("Cannot be empty, just added a transfer"); + let new_transfer = main_state + .transfers + .last() + .expect("Cannot be empty, just added a transfer"); main_state.transfer_region_cache.add_overwrite(new_transfer); main_state.set_current_transfer(new_transfer.id); }