forked from 1b-agent/opencadstudio-upstream
Block Attribute Manager window (BATTMAN / ATTMAN)
BATTMAN and ATTMAN open a manager for the attribute definitions of one attributed block: block chips with reference counts and a pick button, a table whose columns are chosen with chips, move up/down, remove, and an edit card (Attribute / Text / Properties) for the selected row. Apply, OK and Sync write the list back to the block definition and, when asked, rebuild the existing references keeping values through tag renames; each is one undo step. Live changes are taken back on Cancel. Automation gains attman_dialog. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
39c3e9af58
commit
4726c775bf
35 files changed
+2083
-6
No files matched your search
@@ -6609,3 +6609,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6597,3 +6597,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6594,3 +6594,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6595,3 +6595,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6597,3 +6597,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6596,3 +6596,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6597,3 +6597,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: introduce 0 (conservar vista) o 1 (seguir SCP) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activa una ventana de modelo; no se aplica al espacio papel.
|
||||
.invalid = UCSFOLLOW: solo se permite 0 o 1.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6594,3 +6594,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6597,3 +6597,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6585,3 +6585,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6581,3 +6581,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6596,3 +6596,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6585,3 +6585,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6596,3 +6596,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6597,3 +6597,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6595,3 +6595,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6596,3 +6596,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6597,3 +6597,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6598,3 +6598,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6518,3 +6518,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Öznitelik Yöneticisi
|
||||
.modes = Kipler
|
||||
.references = __ocs_fmt_0__ referans
|
||||
.counts = Çizimde __ocs_fmt_0__ · model alanında __ocs_fmt_1__
|
||||
.columns = Sütunlar:
|
||||
.constant-note = Sabit kipi tanımda değiştirilemez.
|
||||
.live = Değişiklikleri çizimde canlı göster
|
||||
.apply-existing = Mevcut referanslara uygula
|
||||
.emphasize = Yinelenen etiketleri vurgula
|
||||
.sync = Eşitle
|
||||
.help = BATTMAN bir bloğun öznitelik tanımlarını yönetir.
|
||||
.no-attributed-block = Blok tablosunda __ocs_fmt_0__ adlı öznitelikli blok yok.
|
||||
@@ -6580,3 +6580,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -6592,3 +6592,17 @@ ucs-follow =
|
||||
.prompt = UCSFOLLOW: enter 0 (keep view) or 1 (follow UCS) <__ocs_fmt_0__>:
|
||||
.paper-space = UCSFOLLOW: activate a model viewport; paper space cannot follow the UCS.
|
||||
.invalid = UCSFOLLOW: only 0 or 1 is allowed.
|
||||
|
||||
attman =
|
||||
.title = Block Attribute Manager
|
||||
.modes = Modes
|
||||
.references = __ocs_fmt_0__ references
|
||||
.counts = In drawing: __ocs_fmt_0__ · in model space: __ocs_fmt_1__
|
||||
.columns = Columns:
|
||||
.constant-note = The Constant mode cannot be changed in the definition.
|
||||
.live = Show changes in the drawing as they are made
|
||||
.apply-existing = Apply changes to existing references
|
||||
.emphasize = Emphasize duplicate tags
|
||||
.sync = Sync
|
||||
.help = BATTMAN manages the attribute definitions of a block.
|
||||
.no-attributed-block = Block table contains no attributed block named __ocs_fmt_0__.
|
||||
@@ -0,0 +1,548 @@
|
||||
//! Block Attribute Manager (BATTMAN / ATTMAN): loading an attributed block's
|
||||
//! definitions into the dialog and writing the edited list back to the
|
||||
//! block definition and, when asked, to its existing references.
|
||||
|
||||
use codec::entities::AttributeDefinition;
|
||||
use codec::{EntityType, Handle};
|
||||
use iced::Task;
|
||||
|
||||
use crate::app::{Message, OpenCADStudio};
|
||||
use crate::modules::insert::block_cmdline::BlockTable;
|
||||
use crate::scene::view::dispatch::{apply_common_prop, apply_geom_prop};
|
||||
use crate::ui::window::attman_dialog::{
|
||||
self as dialog, AttManBlock, AttManMsg, AttManRow, AttManState, EditTab,
|
||||
};
|
||||
|
||||
impl OpenCADStudio {
|
||||
/// Open the dialog on the block of the first preselected attributed
|
||||
/// reference, else on the first attributed block.
|
||||
pub(in crate::app) fn open_attman(&mut self, i: usize, preselected: &[Handle]) -> Task<Message> {
|
||||
let document = &self.tabs[i].scene.document;
|
||||
let table = BlockTable::of(document);
|
||||
let model = document
|
||||
.block_records
|
||||
.get("*Model_Space")
|
||||
.map_or(Handle::NULL, |br| br.handle);
|
||||
let blocks: Vec<AttManBlock> = table
|
||||
.attributed
|
||||
.iter()
|
||||
.map(|name| {
|
||||
let mut found = 0;
|
||||
let mut in_space = 0;
|
||||
for entity in document.entities() {
|
||||
if let EntityType::Insert(insert) = entity {
|
||||
if insert.block_name.eq_ignore_ascii_case(name) {
|
||||
found += 1;
|
||||
if insert.common.owner_handle == model {
|
||||
in_space += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AttManBlock {
|
||||
name: name.clone(),
|
||||
found,
|
||||
in_space,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let start = preselected
|
||||
.iter()
|
||||
.find_map(|h| match document.get_entity(*h) {
|
||||
Some(EntityType::Insert(insert)) => blocks
|
||||
.iter()
|
||||
.position(|b| b.name.eq_ignore_ascii_case(&insert.block_name)),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(0);
|
||||
let mut styles: Vec<String> = document
|
||||
.text_styles
|
||||
.iter()
|
||||
.filter(|s| !s.name.is_empty())
|
||||
.map(|s| s.name.clone())
|
||||
.collect();
|
||||
styles.sort_by_key(|s| s.to_lowercase());
|
||||
let layers: Vec<String> = document.layers.iter().map(|l| l.name.clone()).collect();
|
||||
let linetypes: Vec<String> = document
|
||||
.line_types
|
||||
.iter()
|
||||
.map(|lt| lt.name.clone())
|
||||
.filter(|n| !n.eq_ignore_ascii_case("ByLayer") && !n.eq_ignore_ascii_case("ByBlock"))
|
||||
.collect();
|
||||
self.attman = Some(AttManState {
|
||||
blocks,
|
||||
block: start,
|
||||
rows: Vec::new(),
|
||||
removed: Vec::new(),
|
||||
selected: None,
|
||||
tab: EditTab::Attribute,
|
||||
edit_open: true,
|
||||
drafts: Default::default(),
|
||||
dirty: false,
|
||||
live_steps: 0,
|
||||
more_columns: false,
|
||||
styles,
|
||||
layers,
|
||||
linetypes,
|
||||
error: None,
|
||||
});
|
||||
self.attman_load(i);
|
||||
self.tabs[i].active_cmd = None;
|
||||
self.active_modal = Some(crate::app::ModalKind::AttMan);
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// Read the shown block's attribute definitions, in block order.
|
||||
fn attman_load(&mut self, i: usize) {
|
||||
let document = &self.tabs[i].scene.document;
|
||||
let Some(state) = self.attman.as_mut() else {
|
||||
return;
|
||||
};
|
||||
let Some(name) = state.current_block().map(|b| b.name.clone()) else {
|
||||
return;
|
||||
};
|
||||
state.rows = document
|
||||
.block_records
|
||||
.get(&name)
|
||||
.map(|br| {
|
||||
br.entity_handles
|
||||
.iter()
|
||||
.filter_map(|h| match document.get_entity(*h) {
|
||||
Some(EntityType::AttributeDefinition(def)) => Some(AttManRow {
|
||||
handle: *h,
|
||||
original_tag: def.tag.clone(),
|
||||
def: def.clone(),
|
||||
}),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
state.removed.clear();
|
||||
state.dirty = false;
|
||||
state.selected = (!state.rows.is_empty()).then_some(0);
|
||||
state.load_drafts();
|
||||
}
|
||||
|
||||
pub(in crate::app) fn on_attman(&mut self, m: AttManMsg) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
let Some(state) = self.attman.as_mut() else {
|
||||
return Task::none();
|
||||
};
|
||||
// Edits of the selected row.
|
||||
let mut edited = true;
|
||||
let at = state.selected;
|
||||
match m {
|
||||
AttManMsg::Block(index) => {
|
||||
if index == state.block || index >= state.blocks.len() {
|
||||
return Task::none();
|
||||
}
|
||||
// Pending changes of the shown block are kept.
|
||||
if state.dirty && !self.attman_commit(i, true, false) {
|
||||
return Task::none();
|
||||
}
|
||||
if let Some(state) = self.attman.as_mut() {
|
||||
state.block = index;
|
||||
}
|
||||
self.attman_load(i);
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::PickBlock => {
|
||||
self.active_modal = None;
|
||||
let command = crate::modules::insert::attman::AttmanPickCommand;
|
||||
use crate::command::CadCommand as _;
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Select(index) => {
|
||||
if index < state.rows.len() {
|
||||
state.selected = Some(index);
|
||||
state.load_drafts();
|
||||
}
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::MoveUp | AttManMsg::MoveDown => {
|
||||
let Some(at) = at else {
|
||||
return Task::none();
|
||||
};
|
||||
let to = if matches!(m, AttManMsg::MoveUp) {
|
||||
at.checked_sub(1)
|
||||
} else {
|
||||
Some(at + 1).filter(|t| *t < state.rows.len())
|
||||
};
|
||||
let Some(to) = to else {
|
||||
return Task::none();
|
||||
};
|
||||
state.rows.swap(at, to);
|
||||
state.selected = Some(to);
|
||||
}
|
||||
AttManMsg::Remove => {
|
||||
let Some(at) = at else {
|
||||
return Task::none();
|
||||
};
|
||||
if state.rows.len() < 2 {
|
||||
return Task::none();
|
||||
}
|
||||
let row = state.rows.remove(at);
|
||||
state.removed.push(row.handle);
|
||||
state.selected = Some(at.min(state.rows.len() - 1));
|
||||
state.load_drafts();
|
||||
}
|
||||
AttManMsg::ToggleEdit => {
|
||||
state.edit_open = !state.edit_open;
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Tab(tab) => {
|
||||
state.tab = tab;
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::MoreColumns => {
|
||||
state.more_columns = !state.more_columns;
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Column(column, on) => {
|
||||
let bit = 1u32 << (column as u32);
|
||||
let mut prefs = dialog::prefs();
|
||||
prefs.columns = if on {
|
||||
prefs.columns | bit
|
||||
} else {
|
||||
prefs.columns & !bit
|
||||
};
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::ApplyExisting(on) => {
|
||||
dialog::prefs().apply_existing = on;
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Emphasize(on) => {
|
||||
dialog::prefs().emphasize_duplicates = on;
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Live(on) => {
|
||||
dialog::prefs().live = on;
|
||||
if on && state.dirty {
|
||||
self.attman_commit(i, false, false);
|
||||
}
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::DismissError => {
|
||||
state.error = None;
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Help => {
|
||||
self.command_line.push_info(
|
||||
crate::t!("BATTMAN manages the attribute definitions of a block.").as_ref(),
|
||||
);
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Sync => {
|
||||
self.attman_commit(i, true, true);
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Apply => {
|
||||
self.attman_commit(i, true, false);
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Ok => {
|
||||
if self.attman_commit(i, true, false) {
|
||||
self.attman = None;
|
||||
self.close_active_modal();
|
||||
}
|
||||
return Task::none();
|
||||
}
|
||||
AttManMsg::Cancel => {
|
||||
let steps = state.live_steps;
|
||||
self.attman = None;
|
||||
self.close_active_modal();
|
||||
if steps > 0 {
|
||||
self.undo_steps(steps);
|
||||
}
|
||||
return Task::none();
|
||||
}
|
||||
_ => {
|
||||
edited = false;
|
||||
}
|
||||
}
|
||||
if edited {
|
||||
state.dirty = true;
|
||||
return self.attman_after_edit(i);
|
||||
}
|
||||
// Field edits of the selected row.
|
||||
let Some(row) = at.and_then(|at| state.rows.get_mut(at)) else {
|
||||
return Task::none();
|
||||
};
|
||||
let def = &mut row.def;
|
||||
let yes = |on: bool| if on { "Yes" } else { "No" };
|
||||
match m {
|
||||
AttManMsg::Tag(value) => {
|
||||
state.drafts.tag = value.clone();
|
||||
if crate::ui::window::attdef_dialog::tag_error(&value).is_none() {
|
||||
geom(def, "att_tag", &value);
|
||||
}
|
||||
}
|
||||
AttManMsg::Prompt(value) => geom(def, "att_prompt", &value),
|
||||
AttManMsg::Default(value) => geom(def, "att_default", &value),
|
||||
AttManMsg::Mode(key, on) => {
|
||||
let field = match key {
|
||||
"invisible" => "att_invisible",
|
||||
"verify" => "att_verify",
|
||||
"preset" => "att_preset",
|
||||
"multiline" => "att_multiline",
|
||||
_ => return Task::none(),
|
||||
};
|
||||
geom(def, field, yes(on));
|
||||
}
|
||||
AttManMsg::Style(value) => geom(def, "att_style", &value),
|
||||
AttManMsg::Justify(justify) => geom(def, "att_justify", justify.label()),
|
||||
AttManMsg::Height(value) => {
|
||||
state.drafts.height = value.clone();
|
||||
geom(def, "att_h", &value);
|
||||
}
|
||||
AttManMsg::Rotation(value) => {
|
||||
state.drafts.rotation = value.clone();
|
||||
geom(def, "att_rot", &value);
|
||||
}
|
||||
AttManMsg::Width(value) => {
|
||||
state.drafts.width = value.clone();
|
||||
geom(def, "att_wf", &value);
|
||||
}
|
||||
AttManMsg::Oblique(value) => {
|
||||
state.drafts.oblique = value.clone();
|
||||
geom(def, "att_ob", &value);
|
||||
}
|
||||
AttManMsg::Boundary(value) => {
|
||||
state.drafts.boundary = value.clone();
|
||||
geom(def, "att_bwidth", &value);
|
||||
}
|
||||
AttManMsg::Annotative(on) => geom(def, "att_annotative", yes(on)),
|
||||
AttManMsg::Backwards(on) => geom(def, "att_backward", yes(on)),
|
||||
AttManMsg::UpsideDown(on) => geom(def, "att_upside_down", yes(on)),
|
||||
AttManMsg::Layer(value) => common(def, "layer", &value),
|
||||
AttManMsg::Linetype(value) => common(def, "linetype", &value),
|
||||
AttManMsg::Color(value) => {
|
||||
if let Some(color) = dialog::parse_color(&value) {
|
||||
def.common.color = color;
|
||||
}
|
||||
}
|
||||
AttManMsg::Lineweight(value) => {
|
||||
if let Some(lw) = dialog::parse_lineweight(&value) {
|
||||
def.common.line_weight = lw;
|
||||
}
|
||||
}
|
||||
_ => return Task::none(),
|
||||
}
|
||||
state.dirty = true;
|
||||
self.attman_after_edit(i)
|
||||
}
|
||||
|
||||
fn attman_after_edit(&mut self, i: usize) -> Task<Message> {
|
||||
if dialog::prefs().live {
|
||||
self.attman_commit(i, false, false);
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// The pick of `_ATTMAN_PICK <hex handle>`: show the picked reference's
|
||||
/// block. A reference of a block without attributes is reported.
|
||||
pub(in crate::app) fn attman_picked(&mut self, i: usize, handle: &str) -> Task<Message> {
|
||||
self.active_modal = Some(crate::app::ModalKind::AttMan);
|
||||
let Ok(value) = u64::from_str_radix(handle, 16) else {
|
||||
return Task::none();
|
||||
};
|
||||
let name = match self.tabs[i].scene.document.get_entity(Handle::new(value)) {
|
||||
Some(EntityType::Insert(insert)) => insert.block_name.clone(),
|
||||
_ => return Task::none(),
|
||||
};
|
||||
let index = self.attman.as_ref().and_then(|state| {
|
||||
state
|
||||
.blocks
|
||||
.iter()
|
||||
.position(|b| b.name.eq_ignore_ascii_case(&name))
|
||||
});
|
||||
match index {
|
||||
Some(index) => self.on_attman(AttManMsg::Block(index)),
|
||||
None => {
|
||||
if let Some(state) = self.attman.as_mut() {
|
||||
state.error = Some(
|
||||
crate::tf!("Block table contains no attributed block named {}.", name)
|
||||
.into_owned(),
|
||||
);
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the working copy to the drawing. `finish` closes the undo step
|
||||
/// (Apply / OK / Sync); otherwise the step stays open for the next live
|
||||
/// edit. `sync` rebuilds the references' attributes even when "apply to
|
||||
/// existing references" is off. Returns false when a field is invalid.
|
||||
fn attman_commit(&mut self, i: usize, finish: bool, sync: bool) -> bool {
|
||||
let Some(state) = self.attman.as_mut() else {
|
||||
return false;
|
||||
};
|
||||
if finish {
|
||||
if let Some(error) = state
|
||||
.rows
|
||||
.iter()
|
||||
.find_map(|row| crate::ui::window::attdef_dialog::tag_error(&row.def.tag))
|
||||
.or_else(|| {
|
||||
crate::ui::window::attdef_dialog::tag_error(&state.drafts.tag)
|
||||
.filter(|_| state.selected.is_some())
|
||||
})
|
||||
{
|
||||
state.error = Some(crate::t!(error).into_owned());
|
||||
return false;
|
||||
}
|
||||
state.error = None;
|
||||
}
|
||||
let Some(name) = state.current_block().map(|b| b.name.clone()) else {
|
||||
return false;
|
||||
};
|
||||
let rows: Vec<(Handle, String, AttributeDefinition)> = state
|
||||
.rows
|
||||
.iter()
|
||||
.map(|r| (r.handle, r.original_tag.clone(), r.def.clone()))
|
||||
.collect();
|
||||
let removed = state.removed.clone();
|
||||
let write = state.dirty || sync;
|
||||
let open = state.live_steps > 0 && self.tabs[i].history.pending.is_some();
|
||||
if write {
|
||||
// One undo step; a live step something else closed starts anew.
|
||||
if !open {
|
||||
self.push_undo_snapshot(i, "BATTMAN");
|
||||
}
|
||||
self.attman_write(i, &name, &rows, &removed, sync || dialog::prefs().apply_existing);
|
||||
}
|
||||
let Some(state) = self.attman.as_mut() else {
|
||||
return false;
|
||||
};
|
||||
if finish {
|
||||
if state.live_steps > 0 || write {
|
||||
self.finish_pending_history(i);
|
||||
}
|
||||
if let Some(state) = self.attman.as_mut() {
|
||||
state.live_steps = 0;
|
||||
state.dirty = false;
|
||||
state.removed.clear();
|
||||
for row in &mut state.rows {
|
||||
row.original_tag = row.def.tag.clone();
|
||||
}
|
||||
}
|
||||
} else if write {
|
||||
if !open {
|
||||
state.live_steps += 1;
|
||||
}
|
||||
// The references now hold the written tags.
|
||||
if sync || dialog::prefs().apply_existing {
|
||||
for row in &mut state.rows {
|
||||
row.original_tag = row.def.tag.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// The definition list of `block` becomes `rows` (in that order) less
|
||||
/// `removed`; with `sync`, every reference is rebuilt from it, keeping
|
||||
/// each attribute's value through a tag rename.
|
||||
fn attman_write(
|
||||
&mut self,
|
||||
i: usize,
|
||||
block: &str,
|
||||
rows: &[(Handle, String, AttributeDefinition)],
|
||||
removed: &[Handle],
|
||||
sync: bool,
|
||||
) {
|
||||
let document = &mut self.tabs[i].scene.document;
|
||||
for handle in removed {
|
||||
if document.get_entity(*handle).is_some() {
|
||||
document.remove_entity(*handle);
|
||||
}
|
||||
}
|
||||
// Each definition keeps its object; the definitions take the slots
|
||||
// the block's definitions held, in the new order.
|
||||
for (handle, _, def) in rows {
|
||||
if let Some(EntityType::AttributeDefinition(slot)) = document.get_entity_mut(*handle) {
|
||||
let mut def = def.clone();
|
||||
def.common.handle = *handle;
|
||||
def.common.owner_handle = slot.common.owner_handle;
|
||||
*slot = def;
|
||||
}
|
||||
}
|
||||
if let Some(br) = document.block_records.get_mut(block) {
|
||||
br.entity_handles.retain(|h| !removed.contains(h));
|
||||
let mut order = rows.iter().map(|(handle, _, _)| *handle);
|
||||
for slot in br.entity_handles.iter_mut() {
|
||||
if rows.iter().any(|(handle, _, _)| handle == slot) {
|
||||
if let Some(next) = order.next() {
|
||||
*slot = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Annotative definitions carry the scale context data.
|
||||
for (handle, _, def) in rows {
|
||||
crate::scene::annotative::set_entity_annotative(
|
||||
&mut self.tabs[i].scene.document,
|
||||
*handle,
|
||||
def.flags.annotative,
|
||||
);
|
||||
}
|
||||
if sync {
|
||||
// A renamed definition keeps the value each reference held.
|
||||
let renames: Vec<(String, String)> = rows
|
||||
.iter()
|
||||
.filter(|(_, old, def)| !old.eq_ignore_ascii_case(&def.tag))
|
||||
.map(|(_, old, def)| (old.clone(), def.tag.clone()))
|
||||
.collect();
|
||||
if !renames.is_empty() {
|
||||
let inserts: Vec<Handle> = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.entities()
|
||||
.filter_map(|e| match e {
|
||||
EntityType::Insert(ins) if ins.block_name.eq_ignore_ascii_case(block) => {
|
||||
Some(ins.common.handle)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
for handle in inserts {
|
||||
if let Some(EntityType::Insert(ins)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
for attribute in &mut ins.attributes {
|
||||
if let Some((_, new)) = renames
|
||||
.iter()
|
||||
.find(|(old, _)| old.eq_ignore_ascii_case(&attribute.tag))
|
||||
{
|
||||
attribute.tag = new.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.attsync_block_with(i, block, false);
|
||||
}
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
self.tabs[i].dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn geom(def: &mut AttributeDefinition, field: &str, value: &str) {
|
||||
let mut entity = EntityType::AttributeDefinition(def.clone());
|
||||
apply_geom_prop(&mut entity, field, value);
|
||||
if let EntityType::AttributeDefinition(updated) = entity {
|
||||
*def = updated;
|
||||
}
|
||||
}
|
||||
|
||||
fn common(def: &mut AttributeDefinition, field: &str, value: &str) {
|
||||
let mut entity = EntityType::AttributeDefinition(def.clone());
|
||||
apply_common_prop(&mut entity, field, value);
|
||||
if let EntityType::AttributeDefinition(updated) = entity {
|
||||
*def = updated;
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,12 @@ impl OpenCADStudio {
|
||||
.push_output("This drawing contains no attributed blocks.");
|
||||
return Some(Task::none());
|
||||
}
|
||||
self.open_attedit_dialog();
|
||||
let preselected = self.tabs[i].scene.selected_handles_in_order();
|
||||
return Some(self.open_attman(i, &preselected));
|
||||
}
|
||||
cmd if cmd == "_ATTMAN_PICK" || cmd.starts_with("_ATTMAN_PICK ") => {
|
||||
self.tabs[i].active_cmd = None;
|
||||
return Some(self.attman_picked(i, cmd["_ATTMAN_PICK".len()..].trim()));
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
@@ -166,6 +171,11 @@ impl OpenCADStudio {
|
||||
/// attributes whose definition is gone are dropped. Constant definitions
|
||||
/// carry no attribute.
|
||||
pub(in crate::app) fn attsync_block(&mut self, i: usize, block: &str) {
|
||||
self.attsync_block_with(i, block, true);
|
||||
}
|
||||
|
||||
/// [`Self::attsync_block`], opening its own undo step only when `undo`.
|
||||
pub(in crate::app) fn attsync_block_with(&mut self, i: usize, block: &str, undo: bool) {
|
||||
use codec::Entity as _;
|
||||
let doc = &self.tabs[i].scene.document;
|
||||
let attdefs: Vec<codec::entities::AttributeDefinition> = doc
|
||||
@@ -200,7 +210,9 @@ impl OpenCADStudio {
|
||||
if inserts.is_empty() {
|
||||
return;
|
||||
}
|
||||
self.push_undo_snapshot(i, "ATTSYNC");
|
||||
if undo {
|
||||
self.push_undo_snapshot(i, "ATTSYNC");
|
||||
}
|
||||
let mut changes = Vec::new();
|
||||
for handle in inserts {
|
||||
let document = &self.tabs[i].scene.document;
|
||||
|
||||
@@ -1731,9 +1731,9 @@ mod tests {
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
// ATTMAN and BATTMAN are the Block Attribute Manager; this build routes both
|
||||
// to the attribute editor (ATTEDIT). A drawing without attributed blocks
|
||||
// has nothing to manage, which both report instead of opening it.
|
||||
// ATTMAN and BATTMAN open the Block Attribute Manager. A drawing without
|
||||
// attributed blocks has nothing to manage, which both report instead of
|
||||
// opening it.
|
||||
#[test]
|
||||
fn attman_and_battman_report_a_drawing_without_attributed_blocks() {
|
||||
for command in ["ATTMAN", "BATTMAN"] {
|
||||
|
||||
@@ -5,6 +5,7 @@ use iced::Task;
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod attdef;
|
||||
mod attman;
|
||||
mod block_cmdline;
|
||||
mod blocks;
|
||||
mod blockvars;
|
||||
|
||||
@@ -120,6 +120,7 @@ pub(super) const NAMES: &[&str] = &[
|
||||
"dialog_ok",
|
||||
"attdef_dialog",
|
||||
"field_dialog",
|
||||
"attman_dialog",
|
||||
"sheet_set",
|
||||
"close_document",
|
||||
"toggle_properties",
|
||||
@@ -1547,6 +1548,96 @@ impl OpenCADStudio {
|
||||
_ => return Err(failure("invalid_value", "Unknown attdef dialog field")),
|
||||
})
|
||||
}
|
||||
// The open Block Attribute Manager: `block=<name>`, `select=<row>`,
|
||||
// `up`, `down`, `remove`, `edit`, `tab=attribute|text|properties`,
|
||||
// `tag=…`, `prompt=…`, `default=…`, `mode=<invisible|verify|preset|multiline>:0|1`,
|
||||
// `style=…`, `justify=MC`, `height=…`, `rotation=…`, `width=…`, `oblique=…`,
|
||||
// `boundary=…`, `annotative=0|1`, `backwards=0|1`, `upside_down=0|1`,
|
||||
// `layer=…`, `linetype=…`, `color=…`, `lineweight=…`, `column=<name>:0|1`,
|
||||
// `more_columns`, `apply_existing=0|1`, `emphasize=0|1`, `live=0|1`,
|
||||
// `pick`, `sync`, `apply`, `ok`, `cancel`.
|
||||
"attman_dialog" => {
|
||||
use crate::ui::window::attman_dialog::{AttManMsg as A, Column, EditTab};
|
||||
let Some(state) = self.attman.as_ref() else {
|
||||
return Err(failure("no_dialog", "The attribute manager is not open"));
|
||||
};
|
||||
let value = string(req, "value")?;
|
||||
let (key, v) = value.split_once('=').unwrap_or((value, ""));
|
||||
let on = v == "1";
|
||||
Message::AttMan(match key {
|
||||
"block" => A::Block(
|
||||
state
|
||||
.blocks
|
||||
.iter()
|
||||
.position(|b| b.name.eq_ignore_ascii_case(v))
|
||||
.ok_or_else(|| failure("invalid_value", "No such attributed block"))?,
|
||||
),
|
||||
"select" => A::Select(
|
||||
v.parse()
|
||||
.ok()
|
||||
.filter(|r: &usize| *r < state.rows.len())
|
||||
.ok_or_else(|| failure("invalid_value", "No such row"))?,
|
||||
),
|
||||
"up" => A::MoveUp,
|
||||
"down" => A::MoveDown,
|
||||
"remove" => A::Remove,
|
||||
"edit" => A::ToggleEdit,
|
||||
"tab" => A::Tab(match v {
|
||||
"text" => EditTab::Text,
|
||||
"properties" => EditTab::Properties,
|
||||
_ => EditTab::Attribute,
|
||||
}),
|
||||
"tag" => A::Tag(v.into()),
|
||||
"prompt" => A::Prompt(v.into()),
|
||||
"default" => A::Default(v.into()),
|
||||
"mode" => {
|
||||
let (mode, state) = v.split_once(':').unwrap_or((v, "1"));
|
||||
let mode = match mode {
|
||||
"invisible" => "invisible",
|
||||
"verify" => "verify",
|
||||
"preset" => "preset",
|
||||
"multiline" => "multiline",
|
||||
_ => return Err(failure("invalid_value", "Unknown mode")),
|
||||
};
|
||||
A::Mode(mode, state == "1")
|
||||
}
|
||||
"style" => A::Style(v.into()),
|
||||
"justify" => A::Justify(
|
||||
crate::modules::draw::draw::attdef::Justify::from_keyword(v)
|
||||
.ok_or_else(|| failure("invalid_value", "Unknown justification"))?,
|
||||
),
|
||||
"height" => A::Height(v.into()),
|
||||
"rotation" => A::Rotation(v.into()),
|
||||
"width" => A::Width(v.into()),
|
||||
"oblique" => A::Oblique(v.into()),
|
||||
"boundary" => A::Boundary(v.into()),
|
||||
"annotative" => A::Annotative(on),
|
||||
"backwards" => A::Backwards(on),
|
||||
"upside_down" => A::UpsideDown(on),
|
||||
"layer" => A::Layer(v.into()),
|
||||
"linetype" => A::Linetype(v.into()),
|
||||
"color" => A::Color(v.into()),
|
||||
"lineweight" => A::Lineweight(v.into()),
|
||||
"column" => {
|
||||
let (name, state) = v.split_once(':').unwrap_or((v, "1"));
|
||||
A::Column(
|
||||
Column::from_name(name)
|
||||
.ok_or_else(|| failure("invalid_value", "Unknown column"))?,
|
||||
state == "1",
|
||||
)
|
||||
}
|
||||
"more_columns" => A::MoreColumns,
|
||||
"apply_existing" => A::ApplyExisting(on),
|
||||
"emphasize" => A::Emphasize(on),
|
||||
"live" => A::Live(on),
|
||||
"pick" => A::PickBlock,
|
||||
"sync" => A::Sync,
|
||||
"apply" => A::Apply,
|
||||
"ok" => A::Ok,
|
||||
"cancel" => A::Cancel,
|
||||
_ => return Err(failure("invalid_value", "Unknown attribute manager field")),
|
||||
})
|
||||
}
|
||||
// One field of the open Field dialog: `category=<index>`, `name=Date`,
|
||||
// `date=yyyy-MM-dd`, `case=0..4`, `file=1|2|3`, `ext=0|1`, `size=0..2`,
|
||||
// `sysvar=dimscale`, `diesel=…`, `named_type=<index>`, `named=<index>`,
|
||||
@@ -2119,6 +2210,9 @@ impl OpenCADStudio {
|
||||
Some(crate::app::ModalKind::Field) => {
|
||||
Message::FieldDialog(crate::ui::window::field_dialog::FieldDialogMsg::Ok)
|
||||
}
|
||||
Some(crate::app::ModalKind::AttMan) => {
|
||||
Message::AttMan(crate::ui::window::attman_dialog::AttManMsg::Ok)
|
||||
}
|
||||
_ => return Err(failure("no_dialog", "No dialog with an OK button is open")),
|
||||
},
|
||||
"close_document" => Message::TabClose(self.tabs[self.active_tab].id),
|
||||
|
||||
@@ -585,6 +585,8 @@ pub(super) struct OpenCADStudio {
|
||||
/// ATTDEF dialog and Edit Attribute Definition dialog; `None` while closed.
|
||||
attdef_dialog: Option<crate::ui::window::attdef_dialog::AttdefDialogState>,
|
||||
attdef_edit: Option<crate::ui::window::attdef_dialog::AttdefEditState>,
|
||||
/// Block Attribute Manager working copy; `None` while it is closed.
|
||||
attman: Option<crate::ui::window::attman_dialog::AttManState>,
|
||||
/// Field dialog working copy; `None` while closed.
|
||||
field_dialog: Option<crate::ui::window::field_dialog::FieldDialogState>,
|
||||
point_cloud_color_map: Option<crate::ui::window::pdf_dialogs::PointCloudColorMapState>,
|
||||
@@ -2184,6 +2186,8 @@ pub enum ModalKind {
|
||||
GeometricTolerance,
|
||||
AttDef,
|
||||
AttDefEdit,
|
||||
/// Block Attribute Manager (BATTMAN / ATTMAN).
|
||||
AttMan,
|
||||
CountInvalidArea,
|
||||
Field,
|
||||
DraftingSettings,
|
||||
@@ -4395,6 +4399,8 @@ pub enum Message {
|
||||
/// An edit in one of the PDF dialogs.
|
||||
PdfDialog(crate::ui::window::pdf_dialogs::PdfDialogMsg),
|
||||
AttdefDialog(crate::ui::window::attdef_dialog::AttdefDialogMsg),
|
||||
/// Block Attribute Manager edits.
|
||||
AttMan(crate::ui::window::attman_dialog::AttManMsg),
|
||||
FieldDialog(crate::ui::window::field_dialog::FieldDialogMsg),
|
||||
/// An edit in the Edit Reference dialog.
|
||||
RefEditDialog(crate::ui::window::refedit_dialog::RefEditDialogMsg),
|
||||
@@ -4607,6 +4613,7 @@ impl OpenCADStudio {
|
||||
pdf_attach: None,
|
||||
point_cloud_attach: None,
|
||||
attdef_dialog: None,
|
||||
attman: None,
|
||||
attdef_edit: None,
|
||||
field_dialog: None,
|
||||
point_cloud_color_map: None,
|
||||
|
||||
@@ -232,6 +232,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
Some(GeometricTolerance) => self.geometric_tolerance = None,
|
||||
Some(BlockDefinition) => self.block_definition = None,
|
||||
Some(AttMan) => self.attman = None,
|
||||
Some(BlockEditPicker) => self.block_edit_picker = None,
|
||||
Some(BlockSaveAs) => self.block_save_as = None,
|
||||
Some(PdfAttach) => self.pdf_attach = None,
|
||||
@@ -2407,6 +2408,7 @@ impl OpenCADStudio {
|
||||
|
||||
Message::PdfDialog(message) => self.update_pdf_dialog(message),
|
||||
Message::AttdefDialog(message) => self.on_attdef_dialog(message),
|
||||
Message::AttMan(message) => self.on_attman(message),
|
||||
Message::FieldDialog(message) => self.on_field_dialog(message),
|
||||
Message::RefEditDialog(message) => self.update_refedit_dialog(message),
|
||||
Message::PcManager(message) => self.update_pc_manager(message),
|
||||
@@ -9571,6 +9573,13 @@ impl OpenCADStudio {
|
||||
self.close_field_dialog();
|
||||
return Task::none();
|
||||
}
|
||||
// Closing the attribute manager is its Cancel: live changes
|
||||
// are taken back.
|
||||
if self.active_modal == Some(super::ModalKind::AttMan) {
|
||||
return self.on_attman(
|
||||
crate::ui::window::attman_dialog::AttManMsg::Cancel,
|
||||
);
|
||||
}
|
||||
if matches!(
|
||||
self.active_modal,
|
||||
Some(super::ModalKind::AttDef | super::ModalKind::AttDefEdit)
|
||||
|
||||
@@ -52,6 +52,7 @@ impl OpenCADStudio {
|
||||
Some(K::GeometricTolerance) => crate::t!("Geometric Tolerance").into_owned(),
|
||||
Some(K::AttDef) => crate::t!("Attribute Definition").into_owned(),
|
||||
Some(K::AttDefEdit) => crate::t!("Edit Attribute Definition").into_owned(),
|
||||
Some(K::AttMan) => crate::t!("Block Attribute Manager").into_owned(),
|
||||
Some(K::CountInvalidArea) => crate::t!("Count - Invalid Area").into_owned(),
|
||||
Some(K::Field) => crate::t!("Field").into_owned(),
|
||||
Some(K::DraftingSettings) => crate::t!("Drafting Settings").into_owned(),
|
||||
@@ -629,6 +630,12 @@ impl OpenCADStudio {
|
||||
super::super::ModalKind::CountInvalidArea => sized_flow(ex, 520, 260, |flow| {
|
||||
crate::ui::window::count_palette::invalid_area_view(&self.count_palette, flow)
|
||||
}),
|
||||
super::super::ModalKind::AttMan => {
|
||||
let state = self.attman.as_ref()?;
|
||||
sized_flow(ex, 880, 660, |flow| {
|
||||
crate::ui::window::attman_dialog::view(state, flow)
|
||||
})
|
||||
}
|
||||
super::super::ModalKind::AttDefEdit => {
|
||||
let state = self.attdef_edit.as_ref()?;
|
||||
sized_flow(ex, 460, 220, |flow| {
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
|
||||
pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static str)> {
|
||||
match source {
|
||||
"Block Attribute Manager" => Some(("attman", "title")),
|
||||
"Modes" => Some(("attman", "modes")),
|
||||
"{} references" => Some(("attman", "references")),
|
||||
"In drawing: {} · in model space: {}" => Some(("attman", "counts")),
|
||||
"Columns:" => Some(("attman", "columns")),
|
||||
"The Constant mode cannot be changed in the definition." => Some(("attman", "constant-note")),
|
||||
"Show changes in the drawing as they are made" => Some(("attman", "live")),
|
||||
"Apply changes to existing references" => Some(("attman", "apply-existing")),
|
||||
"Emphasize duplicate tags" => Some(("attman", "emphasize")),
|
||||
"Sync" => Some(("attman", "sync")),
|
||||
"BATTMAN manages the attribute definitions of a block." => Some(("attman", "help")),
|
||||
"Block table contains no attributed block named {}." => Some(("attman", "no-attributed-block")),
|
||||
"{} entities added" => Some(("ref-edit", "entities-added")),
|
||||
"Use REFCLOSE or the Refedit toolbar to end reference editing session." => Some(("ref-edit", "use-refclose")),
|
||||
"Specify opposite corner:" => Some(("ref-edit", "opposite-corner")),
|
||||
|
||||
@@ -8,3 +8,44 @@ pub fn tool() -> ToolDef {
|
||||
event: ModuleEvent::Command("ATTMAN".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// The Block Attribute Manager's "Select block" button: one block reference
|
||||
/// picked in the drawing, handed back as `_ATTMAN_PICK <hex handle>`.
|
||||
pub struct AttmanPickCommand;
|
||||
|
||||
impl crate::command::CadCommand for AttmanPickCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"BATTMAN"
|
||||
}
|
||||
|
||||
fn prompt(&self) -> String {
|
||||
"Select a block:".into()
|
||||
}
|
||||
|
||||
fn needs_entity_pick(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn entity_pick_highlights_hover(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn on_entity_pick(&mut self, handle: codec::Handle, _pt: glam::DVec3) -> crate::command::CmdResult {
|
||||
if handle.is_null() {
|
||||
return crate::command::CmdResult::NeedPoint;
|
||||
}
|
||||
crate::command::CmdResult::Dispatch(format!("_ATTMAN_PICK {:X}", handle.value()))
|
||||
}
|
||||
|
||||
fn on_point(&mut self, _pt: glam::DVec3) -> crate::command::CmdResult {
|
||||
crate::command::CmdResult::NeedPoint
|
||||
}
|
||||
|
||||
fn on_enter(&mut self) -> crate::command::CmdResult {
|
||||
crate::command::CmdResult::Dispatch("_ATTMAN_PICK".into())
|
||||
}
|
||||
|
||||
fn on_escape(&mut self) -> crate::command::CmdResult {
|
||||
crate::command::CmdResult::Dispatch("_ATTMAN_PICK".into())
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
mod attdef;
|
||||
pub(crate) mod attedit;
|
||||
mod attman;
|
||||
pub(crate) mod attman;
|
||||
pub mod base_point;
|
||||
pub(crate) mod block_cmdline;
|
||||
mod content_browser;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,6 +2,7 @@ pub mod about;
|
||||
pub mod alias_editor;
|
||||
pub mod annotation_data;
|
||||
pub mod attdef_dialog;
|
||||
pub mod attman_dialog;
|
||||
pub mod attribute_editor;
|
||||
pub mod auto_constrain_settings;
|
||||
pub mod block_definition;
|
||||
|
||||
Reference in new issue
Block a user