feat(mtext): structured editor with selection, copy, and visible bold

Rewrite the in-app MTEXT editor to run on acadrust's structured
MTextDocument model end-to-end: load via parse_mtext, edit a flat Cell
model, serialize via to_mtext_string. Retires the hand-rolled format-code
string handling, the parallel visible_spans parser, the composed_value
prefix, and the Edit-raw-code tab.

Selection and copy:
- double-click selects the word, triple-click selects all (click-counting)
- Ctrl+A selects all text
- Ctrl+C copies the selected text to the clipboard

Formatting:
- per-selection Bold/Italic/Underline/Overline/Strike/Case/Alignment
- Bold renders as a visibly thicker SDF pen, keyed (family, char, bold)
  through the whole text pipeline; the resolved style font name is stamped
  so the \f...|b1; code survives serialization
- per-selection font and color changes
- editor color dropdown reuses the Properties panel color selector

Global toolbar defaults (font/color/oblique/width/tracking) fold onto the
document as real span properties instead of a leading code prefix; a
trailing empty paragraph is preserved so Enter at the end keeps its line.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-11 20:18:50 +03:00
1 parent 4bc196affd
commit 8ed10ceb2a
17 files changed
+718 -405

No files matched your search

+1
View File
@@ -306,6 +306,7 @@ fn build_attr_truck(input: AttrTextInputs<'_>, document: &acadrust::CadDocument)
width_factor,
oblique: oblique_angle,
tracking: 1.0,
bold: false,
}),
});
}
+1
View File
@@ -1529,6 +1529,7 @@ impl MultiLeaderTess for MultiLeader {
run.oblique,
run.tracking,
&run.font,
run.bold,
&run.text,
);
crate::scene::pipeline::text_gpu::push_glyph_vertices(
+1
View File
@@ -724,6 +724,7 @@ pub fn tessellate_table(
run.oblique,
run.tracking,
&run.font,
run.bold,
&run.text,
);
crate::scene::pipeline::text_gpu::push_glyph_vertices(
+1
View File
@@ -123,6 +123,7 @@ fn to_truck(t: &Text, document: &acadrust::CadDocument) -> TruckEntity {
width_factor: p.width_factor,
oblique: p.oblique_angle,
tracking: 1.0,
bold: false,
}),
}]),
snap_pts: vec![(snap_pt, SnapHint::Insertion)],
+5
View File
@@ -275,6 +275,8 @@ pub struct RunState {
pub underline: bool,
pub overline: bool,
pub strike: bool,
/// Bold run — rendered with a wider SDF pen (thicker strokes).
pub bold: bool,
}
impl Default for RunState {
@@ -290,6 +292,7 @@ impl Default for RunState {
underline: false,
overline: false,
strike: false,
bold: false,
}
}
}
@@ -435,6 +438,7 @@ pub fn adapt_mtext_paragraphs(
_ => 0,
},
font: p.font.as_ref().map(|f| font_stem(&f.name)),
bold: p.font.as_ref().map(|f| f.bold).unwrap_or(false),
color: color_of(p),
underline: p.stroke.underline(),
overline: p.stroke.overline(),
@@ -1108,6 +1112,7 @@ pub fn layout_mtext(opts: &MTextRenderOpts) -> MTextLayout {
width_factor: signed_wf,
oblique,
tracking,
bold: atom.state.bold,
}),
});
if opts.want_glyph_boxes {
+1
View File
@@ -289,6 +289,7 @@ impl TruckConvertible for Tolerance {
width_factor: 1.0,
oblique: 0.0,
tracking: 0.0,
bold: false,
}),
});
}