1mod assets;
20pub mod error;
21mod macros;
22pub mod message;
23pub mod resources;
24mod state;
25pub mod style;
26pub mod widgets;
27
28pub use agape_core::*;
29pub use agape_layout as layout;
30pub use agape_macros::hex;
31pub use agape_renderer as renderer;
32pub use error::{Error, Result};
33pub use message::{Message, MessageQueue};
34use std::path::Path;
35
36use crate::message::{MouseButtonDown, MouseButtonUp};
37use crate::state::{Scroll, State};
38use crate::widgets::Widget;
39pub use agape_macros::Widget;
40use pixels::{Pixels, SurfaceTexture};
41use std::sync::Arc;
42use tracing::info;
43use winit::event::{ElementState, MouseButton, MouseScrollDelta};
44use winit::event_loop::ActiveEventLoop;
45use winit::{
46 application::ApplicationHandler,
47 event::WindowEvent,
48 event_loop::{ControlFlow, EventLoop},
49 window::Window,
50 window::WindowId,
51};
52
53pub struct App<'app> {
55 window: Option<Arc<Window>>,
58 pixels: Option<Pixels<'app>>,
59 state: State,
60}
61
62impl App<'_> {
63 pub fn new(widget: impl Widget + 'static) -> Self {
65 Self {
66 state: State::new(widget),
67 pixels: None,
68 window: None,
69 }
70 }
71
72 pub fn assets(mut self, path: impl AsRef<Path>) -> Self {
73 self.state.asset_dir(path);
74 self
75 }
76
77 fn render(&mut self) {
78 self.state.render();
79 let renderer = self.state.renderer();
80 let pixels = self.pixels.as_mut().unwrap();
81
82 pixels.frame_mut().copy_from_slice(renderer.pixmap().data());
83 pixels.render().unwrap();
84 }
85
86 pub fn run(mut self) -> Result<()> {
93 let event_loop = EventLoop::new()?;
94 event_loop.set_control_flow(ControlFlow::Poll);
95 event_loop.run_app(&mut self)?;
96 Ok(())
97 }
98}
99
100impl ApplicationHandler for App<'_> {
101 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
102 info!("Initializing resources");
103 let window = event_loop.create_window(Default::default()).unwrap();
104 let window = Arc::new(window);
105
106 let size = Size::from(window.inner_size());
107 let width = size.width as u32;
108 let height = size.height as u32;
109
110 let surface = SurfaceTexture::new(width, height, Arc::clone(&window));
111 let pixels = Pixels::new(width, height, surface).unwrap();
112
113 self.pixels = Some(pixels);
114 self.window = Some(Arc::clone(&window));
115 }
116
117 fn window_event(&mut self, event_loop: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
118 match event {
119 WindowEvent::CloseRequested => {
120 info!("Exiting app");
121 event_loop.exit();
122 }
123 WindowEvent::CursorMoved { position, .. } => {
124 self.state.update_cursor_position(position.into());
125 }
126 WindowEvent::MouseInput { state, button, .. } => {
127 let messages = self.state.messages_mut();
128 if let MouseButton::Left = button
129 && let ElementState::Pressed = state
130 {
131 messages.add(MouseButtonDown);
132 }
133
134 if let MouseButton::Left = button
135 && let ElementState::Released = state
136 {
137 messages.add(MouseButtonUp);
138 }
139 }
140 WindowEvent::RedrawRequested => {
141 self.render();
142 self.window.as_mut().unwrap().request_redraw();
143 }
144 WindowEvent::Resized(size) => {
145 self.pixels
146 .as_mut()
147 .unwrap()
148 .resize_surface(size.width, size.height)
149 .expect("Failed to resize the pixel buffer");
150
151 self.pixels
152 .as_mut()
153 .unwrap()
154 .resize_buffer(size.width, size.height)
155 .expect("Failed to resize the pixel buffer");
156
157 self.state.resize(size.into());
158 }
159 WindowEvent::KeyboardInput { event, .. } => {
160 self.state.key_event(&event);
161 }
162 WindowEvent::MouseWheel {
163 delta: MouseScrollDelta::LineDelta(_, y),
164 ..
165 } => {
166 self.state.messages_mut().add(Scroll(y));
167 }
168 _ => {}
169 }
170 self.state.update();
171 }
172}