export now uses separate thread to avoid application locking up
This commit is contained in:
+23
-7
@@ -19,6 +19,11 @@ const LOCKED_DOOR: (u8, u8, u8, u8) = (80, 200, 120, 255);
|
||||
const ARCHWAY: (u8, u8, u8, u8) = (70, 130, 220, 255);
|
||||
const WHITE: (u8, u8, u8, u8) = (255, 255, 255, 255);
|
||||
|
||||
pub enum ExportTarget {
|
||||
File(PathBuf),
|
||||
Folder(PathBuf),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum DoorStyle {
|
||||
Solid,
|
||||
@@ -111,17 +116,13 @@ fn collect_scene_data(layout: &DungeonLayout, settings: &UiSettings) -> SceneDat
|
||||
scene
|
||||
}
|
||||
|
||||
pub fn export_with_dialog(
|
||||
layout: &DungeonLayout,
|
||||
settings: &UiSettings,
|
||||
) -> Result<PathBuf, String> {
|
||||
pub fn select_export_target(settings: &UiSettings) -> Result<ExportTarget, String> {
|
||||
if settings.export_format == ExportFormat::Folder {
|
||||
let folder = FileDialog::new()
|
||||
.set_title("Export composite masks folder")
|
||||
.pick_folder()
|
||||
.ok_or_else(|| "Export canceled".to_string())?;
|
||||
export_composite_masks(layout, settings, &folder)?;
|
||||
return Ok(folder);
|
||||
return Ok(ExportTarget::Folder(folder));
|
||||
}
|
||||
|
||||
let ext = settings.export_format.extension();
|
||||
@@ -141,6 +142,20 @@ pub fn export_with_dialog(
|
||||
path.set_extension(ext);
|
||||
}
|
||||
|
||||
Ok(ExportTarget::File(path))
|
||||
}
|
||||
|
||||
pub fn export_to_target(
|
||||
layout: &DungeonLayout,
|
||||
settings: &UiSettings,
|
||||
target: ExportTarget,
|
||||
) -> Result<PathBuf, String> {
|
||||
match target {
|
||||
ExportTarget::Folder(folder) => {
|
||||
export_composite_masks(layout, settings, &folder)?;
|
||||
Ok(folder)
|
||||
}
|
||||
ExportTarget::File(path) => {
|
||||
match settings.export_format {
|
||||
ExportFormat::Svg => {
|
||||
let svg = build_svg(layout, settings);
|
||||
@@ -160,8 +175,9 @@ pub fn export_with_dialog(
|
||||
}
|
||||
ExportFormat::Folder => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap, String> {
|
||||
|
||||
+35
-3
@@ -5,6 +5,8 @@ mod settings;
|
||||
mod ui;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
use eframe::egui;
|
||||
use egui::{Color32, Stroke};
|
||||
@@ -25,6 +27,7 @@ struct DungeonApp {
|
||||
settings: UiSettings,
|
||||
layout: DungeonLayout,
|
||||
drag_state: Option<DragState>,
|
||||
export_rx: Option<mpsc::Receiver<Result<std::path::PathBuf, String>>>,
|
||||
}
|
||||
|
||||
impl Default for DungeonApp {
|
||||
@@ -48,6 +51,7 @@ impl Default for DungeonApp {
|
||||
settings,
|
||||
layout,
|
||||
drag_state: None,
|
||||
export_rx: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +66,7 @@ impl Drop for DungeonApp {
|
||||
|
||||
impl eframe::App for DungeonApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
let panel_result = draw_side_panel(ctx, &mut self.settings);
|
||||
let panel_result = draw_side_panel(ctx, &mut self.settings, self.export_rx.is_some());
|
||||
|
||||
if self.settings.min_room_size > self.settings.max_room_size {
|
||||
self.settings.max_room_size = self.settings.min_room_size;
|
||||
@@ -77,9 +81,37 @@ impl eframe::App for DungeonApp {
|
||||
if panel_result.reset_clicked || panel_result.settings_changed {
|
||||
self.regenerate_layout();
|
||||
}
|
||||
if panel_result.export_clicked {
|
||||
if let Err(err) = exporter::export_with_dialog(&self.layout, &self.settings) {
|
||||
if panel_result.export_clicked && self.export_rx.is_none() {
|
||||
let target = match exporter::select_export_target(&self.settings) {
|
||||
Ok(target) => target,
|
||||
Err(err) => {
|
||||
eprintln!("{err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let layout = self.layout.clone();
|
||||
let settings = self.settings.clone();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
thread::spawn(move || {
|
||||
let result = exporter::export_to_target(&layout, &settings, target);
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
self.export_rx = Some(rx);
|
||||
}
|
||||
|
||||
if let Some(rx) = &self.export_rx {
|
||||
match rx.try_recv() {
|
||||
Ok(Ok(_)) => {
|
||||
self.export_rx = None;
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
eprintln!("{err}");
|
||||
self.export_rx = None;
|
||||
}
|
||||
Err(mpsc::TryRecvError::Empty) => {}
|
||||
Err(mpsc::TryRecvError::Disconnected) => {
|
||||
self.export_rx = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,11 @@ pub struct SidePanelResult {
|
||||
pub export_clicked: bool,
|
||||
}
|
||||
|
||||
pub fn draw_side_panel(ctx: &egui::Context, settings: &mut UiSettings) -> SidePanelResult {
|
||||
pub fn draw_side_panel(
|
||||
ctx: &egui::Context,
|
||||
settings: &mut UiSettings,
|
||||
export_in_progress: bool,
|
||||
) -> SidePanelResult {
|
||||
let mut result = SidePanelResult::default();
|
||||
|
||||
egui::SidePanel::left("options_panel")
|
||||
@@ -175,7 +179,7 @@ pub fn draw_side_panel(ctx: &egui::Context, settings: &mut UiSettings) -> SidePa
|
||||
ui.separator();
|
||||
|
||||
match settings.active_tab {
|
||||
Tab::Generate => draw_generate_tab(ui, settings, &mut result),
|
||||
Tab::Generate => draw_generate_tab(ui, settings, &mut result, export_in_progress),
|
||||
Tab::Layout => draw_layout_tab(ui, settings, &mut result),
|
||||
}
|
||||
});
|
||||
@@ -183,7 +187,12 @@ pub fn draw_side_panel(ctx: &egui::Context, settings: &mut UiSettings) -> SidePa
|
||||
result
|
||||
}
|
||||
|
||||
fn draw_generate_tab(ui: &mut egui::Ui, settings: &mut UiSettings, result: &mut SidePanelResult) {
|
||||
fn draw_generate_tab(
|
||||
ui: &mut egui::Ui,
|
||||
settings: &mut UiSettings,
|
||||
result: &mut SidePanelResult,
|
||||
export_in_progress: bool,
|
||||
) {
|
||||
ui.label(RichText::new("Grid Settings").strong());
|
||||
ui.add_space(8.0);
|
||||
|
||||
@@ -339,6 +348,11 @@ fn draw_generate_tab(ui: &mut egui::Ui, settings: &mut UiSettings, result: &mut
|
||||
if ui.button("Export Image").clicked() {
|
||||
result.export_clicked = true;
|
||||
}
|
||||
|
||||
if export_in_progress {
|
||||
ui.add_space(6.0);
|
||||
ui.add(egui::ProgressBar::new(0.0).animate(true));
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_layout_tab(ui: &mut egui::Ui, settings: &mut UiSettings, result: &mut SidePanelResult) {
|
||||
|
||||
Reference in New Issue
Block a user