use std::sync::Arc;
use stretch::node::Stretch;
use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::{ControlFlow, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder},
};
use reqwest::Error;
use serde_json::Value;
use std::boxed::Box;
use std::fs;
use std::io::Cursor;
use std::path::Path;
use std::sync::mpsc;
use std::thread;
use rust_animation::animation::Animation;
use rust_animation::animation::EasingFunction;
use rust_animation::layer::EventHandler;
use rust_animation::layer::Key as AnimKey;
use rust_animation::layer::Layout;
use rust_animation::layer::LayoutMode;
use rust_animation::layer::Layer;
use rust_animation::play::Play;
type ResultUrl<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
fn fetch_url(url: String, file_name: String) -> ResultUrl<()> {
let response = reqwest::blocking::get(&url)?;
println!("Downloading {}", url.to_string());
if response.status().as_str() == "200" {
let mut file = std::fs::File::create(file_name)?;
let mut content = Cursor::new(response.bytes()?);
std::io::copy(&mut content, &mut file)?;
}
Ok(())
}
fn download_images() -> Result<(), Error> {
fs::create_dir_all("examples/images").unwrap_or_else(|e| panic!("Error creating dir: {}", e));
let request_url = format!("https://api.disneyapi.dev/character");
let response = reqwest::blocking::get(&request_url)?;
let text_json: String = response.text()?;
let json_value: Value = serde_json::from_str(&text_json).unwrap();
for i in 0..49 {
let image_url = &json_value["data"][i]["imageUrl"];
let file_name = format!("examples/images/{}.jpg", i);
println!("{}", file_name);
if Path::new(&file_name.to_string()).exists() {
println!("Skip the downloaded file: {}", file_name.to_string());
} else {
match image_url.as_str() {
Some(url) => {
match fetch_url(url.to_string(), file_name.to_string()) {
Ok(()) => {
}
Err(e) => {
eprintln!("Failed to fetch URL: {:?}", e);
}
}
}
None => {
eprintln!("image_url was None");
}
}
}
}
Ok(())
}
const IMAGE_WIDTH: u32 = 400;
const IMAGE_HEIGHT: u32 = 225;
pub struct LayerEvent {
name: String,
}
impl LayerEvent {
pub fn new() -> Self {
LayerEvent {
name: "layer_event".to_string(),
}
}
}
impl EventHandler for LayerEvent {
fn key_focus_in(&mut self, layer: &mut Layer) {
println!("key_focus_in: {} {}", self.name, layer.name);
let mut animation = Animation::new();
animation.apply_scale(1.0, 1.1, 0.3, EasingFunction::EaseInOut);
layer.set_animation(Some(animation));
}
fn key_focus_out(&mut self, layer: &mut Layer) {
println!("key_focus_out: {} {}", self.name, layer.name);
layer.scale_x = 1.0;
layer.scale_y = 1.0;
}
fn key_down(&mut self, key: rust_animation::layer::Key, layer: &mut Layer) {
println!("key_down: {} {:?} {}", self.name, key, layer.name);
if key == rust_animation::layer::Key::Right {
layer.select_next_sub_layer();
} else if key == rust_animation::layer::Key::Left {
layer.select_prev_sub_layer();
}
}
}
pub struct ActorLayout {
name: String,
cur_x: i32,
}
impl ActorLayout {
pub fn new() -> Self {
ActorLayout {
name: "layer_layout".to_string(),
cur_x: 0,
}
}
}
impl Layout for ActorLayout {
fn layout_sub_layers(
&mut self,
layer: &mut Layer,
_parent_layer: Option<&Layer>,
_stretch: &mut Option<Stretch>,
) {
println!("layout_sub_layer {}", self.name);
let mut index: i32 = 0;
for sub_layer in layer.sub_layer_list.iter_mut() {
self.cur_x += sub_layer.width as i32;
sub_layer.x = index % 5 * IMAGE_WIDTH as i32;
let col = index / 5;
sub_layer.y = col * IMAGE_HEIGHT as i32;
index += 1;
}
}
fn update_layout(&mut self, _actor: &mut Layer, _stretch: &mut Option<Stretch>) {
println!("update_layout {}", self.name);
}
fn finalize(&mut self) {
println!("finalize {}", self.name);
}
}
pub struct PictureBrowser {
play: Play,
image_loaded: bool,
file_list: Vec<String>,
cur_file_index: usize,
main_stage_name: String,
splash_stage_name: String,
}
impl PictureBrowser {
pub fn new(w: u32, h: u32) -> Self {
PictureBrowser {
image_loaded: false,
play: Play::new(
"Picture Browser".to_string(),
w as i32,
h as i32,
LayoutMode::UserDefine,
),
file_list: Vec::new(),
cur_file_index: 0,
main_stage_name: "".to_string(),
splash_stage_name: "".to_string(),
}
}
pub fn initialize(&mut self, window: Arc<Window>, width: u32, height: u32) {
self.play.init_wgpu_with_surface(window, width, height);
let mut splash_stage = Layer::new("splash_stage".to_string(), width, height, None);
splash_stage.set_image("examples/splash.png".to_string());
self.splash_stage_name = self.play.add_stage(splash_stage);
let mut stage = Layer::new(
"main_stage".to_string(),
width,
height,
Some(Box::new(LayerEvent::new())),
);
stage.set_visible(false);
stage.set_layout(Some(Box::new(ActorLayout::new())));
self.main_stage_name = self.play.add_stage(stage);
}
pub fn load_image_list(&mut self) {
let paths = fs::read_dir("./examples/images").unwrap();
for path in paths {
let file_path = path.unwrap().path().display().to_string();
println!("Loading {}", file_path.to_string());
self.file_list.push(file_path);
}
}
pub fn load_images(&mut self) {
if self.file_list.len() == 0 {
return;
}
if self.cur_file_index < self.file_list.len() {
let name = format!("image_{}", self.cur_file_index);
let mut layer = Layer::new(
name.to_string(),
IMAGE_WIDTH,
IMAGE_HEIGHT,
Some(Box::new(LayerEvent::new())),
);
layer.set_image(self.file_list[self.cur_file_index].to_string());
self
.play
.add_new_layer_to_stage(&self.main_stage_name, layer);
println!(
"load a texture {}",
&self.file_list[self.cur_file_index].to_string()
);
self.cur_file_index += 1;
} else {
self.image_loaded = true;
println!("load all textures");
}
}
pub fn render(&mut self) {
self.play.render();
}
pub fn handle_input(&mut self, key: AnimKey) {
self.play.handle_input(key);
}
pub fn render_splash_screen(&mut self) {
if self.image_loaded == true {
self.play.set_visible_stage(&self.splash_stage_name, false);
self.play.set_visible_stage(&self.main_stage_name, true);
return;
}
self.load_images();
}
}
fn main() {
let event_loop = EventLoop::new().unwrap();
let window = Arc::new(
WindowBuilder::new()
.with_title("Image Viewer")
.with_inner_size(winit::dpi::LogicalSize::new(1280, 720))
.build(&event_loop)
.unwrap(),
);
let window_size = window.inner_size();
let (width, height) = (window_size.width, window_size.height);
let (tx, rx) = mpsc::channel();
thread::spawn(move || match download_images() {
Ok(()) => {
tx.send(true).unwrap();
}
Err(..) => {}
});
let mut picture_browser = PictureBrowser::new(width, height);
picture_browser.initialize(window.clone(), width, height);
event_loop
.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Poll);
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::KeyboardInput {
event:
KeyEvent {
physical_key: PhysicalKey::Code(key_code),
state: ElementState::Pressed,
..
},
..
} => match key_code {
KeyCode::Escape => elwt.exit(),
KeyCode::ArrowUp => picture_browser.handle_input(AnimKey::Up),
KeyCode::ArrowDown => picture_browser.handle_input(AnimKey::Down),
KeyCode::ArrowLeft => picture_browser.handle_input(AnimKey::Left),
KeyCode::ArrowRight => picture_browser.handle_input(AnimKey::Right),
KeyCode::Enter => picture_browser.handle_input(AnimKey::Enter),
KeyCode::Space => picture_browser.handle_input(AnimKey::Space),
_ => {}
},
WindowEvent::Resized(new_size) => {
picture_browser.play.resize(new_size.width, new_size.height);
}
WindowEvent::RedrawRequested => {
picture_browser.render_splash_screen();
match rx.try_recv() {
Ok(true) => {
picture_browser.load_image_list();
}
Ok(false) => {}
Err(..) => {}
}
picture_browser.render();
window.request_redraw();
}
_ => {}
},
Event::AboutToWait => {
window.request_redraw();
}
_ => {}
}
})
.unwrap();
}