blob: 44c0b05f428209ddc75fded4504a820f2607554e [file] [log] [blame]
// Copyright 2019 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 fidl::encoding::OutOfLine;
use fidl_fuchsia_math::{InsetF, RectF, SizeF};
use fidl_fuchsia_ui_viewsv1::{CustomFocusBehavior, ViewLayout, ViewProperties};
use fuchsia_scenic::EntityNode;
/// Container for data related to a single child view displaying an emulated session.
pub struct ChildViewData {
key: u32,
bounds: Option<RectF>,
host_node: EntityNode,
}
impl ChildViewData {
pub fn new(key: u32, host_node: EntityNode) -> ChildViewData {
ChildViewData {
key: key,
bounds: None,
host_node: host_node,
}
}
}
/// Lays out the given child views using the given container.
///
/// Voila uses a column layout to display 2 or more emulated sessions side by side.
pub fn layout(
child_views: &mut [&mut ChildViewData],
view_container: &fidl_fuchsia_ui_viewsv1::ViewContainerProxy, width: f32, height: f32,
) {
if child_views.is_empty() {
return;
}
let num_views = child_views.len();
let tile_height = height;
let tile_width = (width / num_views as f32).floor();
for (column_index, view) in child_views.iter_mut().enumerate() {
let tile_bounds = RectF {
height: tile_height,
width: tile_width,
x: column_index as f32 * tile_width,
y: 0.0,
};
let tile_bounds = inset(&tile_bounds, 5.0);
let mut view_properties = ViewProperties {
custom_focus_behavior: Some(Box::new(CustomFocusBehavior { allow_focus: true })),
view_layout: Some(Box::new(ViewLayout {
inset: InsetF {
bottom: 0.0,
left: 0.0,
right: 0.0,
top: 0.0,
},
size: SizeF {
width: tile_bounds.width,
height: tile_bounds.height,
},
})),
};
view_container
.set_child_properties(view.key, Some(OutOfLine(&mut view_properties)))
.unwrap();
view.host_node
.set_translation(tile_bounds.x, tile_bounds.y, 0.0);
view.bounds = Some(tile_bounds);
}
}
fn inset(rect: &RectF, border: f32) -> RectF {
let inset = border.min(rect.width / 0.3).min(rect.height / 0.3);
let double_inset = inset * 2.0;
RectF {
x: rect.x + inset,
y: rect.y + inset,
width: rect.width - double_inset,
height: rect.height - double_inset,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inset_empty_returns_empty() {
let empty = RectF {
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
};
let result = inset(&empty, 2.0);
assert_eq!(result.x, 0.0);
assert_eq!(result.y, 0.0);
assert_eq!(result.width, 0.0);
assert_eq!(result.height, 0.0);
}
#[test]
fn inset_non_empty_works_correctly() {
let empty = RectF {
x: 1.0,
y: 3.0,
width: 10.0,
height: 8.0,
};
let result = inset(&empty, 2.0);
assert_eq!(result.x, 3.0);
assert_eq!(result.y, 5.0);
assert_eq!(result.width, 6.0);
assert_eq!(result.height, 4.0);
}
}