blob: a1d64e52f9deb7d174b0670ecf5604a3d16dec12 [file] [log] [blame]
// Copyright 2018 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::{Context as _, Error};
use carnelian::{
make_app_assistant, make_message, set_node_color, AnimationMode, App, AppAssistant, Color,
ViewAssistant, ViewAssistantContext, ViewAssistantPtr, ViewKey, ViewMessages,
};
use fidl::endpoints::{RequestStream, ServiceMarker};
use fidl_fidl_examples_echo::{EchoMarker, EchoRequest, EchoRequestStream};
use fidl_fuchsia_ui_input::{KeyboardEvent, KeyboardEventPhase};
use fuchsia_async as fasync;
use fuchsia_scenic::{Rectangle, RoundedRectangle, SessionPtr, ShapeNode};
use fuchsia_zircon::{ClockId, Time};
use futures::prelude::*;
use std::f32::consts::PI;
const BACKGROUND_Z: f32 = 0.0;
const SQUARE_Z: f32 = BACKGROUND_Z - 8.0;
#[derive(Default)]
struct SpinningSquareAppAssistant;
impl AppAssistant for SpinningSquareAppAssistant {
fn setup(&mut self) -> Result<(), Error> {
Ok(())
}
fn create_view_assistant(
&mut self,
_: ViewKey,
session: &SessionPtr,
) -> Result<ViewAssistantPtr, Error> {
Ok(Box::new(SpinningSquareViewAssistant {
background_node: ShapeNode::new(session.clone()),
spinning_square_node: ShapeNode::new(session.clone()),
rounded: false,
start: Time::get(ClockId::Monotonic),
}))
}
/// Return the list of names of services this app wants to provide
fn outgoing_services_names(&self) -> Vec<&'static str> {
[EchoMarker::NAME].to_vec()
}
/// Handle a request to connect to a service provided by this app
fn handle_service_connection_request(
&mut self,
_service_name: &str,
channel: fasync::Channel,
) -> Result<(), Error> {
Self::create_echo_server(channel, false);
Ok(())
}
}
impl SpinningSquareAppAssistant {
fn create_echo_server(channel: fasync::Channel, quiet: bool) {
fasync::spawn_local(
async move {
let mut stream = EchoRequestStream::from_channel(channel);
while let Some(EchoRequest::EchoString { value, responder }) =
stream.try_next().await.context("error running echo server")?
{
if !quiet {
println!("Spinning Square received echo request for string {:?}", value);
}
responder
.send(value.as_ref().map(|s| &**s))
.context("error sending response")?;
if !quiet {
println!("echo response sent successfully");
}
}
Ok(())
}
.unwrap_or_else(|e: anyhow::Error| eprintln!("{:?}", e)),
);
}
}
struct SpinningSquareViewAssistant {
background_node: ShapeNode,
spinning_square_node: ShapeNode,
rounded: bool,
start: Time,
}
impl ViewAssistant for SpinningSquareViewAssistant {
fn setup(&mut self, context: &ViewAssistantContext<'_>) -> Result<(), Error> {
set_node_color(
context.session(),
&self.background_node,
&Color { r: 0xb7, g: 0x41, b: 0x0e, a: 0xff },
);
set_node_color(
context.session(),
&self.spinning_square_node,
&Color { r: 0xff, g: 0x00, b: 0xff, a: 0xff },
);
context.root_node().add_child(&self.background_node);
context.root_node().add_child(&self.spinning_square_node);
Ok(())
}
fn update(&mut self, context: &ViewAssistantContext<'_>) -> Result<(), Error> {
const SPEED: f32 = 0.25;
const SECONDS_PER_NANOSECOND: f32 = 1e-9;
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, BACKGROUND_Z);
let square_size = context.size.width.min(context.size.height) * 0.6;
let t = ((context.presentation_time.into_nanos() - self.start.into_nanos()) as f32
* SECONDS_PER_NANOSECOND
* SPEED)
% 1.0;
let angle = t * PI * 2.0;
if self.rounded {
let corner_radius = (square_size / 4.0).ceil();
self.spinning_square_node.set_shape(&RoundedRectangle::new(
context.session().clone(),
square_size,
square_size,
corner_radius,
corner_radius,
corner_radius,
corner_radius,
));
} else {
self.spinning_square_node.set_shape(&Rectangle::new(
context.session().clone(),
square_size,
square_size,
));
}
self.spinning_square_node.set_translation(center_x, center_y, SQUARE_Z);
self.spinning_square_node.set_rotation(0.0, 0.0, (angle * 0.5).sin(), (angle * 0.5).cos());
Ok(())
}
fn initial_animation_mode(&mut self) -> AnimationMode {
return AnimationMode::EveryFrame;
}
fn handle_keyboard_event(
&mut self,
context: &mut ViewAssistantContext<'_>,
keyboard_event: &KeyboardEvent,
) -> Result<(), Error> {
if keyboard_event.code_point == ' ' as u32
&& keyboard_event.phase == KeyboardEventPhase::Pressed
{
self.rounded = !self.rounded;
}
context.queue_message(make_message(ViewMessages::Update));
Ok(())
}
}
fn main() -> Result<(), Error> {
App::run(make_app_assistant::<SpinningSquareAppAssistant>())
}