use crate::{
Colour,
graphics::GraphicsSettings,
};
use super::{
window_width,
window_height,
window_center,
mouse_cursor,
WindowSettings,
MouseButton,
KeyboardButton,
InnerWindowEvent,
Window,
WindowPage,
WindowBase,
MouseCursorIconSettings,
};
use glium::backend::glutin::DisplayCreationError;
use glium::glutin::{
ContextBuilder,
NotCurrent,
monitor::MonitorHandle,
event_loop::{ControlFlow,EventLoop,EventLoopProxy,EventLoopClosed},
event::{
Event,
WindowEvent as GWindowEvent,
MouseButton as GMouseButton,
ElementState,
},
window::WindowBuilder,
platform::desktop::EventLoopExtDesktop,
};
use std::path::PathBuf;
pub (crate) enum PageState<'a>{
SetNew(Option<&'a mut dyn WindowPage<'a,Window=DynamicWindow<'a>>>),
TakeOld(Option<&'a mut dyn WindowPage<'a,Window=DynamicWindow<'a>>>),
}
pub struct DynamicWindow<'a>{
pub (crate) base:WindowBase<InnerWindowEvent>,
pub (crate) event_loop_proxy:EventLoopProxy<InnerWindowEvent>,
pub (crate) page:PageState<'a>,
}
impl<'a> DynamicWindow<'a>{
pub fn new<F>(setting:F)->Result<DynamicWindow<'a>,DisplayCreationError>
where F:FnOnce(Vec<MonitorHandle>,&mut WindowSettings){
Window::new(setting)
}
pub fn set_page(&mut self,page:&'a mut dyn WindowPage<'a,Window=Self>){
if let PageState::SetNew(page)=&mut self.page{
page.take()
}
else{
None
};
self.page=PageState::SetNew(Some(page));
}
pub fn change_page(&mut self,page:&'a mut dyn WindowPage<'a,Window=Self>)->Option<&'a mut dyn WindowPage<'a,Window=DynamicWindow<'a>>>{
let old=if let PageState::SetNew(page)=&mut self.page{
page.take()
}
else{
None
};
self.page=PageState::SetNew(Some(page));
old
}
pub fn take_old_page(&mut self)->Option<&'a mut dyn WindowPage<'a,Window=DynamicWindow<'a>>>{
if let PageState::TakeOld(page)=&mut self.page{
page.take()
}
else{
None
}
}
pub fn run(mut self){
let el=&mut self.base.event_loop as *mut EventLoop<InnerWindowEvent>;
let event_loop=unsafe{&mut *el};
#[cfg(not(feature="auto_hide"))]
self.event_listener(event_loop);
#[cfg(feature="auto_hide")]
loop{
if self.event_listener(event_loop){
break
}
if self.wait_until_focused(event_loop){
break
}
}
}
pub fn stop_events(&self)->Result<(),EventLoopClosed<InnerWindowEvent>>{
self.event_loop_proxy.send_event(InnerWindowEvent::Exit)
}
}
impl<'a> DynamicWindow<'a>{
fn event_listener(&mut self,event_loop:&mut EventLoop<InnerWindowEvent>)->bool{
let mut close_flag=false;
let mut taken_page=if let PageState::SetNew(page)=&mut self.page{
page.take()
}
else{
None
};
event_loop.run_return(|event,_,control_flow|{
#[cfg(not(feature="lazy"))]{
*control_flow=ControlFlow::Poll;
}
#[cfg(feature="lazy")]{
*control_flow=ControlFlow::Wait;
}
if let PageState::SetNew(page)=&mut self.page{
if let Some(_)=page{
let take_old=taken_page.take();
taken_page=page.take();
self.page=PageState::TakeOld(take_old);
}
}
let page=if let Some(page)=&mut taken_page{
page
}
else{
return
};
match event{
Event::UserEvent(event)=>match event{
InnerWindowEvent::Exit=>{
*control_flow=ControlFlow::Exit;
close_flag=true;
return
}
}
Event::WindowEvent{event,..}=>{
match event{
GWindowEvent::CloseRequested=>{
*control_flow=ControlFlow::Exit;
close_flag=true;
page.on_close_requested(self);
}
GWindowEvent::Resized(size)=>unsafe{
window_width=size.width as f32;
window_height=size.height as f32;
window_center=[window_width/2f32,window_height/2f32];
#[cfg(feature="mouse_cursor_icon")]
self.base.mouse_icon.update(&mut self.base.graphics);
page.on_window_resized(self,[size.width,size.height])
}
GWindowEvent::Moved(pos)=>page.on_window_moved(self,[pos.x,pos.y]),
GWindowEvent::CursorMoved{position,..}=>unsafe{
let last_position=mouse_cursor.position();
let position=[position.x as f32,position.y as f32];
let dx=position[0]-last_position[0];
let dy=position[1]-last_position[1];
mouse_cursor.set_position(position);
page.on_mouse_moved(self,[dx,dy])
}
GWindowEvent::MouseWheel{delta,..}=>page.on_mouse_scrolled(self,delta),
GWindowEvent::MouseInput{button,state,..}=>{
if state==ElementState::Pressed{
match button{
GMouseButton::Left=>{
#[cfg(feature="mouse_cursor_icon")]
self.base.mouse_icon.pressed(&mut self.base.graphics);
page.on_mouse_pressed(self,MouseButton::Left)
}
GMouseButton::Middle=>page.on_mouse_pressed(self,MouseButton::Middle),
GMouseButton::Right=>page.on_mouse_pressed(self,MouseButton::Right),
GMouseButton::Other(_)=>{}
}
}
else{
match button{
GMouseButton::Left=>{
#[cfg(feature="mouse_cursor_icon")]
self.base.mouse_icon.released(&mut self.base.graphics);
page.on_mouse_released(self,MouseButton::Left)
}
GMouseButton::Middle=>page.on_mouse_released(self,MouseButton::Middle),
GMouseButton::Right=>page.on_mouse_released(self,MouseButton::Right),
GMouseButton::Other(_)=>{}
}
}
}
GWindowEvent::KeyboardInput{input,..}=>{
let key=if let Some(key)=input.virtual_keycode{
unsafe{std::mem::transmute(key)}
}
else{
KeyboardButton::Unknown
};
if input.state==ElementState::Pressed{
page.on_keyboard_pressed(self,key)
}
else{
page.on_keyboard_released(self,key)
}
}
GWindowEvent::ReceivedCharacter(character)=>if !character.is_ascii_control(){
page.on_character_recieved(self,character)
}
#[cfg(feature="auto_hide")]
GWindowEvent::Focused(f)=>if !f{
*control_flow=ControlFlow::Exit;
self.base.display.gl_window().window().set_minimized(true);
page.on_window_focused(self,f);
}
#[cfg(not(feature="auto_hide"))]
GWindowEvent::Focused(f)=>page.on_window_focused(self,f),
GWindowEvent::DroppedFile(path)=>page.on_file_dropped(self,path),
GWindowEvent::HoveredFile(path)=>page.on_file_hovered(self,path),
GWindowEvent::HoveredFileCancelled=>page.on_file_hovered_canceled(self),
_=>{}
}
}
Event::Suspended=>page.on_suspended(self),
Event::Resumed=>page.on_resumed(self),
Event::MainEventsCleared=>{
self.base.display.gl_window().window().request_redraw();
}
Event::RedrawRequested(_)=>{
#[cfg(feature="fps_counter")]
self.base.count_fps();
page.on_redraw_requested(self);
}
_=>{}
}
});
close_flag
}
#[cfg(feature="auto_hide")]
fn wait_until_focused(&mut self,event_loop:&mut EventLoop<InnerWindowEvent>)->bool{
let mut close_flag=false;
let mut taken_page=if let PageState::SetNew(page)=&mut self.page{
page.take()
}
else{
None
};
event_loop.run_return(|event,_,control_flow|{
*control_flow=ControlFlow::Wait;
if let PageState::SetNew(page)=&mut self.page{
if let Some(_)=page{
let take_old=taken_page.take();
taken_page=page.take();
self.page=PageState::TakeOld(take_old);
}
}
let page=if let Some(page)=&mut taken_page{
page
}
else{
return
};
match event{
Event::UserEvent(event)=>match event{
InnerWindowEvent::Exit=>{
*control_flow=ControlFlow::Exit;
close_flag=true;
return
}
}
Event::WindowEvent{event,..}=>{
match event{
GWindowEvent::Resized(size)=>unsafe{
window_width=size.width as f32;
window_height=size.height as f32;
window_center=[window_width/2f32,window_height/2f32];
#[cfg(feature="mouse_cursor_icon")]
self.base.mouse_icon.update(&mut self.base.graphics);
page.on_window_resized(self,[size.width,size.height])
}
GWindowEvent::CloseRequested=>{
*control_flow=ControlFlow::Exit;
close_flag=true;
page.on_close_requested(self)
}
GWindowEvent::Focused(f)=>{
*control_flow=ControlFlow::Exit;
self.base.display.gl_window().window().set_minimized(false);
page.on_window_focused(self,f);
}
_=>return
}
}
Event::Suspended=>page.on_suspended(self),
Event::Resumed=>page.on_resumed(self),
_=>return
}
});
close_flag
}
}
impl<'a> Window for DynamicWindow<'a>{
type UserEvent=InnerWindowEvent;
fn window_base_mut(&mut self)->&mut WindowBase<InnerWindowEvent>{
&mut self.base
}
fn window_base(&self)->&WindowBase<InnerWindowEvent>{
&self.base
}
fn raw(
window_builder:WindowBuilder,
context_builder:ContextBuilder<NotCurrent>,
graphics_settings:GraphicsSettings,
event_loop:EventLoop<InnerWindowEvent>,
initial_colour:Option<Colour>,
#[cfg(feature="mouse_cursor_icon")]
mouse_cursor_icon_settings:MouseCursorIconSettings<PathBuf>,
)->Result<DynamicWindow<'a>,DisplayCreationError>{
#[cfg(not(feature="mouse_cursor_icon"))]
let base=WindowBase::<InnerWindowEvent>::raw(window_builder,
context_builder,
graphics_settings,
event_loop,
initial_colour
);
#[cfg(feature="mouse_cursor_icon")]
let base=WindowBase::<InnerWindowEvent>::raw(window_builder,
context_builder,
graphics_settings,
event_loop,
initial_colour,
mouse_cursor_icon_settings
);
match base{
Ok(w)=>{
let proxy=w.event_loop.create_proxy();
Ok(Self{
base:w,
page:PageState::SetNew(None),
event_loop_proxy:proxy,
})
}
Err(e)=>Err(e)
}
}
}