Compare commits
3
Commits
main
..
b4fecd94bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4fecd94bb | ||
|
|
34219b9d54 | ||
|
|
b715fae73f |
+3
-1
@@ -1,12 +1,14 @@
|
||||
[package]
|
||||
name = "desktop_dungeon_generator"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
eframe = "0.31"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
quick-xml = { version = "0.37", features = ["serialize"] }
|
||||
zip = { version = "2", default-features = false, features = ["deflate"] }
|
||||
dirs = "6"
|
||||
rfd = "0.15"
|
||||
tiny-skia = "0.11"
|
||||
|
||||
@@ -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 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);
|
||||
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,
|
||||
4.0,
|
||||
Stroke::new(
|
||||
1.5,
|
||||
1.5_f32,
|
||||
Color32::from_rgb(150, 200, 240).gamma_multiply(ghost_alpha + 0.3),
|
||||
),
|
||||
egui::StrokeKind::Middle,
|
||||
@@ -881,7 +881,7 @@ pub fn draw_add_tool_ghost(app: &DungeonApp, painter: &egui::Painter, geometry:
|
||||
rect.expand(4.0),
|
||||
4.0,
|
||||
Stroke::new(
|
||||
1.0,
|
||||
1.0_f32,
|
||||
Color32::from_rgb(180, 180, 220).gamma_multiply(ghost_alpha + 0.2),
|
||||
),
|
||||
egui::StrokeKind::Middle,
|
||||
@@ -919,7 +919,7 @@ pub fn draw_add_tool_ghost(app: &DungeonApp, painter: &egui::Painter, geometry:
|
||||
rect,
|
||||
4.0,
|
||||
Stroke::new(
|
||||
1.5,
|
||||
1.5_f32,
|
||||
Color32::from_rgb(255, 255, 255).gamma_multiply(ghost_alpha + 0.2),
|
||||
),
|
||||
egui::StrokeKind::Middle,
|
||||
@@ -962,7 +962,7 @@ pub fn draw_add_tool_ghost(app: &DungeonApp, painter: &egui::Painter, geometry:
|
||||
rect,
|
||||
4.0,
|
||||
Stroke::new(
|
||||
1.5,
|
||||
1.5_f32,
|
||||
Color32::from_rgb(220, 180, 80).gamma_multiply(ghost_alpha + 0.2),
|
||||
),
|
||||
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.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 fill = Color32::from_rgb(100, 160, 100).gamma_multiply(ghost_alpha);
|
||||
let stroke = Stroke::new(
|
||||
1.5,
|
||||
1.5_f32,
|
||||
Color32::from_rgb(180, 240, 180).gamma_multiply(ghost_alpha + 0.3),
|
||||
);
|
||||
|
||||
|
||||
@@ -474,7 +474,7 @@ pub fn draw_corridor_hover_overlay(
|
||||
};
|
||||
|
||||
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) {
|
||||
let a = cell_center(geometry, pair[0].0, pair[0].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;
|
||||
};
|
||||
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(
|
||||
painter,
|
||||
geometry,
|
||||
|
||||
@@ -36,7 +36,7 @@ pub fn draw_grid(
|
||||
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);
|
||||
|
||||
for col in 1..cols {
|
||||
|
||||
@@ -617,7 +617,7 @@ pub fn draw_selection_box(app: &DungeonApp, painter: &egui::Painter, geometry: &
|
||||
painter.rect_stroke(
|
||||
rect,
|
||||
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,
|
||||
);
|
||||
}
|
||||
@@ -636,7 +636,7 @@ pub fn draw_selection_highlights(
|
||||
}
|
||||
let layout = &app.levels[app.settings.active_level_index];
|
||||
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 {
|
||||
match item {
|
||||
|
||||
@@ -369,7 +369,7 @@ pub fn draw_resize_overlay(app: &DungeonApp, painter: &egui::Painter, geometry:
|
||||
painter.rect_stroke(
|
||||
rect,
|
||||
0.0,
|
||||
Stroke::new(2.0, Color32::from_gray(180)),
|
||||
Stroke::new(2.0_f32, Color32::from_gray(180)),
|
||||
egui::StrokeKind::Middle,
|
||||
);
|
||||
let pos = crate::interact::cell_center(
|
||||
@@ -423,7 +423,7 @@ pub fn draw_resize_overlay(app: &DungeonApp, painter: &egui::Painter, geometry:
|
||||
painter.rect_stroke(
|
||||
rect,
|
||||
0.0,
|
||||
Stroke::new(2.0, Color32::from_gray(180)),
|
||||
Stroke::new(2.0_f32, Color32::from_gray(180)),
|
||||
egui::StrokeKind::Middle,
|
||||
);
|
||||
}
|
||||
@@ -446,7 +446,7 @@ pub fn draw_room_resize_visuals(
|
||||
show_handles: bool,
|
||||
) {
|
||||
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 top = geometry.rect.top() + room.y as f32 * geometry.cell_size;
|
||||
@@ -491,7 +491,7 @@ pub fn draw_staircase_resize_visuals(
|
||||
show_handles: bool,
|
||||
) {
|
||||
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 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 rect = egui::Rect::from_center_size(corner, egui::vec2(size, size));
|
||||
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 stroke = Stroke::new(1.0, color);
|
||||
let stroke = Stroke::new(1.0_f32, color);
|
||||
match which {
|
||||
ResizeCorner::TopLeft => {
|
||||
painter.line_segment(
|
||||
|
||||
@@ -212,6 +212,7 @@ pub struct WindowSettings {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
pub struct DungeonLayout {
|
||||
pub name: String,
|
||||
pub rooms: Vec<Room>,
|
||||
|
||||
+5
-5
@@ -134,7 +134,7 @@ pub fn draw_layout(
|
||||
painter,
|
||||
geometry,
|
||||
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(
|
||||
text_label_rect(geometry, label).expand(2.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,
|
||||
);
|
||||
}
|
||||
@@ -388,7 +388,7 @@ pub fn draw_staircase(
|
||||
rect,
|
||||
4.0,
|
||||
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),
|
||||
),
|
||||
egui::StrokeKind::Middle,
|
||||
@@ -408,7 +408,7 @@ pub fn draw_staircase(
|
||||
egui::pos2(rect.left() + 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,
|
||||
4.0,
|
||||
Stroke::new(
|
||||
if hovered { 3.0 } else { 2.0 },
|
||||
if hovered { 3.0_f32 } else { 2.0_f32 },
|
||||
stroke_color.gamma_multiply(alpha),
|
||||
),
|
||||
egui::StrokeKind::Middle,
|
||||
|
||||
+123
-15
@@ -1,13 +1,16 @@
|
||||
/*
|
||||
* Persistence logic for 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 serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::io::{Cursor, Read, Write};
|
||||
use std::path::PathBuf;
|
||||
use zip::write::SimpleFileOptions;
|
||||
use zip::{CompressionMethod, ZipArchive, ZipWriter};
|
||||
|
||||
use crate::layout::DungeonLayout;
|
||||
use crate::ui::UiSettings;
|
||||
@@ -19,7 +22,66 @@ pub struct DungeonSave {
|
||||
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(
|
||||
settings: &UiSettings,
|
||||
layouts: Vec<DungeonLayout>,
|
||||
@@ -27,8 +89,8 @@ pub fn save_dungeon(
|
||||
) -> Result<PathBuf, String> {
|
||||
let dialog = FileDialog::new()
|
||||
.set_title("Save Dungeon State")
|
||||
.add_filter("Dungeon File", &["dungeon"])
|
||||
.set_file_name("my_dungeon.dungeon");
|
||||
.add_filter("Dungeon File", &["dun"])
|
||||
.set_file_name("my_dungeon.dun");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let path = std::thread::spawn(move || dialog.save_file())
|
||||
@@ -37,7 +99,10 @@ pub fn save_dungeon(
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
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 {
|
||||
settings: settings.clone(),
|
||||
@@ -45,19 +110,17 @@ pub fn save_dungeon(
|
||||
svgs,
|
||||
};
|
||||
|
||||
let json = serde_json::to_string_pretty(&save_data)
|
||||
.map_err(|e| format!("Failed to serialize dungeon: {e}"))?;
|
||||
|
||||
fs::write(&path, json).map_err(|e| format!("Failed to write file: {e}"))?;
|
||||
let archive = create_archive(&save_data)?;
|
||||
fs::write(&path, archive).map_err(|e| format!("Failed to write file: {e}"))?;
|
||||
|
||||
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> {
|
||||
let dialog = FileDialog::new()
|
||||
.set_title("Load Dungeon State")
|
||||
.add_filter("Dungeon File", &["dungeon"]);
|
||||
.add_filter("Dungeon File", &["dun"]);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
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 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 =
|
||||
serde_json::from_str(&content).map_err(|e| format!("Failed to parse dungeon file: {e}"))?;
|
||||
#[cfg(test)]
|
||||
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 &</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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,7 @@ pub struct UiSettings {
|
||||
pub export_height: u32,
|
||||
pub allow_export_aspect_change: bool,
|
||||
pub export_show_grid: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub last_export_path: Option<String>,
|
||||
pub add_tool: AddTool,
|
||||
pub add_text_value: String,
|
||||
@@ -156,6 +157,7 @@ pub struct UiSettings {
|
||||
pub min_levels: usize,
|
||||
pub max_levels: usize,
|
||||
pub active_level_index: usize,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub overlay_level_index: Option<usize>,
|
||||
pub export_level_index: usize,
|
||||
pub trap_frequency_percent: usize,
|
||||
|
||||
+12
-12
@@ -18,7 +18,7 @@ pub fn draw_legend_entry(ui: &mut egui::Ui, color: Color32, label: &str) {
|
||||
ui.painter().rect_stroke(
|
||||
rect,
|
||||
0.0,
|
||||
Stroke::new(1.0, Color32::WHITE),
|
||||
Stroke::new(1.0_f32, Color32::WHITE),
|
||||
egui::StrokeKind::Middle,
|
||||
);
|
||||
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(
|
||||
rect,
|
||||
0.0,
|
||||
Stroke::new(1.0, Color32::BLACK),
|
||||
Stroke::new(1.0_f32, Color32::BLACK),
|
||||
egui::StrokeKind::Middle,
|
||||
);
|
||||
|
||||
@@ -57,11 +57,11 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
|
||||
LegendStyle::Crosshatch => {
|
||||
ui.painter().line_segment(
|
||||
[rect.left_top(), rect.right_bottom()],
|
||||
Stroke::new(1.2, Color32::BLACK),
|
||||
Stroke::new(1.2_f32, Color32::BLACK),
|
||||
);
|
||||
ui.painter().line_segment(
|
||||
[rect.right_top(), rect.left_bottom()],
|
||||
Stroke::new(1.2, Color32::BLACK),
|
||||
Stroke::new(1.2_f32, Color32::BLACK),
|
||||
);
|
||||
}
|
||||
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.right() - 1.0, rect.center().y),
|
||||
],
|
||||
Stroke::new(2.0, Color32::BLACK),
|
||||
Stroke::new(2.0_f32, Color32::BLACK),
|
||||
);
|
||||
}
|
||||
LegendStyle::Label(prefix) => {
|
||||
ui.painter()
|
||||
.circle_filled(rect.center(), 6.0, Color32::from_gray(180));
|
||||
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_id = egui::FontId::monospace(font_size);
|
||||
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()
|
||||
.circle_filled(rect.center(), 6.0, Color32::from_gray(180));
|
||||
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_id = egui::FontId::monospace(font_size);
|
||||
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(),
|
||||
egui::pos2(rect.left() + 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,
|
||||
3.0,
|
||||
),
|
||||
@@ -141,7 +141,7 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
|
||||
ui.painter(),
|
||||
egui::pos2(rect.left() + 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,
|
||||
2.0,
|
||||
),
|
||||
@@ -149,19 +149,19 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen
|
||||
ui.painter(),
|
||||
egui::pos2(rect.left() + 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(
|
||||
ui.painter(),
|
||||
egui::pos2(rect.left() + 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(
|
||||
ui.painter(),
|
||||
egui::pos2(rect.left() + 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),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user