carnelian/scene/
group.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::scene::facets::FacetId;
6use crate::scene::layout::ArrangerPtr;
7use crate::scene::scene::Scene;
8use crate::{IdFromRaw, IdGenerator2, Size};
9use std::any::Any;
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13/// Identifier for a group.
14pub struct GroupId(u64);
15
16impl GroupId {
17    /// Create a new group identifier.
18    pub(crate) fn new() -> Self {
19        IdGenerator2::<GroupId>::next().expect("group_id")
20    }
21}
22
23impl IdFromRaw for GroupId {
24    fn from_raw(id: u64) -> GroupId {
25        GroupId(id)
26    }
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub(crate) enum GroupMember {
31    Facet(FacetId),
32    Group(GroupId),
33}
34
35/// Dynamic type for data an arranger might want to keep per group
36/// member.
37pub type GroupMemberData = Box<dyn Any>;
38
39impl GroupMember {
40    fn is_facet(&self, facet_id: FacetId) -> bool {
41        match self {
42            GroupMember::Group(_) => false,
43            GroupMember::Facet(member_facet_id) => *member_facet_id == facet_id,
44        }
45    }
46}
47
48#[derive(Debug)]
49pub(crate) struct GroupEntry {
50    member: GroupMember,
51    member_data: Option<GroupMemberData>,
52}
53
54#[derive(Debug)]
55pub(crate) struct Group {
56    // TODO(https://fxbug.dev/42165549)
57    #[allow(unused)]
58    pub id: GroupId,
59    // TODO(https://fxbug.dev/42165549)
60    #[allow(unused)]
61    pub label: String,
62    pub members: Vec<GroupEntry>,
63    pub arranger: Option<ArrangerPtr>,
64}
65
66#[derive(Debug)]
67pub(crate) struct GroupMap {
68    root_group_id: Option<GroupId>,
69    map: HashMap<GroupId, Group>,
70}
71
72impl GroupMap {
73    pub fn new() -> Self {
74        let map = HashMap::new();
75        Self { root_group_id: None, map }
76    }
77
78    pub fn get_root_group_id(&self) -> GroupId {
79        self.root_group_id.expect("root_group_id")
80    }
81
82    pub fn add_facet_to_group(
83        &mut self,
84        facet_id: FacetId,
85        group_id: GroupId,
86        member_data: Option<GroupMemberData>,
87    ) {
88        let group = self.map.get_mut(&group_id).expect("group");
89
90        group.members.push(GroupEntry { member: GroupMember::Facet(facet_id), member_data });
91    }
92
93    pub fn remove_facet_from_group(&mut self, facet_id: FacetId, group_id: GroupId) {
94        let group = self.map.get_mut(&group_id).expect("group");
95        group.members.retain(|entry| !entry.member.is_facet(facet_id));
96    }
97
98    pub fn group_members(&self, group_id: GroupId) -> Vec<GroupMember> {
99        self.map
100            .get(&group_id)
101            .expect("group_id")
102            .members
103            .iter()
104            .map(|entry| entry.member)
105            .collect()
106    }
107
108    pub(crate) fn group_member_data(&self, group_id: GroupId) -> Vec<&Option<GroupMemberData>> {
109        let member_data = self
110            .map
111            .get(&group_id)
112            .expect("group_id")
113            .members
114            .iter()
115            .map(|entry| &entry.member_data)
116            .collect();
117        member_data
118    }
119
120    pub fn group_arranger(&self, group_id: GroupId) -> Option<&ArrangerPtr> {
121        self.map.get(&group_id).and_then(|group| group.arranger.as_ref())
122    }
123
124    pub fn set_group_arranger(&mut self, group_id: GroupId, group_arranger: ArrangerPtr) {
125        let group = self.map.get_mut(&group_id).expect("group");
126        group.arranger = Some(group_arranger);
127    }
128
129    pub fn start_group(
130        &mut self,
131        group_id: GroupId,
132        label: &str,
133        arranger: ArrangerPtr,
134        parent: Option<&GroupId>,
135        member_data: Option<GroupMemberData>,
136    ) {
137        if self.root_group_id.is_none() {
138            self.root_group_id = Some(group_id);
139        }
140        let group = Group {
141            id: group_id,
142            label: String::from(label),
143            members: Vec::new(),
144            arranger: Some(arranger),
145        };
146        self.map.insert(group_id, group);
147        if let Some(parent) = parent {
148            let group = self.map.get_mut(&parent).expect("group");
149            group.members.push(GroupEntry { member: GroupMember::Group(group_id), member_data });
150        }
151    }
152
153    fn calculate_size_map_internal(
154        &self,
155        target_size: &Size,
156        scene: &Scene,
157        group_id: &GroupId,
158        size_map: &mut HashMap<GroupMember, Size>,
159    ) -> Size {
160        let group_members = self.group_members(*group_id);
161        let mut member_sizes = Vec::new();
162        for member in group_members.iter() {
163            match member {
164                GroupMember::Group(member_group_id) => {
165                    let size = self.calculate_size_map_internal(
166                        target_size,
167                        scene,
168                        &member_group_id,
169                        size_map,
170                    );
171                    size_map.insert(*member, size);
172                    member_sizes.push(size);
173                }
174                GroupMember::Facet(member_facet_id) => {
175                    let size = scene.calculate_facet_size(&member_facet_id, *target_size);
176                    member_sizes.push(size);
177                    size_map.insert(*member, size);
178                }
179            }
180        }
181        let optional_arranger = self.group_arranger(*group_id);
182        if let Some(arranger) = optional_arranger {
183            let member_data = self.group_member_data(*group_id);
184            let mut mut_sizes = member_sizes.clone();
185            let arranged_size = arranger.calculate_size(*target_size, &mut mut_sizes, &member_data);
186            for ((member_id, member_size), new_member_size) in
187                group_members.iter().zip(member_sizes.iter()).zip(mut_sizes.iter())
188            {
189                if member_size != new_member_size {
190                    size_map.insert(*member_id, *new_member_size);
191                }
192            }
193            arranged_size
194        } else {
195            panic!("need an arranger");
196        }
197    }
198
199    pub fn calculate_size_map(
200        &self,
201        target_size: Size,
202        scene: &Scene,
203    ) -> HashMap<GroupMember, Size> {
204        let mut size_map = HashMap::new();
205        let root_group_id = self.root_group_id.expect("root_group_id");
206        let root_size =
207            self.calculate_size_map_internal(&target_size, scene, &root_group_id, &mut size_map);
208        size_map.insert(GroupMember::Group(root_group_id), root_size);
209        size_map
210    }
211}