Files
photocraft/crates/ui-egui/src/layer_reveal.rs
T
Brandon ThomasandClaude Opus 5.5 b9809ca63c Dock polish: Layers gets the height, Character/Paragraph group, eliding tab strips, reveal the active layer (#147, #150, #151, #152) (#181)
- #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>
2026-10-05 07:22:37 -04:00

65 lines
2.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 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;