mod assets;
pub mod error;
mod macros;
pub mod message;
pub mod resources;
mod state;
pub mod style;
pub mod widgets;
pub use agape_core::*;
pub use agape_layout as layout;
pub use agape_macros::hex;
pub use agape_renderer as renderer;
pub use error::{Error, Result};
pub use message::{Message, MessageQueue};
use std::path::Path;
use crate::message::{MouseButtonDown, MouseButtonUp};
use crate::state::{Scroll, State};
use crate::widgets::Widget;
pub use agape_macros::Widget;
use pixels::{Pixels, SurfaceTexture};
use std::sync::Arc;
use tracing::info;
use winit::event::{ElementState, MouseButton, MouseScrollDelta};
use winit::event_loop::ActiveEventLoop;
use winit::{
application::ApplicationHandler,
event::WindowEvent,
event_loop::{ControlFlow, EventLoop},
window::Window,
window::WindowId,
};
pub struct App<'app> {
window: Option<Arc<Window>>,
pixels: Option<Pixels<'app>>,
state: State,
}
impl App<'_> {
pub fn new(widget: impl Widget + 'static) -> Self {
Self {
state: State::new(widget),
pixels: None,
window: None,
}
}
pub fn assets(mut self, path: impl AsRef<Path>) -> Self {
self.state.asset_dir(path);
self
}
fn render(&mut self) {
self.state.render();
let renderer = self.state.renderer();
let pixels = self.pixels.as_mut().unwrap();
pixels.frame_mut().copy_from_slice(renderer.pixmap().data());
pixels.render().unwrap();
}
pub fn run(mut self) -> Result<()> {
let event_loop = EventLoop::new()?;
event_loop.set_control_flow(ControlFlow::Poll);
event_loop.run_app(&mut self)?;
Ok(())
}
}
impl ApplicationHandler for App<'_> {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
info!("Initializing resources");
let window = event_loop.create_window(Default::default()).unwrap();
let window = Arc::new(window);
let size = Size::from(window.inner_size());
let width = size.width as u32;
let height = size.height as u32;
let surface = SurfaceTexture::new(width, height, Arc::clone(&window));
let pixels = Pixels::new(width, height, surface).unwrap();
self.pixels = Some(pixels);
self.window = Some(Arc::clone(&window));
}
fn window_event(&mut self, event_loop: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
match event {
WindowEvent::CloseRequested => {
info!("Exiting app");
event_loop.exit();
}
WindowEvent::CursorMoved { position, .. } => {
self.state.update_cursor_position(position.into());
}
WindowEvent::MouseInput { state, button, .. } => {
let messages = self.state.messages_mut();
if let MouseButton::Left = button
&& let ElementState::Pressed = state
{
messages.add(MouseButtonDown);
}
if let MouseButton::Left = button
&& let ElementState::Released = state
{
messages.add(MouseButtonUp);
}
}
WindowEvent::RedrawRequested => {
self.render();
self.window.as_mut().unwrap().request_redraw();
}
WindowEvent::Resized(size) => {
self.pixels
.as_mut()
.unwrap()
.resize_surface(size.width, size.height)
.expect("Failed to resize the pixel buffer");
self.pixels
.as_mut()
.unwrap()
.resize_buffer(size.width, size.height)
.expect("Failed to resize the pixel buffer");
self.state.resize(size.into());
}
WindowEvent::KeyboardInput { event, .. } => {
self.state.key_event(&event);
}
WindowEvent::MouseWheel {
delta: MouseScrollDelta::LineDelta(_, y),
..
} => {
self.state.messages_mut().add(Scroll(y));
}
_ => {}
}
self.state.update();
}
}