forked from 1b-agent/opencadstudio-upstream
feat(entities): integrate remaining fields on block-based entities
MultiLeader and Table were ignoring most of the styling and content fields that the parser populated. Bring both up to file-driven render: MultiLeader - line_color: leader stroke / arrow colour with ByBlock/ByLayer fallback - line_type_handle: dashed leader via line_types lookup by handle - line_weight (ml.line_weight): per-leader pixel width override - arrowhead_handle: arrow shape resolved through the dim arrow emitter (Closed Filled / Open / Dot / Origin / Box / Datum / Tick / None) - extend_leader_to_text: continue the leader past the landing to the text insertion point - text_angle_type: Horizontal forces 0, Optimized clamps to a readable half-plane, ParallelToLastLeaderLine keeps the stored direction - text_direction_negative: adds π to the rotation - text_alignment: drives the horizontal anchor when more specific than the context's text_attachment_point - text_attachment_direction + text_top_attachment + text_bottom_attachment: Vertical mode uses the top / bottom attachment values chosen from the first root's direction.y sign - has_block_contents + block_content_handle + block_content_location + block_rotation + block_scale + block_content_color: synthesise an Insert and explode it through the standard tessellator so block- content MultiLeaders render their referenced block - style_handle, arrowhead_handle, line_type_handle, text_style_handle, block_content_handle, property_override_flags, text_align_in_ipe, block_scale, block_rotation, extend_leader_to_text, text_direction_negative, text_top_attachment, text_bottom_attachment surfaced in the Properties panel Table - Per-cell borders: drop the always-grid pass, walk the cells and emit each border honouring its `invisible` flag with dedup so shared edges aren't doubled - table_style_handle, block_record_handle, data_version, value_flags, override_flag / override_border_* flags, break_options / break_flow_direction / break_spacing, normal surfaced in the Properties panel Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
e0ec7f1999
commit
613d6cf99d
3 files changed
+434
-47
No files matched your search
@@ -510,9 +510,112 @@ fn properties(ml: &MultiLeader) -> PropSection {
|
||||
"Bottom Line",
|
||||
],
|
||||
),
|
||||
// Top / Bottom attach (used when text_attachment_direction = Vertical)
|
||||
choice(
|
||||
"Top Attach",
|
||||
"text_top_attachment",
|
||||
attachment_str(&ml.text_top_attachment),
|
||||
&[
|
||||
"Top of Top",
|
||||
"Mid of Top",
|
||||
"Mid of Text",
|
||||
"Mid of Bot",
|
||||
"Bot of Bot",
|
||||
"Bottom Line",
|
||||
],
|
||||
),
|
||||
choice(
|
||||
"Bottom Attach",
|
||||
"text_bottom_attachment",
|
||||
attachment_str(&ml.text_bottom_attachment),
|
||||
&[
|
||||
"Top of Top",
|
||||
"Mid of Top",
|
||||
"Mid of Text",
|
||||
"Mid of Bot",
|
||||
"Bot of Bot",
|
||||
"Bottom Line",
|
||||
],
|
||||
),
|
||||
// Stats
|
||||
ro("Leader Pts", "total_pts", total_pts.to_string()),
|
||||
ro("Roots", "root_count", ctx.leader_roots.len().to_string()),
|
||||
// Style references / handles (read-only — the multileader's own
|
||||
// copies of the style values are the authoritative render inputs).
|
||||
ro(
|
||||
"Style Handle",
|
||||
"style_handle",
|
||||
match ml.style_handle {
|
||||
Some(h) if !h.is_null() => format!("{:X}", h.value()),
|
||||
_ => "(none)".to_string(),
|
||||
},
|
||||
),
|
||||
ro(
|
||||
"Text Style Handle",
|
||||
"text_style_handle",
|
||||
match ml.text_style_handle {
|
||||
Some(h) if !h.is_null() => format!("{:X}", h.value()),
|
||||
_ => "(none)".to_string(),
|
||||
},
|
||||
),
|
||||
ro(
|
||||
"Arrow Handle",
|
||||
"arrowhead_handle",
|
||||
match ml.arrowhead_handle {
|
||||
Some(h) if !h.is_null() => format!("{:X}", h.value()),
|
||||
_ => "(none)".to_string(),
|
||||
},
|
||||
),
|
||||
ro(
|
||||
"Line Type Handle",
|
||||
"line_type_handle",
|
||||
match ml.line_type_handle {
|
||||
Some(h) if !h.is_null() => format!("{:X}", h.value()),
|
||||
_ => "(none)".to_string(),
|
||||
},
|
||||
),
|
||||
ro(
|
||||
"Block Content Handle",
|
||||
"block_content_handle",
|
||||
match ml.block_content_handle {
|
||||
Some(h) if !h.is_null() => format!("{:X}", h.value()),
|
||||
_ => "(none)".to_string(),
|
||||
},
|
||||
),
|
||||
// Less common toggles surfaced read-only.
|
||||
ro(
|
||||
"Extend Leader",
|
||||
"extend_leader_to_text",
|
||||
if ml.extend_leader_to_text { "Yes" } else { "No" },
|
||||
),
|
||||
ro(
|
||||
"Text Direction Negative",
|
||||
"text_direction_negative",
|
||||
if ml.text_direction_negative { "Yes" } else { "No" },
|
||||
),
|
||||
ro(
|
||||
"Text Align In IPE",
|
||||
"text_align_in_ipe",
|
||||
ml.text_align_in_ipe.to_string(),
|
||||
),
|
||||
ro(
|
||||
"Property Override Flags",
|
||||
"property_override_flags",
|
||||
format!("{:#018b}", ml.property_override_flags.bits()),
|
||||
),
|
||||
ro(
|
||||
"Block Scale",
|
||||
"block_scale",
|
||||
format!(
|
||||
"{:.3} × {:.3} × {:.3}",
|
||||
ml.block_scale.x, ml.block_scale.y, ml.block_scale.z
|
||||
),
|
||||
),
|
||||
ro(
|
||||
"Block Rotation",
|
||||
"block_rotation",
|
||||
format!("{:.3}°", ml.block_rotation.to_degrees()),
|
||||
),
|
||||
];
|
||||
|
||||
// Connection point for first root (most common case)
|
||||
@@ -635,6 +738,14 @@ fn apply_geom_prop(ml: &mut MultiLeader, field: &str, value: &str) {
|
||||
ml.text_right_attachment = parse_attachment(value);
|
||||
ml.context.text_right_attachment = parse_attachment(value);
|
||||
}
|
||||
"text_top_attachment" => {
|
||||
ml.text_top_attachment = parse_attachment(value);
|
||||
ml.context.text_top_attachment = parse_attachment(value);
|
||||
}
|
||||
"text_bottom_attachment" => {
|
||||
ml.text_bottom_attachment = parse_attachment(value);
|
||||
ml.context.text_bottom_attachment = parse_attachment(value);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
+133
-12
@@ -53,25 +53,73 @@ impl TruckConvertible for Table {
|
||||
|
||||
let mut pts: Vec<[f32; 3]> = Vec::new();
|
||||
|
||||
let mut add_seg = |a: Vec3, b: Vec3| {
|
||||
// Per-cell borders. When a cell carries a CellStyle, honour the
|
||||
// visibility / `invisible` flag of each of its four borders so
|
||||
// hidden borders disappear from the grid. Cells with no style still
|
||||
// emit the standard four borders. To avoid drawing each shared edge
|
||||
// twice we coalesce the segments by their (start, end) coordinates.
|
||||
use std::collections::HashSet;
|
||||
let mut emitted: HashSet<(i32, i32, i32, i32)> = HashSet::new();
|
||||
let try_add = |a: Vec3, b: Vec3, vis: bool, emitted: &mut HashSet<(i32, i32, i32, i32)>, pts: &mut Vec<[f32; 3]>| {
|
||||
if !vis {
|
||||
return;
|
||||
}
|
||||
let key = (
|
||||
(a.x * 1_000.0) as i32,
|
||||
(a.y * 1_000.0) as i32,
|
||||
(b.x * 1_000.0) as i32,
|
||||
(b.y * 1_000.0) as i32,
|
||||
);
|
||||
let key_rev = (key.2, key.3, key.0, key.1);
|
||||
if emitted.contains(&key) || emitted.contains(&key_rev) {
|
||||
return;
|
||||
}
|
||||
emitted.insert(key);
|
||||
if !pts.is_empty() {
|
||||
pts.push([f32::NAN; 3]);
|
||||
}
|
||||
pts.push([a.x, a.y, a.z]);
|
||||
pts.push([b.x, b.y, b.z]);
|
||||
};
|
||||
|
||||
for &ry in &row_offsets {
|
||||
let left = origin + h * 0.0 + v_down * ry;
|
||||
let right = origin + h * total_w + v_down * ry;
|
||||
add_seg(left, right);
|
||||
}
|
||||
|
||||
for &cx in &col_offsets {
|
||||
let top = origin + h * cx + v_down * 0.0;
|
||||
let bottom = origin + h * cx + v_down * total_h;
|
||||
add_seg(top, bottom);
|
||||
for (ri, row) in self.rows.iter().enumerate() {
|
||||
let row_top = row_offsets[ri];
|
||||
let row_bot = row_offsets
|
||||
.get(ri + 1)
|
||||
.copied()
|
||||
.unwrap_or(row_top + row.height as f32);
|
||||
for (ci, cell) in row.cells.iter().enumerate() {
|
||||
let col_left = col_offsets[ci];
|
||||
let col_right = col_offsets
|
||||
.get(ci + 1)
|
||||
.copied()
|
||||
.unwrap_or(col_left
|
||||
+ self.columns.get(ci).map(|c| c.width as f32).unwrap_or(1.0));
|
||||
// Default to visible when no style override is present.
|
||||
let (top_vis, right_vis, bottom_vis, left_vis) = cell
|
||||
.style
|
||||
.as_ref()
|
||||
.map(|s| {
|
||||
(
|
||||
!s.top_border.invisible,
|
||||
!s.right_border.invisible,
|
||||
!s.bottom_border.invisible,
|
||||
!s.left_border.invisible,
|
||||
)
|
||||
})
|
||||
.unwrap_or((true, true, true, true));
|
||||
let tl = origin + h * col_left + v_down * row_top;
|
||||
let tr = origin + h * col_right + v_down * row_top;
|
||||
let br_ = origin + h * col_right + v_down * row_bot;
|
||||
let bl = origin + h * col_left + v_down * row_bot;
|
||||
try_add(tl, tr, top_vis, &mut emitted, &mut pts);
|
||||
try_add(tr, br_, right_vis, &mut emitted, &mut pts);
|
||||
try_add(bl, br_, bottom_vis, &mut emitted, &mut pts);
|
||||
try_add(tl, bl, left_vis, &mut emitted, &mut pts);
|
||||
}
|
||||
}
|
||||
// Suppress unused-variable warnings now that the simple grid-pass
|
||||
// is gone — col/row offsets still feed cell drawing below.
|
||||
let _ = (total_w, total_h);
|
||||
|
||||
// Cell text — lifted into Lines points via 2D strokes
|
||||
let text_height = 0.18_f32;
|
||||
@@ -187,6 +235,12 @@ impl Grippable for Table {
|
||||
|
||||
impl PropertyEditable for Table {
|
||||
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
|
||||
let fmt_h = |oh: &Option<acadrust::types::Handle>| -> String {
|
||||
match oh {
|
||||
Some(h) if !h.is_null() => format!("{:X}", h.value()),
|
||||
_ => "(none)".to_string(),
|
||||
}
|
||||
};
|
||||
PropSection {
|
||||
title: "Table".into(),
|
||||
props: vec![
|
||||
@@ -207,6 +261,73 @@ impl PropertyEditable for Table {
|
||||
"tbl_iz",
|
||||
format!("{:.4}", self.insertion_point.z),
|
||||
),
|
||||
ro(
|
||||
"Table Style",
|
||||
"tbl_style_handle",
|
||||
fmt_h(&self.table_style_handle),
|
||||
),
|
||||
ro(
|
||||
"Block Record",
|
||||
"tbl_block_rec_handle",
|
||||
fmt_h(&self.block_record_handle),
|
||||
),
|
||||
ro("Data Version", "tbl_data_version", self.data_version.to_string()),
|
||||
ro(
|
||||
"Value Flags",
|
||||
"tbl_value_flags",
|
||||
format!("{:#010x}", self.value_flags),
|
||||
),
|
||||
ro(
|
||||
"Override Flag",
|
||||
"tbl_override_flag",
|
||||
if self.override_flag { "Yes" } else { "No" },
|
||||
),
|
||||
ro(
|
||||
"Override Border Color",
|
||||
"tbl_override_border_color",
|
||||
if self.override_border_color { "Yes" } else { "No" },
|
||||
),
|
||||
ro(
|
||||
"Override Border LW",
|
||||
"tbl_override_border_lw",
|
||||
if self.override_border_line_weight {
|
||||
"Yes"
|
||||
} else {
|
||||
"No"
|
||||
},
|
||||
),
|
||||
ro(
|
||||
"Override Border Vis",
|
||||
"tbl_override_border_vis",
|
||||
if self.override_border_visibility {
|
||||
"Yes"
|
||||
} else {
|
||||
"No"
|
||||
},
|
||||
),
|
||||
ro(
|
||||
"Break Spacing",
|
||||
"tbl_break_spacing",
|
||||
format!("{:.4}", self.break_spacing),
|
||||
),
|
||||
ro(
|
||||
"Break Flow",
|
||||
"tbl_break_flow",
|
||||
format!("{:?}", self.break_flow_direction),
|
||||
),
|
||||
ro(
|
||||
"Break Options",
|
||||
"tbl_break_options",
|
||||
format!("{:#018b}", self.break_options.bits()),
|
||||
),
|
||||
ro(
|
||||
"Normal",
|
||||
"tbl_normal",
|
||||
format!(
|
||||
"{:.3}, {:.3}, {:.3}",
|
||||
self.normal.x, self.normal.y, self.normal.z
|
||||
),
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user