Display options for plate
This commit is contained in:
		
							parent
							
								
									e6d80ab8a3
								
							
						
					
					
						commit
						418bf4a79e
					
				| 
						 | 
					@ -5,7 +5,7 @@ use eframe::egui::{self};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::main_state::{construct_fake_mainstate, MainState};
 | 
					use crate::main_state::{construct_fake_mainstate, MainState};
 | 
				
			||||||
use crate::modals::{self, ModalState};
 | 
					use crate::modals::{self, ModalState};
 | 
				
			||||||
use crate::plate::{add_plate, PlateUiState};
 | 
					use crate::plate::{add_plate, PlateDisplayOptions, PlateUiState};
 | 
				
			||||||
use crate::transfer_menu::{transfer_menu, CurrentTransferState, TransferMenuState};
 | 
					use crate::transfer_menu::{transfer_menu, CurrentTransferState, TransferMenuState};
 | 
				
			||||||
use crate::tree::tree;
 | 
					use crate::tree::tree;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,12 +13,14 @@ use crate::tree::tree;
 | 
				
			||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
struct MainWindowState {
 | 
					struct MainWindowState {
 | 
				
			||||||
    show_side_panel: bool,
 | 
					    show_side_panel: bool,
 | 
				
			||||||
 | 
					    plate_display_options: PlateDisplayOptions,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for MainWindowState {
 | 
					impl Default for MainWindowState {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            show_side_panel: true,
 | 
					            show_side_panel: true,
 | 
				
			||||||
 | 
					            plate_display_options: PlateDisplayOptions::default(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -101,9 +103,15 @@ impl eframe::App for PlateToolEframe {
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
                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() {}
 | 
					                            self.main_window_state.plate_display_options.show_transfer_hashes ^= true;
 | 
				
			||||||
                        if ui.button("Toggle current coordinates view").clicked() {}
 | 
					                        }
 | 
				
			||||||
 | 
					                        if ui.button("Toggle volume heatmap").clicked() {
 | 
				
			||||||
 | 
					                            self.main_window_state.plate_display_options.show_volume_heatmap ^= true;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if ui.button("Toggle current coordinates view").clicked() {
 | 
				
			||||||
 | 
					                            self.main_window_state.plate_display_options.show_coordinates ^= true;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                    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() {}
 | 
				
			||||||
| 
						 | 
					@ -169,6 +177,7 @@ impl eframe::App for PlateToolEframe {
 | 
				
			||||||
                        Some(&self.current_transfer_state),
 | 
					                        Some(&self.current_transfer_state),
 | 
				
			||||||
                        ui,
 | 
					                        ui,
 | 
				
			||||||
                        self.source_plate_state.lock().unwrap().deref_mut(),
 | 
					                        self.source_plate_state.lock().unwrap().deref_mut(),
 | 
				
			||||||
 | 
					                        self.main_window_state.plate_display_options,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if let Some(destination_pi) =
 | 
					                if let Some(destination_pi) =
 | 
				
			||||||
| 
						 | 
					@ -184,6 +193,7 @@ impl eframe::App for PlateToolEframe {
 | 
				
			||||||
                        Some(&self.current_transfer_state),
 | 
					                        Some(&self.current_transfer_state),
 | 
				
			||||||
                        ui,
 | 
					                        ui,
 | 
				
			||||||
                        self.destination_plate_state.lock().unwrap().deref_mut(),
 | 
					                        self.destination_plate_state.lock().unwrap().deref_mut(),
 | 
				
			||||||
 | 
					                        self.main_window_state.plate_display_options,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
use eframe::egui::{self, pos2, Color32, Rounding};
 | 
					use eframe::egui::{self, pos2, Color32, Rounding};
 | 
				
			||||||
 | 
					use eframe::glow::OFFSET;
 | 
				
			||||||
use plate_tool_lib::plate::PlateFormat;
 | 
					use plate_tool_lib::plate::PlateFormat;
 | 
				
			||||||
use plate_tool_lib::transfer_region::Region;
 | 
					use plate_tool_lib::transfer_region::Region;
 | 
				
			||||||
use plate_tool_lib::uuid::Uuid;
 | 
					use plate_tool_lib::uuid::Uuid;
 | 
				
			||||||
| 
						 | 
					@ -37,11 +38,34 @@ impl Default for PlateUiState {
 | 
				
			||||||
struct WellInfo {
 | 
					struct WellInfo {
 | 
				
			||||||
    volume: f32,
 | 
					    volume: f32,
 | 
				
			||||||
    color: [f64; 3],
 | 
					    color: [f64; 3],
 | 
				
			||||||
 | 
					    highlight: bool,
 | 
				
			||||||
 | 
					    fill: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl WellInfo {
 | 
					impl WellInfo {
 | 
				
			||||||
    fn new(volume: f32, color: [f64; 3]) -> Self {
 | 
					    fn new(volume: f32, color: [f64; 3]) -> Self {
 | 
				
			||||||
        WellInfo { volume, color }
 | 
					        WellInfo {
 | 
				
			||||||
 | 
					            volume,
 | 
				
			||||||
 | 
					            color,
 | 
				
			||||||
 | 
					            highlight: false,
 | 
				
			||||||
 | 
					            fill: true,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
 | 
					pub struct PlateDisplayOptions {
 | 
				
			||||||
 | 
					    pub show_transfer_hashes: bool,
 | 
				
			||||||
 | 
					    pub show_volume_heatmap: bool,
 | 
				
			||||||
 | 
					    pub show_coordinates: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl Default for PlateDisplayOptions {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            show_transfer_hashes: true,
 | 
				
			||||||
 | 
					            show_volume_heatmap: false,
 | 
				
			||||||
 | 
					            show_coordinates: true,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,9 +167,9 @@ fn calculate_shading_for_wells(
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            if let Some(wells) = cache_result {
 | 
					            if let Some(wells) = cache_result {
 | 
				
			||||||
                for well in wells.iter().filter(|x| x.row <= rows && x.col <= columns) {
 | 
					                for well in wells.iter().filter(|x| x.row <= rows && x.col <= columns) {
 | 
				
			||||||
                if let Some(Some(mut x)) = well_infos
 | 
					                    if let Some(Some(mut x)) = well_infos.get_mut(
 | 
				
			||||||
                    .get_mut((well.row - 1) as usize * columns as usize + (well.col - 1) as usize)
 | 
					                        (well.row - 1) as usize * columns as usize + (well.col - 1) as usize,
 | 
				
			||||||
                {
 | 
					                    ) {
 | 
				
			||||||
                        x.volume += 5.0;
 | 
					                        x.volume += 5.0;
 | 
				
			||||||
                        x.color = PALETTE.get_ordered(transfer.id, ordered_ids);
 | 
					                        x.color = PALETTE.get_ordered(transfer.id, ordered_ids);
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
| 
						 | 
					@ -173,6 +197,20 @@ fn f64_to_color32(x: [f64; 3]) -> Color32 {
 | 
				
			||||||
    Color32::from_rgb(r, g, b)
 | 
					    Color32::from_rgb(r, g, b)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn draw_cross(painter: &egui::Painter, center: egui::Pos2, radius: f32, stroke: egui::Stroke) {
 | 
				
			||||||
 | 
					    // Generate points on circle
 | 
				
			||||||
 | 
					    const OFFSET_ARRAY_X: [f32; 4] = [0.71, -0.71, -0.71, 0.71]; // == sin(2pi/8) == cos(2pi/8)
 | 
				
			||||||
 | 
					    const OFFSET_ARRAY_Y: [f32; 4] = [0.71, 0.71, -0.71, -0.71];
 | 
				
			||||||
 | 
					    let radius_adjusted_array_x: [f32; 4] = core::array::from_fn(|x| OFFSET_ARRAY_X[x] * radius);
 | 
				
			||||||
 | 
					    let radius_adjusted_array_y: [f32; 4] = core::array::from_fn(|y| OFFSET_ARRAY_Y[y] * radius);
 | 
				
			||||||
 | 
					    let xs: [f32; 4] = core::array::from_fn(|x| radius_adjusted_array_x[x] + center.x);
 | 
				
			||||||
 | 
					    let ys: [f32; 4] = core::array::from_fn(|y| radius_adjusted_array_y[y] + center.y);
 | 
				
			||||||
 | 
					    let pts: [egui::Pos2; 4] = core::array::from_fn(|i| egui::Pos2::new(xs[i], ys[i]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    painter.line_segment([pts[0], pts[2]], stroke);
 | 
				
			||||||
 | 
					    painter.line_segment([pts[1], pts[3]], stroke);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn add_plate_sub(
 | 
					fn add_plate_sub(
 | 
				
			||||||
    size: egui::Vec2,
 | 
					    size: egui::Vec2,
 | 
				
			||||||
    rows: u8,
 | 
					    rows: u8,
 | 
				
			||||||
| 
						 | 
					@ -184,6 +222,7 @@ fn add_plate_sub(
 | 
				
			||||||
    current_transfer_state: Option<&CurrentTransferState>,
 | 
					    current_transfer_state: Option<&CurrentTransferState>,
 | 
				
			||||||
    ui: &mut egui::Ui,
 | 
					    ui: &mut egui::Ui,
 | 
				
			||||||
    state: &mut PlateUiState,
 | 
					    state: &mut PlateUiState,
 | 
				
			||||||
 | 
					    display_options: PlateDisplayOptions,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    let (response, painter) = ui.allocate_painter(size, egui::Sense::click_and_drag());
 | 
					    let (response, painter) = ui.allocate_painter(size, egui::Sense::click_and_drag());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -288,10 +327,14 @@ fn add_plate_sub(
 | 
				
			||||||
                            .and_then(|x| x.lock().ok())
 | 
					                            .and_then(|x| x.lock().ok())
 | 
				
			||||||
                            .map(|x| x.volume)
 | 
					                            .map(|x| x.volume)
 | 
				
			||||||
                            .unwrap_or(0.0);
 | 
					                            .unwrap_or(0.0);
 | 
				
			||||||
 | 
					                    let color = well_info.map(|x| x.color).unwrap_or([255.0, 255.0, 255.0]);
 | 
				
			||||||
 | 
					                    let fill = well_info.map(|x| x.color).is_some();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    *well_info = Some(WellInfo {
 | 
					                    *well_info = Some(WellInfo {
 | 
				
			||||||
                        color: [255.0, 255.0, 255.0],
 | 
					                        color,
 | 
				
			||||||
                        volume: 1.0,
 | 
					                        volume: 1.0,
 | 
				
			||||||
 | 
					                        fill,
 | 
				
			||||||
 | 
					                        highlight: true,
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -327,8 +370,13 @@ fn add_plate_sub(
 | 
				
			||||||
            if let Some(well_info) =
 | 
					            if let Some(well_info) =
 | 
				
			||||||
                well_infos[(c_row - 1) as usize * columns as usize + (c_column - 1) as usize]
 | 
					                well_infos[(c_row - 1) as usize * columns as usize + (c_column - 1) as usize]
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                if well_info.fill {
 | 
				
			||||||
                    painter.circle_filled(center, radius * 0.80, f64_to_color32(well_info.color));
 | 
					                    painter.circle_filled(center, radius * 0.80, f64_to_color32(well_info.color));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                if well_info.highlight && display_options.show_transfer_hashes {
 | 
				
			||||||
 | 
					                    draw_cross(&painter, center, radius * 0.80, *STROKE_CURRENT);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //
 | 
					            //
 | 
				
			||||||
            // Draw stroke on top
 | 
					            // Draw stroke on top
 | 
				
			||||||
| 
						 | 
					@ -366,7 +414,19 @@ fn add_plate_sub(
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Draw row/column labels
 | 
					    // Draw row/column labels
 | 
				
			||||||
 | 
					    let default_font = egui::FontId::monospace(f32::min(radius, 14.0));
 | 
				
			||||||
 | 
					    static DEFAULT_TEXT_COLOR: LazyLock<egui::Color32> =
 | 
				
			||||||
 | 
					        LazyLock::new(|| egui::Color32::from_gray(128));
 | 
				
			||||||
 | 
					    static HIGHLIGHT_TEXT_COLOR: LazyLock<egui::Color32> =
 | 
				
			||||||
 | 
					        LazyLock::new(|| egui::Color32::from_gray(255));
 | 
				
			||||||
    for c_row in 0..rows {
 | 
					    for c_row in 0..rows {
 | 
				
			||||||
 | 
					        let text_color = {
 | 
				
			||||||
 | 
					            if display_options.show_coordinates && hovered_well.is_some_and(|x| x.0 == c_row + 1) {
 | 
				
			||||||
 | 
					                *HIGHLIGHT_TEXT_COLOR
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                *DEFAULT_TEXT_COLOR
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
        painter.text(
 | 
					        painter.text(
 | 
				
			||||||
            egui::pos2(
 | 
					            egui::pos2(
 | 
				
			||||||
                start_x - 10.0,
 | 
					                start_x - 10.0,
 | 
				
			||||||
| 
						 | 
					@ -374,11 +434,18 @@ fn add_plate_sub(
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            egui::Align2::CENTER_CENTER,
 | 
					            egui::Align2::CENTER_CENTER,
 | 
				
			||||||
            (c_row + 1).to_string(),
 | 
					            (c_row + 1).to_string(),
 | 
				
			||||||
            egui::FontId::monospace(f32::min(radius, 14.0)),
 | 
					            default_font.clone(),
 | 
				
			||||||
            egui::Color32::from_gray(128),
 | 
					            text_color,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    for c_column in 0..columns {
 | 
					    for c_column in 0..columns {
 | 
				
			||||||
 | 
					        let text_color = {
 | 
				
			||||||
 | 
					            if display_options.show_coordinates && hovered_well.is_some_and(|x| x.1 == c_column + 1) {
 | 
				
			||||||
 | 
					                *HIGHLIGHT_TEXT_COLOR
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                *DEFAULT_TEXT_COLOR
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
        painter.text(
 | 
					        painter.text(
 | 
				
			||||||
            egui::pos2(
 | 
					            egui::pos2(
 | 
				
			||||||
                start_x + radius + 2.0 * radius * c_column as f32,
 | 
					                start_x + radius + 2.0 * radius * c_column as f32,
 | 
				
			||||||
| 
						 | 
					@ -386,8 +453,8 @@ fn add_plate_sub(
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            egui::Align2::CENTER_CENTER,
 | 
					            egui::Align2::CENTER_CENTER,
 | 
				
			||||||
            plate_tool_lib::util::num_to_letters(c_column + 1).unwrap(),
 | 
					            plate_tool_lib::util::num_to_letters(c_column + 1).unwrap(),
 | 
				
			||||||
            egui::FontId::monospace(f32::min(radius, 14.0)),
 | 
					            default_font.clone(),
 | 
				
			||||||
            egui::Color32::from_gray(128),
 | 
					            text_color,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -402,6 +469,7 @@ pub fn add_plate(
 | 
				
			||||||
    current_transfer_state: Option<&CurrentTransferState>,
 | 
					    current_transfer_state: Option<&CurrentTransferState>,
 | 
				
			||||||
    ui: &mut egui::Ui,
 | 
					    ui: &mut egui::Ui,
 | 
				
			||||||
    state: &mut PlateUiState,
 | 
					    state: &mut PlateUiState,
 | 
				
			||||||
 | 
					    display_options: PlateDisplayOptions,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    add_plate_sub(
 | 
					    add_plate_sub(
 | 
				
			||||||
        size,
 | 
					        size,
 | 
				
			||||||
| 
						 | 
					@ -414,5 +482,6 @@ pub fn add_plate(
 | 
				
			||||||
        current_transfer_state,
 | 
					        current_transfer_state,
 | 
				
			||||||
        ui,
 | 
					        ui,
 | 
				
			||||||
        state,
 | 
					        state,
 | 
				
			||||||
 | 
					        display_options,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue