mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-30 04:57:54 -06:00
Merge pull request #2629 from storytold/fix/2585-scriptui-dock-size
ScriptUI: a docked panel gets its dock's size and onResize (#2585)
This commit is contained in:
@@ -581,6 +581,15 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
always,
|
||||
scriptui::mouse
|
||||
),
|
||||
cmd!(
|
||||
"scriptui.resize",
|
||||
"Resize Script Window",
|
||||
[],
|
||||
None,
|
||||
"{window?, size: [width, height] (pixels)} → the window takes the size, lays itself out again and its onResizing / onResize run (a docked ScriptUI panel gets its dock's size)",
|
||||
always,
|
||||
scriptui::resize
|
||||
),
|
||||
cmd!(
|
||||
"scriptui.close",
|
||||
"Close Script Window",
|
||||
|
||||
@@ -769,6 +769,17 @@ pub(crate) fn mouse(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
dispatch(s, ScriptUiEvent { window, widget, kind: (*ty).to_string(), value })
|
||||
}
|
||||
|
||||
/// `scriptui.resize`: the host gave the window a new size (a docked panel's dock, #2585): the
|
||||
/// script's window takes it, lays itself out again and gets `onResizing` / `onResize`.
|
||||
pub(crate) fn resize(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let c = "scriptui.resize";
|
||||
let window = window_p(s, p, c)?;
|
||||
let size = p.get("size").and_then(Value::as_array).ok_or_else(|| crate::commands::bad(c, "missing `size` [width, height]"))?;
|
||||
let side = |i: usize| size.get(i).and_then(Value::as_f64).filter(|v| v.is_finite()).map(|v| v.round().clamp(1.0, 16384.0));
|
||||
let (Some(w), Some(h)) = (side(0), side(1)) else { return Err(crate::commands::bad(c, "`size` must be [width, height] in pixels")) };
|
||||
dispatch(s, ScriptUiEvent { window, widget: 0, kind: "resize".into(), value: json!([w, h]) })
|
||||
}
|
||||
|
||||
/// `scriptui.close`: close a window (a dialog's `show()` returns `result`, default 2 = Cancel).
|
||||
pub(crate) fn close(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let window = window_p(s, p, "scriptui.close")?;
|
||||
|
||||
@@ -912,6 +912,18 @@ function __uiDispatch(winId, id, kind, valueJson) {
|
||||
w.close(v === null ? 2 : v);
|
||||
return;
|
||||
}
|
||||
// The host gave the window a new size (a docked panel's dock): take it, lay out, tell the script.
|
||||
if (kind === "resize") {
|
||||
var nw = Number(v && v[0]), nh = Number(v && v[1]);
|
||||
var b = w.__ub || w.__lb;
|
||||
if (nw > 0 && nh > 0 && (b[2] - b[0] !== nw || b[3] - b[1] !== nh)) {
|
||||
w.__ub = [b[0], b[1], b[0] + nw, b[1] + nh];
|
||||
__uiLayout(w);
|
||||
w.__fire("onResizing");
|
||||
w.__fire("onResize");
|
||||
}
|
||||
return;
|
||||
}
|
||||
var c = __uiFind(w, id);
|
||||
if (!c || c.enabled === false) return;
|
||||
var radio = function () {
|
||||
|
||||
@@ -26,6 +26,8 @@ enum Act {
|
||||
Close(u32),
|
||||
/// A mouse event (`scriptui.mouse` parameters without window and widget).
|
||||
Mouse(u32, u32, Value),
|
||||
/// A docked panel's new size (`scriptui.resize`).
|
||||
Resize(u32, [f32; 2]),
|
||||
}
|
||||
|
||||
fn rect_of(origin: egui::Pos2, b: [f64; 4]) -> Rect {
|
||||
@@ -500,6 +502,7 @@ fn perform(app: &mut EffectcraftApp, ctx: &egui::Context, acts: Vec<Act>) {
|
||||
Act::Set(w, id, v) => ("scriptui.set", json!({"window": w, "widget": id, "value": v})),
|
||||
Act::Changing(w, id, v) => ("scriptui.set", json!({"window": w, "widget": id, "value": v, "changing": true})),
|
||||
Act::Close(w) => ("scriptui.close", json!({"window": w})),
|
||||
Act::Resize(w, [x, y]) => ("scriptui.resize", json!({"window": w, "size": [x, y]})),
|
||||
Act::Mouse(w, id, mut v) => {
|
||||
if let Some(o) = v.as_object_mut() {
|
||||
o.insert("window".into(), json!(w));
|
||||
@@ -582,6 +585,14 @@ pub fn panel(app: &mut EffectcraftApp, ui: &mut egui::Ui, rect: Rect, id: u32) {
|
||||
// A modal script dialog blocks the panels too.
|
||||
let modal = app.session.script_ui.windows.iter().any(|w| w.modal);
|
||||
let mut acts = vec![];
|
||||
// The script learns its dock's size when it changes (#2585), as After Effects tells a
|
||||
// docked panel: its window takes the size and onResize runs.
|
||||
let dock = [rect.width().round(), rect.height().round()];
|
||||
let told = egui::Id::unique(("scriptui-dock-size", id));
|
||||
if ui.data(|d| d.get_temp::<[f32; 2]>(told)) != Some(dock) && dock[0] >= 1.0 && dock[1] >= 1.0 {
|
||||
ui.data_mut(|d| d.insert_temp(told, dock));
|
||||
acts.push(Act::Resize(id, dock));
|
||||
}
|
||||
let content = rect;
|
||||
egui::ScrollArea::both().id_salt(("scriptui-panel", id)).max_width(content.width()).max_height(content.height()).show(ui, |ui| {
|
||||
let (r, _) = ui.allocate_exact_size(vec2(w.root.bounds[2] as f32, w.root.bounds[3] as f32), Sense::hover());
|
||||
|
||||
@@ -341,6 +341,38 @@ fn a_drag_keeps_its_control_past_the_window_edge() {
|
||||
h.state_mut().session.execute("scriptui.close", json!({})).unwrap();
|
||||
}
|
||||
|
||||
/// #2585: a window the host resizes takes the size, lays out again and runs onResize; a docked
|
||||
/// ScriptUI panel gets its dock's size that way.
|
||||
#[test]
|
||||
fn script_windows_learn_the_size_they_are_given() {
|
||||
let mut h = harness();
|
||||
let code = r#"
|
||||
var w = new Window("palette", "Sized");
|
||||
var log = w.add("statictext", undefined, "", { name: "log" });
|
||||
log.preferredSize = [200, 20];
|
||||
w.onResize = function () { log.text = "resized " + w.size.width + "x" + w.size.height; };
|
||||
w.show();
|
||||
"#;
|
||||
let r = h.state_mut().session.execute("script.run", json!({"code": code, "name": "sized.jsx"})).unwrap();
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
h.run_steps(2);
|
||||
h.state_mut().session.execute("scriptui.resize", json!({"window": "Sized", "size": [300, 180]})).unwrap();
|
||||
let win = h.state().session.script_ui.windows[0].clone();
|
||||
assert_eq!(win.root.lookup(&json!("log")).unwrap().text, "resized 300x180");
|
||||
let list = h.state_mut().session.execute("scriptui.list", json!({})).unwrap();
|
||||
assert_eq!(list[0]["size"], json!([300.0, 180.0]), "{list}");
|
||||
assert!(h.state_mut().session.execute("scriptui.resize", json!({"window": "Sized", "size": ["wide", 1]})).is_err());
|
||||
h.state_mut().session.execute("scriptui.close", json!({})).unwrap();
|
||||
// A docked panel: its window is its dock's size, not its preferred size.
|
||||
h.state_mut().session.execute("window.scriptPanel", json!({"name": "Layer Tools.jsx"})).unwrap();
|
||||
h.run_steps(4);
|
||||
let panel = h.state().session.script_ui.windows.iter().find(|w| w.script == "Layer Tools.jsx").unwrap().clone();
|
||||
let dock = rect(&h, &format!("scriptui.{}", panel.id));
|
||||
assert_eq!([panel.root.bounds[2].round(), panel.root.bounds[3].round()], [dock.width().round() as f64, dock.height().round() as f64]);
|
||||
h.state_mut().close_panel(PanelKind::ScriptPanel(panel.id));
|
||||
h.run_steps(2);
|
||||
}
|
||||
|
||||
fn click_at(h: &mut Harness<'_, EffectcraftApp>, c: egui::Pos2) {
|
||||
h.input_mut().events.push(Event::PointerMoved(c));
|
||||
h.run_steps(1);
|
||||
|
||||
Reference in New Issue
Block a user