blob: 01aa31b301c65e798959fb3851c78b1ba2fac17e [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 anyhow::Error;
use carnelian::{
make_app_assistant, set_node_color, AnimationMode, App, AppAssistant, Color, Label, Paint,
Point, Rect, ViewAssistant, ViewAssistantContext, ViewAssistantPtr, ViewKey,
};
use euclid::Vector2D;
use fuchsia_scenic::{EntityNode, Rectangle, SessionPtr, ShapeNode};
fn make_bounds(context: &ViewAssistantContext<'_>) -> Rect {
Rect::new(Point::zero(), context.size)
}
#[derive(Default)]
struct TextScrollAppAssistant;
const BACKGROUND_Z: f32 = 0.0;
const TEXT_Z: f32 = BACKGROUND_Z - 5.0;
impl AppAssistant for TextScrollAppAssistant {
fn setup(&mut self) -> Result<(), Error> {
Ok(())
}
fn create_view_assistant(
&mut self,
_: ViewKey,
session: &SessionPtr,
) -> Result<ViewAssistantPtr, Error> {
Ok(Box::new(TextScrollViewAssistant::new(session)?))
}
}
struct TextLineAnimator {
label: Label,
location: Point,
velocity: Vector2D<f32>,
running: bool,
}
impl TextLineAnimator {
pub fn new(location: Point, label: Label) -> TextLineAnimator {
TextLineAnimator { label, location, velocity: Vector2D::new(0.0, -0.5), running: true }
}
pub fn animate(&mut self, bounds: &Rect) {
self.location += self.velocity;
self.label.node().set_translation(bounds.size.width / 2.0, self.location.y, TEXT_Z);
const ARBITRARILY_CHOSE_TOP_Y_LIMIT: f32 = 20.0;
if self.location.y < bounds.origin.y + ARBITRARILY_CHOSE_TOP_Y_LIMIT {
self.running = false;
self.label.node().detach();
}
}
}
struct TextScrollViewAssistant {
background_node: ShapeNode,
container: EntityNode,
animators: Vec<TextLineAnimator>,
bg_color: Color,
fg_color: Color,
}
impl TextScrollViewAssistant {
fn new(session: &SessionPtr) -> Result<TextScrollViewAssistant, Error> {
Ok(TextScrollViewAssistant {
background_node: ShapeNode::new(session.clone()),
container: EntityNode::new(session.clone()),
animators: Vec::new(),
fg_color: Color::from_hash_code("#A9A9A9")?,
bg_color: Color::from_hash_code("#0000FF")?,
})
}
}
const LINE_FONT_SIZE: u32 = 32;
const STATES: &[&str] = &[
"Alabama",
"Alaska",
"Arizona",
"Arkansas",
"California",
"Colorado",
"Connecticut",
"Delaware",
"Florida",
"Georgia",
"Hawaii",
"Idaho",
"Illinois",
"Indiana",
"Iowa",
"Kansas",
"Kentucky",
"Louisiana",
"Maine",
"Maryland",
"Massachusetts",
"Michigan",
"Minnesota",
"Mississippi",
"Missouri",
"Montana",
"Nebraska",
"Nevada",
"New Hampshire",
"New Jersey",
"New Mexico",
"New York",
"North Carolina",
"North Dakota",
"Ohio",
"Oklahoma",
"Oregon",
"Pennsylvania",
"Rhode Island",
"South Carolina",
"South Dakota",
"Tennessee",
"Texas",
"Utah",
"Vermont",
"Virginia",
"Washington",
"West Virginia",
"Wisconsin",
"Wyoming",
];
impl ViewAssistant for TextScrollViewAssistant {
fn setup(&mut self, context: &ViewAssistantContext<'_>) -> Result<(), Error> {
context.root_node().add_child(&self.container);
self.container.add_child(&self.background_node);
set_node_color(context.session(), &self.background_node, &self.bg_color);
const AESTHETICALLY_PLEASING_INITAL_Y: f32 = 10.0;
let mut y = AESTHETICALLY_PLEASING_INITAL_Y;
for line in STATES.iter() {
if line.len() > 0 {
let label = Label::new(context.session(), line)?;
let size = label.dimensions(LINE_FONT_SIZE);
y += size.height;
const AESTHETICALLY_PLEASING_LINE_PADDING: f32 = 4.0;
y += AESTHETICALLY_PLEASING_LINE_PADDING;
let mut text_animator =
TextLineAnimator::new(Point::new(context.size.width / 2.0, y), label);
let paint = Paint { fg: self.fg_color, bg: self.bg_color };
self.container.add_child(text_animator.label.node());
text_animator.label.update(32, &paint).expect("label update failed");
self.animators.push(text_animator);
}
}
Ok(())
}
fn update(&mut self, context: &ViewAssistantContext<'_>) -> Result<(), Error> {
let center_x = context.size.width * 0.5;
let center_y = context.size.height * 0.5;
self.background_node.set_shape(&Rectangle::new(
context.session().clone(),
context.size.width,
context.size.height,
));
self.background_node.set_translation(center_x, center_y, 0.0);
let bounds = make_bounds(context);
for animator in &mut self.animators {
animator.animate(&bounds);
}
Ok(())
}
fn initial_animation_mode(&mut self) -> AnimationMode {
return AnimationMode::EveryFrame;
}
}
fn main() -> Result<(), Error> {
App::run(make_app_assistant::<TextScrollAppAssistant>())
}