moved some ui stuff from main to ui.rs
This commit is contained in:
+4
-233
@@ -16,7 +16,7 @@ use layout::{
|
|||||||
manual_marker_size, manual_monster_marker_size, manual_trap_marker_size,
|
manual_marker_size, manual_monster_marker_size, manual_trap_marker_size,
|
||||||
populate_random_markers, populate_stairs, shortest_path_cells,
|
populate_random_markers, populate_stairs, shortest_path_cells,
|
||||||
};
|
};
|
||||||
use ui::{AddTool, UiSettings, draw_side_panel};
|
use ui::{AddTool, UiSettings, draw_legend_panel, draw_level_tabs, draw_side_panel};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum ManualDoorKind {
|
enum ManualDoorKind {
|
||||||
@@ -216,81 +216,12 @@ impl eframe::App for DungeonApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
egui::SidePanel::right("legend_panel")
|
draw_legend_panel(ctx, &mut self.settings.colorblind_mode);
|
||||||
.resizable(false)
|
|
||||||
.min_width(180.0)
|
|
||||||
.default_width(200.0)
|
|
||||||
.show_separator_line(true)
|
|
||||||
.show(ctx, |ui| {
|
|
||||||
ui.heading("Accessibility");
|
|
||||||
ui.add_space(6.0);
|
|
||||||
ui.checkbox(&mut self.settings.colorblind_mode, "Colorblind Mode");
|
|
||||||
ui.add_space(10.0);
|
|
||||||
ui.separator();
|
|
||||||
ui.add_space(8.0);
|
|
||||||
ui.heading("Legend");
|
|
||||||
ui.add_space(8.0);
|
|
||||||
if self.settings.colorblind_mode {
|
|
||||||
draw_legend_entry_colorblind(ui, "Rooms", LegendStyle::Crosshatch);
|
|
||||||
draw_legend_entry_colorblind(ui, "Corridors", LegendStyle::Dots);
|
|
||||||
draw_legend_entry_colorblind(ui, "Walls", LegendStyle::SolidLine);
|
|
||||||
draw_legend_entry_colorblind(ui, "Doors", LegendStyle::LongDash);
|
|
||||||
draw_legend_entry_colorblind(ui, "Locked Doors", LegendStyle::ShortDash);
|
|
||||||
draw_legend_entry_colorblind(ui, "Secret Doors", LegendStyle::DashDotDotLine);
|
|
||||||
draw_legend_entry_colorblind(ui, "Archways", LegendStyle::DottedLine);
|
|
||||||
draw_legend_entry_colorblind(ui, "Windows", LegendStyle::DashDotLine);
|
|
||||||
draw_legend_entry_colorblind(ui, "Stairs", LegendStyle::LabelChar('\u{1F5CF}'));
|
|
||||||
draw_legend_entry_colorblind(ui, "Start Marker", LegendStyle::Label("S"));
|
|
||||||
draw_legend_entry_colorblind(ui, "End Marker", LegendStyle::Label("E"));
|
|
||||||
draw_legend_entry_colorblind(ui, "Trap", LegendStyle::Label("T"));
|
|
||||||
draw_legend_entry_colorblind(ui, "Monster", LegendStyle::Label("M"));
|
|
||||||
} else {
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(70, 120, 160), "Rooms");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(210, 190, 120), "Corridors");
|
|
||||||
draw_legend_entry(ui, Color32::BLACK, "Walls");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(80, 200, 120), "Doors");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(220, 70, 70), "Locked Doors");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(170, 80, 170), "Secret Doors");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(230, 140, 60), "Archways");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(70, 130, 220), "Windows");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(200, 150, 50), "Stairs");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(60, 220, 200), "Start Marker");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(240, 90, 90), "End Marker");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(150, 80, 230), "Trap");
|
|
||||||
draw_legend_entry(ui, Color32::from_rgb(200, 50, 50), "Monster");
|
|
||||||
}
|
|
||||||
ui.add_space(10.0);
|
|
||||||
ui.separator();
|
|
||||||
ui.add_space(8.0);
|
|
||||||
ui.heading("Keybinds");
|
|
||||||
ui.add_space(6.0);
|
|
||||||
ui.label(
|
|
||||||
"• Delete / Backspace: Remove hovered room, corridor, door, text, or marker",
|
|
||||||
);
|
|
||||||
ui.label("• Ctrl+Z: Undo");
|
|
||||||
ui.label("• Ctrl+Y: Redo");
|
|
||||||
ui.label("• Left click + drag: Move hovered room");
|
|
||||||
ui.label("• Right click: Cancel add tool");
|
|
||||||
ui.label("• Right click + drag: Resize hovered room");
|
|
||||||
});
|
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
// Clear level hover state so it only reflects current frame.
|
// Clear level hover state so it only reflects current frame.
|
||||||
self.hover_level_idx = None;
|
self.hover_level_idx =
|
||||||
ui.horizontal(|ui| {
|
draw_level_tabs(ui, self.levels.len(), &mut self.settings.active_level_index);
|
||||||
for i in 0..self.levels.len() {
|
|
||||||
let label = format!("Level {}", i + 1);
|
|
||||||
let is_active = self.settings.active_level_index == i;
|
|
||||||
let response = ui.selectable_label(is_active, label);
|
|
||||||
// Track hover on level tabs.
|
|
||||||
if response.hovered() {
|
|
||||||
self.hover_level_idx = Some(i);
|
|
||||||
}
|
|
||||||
if response.clicked() {
|
|
||||||
self.settings.active_level_index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
let available = ui.available_size_before_wrap();
|
let available = ui.available_size_before_wrap();
|
||||||
@@ -3651,163 +3582,3 @@ fn draw_room_crosshatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw a colored legend entry in the sidebar.
|
|
||||||
fn draw_legend_entry(ui: &mut egui::Ui, color: Color32, label: &str) {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let (rect, _resp) = ui.allocate_exact_size(egui::vec2(16.0, 16.0), egui::Sense::hover());
|
|
||||||
ui.painter().rect_filled(rect, 0.0, color);
|
|
||||||
ui.painter().rect_stroke(
|
|
||||||
rect,
|
|
||||||
0.0,
|
|
||||||
Stroke::new(1.0, Color32::WHITE),
|
|
||||||
egui::StrokeKind::Middle,
|
|
||||||
);
|
|
||||||
ui.add_space(6.0);
|
|
||||||
ui.label(label);
|
|
||||||
});
|
|
||||||
ui.add_space(4.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum LegendStyle {
|
|
||||||
Crosshatch,
|
|
||||||
Dots,
|
|
||||||
SolidLine,
|
|
||||||
LongDash,
|
|
||||||
ShortDash,
|
|
||||||
DottedLine,
|
|
||||||
DashDotLine,
|
|
||||||
DashDotDotLine,
|
|
||||||
Label(&'static str),
|
|
||||||
LabelChar(char),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw a patterned legend entry for colorblind mode.
|
|
||||||
fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: LegendStyle) {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let (rect, _resp) = ui.allocate_exact_size(egui::vec2(16.0, 16.0), egui::Sense::hover());
|
|
||||||
ui.painter().rect_filled(rect, 0.0, Color32::from_gray(220));
|
|
||||||
ui.painter().rect_stroke(
|
|
||||||
rect,
|
|
||||||
0.0,
|
|
||||||
Stroke::new(1.0, Color32::BLACK),
|
|
||||||
egui::StrokeKind::Middle,
|
|
||||||
);
|
|
||||||
|
|
||||||
match style {
|
|
||||||
LegendStyle::Crosshatch => {
|
|
||||||
ui.painter().line_segment(
|
|
||||||
[rect.left_top(), rect.right_bottom()],
|
|
||||||
Stroke::new(1.2, Color32::BLACK),
|
|
||||||
);
|
|
||||||
ui.painter().line_segment(
|
|
||||||
[rect.right_top(), rect.left_bottom()],
|
|
||||||
Stroke::new(1.2, Color32::BLACK),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
LegendStyle::Dots => {
|
|
||||||
ui.painter()
|
|
||||||
.circle_filled(rect.center(), 2.0, Color32::BLACK);
|
|
||||||
ui.painter().circle_filled(
|
|
||||||
egui::pos2(rect.center().x - 4.0, rect.center().y),
|
|
||||||
1.4,
|
|
||||||
Color32::BLACK,
|
|
||||||
);
|
|
||||||
ui.painter().circle_filled(
|
|
||||||
egui::pos2(rect.center().x + 4.0, rect.center().y),
|
|
||||||
1.4,
|
|
||||||
Color32::BLACK,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
LegendStyle::SolidLine => {
|
|
||||||
ui.painter().line_segment(
|
|
||||||
[
|
|
||||||
egui::pos2(rect.left() + 1.0, rect.center().y),
|
|
||||||
egui::pos2(rect.right() - 1.0, rect.center().y),
|
|
||||||
],
|
|
||||||
Stroke::new(2.0, Color32::BLACK),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
LegendStyle::Label(prefix) => {
|
|
||||||
// Draw a small circle background for the label
|
|
||||||
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));
|
|
||||||
// Draw the prefix text in the center (monospace char is ~0.6 * font_size wide)
|
|
||||||
let font_size = 10.0;
|
|
||||||
let font_id = egui::FontId::monospace(font_size);
|
|
||||||
let text_width = prefix.len() as f32 * font_size * 0.6;
|
|
||||||
let text_height = font_size * 0.8;
|
|
||||||
let text_pos = egui::pos2(
|
|
||||||
rect.center().x - text_width / 2.0,
|
|
||||||
rect.center().y - text_height / 2.0 + font_size / 5.0,
|
|
||||||
);
|
|
||||||
ui.painter().text(
|
|
||||||
text_pos,
|
|
||||||
egui::Align2::LEFT_TOP,
|
|
||||||
prefix,
|
|
||||||
font_id,
|
|
||||||
Color32::BLACK,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
LegendStyle::LabelChar(c) => {
|
|
||||||
// Draw a small circle background for the label
|
|
||||||
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));
|
|
||||||
// Draw the character in the center
|
|
||||||
let font_size = 10.0;
|
|
||||||
let font_id = egui::FontId::monospace(font_size);
|
|
||||||
let text_width = 1.0 as f32 * font_size * 0.6;
|
|
||||||
let text_height = font_size * 0.8;
|
|
||||||
let text_pos = egui::pos2(
|
|
||||||
rect.center().x - text_width / 2.0,
|
|
||||||
rect.center().y - text_height / 2.0 + font_size / 5.0,
|
|
||||||
);
|
|
||||||
ui.painter()
|
|
||||||
.text(text_pos, egui::Align2::LEFT_TOP, c, font_id, Color32::BLACK);
|
|
||||||
}
|
|
||||||
LegendStyle::LongDash => draw_dashed_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),
|
|
||||||
6.0,
|
|
||||||
3.0,
|
|
||||||
),
|
|
||||||
LegendStyle::ShortDash => draw_dashed_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),
|
|
||||||
3.0,
|
|
||||||
2.0,
|
|
||||||
),
|
|
||||||
LegendStyle::DottedLine => draw_dotted_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),
|
|
||||||
),
|
|
||||||
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),
|
|
||||||
),
|
|
||||||
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),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.add_space(6.0);
|
|
||||||
ui.label(label);
|
|
||||||
});
|
|
||||||
ui.add_space(4.0);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::seed;
|
use crate::seed;
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::RichText;
|
use egui::{Color32, RichText, Stroke};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
@@ -323,6 +323,88 @@ pub fn draw_side_panel(
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw the accessibility and legend panel.
|
||||||
|
pub fn draw_legend_panel(ctx: &egui::Context, colorblind_mode: &mut bool) {
|
||||||
|
egui::SidePanel::right("legend_panel")
|
||||||
|
.resizable(false)
|
||||||
|
.min_width(180.0)
|
||||||
|
.default_width(200.0)
|
||||||
|
.show_separator_line(true)
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
ui.heading("Accessibility");
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.checkbox(colorblind_mode, "Colorblind Mode");
|
||||||
|
ui.add_space(10.0);
|
||||||
|
ui.separator();
|
||||||
|
ui.add_space(8.0);
|
||||||
|
ui.heading("Legend");
|
||||||
|
ui.add_space(8.0);
|
||||||
|
if *colorblind_mode {
|
||||||
|
draw_legend_entry_colorblind(ui, "Rooms", LegendStyle::Crosshatch);
|
||||||
|
draw_legend_entry_colorblind(ui, "Corridors", LegendStyle::Dots);
|
||||||
|
draw_legend_entry_colorblind(ui, "Walls", LegendStyle::SolidLine);
|
||||||
|
draw_legend_entry_colorblind(ui, "Doors", LegendStyle::LongDash);
|
||||||
|
draw_legend_entry_colorblind(ui, "Locked Doors", LegendStyle::ShortDash);
|
||||||
|
draw_legend_entry_colorblind(ui, "Secret Doors", LegendStyle::DashDotDotLine);
|
||||||
|
draw_legend_entry_colorblind(ui, "Archways", LegendStyle::DottedLine);
|
||||||
|
draw_legend_entry_colorblind(ui, "Windows", LegendStyle::DashDotLine);
|
||||||
|
draw_legend_entry_colorblind(ui, "Stairs", LegendStyle::LabelChar('\u{1F5CF}'));
|
||||||
|
draw_legend_entry_colorblind(ui, "Start Marker", LegendStyle::Label("S"));
|
||||||
|
draw_legend_entry_colorblind(ui, "End Marker", LegendStyle::Label("E"));
|
||||||
|
draw_legend_entry_colorblind(ui, "Trap", LegendStyle::Label("T"));
|
||||||
|
draw_legend_entry_colorblind(ui, "Monster", LegendStyle::Label("M"));
|
||||||
|
} else {
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(70, 120, 160), "Rooms");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(210, 190, 120), "Corridors");
|
||||||
|
draw_legend_entry(ui, Color32::BLACK, "Walls");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(80, 200, 120), "Doors");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(220, 70, 70), "Locked Doors");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(170, 80, 170), "Secret Doors");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(230, 140, 60), "Archways");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(70, 130, 220), "Windows");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(200, 150, 50), "Stairs");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(60, 220, 200), "Start Marker");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(240, 90, 90), "End Marker");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(150, 80, 230), "Trap");
|
||||||
|
draw_legend_entry(ui, Color32::from_rgb(200, 50, 50), "Monster");
|
||||||
|
}
|
||||||
|
ui.add_space(10.0);
|
||||||
|
ui.separator();
|
||||||
|
ui.add_space(8.0);
|
||||||
|
ui.heading("Keybinds");
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.label("• Delete / Backspace: Remove hovered room, corridor, door, text, or marker");
|
||||||
|
ui.label("• Ctrl+Z: Undo");
|
||||||
|
ui.label("• Ctrl+Y: Redo");
|
||||||
|
ui.label("• Left click + drag: Move hovered room");
|
||||||
|
ui.label("• Right click: Cancel add tool");
|
||||||
|
ui.label("• Right click + drag: Resize hovered room");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw level tabs and return the hovered tab index.
|
||||||
|
pub fn draw_level_tabs(
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
level_count: usize,
|
||||||
|
active_level_index: &mut usize,
|
||||||
|
) -> Option<usize> {
|
||||||
|
let mut hovered_level_idx = None;
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
for level_idx in 0..level_count {
|
||||||
|
let label = format!("Level {}", level_idx + 1);
|
||||||
|
let is_active = *active_level_index == level_idx;
|
||||||
|
let response = ui.selectable_label(is_active, label);
|
||||||
|
if response.hovered() {
|
||||||
|
hovered_level_idx = Some(level_idx);
|
||||||
|
}
|
||||||
|
if response.clicked() {
|
||||||
|
*active_level_index = level_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hovered_level_idx
|
||||||
|
}
|
||||||
|
|
||||||
// Render the Generate tab controls.
|
// Render the Generate tab controls.
|
||||||
fn draw_generate_tab(
|
fn draw_generate_tab(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
@@ -1058,6 +1140,281 @@ fn draw_add_tab(ui: &mut egui::Ui, settings: &mut UiSettings, result: &mut SideP
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw a colored legend entry.
|
||||||
|
fn draw_legend_entry(ui: &mut egui::Ui, color: Color32, label: &str) {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let (rect, _resp) = ui.allocate_exact_size(egui::vec2(16.0, 16.0), egui::Sense::hover());
|
||||||
|
ui.painter().rect_filled(rect, 0.0, color);
|
||||||
|
ui.painter().rect_stroke(
|
||||||
|
rect,
|
||||||
|
0.0,
|
||||||
|
Stroke::new(1.0, Color32::WHITE),
|
||||||
|
egui::StrokeKind::Middle,
|
||||||
|
);
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.label(label);
|
||||||
|
});
|
||||||
|
ui.add_space(4.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum LegendStyle {
|
||||||
|
Crosshatch,
|
||||||
|
Dots,
|
||||||
|
SolidLine,
|
||||||
|
LongDash,
|
||||||
|
ShortDash,
|
||||||
|
DottedLine,
|
||||||
|
DashDotLine,
|
||||||
|
DashDotDotLine,
|
||||||
|
Label(&'static str),
|
||||||
|
LabelChar(char),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a patterned legend entry.
|
||||||
|
fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: LegendStyle) {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let (rect, _resp) = ui.allocate_exact_size(egui::vec2(16.0, 16.0), egui::Sense::hover());
|
||||||
|
ui.painter().rect_filled(rect, 0.0, Color32::from_gray(220));
|
||||||
|
ui.painter().rect_stroke(
|
||||||
|
rect,
|
||||||
|
0.0,
|
||||||
|
Stroke::new(1.0, Color32::BLACK),
|
||||||
|
egui::StrokeKind::Middle,
|
||||||
|
);
|
||||||
|
|
||||||
|
match style {
|
||||||
|
LegendStyle::Crosshatch => {
|
||||||
|
ui.painter().line_segment(
|
||||||
|
[rect.left_top(), rect.right_bottom()],
|
||||||
|
Stroke::new(1.2, Color32::BLACK),
|
||||||
|
);
|
||||||
|
ui.painter().line_segment(
|
||||||
|
[rect.right_top(), rect.left_bottom()],
|
||||||
|
Stroke::new(1.2, Color32::BLACK),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
LegendStyle::Dots => {
|
||||||
|
ui.painter()
|
||||||
|
.circle_filled(rect.center(), 2.0, Color32::BLACK);
|
||||||
|
ui.painter().circle_filled(
|
||||||
|
egui::pos2(rect.center().x - 4.0, rect.center().y),
|
||||||
|
1.4,
|
||||||
|
Color32::BLACK,
|
||||||
|
);
|
||||||
|
ui.painter().circle_filled(
|
||||||
|
egui::pos2(rect.center().x + 4.0, rect.center().y),
|
||||||
|
1.4,
|
||||||
|
Color32::BLACK,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
LegendStyle::SolidLine => {
|
||||||
|
ui.painter().line_segment(
|
||||||
|
[
|
||||||
|
egui::pos2(rect.left() + 1.0, rect.center().y),
|
||||||
|
egui::pos2(rect.right() - 1.0, rect.center().y),
|
||||||
|
],
|
||||||
|
Stroke::new(2.0, 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));
|
||||||
|
let font_size = 10.0;
|
||||||
|
let font_id = egui::FontId::monospace(font_size);
|
||||||
|
let text_width = prefix.len() as f32 * font_size * 0.6;
|
||||||
|
let text_height = font_size * 0.8;
|
||||||
|
let text_pos = egui::pos2(
|
||||||
|
rect.center().x - text_width / 2.0,
|
||||||
|
rect.center().y - text_height / 2.0 + font_size / 5.0,
|
||||||
|
);
|
||||||
|
ui.painter().text(
|
||||||
|
text_pos,
|
||||||
|
egui::Align2::LEFT_TOP,
|
||||||
|
prefix,
|
||||||
|
font_id,
|
||||||
|
Color32::BLACK,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
LegendStyle::LabelChar(character) => {
|
||||||
|
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));
|
||||||
|
let font_size = 10.0;
|
||||||
|
let font_id = egui::FontId::monospace(font_size);
|
||||||
|
let text_width = font_size * 0.6;
|
||||||
|
let text_height = font_size * 0.8;
|
||||||
|
let text_pos = egui::pos2(
|
||||||
|
rect.center().x - text_width / 2.0,
|
||||||
|
rect.center().y - text_height / 2.0 + font_size / 5.0,
|
||||||
|
);
|
||||||
|
ui.painter().text(
|
||||||
|
text_pos,
|
||||||
|
egui::Align2::LEFT_TOP,
|
||||||
|
character,
|
||||||
|
font_id,
|
||||||
|
Color32::BLACK,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
LegendStyle::LongDash => draw_dashed_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),
|
||||||
|
6.0,
|
||||||
|
3.0,
|
||||||
|
),
|
||||||
|
LegendStyle::ShortDash => draw_dashed_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),
|
||||||
|
3.0,
|
||||||
|
2.0,
|
||||||
|
),
|
||||||
|
LegendStyle::DottedLine => draw_dotted_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),
|
||||||
|
),
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.label(label);
|
||||||
|
});
|
||||||
|
ui.add_space(4.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a dashed line.
|
||||||
|
fn draw_dashed_line(
|
||||||
|
painter: &egui::Painter,
|
||||||
|
from: egui::Pos2,
|
||||||
|
to: egui::Pos2,
|
||||||
|
stroke: Stroke,
|
||||||
|
dash_len: f32,
|
||||||
|
gap_len: f32,
|
||||||
|
) {
|
||||||
|
let dx = to.x - from.x;
|
||||||
|
let dy = to.y - from.y;
|
||||||
|
let len = (dx * dx + dy * dy).sqrt();
|
||||||
|
if len <= 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ux = dx / len;
|
||||||
|
let uy = dy / len;
|
||||||
|
|
||||||
|
let mut dist = 0.0_f32;
|
||||||
|
while dist < len {
|
||||||
|
let seg_start = dist;
|
||||||
|
let seg_end = (dist + dash_len).min(len);
|
||||||
|
let p0 = egui::pos2(from.x + ux * seg_start, from.y + uy * seg_start);
|
||||||
|
let p1 = egui::pos2(from.x + ux * seg_end, from.y + uy * seg_end);
|
||||||
|
painter.line_segment([p0, p1], stroke);
|
||||||
|
dist += dash_len + gap_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a dotted line.
|
||||||
|
fn draw_dotted_line(painter: &egui::Painter, from: egui::Pos2, to: egui::Pos2, stroke: Stroke) {
|
||||||
|
let dx = to.x - from.x;
|
||||||
|
let dy = to.y - from.y;
|
||||||
|
let len = (dx * dx + dy * dy).sqrt();
|
||||||
|
if len <= 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ux = dx / len;
|
||||||
|
let uy = dy / len;
|
||||||
|
let step = 5.0_f32;
|
||||||
|
let radius = (stroke.width * 0.35).max(1.0);
|
||||||
|
|
||||||
|
let mut dist = 0.0_f32;
|
||||||
|
while dist <= len {
|
||||||
|
let point = egui::pos2(from.x + ux * dist, from.y + uy * dist);
|
||||||
|
painter.circle_filled(point, radius, stroke.color);
|
||||||
|
dist += step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_dash_dot_line(painter: &egui::Painter, from: egui::Pos2, to: egui::Pos2, stroke: Stroke) {
|
||||||
|
let dx = to.x - from.x;
|
||||||
|
let dy = to.y - from.y;
|
||||||
|
let len = (dx * dx + dy * dy).sqrt();
|
||||||
|
if len <= 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ux = dx / len;
|
||||||
|
let uy = dy / len;
|
||||||
|
let mut dist = 0.0_f32;
|
||||||
|
while dist < len {
|
||||||
|
let dash_end = (dist + 7.0).min(len);
|
||||||
|
let p0 = egui::pos2(from.x + ux * dist, from.y + uy * dist);
|
||||||
|
let p1 = egui::pos2(from.x + ux * dash_end, from.y + uy * dash_end);
|
||||||
|
painter.line_segment([p0, p1], stroke);
|
||||||
|
dist = dash_end + 3.0;
|
||||||
|
if dist >= len {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let dot = egui::pos2(from.x + ux * dist, from.y + uy * dist);
|
||||||
|
painter.circle_filled(dot, (stroke.width * 0.35).max(1.0), stroke.color);
|
||||||
|
dist += 4.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_dash_dot_dot_line(
|
||||||
|
painter: &egui::Painter,
|
||||||
|
from: egui::Pos2,
|
||||||
|
to: egui::Pos2,
|
||||||
|
stroke: Stroke,
|
||||||
|
) {
|
||||||
|
let dx = to.x - from.x;
|
||||||
|
let dy = to.y - from.y;
|
||||||
|
let len = (dx * dx + dy * dy).sqrt();
|
||||||
|
if len <= 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ux = dx / len;
|
||||||
|
let uy = dy / len;
|
||||||
|
let radius = (stroke.width * 0.35).max(1.0);
|
||||||
|
let mut dist = 0.0_f32;
|
||||||
|
while dist < len {
|
||||||
|
let dash_end = (dist + 7.0).min(len);
|
||||||
|
let p0 = egui::pos2(from.x + ux * dist, from.y + uy * dist);
|
||||||
|
let p1 = egui::pos2(from.x + ux * dash_end, from.y + uy * dash_end);
|
||||||
|
painter.line_segment([p0, p1], stroke);
|
||||||
|
dist = dash_end + 3.0;
|
||||||
|
if dist >= len {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let dot1 = egui::pos2(from.x + ux * dist, from.y + uy * dist);
|
||||||
|
painter.circle_filled(dot1, radius, stroke.color);
|
||||||
|
dist += 3.0;
|
||||||
|
if dist >= len {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let dot2 = egui::pos2(from.x + ux * dist, from.y + uy * dist);
|
||||||
|
painter.circle_filled(dot2, radius, stroke.color);
|
||||||
|
dist += 4.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_start_and_end_tab(
|
fn draw_start_and_end_tab(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
settings: &mut UiSettings,
|
settings: &mut UiSettings,
|
||||||
|
|||||||
Reference in New Issue
Block a user