Highlight primitives of selected pins

This commit is contained in:
Mikolaj Wielgus 2026-03-15 00:51:20 +01:00
parent a71df91fc1
commit 2e56d20065
3 changed files with 121 additions and 48 deletions

View File

@ -10,17 +10,17 @@ use topola::Board;
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Colors { pub struct Colors {
pub layers: LayerColors, pub layers: ColorLayers,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LayerColors { pub struct ColorLayers {
default: LayerColor, default: LayerColors,
colors: BTreeMap<String, LayerColor>, colors: BTreeMap<String, LayerColors>,
} }
impl LayerColors { impl ColorLayers {
pub fn color(&self, layer_name: Option<&str>) -> &LayerColor { pub fn colors(&self, layer_name: Option<&str>) -> &LayerColors {
layer_name layer_name
.map(|layername| self.colors.get(layername).unwrap_or(&self.default)) .map(|layername| self.colors.get(layername).unwrap_or(&self.default))
.unwrap_or(&self.default) .unwrap_or(&self.default)
@ -28,7 +28,7 @@ impl LayerColors {
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LayerColor { pub struct LayerColors {
pub normal: egui::Color32, pub normal: egui::Color32,
pub highlighted: egui::Color32, pub highlighted: egui::Color32,
} }
@ -38,8 +38,8 @@ pub struct AppearancePanel {
// TODO: // TODO:
// In1.Cu shall be #7fc87f (#d5ecd5 when selected). // In1.Cu shall be #7fc87f (#d5ecd5 when selected).
// In2.Cu shall be #ce7d2c (#e8c39e when selected). // In2.Cu shall be #ce7d2c (#e8c39e when selected).
pub dark_colors: Colors, dark_colors: Colors,
pub light_colors: Colors, light_colors: Colors,
#[serde(skip)] #[serde(skip)]
pub visible: Box<[bool]>, pub visible: Box<[bool]>,
@ -48,50 +48,50 @@ pub struct AppearancePanel {
impl AppearancePanel { impl AppearancePanel {
pub fn new(board: &Board) -> Self { pub fn new(board: &Board) -> Self {
let dark_colors = Colors { let dark_colors = Colors {
layers: LayerColors { layers: ColorLayers {
default: LayerColor { default: LayerColors {
normal: egui::Color32::from_rgb(255, 255, 255), normal: egui::Color32::from_rgb(255, 255, 255),
highlighted: egui::Color32::from_rgb(255, 255, 255), highlighted: egui::Color32::from_rgb(255, 255, 255),
}, },
colors: BTreeMap::from([ colors: BTreeMap::from([
( (
"F.Cu".to_string(), "F.Cu".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(255, 52, 52), normal: egui::Color32::from_rgb(255, 52, 52),
highlighted: egui::Color32::from_rgb(255, 100, 100), highlighted: egui::Color32::from_rgb(255, 100, 100),
}, },
), ),
( (
"1".to_string(), "1".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(255, 52, 52), normal: egui::Color32::from_rgb(255, 52, 52),
highlighted: egui::Color32::from_rgb(255, 100, 100), highlighted: egui::Color32::from_rgb(255, 100, 100),
}, },
), ),
( (
"B.Cu".to_string(), "B.Cu".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(52, 52, 255), normal: egui::Color32::from_rgb(52, 52, 255),
highlighted: egui::Color32::from_rgb(100, 100, 255), highlighted: egui::Color32::from_rgb(100, 100, 255),
}, },
), ),
( (
"2".to_string(), "2".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(52, 52, 255), normal: egui::Color32::from_rgb(52, 52, 255),
highlighted: egui::Color32::from_rgb(100, 100, 255), highlighted: egui::Color32::from_rgb(100, 100, 255),
}, },
), ),
( (
"In1.Cu".to_string(), "In1.Cu".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(127, 200, 127), normal: egui::Color32::from_rgb(127, 200, 127),
highlighted: egui::Color32::from_rgb(213, 236, 213), highlighted: egui::Color32::from_rgb(213, 236, 213),
}, },
), ),
( (
"In2.Cu".to_string(), "In2.Cu".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(206, 125, 44), normal: egui::Color32::from_rgb(206, 125, 44),
highlighted: egui::Color32::from_rgb(232, 195, 158), highlighted: egui::Color32::from_rgb(232, 195, 158),
}, },
@ -100,50 +100,50 @@ impl AppearancePanel {
}, },
}; };
let light_colors = Colors { let light_colors = Colors {
layers: LayerColors { layers: ColorLayers {
default: LayerColor { default: LayerColors {
normal: egui::Color32::from_rgb(0, 0, 0), normal: egui::Color32::from_rgb(0, 0, 0),
highlighted: egui::Color32::from_rgb(0, 0, 0), highlighted: egui::Color32::from_rgb(0, 0, 0),
}, },
colors: BTreeMap::from([ colors: BTreeMap::from([
( (
"F.Cu".to_string(), "F.Cu".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(255, 27, 27), normal: egui::Color32::from_rgb(255, 27, 27),
highlighted: egui::Color32::from_rgb(255, 52, 52), highlighted: egui::Color32::from_rgb(255, 52, 52),
}, },
), ),
( (
"1".to_string(), "1".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(255, 27, 27), normal: egui::Color32::from_rgb(255, 27, 27),
highlighted: egui::Color32::from_rgb(255, 52, 52), highlighted: egui::Color32::from_rgb(255, 52, 52),
}, },
), ),
( (
"B.Cu".to_string(), "B.Cu".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(27, 27, 255), normal: egui::Color32::from_rgb(27, 27, 255),
highlighted: egui::Color32::from_rgb(52, 52, 255), highlighted: egui::Color32::from_rgb(52, 52, 255),
}, },
), ),
( (
"2".to_string(), "2".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(27, 27, 255), normal: egui::Color32::from_rgb(27, 27, 255),
highlighted: egui::Color32::from_rgb(52, 52, 255), highlighted: egui::Color32::from_rgb(52, 52, 255),
}, },
), ),
( (
"In1.Cu".to_string(), "In1.Cu".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(76, 169, 76), normal: egui::Color32::from_rgb(76, 169, 76),
highlighted: egui::Color32::from_rgb(127, 200, 127), highlighted: egui::Color32::from_rgb(127, 200, 127),
}, },
), ),
( (
"In2.Cu".to_string(), "In2.Cu".to_string(),
LayerColor { LayerColors {
normal: egui::Color32::from_rgb(183, 80, 12), normal: egui::Color32::from_rgb(183, 80, 12),
highlighted: egui::Color32::from_rgb(206, 125, 44), highlighted: egui::Color32::from_rgb(206, 125, 44),
}, },
@ -214,4 +214,21 @@ impl AppearancePanel {
egui::Theme::Light => &self.light_colors, egui::Theme::Light => &self.light_colors,
} }
} }
pub fn layer_colors(&self, ctx: &Context, layer_name: Option<&str>) -> &LayerColors {
self.colors(ctx).layers.colors(layer_name)
}
pub fn layer_color(
&self,
ctx: &Context,
layer_name: Option<&str>,
highlight: bool,
) -> egui::Color32 {
if highlight {
self.colors(ctx).layers.colors(layer_name).highlighted
} else {
self.colors(ctx).layers.colors(layer_name).normal
}
}
} }

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{viewport::Viewport, workspace::Workspace}; use crate::{viewport::Viewport, workspace::Workspace};
use topola::{Joint, Polygon, Segment, SegmentId, Vector2}; use topola::{Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Vector2};
pub struct Display {} pub struct Display {}
@ -48,7 +48,7 @@ impl Display {
egui::Stroke::new(5.0 / viewport.scale_factor(), egui::Color32::WHITE), egui::Stroke::new(5.0 / viewport.scale_factor(), egui::Color32::WHITE),
); );
for (_, joint) in workspace for (joint_index, joint) in workspace
.navmesher_board .navmesher_board
.board() .board()
.layout() .layout()
@ -61,17 +61,22 @@ impl Display {
ui, ui,
viewport, viewport,
joint, joint,
workspace workspace.appearance_panel.layer_color(
.appearance_panel ctx,
.colors(ctx) workspace.navmesher_board.board().layer_name(joint.layer),
.layers workspace
.color(workspace.navmesher_board.board().layer_name(joint.layer)) .navmesher_board
.normal, .board()
.pin_selection_contains_joint(
&workspace.pin_selection,
JointId::new(joint_index),
),
),
); );
} }
} }
for (i, segment) in workspace for (segment_index, segment) in workspace
.navmesher_board .navmesher_board
.board() .board()
.layout() .layout()
@ -88,18 +93,25 @@ impl Display {
.navmesher_board .navmesher_board
.board() .board()
.layout() .layout()
.segment_endpoints(SegmentId::new(i)), .segment_endpoints(SegmentId::new(segment_index)),
workspace workspace.appearance_panel.layer_color(
.appearance_panel ctx,
.colors(ctx) workspace.navmesher_board.board().layer_name(segment.layer),
.layers workspace
.color(workspace.navmesher_board.board().layer_name(segment.layer)) .navmesher_board
.normal, .board()
.pin_selection_contains_segment(
&workspace.pin_selection,
SegmentId::new(segment_index),
),
),
); );
} }
} }
for (_, polygon) in workspace // TODO: Vias.
for (polygon_index, polygon) in workspace
.navmesher_board .navmesher_board
.board() .board()
.layout() .layout()
@ -112,12 +124,17 @@ impl Display {
ui, ui,
viewport, viewport,
polygon, polygon,
workspace workspace.appearance_panel.layer_color(
.appearance_panel ctx,
.colors(ctx) workspace.navmesher_board.board().layer_name(polygon.layer),
.layers workspace
.color(workspace.navmesher_board.board().layer_name(polygon.layer)) .navmesher_board
.normal, .board()
.pin_selection_contains_polygon(
&workspace.pin_selection,
PolygonId::new(polygon_index),
),
),
); );
} }
} }

View File

@ -10,6 +10,7 @@ use crate::{
layout::{Layout, LayoutHalfDelta, NetId, PinId}, layout::{Layout, LayoutHalfDelta, NetId, PinId},
math::Vector2, math::Vector2,
primitives::{Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Via, ViaId}, primitives::{Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Via, ViaId},
selection::PinSelection,
selection::PinSelector, selection::PinSelector,
}; };
@ -122,6 +123,44 @@ impl Board {
None None
} }
pub fn pin_selection_contains_joint(
&self,
pin_selection: &PinSelection,
joint_id: JointId,
) -> bool {
let Some(pin_selector) = self.joint_pin_selector(joint_id) else {
return false;
};
pin_selection.0.contains(&pin_selector)
}
pub fn pin_selection_contains_segment(
&self,
pin_selection: &PinSelection,
segment_id: SegmentId,
) -> bool {
let Some(pin_selector) = self.segment_pin_selector(segment_id) else {
return false;
};
pin_selection.0.contains(&pin_selector)
}
// TODO: Vias.
pub fn pin_selection_contains_polygon(
&self,
pin_selection: &PinSelection,
polygon_id: PolygonId,
) -> bool {
let Some(pin_selector) = self.polygon_pin_selector(polygon_id) else {
return false;
};
pin_selection.0.contains(&pin_selector)
}
pub fn pin_name(&self, pin: PinId) -> Option<&str> { pub fn pin_name(&self, pin: PinId) -> Option<&str> {
self.pin_names.get_by_left(&pin).map(String::as_str) self.pin_names.get_by_left(&pin).map(String::as_str)
} }