blob: 71504fb2a6ba145e628636678aedc5805f405a6e [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::scene::facets::FacetId;
use crate::scene::layout::ArrangerPtr;
use crate::scene::scene::Scene;
use crate::{IdFromRaw, IdGenerator2, Size};
use std::any::Any;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// Identifier for a group.
pub struct GroupId(u64);
impl GroupId {
/// Create a new group identifier.
pub(crate) fn new() -> Self {
IdGenerator2::<GroupId>::next().expect("group_id")
}
}
impl IdFromRaw for GroupId {
fn from_raw(id: u64) -> GroupId {
GroupId(id)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) enum GroupMember {
Facet(FacetId),
Group(GroupId),
}
/// Dynamic type for data an arranger might want to keep per group
/// member.
pub type GroupMemberData = Box<dyn Any>;
impl GroupMember {
fn is_facet(&self, facet_id: FacetId) -> bool {
match self {
GroupMember::Group(_) => false,
GroupMember::Facet(member_facet_id) => *member_facet_id == facet_id,
}
}
}
#[derive(Debug)]
pub(crate) struct GroupEntry {
member: GroupMember,
member_data: Option<GroupMemberData>,
}
#[derive(Debug)]
pub(crate) struct Group {
// TODO(https://fxbug.dev/42165549)
#[allow(unused)]
pub id: GroupId,
// TODO(https://fxbug.dev/42165549)
#[allow(unused)]
pub label: String,
pub members: Vec<GroupEntry>,
pub arranger: Option<ArrangerPtr>,
}
#[derive(Debug)]
pub(crate) struct GroupMap {
root_group_id: Option<GroupId>,
map: HashMap<GroupId, Group>,
}
impl GroupMap {
pub fn new() -> Self {
let map = HashMap::new();
Self { root_group_id: None, map }
}
pub fn get_root_group_id(&self) -> GroupId {
self.root_group_id.expect("root_group_id")
}
pub fn add_facet_to_group(
&mut self,
facet_id: FacetId,
group_id: GroupId,
member_data: Option<GroupMemberData>,
) {
let group = self.map.get_mut(&group_id).expect("group");
group.members.push(GroupEntry { member: GroupMember::Facet(facet_id), member_data });
}
pub fn remove_facet_from_group(&mut self, facet_id: FacetId, group_id: GroupId) {
let group = self.map.get_mut(&group_id).expect("group");
group.members.retain(|entry| !entry.member.is_facet(facet_id));
}
pub fn group_members(&self, group_id: GroupId) -> Vec<GroupMember> {
self.map
.get(&group_id)
.expect("group_id")
.members
.iter()
.map(|entry| entry.member)
.collect()
}
pub(crate) fn group_member_data(&self, group_id: GroupId) -> Vec<&Option<GroupMemberData>> {
let member_data = self
.map
.get(&group_id)
.expect("group_id")
.members
.iter()
.map(|entry| &entry.member_data)
.collect();
member_data
}
pub fn group_arranger(&self, group_id: GroupId) -> Option<&ArrangerPtr> {
self.map.get(&group_id).and_then(|group| group.arranger.as_ref())
}
pub fn set_group_arranger(&mut self, group_id: GroupId, group_arranger: ArrangerPtr) {
let group = self.map.get_mut(&group_id).expect("group");
group.arranger = Some(group_arranger);
}
pub fn start_group(
&mut self,
group_id: GroupId,
label: &str,
arranger: ArrangerPtr,
parent: Option<&GroupId>,
member_data: Option<GroupMemberData>,
) {
if self.root_group_id.is_none() {
self.root_group_id = Some(group_id);
}
let group = Group {
id: group_id,
label: String::from(label),
members: Vec::new(),
arranger: Some(arranger),
};
self.map.insert(group_id, group);
if let Some(parent) = parent {
let group = self.map.get_mut(&parent).expect("group");
group.members.push(GroupEntry { member: GroupMember::Group(group_id), member_data });
}
}
fn calculate_size_map_internal(
&self,
target_size: &Size,
scene: &Scene,
group_id: &GroupId,
size_map: &mut HashMap<GroupMember, Size>,
) -> Size {
let group_members = self.group_members(*group_id);
let mut member_sizes = Vec::new();
for member in group_members.iter() {
match member {
GroupMember::Group(member_group_id) => {
let size = self.calculate_size_map_internal(
target_size,
scene,
&member_group_id,
size_map,
);
size_map.insert(*member, size);
member_sizes.push(size);
}
GroupMember::Facet(member_facet_id) => {
let size = scene.calculate_facet_size(&member_facet_id, *target_size);
member_sizes.push(size);
size_map.insert(*member, size);
}
}
}
let optional_arranger = self.group_arranger(*group_id);
if let Some(arranger) = optional_arranger {
let member_data = self.group_member_data(*group_id);
let mut mut_sizes = member_sizes.clone();
let arranged_size = arranger.calculate_size(*target_size, &mut mut_sizes, &member_data);
for ((member_id, member_size), new_member_size) in
group_members.iter().zip(member_sizes.iter()).zip(mut_sizes.iter())
{
if member_size != new_member_size {
size_map.insert(*member_id, *new_member_size);
}
}
arranged_size
} else {
panic!("need an arranger");
}
}
pub fn calculate_size_map(
&self,
target_size: Size,
scene: &Scene,
) -> HashMap<GroupMember, Size> {
let mut size_map = HashMap::new();
let root_group_id = self.root_group_id.expect("root_group_id");
let root_size =
self.calculate_size_map_internal(&target_size, scene, &root_group_id, &mut size_map);
size_map.insert(GroupMember::Group(root_group_id), root_size);
size_map
}
}