big eframe moment
Gitea Scan/plate-tool/pipeline/head This commit looks good
Details
Gitea Scan/plate-tool/pipeline/head This commit looks good
Details
perhaps a "Draw the rest of the owl" commit
This commit is contained in:
parent
b34b02af89
commit
bbf420080d
|
@ -97,6 +97,55 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anymap"
|
name = "anymap"
|
||||||
version = "1.0.0-beta.2"
|
version = "1.0.0-beta.2"
|
||||||
|
@ -375,6 +424,12 @@ dependencies = [
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.7"
|
version = "4.6.7"
|
||||||
|
@ -713,6 +768,29 @@ dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_filter"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.11.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"env_filter",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "epaint"
|
name = "epaint"
|
||||||
version = "0.30.0"
|
version = "0.30.0"
|
||||||
|
@ -1466,6 +1544,12 @@ dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.61"
|
version = "0.1.61"
|
||||||
|
@ -1688,6 +1772,12 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
@ -2332,6 +2422,8 @@ name = "plate-tool-eframe"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"eframe",
|
"eframe",
|
||||||
|
"env_logger",
|
||||||
|
"log",
|
||||||
"plate-tool-lib",
|
"plate-tool-lib",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3115,6 +3207,12 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
|
|
|
@ -10,3 +10,6 @@ eframe = { version = "0.30", default-features = false, features = [
|
||||||
"glow",
|
"glow",
|
||||||
"wayland",
|
"wayland",
|
||||||
]}
|
]}
|
||||||
|
|
||||||
|
log = "0.4"
|
||||||
|
env_logger = "0.11"
|
||||||
|
|
|
@ -4,9 +4,74 @@ use std::sync::Mutex;
|
||||||
use eframe::egui::{self};
|
use eframe::egui::{self};
|
||||||
|
|
||||||
use plate_tool_lib::plate::PlateFormat;
|
use plate_tool_lib::plate::PlateFormat;
|
||||||
|
use plate_tool_lib::plate_instances;
|
||||||
|
|
||||||
use crate::plate::{add_grid, PlateUiState};
|
use crate::plate::{add_grid, PlateUiState};
|
||||||
use crate::transfer_menu::{self, transfer_menu, TransferMenuState};
|
use crate::transfer_menu::{self, transfer_menu, CurrentTransferState, TransferMenuState};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MainState {
|
||||||
|
pub source_plates: Vec<plate_tool_lib::plate_instances::PlateInstance>,
|
||||||
|
pub destination_plates: Vec<plate_tool_lib::plate_instances::PlateInstance>,
|
||||||
|
pub transfers: Vec<plate_tool_lib::transfer::Transfer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_fake_mainstate() -> MainState {
|
||||||
|
let src_plate: plate_tool_lib::plate_instances::PlateInstance =
|
||||||
|
plate_instances::PlateInstance::new(
|
||||||
|
plate_tool_lib::plate::PlateType::Source,
|
||||||
|
PlateFormat::W96,
|
||||||
|
"src1".to_owned(),
|
||||||
|
);
|
||||||
|
let dest_plate: plate_tool_lib::plate_instances::PlateInstance =
|
||||||
|
plate_instances::PlateInstance::new(
|
||||||
|
plate_tool_lib::plate::PlateType::Destination,
|
||||||
|
PlateFormat::W96,
|
||||||
|
"dest1".to_owned(),
|
||||||
|
);
|
||||||
|
let well_a1 = plate_tool_lib::Well { row: 1, col: 1 };
|
||||||
|
let well_c3 = plate_tool_lib::Well { row: 3, col: 3 };
|
||||||
|
let well_a5 = plate_tool_lib::Well { row: 1, col: 5 };
|
||||||
|
|
||||||
|
let transfer1_region: plate_tool_lib::transfer_region::TransferRegion =
|
||||||
|
plate_tool_lib::transfer_region::TransferRegion {
|
||||||
|
source_plate: src_plate.plate,
|
||||||
|
source_region: plate_tool_lib::transfer_region::Region::Rect(well_a1, well_c3),
|
||||||
|
dest_plate: dest_plate.plate,
|
||||||
|
dest_region: plate_tool_lib::transfer_region::Region::Point(well_a1),
|
||||||
|
interleave_source: (1, 1),
|
||||||
|
interleave_dest: (1, 1),
|
||||||
|
};
|
||||||
|
let transfer1: plate_tool_lib::transfer::Transfer = plate_tool_lib::transfer::Transfer::new(
|
||||||
|
src_plate.clone(),
|
||||||
|
dest_plate.clone(),
|
||||||
|
transfer1_region,
|
||||||
|
"Shrimp".to_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let transfer2_region: plate_tool_lib::transfer_region::TransferRegion =
|
||||||
|
plate_tool_lib::transfer_region::TransferRegion {
|
||||||
|
source_plate: src_plate.plate,
|
||||||
|
source_region: plate_tool_lib::transfer_region::Region::Rect(well_a1, well_c3),
|
||||||
|
dest_plate: dest_plate.plate,
|
||||||
|
dest_region: plate_tool_lib::transfer_region::Region::Point(well_a5),
|
||||||
|
interleave_source: (1, 1),
|
||||||
|
interleave_dest: (2, 2),
|
||||||
|
};
|
||||||
|
let transfer2: plate_tool_lib::transfer::Transfer = plate_tool_lib::transfer::Transfer::new(
|
||||||
|
src_plate.clone(),
|
||||||
|
dest_plate.clone(),
|
||||||
|
transfer2_region,
|
||||||
|
"Shrimp".to_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
MainState {
|
||||||
|
source_plates: vec![src_plate],
|
||||||
|
destination_plates: vec![dest_plate],
|
||||||
|
transfers: vec![transfer1, transfer2],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
struct MainWindowState {
|
struct MainWindowState {
|
||||||
|
@ -23,21 +88,26 @@ impl Default for MainWindowState {
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct PlateToolEframe {
|
pub struct PlateToolEframe {
|
||||||
format: PlateFormat,
|
|
||||||
source_plate_state: Mutex<PlateUiState>,
|
source_plate_state: Mutex<PlateUiState>,
|
||||||
destination_plate_state: Mutex<PlateUiState>,
|
destination_plate_state: Mutex<PlateUiState>,
|
||||||
main_window_state: MainWindowState,
|
main_window_state: MainWindowState,
|
||||||
|
current_transfer_state: CurrentTransferState,
|
||||||
transfer_menu_state: TransferMenuState,
|
transfer_menu_state: TransferMenuState,
|
||||||
|
transfer_region_cache: plate_tool_lib::transfer_region_cache::TransferRegionCache,
|
||||||
|
main_state: MainState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlateToolEframe {
|
impl Default for PlateToolEframe {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
format: PlateFormat::W96,
|
|
||||||
source_plate_state: Mutex::new(PlateUiState::default()),
|
source_plate_state: Mutex::new(PlateUiState::default()),
|
||||||
destination_plate_state: Mutex::new(PlateUiState::default()),
|
destination_plate_state: Mutex::new(PlateUiState::default()),
|
||||||
main_window_state: MainWindowState::default(),
|
main_window_state: MainWindowState::default(),
|
||||||
|
current_transfer_state: CurrentTransferState::default(),
|
||||||
transfer_menu_state: TransferMenuState::default(),
|
transfer_menu_state: TransferMenuState::default(),
|
||||||
|
transfer_region_cache: plate_tool_lib::transfer_region_cache::TransferRegionCache::new(
|
||||||
|
),
|
||||||
|
main_state: construct_fake_mainstate(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +116,10 @@ impl PlateToolEframe {
|
||||||
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
// Would load state here
|
// Would load state here
|
||||||
|
|
||||||
Default::default()
|
let pte: PlateToolEframe = Default::default();
|
||||||
|
pte.transfer_region_cache.generate_cache(&pte.main_state.transfers);
|
||||||
|
|
||||||
|
pte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,39 +132,45 @@ impl eframe::App for PlateToolEframe {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn update(&mut self, ctx: &eframe::egui::Context, _frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &eframe::egui::Context, _frame: &mut eframe::Frame) {
|
||||||
|
let ordered_ids: Vec<plate_tool_lib::uuid::Uuid> = {
|
||||||
|
let mut ids: Vec<plate_tool_lib::uuid::Uuid> = self
|
||||||
|
.main_state
|
||||||
|
.transfers
|
||||||
|
.clone()
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.id)
|
||||||
|
.collect();
|
||||||
|
ids.sort_unstable();
|
||||||
|
ids
|
||||||
|
};
|
||||||
|
|
||||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||||
egui::menu::bar(ui, |ui| {
|
egui::menu::bar(ui, |ui| {
|
||||||
ui.menu_button("File", |ui| {
|
ui.menu_button("File", |ui| {
|
||||||
if ui.button("New").clicked() {
|
if ui.button("New").clicked() {}
|
||||||
}
|
|
||||||
ui.menu_button("Export", |ui| {
|
ui.menu_button("Export", |ui| {
|
||||||
if ui.button("Export as CSV").clicked() {
|
if ui.button("Export as CSV").clicked() {}
|
||||||
}
|
if ui.button("Export as JSON").clicked() {}
|
||||||
if ui.button("Export as JSON").clicked() {
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
ui.menu_button("Import", |ui| {
|
ui.menu_button("Import", |ui| {
|
||||||
if ui.button("Import from JSON").clicked() {
|
if ui.button("Import from JSON").clicked() {}
|
||||||
}
|
if ui.button("Import transfer from CSV").clicked() {}
|
||||||
if ui.button("Import transfer from CSV").clicked() {
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.menu_button("Options", |ui| {
|
ui.menu_button("Options", |ui| {
|
||||||
ui.menu_button("Styles", |ui| {
|
ui.menu_button("Styles", |ui| {
|
||||||
if ui.button("Toggle transfer hashes").clicked() {
|
if ui.button("Toggle transfer hashes").clicked() {}
|
||||||
}
|
if ui.button("Toggle volume heatmap").clicked() {}
|
||||||
if ui.button("Toggle volume heatmap").clicked() {
|
if ui.button("Toggle current coordinates view").clicked() {}
|
||||||
}
|
|
||||||
if ui.button("Toggle current coordinates view").clicked() {
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
ui.menu_button("Exports", |ui| {
|
ui.menu_button("Exports", |ui| {
|
||||||
if ui.button("Change CSV export type").clicked() {
|
if ui.button("Change CSV export type").clicked() {}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
ui.menu_button("Windows", |ui| {
|
ui.menu_button("Windows", |ui| {
|
||||||
ui.toggle_value(&mut self.main_window_state.show_side_panel, "Toggle side panel");
|
ui.toggle_value(
|
||||||
|
&mut self.main_window_state.show_side_panel,
|
||||||
|
"Toggle side panel",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -100,7 +179,7 @@ impl eframe::App for PlateToolEframe {
|
||||||
if self.main_window_state.show_side_panel {
|
if self.main_window_state.show_side_panel {
|
||||||
egui::SidePanel::left("side_menus").show(ctx, |ui| {
|
egui::SidePanel::left("side_menus").show(ctx, |ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
transfer_menu(ui, &mut self.transfer_menu_state);
|
transfer_menu(ui, &self.current_transfer_state, &mut self.transfer_menu_state);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -115,13 +194,23 @@ impl eframe::App for PlateToolEframe {
|
||||||
};
|
};
|
||||||
add_grid(
|
add_grid(
|
||||||
half_height,
|
half_height,
|
||||||
PlateFormat::W1536,
|
PlateFormat::W96,
|
||||||
|
&self.main_state.transfers,
|
||||||
|
plate_tool_lib::plate::PlateType::Source,
|
||||||
|
&ordered_ids,
|
||||||
|
&self.transfer_region_cache,
|
||||||
|
Some(&self.current_transfer_state),
|
||||||
ui,
|
ui,
|
||||||
self.source_plate_state.lock().unwrap().deref_mut(),
|
self.source_plate_state.lock().unwrap().deref_mut(),
|
||||||
);
|
);
|
||||||
add_grid(
|
add_grid(
|
||||||
half_height,
|
half_height,
|
||||||
PlateFormat::W1536,
|
PlateFormat::W96,
|
||||||
|
&self.main_state.transfers,
|
||||||
|
plate_tool_lib::plate::PlateType::Destination,
|
||||||
|
&ordered_ids,
|
||||||
|
&self.transfer_region_cache,
|
||||||
|
Some(&self.current_transfer_state),
|
||||||
ui,
|
ui,
|
||||||
self.destination_plate_state.lock().unwrap().deref_mut(),
|
self.destination_plate_state.lock().unwrap().deref_mut(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,9 @@ use eframe::*;
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
|
|
||||||
fn main() -> eframe::Result{
|
fn main() -> eframe::Result{
|
||||||
|
env_logger::init();
|
||||||
|
log::info!("Shrimp!");
|
||||||
|
|
||||||
let native_options = eframe::NativeOptions {
|
let native_options = eframe::NativeOptions {
|
||||||
viewport: egui::ViewportBuilder::default()
|
viewport: egui::ViewportBuilder::default()
|
||||||
.with_title("Shrimp"),
|
.with_title("Shrimp"),
|
||||||
|
|
|
@ -1,8 +1,25 @@
|
||||||
use eframe::egui::{self, pos2, Color32, Rounding};
|
use eframe::egui::{self, pos2, Color32, Rounding};
|
||||||
use plate_tool_lib::plate::PlateFormat;
|
use plate_tool_lib::plate::PlateFormat;
|
||||||
|
use plate_tool_lib::transfer_region::Region;
|
||||||
|
use plate_tool_lib::uuid::Uuid;
|
||||||
|
use plate_tool_lib::Well;
|
||||||
|
|
||||||
|
use crate::transfer_menu::CurrentTransferState;
|
||||||
|
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
const PALETTE: plate_tool_lib::util::ColorPalette = plate_tool_lib::util::Palettes::RAINBOW;
|
const PALETTE: plate_tool_lib::util::ColorPalette = plate_tool_lib::util::Palettes::RAINBOW;
|
||||||
|
|
||||||
|
// Stroke types
|
||||||
|
static STROKE_DEFAULT: LazyLock<egui::Stroke> =
|
||||||
|
LazyLock::new(|| egui::Stroke::new(2.0, egui::Color32::from_gray(128)));
|
||||||
|
static STROKE_CURRENT: LazyLock<egui::Stroke> =
|
||||||
|
LazyLock::new(|| egui::Stroke::new(2.0, egui::Color32::from_gray(200)));
|
||||||
|
static STROKE_SELECT: LazyLock<egui::Stroke> =
|
||||||
|
LazyLock::new(|| egui::Stroke::new(3.0, egui::Color32::from_gray(200)));
|
||||||
|
static STROKE_HOVER: LazyLock<egui::Stroke> =
|
||||||
|
LazyLock::new(|| egui::Stroke::new(3.0, egui::Color32::from_gray(255)));
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PlateUiState {
|
pub struct PlateUiState {
|
||||||
pub drag_start_position: Option<egui::Pos2>,
|
pub drag_start_position: Option<egui::Pos2>,
|
||||||
|
@ -19,19 +36,22 @@ impl Default for PlateUiState {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct WellInfo {
|
struct WellInfo {
|
||||||
volume: f32,
|
volume: f32,
|
||||||
color: [f32; 3],
|
color: [f64; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
impl WellInfo {
|
||||||
transfers: &Vec<plate_tool_lib::transfer::Transfer>,
|
fn new(volume: f32, color: [f64; 3]) -> Self {
|
||||||
ui: &mut egui::Ui, state: &mut PlateUiState) {
|
WellInfo { volume, color }
|
||||||
fn calculate_grid_params(
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_grid_params(
|
||||||
ul_origin: (f32, f32),
|
ul_origin: (f32, f32),
|
||||||
tw: f32,
|
tw: f32,
|
||||||
th: f32,
|
th: f32,
|
||||||
rows: u8,
|
rows: u8,
|
||||||
columns: u8,
|
columns: u8,
|
||||||
) -> (f32, f32, f32) {
|
) -> (f32, f32, f32) {
|
||||||
// (Start X, Start Y, Radius)
|
// (Start X, Start Y, Radius)
|
||||||
const PADDING: f32 = 20.0;
|
const PADDING: f32 = 20.0;
|
||||||
|
|
||||||
|
@ -42,23 +62,23 @@ pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
||||||
let shared_height = f32::ceil(usable_height / rows as f32);
|
let shared_height = f32::ceil(usable_height / rows as f32);
|
||||||
let radius = f32::min(shared_width, shared_height) / 2.0;
|
let radius = f32::min(shared_width, shared_height) / 2.0;
|
||||||
(ul_origin.0 + PADDING, ul_origin.1 + PADDING, radius)
|
(ul_origin.0 + PADDING, ul_origin.1 + PADDING, radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_hover_well(
|
fn get_hover_well(
|
||||||
response: &egui::Response,
|
response: &egui::Response,
|
||||||
start_x: f32,
|
start_x: f32,
|
||||||
start_y: f32,
|
start_y: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
) -> Option<(u8, u8)> {
|
) -> Option<(u8, u8)> {
|
||||||
get_well_from_pos(response.hover_pos(), start_x, start_y, radius)
|
get_well_from_pos(response.hover_pos(), start_x, start_y, radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_well_from_pos(
|
fn get_well_from_pos(
|
||||||
position: Option<egui::Pos2>,
|
position: Option<egui::Pos2>,
|
||||||
start_x: f32,
|
start_x: f32,
|
||||||
start_y: f32,
|
start_y: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
) -> Option<(u8, u8)> {
|
) -> Option<(u8, u8)> {
|
||||||
// Some((row, column))
|
// Some((row, column))
|
||||||
position
|
position
|
||||||
.map(|p| Into::<(f32, f32)>::into(p))
|
.map(|p| Into::<(f32, f32)>::into(p))
|
||||||
|
@ -74,27 +94,62 @@ pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
||||||
|
|
||||||
Some((solved_row, solved_column))
|
Some((solved_row, solved_column))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_shading_for_wells(
|
fn calculate_shading_for_wells(
|
||||||
rows: u8,
|
rows: u8,
|
||||||
columns: u8,
|
columns: u8,
|
||||||
transfers: &Vec<plate_tool_lib::transfer::Transfer>,
|
transfers: &Vec<plate_tool_lib::transfer::Transfer>,
|
||||||
) -> Box<[Option<WellInfo>]> {
|
plate_type: plate_tool_lib::plate::PlateType,
|
||||||
|
ordered_ids: &[Uuid],
|
||||||
|
cache: &plate_tool_lib::transfer_region_cache::TransferRegionCache,
|
||||||
|
) -> Box<[Option<WellInfo>]> {
|
||||||
let box_size: usize = rows as usize * columns as usize;
|
let box_size: usize = rows as usize * columns as usize;
|
||||||
let mut well_infos: Box<[Option<WellInfo>]> = vec![None; box_size].into_boxed_slice();
|
let mut well_infos: Box<[Option<WellInfo>]> = vec![None; box_size].into_boxed_slice();
|
||||||
|
|
||||||
well_infos
|
for transfer in transfers {
|
||||||
|
let cache_result = match plate_type {
|
||||||
|
plate_tool_lib::plate::PlateType::Source => cache.get_source(transfer),
|
||||||
|
plate_tool_lib::plate::PlateType::Destination => cache.get_destination(transfer),
|
||||||
|
};
|
||||||
|
if let Some(wells) = cache_result {
|
||||||
|
for well in wells.iter().filter(|x| x.row <= rows && x.col <= columns) {
|
||||||
|
if let Some(mut x) =
|
||||||
|
well_infos[well.row as usize * columns as usize + well.col as usize]
|
||||||
|
{
|
||||||
|
x.volume += 5.0;
|
||||||
|
x.color = PALETTE.get_ordered(transfer.id, ordered_ids);
|
||||||
|
} else {
|
||||||
|
well_infos[well.row as usize * columns as usize + well.col as usize] = Some(
|
||||||
|
WellInfo::new(5.0, PALETTE.get_ordered(transfer.id, ordered_ids)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_grid_sub(
|
well_infos
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f64_to_color32(x: [f64; 3]) -> Color32 {
|
||||||
|
let r = x[0] as u8;
|
||||||
|
let g = x[1] as u8;
|
||||||
|
let b = x[2] as u8;
|
||||||
|
Color32::from_rgb(r, g, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_grid_sub(
|
||||||
size: egui::Vec2,
|
size: egui::Vec2,
|
||||||
rows: u8,
|
rows: u8,
|
||||||
columns: u8,
|
columns: u8,
|
||||||
transfers: &Vec<plate_tool_lib::transfer::Transfer>,
|
transfers: &Vec<plate_tool_lib::transfer::Transfer>,
|
||||||
|
plate_type: plate_tool_lib::plate::PlateType,
|
||||||
|
ordered_ids: &[Uuid],
|
||||||
|
cache: &plate_tool_lib::transfer_region_cache::TransferRegionCache,
|
||||||
|
current_transfer_state: Option<&CurrentTransferState>,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
state: &mut PlateUiState,
|
state: &mut PlateUiState,
|
||||||
) {
|
) {
|
||||||
let (response, painter) = ui.allocate_painter(size, egui::Sense::click_and_drag());
|
let (response, painter) = ui.allocate_painter(size, egui::Sense::click_and_drag());
|
||||||
|
|
||||||
let rect = response.rect;
|
let rect = response.rect;
|
||||||
|
@ -103,7 +158,6 @@ pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
||||||
let total_width = rect.width();
|
let total_width = rect.width();
|
||||||
let total_height = rect.height();
|
let total_height = rect.height();
|
||||||
|
|
||||||
let stroke = egui::Stroke::new(2.0, egui::Color32::from_gray(128));
|
|
||||||
let (start_x, start_y, radius) =
|
let (start_x, start_y, radius) =
|
||||||
calculate_grid_params(ul_origin.into(), total_width, total_height, rows, columns);
|
calculate_grid_params(ul_origin.into(), total_width, total_height, rows, columns);
|
||||||
|
|
||||||
|
@ -111,13 +165,98 @@ pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
||||||
if response.drag_started() {
|
if response.drag_started() {
|
||||||
state.drag_start_position = Some(response.hover_pos().unwrap());
|
state.drag_start_position = Some(response.hover_pos().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let drag_start_well = get_well_from_pos(state.drag_start_position, start_x, start_y, radius);
|
||||||
|
let hovered_well = get_hover_well(&response, start_x, start_y, radius);
|
||||||
|
|
||||||
|
if response.clicked() {
|
||||||
|
if let Some(cts) = current_transfer_state {
|
||||||
|
let end_well: Option<Well> = hovered_well.map(|(row, col)| Well {
|
||||||
|
row: row + 1,
|
||||||
|
col: col + 1,
|
||||||
|
});
|
||||||
|
if let Some(end_well) = end_well {
|
||||||
|
let new_region = Region::new_from_wells(end_well, None);
|
||||||
|
let mut cts = cts.lock().unwrap();
|
||||||
|
match plate_type {
|
||||||
|
plate_tool_lib::plate::PlateType::Source => cts.source_region = new_region,
|
||||||
|
plate_tool_lib::plate::PlateType::Destination => {
|
||||||
|
cts.destination_region = new_region
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if response.drag_stopped() {
|
if response.drag_stopped() {
|
||||||
|
if let Some(cts) = current_transfer_state {
|
||||||
|
let start_well: Well = drag_start_well
|
||||||
|
.map(|(row, col)| Well {
|
||||||
|
// Lib uses 1-indexing!
|
||||||
|
row: row + 1,
|
||||||
|
col: col + 1,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let end_well: Option<Well> = hovered_well.map(|(row, col)| Well {
|
||||||
|
row: row + 1,
|
||||||
|
col: col + 1,
|
||||||
|
});
|
||||||
|
let new_region = Region::new_from_wells(start_well, end_well);
|
||||||
|
let mut cts = cts.lock().unwrap();
|
||||||
|
match plate_type {
|
||||||
|
plate_tool_lib::plate::PlateType::Source => cts.source_region = new_region,
|
||||||
|
plate_tool_lib::plate::PlateType::Destination => {
|
||||||
|
cts.destination_region = new_region
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
state.drag_start_position = None;
|
state.drag_start_position = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let drag_start_well =
|
let current_selection: Option<Region> = {
|
||||||
get_well_from_pos(state.drag_start_position, start_x, start_y, radius);
|
if let Some(cts) = current_transfer_state {
|
||||||
let hovered_well = get_hover_well(&response, start_x, start_y, radius);
|
let cts = cts.lock().unwrap();
|
||||||
|
match plate_type {
|
||||||
|
plate_tool_lib::plate::PlateType::Source => Some(cts.source_region.clone()),
|
||||||
|
plate_tool_lib::plate::PlateType::Destination => {
|
||||||
|
Some(cts.destination_region.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let well_infos = {
|
||||||
|
let mut well_infos = calculate_shading_for_wells(rows, columns, transfers, plate_type, ordered_ids, cache);
|
||||||
|
// Get wells in the current transfer to tack on to well_infos separately
|
||||||
|
let current_transfer_wells: Option<Box<[(usize,usize)]>> = {
|
||||||
|
(match plate_type {
|
||||||
|
plate_tool_lib::plate::PlateType::Source => current_transfer_state
|
||||||
|
.and_then(|x| x.lock().ok())
|
||||||
|
.map(|mut x| x.get_source_wells()),
|
||||||
|
plate_tool_lib::plate::PlateType::Destination => current_transfer_state
|
||||||
|
.and_then(|x| x.lock().ok())
|
||||||
|
.map(|mut x| x.get_destination_wells()),
|
||||||
|
})
|
||||||
|
// Drop back to 0-indexing here
|
||||||
|
.map(|xs| xs.iter().map(|x| (x.row as usize - 1, x.col as usize - 1)).collect())
|
||||||
|
};
|
||||||
|
if let Some(wells) = current_transfer_wells {
|
||||||
|
for w in wells {
|
||||||
|
let well_info = &mut well_infos[w.0 * columns as usize + w.1];
|
||||||
|
let volume = well_info.map(|x| x.volume).unwrap_or(0.0)
|
||||||
|
+ current_transfer_state.and_then(|x| x.lock().ok())
|
||||||
|
.map(|x| x.volume)
|
||||||
|
.unwrap_or(0.0);
|
||||||
|
|
||||||
|
*well_info = Some(WellInfo {
|
||||||
|
color: [255.0,255.0,255.0],
|
||||||
|
volume: 1.0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
well_infos
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Plate Frame
|
// Plate Frame
|
||||||
painter.rect_stroke(
|
painter.rect_stroke(
|
||||||
|
@ -129,7 +268,7 @@ pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
Rounding::default(),
|
Rounding::default(),
|
||||||
stroke,
|
*STROKE_DEFAULT,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Draw wells
|
// Draw wells
|
||||||
|
@ -140,7 +279,34 @@ pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
||||||
start_y + radius + 2.0 * radius * c_row as f32,
|
start_y + radius + 2.0 * radius * c_row as f32,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//
|
||||||
// Draw fill first
|
// Draw fill first
|
||||||
|
//
|
||||||
|
|
||||||
|
if let Some(well_info) =
|
||||||
|
well_infos[c_row as usize * columns as usize + c_column as usize]
|
||||||
|
{
|
||||||
|
painter.circle_filled(center, radius * 0.80, f64_to_color32(well_info.color));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Draw stroke on top
|
||||||
|
//
|
||||||
|
|
||||||
|
// Base stroke
|
||||||
|
painter.circle_stroke(center, radius * 0.80, *STROKE_DEFAULT);
|
||||||
|
|
||||||
|
if current_selection.as_ref().is_some_and(|x| {
|
||||||
|
x.contains_well(
|
||||||
|
&Well {
|
||||||
|
row: c_row + 1,
|
||||||
|
col: c_column + 1,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
painter.circle_stroke(center, radius * 0.80, *STROKE_CURRENT);
|
||||||
|
}
|
||||||
if response.dragged() {
|
if response.dragged() {
|
||||||
if let (Some(hw), Some(dw)) = (hovered_well, drag_start_well) {
|
if let (Some(hw), Some(dw)) = (hovered_well, drag_start_well) {
|
||||||
if c_column <= u8::max(hw.1, dw.1)
|
if c_column <= u8::max(hw.1, dw.1)
|
||||||
|
@ -148,18 +314,14 @@ pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
||||||
&& c_row <= u8::max(hw.0, dw.0)
|
&& c_row <= u8::max(hw.0, dw.0)
|
||||||
&& c_row >= u8::min(hw.0, dw.0)
|
&& c_row >= u8::min(hw.0, dw.0)
|
||||||
{
|
{
|
||||||
painter.circle_filled(center, radius, Color32::DARK_BLUE);
|
painter.circle_stroke(center, radius * 0.80, *STROKE_SELECT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if Some((c_row, c_column)) == hovered_well {
|
if Some((c_row, c_column)) == hovered_well {
|
||||||
painter.circle_filled(center, radius, Color32::RED);
|
painter.circle_stroke(center, radius * 0.80, *STROKE_HOVER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw stroke on top
|
|
||||||
painter.circle_stroke(center, radius - 2.0, stroke);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw row/column labels
|
// Draw row/column labels
|
||||||
|
@ -187,12 +349,56 @@ pub fn add_grid(size: egui::Vec2, pf: PlateFormat,
|
||||||
egui::Color32::from_gray(128),
|
egui::Color32::from_gray(128),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_grid(
|
||||||
|
size: egui::Vec2,
|
||||||
|
pf: PlateFormat,
|
||||||
|
transfers: &Vec<plate_tool_lib::transfer::Transfer>,
|
||||||
|
plate_type: plate_tool_lib::plate::PlateType,
|
||||||
|
ordered_ids: &[Uuid],
|
||||||
|
cache: &plate_tool_lib::transfer_region_cache::TransferRegionCache,
|
||||||
|
current_transfer_state: Option<&CurrentTransferState>,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
state: &mut PlateUiState,
|
||||||
|
) {
|
||||||
match pf {
|
match pf {
|
||||||
PlateFormat::W96 => add_grid_sub(size, 8, 12, transfers, ui, state),
|
PlateFormat::W96 => add_grid_sub(
|
||||||
PlateFormat::W384 => add_grid_sub(size, 16, 24, transfers, ui, state),
|
size,
|
||||||
PlateFormat::W1536 => add_grid_sub(size, 32, 48, transfers, ui, state),
|
8,
|
||||||
|
12,
|
||||||
|
transfers,
|
||||||
|
plate_type,
|
||||||
|
ordered_ids,
|
||||||
|
cache,
|
||||||
|
current_transfer_state,
|
||||||
|
ui,
|
||||||
|
state,
|
||||||
|
),
|
||||||
|
PlateFormat::W384 => add_grid_sub(
|
||||||
|
size,
|
||||||
|
16,
|
||||||
|
24,
|
||||||
|
transfers,
|
||||||
|
plate_type,
|
||||||
|
ordered_ids,
|
||||||
|
cache,
|
||||||
|
current_transfer_state,
|
||||||
|
ui,
|
||||||
|
state,
|
||||||
|
),
|
||||||
|
PlateFormat::W1536 => add_grid_sub(
|
||||||
|
size,
|
||||||
|
32,
|
||||||
|
48,
|
||||||
|
transfers,
|
||||||
|
plate_type,
|
||||||
|
ordered_ids,
|
||||||
|
cache,
|
||||||
|
current_transfer_state,
|
||||||
|
ui,
|
||||||
|
state,
|
||||||
|
),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,136 @@
|
||||||
use eframe::egui::{self, pos2, Color32, Rounding};
|
use eframe::egui;
|
||||||
|
use plate_tool_lib::transfer_region::{Region, TransferRegion};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||||
|
|
||||||
|
pub type CurrentTransferState = Arc<Mutex<CurrentTransferStateInterior>>;
|
||||||
|
pub struct CurrentTransferStateInterior {
|
||||||
|
pub transfer_name: String,
|
||||||
|
pub source_region: plate_tool_lib::transfer_region::Region,
|
||||||
|
pub destination_region: plate_tool_lib::transfer_region::Region,
|
||||||
|
pub source_plate: plate_tool_lib::plate::Plate,
|
||||||
|
pub destination_plate: plate_tool_lib::plate::Plate,
|
||||||
|
pub source_row_interleave: i8,
|
||||||
|
pub source_column_interleave: i8,
|
||||||
|
pub destination_row_interleave: i8,
|
||||||
|
pub destination_column_interleave: i8,
|
||||||
|
pub volume: f32,
|
||||||
|
transfer_hash: Option<u64>,
|
||||||
|
source_wells: Option<Vec<plate_tool_lib::Well>>,
|
||||||
|
destination_wells: Option<Vec<plate_tool_lib::Well>>,
|
||||||
|
}
|
||||||
|
impl Default for CurrentTransferStateInterior {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
transfer_name: String::default(),
|
||||||
|
source_region: plate_tool_lib::transfer_region::Region::Point(plate_tool_lib::Well {
|
||||||
|
row: 1,
|
||||||
|
col: 1,
|
||||||
|
}),
|
||||||
|
destination_region: plate_tool_lib::transfer_region::Region::Point(
|
||||||
|
plate_tool_lib::Well { row: 1, col: 1 },
|
||||||
|
),
|
||||||
|
source_plate: plate_tool_lib::plate::SOURCE_W96,
|
||||||
|
destination_plate: plate_tool_lib::plate::DESTINATION_W96,
|
||||||
|
source_row_interleave: 1,
|
||||||
|
source_column_interleave: 1,
|
||||||
|
destination_row_interleave: 1,
|
||||||
|
destination_column_interleave: 1,
|
||||||
|
volume: 5.0,
|
||||||
|
transfer_hash: None,
|
||||||
|
source_wells: None,
|
||||||
|
destination_wells: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl CurrentTransferStateInterior {
|
||||||
|
pub fn get_source_wells(&mut self) -> Box<[plate_tool_lib::Well]> {
|
||||||
|
if self.source_wells.is_none() {
|
||||||
|
self.recalulate_wells();
|
||||||
|
}
|
||||||
|
self.recalculate_wells_if_needed();
|
||||||
|
self.source_wells
|
||||||
|
.clone()
|
||||||
|
.expect("Source wells must have been calculated by here.")
|
||||||
|
.into_boxed_slice()
|
||||||
|
}
|
||||||
|
pub fn get_destination_wells(&mut self) -> Box<[plate_tool_lib::Well]> {
|
||||||
|
if self.destination_wells.is_none() {
|
||||||
|
self.recalulate_wells();
|
||||||
|
}
|
||||||
|
self.recalculate_wells_if_needed();
|
||||||
|
self.destination_wells
|
||||||
|
.clone()
|
||||||
|
.expect("Destination wells must have been calculated by here.")
|
||||||
|
.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recalculate_wells_if_needed(&mut self) {
|
||||||
|
if self.transfer_hash.is_none() {
|
||||||
|
self.recalulate_wells();
|
||||||
|
}
|
||||||
|
if self.transfer_hash.unwrap() != self.calculate_hash() {
|
||||||
|
self.recalulate_wells();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn recalulate_wells(&mut self) {
|
||||||
|
let tr = self.generate_transfer_region();
|
||||||
|
|
||||||
|
self.source_wells = Some(tr.get_source_wells());
|
||||||
|
self.destination_wells = Some(tr.get_destination_wells());
|
||||||
|
self.transfer_hash = Some(self.calculate_hash());
|
||||||
|
}
|
||||||
|
fn calculate_hash(&self) -> u64 {
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
self.generate_transfer_region().hash(&mut hasher);
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_transfer_region(&self) -> TransferRegion {
|
||||||
|
TransferRegion {
|
||||||
|
source_plate: self.source_plate,
|
||||||
|
source_region: self.source_region.clone(),
|
||||||
|
dest_plate: self.destination_plate,
|
||||||
|
dest_region: self.destination_region.clone(),
|
||||||
|
interleave_source: (self.source_row_interleave, self.source_column_interleave),
|
||||||
|
interleave_dest: (self.destination_row_interleave, self.destination_column_interleave),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct TransferMenuState {
|
pub struct TransferMenuState {
|
||||||
pub transfer_name: String,
|
pub source_region_string: String,
|
||||||
pub source_region: String,
|
pub destination_region_string: String,
|
||||||
pub destination_region: String,
|
|
||||||
pub source_row_interleave: f32,
|
|
||||||
pub source_column_interleave: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TransferMenuState {
|
impl Default for TransferMenuState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
TransferMenuState {
|
||||||
transfer_name: String::default(),
|
source_region_string: String::new(),
|
||||||
source_region: String::default(),
|
destination_region_string: String::new(),
|
||||||
destination_region: String::default(),
|
}
|
||||||
source_row_interleave: 1.0,
|
}
|
||||||
source_column_interleave: 1.0,
|
}
|
||||||
|
impl TransferMenuState {
|
||||||
|
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();
|
||||||
|
TransferMenuState {
|
||||||
|
source_region_string,
|
||||||
|
destination_region_string,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transfer_menu(ui: &mut egui::Ui, state: &mut TransferMenuState) {
|
pub fn transfer_menu(
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
state: &CurrentTransferState,
|
||||||
|
ui_state: &mut TransferMenuState,
|
||||||
|
) {
|
||||||
|
// Can we reduce the length of this lock pls
|
||||||
|
let mut state = state.lock().unwrap();
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(egui::Label::new("Name"));
|
ui.add(egui::Label::new("Name"));
|
||||||
ui.add(
|
ui.add(
|
||||||
|
@ -32,36 +142,82 @@ pub fn transfer_menu(ui: &mut egui::Ui, state: &mut TransferMenuState) {
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(egui::Label::new("Source Region"));
|
ui.add(egui::Label::new("Source Region"));
|
||||||
ui.add(
|
let resp = ui.add(
|
||||||
egui::TextEdit::singleline(&mut state.source_region)
|
egui::TextEdit::singleline(&mut ui_state.source_region_string)
|
||||||
.hint_text("Source Region")
|
.hint_text("Source Region")
|
||||||
.char_limit(9)
|
.char_limit(9)
|
||||||
.horizontal_align(egui::Align::Center),
|
.horizontal_align(egui::Align::Center),
|
||||||
);
|
);
|
||||||
|
if resp.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
|
||||||
|
if let Some(new_region) = Region::try_parse_str(&ui_state.source_region_string) {
|
||||||
|
state.source_region = new_region;
|
||||||
|
} else {
|
||||||
|
log::warn!("Invalid source region entered.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !resp.has_focus() && !resp.lost_focus() {
|
||||||
|
ui_state.source_region_string = state.source_region.to_string();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(egui::Label::new("Destination Region"));
|
ui.add(egui::Label::new("Destination Region"));
|
||||||
ui.add(
|
let resp = ui.add(
|
||||||
egui::TextEdit::singleline(&mut state.destination_region)
|
egui::TextEdit::singleline(&mut ui_state.destination_region_string)
|
||||||
.hint_text("Destination Region")
|
.hint_text("Destination Region")
|
||||||
.char_limit(9)
|
.char_limit(9)
|
||||||
.horizontal_align(egui::Align::Center),
|
.horizontal_align(egui::Align::Center),
|
||||||
);
|
);
|
||||||
|
if resp.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
|
||||||
|
if let Some(new_region) = Region::try_parse_str(&ui_state.destination_region_string) {
|
||||||
|
state.destination_region = new_region;
|
||||||
|
} else {
|
||||||
|
log::warn!("Invalid destination region entered.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !resp.has_focus() {
|
||||||
|
ui_state.destination_region_string = state.destination_region.to_string();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.label("Source Interleave");
|
ui.label("Source Interleave");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Row: ");
|
ui.label("Row: ");
|
||||||
ui.add(egui::DragValue::new(&mut state.source_row_interleave)
|
ui.add(
|
||||||
|
egui::DragValue::new(&mut state.source_row_interleave)
|
||||||
.fixed_decimals(0)
|
.fixed_decimals(0)
|
||||||
.range(0..=30));
|
.range(1..=30)
|
||||||
|
.speed(0.1),
|
||||||
|
);
|
||||||
ui.label("Col: ");
|
ui.label("Col: ");
|
||||||
ui.add(egui::DragValue::new(&mut state.source_column_interleave)
|
ui.add(
|
||||||
|
egui::DragValue::new(&mut state.source_column_interleave)
|
||||||
.fixed_decimals(0)
|
.fixed_decimals(0)
|
||||||
.range(0..=30));
|
.range(1..=30)
|
||||||
|
.speed(0.1),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
ui.label("Col: ");
|
||||||
|
ui.add(
|
||||||
|
egui::DragValue::new(&mut state.destination_column_interleave)
|
||||||
|
.fixed_decimals(0)
|
||||||
|
.range(0..=30)
|
||||||
|
.speed(0.1),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue