abletk/src/window.rs

211 lines
5.6 KiB
Rust
Executable File

use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use raw_window_handle::HasRawWindowHandle;
use winit::{
event_loop::EventLoopWindowTarget,
window::{Window as WinitWindow, WindowBuilder as WinitWindowBuilder},
};
use winit::dpi::PhysicalSize;
use winit::error::OsError;
use winit::window::WindowId;
use abletk_common::color::Color;
use abletk_common::Renderer;
use crate::context::Context;
use crate::event::window::Event;
use crate::widget::Widget;
pub struct Window {
window: WinitWindow,
events: HashMap<Event, Vec<fn(&mut Context, &mut Window)>>,
root: Box<dyn Widget>,
ctx: Rc<RefCell<Context>>,
renderer: Renderer,
background: Color,
}
impl Window {
pub fn new<S: Into<String>>(
ctx: Rc<RefCell<Context>>,
root: Box<dyn Widget>,
event_loop: &EventLoopWindowTarget<()>,
events: HashMap<Event, Vec<fn(&mut Context, &mut Window)>>,
always_on_top: bool,
background: Color,
decorations: bool,
maximized: bool,
resizable: bool,
title: S,
transparent: bool,
visible: bool,
) -> Result<Self, OsError> {
let window = WinitWindowBuilder::new()
.with_always_on_top(always_on_top)
.with_decorations(decorations)
.with_maximized(maximized)
.with_resizable(resizable)
.with_title(title)
.with_transparent(transparent)
.with_visible(visible)
.build(event_loop)?;
Ok(Self {
renderer: Renderer::new(window.raw_window_handle()),
window,
background,
events,
root,
ctx,
})
}
pub fn builder<W: Widget + 'static>(root: W) -> WindowBuilder {
WindowBuilder::new(root)
}
pub fn render(&mut self) {
eprintln!("Rendering window with id {:?}", self.id());
self.renderer.begin_draw();
self.renderer.clear(self.background);
self.root.draw(&self.renderer);
self.renderer.end_draw()
}
pub fn set_always_on_top(&self, value: bool) {
self.window.set_always_on_top(value)
}
pub fn focus(&self) {
self.window.focus_window()
}
pub fn redraw(&self) {
self.window.request_redraw()
}
pub fn set_title<S: AsRef<str> + Into<String>>(&mut self, title: S) {
self.window.set_title(title.as_ref())
}
pub(crate) fn emit_event(&mut self, event: Event) {
if let Some(handlers) = self.events.get(&event) {
let ctx = self.ctx.clone();
let ctx = &mut ctx.borrow_mut();
handlers.clone().iter().for_each(|handler| handler(ctx, self))
}
}
pub(crate) fn id(&self) -> WindowId {
self.window.id()
}
pub(crate) fn resized(&mut self, size: PhysicalSize<u32>) {
self.renderer.resized(size.width, size.height)
}
}
pub struct WindowBuilder {
events: HashMap<Event, Vec<fn(&mut Context, &mut Window)>>,
always_on_top: bool,
background: Option<Color>,
decorations: bool,
maximized: bool,
resizable: bool,
title: Option<String>,
transparent: bool,
visible: bool,
root: Box<dyn Widget>,
}
impl WindowBuilder {
pub fn new<W: Widget + 'static>(root: W) -> Self {
Self {
events: Default::default(),
always_on_top: false,
background: None,
decorations: true,
maximized: false,
resizable: true,
title: None,
transparent: false,
visible: true,
root: Box::new(root),
}
}
pub fn on_event(mut self,
event: Event,
handler: fn(&mut Context, &mut Window),
) -> Self {
if let Some(handlers) = self.events.get_mut(&event) {
handlers.push(handler);
} else {
self.events.insert(event, vec![handler]);
}
self
}
pub fn always_on_top(mut self, value: bool) -> Self {
self.always_on_top = value;
self
}
pub fn background(mut self, value: Color) -> Self {
self.background = Some(value);
self
}
pub fn decorations(mut self, value: bool) -> Self {
self.decorations = value;
self
}
pub fn maximized(mut self, value: bool) -> Self {
self.maximized = value;
self
}
pub fn resizable(mut self, value: bool) -> Self {
self.resizable = value;
self
}
pub fn title<S: Into<String>>(mut self, value: S) -> Self {
self.title = Some(value.into());
self
}
pub fn transparent(mut self, value: bool) -> Self {
self.transparent = value;
self
}
pub fn visible(mut self, value: bool) -> Self {
self.visible = value;
self
}
pub fn build(self,
ctx: Rc<RefCell<Context>>,
event_loop: &EventLoopWindowTarget<()>
) -> Result<Window, OsError> {
Window::new(
ctx,
self.root,
event_loop,
self.events,
// todo: make this the application name
self.always_on_top,
self.background.unwrap_or(Color::RGB(255.0, 255.0, 255.0)),
self.decorations,
self.maximized,
self.resizable,
self.title.unwrap_or("AbleTK Window".into()),
self.transparent,
self.visible,
)
}
}