forked from 1b-agent/opencadstudio-upstream
feat(layer-state): add saved-state editor
This commit is contained in:
1 parent
1e624cc6b7
commit
6ecd67ff6e
12 files changed
+691
-14
No files matched your search
@@ -740,6 +740,9 @@ pub(super) struct OpenCADStudio {
|
||||
layer_state_name_buf: String,
|
||||
layer_state_description_buf: String,
|
||||
layer_state_filter: String,
|
||||
layer_state_edit_draft: Option<acadrust::LayerState>,
|
||||
layer_state_edit_filter: String,
|
||||
layer_state_edit_color_open: Option<usize>,
|
||||
|
||||
// ── Annotation-scale Manager ──────────────────────────────────────────
|
||||
scale_manager_selected: String,
|
||||
@@ -1003,6 +1006,8 @@ pub enum ColorPickTarget {
|
||||
Ribbon,
|
||||
/// A layer's colour, by panel row index.
|
||||
Layer(usize),
|
||||
/// A saved layer-state layer's colour, by editor row index.
|
||||
LayerState(usize),
|
||||
/// The MText editor's selection (or global) colour.
|
||||
MText,
|
||||
}
|
||||
@@ -1324,6 +1329,7 @@ pub enum ModalKind {
|
||||
UpdateNotice,
|
||||
Layers,
|
||||
LayerStateManager,
|
||||
LayerStateEditor,
|
||||
Plot,
|
||||
LayoutManager,
|
||||
Plotstyle,
|
||||
@@ -1352,6 +1358,31 @@ pub enum ModalKind {
|
||||
AnnoObjectScale,
|
||||
}
|
||||
|
||||
/// A property group controlled by a layer state's restore mask.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LayerStateProperty {
|
||||
On,
|
||||
Frozen,
|
||||
Locked,
|
||||
Plot,
|
||||
NewViewport,
|
||||
Color,
|
||||
LineType,
|
||||
LineWeight,
|
||||
PlotStyle,
|
||||
Transparency,
|
||||
}
|
||||
|
||||
/// A boolean saved for one layer inside a named layer state.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LayerStateLayerFlag {
|
||||
On,
|
||||
Frozen,
|
||||
Locked,
|
||||
Plot,
|
||||
NewViewport,
|
||||
}
|
||||
|
||||
/// Identifies a DimStyle field that can be edited in the dialog.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DsField {
|
||||
@@ -1688,6 +1719,21 @@ pub enum Message {
|
||||
LayerStateManagerSave,
|
||||
LayerStateManagerRestore,
|
||||
LayerStateManagerDelete,
|
||||
LayerStateManagerEdit,
|
||||
LayerStateEditorMaskToggle(LayerStateProperty),
|
||||
LayerStateEditorLayerFlagToggle(usize, LayerStateLayerFlag),
|
||||
LayerStateEditorLayerColorToggle(usize),
|
||||
LayerStateEditorLayerColor(usize, acadrust::types::Color),
|
||||
LayerStateEditorLayerLinetype(usize, String),
|
||||
LayerStateEditorLayerLineweight(usize, LineWeight),
|
||||
LayerStateEditorLayerPlotStyle(usize, String),
|
||||
LayerStateEditorLayerTransparency(usize, Option<acadrust::types::Transparency>),
|
||||
LayerStateEditorName(String),
|
||||
LayerStateEditorDescription(String),
|
||||
LayerStateEditorCurrentLayer(String),
|
||||
LayerStateEditorFilter(String),
|
||||
LayerStateEditorSave,
|
||||
LayerStateEditorCancel,
|
||||
CursorMoved(Point),
|
||||
ViewportClick,
|
||||
ViewportMove(Point),
|
||||
@@ -2729,6 +2775,9 @@ impl OpenCADStudio {
|
||||
layer_state_name_buf: String::new(),
|
||||
layer_state_description_buf: String::new(),
|
||||
layer_state_filter: String::new(),
|
||||
layer_state_edit_draft: None,
|
||||
layer_state_edit_filter: String::new(),
|
||||
layer_state_edit_color_open: None,
|
||||
scale_manager_selected: String::new(),
|
||||
scale_manager_paper_buf: String::new(),
|
||||
scale_manager_drawing_buf: String::new(),
|
||||
|
||||
@@ -136,6 +136,11 @@ impl OpenCADStudio {
|
||||
Some(Aliases) => {
|
||||
self.alias_editor_rows.clear();
|
||||
}
|
||||
Some(LayerStateEditor) => {
|
||||
self.layer_state_edit_draft = None;
|
||||
self.layer_state_edit_filter.clear();
|
||||
self.layer_state_edit_color_open = None;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// The tool that opened this dialog is done with it now. Keep the
|
||||
@@ -1014,10 +1019,13 @@ impl OpenCADStudio {
|
||||
Some(
|
||||
super::ModalKind::LayoutManager
|
||||
| super::ModalKind::LayerStateManager
|
||||
| super::ModalKind::LayerStateEditor
|
||||
)
|
||||
)
|
||||
{
|
||||
self.close_active_modal();
|
||||
} else if self.active_modal == Some(super::ModalKind::LayerStateEditor) {
|
||||
self.close_active_modal();
|
||||
} else if self.active_modal == Some(super::ModalKind::LayerStateManager) {
|
||||
let mut names: Vec<String> = self.tabs[idx]
|
||||
.scene
|
||||
@@ -1560,6 +1568,211 @@ impl OpenCADStudio {
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateManagerEdit => {
|
||||
let i = self.active_tab;
|
||||
let Some(name) = self.layer_state_selected.clone() else {
|
||||
return Task::none();
|
||||
};
|
||||
let Some(state) = self.tabs[i].scene.document.layer_state(&name) else {
|
||||
self.command_line
|
||||
.push_error(&format!("Layer state \"{name}\" was not found."));
|
||||
return Task::none();
|
||||
};
|
||||
self.layer_state_edit_draft = Some(state);
|
||||
self.layer_state_edit_filter.clear();
|
||||
self.layer_state_edit_color_open = None;
|
||||
self.active_modal = Some(super::ModalKind::LayerStateEditor);
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorMaskToggle(property) => {
|
||||
let flag = match property {
|
||||
super::LayerStateProperty::On => acadrust::LayerStateMask::ON,
|
||||
super::LayerStateProperty::Frozen => acadrust::LayerStateMask::FROZEN,
|
||||
super::LayerStateProperty::Locked => acadrust::LayerStateMask::LOCKED,
|
||||
super::LayerStateProperty::Plot => acadrust::LayerStateMask::PLOT,
|
||||
super::LayerStateProperty::NewViewport => {
|
||||
acadrust::LayerStateMask::NEW_VIEWPORT
|
||||
}
|
||||
super::LayerStateProperty::Color => acadrust::LayerStateMask::COLOR,
|
||||
super::LayerStateProperty::LineType => acadrust::LayerStateMask::LINE_TYPE,
|
||||
super::LayerStateProperty::LineWeight => {
|
||||
acadrust::LayerStateMask::LINE_WEIGHT
|
||||
}
|
||||
super::LayerStateProperty::PlotStyle => acadrust::LayerStateMask::PLOT_STYLE,
|
||||
super::LayerStateProperty::Transparency => {
|
||||
acadrust::LayerStateMask::TRANSPARENCY
|
||||
}
|
||||
};
|
||||
if let Some(state) = self.layer_state_edit_draft.as_mut() {
|
||||
state.mask =
|
||||
acadrust::LayerStateMask::from_bits(state.mask.bits() ^ flag.bits());
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorLayerFlagToggle(index, flag) => {
|
||||
let Some(layer) = self
|
||||
.layer_state_edit_draft
|
||||
.as_mut()
|
||||
.and_then(|state| state.layers.get_mut(index))
|
||||
else {
|
||||
return Task::none();
|
||||
};
|
||||
match flag {
|
||||
super::LayerStateLayerFlag::On => layer.off = !layer.off,
|
||||
super::LayerStateLayerFlag::Frozen => layer.frozen = !layer.frozen,
|
||||
super::LayerStateLayerFlag::Locked => layer.locked = !layer.locked,
|
||||
super::LayerStateLayerFlag::Plot => layer.plottable = !layer.plottable,
|
||||
super::LayerStateLayerFlag::NewViewport => {
|
||||
layer.new_viewport_frozen = !layer.new_viewport_frozen
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorLayerColorToggle(index) => {
|
||||
self.layer_state_edit_color_open = if self.layer_state_edit_color_open == Some(index)
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(index)
|
||||
};
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorLayerColor(index, color) => {
|
||||
if let Some(layer) = self
|
||||
.layer_state_edit_draft
|
||||
.as_mut()
|
||||
.and_then(|state| state.layers.get_mut(index))
|
||||
{
|
||||
layer.color = color;
|
||||
}
|
||||
self.layer_state_edit_color_open = None;
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorLayerLinetype(index, value) => {
|
||||
if let Some(layer) = self
|
||||
.layer_state_edit_draft
|
||||
.as_mut()
|
||||
.and_then(|state| state.layers.get_mut(index))
|
||||
{
|
||||
layer.line_type = value;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorLayerLineweight(index, value) => {
|
||||
if let Some(layer) = self
|
||||
.layer_state_edit_draft
|
||||
.as_mut()
|
||||
.and_then(|state| state.layers.get_mut(index))
|
||||
{
|
||||
layer.line_weight = value;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorLayerPlotStyle(index, value) => {
|
||||
if let Some(layer) = self
|
||||
.layer_state_edit_draft
|
||||
.as_mut()
|
||||
.and_then(|state| state.layers.get_mut(index))
|
||||
{
|
||||
layer.plot_style = value;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorLayerTransparency(index, value) => {
|
||||
if let Some(layer) = self
|
||||
.layer_state_edit_draft
|
||||
.as_mut()
|
||||
.and_then(|state| state.layers.get_mut(index))
|
||||
{
|
||||
layer.transparency = value;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorName(value) => {
|
||||
if let Some(state) = self.layer_state_edit_draft.as_mut() {
|
||||
state.name = value;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorDescription(value) => {
|
||||
if let Some(state) = self.layer_state_edit_draft.as_mut() {
|
||||
state.description = value;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorCurrentLayer(value) => {
|
||||
if let Some(state) = self.layer_state_edit_draft.as_mut() {
|
||||
state.current_layer = value;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorFilter(value) => {
|
||||
self.layer_state_edit_filter = value;
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorSave => {
|
||||
let i = self.active_tab;
|
||||
let Some(draft) = self.layer_state_edit_draft.as_ref() else {
|
||||
return Task::none();
|
||||
};
|
||||
let name = draft.name.trim().to_string();
|
||||
if name.is_empty() {
|
||||
self.command_line
|
||||
.push_error("Layer state name cannot be empty.");
|
||||
return Task::none();
|
||||
}
|
||||
let old_name = self.layer_state_selected.clone();
|
||||
let duplicate = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.layer_states()
|
||||
.into_iter()
|
||||
.any(|state| {
|
||||
state.name.eq_ignore_ascii_case(&name)
|
||||
&& old_name
|
||||
.as_deref()
|
||||
.is_none_or(|old| !state.name.eq_ignore_ascii_case(old))
|
||||
});
|
||||
if duplicate {
|
||||
self.command_line
|
||||
.push_error(&format!("Layer state \"{name}\" already exists."));
|
||||
return Task::none();
|
||||
}
|
||||
let Some(state) = self.layer_state_edit_draft.take() else {
|
||||
return Task::none();
|
||||
};
|
||||
let mut state = state;
|
||||
state.name.clone_from(&name);
|
||||
state.description = state.description.trim().to_string();
|
||||
let description = state.description.clone();
|
||||
self.push_undo_snapshot(i, "LAYERSTATE EDIT");
|
||||
if let Some(old_name) = old_name.as_deref() {
|
||||
if !old_name.eq_ignore_ascii_case(&name) {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.rename_layer_state(old_name, &name);
|
||||
}
|
||||
}
|
||||
self.tabs[i].scene.document.store_layer_state(state);
|
||||
self.tabs[i].dirty = true;
|
||||
self.layer_state_selected = Some(name.clone());
|
||||
self.layer_state_name_buf = name.clone();
|
||||
self.layer_state_description_buf = description;
|
||||
self.layer_state_edit_filter.clear();
|
||||
self.layer_state_edit_color_open = None;
|
||||
self.active_modal = Some(super::ModalKind::LayerStateManager);
|
||||
self.command_line
|
||||
.push_output(&format!("LAYERSTATE: updated \"{name}\"."));
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerStateEditorCancel => {
|
||||
self.layer_state_edit_draft = None;
|
||||
self.layer_state_edit_filter.clear();
|
||||
self.layer_state_edit_color_open = None;
|
||||
self.active_modal = Some(super::ModalKind::LayerStateManager);
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::WindowCloseRequested(id) => {
|
||||
if self.main_window == Some(id) {
|
||||
@@ -1867,12 +2080,22 @@ impl OpenCADStudio {
|
||||
if let Some(v) = val {
|
||||
let targets = self.layer_row_action_targets(i, idx);
|
||||
for name in &targets {
|
||||
if let Some(layer) =
|
||||
self.tabs[i].scene.document.layers.get_mut(name)
|
||||
{
|
||||
layer.transparency =
|
||||
acadrust::types::Transparency::from_percent(v as f64 / 100.0);
|
||||
}
|
||||
if let Some(pl) =
|
||||
self.tabs[i].layers.layers.iter_mut().find(|l| &l.name == name)
|
||||
{
|
||||
pl.transparency = v;
|
||||
}
|
||||
}
|
||||
if !targets.is_empty() {
|
||||
self.tabs[i].scene.invalidate_layer_dependencies(&targets);
|
||||
self.tabs[i].dirty = true;
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
@@ -991,6 +991,9 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Some(crate::app::ColorPickTarget::LayerState(idx)) => {
|
||||
Some(Message::LayerStateEditorLayerColor(idx, color))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
if let Some(m) = edit {
|
||||
|
||||
@@ -1572,6 +1572,7 @@ impl OpenCADStudio {
|
||||
UpdateNotice => (560, 460),
|
||||
Layers => (900, 360),
|
||||
LayerStateManager => (720, 420),
|
||||
LayerStateEditor => (1180, 560),
|
||||
Plot => (760, 540),
|
||||
LayoutManager => (640, 320),
|
||||
Plotstyle => (780, 540),
|
||||
|
||||
@@ -16,6 +16,7 @@ impl OpenCADStudio {
|
||||
Some(K::UpdateNotice) => "Update Available",
|
||||
Some(K::Layers) => "Layer Manager",
|
||||
Some(K::LayerStateManager) => "Layer State Manager",
|
||||
Some(K::LayerStateEditor) => "Edit Layer State",
|
||||
Some(K::Plot) => "Plot",
|
||||
Some(K::LayoutManager) => "Layout Manager",
|
||||
Some(K::ScaleManager) => "Scale Manager",
|
||||
@@ -134,6 +135,46 @@ impl OpenCADStudio {
|
||||
420,
|
||||
)
|
||||
}
|
||||
super::super::ModalKind::LayerStateEditor => {
|
||||
let tab = &self.tabs[self.active_tab];
|
||||
if let Some(state) = self.layer_state_edit_draft.as_ref() {
|
||||
let mut linetypes: Vec<String> = tab
|
||||
.scene
|
||||
.document
|
||||
.line_types
|
||||
.iter()
|
||||
.map(|line_type| line_type.name.clone())
|
||||
.collect();
|
||||
for layer in &state.layers {
|
||||
if !layer.line_type.is_empty()
|
||||
&& !linetypes
|
||||
.iter()
|
||||
.any(|name| name.eq_ignore_ascii_case(&layer.line_type))
|
||||
{
|
||||
linetypes.push(layer.line_type.clone());
|
||||
}
|
||||
}
|
||||
linetypes.sort_by_key(|name| name.to_lowercase());
|
||||
sized(
|
||||
crate::ui::window::layer_state_manager::view_editor(
|
||||
state,
|
||||
&self.layer_state_edit_filter,
|
||||
self.layer_state_edit_color_open,
|
||||
linetypes,
|
||||
),
|
||||
1180,
|
||||
560,
|
||||
)
|
||||
} else {
|
||||
sized(
|
||||
container(text("The selected layer state is no longer available."))
|
||||
.padding(16)
|
||||
.into(),
|
||||
520,
|
||||
180,
|
||||
)
|
||||
}
|
||||
}
|
||||
super::super::ModalKind::Plot => {
|
||||
sized(crate::ui::window::plot::view_window(&self.plot_dialog), 760, 540)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user