2020-07-26 19:27:09 +00:00
|
|
|
mod convert;
|
|
|
|
|
2020-07-28 04:04:04 +00:00
|
|
|
use crate::{CalculatedSize, Node, Style};
|
2020-07-25 06:04:45 +00:00
|
|
|
use bevy_ecs::{Changed, Entity, Query, Res, ResMut, With, Without};
|
|
|
|
use bevy_math::Vec2;
|
2020-09-14 21:00:32 +00:00
|
|
|
use bevy_transform::prelude::{Children, Parent, Transform};
|
2020-08-29 00:08:51 +00:00
|
|
|
use bevy_utils::HashMap;
|
2020-07-25 20:14:36 +00:00
|
|
|
use bevy_window::{Window, WindowId, Windows};
|
2020-10-08 18:43:01 +00:00
|
|
|
use std::fmt;
|
2020-07-28 07:37:25 +00:00
|
|
|
use stretch::{number::Number, Stretch};
|
2020-07-25 06:04:45 +00:00
|
|
|
|
|
|
|
pub struct FlexSurface {
|
|
|
|
entity_to_stretch: HashMap<Entity, stretch::node::Node>,
|
2020-07-25 20:14:36 +00:00
|
|
|
window_nodes: HashMap<WindowId, stretch::node::Node>,
|
2020-07-25 06:04:45 +00:00
|
|
|
stretch: Stretch,
|
|
|
|
}
|
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
impl fmt::Debug for FlexSurface {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.debug_struct("FlexSurface")
|
|
|
|
.field("entity_to_stretch", &self.entity_to_stretch)
|
|
|
|
.field("window_nodes", &self.window_nodes)
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-25 20:14:36 +00:00
|
|
|
impl Default for FlexSurface {
|
|
|
|
fn default() -> Self {
|
2020-07-25 06:04:45 +00:00
|
|
|
Self {
|
|
|
|
entity_to_stretch: Default::default(),
|
2020-07-25 20:14:36 +00:00
|
|
|
window_nodes: Default::default(),
|
|
|
|
stretch: Stretch::new(),
|
2020-07-25 06:04:45 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-25 20:14:36 +00:00
|
|
|
}
|
2020-07-25 06:04:45 +00:00
|
|
|
|
2020-07-25 20:14:36 +00:00
|
|
|
impl FlexSurface {
|
|
|
|
pub fn upsert_node(&mut self, entity: Entity, style: &Style) {
|
2020-07-25 06:04:45 +00:00
|
|
|
let mut added = false;
|
|
|
|
let stretch = &mut self.stretch;
|
2020-07-26 19:27:09 +00:00
|
|
|
let stretch_style = style.into();
|
2020-07-25 06:04:45 +00:00
|
|
|
let stretch_node = self.entity_to_stretch.entry(entity).or_insert_with(|| {
|
|
|
|
added = true;
|
2020-08-16 07:30:04 +00:00
|
|
|
stretch.new_node(stretch_style, Vec::new()).unwrap()
|
2020-07-25 06:04:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
if !added {
|
|
|
|
self.stretch
|
2020-07-26 19:27:09 +00:00
|
|
|
.set_style(*stretch_node, stretch_style)
|
2020-07-25 06:04:45 +00:00
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-28 04:04:04 +00:00
|
|
|
pub fn upsert_leaf(&mut self, entity: Entity, style: &Style, calculated_size: CalculatedSize) {
|
|
|
|
let stretch = &mut self.stretch;
|
|
|
|
let stretch_style = style.into();
|
2020-07-28 07:37:25 +00:00
|
|
|
let measure = Box::new(move |constraints: stretch::geometry::Size<Number>| {
|
|
|
|
let mut size = stretch::geometry::Size {
|
|
|
|
width: calculated_size.size.width,
|
|
|
|
height: calculated_size.size.height,
|
|
|
|
};
|
|
|
|
match (constraints.width, constraints.height) {
|
|
|
|
(Number::Undefined, Number::Undefined) => {}
|
|
|
|
(Number::Defined(width), Number::Undefined) => {
|
|
|
|
size.height = width * size.height / size.width;
|
|
|
|
size.width = width;
|
|
|
|
}
|
|
|
|
(Number::Undefined, Number::Defined(height)) => {
|
|
|
|
size.width = height * size.width / size.height;
|
|
|
|
size.height = height;
|
|
|
|
}
|
|
|
|
(Number::Defined(width), Number::Defined(height)) => {
|
|
|
|
size.width = width;
|
|
|
|
size.height = height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(size)
|
2020-07-28 04:04:04 +00:00
|
|
|
});
|
|
|
|
|
2020-07-28 07:37:25 +00:00
|
|
|
if let Some(stretch_node) = self.entity_to_stretch.get(&entity) {
|
2020-07-28 04:04:04 +00:00
|
|
|
self.stretch
|
|
|
|
.set_style(*stretch_node, stretch_style)
|
|
|
|
.unwrap();
|
|
|
|
self.stretch
|
2020-07-28 07:37:25 +00:00
|
|
|
.set_measure(*stretch_node, Some(measure))
|
2020-07-28 04:04:04 +00:00
|
|
|
.unwrap();
|
2020-07-28 07:37:25 +00:00
|
|
|
} else {
|
|
|
|
let stretch_node = stretch.new_leaf(stretch_style, measure).unwrap();
|
|
|
|
self.entity_to_stretch.insert(entity, stretch_node);
|
2020-07-28 04:04:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-25 06:04:45 +00:00
|
|
|
pub fn update_children(&mut self, entity: Entity, children: &Children) {
|
|
|
|
let mut stretch_children = Vec::with_capacity(children.len());
|
|
|
|
for child in children.iter() {
|
|
|
|
let stretch_node = self.entity_to_stretch.get(child).unwrap();
|
|
|
|
stretch_children.push(*stretch_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
let stretch_node = self.entity_to_stretch.get(&entity).unwrap();
|
|
|
|
self.stretch
|
|
|
|
.set_children(*stretch_node, stretch_children)
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
2020-07-25 20:14:36 +00:00
|
|
|
pub fn update_window(&mut self, window: &Window) {
|
|
|
|
let stretch = &mut self.stretch;
|
2020-10-15 18:42:19 +00:00
|
|
|
let node = self.window_nodes.entry(window.id()).or_insert_with(|| {
|
2020-07-25 20:14:36 +00:00
|
|
|
stretch
|
2020-07-28 04:04:04 +00:00
|
|
|
.new_node(stretch::style::Style::default(), Vec::new())
|
2020-07-25 20:14:36 +00:00
|
|
|
.unwrap()
|
|
|
|
});
|
|
|
|
|
|
|
|
stretch
|
|
|
|
.set_style(
|
|
|
|
*node,
|
2020-07-26 19:27:09 +00:00
|
|
|
stretch::style::Style {
|
|
|
|
size: stretch::geometry::Size {
|
2020-10-15 18:42:19 +00:00
|
|
|
width: stretch::style::Dimension::Points(window.width() as f32),
|
|
|
|
height: stretch::style::Dimension::Points(window.height() as f32),
|
2020-07-25 20:14:36 +00:00
|
|
|
},
|
|
|
|
..Default::default()
|
2020-07-25 06:04:45 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
2020-07-25 20:14:36 +00:00
|
|
|
pub fn set_window_children(
|
|
|
|
&mut self,
|
|
|
|
window_id: WindowId,
|
|
|
|
children: impl Iterator<Item = Entity>,
|
|
|
|
) {
|
|
|
|
let stretch_node = self.window_nodes.get(&window_id).unwrap();
|
|
|
|
let child_nodes = children
|
|
|
|
.map(|e| *self.entity_to_stretch.get(&e).unwrap())
|
|
|
|
.collect::<Vec<stretch::node::Node>>();
|
|
|
|
self.stretch
|
|
|
|
.set_children(*stretch_node, child_nodes)
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn compute_window_layouts(&mut self) {
|
|
|
|
for window_node in self.window_nodes.values() {
|
|
|
|
self.stretch
|
|
|
|
.compute_layout(*window_node, stretch::geometry::Size::undefined())
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-26 19:27:09 +00:00
|
|
|
pub fn get_layout(&self, entity: Entity) -> Result<&stretch::result::Layout, stretch::Error> {
|
2020-07-25 06:04:45 +00:00
|
|
|
let stretch_node = self.entity_to_stretch.get(&entity).unwrap();
|
|
|
|
self.stretch.layout(*stretch_node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SAFE: as long as MeasureFunc is Send + Sync. https://github.com/vislyhq/stretch/issues/69
|
2020-07-25 20:14:36 +00:00
|
|
|
unsafe impl Send for FlexSurface {}
|
|
|
|
unsafe impl Sync for FlexSurface {}
|
2020-07-25 06:04:45 +00:00
|
|
|
|
|
|
|
pub fn flex_node_system(
|
2020-07-25 20:14:36 +00:00
|
|
|
windows: Res<Windows>,
|
|
|
|
mut flex_surface: ResMut<FlexSurface>,
|
2020-11-11 04:48:34 +00:00
|
|
|
root_node_query: Query<Entity, (With<Node>, Without<Parent>)>,
|
|
|
|
node_query: Query<(Entity, &Style, Option<&CalculatedSize>), (With<Node>, Changed<Style>)>,
|
|
|
|
changed_size_query: Query<
|
|
|
|
(Entity, &Style, &CalculatedSize),
|
|
|
|
(With<Node>, Changed<CalculatedSize>),
|
|
|
|
>,
|
|
|
|
children_query: Query<(Entity, &Children), (With<Node>, Changed<Children>)>,
|
2020-09-14 21:00:32 +00:00
|
|
|
mut node_transform_query: Query<(Entity, &mut Node, &mut Transform, Option<&Parent>)>,
|
2020-07-25 06:04:45 +00:00
|
|
|
) {
|
2020-07-25 20:14:36 +00:00
|
|
|
// update window root nodes
|
|
|
|
for window in windows.iter() {
|
|
|
|
flex_surface.update_window(window);
|
2020-07-25 06:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// update changed nodes
|
2020-10-30 06:39:55 +00:00
|
|
|
for (entity, style, calculated_size) in node_query.iter() {
|
2020-07-25 06:04:45 +00:00
|
|
|
// TODO: remove node from old hierarchy if its root has changed
|
2020-07-28 04:04:04 +00:00
|
|
|
if let Some(calculated_size) = calculated_size {
|
|
|
|
flex_surface.upsert_leaf(entity, &style, *calculated_size);
|
|
|
|
} else {
|
|
|
|
flex_surface.upsert_node(entity, &style);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
for (entity, style, calculated_size) in changed_size_query.iter() {
|
2020-07-28 04:04:04 +00:00
|
|
|
flex_surface.upsert_leaf(entity, &style, *calculated_size);
|
2020-07-25 06:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: handle removed nodes
|
|
|
|
|
2020-07-25 20:14:36 +00:00
|
|
|
// update window children (for now assuming all Nodes live in the primary window)
|
|
|
|
if let Some(primary_window) = windows.get_primary() {
|
2020-10-30 06:39:55 +00:00
|
|
|
flex_surface.set_window_children(primary_window.id(), root_node_query.iter());
|
2020-07-25 20:14:36 +00:00
|
|
|
}
|
|
|
|
|
2020-07-25 06:04:45 +00:00
|
|
|
// update children
|
2020-10-30 06:39:55 +00:00
|
|
|
for (entity, children) in children_query.iter() {
|
2020-07-25 20:14:36 +00:00
|
|
|
flex_surface.update_children(entity, &children);
|
2020-07-25 06:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// compute layouts
|
2020-07-25 20:14:36 +00:00
|
|
|
flex_surface.compute_window_layouts();
|
2020-07-25 06:04:45 +00:00
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
for (entity, mut node, mut transform, parent) in node_transform_query.iter_mut() {
|
2020-07-25 20:14:36 +00:00
|
|
|
let layout = flex_surface.get_layout(entity).unwrap();
|
2020-07-25 06:04:45 +00:00
|
|
|
node.size = Vec2::new(layout.size.width, layout.size.height);
|
2020-10-18 20:03:16 +00:00
|
|
|
let position = &mut transform.translation;
|
2020-07-25 06:04:45 +00:00
|
|
|
position.set_x(layout.location.x + layout.size.width / 2.0);
|
|
|
|
position.set_y(layout.location.y + layout.size.height / 2.0);
|
|
|
|
if let Some(parent) = parent {
|
2020-07-25 20:14:36 +00:00
|
|
|
if let Ok(parent_layout) = flex_surface.get_layout(parent.0) {
|
2020-07-25 06:04:45 +00:00
|
|
|
*position.x_mut() -= parent_layout.size.width / 2.0;
|
|
|
|
*position.y_mut() -= parent_layout.size.height / 2.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|