feat(layers): add non-printing layer support
This commit is contained in:
parent
b1b5d31be5
commit
eb5cbaeca0
7 changed files with 192 additions and 6 deletions
|
|
@ -2013,6 +2013,7 @@ pub enum Message {
|
||||||
LayerToggleVisible(usize),
|
LayerToggleVisible(usize),
|
||||||
LayerToggleLock(usize),
|
LayerToggleLock(usize),
|
||||||
LayerToggleFreeze(usize),
|
LayerToggleFreeze(usize),
|
||||||
|
LayerTogglePlot(usize),
|
||||||
/// Sort the Layer Manager table by a clicked column header.
|
/// Sort the Layer Manager table by a clicked column header.
|
||||||
LayerSort(crate::ui::window::layers::LayerSortCol),
|
LayerSort(crate::ui::window::layers::LayerSortCol),
|
||||||
/// Toggle per-viewport freeze: (layer_index, vp_col_index)
|
/// Toggle per-viewport freeze: (layer_index, vp_col_index)
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ fn plot_scene_content(
|
||||||
let (mut paper_wires, mut model_wires) = scene.plot_wire_groups(render_mode_override);
|
let (mut paper_wires, mut model_wires) = scene.plot_wire_groups(render_mode_override);
|
||||||
paper_wires.retain(|wire| wire.plot_visible);
|
paper_wires.retain(|wire| wire.plot_visible);
|
||||||
model_wires.retain(|wire| wire.plot_visible);
|
model_wires.retain(|wire| wire.plot_visible);
|
||||||
let paper_hatches = scene.paper_canvas_hatches().as_ref().clone();
|
let paper_hatches = scene.paper_plot_hatches().as_ref().clone();
|
||||||
let paper_wipeouts = scene.paper_canvas_wipeouts().as_ref().clone();
|
let paper_wipeouts = scene.paper_canvas_wipeouts().as_ref().clone();
|
||||||
if scene.current_layout == "Model" {
|
if scene.current_layout == "Model" {
|
||||||
let splits = crate::io::pdf_export::PlotGroupSplits {
|
let splits = crate::io::pdf_export::PlotGroupSplits {
|
||||||
|
|
|
||||||
|
|
@ -2427,6 +2427,56 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
Message::LayerTogglePlot(idx) => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
|
||||||
|
let plottable = self.tabs[i]
|
||||||
|
.layers
|
||||||
|
.layers
|
||||||
|
.get(idx)
|
||||||
|
.map(|layer| !layer.plottable);
|
||||||
|
|
||||||
|
let targets = self.layer_row_action_targets(i, idx);
|
||||||
|
|
||||||
|
if let Some(plottable) = plottable {
|
||||||
|
if !targets.is_empty() {
|
||||||
|
let undo = self.begin_layer_undo(i, "LAYER PLOT/NOPLOT", &targets);
|
||||||
|
|
||||||
|
for name in &targets {
|
||||||
|
if let Some(layer) = self.tabs[i].scene.document.layers.get_mut(name) {
|
||||||
|
layer.is_plottable = plottable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(layer) = self.tabs[i]
|
||||||
|
.layers
|
||||||
|
.layers
|
||||||
|
.iter_mut()
|
||||||
|
.find(|layer| &layer.name == name)
|
||||||
|
{
|
||||||
|
layer.plottable = plottable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tabs[i]
|
||||||
|
.scene
|
||||||
|
.invalidate_layer_dependencies(&targets);
|
||||||
|
|
||||||
|
self.tabs[i].dirty = true;
|
||||||
|
self.commit_layer_undo(i, undo);
|
||||||
|
|
||||||
|
self.command_line.push_output(
|
||||||
|
crate::tf!(
|
||||||
|
"{} layer(s) set to {}",
|
||||||
|
targets.len(),
|
||||||
|
if plottable { "Plot" } else { "No Plot" }
|
||||||
|
)
|
||||||
|
.as_ref(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Task::none()
|
||||||
|
},
|
||||||
|
|
||||||
Message::LayerToggleVpFreeze(layer_idx, vp_col_idx) => {
|
Message::LayerToggleVpFreeze(layer_idx, vp_col_idx) => {
|
||||||
self.on_layer_toggle_vp_freeze(layer_idx, vp_col_idx)
|
self.on_layer_toggle_vp_freeze(layer_idx, vp_col_idx)
|
||||||
|
|
|
||||||
|
|
@ -339,8 +339,48 @@ pub(crate) fn tessellate_entity_dim_text(
|
||||||
}
|
}
|
||||||
wires
|
wires
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tessellate_entity(
|
pub(crate) fn tessellate_entity(
|
||||||
|
document: &acadrust::CadDocument,
|
||||||
|
selected: &HashSet<Handle>,
|
||||||
|
active_viewport: Option<Handle>,
|
||||||
|
bg_color: [f32; 4],
|
||||||
|
anno_scale: f32,
|
||||||
|
annotation_scale_handle: Option<Handle>,
|
||||||
|
e: &EntityType,
|
||||||
|
block_cache: Option<&cache::block_cache::BlockCache>,
|
||||||
|
view_aabb: Option<[f32; 4]>,
|
||||||
|
world_per_pixel: Option<f32>,
|
||||||
|
paper_space: bool,
|
||||||
|
) -> Vec<WireModel> {
|
||||||
|
let mut wires = tessellate_entity_inner(
|
||||||
|
document,
|
||||||
|
selected,
|
||||||
|
active_viewport,
|
||||||
|
bg_color,
|
||||||
|
anno_scale,
|
||||||
|
annotation_scale_handle,
|
||||||
|
e,
|
||||||
|
block_cache,
|
||||||
|
view_aabb,
|
||||||
|
world_per_pixel,
|
||||||
|
paper_space,
|
||||||
|
);
|
||||||
|
|
||||||
|
let layer_plottable = document
|
||||||
|
.layers
|
||||||
|
.get(&e.common().layer)
|
||||||
|
.map(|layer| layer.is_plottable)
|
||||||
|
.unwrap_or(true);
|
||||||
|
|
||||||
|
if !layer_plottable {
|
||||||
|
for wire in &mut wires {
|
||||||
|
wire.plot_visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wires
|
||||||
|
}
|
||||||
|
fn tessellate_entity_inner(
|
||||||
document: &acadrust::CadDocument,
|
document: &acadrust::CadDocument,
|
||||||
selected: &HashSet<Handle>,
|
selected: &HashSet<Handle>,
|
||||||
active_viewport: Option<Handle>,
|
active_viewport: Option<Handle>,
|
||||||
|
|
|
||||||
|
|
@ -1144,9 +1144,31 @@ impl Scene {
|
||||||
viewport,
|
viewport,
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub(super) fn instanced_plot_hatch_models(
|
||||||
|
&self,
|
||||||
|
layout_block: Handle,
|
||||||
|
hatch_bg: [f32; 4],
|
||||||
|
frozen: Option<&rustc_hash::FxHashSet<Handle>>,
|
||||||
|
annotation_scale_handle: Option<Handle>,
|
||||||
|
all_visible: bool,
|
||||||
|
viewport: Option<Handle>,
|
||||||
|
) -> Vec<HatchModel> {
|
||||||
|
self.instanced_hatch_models_filtered(
|
||||||
|
layout_block,
|
||||||
|
hatch_bg,
|
||||||
|
false,
|
||||||
|
frozen,
|
||||||
|
annotation_scale_handle,
|
||||||
|
all_visible,
|
||||||
|
viewport,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build live hatch overlays for INSERT grip previews. The edited INSERT
|
/// Build live hatch overlays for INSERT grip previews. The edited INSERT
|
||||||
/// is intentionally hidden from the resident scene while its current
|
/// is intentionally hidden from the resident scene while its current
|
||||||
/// document entity moves, so include that hidden target and reuse the full
|
/// document entity moves, so include that hidden target and reuse the full
|
||||||
|
|
@ -1183,6 +1205,7 @@ impl Scene {
|
||||||
self.active_viewport,
|
self.active_viewport,
|
||||||
Some(&targets),
|
Some(&targets),
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1197,6 +1220,7 @@ impl Scene {
|
||||||
viewport: Option<Handle>,
|
viewport: Option<Handle>,
|
||||||
targets: Option<&rustc_hash::FxHashSet<Handle>>,
|
targets: Option<&rustc_hash::FxHashSet<Handle>>,
|
||||||
include_preview_hidden: bool,
|
include_preview_hidden: bool,
|
||||||
|
plot_only: bool,
|
||||||
) -> Vec<HatchModel> {
|
) -> Vec<HatchModel> {
|
||||||
let depth_map = self.draw_depth_map();
|
let depth_map = self.draw_depth_map();
|
||||||
let graph = crate::scene::render_graph::RenderSceneGraph::new(
|
let graph = crate::scene::render_graph::RenderSceneGraph::new(
|
||||||
|
|
@ -1213,10 +1237,21 @@ impl Scene {
|
||||||
graph.walk_root(
|
graph.walk_root(
|
||||||
self.render_scene_root(layout_block),
|
self.render_scene_root(layout_block),
|
||||||
|entity, context| {
|
|entity, context| {
|
||||||
|
let common = entity.common();
|
||||||
|
|
||||||
|
if plot_only
|
||||||
|
&& self
|
||||||
|
.document
|
||||||
|
.layers
|
||||||
|
.get(&common.layer)
|
||||||
|
.is_some_and(|layer| !layer.is_plottable)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if context.is_instanced() {
|
if context.is_instanced() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let common = entity.common();
|
|
||||||
if self.object_isolation.hides(common.handle)
|
if self.object_isolation.hides(common.handle)
|
||||||
|| (!include_preview_hidden
|
|| (!include_preview_hidden
|
||||||
&& self.preview_hidden.contains(&common.handle))
|
&& self.preview_hidden.contains(&common.handle))
|
||||||
|
|
@ -1254,6 +1289,15 @@ impl Scene {
|
||||||
let EntityType::Hatch(source_hatch) = entity else {
|
let EntityType::Hatch(source_hatch) = entity else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
if plot_only
|
||||||
|
&& self
|
||||||
|
.document
|
||||||
|
.layers
|
||||||
|
.get(&source_hatch.common.layer)
|
||||||
|
.is_some_and(|layer| !layer.is_plottable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
let style = context.style_for(&self.document, entity);
|
let style = context.style_for(&self.document, entity);
|
||||||
let preserve_white_mask = source_hatch.is_solid
|
let preserve_white_mask = source_hatch.is_solid
|
||||||
&& matches!(
|
&& matches!(
|
||||||
|
|
|
||||||
|
|
@ -482,6 +482,16 @@ impl Scene {
|
||||||
models.extend(instanced);
|
models.extend(instanced);
|
||||||
Arc::new(models)
|
Arc::new(models)
|
||||||
}
|
}
|
||||||
|
pub fn paper_plot_hatches(&self) -> Arc<Vec<HatchModel>> {
|
||||||
|
let layout_block = self.current_layout_block_handle();
|
||||||
|
|
||||||
|
Arc::new(self.plot_hatches_for_block(
|
||||||
|
layout_block,
|
||||||
|
None,
|
||||||
|
self.paper_annotation_scale_handle(),
|
||||||
|
self.annotation_all_visible(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Plot-only hatch set for a specific block. Paper PDF generation uses this
|
/// Plot-only hatch set for a specific block. Paper PDF generation uses this
|
||||||
/// for the model block behind each floating viewport; unlike
|
/// for the model block behind each floating viewport; unlike
|
||||||
|
|
@ -500,6 +510,13 @@ impl Scene {
|
||||||
.map(|l| l.flags.off || l.flags.frozen)
|
.map(|l| l.flags.off || l.flags.frozen)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
};
|
};
|
||||||
|
let layer_plottable = |layer: &str| {
|
||||||
|
self.document
|
||||||
|
.layers
|
||||||
|
.get(layer)
|
||||||
|
.map(|l| l.is_plottable)
|
||||||
|
.unwrap_or(true)
|
||||||
|
};
|
||||||
let mut models = Vec::new();
|
let mut models = Vec::new();
|
||||||
for (&handle, model) in self.hatches.iter() {
|
for (&handle, model) in self.hatches.iter() {
|
||||||
let Some(source) = self.document.get_entity(handle) else {
|
let Some(source) = self.document.get_entity(handle) else {
|
||||||
|
|
@ -515,6 +532,7 @@ impl Scene {
|
||||||
if common.invisible
|
if common.invisible
|
||||||
|| self.entity_temporarily_hidden(handle)
|
|| self.entity_temporarily_hidden(handle)
|
||||||
|| layer_hidden(&common.layer)
|
|| layer_hidden(&common.layer)
|
||||||
|
|| !layer_plottable(&common.layer)
|
||||||
|| self.layer_frozen_in(&common.layer, frozen)
|
|| self.layer_frozen_in(&common.layer, frozen)
|
||||||
|| crate::scene::annotative::annotative_offscale_for(
|
|| crate::scene::annotative::annotative_offscale_for(
|
||||||
&self.document,
|
&self.document,
|
||||||
|
|
@ -554,10 +572,9 @@ impl Scene {
|
||||||
}
|
}
|
||||||
models.push(hatch);
|
models.push(hatch);
|
||||||
}
|
}
|
||||||
models.extend(self.instanced_hatch_models(
|
models.extend(self.instanced_plot_hatch_models(
|
||||||
block,
|
block,
|
||||||
self.paper_bg_color,
|
self.paper_bg_color,
|
||||||
false,
|
|
||||||
frozen,
|
frozen,
|
||||||
annotation_scale_handle,
|
annotation_scale_handle,
|
||||||
all_visible,
|
all_visible,
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ pub enum LayerSortCol {
|
||||||
On,
|
On,
|
||||||
Freeze,
|
Freeze,
|
||||||
Lock,
|
Lock,
|
||||||
|
Plot,
|
||||||
Color,
|
Color,
|
||||||
Linetype,
|
Linetype,
|
||||||
Lineweight,
|
Lineweight,
|
||||||
|
|
@ -86,6 +87,7 @@ pub struct Layer {
|
||||||
pub visible: bool,
|
pub visible: bool,
|
||||||
pub frozen: bool,
|
pub frozen: bool,
|
||||||
pub locked: bool,
|
pub locked: bool,
|
||||||
|
pub plottable: bool,
|
||||||
pub color: AcadColor,
|
pub color: AcadColor,
|
||||||
pub linetype: String,
|
pub linetype: String,
|
||||||
pub lineweight: LineWeight,
|
pub lineweight: LineWeight,
|
||||||
|
|
@ -101,6 +103,7 @@ impl Layer {
|
||||||
visible: true,
|
visible: true,
|
||||||
frozen: false,
|
frozen: false,
|
||||||
locked: false,
|
locked: false,
|
||||||
|
plottable: true,
|
||||||
color,
|
color,
|
||||||
linetype: "Continuous".to_string(),
|
linetype: "Continuous".to_string(),
|
||||||
lineweight: LineWeight::Default,
|
lineweight: LineWeight::Default,
|
||||||
|
|
@ -214,6 +217,7 @@ impl LayerPanel {
|
||||||
visible: !l.flags.off,
|
visible: !l.flags.off,
|
||||||
frozen: l.flags.frozen,
|
frozen: l.flags.frozen,
|
||||||
locked: l.flags.locked,
|
locked: l.flags.locked,
|
||||||
|
plottable: l.is_plottable,
|
||||||
color: l.color,
|
color: l.color,
|
||||||
linetype: if l.line_type.is_empty() {
|
linetype: if l.line_type.is_empty() {
|
||||||
"Continuous".to_string()
|
"Continuous".to_string()
|
||||||
|
|
@ -275,6 +279,7 @@ impl LayerPanel {
|
||||||
LayerSortCol::On => a.visible.cmp(&b.visible),
|
LayerSortCol::On => a.visible.cmp(&b.visible),
|
||||||
LayerSortCol::Freeze => a.frozen.cmp(&b.frozen),
|
LayerSortCol::Freeze => a.frozen.cmp(&b.frozen),
|
||||||
LayerSortCol::Lock => a.locked.cmp(&b.locked),
|
LayerSortCol::Lock => a.locked.cmp(&b.locked),
|
||||||
|
LayerSortCol::Plot => a.plottable.cmp(&b.plottable),
|
||||||
LayerSortCol::Color => color_sort_key(a.color).cmp(&color_sort_key(b.color)),
|
LayerSortCol::Color => color_sort_key(a.color).cmp(&color_sort_key(b.color)),
|
||||||
LayerSortCol::Linetype => {
|
LayerSortCol::Linetype => {
|
||||||
a.linetype.to_lowercase().cmp(&b.linetype.to_lowercase())
|
a.linetype.to_lowercase().cmp(&b.linetype.to_lowercase())
|
||||||
|
|
@ -392,6 +397,7 @@ impl LayerPanel {
|
||||||
sortable_header(t!("On"), LayerSortCol::On, Length::Fixed(COL_ICON), sc, sa),
|
sortable_header(t!("On"), LayerSortCol::On, Length::Fixed(COL_ICON), sc, sa),
|
||||||
sortable_header(t!("Freeze"), LayerSortCol::Freeze, Length::Fixed(COL_ICON), sc, sa),
|
sortable_header(t!("Freeze"), LayerSortCol::Freeze, Length::Fixed(COL_ICON), sc, sa),
|
||||||
sortable_header(t!("Lock"), LayerSortCol::Lock, Length::Fixed(COL_ICON), sc, sa),
|
sortable_header(t!("Lock"), LayerSortCol::Lock, Length::Fixed(COL_ICON), sc, sa),
|
||||||
|
sortable_header(t!("Plot"), LayerSortCol::Plot, Length::Fixed(COL_ICON), sc, sa),
|
||||||
sortable_header(t!("Color"), LayerSortCol::Color, Length::Fixed(COL_COLOR), sc, sa),
|
sortable_header(t!("Color"), LayerSortCol::Color, Length::Fixed(COL_COLOR), sc, sa),
|
||||||
sortable_header(t!("Linetype"), LayerSortCol::Linetype, Length::Fixed(COL_LT), sc, sa),
|
sortable_header(t!("Linetype"), LayerSortCol::Linetype, Length::Fixed(COL_LT), sc, sa),
|
||||||
sortable_header(t!("Lineweight"), LayerSortCol::Lineweight, Length::Fixed(COL_LW), sc, sa),
|
sortable_header(t!("Lineweight"), LayerSortCol::Lineweight, Length::Fixed(COL_LW), sc, sa),
|
||||||
|
|
@ -719,6 +725,31 @@ fn layer_row<'a>(
|
||||||
let vis_svg = crate::ui::icons::layer_visible(layer.visible);
|
let vis_svg = crate::ui::icons::layer_visible(layer.visible);
|
||||||
let frz_svg = crate::ui::icons::layer_freeze(layer.frozen);
|
let frz_svg = crate::ui::icons::layer_freeze(layer.frozen);
|
||||||
let lck_svg = crate::ui::icons::layer_lock(layer.locked);
|
let lck_svg = crate::ui::icons::layer_lock(layer.locked);
|
||||||
|
let plot_icon: Element<'_, Message> = if layer.plottable {
|
||||||
|
crate::ui::icons::themed(crate::ui::icons::PRINT, ICON_SZ)
|
||||||
|
} else {
|
||||||
|
row![
|
||||||
|
crate::ui::icons::themed(crate::ui::icons::PRINT, ICON_SZ),
|
||||||
|
crate::ui::icons::themed_danger(crate::ui::icons::CLOSE, ICON_SZ * 0.65),
|
||||||
|
]
|
||||||
|
.spacing(0)
|
||||||
|
.align_y(iced::Center)
|
||||||
|
.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
let plot_btn: Element<'_, Message> = button(plot_icon)
|
||||||
|
.on_press(Message::LayerTogglePlot(index))
|
||||||
|
.style(move |theme: &Theme, status| {
|
||||||
|
layer_cell_button_style(theme, status, is_selected, index)
|
||||||
|
})
|
||||||
|
.padding(Padding {
|
||||||
|
top: COMBO_PAD_V,
|
||||||
|
bottom: COMBO_PAD_V,
|
||||||
|
left: 4.0,
|
||||||
|
right: 4.0,
|
||||||
|
})
|
||||||
|
.height(Length::Fixed(ROW_H))
|
||||||
|
.into();
|
||||||
|
|
||||||
let status_dot: Element<'_, Message> = if is_current {
|
let status_dot: Element<'_, Message> = if is_current {
|
||||||
crate::ui::icons::themed_success(crate::ui::icons::CHECK, 13.0)
|
crate::ui::icons::themed_success(crate::ui::icons::CHECK, 13.0)
|
||||||
|
|
@ -877,6 +908,9 @@ fn layer_row<'a>(
|
||||||
container(svg_btn(lck_svg, Message::LayerToggleLock(index)))
|
container(svg_btn(lck_svg, Message::LayerToggleLock(index)))
|
||||||
.width(Length::Fixed(COL_ICON))
|
.width(Length::Fixed(COL_ICON))
|
||||||
.align_x(iced::Center),
|
.align_x(iced::Center),
|
||||||
|
container(plot_btn)
|
||||||
|
.width(Length::Fixed(COL_ICON))
|
||||||
|
.align_x(iced::Center),
|
||||||
color_cell,
|
color_cell,
|
||||||
lt_cell,
|
lt_cell,
|
||||||
lw_cell,
|
lw_cell,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue