mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-31 05:17:12 -06:00
- #147: default-sized dock groups give way (down to compact heights) so the filler (Layers) keeps a preferred 500 pt: 10+ rows at 1440x900, ~5 at 1280x720 (was ~2.5 and 0). Heights the user dragged to are untouched; the first splitter drag pins the other groups at the heights they show. - #150: Window > Character / Paragraph (and Type > Panels) open a new Character | Paragraph dock group below Properties instead of switching Properties; choosing the visible one again closes it; workspace presets and Reset close it. Saved layouts missing a group slot it below its default predecessor, so it never lands under Layers. - #151: dock tab strips (Pro and Studio) fit left of the panel menu button: padding shrinks, then labels elide with '...', then overflowing tabs move into a >> chevron menu; the selected tab always stays on the strip. - #152: when the active layer changes by any means (canvas auto-select, Select commands, undo, automation) the Layers panel opens its closed parent groups (layer.setExpanded) and scrolls the row into view if it is hidden. - Tests: rows visible at 900/720 pt; Character keeps Properties and toggles; tab rects never intersect the menu button in every theme at 1x/2x and 180-420 pt; chevron menu switches tabs; reveal expands and scrolls (and doesn't scroll for visible rows); undo reveals. Adjustment-editor and shortcut tests no longer depend on default group heights. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
2.8 KiB
Rust
65 lines
2.8 KiB
Rust
//! Reveal the active layer in the Layers panel (#152), like Photoshop: whenever the active
|
||
//! layer changes, by whatever means (a click on the canvas with Auto-Select, Select › layer
|
||
//! commands, ⌥[ / ⌥], undo, automation), its closed parent groups open (`layer.setExpanded`)
|
||
//! and the panel scrolls just enough to show its row, unless the row is already in view.
|
||
//!
|
||
//! Only a change of the active layer reveals: closing the group that holds it, or scrolling
|
||
//! away, is left alone until the next change.
|
||
|
||
use egui::{Rect, pos2};
|
||
use photocraft_doc::{LayerContent, LayerId};
|
||
use serde_json::json;
|
||
|
||
use crate::PhotocraftApp;
|
||
|
||
/// Last active layer the panel saw: (document index, layer).
|
||
#[derive(Clone, Copy, PartialEq)]
|
||
struct Seen(usize, Option<LayerId>);
|
||
|
||
fn seen_id() -> egui::Id {
|
||
egui::Id::new("layers-reveal-seen")
|
||
}
|
||
|
||
/// Called once per Layers panel frame, before its rows are listed. When the active layer
|
||
/// changed since the last frame, opens its closed parent groups and returns it: the row to
|
||
/// scroll into view (see [`scroll_to_row`]). The first frame of a document only records it.
|
||
pub fn track(app: &mut PhotocraftApp, ctx: &egui::Context) -> Option<LayerId> {
|
||
let index = app.session.active_index()?;
|
||
let active = app.session.active()?.active_layer;
|
||
let now = Seen(index, active);
|
||
let before = ctx.data(|d| d.get_temp::<Seen>(seen_id()));
|
||
ctx.data_mut(|d| d.insert_temp(seen_id(), now));
|
||
match before {
|
||
Some(Seen(i, prev)) if i == index && prev != active => {}
|
||
_ => return None,
|
||
}
|
||
let id = active?;
|
||
for group in closed_ancestors(app, id) {
|
||
// A view change (no history step); a failure just leaves the group closed.
|
||
let _ = app.session.execute("layer.setExpanded", json!({"layer": group.0, "expanded": true}));
|
||
}
|
||
Some(id)
|
||
}
|
||
|
||
/// The groups containing `id` that are closed, outermost first.
|
||
fn closed_ancestors(app: &PhotocraftApp, id: LayerId) -> Vec<LayerId> {
|
||
let Some(doc) = app.session.active().map(|s| &s.doc) else { return Vec::new() };
|
||
let Some(path) = doc.path_of(id) else { return Vec::new() };
|
||
(1..path.len()).filter_map(|n| doc.layer_at(path.get(..n)?)).filter(|l| matches!(&l.content, LayerContent::Group(g) if !g.expanded)).map(|l| l.id).collect()
|
||
}
|
||
|
||
/// After drawing the row that started at `top` in the Layers scroll area, scroll it into view
|
||
/// if any of it is hidden (no animation: Photoshop jumps).
|
||
pub fn scroll_to_row(ui: &egui::Ui, top: f32) {
|
||
let bottom = ui.min_rect().bottom().max(top);
|
||
let row = Rect::from_min_max(pos2(ui.min_rect().left(), top), pos2(ui.min_rect().right(), bottom));
|
||
let view = ui.clip_rect();
|
||
if row.top() < view.top() - 0.5 || row.bottom() > view.bottom() + 0.5 {
|
||
ui.scroll_to_rect_animation(row, None, egui::style::ScrollAnimation::none());
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
#[path = "layer_reveal_tests.rs"]
|
||
mod tests;
|