forked from 1b-agent/opencadstudio-upstream
feat(field): FIELDDISPLAY gray field background (screen only, profile setting)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
762cf1e7e4
commit
f6f2b81441
6 files changed
+120
No files matched your search
@@ -668,6 +668,7 @@ inventory::submit!(crate::command::CommandRegistration {
|
||||
"DGNFRAME",
|
||||
"PDFOSNAP",
|
||||
"UOSNAP",
|
||||
"FIELDDISPLAY",
|
||||
"PDFIMPORTMODE",
|
||||
"PDFIMPORTFILTER",
|
||||
"PDFIMPORTLAYERS",
|
||||
|
||||
@@ -1025,6 +1025,7 @@ impl OpenCADStudio {
|
||||
| "DWFOSNAP"
|
||||
| "DGNOSNAP"
|
||||
| "UOSNAP"
|
||||
| "FIELDDISPLAY"
|
||||
| "PDFIMPORTMODE"
|
||||
| "PDFIMPORTFILTER"
|
||||
| "PDFIMPORTLAYERS"
|
||||
@@ -1232,6 +1233,40 @@ impl OpenCADStudio {
|
||||
}
|
||||
return Some(self.finish_dispatch(cmd));
|
||||
}
|
||||
if name == "FIELDDISPLAY" {
|
||||
let current = i16::from(crate::entities::field::display());
|
||||
match value.as_deref().map(|v| v.trim().parse::<i16>().ok().filter(|v| (0..=1).contains(v))) {
|
||||
Some(Some(mode)) => {
|
||||
if current != mode {
|
||||
crate::entities::field::set_display(mode == 1);
|
||||
// A profile setting: redraw the fields of every open drawing.
|
||||
for tab in &mut self.tabs {
|
||||
let changes: Vec<_> = tab
|
||||
.scene
|
||||
.document
|
||||
.entities()
|
||||
.filter(|e| crate::entities::field::hosts_field(&tab.scene.document, e))
|
||||
.map(|e| (e.common().handle, crate::scene::ChangeKind::Modified))
|
||||
.collect();
|
||||
if !changes.is_empty() {
|
||||
tab.scene.bump_entities(&changes);
|
||||
}
|
||||
}
|
||||
self.save_config();
|
||||
}
|
||||
}
|
||||
Some(None) => {
|
||||
self.command_line.push_error(crate::t!("Requires 0 or 1 only.").as_ref());
|
||||
self.command_line.push_output(&format!("Enter new value for FIELDDISPLAY <{current}>:"));
|
||||
self.pending_setvar = Some(name.clone());
|
||||
}
|
||||
None => {
|
||||
self.command_line.push_output(&format!("Enter new value for FIELDDISPLAY <{current}>:"));
|
||||
self.pending_setvar = Some(name.clone());
|
||||
}
|
||||
}
|
||||
return Some(self.finish_dispatch(cmd));
|
||||
}
|
||||
if matches!(name.as_str(), "PDFOSNAP" | "DWFOSNAP" | "DGNOSNAP" | "UOSNAP") {
|
||||
use crate::scene::model::pdf_vector as pv;
|
||||
use codec::entities::UnderlayType;
|
||||
|
||||
@@ -371,6 +371,8 @@ pub struct UserSettings {
|
||||
pub image_frame: i16,
|
||||
/// The Attribute Definition dialog's "Specify on-screen" choice.
|
||||
pub attdef_on_screen: bool,
|
||||
/// FIELDDISPLAY: fields show on a gray background.
|
||||
pub field_display: bool,
|
||||
/// Nested-copy symbol handling: false inserts, true binds.
|
||||
pub ncopy_bind: bool,
|
||||
/// Last Options page; unknown saved names fall back without rejecting the config.
|
||||
@@ -750,6 +752,7 @@ impl Default for UserSettings {
|
||||
grip_object_limit: DEFAULT_GRIP_OBJECT_LIMIT,
|
||||
image_frame: 1,
|
||||
attdef_on_screen: true,
|
||||
field_display: true,
|
||||
ncopy_bind: false,
|
||||
cursor_type: CursorType::Crosshair,
|
||||
crosshair_color: None,
|
||||
|
||||
@@ -677,6 +677,7 @@ impl OpenCADStudio {
|
||||
grip_object_limit: self.grip_object_limit,
|
||||
image_frame: crate::scene::frame::profile_image_mode(),
|
||||
attdef_on_screen: crate::modules::draw::draw::attdef::session().on_screen,
|
||||
field_display: crate::entities::field::display(),
|
||||
ncopy_bind: self.ncopy_bind,
|
||||
cursor_type: self.cursor_type,
|
||||
crosshair_color: self.crosshair_color,
|
||||
@@ -771,6 +772,7 @@ impl OpenCADStudio {
|
||||
self.grip_object_limit = s.grip_object_limit.clamp(0, 32767);
|
||||
crate::scene::frame::set_profile_image_mode(s.image_frame);
|
||||
crate::modules::draw::draw::attdef::session().on_screen = s.attdef_on_screen;
|
||||
crate::entities::field::set_display(s.field_display);
|
||||
self.ncopy_bind = s.ncopy_bind;
|
||||
self.cursor_type = s.cursor_type;
|
||||
self.crosshair_color = s.crosshair_color;
|
||||
|
||||
@@ -249,3 +249,29 @@ fn os_date_locale() -> codec::fields::DateLocale {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
codec::fields::DateLocale::default()
|
||||
}
|
||||
|
||||
/// FIELDDISPLAY: whether fields show on a gray background (not plotted).
|
||||
/// A profile setting, so one value for every drawing.
|
||||
static FIELD_DISPLAY: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
|
||||
|
||||
pub fn display() -> bool {
|
||||
FIELD_DISPLAY.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn set_display(on: bool) {
|
||||
FIELD_DISPLAY.store(on, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// The gray the reference draws behind a field.
|
||||
pub const BACKGROUND: [f32; 4] = [203.0 / 255.0, 203.0 / 255.0, 203.0 / 255.0, 1.0];
|
||||
|
||||
/// Whether `entity` hosts a field: its extension dictionary has ACAD_FIELD.
|
||||
pub fn hosts_field(document: &CadDocument, entity: &codec::entities::EntityType) -> bool {
|
||||
let Some(xdict) = entity.common().xdictionary_handle else {
|
||||
return false;
|
||||
};
|
||||
matches!(
|
||||
document.objects.get(&xdict),
|
||||
Some(codec::objects::ObjectType::Dictionary(d)) if d.get("ACAD_FIELD").is_some()
|
||||
)
|
||||
}
|
||||
@@ -1408,6 +1408,59 @@ pub fn tessellate(
|
||||
// also carries the glyph quads built above.
|
||||
if bins.is_empty() {
|
||||
let mut wires: Vec<WireModel> = Vec::new();
|
||||
// FIELDDISPLAY: a field shows on a gray box behind its
|
||||
// glyphs, on screen only.
|
||||
if text_aabb != WireModel::UNBOUNDED_AABB
|
||||
&& crate::entities::field::display()
|
||||
&& crate::entities::field::hosts_field(document, entity)
|
||||
{
|
||||
let corner_groups = match entity {
|
||||
EntityType::MText(m) => {
|
||||
let rotation = stroke_groups
|
||||
.iter()
|
||||
.find_map(|group| group.run.as_ref().map(|run| run.rotation as f64))
|
||||
.unwrap_or(m.rotation);
|
||||
oriented_mtext_corner_groups(&sdf_verts, m, rotation, 0.0, anno)
|
||||
}
|
||||
EntityType::Text(t) => vec![oriented_text_corners(
|
||||
&sdf_verts,
|
||||
[t.insertion_point.x, t.insertion_point.y],
|
||||
t.rotation,
|
||||
0.0,
|
||||
)],
|
||||
EntityType::AttributeEntity(a) => vec![oriented_text_corners(
|
||||
&sdf_verts,
|
||||
[a.insertion_point.x, a.insertion_point.y],
|
||||
a.rotation,
|
||||
0.0,
|
||||
)],
|
||||
_ => Vec::new(),
|
||||
};
|
||||
let mut ft = Vec::with_capacity(6 * corner_groups.len());
|
||||
let mut ftl = Vec::with_capacity(6 * corner_groups.len());
|
||||
for corners in &corner_groups {
|
||||
for &k in &[0usize, 1, 2, 0, 2, 3] {
|
||||
let (h, lo) = split_ds_xyz(corners[k][0], corners[k][1], elev_v);
|
||||
ft.push(h);
|
||||
ftl.push(lo);
|
||||
}
|
||||
}
|
||||
if !ft.is_empty() {
|
||||
wires.push(WireModel {
|
||||
display_visible: true,
|
||||
plot_visible: false,
|
||||
name: name.clone(),
|
||||
color: crate::entities::field::BACKGROUND,
|
||||
selected,
|
||||
line_weight_px,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
fill_tris: ft,
|
||||
fill_tris_low: ftl,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
// MTEXT background and frame follow the glyph bounds.
|
||||
if text_aabb != WireModel::UNBOUNDED_AABB {
|
||||
if let EntityType::MText(m) = entity {
|
||||
|
||||
Reference in new issue
Block a user