mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-01 22:26:49 -06:00
#1311: group the dock's panel icons as InDesign does
This commit is contained in:
@@ -92,30 +92,55 @@ impl Placed {
|
||||
|
||||
/// A group of the unplaced registered panels of `panels`, with the one at `active` in front
|
||||
/// when it is among them.
|
||||
fn group(&mut self, panels: &[String], active: usize) -> Option<Group<String>> {
|
||||
let front = panels.get(active).and_then(|p| normalize(p));
|
||||
let kept: Vec<String> = panels.iter().filter_map(|p| self.take(p)).collect();
|
||||
fn group(&mut self, panels: &[impl AsRef<str>], active: usize) -> Option<Group<String>> {
|
||||
let front = panels.get(active).and_then(|p| normalize(p.as_ref()));
|
||||
let kept: Vec<String> = panels.iter().filter_map(|p| self.take(p.as_ref())).collect();
|
||||
let active = front.and_then(|f| kept.iter().position(|p| p == f)).unwrap_or(0);
|
||||
(!kept.is_empty()).then(|| Group::new(kept, active))
|
||||
}
|
||||
}
|
||||
|
||||
/// A workspace's iconic column: its named `icon_groups` (Essentials Classic, Typography), or
|
||||
/// one group per panel not placed yet. Window › Styles opens the style panels as a floating
|
||||
/// group, so they start outside it.
|
||||
/// The iconic column's groups, top to bottom, in a workspace without its own `icon_groups`:
|
||||
/// InDesign's panel families, with a separator only between families.
|
||||
const ICON_GROUPS: &[&[&str]] = &[
|
||||
&["stroke", "color", "swatches", "gradient"],
|
||||
&["effects"],
|
||||
&["character", "paragraph", "typography"],
|
||||
&["glyphs"],
|
||||
&["table"],
|
||||
&["textWrap"],
|
||||
&["align", "pathfinder"],
|
||||
&["flexLayout", "liquid"],
|
||||
&["links", "library"],
|
||||
&["info"],
|
||||
&["attributes", "preflight"],
|
||||
&["notes", "trackChanges", "conditions"],
|
||||
&["hyperlinks", "bookmarks"],
|
||||
&["buttons", "states"],
|
||||
&["media", "transitions"],
|
||||
&["articles", "tags"],
|
||||
&["book", "dataMerge", "scripts"],
|
||||
];
|
||||
|
||||
/// A workspace's iconic column of the panels not placed yet: its named `icon_groups`
|
||||
/// (Essentials Classic, Typography), or [`ICON_GROUPS`] followed by any other dock panel as a
|
||||
/// group of its own. Window › Styles opens the style panels as a floating group, so they start
|
||||
/// outside it.
|
||||
fn icon_column(icon_groups: Option<&[Vec<String>]>, placed: &mut Placed) -> Option<Column<String>> {
|
||||
let (groups, width): (Vec<Group<String>>, f32) = match icon_groups {
|
||||
Some(groups) => (groups.iter().filter_map(|g| placed.group(g, 0)).collect(), NAMED_ICON_WIDTH),
|
||||
None => (
|
||||
crate::dock::DOCK_TABS
|
||||
.iter()
|
||||
.chain(crate::dock::ICON_PANELS)
|
||||
.filter(|p| !FLOATING_GROUPS.iter().any(|g| g.contains(&p.0)))
|
||||
.filter_map(|p| placed.take(p.0))
|
||||
.map(|id| Group::new(vec![id], 0))
|
||||
.collect(),
|
||||
ICON_WIDTH,
|
||||
),
|
||||
None => {
|
||||
let mut groups: Vec<Group<String>> = ICON_GROUPS.iter().filter_map(|g| placed.group(g, 0)).collect();
|
||||
groups.extend(
|
||||
crate::dock::DOCK_TABS
|
||||
.iter()
|
||||
.chain(crate::dock::ICON_PANELS)
|
||||
.filter(|p| !FLOATING_GROUPS.iter().any(|g| g.contains(&p.0)))
|
||||
.filter_map(|p| placed.take(p.0))
|
||||
.map(|id| Group::new(vec![id], 0)),
|
||||
);
|
||||
(groups, ICON_WIDTH)
|
||||
}
|
||||
};
|
||||
(!groups.is_empty()).then_some(Column { groups, width: COLUMN_WIDTH, iconic: true, iconic_width: Some(width) })
|
||||
}
|
||||
|
||||
@@ -811,7 +811,9 @@ fn default_workspaces_are_the_canvas_beside_an_end_dock() {
|
||||
assert_eq!(outer.groups.len(), 1);
|
||||
assert_eq!(outer.groups[0].panels, ["properties", "pages", "layers"]);
|
||||
assert!(icons.iconic);
|
||||
assert!(icons.groups.iter().all(|g| g.panels.len() == 1));
|
||||
let groups: Vec<Vec<&str>> = icons.groups.iter().map(|g| g.panels.iter().map(String::as_str).collect()).collect();
|
||||
let expected: Vec<Vec<&str>> = ICON_GROUPS.iter().map(|g| g.to_vec()).collect();
|
||||
assert_eq!(groups, expected, "the iconic column groups InDesign's panel families");
|
||||
assert!(!layout.contains(&"paragraphStyles".to_string()), "Window › Styles opens the styles floating");
|
||||
// Essentials Classic: only its named icon groups, in one iconic column.
|
||||
app.run("window.workspace", json!({"name": "Essentials Classic"})).unwrap();
|
||||
@@ -826,6 +828,32 @@ fn default_workspaces_are_the_canvas_beside_an_end_dock() {
|
||||
assert!(groups.iter().flatten().all(|p| expected.iter().flatten().any(|e| e == p)));
|
||||
}
|
||||
|
||||
/// Every dock panel that starts in the iconic column has one place in [`ICON_GROUPS`], so a new
|
||||
/// panel is not left as a group of its own.
|
||||
#[test]
|
||||
fn every_icon_panel_is_in_one_default_icon_group() {
|
||||
for (id, _, _) in crate::dock::ICON_PANELS.iter().filter(|p| !FLOATING_GROUPS.iter().any(|g| g.contains(&p.0))) {
|
||||
assert_eq!(ICON_GROUPS.iter().flat_map(|g| g.iter()).filter(|p| *p == id).count(), 1, "{id}");
|
||||
}
|
||||
for id in ICON_GROUPS.iter().flat_map(|g| g.iter()) {
|
||||
assert!(crate::dock::ICON_PANELS.iter().any(|p| p.0 == *id), "{id} is not a dock panel");
|
||||
}
|
||||
}
|
||||
|
||||
/// A panel the workspace places elsewhere leaves its icon group; a group it empties goes.
|
||||
#[test]
|
||||
fn placed_panels_leave_their_icon_groups() {
|
||||
let mut placed = Placed::default();
|
||||
for id in ["properties", "pages", "layers", "swatches", "effects"] {
|
||||
placed.take(id);
|
||||
}
|
||||
let column = icon_column(None, &mut placed).unwrap();
|
||||
let groups: Vec<Vec<&str>> = column.groups.iter().map(|g| g.panels.iter().map(String::as_str).collect()).collect();
|
||||
assert_eq!(groups.first().unwrap(), &["stroke", "color", "gradient"]);
|
||||
assert_eq!(groups.get(1).unwrap(), &["character", "paragraph", "typography"]);
|
||||
assert_eq!(groups.len(), ICON_GROUPS.len() - 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_dock_is_at_the_right_in_english_and_the_left_in_arabic() {
|
||||
let tab = |h: &Harness<'static, DesignApp>| h.ctx.read_response(tab_id("properties")).map(|r| r.rect).unwrap();
|
||||
|
||||
@@ -228,8 +228,8 @@ mod tests {
|
||||
assert_eq!(columns[0].groups[0].active, 3);
|
||||
assert!(!columns[0].iconic);
|
||||
let icons = &columns[1];
|
||||
assert!(icons.iconic && icons.groups.iter().any(|g| g.panels == ["stroke"]));
|
||||
assert!(icons.groups.iter().all(|g| g.panels != ["swatches"]), "each panel appears once");
|
||||
assert!(icons.iconic && icons.groups.iter().any(|g| g.panels == ["stroke", "color", "gradient"]));
|
||||
assert!(icons.groups.iter().all(|g| !g.panels.iter().any(|p| p == "swatches")), "each panel appears once");
|
||||
|
||||
// Splits: a vertical split stacks groups in one column, a horizontal one adds a column
|
||||
// (the dock lists columns from the window edge inwards).
|
||||
|
||||
Reference in New Issue
Block a user