Compare commits

...
3 Commits
11 changed files with 164 additions and 51 deletions
+3 -1
View File
@@ -1,12 +1,14 @@
[package] [package]
name = "desktop_dungeon_generator" name = "desktop_dungeon_generator"
version = "0.9.0" version = "0.10.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
eframe = "0.31" eframe = "0.31"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
quick-xml = { version = "0.37", features = ["serialize"] }
zip = { version = "2", default-features = false, features = ["deflate"] }
dirs = "6" dirs = "6"
rfd = "0.15" rfd = "0.15"
tiny-skia = "0.11" tiny-skia = "0.11"
+7 -7
View File
@@ -811,7 +811,7 @@ pub fn draw_add_overlay(app: &DungeonApp, painter: &egui::Painter, geometry: &Gr
let start = cell_center(geometry, drag.start_cell.0, drag.start_cell.1); let start = cell_center(geometry, drag.start_cell.0, drag.start_cell.1);
let end = cell_center(geometry, drag.current_cell.0, drag.current_cell.1); let end = cell_center(geometry, drag.current_cell.0, drag.current_cell.1);
let stroke = Stroke::new(2.0, Color32::WHITE); let stroke = Stroke::new(2.0_f32, Color32::WHITE);
painter.circle_filled(start, 3.0, Color32::WHITE); painter.circle_filled(start, 3.0, Color32::WHITE);
crate::rendering::draw_dashed_line(painter, start, end, stroke, 8.0, 6.0); crate::rendering::draw_dashed_line(painter, start, end, stroke, 8.0, 6.0);
} }
@@ -854,7 +854,7 @@ pub fn draw_add_tool_ghost(app: &DungeonApp, painter: &egui::Painter, geometry:
rect, rect,
4.0, 4.0,
Stroke::new( Stroke::new(
1.5, 1.5_f32,
Color32::from_rgb(150, 200, 240).gamma_multiply(ghost_alpha + 0.3), Color32::from_rgb(150, 200, 240).gamma_multiply(ghost_alpha + 0.3),
), ),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
@@ -881,7 +881,7 @@ pub fn draw_add_tool_ghost(app: &DungeonApp, painter: &egui::Painter, geometry:
rect.expand(4.0), rect.expand(4.0),
4.0, 4.0,
Stroke::new( Stroke::new(
1.0, 1.0_f32,
Color32::from_rgb(180, 180, 220).gamma_multiply(ghost_alpha + 0.2), Color32::from_rgb(180, 180, 220).gamma_multiply(ghost_alpha + 0.2),
), ),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
@@ -919,7 +919,7 @@ pub fn draw_add_tool_ghost(app: &DungeonApp, painter: &egui::Painter, geometry:
rect, rect,
4.0, 4.0,
Stroke::new( Stroke::new(
1.5, 1.5_f32,
Color32::from_rgb(255, 255, 255).gamma_multiply(ghost_alpha + 0.2), Color32::from_rgb(255, 255, 255).gamma_multiply(ghost_alpha + 0.2),
), ),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
@@ -962,7 +962,7 @@ pub fn draw_add_tool_ghost(app: &DungeonApp, painter: &egui::Painter, geometry:
rect, rect,
4.0, 4.0,
Stroke::new( Stroke::new(
1.5, 1.5_f32,
Color32::from_rgb(220, 180, 80).gamma_multiply(ghost_alpha + 0.2), Color32::from_rgb(220, 180, 80).gamma_multiply(ghost_alpha + 0.2),
), ),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
@@ -978,7 +978,7 @@ pub fn draw_add_tool_ghost(app: &DungeonApp, painter: &egui::Painter, geometry:
egui::pos2(rect.left() + 2.0, y), egui::pos2(rect.left() + 2.0, y),
egui::pos2(rect.right() - 2.0, y), egui::pos2(rect.right() - 2.0, y),
], ],
Stroke::new(1.5, line_color), Stroke::new(1.5_f32, line_color),
); );
} }
} }
@@ -1082,7 +1082,7 @@ pub fn draw_paste_ghost(app: &DungeonApp, painter: &egui::Painter, geometry: &Gr
let ghost_alpha = 0.35; let ghost_alpha = 0.35;
let fill = Color32::from_rgb(100, 160, 100).gamma_multiply(ghost_alpha); let fill = Color32::from_rgb(100, 160, 100).gamma_multiply(ghost_alpha);
let stroke = Stroke::new( let stroke = Stroke::new(
1.5, 1.5_f32,
Color32::from_rgb(180, 240, 180).gamma_multiply(ghost_alpha + 0.3), Color32::from_rgb(180, 240, 180).gamma_multiply(ghost_alpha + 0.3),
); );
+2 -2
View File
@@ -474,7 +474,7 @@ pub fn draw_corridor_hover_overlay(
}; };
let color = Color32::from_gray(170); let color = Color32::from_gray(170);
let stroke = Stroke::new(2.0, color); let stroke = Stroke::new(2.0_f32, color);
for pair in corridor.path.windows(2) { for pair in corridor.path.windows(2) {
let a = cell_center(geometry, pair[0].0, pair[0].1); let a = cell_center(geometry, pair[0].0, pair[0].1);
let b = cell_center(geometry, pair[1].0, pair[1].1); let b = cell_center(geometry, pair[1].0, pair[1].1);
@@ -496,7 +496,7 @@ pub fn draw_door_hover_overlay(app: &DungeonApp, painter: &egui::Painter, geomet
return; return;
}; };
let color = Color32::from_gray(200); let color = Color32::from_gray(200);
let stroke = Stroke::new(2.0, color); let stroke = Stroke::new(2.0_f32, color);
crate::rendering::draw_door_line( crate::rendering::draw_door_line(
painter, painter,
geometry, geometry,
+1 -1
View File
@@ -36,7 +36,7 @@ pub fn draw_grid(
egui::vec2(grid_width, grid_height), egui::vec2(grid_width, grid_height),
); );
let stroke = Stroke::new(1.0, Color32::from_gray(160)); let stroke = Stroke::new(1.0_f32, Color32::from_gray(160));
painter.rect_stroke(grid_rect, 0.0, stroke, egui::StrokeKind::Middle); painter.rect_stroke(grid_rect, 0.0, stroke, egui::StrokeKind::Middle);
for col in 1..cols { for col in 1..cols {
+2 -2
View File
@@ -617,7 +617,7 @@ pub fn draw_selection_box(app: &DungeonApp, painter: &egui::Painter, geometry: &
painter.rect_stroke( painter.rect_stroke(
rect, rect,
0.0, 0.0,
Stroke::new(1.5, Color32::from_rgba_unmultiplied(100, 160, 255, 200)), Stroke::new(1.5_f32, Color32::from_rgba_unmultiplied(100, 160, 255, 200)),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
); );
} }
@@ -636,7 +636,7 @@ pub fn draw_selection_highlights(
} }
let layout = &app.levels[app.settings.active_level_index]; let layout = &app.levels[app.settings.active_level_index];
let color = Color32::from_rgba_unmultiplied(100, 180, 255, 220); let color = Color32::from_rgba_unmultiplied(100, 180, 255, 220);
let stroke = Stroke::new(2.0, color); let stroke = Stroke::new(2.0_f32, color);
for item in &app.selection { for item in &app.selection {
match item { match item {
+6 -6
View File
@@ -369,7 +369,7 @@ pub fn draw_resize_overlay(app: &DungeonApp, painter: &egui::Painter, geometry:
painter.rect_stroke( painter.rect_stroke(
rect, rect,
0.0, 0.0,
Stroke::new(2.0, Color32::from_gray(180)), Stroke::new(2.0_f32, Color32::from_gray(180)),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
); );
let pos = crate::interact::cell_center( let pos = crate::interact::cell_center(
@@ -423,7 +423,7 @@ pub fn draw_resize_overlay(app: &DungeonApp, painter: &egui::Painter, geometry:
painter.rect_stroke( painter.rect_stroke(
rect, rect,
0.0, 0.0,
Stroke::new(2.0, Color32::from_gray(180)), Stroke::new(2.0_f32, Color32::from_gray(180)),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
); );
} }
@@ -446,7 +446,7 @@ pub fn draw_room_resize_visuals(
show_handles: bool, show_handles: bool,
) { ) {
let color = Color32::from_gray(170); let color = Color32::from_gray(170);
let stroke = Stroke::new(1.5, color); let stroke = Stroke::new(1.5_f32, color);
let left = geometry.rect.left() + room.x as f32 * geometry.cell_size; let left = geometry.rect.left() + room.x as f32 * geometry.cell_size;
let top = geometry.rect.top() + room.y as f32 * geometry.cell_size; let top = geometry.rect.top() + room.y as f32 * geometry.cell_size;
@@ -491,7 +491,7 @@ pub fn draw_staircase_resize_visuals(
show_handles: bool, show_handles: bool,
) { ) {
let color = Color32::from_gray(170); let color = Color32::from_gray(170);
let stroke = Stroke::new(1.5, color); let stroke = Stroke::new(1.5_f32, color);
let left = geometry.rect.left() + stair.cell.0 as f32 * geometry.cell_size; let left = geometry.rect.left() + stair.cell.0 as f32 * geometry.cell_size;
let top = geometry.rect.top() + stair.cell.1 as f32 * geometry.cell_size; let top = geometry.rect.top() + stair.cell.1 as f32 * geometry.cell_size;
@@ -527,10 +527,10 @@ pub fn draw_resize_handle(
let half = size * 0.5; let half = size * 0.5;
let rect = egui::Rect::from_center_size(corner, egui::vec2(size, size)); let rect = egui::Rect::from_center_size(corner, egui::vec2(size, size));
painter.rect_filled(rect, 2.0, Color32::from_gray(30)); painter.rect_filled(rect, 2.0, Color32::from_gray(30));
painter.rect_stroke(rect, 2.0, Stroke::new(1.0, color), egui::StrokeKind::Middle); painter.rect_stroke(rect, 2.0, Stroke::new(1.0_f32, color), egui::StrokeKind::Middle);
let center = corner; let center = corner;
let stroke = Stroke::new(1.0, color); let stroke = Stroke::new(1.0_f32, color);
match which { match which {
ResizeCorner::TopLeft => { ResizeCorner::TopLeft => {
painter.line_segment( painter.line_segment(
+1
View File
@@ -212,6 +212,7 @@ pub struct WindowSettings {
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct DungeonLayout { pub struct DungeonLayout {
pub name: String, pub name: String,
pub rooms: Vec<Room>, pub rooms: Vec<Room>,
+5 -5
View File
@@ -134,7 +134,7 @@ pub fn draw_layout(
painter, painter,
geometry, geometry,
room, room,
Stroke::new(1.5, Color32::BLACK.gamma_multiply(alpha)), Stroke::new(1.5_f32, Color32::BLACK.gamma_multiply(alpha)),
); );
} }
} }
@@ -277,7 +277,7 @@ pub fn draw_layout(
painter.rect_stroke( painter.rect_stroke(
text_label_rect(geometry, label).expand(2.0), text_label_rect(geometry, label).expand(2.0),
0.0, 0.0,
Stroke::new(2.0, Color32::from_rgb(255, 220, 120).gamma_multiply(alpha)), Stroke::new(2.0_f32, Color32::from_rgb(255, 220, 120).gamma_multiply(alpha)),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
); );
} }
@@ -388,7 +388,7 @@ pub fn draw_staircase(
rect, rect,
4.0, 4.0,
Stroke::new( Stroke::new(
if is_hovered { 3.0 } else { 2.0 }, if is_hovered { 3.0_f32 } else { 2.0_f32 },
stroke_color.gamma_multiply(alpha), stroke_color.gamma_multiply(alpha),
), ),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
@@ -408,7 +408,7 @@ pub fn draw_staircase(
egui::pos2(rect.left() + 2.0, y), egui::pos2(rect.left() + 2.0, y),
egui::pos2(rect.right() - 2.0, y), egui::pos2(rect.right() - 2.0, y),
], ],
Stroke::new(1.5, line_color.gamma_multiply(alpha)), Stroke::new(1.5_f32, line_color.gamma_multiply(alpha)),
); );
} }
} }
@@ -455,7 +455,7 @@ pub fn draw_area_marker(
rect, rect,
4.0, 4.0,
Stroke::new( Stroke::new(
if hovered { 3.0 } else { 2.0 }, if hovered { 3.0_f32 } else { 2.0_f32 },
stroke_color.gamma_multiply(alpha), stroke_color.gamma_multiply(alpha),
), ),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
+123 -15
View File
@@ -1,13 +1,16 @@
/* /*
* Persistence logic for dungeon state. * Persistence logic for dungeon state.
* Handles saving and loading the complete dungeon state * Handles saving and loading the complete dungeon state
* (settings and layout data) to and from disk using JSON. * (settings, layout data, and SVGs) to and from compressed XML archives.
*/ */
use rfd::FileDialog; use rfd::FileDialog;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fs; use std::fs;
use std::io::{Cursor, Read, Write};
use std::path::PathBuf; use std::path::PathBuf;
use zip::write::SimpleFileOptions;
use zip::{CompressionMethod, ZipArchive, ZipWriter};
use crate::layout::DungeonLayout; use crate::layout::DungeonLayout;
use crate::ui::UiSettings; use crate::ui::UiSettings;
@@ -19,7 +22,66 @@ pub struct DungeonSave {
pub svgs: Vec<String>, pub svgs: Vec<String>,
} }
// Saves dungeon state to a user-selected JSON file. const XML_ENTRY_NAME: &str = "dungeon.xml";
#[derive(Serialize, Deserialize)]
struct DungeonXml {
#[serde(rename = "$text")]
payload: String,
}
fn serialize_dungeon(save_data: &DungeonSave) -> Result<Vec<u8>, String> {
let payload = serde_json::to_string(save_data)
.map_err(|e| format!("Failed to serialize dungeon: {e}"))?;
quick_xml::se::to_string(&DungeonXml { payload })
.map(|xml| {
let mut document = String::from("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
document.push_str(&xml);
document.into_bytes()
})
.map_err(|e| format!("Failed to serialize dungeon: {e}"))
}
fn deserialize_dungeon(xml: &[u8]) -> Result<DungeonSave, String> {
let document: DungeonXml = quick_xml::de::from_reader(Cursor::new(xml))
.map_err(|e| format!("Failed to parse dungeon XML: {e}"))?;
serde_json::from_str(&document.payload)
.map_err(|e| format!("Failed to parse dungeon XML payload: {e}"))
}
fn create_archive(save_data: &DungeonSave) -> Result<Vec<u8>, String> {
let xml = serialize_dungeon(save_data)?;
let mut archive = Cursor::new(Vec::new());
{
let mut writer = ZipWriter::new(&mut archive);
let options = SimpleFileOptions::default().compression_method(CompressionMethod::Deflated);
writer
.start_file(XML_ENTRY_NAME, options)
.map_err(|e| format!("Failed to create dungeon archive: {e}"))?;
writer
.write_all(&xml)
.map_err(|e| format!("Failed to write dungeon XML: {e}"))?;
writer
.finish()
.map_err(|e| format!("Failed to finish dungeon archive: {e}"))?;
}
Ok(archive.into_inner())
}
fn read_archive(bytes: &[u8]) -> Result<DungeonSave, String> {
let mut archive =
ZipArchive::new(Cursor::new(bytes)).map_err(|e| format!("Invalid dungeon archive: {e}"))?;
let mut xml_file = archive
.by_name(XML_ENTRY_NAME)
.map_err(|e| format!("Dungeon archive is missing {XML_ENTRY_NAME}: {e}"))?;
let mut xml = Vec::new();
xml_file
.read_to_end(&mut xml)
.map_err(|e| format!("Failed to read dungeon XML: {e}"))?;
deserialize_dungeon(&xml)
}
// Saves dungeon state to a compressed XML archive.
pub fn save_dungeon( pub fn save_dungeon(
settings: &UiSettings, settings: &UiSettings,
layouts: Vec<DungeonLayout>, layouts: Vec<DungeonLayout>,
@@ -27,8 +89,8 @@ pub fn save_dungeon(
) -> Result<PathBuf, String> { ) -> Result<PathBuf, String> {
let dialog = FileDialog::new() let dialog = FileDialog::new()
.set_title("Save Dungeon State") .set_title("Save Dungeon State")
.add_filter("Dungeon File", &["dungeon"]) .add_filter("Dungeon File", &["dun"])
.set_file_name("my_dungeon.dungeon"); .set_file_name("my_dungeon.dun");
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let path = std::thread::spawn(move || dialog.save_file()) let path = std::thread::spawn(move || dialog.save_file())
@@ -37,7 +99,10 @@ pub fn save_dungeon(
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let path = dialog.save_file(); let path = dialog.save_file();
let path = path.ok_or_else(|| "Save canceled".to_string())?; let mut path = path.ok_or_else(|| "Save canceled".to_string())?;
if path.extension().is_none() {
path.set_extension("dun");
}
let save_data = DungeonSave { let save_data = DungeonSave {
settings: settings.clone(), settings: settings.clone(),
@@ -45,19 +110,17 @@ pub fn save_dungeon(
svgs, svgs,
}; };
let json = serde_json::to_string_pretty(&save_data) let archive = create_archive(&save_data)?;
.map_err(|e| format!("Failed to serialize dungeon: {e}"))?; fs::write(&path, archive).map_err(|e| format!("Failed to write file: {e}"))?;
fs::write(&path, json).map_err(|e| format!("Failed to write file: {e}"))?;
Ok(path) Ok(path)
} }
// Loads dungeon state from a user-selected JSON file. // Loads dungeon state from a compressed XML archive.
pub fn load_dungeon() -> Result<DungeonSave, String> { pub fn load_dungeon() -> Result<DungeonSave, String> {
let dialog = FileDialog::new() let dialog = FileDialog::new()
.set_title("Load Dungeon State") .set_title("Load Dungeon State")
.add_filter("Dungeon File", &["dungeon"]); .add_filter("Dungeon File", &["dun"]);
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let path = std::thread::spawn(move || dialog.pick_file()) let path = std::thread::spawn(move || dialog.pick_file())
@@ -68,10 +131,55 @@ pub fn load_dungeon() -> Result<DungeonSave, String> {
let path = path.ok_or_else(|| "Load canceled".to_string())?; let path = path.ok_or_else(|| "Load canceled".to_string())?;
let content = fs::read_to_string(path).map_err(|e| format!("Failed to read file: {e}"))?; let content = fs::read(path).map_err(|e| format!("Failed to read file: {e}"))?;
read_archive(&content)
}
let save_data: DungeonSave = #[cfg(test)]
serde_json::from_str(&content).map_err(|e| format!("Failed to parse dungeon file: {e}"))?; mod tests {
use super::*;
Ok(save_data) #[test]
fn archive_round_trip_preserves_saved_data() {
let save = DungeonSave {
settings: UiSettings::default(),
layouts: vec![DungeonLayout {
name: "Level 1".to_string(),
rooms: vec![crate::layout::types::Room {
x: 2,
y: 3,
width: 5,
height: 4,
}],
text_labels: vec![crate::layout::types::TextLabel {
cell: (4, 5),
text: "Keep & escape".to_string(),
font_size: 18,
}],
..DungeonLayout::default()
}],
svgs: vec!["<svg><text>test &amp;</text></svg>".to_string()],
};
let archive = create_archive(&save).expect("archive should serialize");
let restored = read_archive(&archive).expect("archive should deserialize");
assert_eq!(restored.settings, save.settings);
assert_eq!(restored.layouts, save.layouts);
assert_eq!(restored.svgs, save.svgs);
}
#[test]
fn archive_uses_deflate_compression() {
let save = DungeonSave {
settings: UiSettings::default(),
layouts: Vec::new(),
svgs: vec!["<svg>".repeat(100)],
};
let archive = create_archive(&save).expect("archive should serialize");
let mut zip = ZipArchive::new(Cursor::new(archive)).expect("archive should be valid");
let entry = zip.by_name(XML_ENTRY_NAME).expect("XML entry should exist");
assert_eq!(entry.compression(), CompressionMethod::Deflated);
}
} }
+2
View File
@@ -135,6 +135,7 @@ pub struct UiSettings {
pub export_height: u32, pub export_height: u32,
pub allow_export_aspect_change: bool, pub allow_export_aspect_change: bool,
pub export_show_grid: bool, pub export_show_grid: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_export_path: Option<String>, pub last_export_path: Option<String>,
pub add_tool: AddTool, pub add_tool: AddTool,
pub add_text_value: String, pub add_text_value: String,
@@ -156,6 +157,7 @@ pub struct UiSettings {
pub min_levels: usize, pub min_levels: usize,
pub max_levels: usize, pub max_levels: usize,
pub active_level_index: usize, pub active_level_index: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub overlay_level_index: Option<usize>, pub overlay_level_index: Option<usize>,
pub export_level_index: usize, pub export_level_index: usize,
pub trap_frequency_percent: usize, pub trap_frequency_percent: usize,
+12 -12
View File
@@ -18,7 +18,7 @@ pub fn draw_legend_entry(ui: &mut egui::Ui, color: Color32, label: &str) {
ui.painter().rect_stroke( ui.painter().rect_stroke(
rect, rect,
0.0, 0.0,
Stroke::new(1.0, Color32::WHITE), Stroke::new(1.0_f32, Color32::WHITE),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
); );
ui.add_space(6.0); ui.add_space(6.0);
@@ -49,7 +49,7 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
ui.painter().rect_stroke( ui.painter().rect_stroke(
rect, rect,
0.0, 0.0,
Stroke::new(1.0, Color32::BLACK), Stroke::new(1.0_f32, Color32::BLACK),
egui::StrokeKind::Middle, egui::StrokeKind::Middle,
); );
@@ -57,11 +57,11 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
LegendStyle::Crosshatch => { LegendStyle::Crosshatch => {
ui.painter().line_segment( ui.painter().line_segment(
[rect.left_top(), rect.right_bottom()], [rect.left_top(), rect.right_bottom()],
Stroke::new(1.2, Color32::BLACK), Stroke::new(1.2_f32, Color32::BLACK),
); );
ui.painter().line_segment( ui.painter().line_segment(
[rect.right_top(), rect.left_bottom()], [rect.right_top(), rect.left_bottom()],
Stroke::new(1.2, Color32::BLACK), Stroke::new(1.2_f32, Color32::BLACK),
); );
} }
LegendStyle::Dots => { LegendStyle::Dots => {
@@ -84,14 +84,14 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
egui::pos2(rect.left() + 1.0, rect.center().y), egui::pos2(rect.left() + 1.0, rect.center().y),
egui::pos2(rect.right() - 1.0, rect.center().y), egui::pos2(rect.right() - 1.0, rect.center().y),
], ],
Stroke::new(2.0, Color32::BLACK), Stroke::new(2.0_f32, Color32::BLACK),
); );
} }
LegendStyle::Label(prefix) => { LegendStyle::Label(prefix) => {
ui.painter() ui.painter()
.circle_filled(rect.center(), 6.0, Color32::from_gray(180)); .circle_filled(rect.center(), 6.0, Color32::from_gray(180));
ui.painter() ui.painter()
.circle_stroke(rect.center(), 6.0, Stroke::new(1.0, Color32::BLACK)); .circle_stroke(rect.center(), 6.0, Stroke::new(1.0_f32, Color32::BLACK));
let font_size = 10.0; let font_size = 10.0;
let font_id = egui::FontId::monospace(font_size); let font_id = egui::FontId::monospace(font_size);
let text_width = prefix.len() as f32 * font_size * 0.6; let text_width = prefix.len() as f32 * font_size * 0.6;
@@ -112,7 +112,7 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
ui.painter() ui.painter()
.circle_filled(rect.center(), 6.0, Color32::from_gray(180)); .circle_filled(rect.center(), 6.0, Color32::from_gray(180));
ui.painter() ui.painter()
.circle_stroke(rect.center(), 6.0, Stroke::new(1.0, Color32::BLACK)); .circle_stroke(rect.center(), 6.0, Stroke::new(1.0_f32, Color32::BLACK));
let font_size = 10.0; let font_size = 10.0;
let font_id = egui::FontId::monospace(font_size); let font_id = egui::FontId::monospace(font_size);
let text_width = font_size * 0.6; let text_width = font_size * 0.6;
@@ -133,7 +133,7 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
ui.painter(), ui.painter(),
egui::pos2(rect.left() + 1.0, rect.center().y), egui::pos2(rect.left() + 1.0, rect.center().y),
egui::pos2(rect.right() - 1.0, rect.center().y), egui::pos2(rect.right() - 1.0, rect.center().y),
Stroke::new(2.0, Color32::BLACK), Stroke::new(2.0_f32, Color32::BLACK),
6.0, 6.0,
3.0, 3.0,
), ),
@@ -141,7 +141,7 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
ui.painter(), ui.painter(),
egui::pos2(rect.left() + 1.0, rect.center().y), egui::pos2(rect.left() + 1.0, rect.center().y),
egui::pos2(rect.right() - 1.0, rect.center().y), egui::pos2(rect.right() - 1.0, rect.center().y),
Stroke::new(2.0, Color32::BLACK), Stroke::new(2.0_f32, Color32::BLACK),
3.0, 3.0,
2.0, 2.0,
), ),
@@ -149,19 +149,19 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
ui.painter(), ui.painter(),
egui::pos2(rect.left() + 1.0, rect.center().y), egui::pos2(rect.left() + 1.0, rect.center().y),
egui::pos2(rect.right() - 1.0, rect.center().y), egui::pos2(rect.right() - 1.0, rect.center().y),
Stroke::new(2.0, Color32::BLACK), Stroke::new(2.0_f32, Color32::BLACK),
), ),
LegendStyle::DashDotLine => draw_dash_dot_line( LegendStyle::DashDotLine => draw_dash_dot_line(
ui.painter(), ui.painter(),
egui::pos2(rect.left() + 1.0, rect.center().y), egui::pos2(rect.left() + 1.0, rect.center().y),
egui::pos2(rect.right() - 1.0, rect.center().y), egui::pos2(rect.right() - 1.0, rect.center().y),
Stroke::new(2.0, Color32::BLACK), Stroke::new(2.0_f32, Color32::BLACK),
), ),
LegendStyle::DashDotDotLine => draw_dash_dot_dot_line( LegendStyle::DashDotDotLine => draw_dash_dot_dot_line(
ui.painter(), ui.painter(),
egui::pos2(rect.left() + 1.0, rect.center().y), egui::pos2(rect.left() + 1.0, rect.center().y),
egui::pos2(rect.right() - 1.0, rect.center().y), egui::pos2(rect.right() - 1.0, rect.center().y),
Stroke::new(2.0, Color32::BLACK), Stroke::new(2.0_f32, Color32::BLACK),
), ),
} }