mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-24 10:16:59 -06:00
Layout: Go Back after Presentation returns to the last spread presented
Presentation's spreads now count as one jump in the window's history, and leaving it as a jump back to the view it was entered from, at the place the view was. Before, the history stayed on the last presented spread while the view was put back, so Go Back couldn't reach it. docs/gaps.md: Go Back and Go Forward are two of the missing menu items, 149.
This commit is contained in:
@@ -262,7 +262,7 @@ fn page_ids(doc: &Document) -> Vec<designcraft_doc::ids::PageId> {
|
||||
|
||||
/// The page in view and the view centre's offset from that page's centre. Parent pages have none,
|
||||
/// nor has a view still waiting to be fitted (leaving parent pages for a document page).
|
||||
fn page_in_view(app: &DesignApp) -> Option<(designcraft_doc::ids::PageId, DVec2)> {
|
||||
pub(crate) fn page_in_view(app: &DesignApp) -> Option<(designcraft_doc::ids::PageId, DVec2)> {
|
||||
let st = app.session.active().filter(|st| !st.editing_parents)?;
|
||||
let (v, r) = (app.view().filter(|v| v.fitted)?, app.canvas_rect?);
|
||||
let abs = current_page(app)?;
|
||||
|
||||
@@ -194,6 +194,12 @@ pub struct UiState {
|
||||
/// The view (by its `views` key) Presentation was entered from; leaving puts it back.
|
||||
#[serde(skip)]
|
||||
pub presentation_view: Option<(u64, View)>,
|
||||
/// The page in that view and the place on it, for Go Back after leaving Presentation.
|
||||
#[serde(skip)]
|
||||
pub presentation_page: Option<(designcraft_doc::ids::PageId, designcraft_geom::Vec2)>,
|
||||
/// That view's Go Back / Go Forward history; leaving puts it back with one jump added.
|
||||
#[serde(skip)]
|
||||
pub(crate) presentation_history: Option<page_history::PageHistory>,
|
||||
pub frame_edges: bool,
|
||||
pub rulers: bool,
|
||||
pub guides: bool,
|
||||
@@ -362,6 +368,8 @@ impl Default for UiState {
|
||||
screen_mode: ScreenMode::Normal,
|
||||
presentation_return: ScreenMode::Normal,
|
||||
presentation_view: None,
|
||||
presentation_page: None,
|
||||
presentation_history: None,
|
||||
frame_edges: true,
|
||||
rulers: true,
|
||||
guides: true,
|
||||
|
||||
@@ -1978,13 +1978,28 @@ fn set_screen_mode(app: &mut DesignApp, mode: ScreenMode) {
|
||||
app.ui.presentation_return = app.ui.screen_mode;
|
||||
// Presentation fits the spread to the screen; leaving it puts the user's view back.
|
||||
app.ui.presentation_view = app.view_key().zip(app.view().copied());
|
||||
app.ui.presentation_page = crate::canvas::page_in_view(app);
|
||||
app.ui.presentation_history = app.page_history().cloned();
|
||||
}
|
||||
if mode != ScreenMode::Presentation
|
||||
&& presenting
|
||||
&& let Some((k, v)) = app.ui.presentation_view.take()
|
||||
&& let Some(view) = app.views.get_mut(&k)
|
||||
&& app.views.contains_key(&k)
|
||||
{
|
||||
*view = v;
|
||||
// Go Back sees the presentation as one jump to the last spread presented, and putting the
|
||||
// view back as a jump from there: the spreads in between would otherwise have replaced the
|
||||
// place the view was at with the presentation's.
|
||||
let shown = app.ui.presentation_page.take().zip(crate::canvas::page_in_view(app)).filter(|_| app.view_key() == Some(k));
|
||||
let h = app.page_history.entry(k).or_default();
|
||||
*h = app.ui.presentation_history.take().unwrap_or_default();
|
||||
if let Some(((from, at), (to, offset))) = shown {
|
||||
h.leave(from, at);
|
||||
h.visit(to, offset);
|
||||
h.visit(from, at);
|
||||
}
|
||||
if let Some(view) = app.views.get_mut(&k) {
|
||||
*view = v;
|
||||
}
|
||||
}
|
||||
app.ui.screen_mode = mode;
|
||||
}
|
||||
@@ -4346,6 +4361,64 @@ mod tests {
|
||||
assert_eq!(spread(&app), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn go_back_after_presentation_returns_to_the_last_spread_presented() {
|
||||
let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
app.session.execute("file.new", &json!({"pages": 7, "facingPages": true})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
let frame = |app: &mut crate::DesignApp, events: Vec<egui::Event>| {
|
||||
let input = egui::RawInput {
|
||||
screen_rect: Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1400.0, 900.0))),
|
||||
events,
|
||||
..Default::default()
|
||||
};
|
||||
let mut out = ctx.run_ui(input, |ui| {
|
||||
app.logic(&ui.ctx().clone());
|
||||
app.ui(ui);
|
||||
});
|
||||
out.textures_delta.clear();
|
||||
};
|
||||
let key = |k: egui::Key, modifiers: egui::Modifiers| {
|
||||
vec![
|
||||
egui::Event::Key { key: k, physical_key: None, pressed: true, repeat: false, modifiers },
|
||||
egui::Event::Key { key: k, physical_key: None, pressed: false, repeat: false, modifiers },
|
||||
]
|
||||
};
|
||||
let spread = |app: &crate::DesignApp| {
|
||||
let st = app.session.active().unwrap();
|
||||
crate::canvas::current_slot(app, &designcraft_tools::layout::CanvasLayout::new(&st.doc, false)).unwrap()
|
||||
};
|
||||
let cmd = egui::Modifiers { command: true, ctrl: true, ..Default::default() };
|
||||
frame(&mut app, vec![]);
|
||||
frame(&mut app, vec![]);
|
||||
// Scrolled off the page's centre, so the place Go Back returns to is not just the page.
|
||||
let view = app.view_mut().unwrap();
|
||||
view.origin.x += 40.0;
|
||||
view.origin.y += 60.0;
|
||||
frame(&mut app, vec![]);
|
||||
assert_eq!(spread(&app), 0);
|
||||
let before = *app.view().unwrap();
|
||||
// Presentation goes on to spreads 1 and 2; leaving it puts spread 0 back as it was.
|
||||
app.run("view.screenMode", json!({"mode": "presentation"})).unwrap();
|
||||
frame(&mut app, vec![]);
|
||||
frame(&mut app, key(egui::Key::ArrowRight, egui::Modifiers::NONE));
|
||||
frame(&mut app, key(egui::Key::ArrowRight, egui::Modifiers::NONE));
|
||||
assert_eq!(spread(&app), 2);
|
||||
app.run("view.screenMode", json!({"mode": "normal"})).unwrap();
|
||||
frame(&mut app, vec![]);
|
||||
assert_eq!(spread(&app), 0);
|
||||
assert!(!menu_enabled(&app, "view.goForward"));
|
||||
frame(&mut app, key(egui::Key::PageUp, cmd));
|
||||
assert_eq!(spread(&app), 2, "Go Back shows the last spread presented");
|
||||
frame(&mut app, key(egui::Key::PageUp, cmd));
|
||||
assert_eq!(spread(&app), 0, "Go Back again, the view Presentation was entered from");
|
||||
let v = *app.view().unwrap();
|
||||
assert!((v.origin - before.origin).hypot() < 1e-6, "where it was: {:?} vs {:?}", v.origin, before.origin);
|
||||
assert!(!menu_enabled(&app, "view.goBack"), "the presentation is one jump: spread 1 isn't kept");
|
||||
frame(&mut app, key(egui::Key::PageDown, cmd));
|
||||
assert_eq!(spread(&app), 2, "Go Forward");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn presentation_shows_one_spread_and_goes_through_them_with_keys_and_clicks() {
|
||||
let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
|
||||
+1
-1
@@ -165,7 +165,7 @@ Kind: **F** feature · **U** UI/UX · **T** typography · **FF** file format ·
|
||||
- **Estimate:** 30–50 h.
|
||||
|
||||
### 16. Menu items still missing (U)
|
||||
- **Missing:** 151 of 482 in-scope items of InDesign 21.6's menu dump have no match (measured 2026-10-10; some exist under other labels): Type ▸ Notes
|
||||
- **Missing:** 149 of 482 in-scope items of InDesign 21.6's menu dump have no match (measured 2026-10-10; some exist under other labels): Type ▸ Notes
|
||||
and Track Changes submenus (the panels and commands exist), hyperlink and cross-reference
|
||||
update commands, Convert Bullets/Numbering to Text, Convert Variable to Text, Object ▸ Clear
|
||||
Effects / Clear All Transparency / Rotate 180° / Reverse Path,
|
||||
|
||||
Reference in New Issue
Block a user