219 lines
5.9 KiB
Rust
Executable file
219 lines
5.9 KiB
Rust
Executable file
/*
|
|
* Copyright (C) 2022 Umut İnan Erdoğan <umutinanerdogan@pm.me>
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
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(&mut 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(1.0, 1.0, 1.0)),
|
|
self.decorations,
|
|
self.maximized,
|
|
self.resizable,
|
|
self.title.unwrap_or("AbleTK Window".into()),
|
|
self.transparent,
|
|
self.visible,
|
|
)
|
|
}
|
|
}
|