fix(text): keep in-place MText/Text editor on-screen at window edges

The editor overlay's anchor was only clamped to the top/left edge, so an
MTEXT placed near the right/bottom of the viewport pushed the 640px panel
(and its toolbar buttons) off-screen where they were unclickable.

Both the MText editor and the single-line TEXT editor now receive the
viewport canvas size and clamp the anchor against the right/bottom edges
too, so the whole panel stays visible and usable wherever it is opened.

Fixes #52

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-03 10:59:59 +03:00
1 parent f0b11acc88
commit 6f64d8d0d9
1 file changed
+22 -7
+22 -7
View File
@@ -799,6 +799,7 @@ impl OpenCADStudio {
// In-place MText editor (toolbar + text area), anchored at the
// insertion-point click.
if !tab.is_start {
let canvas = tab.scene.selection.borrow().vp_size;
if let Some(ed) = &self.mtext_editor {
let styles: Vec<String> = tab
.scene
@@ -807,10 +808,10 @@ impl OpenCADStudio {
.iter()
.map(|s| s.name.clone())
.collect();
viewport_stack = viewport_stack.push(mtext_editor_overlay(ed, styles));
viewport_stack = viewport_stack.push(mtext_editor_overlay(ed, styles, canvas));
}
if let Some(ed) = &self.text_inline {
viewport_stack = viewport_stack.push(text_inline_overlay(ed));
viewport_stack = viewport_stack.push(text_inline_overlay(ed, canvas));
}
}
@@ -1372,7 +1373,10 @@ pub(super) const TEXT_INLINE_ID: &str = "text_inline_input";
/// In-place single-line TEXT editor: a plain text-entry box (no formatting
/// toolbar), anchored at the insertion-point click. Enter commits; Esc cancels.
fn text_inline_overlay(ed: &super::text_inline::TextInlineState) -> Element<'_, Message> {
fn text_inline_overlay(
ed: &super::text_inline::TextInlineState,
canvas: (f32, f32),
) -> Element<'_, Message> {
const PANEL_BG: Color = Color { r: 0.16, g: 0.16, b: 0.16, a: 0.98 };
const BORDER: Color = Color { r: 0.40, g: 0.40, b: 0.40, a: 1.0 };
@@ -1392,9 +1396,13 @@ fn text_inline_overlay(ed: &super::text_inline::TextInlineState) -> Element<'_,
})
.padding(4);
// Keep the box on-screen so its field stays clickable at the edges.
const PANEL_W: f32 = 240.0 + 20.0;
const PANEL_H: f32 = 46.0;
let (cw, ch) = canvas;
let anchor = iced::Point::new(
(ed.screen_anchor.x - 6.0).max(0.0),
(ed.screen_anchor.y - 18.0).max(0.0),
(ed.screen_anchor.x - 6.0).clamp(0.0, (cw - PANEL_W).max(0.0)),
(ed.screen_anchor.y - 18.0).clamp(0.0, (ch - PANEL_H).max(0.0)),
);
position_canvas_overlay(anchor, panel.into())
}
@@ -1656,6 +1664,7 @@ fn mtext_preview_segments(
fn mtext_editor_overlay<'a>(
ed: &'a super::mtext_editor::MTextEditorState,
styles: Vec<String>,
canvas_size: (f32, f32),
) -> Element<'a, Message> {
use super::mtext_editor::{JustifyChoice, MTextFmt, ParaAlign};
use iced::widget::{canvas, svg, text_editor};
@@ -1891,9 +1900,15 @@ fn mtext_editor_overlay<'a>(
.padding(6)
.width(iced::Length::Fixed(640.0));
// Keep the whole panel on-screen: clamp the anchor so it never spills past
// the right/bottom edge (where its toolbar buttons would be unclickable).
// Width is fixed; height is the toolbar rows + the fixed VIEW_H body.
const PANEL_W: f32 = 640.0 + 14.0; // fixed width + padding/border
const PANEL_H: f32 = VIEW_H + 150.0; // body + toolbars/toggle/padding
let (cw, ch) = canvas_size;
let anchor = iced::Point::new(
(ed.screen_anchor.x - 10.0).max(0.0),
(ed.screen_anchor.y - 90.0).max(0.0),
(ed.screen_anchor.x - 10.0).clamp(0.0, (cw - PANEL_W).max(0.0)),
(ed.screen_anchor.y - 90.0).clamp(0.0, (ch - PANEL_H).max(0.0)),
);
position_canvas_overlay(anchor, panel.into())
}