mirror of
https://github.com/storytold/wordcraft.git
synced 2026-11-02 16:30:05 -06:00
Task panes: Dock Left, Dock Right and Float run ui.paneDock for every pane but Styles
This commit is contained in:
@@ -1660,6 +1660,7 @@ impl WordApp {
|
||||
self.canvas.want_focus = true;
|
||||
json!({"pending": "contextMenu"})
|
||||
}
|
||||
"ui.paneDock" => return Some(panes::dock_command(self, p)),
|
||||
"ui.collapseRibbon" => {
|
||||
self.ui.ribbon_collapsed = !self.ui.ribbon_collapsed;
|
||||
json!({"collapsed": self.ui.ribbon_collapsed})
|
||||
|
||||
@@ -336,12 +336,12 @@ pub(crate) fn apply(app: &mut WordApp, request: PaneRequest<Pane>) {
|
||||
PaneRequest::FloatRect(Pane::Styles, rect) => app.ui.styles_pane_float = Some(rect),
|
||||
PaneRequest::Place(pane, place) => {
|
||||
let dock = match place {
|
||||
Place::Docked(Edge::Start) => SavedDock::Left,
|
||||
Place::Docked(Edge::End) => SavedDock::Right,
|
||||
Place::Floating => SavedDock::Float,
|
||||
Place::Docked(Edge::Start) => "left",
|
||||
Place::Docked(Edge::End) => "right",
|
||||
Place::Floating => "float",
|
||||
Place::Docked(Edge::Bottom) => return,
|
||||
};
|
||||
app.ui.pane_places.entry(pane.key().into()).or_default().dock = Some(dock);
|
||||
let _ = app.run("ui.paneDock", json!({"pane": pane.key(), "dock": dock}));
|
||||
}
|
||||
PaneRequest::Resize(pane, width) => app.ui.pane_places.entry(pane.key().into()).or_default().width = Some(width),
|
||||
PaneRequest::FloatRect(pane, rect) => app.ui.pane_places.entry(pane.key().into()).or_default().float = Some(rect),
|
||||
@@ -349,6 +349,37 @@ pub(crate) fn apply(app: &mut WordApp, request: PaneRequest<Pane>) {
|
||||
}
|
||||
}
|
||||
|
||||
/// `ui.paneDock {"pane": key, "dock"?: "left" | "right" | "float"}` (#1756): docks or floats a
|
||||
/// task pane, as its menu's Dock Left, Dock Right and Float do; without `dock` it reads the
|
||||
/// pane's place. `pane` is the pane's `panePlaces` key; Styles goes through `view.stylesPaneDock`.
|
||||
pub(crate) fn dock_command(app: &mut WordApp, p: &Value) -> Result<Value, String> {
|
||||
let key = p.get("pane").and_then(Value::as_str).ok_or("`pane` must be a task pane's key, such as \"navigation\"")?;
|
||||
let pane = Pane::ALL.into_iter().find(|pane| pane.key() == key).ok_or_else(|| format!("unknown task pane `{key}`"))?;
|
||||
let dock = match p.get("dock") {
|
||||
None => None,
|
||||
Some(v) => Some(match v.as_str() {
|
||||
Some("left") => SavedDock::Left,
|
||||
Some("right") => SavedDock::Right,
|
||||
Some("float") => SavedDock::Float,
|
||||
_ => return Err("`dock` must be left, right or float".into()),
|
||||
}),
|
||||
};
|
||||
if pane == Pane::Styles {
|
||||
let params = p.get("dock").map_or_else(|| json!({}), |d| json!({"dock": d}));
|
||||
let result = app.run("view.stylesPaneDock", params)?;
|
||||
return Ok(json!({"pane": key, "dock": result.get("dock")}));
|
||||
}
|
||||
if let Some(dock) = dock {
|
||||
app.ui.pane_places.entry(key.into()).or_default().dock = Some(dock);
|
||||
}
|
||||
let name = match pane_state(app, pane).place {
|
||||
Place::Docked(Edge::Start) => "left",
|
||||
Place::Floating => "float",
|
||||
Place::Docked(_) => "right",
|
||||
};
|
||||
Ok(json!({"pane": key, "dock": name}))
|
||||
}
|
||||
|
||||
fn close(app: &mut WordApp, pane: Pane) {
|
||||
match pane.close_command() {
|
||||
Some(id) => {
|
||||
@@ -1402,6 +1433,35 @@ mod tests {
|
||||
assert!(odd.ui.pane_places.is_empty() && odd.session.view.nav_pane);
|
||||
}
|
||||
|
||||
/// `ui.paneDock` docks or floats any pane and reads its place, as the pane's menu does
|
||||
/// (#1756); Styles goes through `view.stylesPaneDock`; junk is refused and changes nothing.
|
||||
#[test]
|
||||
fn pane_dock_command_docks_floats_and_reads_each_pane() {
|
||||
use craft_ui::panes::{Edge, Place};
|
||||
use serde_json::json;
|
||||
let mut app = crate::WordApp::new(wordcraft_engine::Session::new(wordcraft_doc::Document::from_text("")), crate::Services::default());
|
||||
assert_eq!(app.run("ui.paneDock", json!({"pane": "navigation"})).unwrap(), json!({"pane": "navigation", "dock": "left"}));
|
||||
assert_eq!(app.run("ui.paneDock", json!({"pane": "comments"})).unwrap(), json!({"pane": "comments", "dock": "right"}));
|
||||
assert_eq!(app.run("ui.paneDock", json!({"pane": "navigation", "dock": "float"})).unwrap()["dock"], "float");
|
||||
assert_eq!(super::pane_state(&app, Pane::Navigation).place, Place::Floating);
|
||||
app.run("ui.paneDock", json!({"pane": "comments", "dock": "left"})).unwrap();
|
||||
assert_eq!(super::pane_state(&app, Pane::Comments).place, Place::Docked(Edge::Start));
|
||||
assert_eq!(app.run("ui.paneDock", json!({"pane": "styles", "dock": "float"})).unwrap(), json!({"pane": "styles", "dock": "float"}));
|
||||
assert_eq!(app.session.view.styles_pane_dock, wordcraft_engine::StylesPaneDock::Floating);
|
||||
assert!(!app.ui.pane_places.contains_key("styles"), "Styles keeps its place in the view state");
|
||||
for junk in [
|
||||
json!({}),
|
||||
json!({"pane": "nope", "dock": "left"}),
|
||||
json!({"pane": 3}),
|
||||
json!({"pane": "navigation", "dock": "top"}),
|
||||
json!({"pane": "navigation", "dock": 1}),
|
||||
json!({"pane": "navigation", "dock": null}),
|
||||
] {
|
||||
assert!(app.run("ui.paneDock", junk.clone()).is_err(), "{junk}");
|
||||
}
|
||||
assert_eq!(super::pane_state(&app, Pane::Navigation).place, Place::Floating, "junk changed nothing");
|
||||
}
|
||||
|
||||
/// #3032: Delete is greyed out for built-in styles in the Styles pane (the engine refuses
|
||||
/// them — `crates/engine/src/cmd/para.rs`), while custom styles keep it enabled.
|
||||
#[test]
|
||||
|
||||
@@ -52,7 +52,7 @@ and set `WORDCRAFT_CONTROL_KEY` to that app's key.
|
||||
|
||||
| Method | Params | Result |
|
||||
|---|---|---|
|
||||
| `engine.execute` | `command`, `params` | the command's result (any id from `engine.commands`, including UI commands `ui.tab`, `ui.dialog` (`{"name": dialog, "part"?: table style part}`; `part` opens New / Modify Table Style (`newTableStyle` / `modifyTableStyle`) on that part: `wholeTable`, `headerRow`, `firstColumn`, `bandedRows`, `nwCell`… as `table.modifyStyle` names them), `ui.backstage`, `ui.zotero.*` (see `docs/zotero.md`), `ui.language` (`{"value": "auto"\|"en"\|"zh-hans"\|"zh-hant"\|"ja"\|"pt-br"\|"es"\|"uk"\|"sr"\|"sr-latn"\|"et"\|"tr"\|"ru"\|"pl"\|"de"\|"it"\|"cs"\|"hu"\|"fr"}`), `ui.theme` (`{"value": "system"\|"light"\|"dark"}`; `system` follows the OS appearance, light when it reports none), `ui.interfaceSize` (`{"value": "auto"}` or `{"percent": 50–300}`, clamped; no value reads it; `auto` keeps the system display scale, a percentage is absolute, so 100 is one screen pixel per point (#822); the result's `percent` is the size drawn at and `auto` whether it follows the system; document zoom stays `view.zoom`), `ui.animations` (`{"value": "system"\|"on"\|"off"}`; no value reads it; `system` follows the system's animation setting, which the desktop app reads on Windows, macOS, Linux and the BSDs and the web app from `prefers-reduced-motion`, and means on where the system doesn't say; the result's `enabled` is what the setting comes to and `system` what the system reports, `null` when it doesn't say), `ui.fileBrowser` (desktop: `{"purpose": "document"\|"picture"\|"recipients"\|"save"}` opens WordCraft's own file browser, for when the system file dialog doesn't show up, #576), `ui.saveAsTemplate` (File › Save As › Save as Word Template: the Save dialog for a `.dotx`, starting in the user templates folder; the result's `dir` is that folder, `null` on the web, #2852), `ui.caretAnimation` (`{"value": true\|false}`; no value reads it; off, the caret jumps and blinks on and off instead of gliding and fading), `ui.startScreen` (`{"value": true\|false}`; no value reads it; on, the default, the desktop and web apps start on File › Home when launched with nothing to open, #766), `ui.alignmentGuides` (`{"value": true\|false}`; no value reads it; on, the default, moving a picture or shape snaps it to the page, the margins and other objects, with guide lines while dragging; Alt moves freely), `ui.quickAccessToolbar` (`{"value": true\|false}`; no value toggles it; false takes the Quick Access Toolbar out of the title bar, as its menu's Hide Quick Access Toolbar does, and true brings it back, #1945), `ui.focusRibbon` (`{"value": true\|false}`; no value toggles it; in Focus, true drops the ribbon down over the page, as the bar's ⋯ does, and false puts it away, as a click on the page does; outside Focus it stays put away, #1678), `ui.contextMenu` (opens the page's context menu below the caret, as Shift+F10 does)…) |
|
||||
| `engine.execute` | `command`, `params` | the command's result (any id from `engine.commands`, including UI commands `ui.tab`, `ui.dialog` (`{"name": dialog, "part"?: table style part}`; `part` opens New / Modify Table Style (`newTableStyle` / `modifyTableStyle`) on that part: `wholeTable`, `headerRow`, `firstColumn`, `bandedRows`, `nwCell`… as `table.modifyStyle` names them), `ui.backstage`, `ui.zotero.*` (see `docs/zotero.md`), `ui.language` (`{"value": "auto"\|"en"\|"zh-hans"\|"zh-hant"\|"ja"\|"pt-br"\|"es"\|"uk"\|"sr"\|"sr-latn"\|"et"\|"tr"\|"ru"\|"pl"\|"de"\|"it"\|"cs"\|"hu"\|"fr"}`), `ui.theme` (`{"value": "system"\|"light"\|"dark"}`; `system` follows the OS appearance, light when it reports none), `ui.interfaceSize` (`{"value": "auto"}` or `{"percent": 50–300}`, clamped; no value reads it; `auto` keeps the system display scale, a percentage is absolute, so 100 is one screen pixel per point (#822); the result's `percent` is the size drawn at and `auto` whether it follows the system; document zoom stays `view.zoom`), `ui.animations` (`{"value": "system"\|"on"\|"off"}`; no value reads it; `system` follows the system's animation setting, which the desktop app reads on Windows, macOS, Linux and the BSDs and the web app from `prefers-reduced-motion`, and means on where the system doesn't say; the result's `enabled` is what the setting comes to and `system` what the system reports, `null` when it doesn't say), `ui.fileBrowser` (desktop: `{"purpose": "document"\|"picture"\|"recipients"\|"save"}` opens WordCraft's own file browser, for when the system file dialog doesn't show up, #576), `ui.saveAsTemplate` (File › Save As › Save as Word Template: the Save dialog for a `.dotx`, starting in the user templates folder; the result's `dir` is that folder, `null` on the web, #2852), `ui.caretAnimation` (`{"value": true\|false}`; no value reads it; off, the caret jumps and blinks on and off instead of gliding and fading), `ui.startScreen` (`{"value": true\|false}`; no value reads it; on, the default, the desktop and web apps start on File › Home when launched with nothing to open, #766), `ui.alignmentGuides` (`{"value": true\|false}`; no value reads it; on, the default, moving a picture or shape snaps it to the page, the margins and other objects, with guide lines while dragging; Alt moves freely), `ui.quickAccessToolbar` (`{"value": true\|false}`; no value toggles it; false takes the Quick Access Toolbar out of the title bar, as its menu's Hide Quick Access Toolbar does, and true brings it back, #1945), `ui.focusRibbon` (`{"value": true\|false}`; no value toggles it; in Focus, true drops the ribbon down over the page, as the bar's ⋯ does, and false puts it away, as a click on the page does; outside Focus it stays put away, #1678), `ui.contextMenu` (opens the page's context menu below the caret, as Shift+F10 does), `ui.paneDock` (`{"pane": "navigation"\|"clipboard"\|"styles"\|"styleInspector"\|"accessibility"\|"altText"\|"formatShape"\|"restrictEditing"\|"comments"\|"smartArtText", "dock"?: "left"\|"right"\|"float"}`; no `dock` reads it; docks or floats a task pane as its menu does, kept between runs; Styles is `view.stylesPaneDock`, #1756)…) |
|
||||
| `engine.commands` | — | every command: id, label, location, shortcut, params, enabled |
|
||||
| `document.inspect` | `text?` | blocks (text, style, runs, lists, tables), parts, sections, selection, pages |
|
||||
| `ui.inspect` | — | UI state, view, dialog, window size, page rects on screen, caret, comment balloons (`balloons`: id + screen rect; `balloon`: the selected one), perf |
|
||||
|
||||
Reference in New Issue
Block a user