mirror of https://codeberg.org/topola/topola.git
feat(topola-egui): AppearancePanel active_layer selection should be explicit
This commit is contained in:
parent
d1bcf22e96
commit
3ae298e4e9
|
|
@ -2,6 +2,7 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use egui::{widget_text::WidgetText, Context, Grid, ScrollArea, SidePanel};
|
||||||
use topola::board::{AccessMesadata, Board};
|
use topola::board::{AccessMesadata, Board};
|
||||||
|
|
||||||
pub struct AppearancePanel {
|
pub struct AppearancePanel {
|
||||||
|
|
@ -10,40 +11,63 @@ pub struct AppearancePanel {
|
||||||
// In2.Cu shall be #ce7d2c (#e8c39e when selected).
|
// In2.Cu shall be #ce7d2c (#e8c39e when selected).
|
||||||
pub visible: Box<[bool]>,
|
pub visible: Box<[bool]>,
|
||||||
|
|
||||||
pub active_layer: usize,
|
pub active_layer: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppearancePanel {
|
impl AppearancePanel {
|
||||||
pub fn new(board: &Board<impl AccessMesadata>) -> Self {
|
pub fn new(board: &Board<impl AccessMesadata>) -> Self {
|
||||||
let layer_count = board.layout().drawing().layer_count();
|
let layer_count = board.layout().drawing().layer_count();
|
||||||
let visible = std::iter::repeat(true)
|
let visible = core::iter::repeat(true)
|
||||||
.take(layer_count)
|
.take(layer_count)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Box<[_]>>();
|
||||||
.into_boxed_slice();
|
|
||||||
Self {
|
Self {
|
||||||
visible,
|
visible,
|
||||||
active_layer: 0,
|
active_layer: Some(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, ctx: &egui::Context, board: &Board<impl AccessMesadata>) {
|
pub fn update(&mut self, ctx: &Context, board: &Board<impl AccessMesadata>) {
|
||||||
egui::SidePanel::right("right_side_panel").show(ctx, |ui| {
|
SidePanel::right("appearance_panel").show(ctx, |ui| {
|
||||||
ui.label("Layers");
|
ui.label("Layers");
|
||||||
|
let row_height = ui.spacing().interact_size.y;
|
||||||
|
ScrollArea::vertical().show_rows(
|
||||||
|
ui,
|
||||||
|
row_height,
|
||||||
|
self.visible.len(),
|
||||||
|
|ui, row_range| {
|
||||||
|
let start_row = row_range.start;
|
||||||
|
Grid::new("appearance_layers")
|
||||||
|
.min_col_width(ui.spacing().icon_width)
|
||||||
|
.num_columns(3)
|
||||||
|
.start_row(start_row)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
for (layer, visible) in self.visible[row_range].iter_mut().enumerate() {
|
||||||
|
let layer = layer + start_row;
|
||||||
|
let layername =
|
||||||
|
board.layout().drawing().rules().layer_layername(layer);
|
||||||
|
|
||||||
for (layer, visible) in self.visible.iter_mut().enumerate() {
|
// unnamed layers can't be used for routing
|
||||||
let layername = board
|
if layername.is_some() {
|
||||||
.layout()
|
ui.radio_value(
|
||||||
.drawing()
|
&mut self.active_layer,
|
||||||
.rules()
|
Some(layer),
|
||||||
.layer_layername(layer)
|
WidgetText::default(),
|
||||||
.unwrap_or("Unnamed layer");
|
);
|
||||||
|
} else {
|
||||||
let old = *visible;
|
// dummy item to bump the grid
|
||||||
ui.checkbox(visible, layername);
|
ui.label("");
|
||||||
if old != *visible {
|
|
||||||
self.active_layer = layer;
|
|
||||||
}
|
}
|
||||||
|
ui.checkbox(visible, WidgetText::default());
|
||||||
|
ui.label(
|
||||||
|
layername
|
||||||
|
.map(|i| i.to_string())
|
||||||
|
.unwrap_or_else(|| format!("{} - Unnamed layer", layer)),
|
||||||
|
);
|
||||||
|
ui.end_row();
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use topola::{
|
||||||
autorouter::{
|
autorouter::{
|
||||||
execution::Command, invoker::InvokerError, selection::Selection, AutorouterOptions,
|
execution::Command, invoker::InvokerError, selection::Selection, AutorouterOptions,
|
||||||
},
|
},
|
||||||
|
board::AccessMesadata,
|
||||||
router::RouterOptions,
|
router::RouterOptions,
|
||||||
specctra::{design::SpecctraDesign, ParseError, ParseErrorContext as SpecctraLoadingError},
|
specctra::{design::SpecctraDesign, ParseError, ParseErrorContext as SpecctraLoadingError},
|
||||||
};
|
};
|
||||||
|
|
@ -281,7 +282,22 @@ impl MenuBar {
|
||||||
) {
|
) {
|
||||||
} else if workspace_activities_enabled {
|
} else if workspace_activities_enabled {
|
||||||
let mut schedule = |op: fn(Selection, AutorouterOptions) -> Command| {
|
let mut schedule = |op: fn(Selection, AutorouterOptions) -> Command| {
|
||||||
let selection = workspace.overlay.take_selection();
|
let mut selection = workspace.overlay.take_selection();
|
||||||
|
if let Some(active_layer) = workspace.appearance_panel.active_layer {
|
||||||
|
let active_layer = workspace
|
||||||
|
.interactor
|
||||||
|
.invoker()
|
||||||
|
.autorouter()
|
||||||
|
.board()
|
||||||
|
.layout()
|
||||||
|
.rules()
|
||||||
|
.layer_layername(active_layer)
|
||||||
|
.expect("unknown active layer");
|
||||||
|
selection
|
||||||
|
.pin_selection
|
||||||
|
.0
|
||||||
|
.retain(|i| i.layer == active_layer);
|
||||||
|
}
|
||||||
workspace
|
workspace
|
||||||
.interactor
|
.interactor
|
||||||
.schedule(op(selection, self.autorouter_options));
|
.schedule(op(selection, self.autorouter_options));
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ pub enum SelectionMode {
|
||||||
|
|
||||||
pub struct Overlay {
|
pub struct Overlay {
|
||||||
ratsnest: Ratsnest,
|
ratsnest: Ratsnest,
|
||||||
selection: Selection,
|
pub selection: Selection,
|
||||||
planar_incr_navmesh: Option<PieNavmesh>,
|
planar_incr_navmesh: Option<PieNavmesh>,
|
||||||
reselect_bbox: Option<(SelectionMode, Point)>,
|
reselect_bbox: Option<(SelectionMode, Point)>,
|
||||||
}
|
}
|
||||||
|
|
@ -86,6 +86,10 @@ impl Overlay {
|
||||||
use spade::Triangulation;
|
use spade::Triangulation;
|
||||||
use topola::router::planar_incr_embed::navmesh::TrianVertex;
|
use topola::router::planar_incr_embed::navmesh::TrianVertex;
|
||||||
|
|
||||||
|
let Some(active_layer) = appearance_panel.active_layer else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
if let Ok(triangulation) =
|
if let Ok(triangulation) =
|
||||||
spade::DelaunayTriangulation::<TrianVertex<NodeIndex, f64>>::bulk_load(
|
spade::DelaunayTriangulation::<TrianVertex<NodeIndex, f64>>::bulk_load(
|
||||||
board
|
board
|
||||||
|
|
@ -93,16 +97,8 @@ impl Overlay {
|
||||||
.drawing()
|
.drawing()
|
||||||
.rtree()
|
.rtree()
|
||||||
.locate_in_envelope_intersecting(&AABB::<[f64; 3]>::from_corners(
|
.locate_in_envelope_intersecting(&AABB::<[f64; 3]>::from_corners(
|
||||||
[
|
[-f64::INFINITY, -f64::INFINITY, active_layer as f64],
|
||||||
-f64::INFINITY,
|
[f64::INFINITY, f64::INFINITY, active_layer as f64],
|
||||||
-f64::INFINITY,
|
|
||||||
appearance_panel.active_layer as f64,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
f64::INFINITY,
|
|
||||||
f64::INFINITY,
|
|
||||||
appearance_panel.active_layer as f64,
|
|
||||||
],
|
|
||||||
))
|
))
|
||||||
.map(|&geom| geom.data)
|
.map(|&geom| geom.data)
|
||||||
.filter_map(|node| {
|
.filter_map(|node| {
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ impl PinSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
pub struct PinSelection(BTreeSet<PinSelector>);
|
pub struct PinSelection(pub BTreeSet<PinSelector>);
|
||||||
|
|
||||||
impl PinSelection {
|
impl PinSelection {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue