copying now uses it's own thread to avoid freezing the ui for larger images

This commit is contained in:
grimsace
2026-04-21 14:49:45 -05:00
parent 817a9f4e4f
commit 21c580a3c0
+59 -13
View File
@@ -37,6 +37,8 @@ pub struct TerrainApp {
generated: Option<GeneratedImages>, generated: Option<GeneratedImages>,
generation_receiver: Option<Receiver<Result<GeneratedImages, String>>>, generation_receiver: Option<Receiver<Result<GeneratedImages, String>>>,
generation_in_progress: bool, generation_in_progress: bool,
copy_receiver: Option<Receiver<Result<String, String>>>,
copy_in_progress: bool,
status_message: String, status_message: String,
} }
@@ -51,6 +53,8 @@ impl TerrainApp {
generated: None, generated: None,
generation_receiver: None, generation_receiver: None,
generation_in_progress: false, generation_in_progress: false,
copy_receiver: None,
copy_in_progress: false,
status_message: String::from("Adjust parameters and click Generate."), status_message: String::from("Adjust parameters and click Generate."),
} }
} }
@@ -108,6 +112,33 @@ impl TerrainApp {
} }
} }
fn poll_copy(&mut self, ctx: &Context) {
let Some(receiver) = &self.copy_receiver else {
return;
};
match receiver.try_recv() {
Ok(Ok(message)) => {
self.status_message = message;
self.copy_receiver = None;
self.copy_in_progress = false;
}
Ok(Err(error)) => {
self.status_message = error;
self.copy_receiver = None;
self.copy_in_progress = false;
}
Err(TryRecvError::Empty) => {
ctx.request_repaint();
}
Err(TryRecvError::Disconnected) => {
self.status_message = String::from("Copy worker disconnected.");
self.copy_receiver = None;
self.copy_in_progress = false;
}
}
}
fn install_textures(&mut self, ctx: &Context, images: &GeneratedImages) { fn install_textures(&mut self, ctx: &Context, images: &GeneratedImages) {
let heightmap = gray_to_color_image(&images.heightmap_image); let heightmap = gray_to_color_image(&images.heightmap_image);
let bumpmap = gray_to_color_image(&images.bumpmap_image); let bumpmap = gray_to_color_image(&images.bumpmap_image);
@@ -119,27 +150,37 @@ impl TerrainApp {
} }
fn copy_preview(&mut self, preview: PreviewFocus) { fn copy_preview(&mut self, preview: PreviewFocus) {
if self.copy_in_progress {
self.status_message = String::from("Copy already in progress...");
return;
}
let Some(generated) = &self.generated else { let Some(generated) = &self.generated else {
self.status_message = String::from("No generated image is available to copy."); self.status_message = String::from("No generated image is available to copy.");
return; return;
}; };
let image = match preview { let image = match preview {
PreviewFocus::Heightmap => &generated.heightmap_image, PreviewFocus::Heightmap => generated.heightmap_image.clone(),
PreviewFocus::Bumpmap => &generated.bumpmap_image, PreviewFocus::Bumpmap => generated.bumpmap_image.clone(),
};
let success_message = match preview {
PreviewFocus::Heightmap => String::from("Heightmap copied to clipboard."),
PreviewFocus::Bumpmap => String::from("Bumpmap copied to clipboard."),
}; };
match copy_gray_image_to_clipboard(image) { let (tx, rx) = mpsc::channel();
Ok(()) => { self.copy_receiver = Some(rx);
self.status_message = match preview { self.copy_in_progress = true;
PreviewFocus::Heightmap => String::from("Heightmap copied to clipboard."), self.status_message = match preview {
PreviewFocus::Bumpmap => String::from("Bumpmap copied to clipboard."), PreviewFocus::Heightmap => String::from("Copying heightmap to clipboard..."),
}; PreviewFocus::Bumpmap => String::from("Copying bumpmap to clipboard..."),
} };
Err(error) => {
self.status_message = format!("Failed to copy image: {error}"); thread::spawn(move || {
} let result = copy_gray_image_to_clipboard(&image).map(|_| success_message);
} let _ = tx.send(result);
});
} }
fn preview_context_menu(response: &Response) -> bool { fn preview_context_menu(response: &Response) -> bool {
@@ -236,6 +277,10 @@ impl TerrainApp {
ui.add_space(8.0); ui.add_space(8.0);
ui.spinner(); ui.spinner();
} }
if self.copy_in_progress {
ui.add_space(4.0);
ui.spinner();
}
ui.add_space(8.0); ui.add_space(8.0);
ui.label(&self.status_message); ui.label(&self.status_message);
@@ -392,6 +437,7 @@ impl eframe::App for TerrainApp {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
self.hovered_preview = None; self.hovered_preview = None;
self.poll_generation(ctx); self.poll_generation(ctx);
self.poll_copy(ctx);
self.ui_left_panel(ctx); self.ui_left_panel(ctx);
self.ui_right_panel(ctx); self.ui_right_panel(ctx);