mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
#866: Layer > New > Text starts typing into Source Text
Problem: Layer > New > Text (menu, Ctrl+Alt+Shift+T, Timeline context menus) created a layer with the placeholder "Text" and no edit session, so typed keys ran shortcuts; users then renamed the layer (Enter) and the name, not the Source Text, got their text. Fix: as in After Effects, the UI dispatch runs layer.newText with an empty text and an edit session (insertion point in the comp centre); the name follows the typed text. engine.execute keeps the headless default. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
9a7d3e7699
commit
1226576a92
3 files changed
+38
-2
No files matched your search
@@ -273,6 +273,12 @@ fn no_params(p: &Value) -> bool {
|
||||
|
||||
/// Execute a UI or engine command by id.
|
||||
pub fn invoke(app: &mut EffectcraftApp, ctx: &egui::Context, id: &str, params: Value) -> Result<Value, String> {
|
||||
// Layer ▸ New ▸ Text (menu, shortcut, context menus) puts an insertion point in the centre of
|
||||
// the comp, as After Effects does, so typing goes into Source Text rather than running
|
||||
// shortcuts (#866). `engine.execute` keeps the headless default.
|
||||
if id == "layer.newText" && no_params(¶ms) {
|
||||
return run_engine(app, ctx, id, json!({"text": "", "edit": true}));
|
||||
}
|
||||
if no_params(¶ms) && app.ui.focused == PanelKind::Project {
|
||||
match id {
|
||||
"edit.duplicate" => return run_engine(app, ctx, "project.duplicate", json!({})),
|
||||
|
||||
@@ -2661,7 +2661,7 @@ pub fn show(app: &mut EffectcraftApp, ui: &mut egui::Ui, rect: Rect) {
|
||||
response.context_menu(|ui| {
|
||||
let menu = ui.menu_button(crate::i18n::tr("New"), |ui| {
|
||||
for (key, label, command, params) in [
|
||||
("text", "Text", "layer.newText", json!({"text": "Text"})),
|
||||
("text", "Text", "layer.newText", json!({})),
|
||||
("solid", "Solid…", "layer.newSolid", json!({})),
|
||||
("light", "Light…", "layer.newLight", json!({})),
|
||||
("camera", "Camera…", "layer.newCamera", json!({})),
|
||||
@@ -3457,7 +3457,7 @@ pub(crate) fn layer_menu(ui: &mut egui::Ui, layers: &[u64], actions: &mut Vec<(S
|
||||
}
|
||||
};
|
||||
ui.menu_button(crate::i18n::tr("New"), |ui| {
|
||||
item(ui, "Text", "layer.newText", json!({"text": "Text"}));
|
||||
item(ui, "Text", "layer.newText", json!({}));
|
||||
item(ui, "Solid…", "app.solidSettings", json!({}));
|
||||
item(ui, "Light…", "layer.newLight", json!({}));
|
||||
item(ui, "Camera…", "layer.newCamera", json!({}));
|
||||
|
||||
@@ -277,3 +277,33 @@ fn type_tool_drag_makes_paragraph_text_with_box_handles() {
|
||||
assert!(doc2.box_size.unwrap()[0] > bs[0] + 20.0, "{:?}", doc2.box_size);
|
||||
assert!(h.state().session.state.text_edit.is_some(), "still editing after resizing");
|
||||
}
|
||||
|
||||
/// #866: Layer ▸ New ▸ Text (menu or its shortcut) puts an insertion point in the comp, as After
|
||||
/// Effects does, so typed keys reach Source Text (and the layer name follows) instead of running
|
||||
/// shortcuts while the layer keeps the placeholder "Text".
|
||||
#[test]
|
||||
fn layer_new_text_menu_and_shortcut_start_typing_into_source_text() {
|
||||
for via_shortcut in [false, true] {
|
||||
let mut s = Session::default();
|
||||
s.execute("comp.new", json!({"name": "Type", "width": 640, "height": 360, "duration": 2})).unwrap();
|
||||
s.execute("layer.newSolid", json!({"color": "#ffffff"})).unwrap();
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).with_step_dt(1.0 / 60.0).build_eframe(move |_| EffectcraftApp::new(s));
|
||||
h.state_mut().show_panel(PanelKind::Composition);
|
||||
h.run_steps(3);
|
||||
if via_shortcut {
|
||||
key(&mut h, Key::T, Modifiers::COMMAND | Modifiers::ALT | Modifiers::SHIFT);
|
||||
} else {
|
||||
let ctx = h.ctx.clone();
|
||||
effectcraft_ui_egui::menus::invoke(h.state_mut(), &ctx, "layer.newText", json!({})).unwrap();
|
||||
h.run_steps(2);
|
||||
}
|
||||
let (lid, text, _, _) = edited(&h);
|
||||
assert_eq!(text, "", "no placeholder to type over (shortcut: {via_shortcut})");
|
||||
type_text(&mut h, "My First Project");
|
||||
key(&mut h, Key::Escape, Modifiers::NONE);
|
||||
assert!(h.state().session.state.text_edit.is_none(), "Escape commits");
|
||||
let s = &h.state().session;
|
||||
assert_eq!(layer_doc(s, LayerId(lid)).unwrap().text, "My First Project", "typed text is the Source Text");
|
||||
assert_eq!(s.active_comp().unwrap().layer(LayerId(lid)).unwrap().name, "My First Project", "the name follows the text");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user