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 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.7 committed 2026-05-19 21:17:05 +03:00
1 parent e0ec7f1999
commit 613d6cf99d
3 files changed
+434 -47

No files matched your search

+111
View File
@@ -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);
}
_ => {}
}
}