Text editing on the Program monitor: double-click and Ctrl/Cmd+A select all the text (#1102)
This commit is contained in:
parent
0800a8b0aa
commit
78a4c73a1e
|
|
@ -175,6 +175,9 @@ pub fn targets_source(app: &FilmcraftApp, params: &Value) -> bool {
|
|||
|
||||
/// Execute a UI or engine command by id.
|
||||
pub fn invoke(app: &mut FilmcraftApp, ctx: &egui::Context, id: &str, mut params: Value) -> Result<Value, String> {
|
||||
if id == "edit.selectAll" && crate::panels::graphics::select_all_edited_text(app) {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
if filmcraft_engine::source_monitor::source_command(id) && targets_source(app, ¶ms) && params.get("target").is_none() {
|
||||
let object = params.as_object_mut().ok_or("command parameters must be an object")?;
|
||||
object.insert("target".into(), json!("source"));
|
||||
|
|
|
|||
|
|
@ -835,6 +835,10 @@ pub fn monitor_overlay(app: &mut FilmcraftApp, ui: &mut egui::Ui, pic: Rect, fra
|
|||
if resp.double_clicked() {
|
||||
if let Some(v) = views.iter().find(|v| v.is_text() && v.hit(p)) {
|
||||
start_edit_at(app, ui, v, p, &mut actions);
|
||||
// double-click selects all the text so typing replaces it, as in Premiere
|
||||
if let (Some(tp), Some(e)) = (text_of(&v.spec), app.ui.gfx_edit.as_mut()) {
|
||||
(e.anchor, e.caret) = (0, tp.text.len());
|
||||
}
|
||||
}
|
||||
} else if let Some(v) = views.iter().find(|v| v.hit(p)) {
|
||||
if app.ui.gfx_edit.is_some() {
|
||||
|
|
@ -964,6 +968,21 @@ fn start_edit_at(app: &mut FilmcraftApp, ui: &egui::Ui, v: &LayerView, p: Pos2,
|
|||
actions.push(("graphics.selectLayer".into(), json!({"clip": v.clip.0, "layers": [v.layer]})));
|
||||
}
|
||||
|
||||
/// Edit ▸ Select All while text is edited on the monitor selects all of that text, not the
|
||||
/// timeline clips: on macOS the native menu takes Cmd+A before the text sees the key (#1102).
|
||||
/// False when no text is being edited.
|
||||
pub(crate) fn select_all_edited_text(app: &mut FilmcraftApp) -> bool {
|
||||
let Some((clip, layer)) = app.ui.gfx_edit.as_ref().map(|e| (e.clip, e.layer)) else { return false };
|
||||
let t = app.session.playhead();
|
||||
let Some((_, it)) = app.session.active_sequence().and_then(|q| q.find_item(ClipId(clip))) else { return false };
|
||||
let Some(ItemKind::Graphic { width, height, .. }) = app.session.project.item(it.item).map(|p| &p.kind) else { return false };
|
||||
let Some(effect) = layer_indices(&it.effects).get(layer).and_then(|&i| it.effects.get(i)) else { return false };
|
||||
let Some(len) = eval_layer(effect, it.source_time_at(t), (*width, *height)).as_ref().and_then(text_of).map(|tp| tp.text.len()) else { return false };
|
||||
let Some(ed) = app.ui.gfx_edit.as_mut() else { return false };
|
||||
(ed.anchor, ed.caret) = (0, len);
|
||||
true
|
||||
}
|
||||
|
||||
/// Keyboard handling while a text layer is being edited.
|
||||
fn text_edit(app: &mut FilmcraftApp, ui: &mut egui::Ui, v: &LayerView, mut ed: GfxEdit, resp: &egui::Response, actions: &mut Vec<(String, Value)>) {
|
||||
let _ = resp;
|
||||
|
|
|
|||
|
|
@ -545,3 +545,28 @@ fn a_hidden_layer_has_no_box_and_cannot_be_clicked() {
|
|||
d.frames(4);
|
||||
assert_eq!(ids(&mut d).len(), 14);
|
||||
}
|
||||
|
||||
/// A double-click on a text layer edits it with all its text selected, so typing replaces it; while
|
||||
/// it is edited, Select All selects the text again, not the timeline clips, as in Premiere (#1102).
|
||||
#[test]
|
||||
fn double_click_and_select_all_select_the_text_being_edited() {
|
||||
let mut d = Driver::new();
|
||||
let (clip, pre) = d.point_text();
|
||||
let (a, b) = (d.handle(&pre, 0), d.handle(&pre, 2));
|
||||
d.ok("ui.click", json!({"x": (a.0 + b.0) / 2.0, "y": (a.1 + b.1) / 2.0, "count": 2}));
|
||||
d.frames(4);
|
||||
let edit = |d: &Driver| d.harness.state().ui.gfx_edit.as_ref().map(|e| (e.clip, e.layer, e.anchor, e.caret));
|
||||
assert_eq!(edit(&d), Some((clip, 0, 0, "Title".len())), "the double-click selects the whole text");
|
||||
|
||||
// caret at the end, then Select All as the native macOS menu sends it (it takes Cmd+A first)
|
||||
if let Some(e) = d.harness.state_mut().ui.gfx_edit.as_mut() {
|
||||
(e.anchor, e.caret) = (5, 5);
|
||||
}
|
||||
let selection = d.harness.state().session.state.selection.clone();
|
||||
let (tx, rx) = channel();
|
||||
d.harness.state_mut().command_inbox = Some(rx);
|
||||
tx.send("edit.selectAll".to_string()).unwrap();
|
||||
d.frames(2);
|
||||
assert_eq!(edit(&d), Some((clip, 0, 0, 5)), "Select All selects the text being edited");
|
||||
assert_eq!(d.harness.state().session.state.selection, selection, "and leaves the timeline selection alone");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ duration (a track is added if needed).
|
|||
| Tool | On the Program monitor |
|
||||
|---|---|
|
||||
| Type (T) | Click empty picture: new point-text layer with a caret. Drag on empty picture: new paragraph-text layer with that box. Click a text layer: caret there. The box of the text being typed into is red. Type; ←/→ (⌥ word, ⌘ line), ↑/↓, Home/End, Shift to select, ⌘A, ⌘C/⌘X/⌘V, Return = new line, Backspace/Delete, Esc = stop editing. Drag inside the edited text to select. |
|
||||
| Selection (V) | Click a layer to select it (box with handles and anchor point; only selected layers have a box, and a layer whose visibility is off has none and cannot be clicked); drag to move; drag the anchor point to move it alone; drag a handle to scale point text about its anchor, resize a paragraph-text box (see *Point text and paragraph text*), or change a shape's Size: the dragged side or corner follows the pointer while the opposite one and the anchor point stay, Scale is untouched, and Shift on a corner keeps the proportions (a path, which has no Size, stretches instead); double-click a text layer to edit it. |
|
||||
| Selection (V) | Click a layer to select it (box with handles and anchor point; only selected layers have a box, and a layer whose visibility is off has none and cannot be clicked); drag to move; drag the anchor point to move it alone; drag a handle to scale point text about its anchor, resize a paragraph-text box (see *Point text and paragraph text*), or change a shape's Size: the dragged side or corner follows the pointer while the opposite one and the anchor point stay, Scale is untouched, and Shift on a corner keeps the proportions (a path, which has no Size, stretches instead); double-click a text layer to edit it with all its text selected, so typing replaces it; while text is edited, Select All (Cmd/Ctrl+A or Edit ▸ Select All) selects all of that text instead of the timeline clips. |
|
||||
| Rectangle / Ellipse | Drag to draw a shape layer. |
|
||||
| Pen (P) | Click to place points; click the first point (or Return) to close the path; Esc cancels. |
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue