forked from 1b-agent/opencadstudio-upstream
feat(ui): MTEXT editor in shared modal + resizable dialogs
Route the MTEXT editor through the shared in-canvas modal frame with an Apply-at-top toolbar (style-manager style): Apply commits and keeps the editor open (creates on first apply, updates in place after), the ✕ cancels. Give every modal a bottom-right corner resize grip driven by a shared grow-only `modal_resize` delta that resets with `modal_offset` on open/close, so each dialog opens at its natural size and can be dragged larger — style managers included. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
f797fd800b
commit
977701b47e
10 files changed
+221
-70
No files matched your search
@@ -53,6 +53,7 @@ pub const TRASH: &[u8] = include_bytes!("../../assets/icons/ui/trash.svg");
|
||||
pub const COPY: &[u8] = include_bytes!("../../assets/icons/ui/copy.svg");
|
||||
pub const MENU: &[u8] = include_bytes!("../../assets/icons/ui/menu.svg");
|
||||
pub const MOVE: &[u8] = include_bytes!("../../assets/icons/ui/move.svg");
|
||||
pub const RESIZE: &[u8] = include_bytes!("../../assets/icons/ui/resize.svg");
|
||||
pub const SPLIT_V: &[u8] = include_bytes!("../../assets/icons/ui/split_v.svg");
|
||||
pub const SPLIT_H: &[u8] = include_bytes!("../../assets/icons/ui/split_h.svg");
|
||||
pub const GRID: &[u8] = include_bytes!("../../assets/icons/ui/grid.svg");
|
||||
|
||||
+31
-15
@@ -48,6 +48,7 @@ pub fn modal<'a>(
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
on_close: Message,
|
||||
offset: Vector,
|
||||
resizable: bool,
|
||||
) -> Element<'a, Message> {
|
||||
let close = button(crate::ui::icons::tinted(
|
||||
crate::ui::icons::CLOSE,
|
||||
@@ -84,23 +85,38 @@ pub fn modal<'a>(
|
||||
|
||||
let title_bar = row![grip, close].spacing(6).align_y(iced::Center);
|
||||
|
||||
// The column shrinks to the content's width; the title bar sits top-right
|
||||
// above it, mirroring the former ✕ placement with a drag handle.
|
||||
let framed = container(
|
||||
let panel_style = |_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL)),
|
||||
border: Border {
|
||||
color: BORDER_C,
|
||||
width: 1.0,
|
||||
radius: 6.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// The dialog is always sized to its content (the caller fixes the content's
|
||||
// width/height, growing it by the shared resize delta). When `resizable`, a
|
||||
// corner grip is appended bottom-right; dragging it drives `ModalResizeGrab`
|
||||
// + the shared drag move/release, which bumps that delta. The title bar sits
|
||||
// top-right above the content either way (`align_x(Right)`).
|
||||
let body = if resizable {
|
||||
let resize = mouse_area(
|
||||
container(crate::ui::icons::tinted(crate::ui::icons::RESIZE, 15.0, GRIP_C))
|
||||
.padding([0, 2]),
|
||||
)
|
||||
.on_press(Message::ModalResizeGrab)
|
||||
.interaction(iced::mouse::Interaction::Grab);
|
||||
column![title_bar, content.into(), resize]
|
||||
} else {
|
||||
column![title_bar, content.into()]
|
||||
.spacing(6)
|
||||
.align_x(iced::alignment::Horizontal::Right),
|
||||
};
|
||||
let framed: Element<'a, Message> = container(
|
||||
body.spacing(6).align_x(iced::alignment::Horizontal::Right),
|
||||
)
|
||||
.padding(10)
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL)),
|
||||
border: Border {
|
||||
color: BORDER_C,
|
||||
width: 1.0,
|
||||
radius: 6.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
.padding(10)
|
||||
.style(panel_style)
|
||||
.into();
|
||||
|
||||
// Position via asymmetric padding (padding is non-negative): shifting a
|
||||
// centred box by `d` on an axis needs (near − far) padding = 2·d there.
|
||||
|
||||
Reference in new issue
Block a user