parent
0e0d72ec9c
commit
dc3ef4830a
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,3 @@
|
|||
[workspace]
|
||||
members = ["plate-tool-web", "plate-tool-lib"]
|
||||
members = ["plate-tool-web", "plate-tool-lib", "plate-tool-eframe"]
|
||||
resolver = "2"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
target = "x86_64-unknown-linux-gnu"
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "plate-tool-eframe"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
plate-tool-lib = { path = "../plate-tool-lib" }
|
||||
eframe = { version = "0.30", default-features = false, features = [
|
||||
"default_fonts",
|
||||
"glow",
|
||||
"wayland",
|
||||
]}
|
|
@ -0,0 +1,54 @@
|
|||
use std::ops::DerefMut;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use eframe::egui::{self};
|
||||
|
||||
use plate_tool_lib::plate::PlateFormat;
|
||||
|
||||
use crate::plate::{add_grid, PlateUiState};
|
||||
|
||||
pub struct PlateToolEframe {
|
||||
format: PlateFormat,
|
||||
source_plate_state: Mutex<PlateUiState>,
|
||||
}
|
||||
|
||||
impl Default for PlateToolEframe {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
format: PlateFormat::W96,
|
||||
source_plate_state: Mutex::new(PlateUiState::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlateToolEframe {
|
||||
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
// Would load state here
|
||||
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for PlateToolEframe {
|
||||
// State storage
|
||||
/*
|
||||
fn save(&mut self, storage: &mut dyn eframe::Storage) {
|
||||
unimplemented!()
|
||||
};
|
||||
*/
|
||||
|
||||
fn update(&mut self, ctx: &eframe::egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||
ui.label("shrimp");
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("lobster");
|
||||
add_grid(
|
||||
PlateFormat::W1536,
|
||||
ui,
|
||||
self.source_plate_state.lock().unwrap().deref_mut(),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
mod app;
|
||||
mod plate;
|
||||
pub use app::PlateToolEframe;
|
|
@ -0,0 +1,15 @@
|
|||
use eframe::*;
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> eframe::Result{
|
||||
let native_options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_title("Shrimp"),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"PlateToolEframe",
|
||||
native_options,
|
||||
Box::new(|cc| Ok(Box::new(plate_tool_eframe::PlateToolEframe::new(cc))))
|
||||
)
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
use eframe::egui::{self, pos2, Color32, Rounding};
|
||||
use plate_tool_lib::plate::PlateFormat;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct PlateUiState {
|
||||
pub drag_start_position: Option<egui::Pos2>,
|
||||
}
|
||||
|
||||
impl Default for PlateUiState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
drag_start_position: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_grid(pf: PlateFormat, ui: &mut egui::Ui, state: &mut PlateUiState) {
|
||||
fn calculate_grid_params(
|
||||
ul_origin: (f32, f32),
|
||||
tw: f32,
|
||||
th: f32,
|
||||
rows: u8,
|
||||
columns: u8,
|
||||
) -> (f32, f32, f32) {
|
||||
// (Start X, Start Y, Radius)
|
||||
const PADDING: f32 = 20.0;
|
||||
|
||||
let usable_width = tw - 2.0 * PADDING;
|
||||
let usable_height = th - 2.0 * PADDING;
|
||||
|
||||
let shared_width = f32::ceil(usable_width / columns as f32);
|
||||
let shared_height = f32::ceil(usable_height / rows as f32);
|
||||
let radius = f32::min(shared_width, shared_height) / 2.0;
|
||||
(ul_origin.0 + PADDING, ul_origin.1 + PADDING, radius)
|
||||
}
|
||||
|
||||
fn get_hover_well(
|
||||
response: &egui::Response,
|
||||
start_x: f32,
|
||||
start_y: f32,
|
||||
radius: f32,
|
||||
) -> Option<(u8, u8)> {
|
||||
get_well_from_pos(response.hover_pos(), start_x, start_y, radius)
|
||||
}
|
||||
|
||||
fn get_well_from_pos(
|
||||
position: Option<egui::Pos2>,
|
||||
start_x: f32,
|
||||
start_y: f32,
|
||||
radius: f32,
|
||||
) -> Option<(u8, u8)> {
|
||||
// Some((row, column))
|
||||
position
|
||||
.map(|p| Into::<(f32, f32)>::into(p))
|
||||
.and_then(|(x, y)| {
|
||||
// Check bounds
|
||||
if x < start_x || y < start_y {
|
||||
return None;
|
||||
}
|
||||
// CHECK Bottom Right BOUND
|
||||
|
||||
let solved_column: u8 = (x - start_x).div_euclid(radius * 2.0) as u8;
|
||||
let solved_row: u8 = (y - start_y).div_euclid(radius * 2.0) as u8;
|
||||
|
||||
Some((solved_row, solved_column))
|
||||
})
|
||||
}
|
||||
|
||||
fn add_grid_sub(rows: u8, columns: u8, ui: &mut egui::Ui, state: &mut PlateUiState) {
|
||||
let available_size = ui.available_size();
|
||||
let (response, painter) =
|
||||
ui.allocate_painter(available_size, egui::Sense::click_and_drag());
|
||||
|
||||
let rect = response.rect;
|
||||
|
||||
let ul_origin = rect.left_top();
|
||||
let total_width = rect.width();
|
||||
let total_height = rect.height();
|
||||
|
||||
let stroke = egui::Stroke::new(2.0, egui::Color32::from_gray(128));
|
||||
let (start_x, start_y, radius) =
|
||||
calculate_grid_params(ul_origin.into(), total_width, total_height, rows, columns);
|
||||
|
||||
// Manage clicks and drags
|
||||
if response.drag_started() {
|
||||
state.drag_start_position = Some(response.hover_pos().unwrap());
|
||||
}
|
||||
if response.drag_stopped() {
|
||||
state.drag_start_position = None;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Plate Frame
|
||||
painter.rect_stroke(
|
||||
egui::Rect {
|
||||
min: pos2(start_x, start_y),
|
||||
max: pos2(
|
||||
start_x + 2.0 * radius * columns as f32,
|
||||
start_y + 2.0 * radius * rows as f32,
|
||||
),
|
||||
},
|
||||
Rounding::default(),
|
||||
stroke,
|
||||
);
|
||||
|
||||
// Draw wells
|
||||
for c_row in 0..rows {
|
||||
for c_column in 0..columns {
|
||||
let center = egui::pos2(
|
||||
start_x + radius + 2.0 * radius * c_column as f32,
|
||||
start_y + radius + 2.0 * radius * c_row as f32,
|
||||
);
|
||||
|
||||
// Draw fill first
|
||||
if response.dragged() {
|
||||
if let (Some(hw), Some(dw)) = (hovered_well, drag_start_well) {
|
||||
if c_column <= u8::max(hw.1, dw.1)
|
||||
&& c_column >= u8::min(hw.1, dw.1)
|
||||
&& c_row <= u8::max(hw.0, dw.0)
|
||||
&& c_row >= u8::min(hw.0, dw.0)
|
||||
{
|
||||
painter.circle_filled(center, radius, Color32::DARK_BLUE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if Some((c_row, c_column)) == hovered_well {
|
||||
painter.circle_filled(center, radius, Color32::RED);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw stroke on top
|
||||
painter.circle_stroke(center, radius - 2.0, stroke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match pf {
|
||||
PlateFormat::W96 => add_grid_sub(8, 12, ui, state),
|
||||
PlateFormat::W384 => add_grid_sub(16, 24, ui, state),
|
||||
PlateFormat::W1536 => add_grid_sub(32, 48, ui, state),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue