Rearchitect to allow API compliance

This commit is contained in:
Ryan Goldstein 2019-03-11 22:18:58 -04:00
parent 3dd0e31cc4
commit aaee72422a
4 changed files with 163 additions and 114 deletions

View file

@ -139,7 +139,7 @@ impl<T> EventLoop<T> {
/// ///
/// [`ControlFlow`]: ./enum.ControlFlow.html /// [`ControlFlow`]: ./enum.ControlFlow.html
#[inline] #[inline]
pub fn run<F>(self, event_handler: F) // TODO: this needs to be ! pub fn run<F>(self, event_handler: F) -> !
where F: 'static + FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow) where F: 'static + FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow)
{ {
self.event_loop.run(event_handler) self.event_loop.run(event_handler)

View file

@ -32,30 +32,55 @@ impl DeviceId {
pub struct EventLoop<T: 'static> { pub struct EventLoop<T: 'static> {
elw: RootELW<T>, elw: RootELW<T>,
} runner: EventLoopRunnerShared<T>
#[derive(Clone)]
struct EventLoopData<T> {
events: VecDeque<Event<T>>,
control: ControlFlow,
} }
pub struct EventLoopWindowTarget<T: 'static> { pub struct EventLoopWindowTarget<T: 'static> {
data: Rc<RefCell<EventLoopData<T>>>, pub(crate) canvases: RefCell<Vec<CanvasElement>>,
_marker: PhantomData<T>
}
impl<T> EventLoopWindowTarget<T> {
fn new() -> Self {
EventLoopWindowTarget {
canvases: RefCell::new(Vec::new()),
_marker: PhantomData
}
}
}
#[derive(Clone)]
pub struct EventLoopProxy<T> {
runner: EventLoopRunnerShared<T>
}
impl<T> EventLoopProxy<T> {
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
self.runner.send_event(Event::UserEvent(event));
Ok(())
}
}
type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
struct ELRShared<T> {
runner: RefCell<Option<EventLoopRunner<T>>>,
events: RefCell<VecDeque<Event<T>>>, // TODO: this may not be necessary?
}
struct EventLoopRunner<T> {
control: ControlFlow,
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
} }
impl<T> EventLoop<T> { impl<T> EventLoop<T> {
pub fn new() -> Self { pub fn new() -> Self {
EventLoop { EventLoop {
elw: RootELW { elw: RootELW {
p: EventLoopWindowTarget { p: EventLoopWindowTarget::new(),
data: Rc::new(RefCell::new(EventLoopData {
events: VecDeque::new(),
control: ControlFlow::Poll
}))
},
_marker: PhantomData _marker: PhantomData
} },
runner: Rc::new(ELRShared::blank()),
} }
} }
@ -67,50 +92,41 @@ impl<T> EventLoop<T> {
MonitorHandle MonitorHandle
} }
pub fn run<F>(mut self, event_handler: F) pub fn run<F>(mut self, mut event_handler: F) -> !
where F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow) where F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
{ {
// TODO: Create event handlers for the JS events // TODO: Create event handlers for the JS events
// TODO: how to handle request redraw? // TODO: how to handle request redraw?
// TODO: onclose (stdweb PR) // TODO: onclose (stdweb PR)
// TODO: file dropping, PathBuf isn't useful for web // TODO: file dropping, PathBuf isn't useful for web
let EventLoop { elw, runner } = self;
for canvas in elw.p.canvases.borrow().iter() {
register(&runner, canvas);
}
let relw = RootELW {
p: EventLoopWindowTarget::new(),
_marker: PhantomData
};
runner.set_listener(Box::new(move |evt, ctrl| event_handler(evt, &relw, ctrl)));
let document = &document(); let document = &document();
self.elw.p.add_event(document, |mut data, event: BlurEvent| { add_event(&runner, document, |_, _: BlurEvent| {
}); });
self.elw.p.add_event(document, |mut data, event: FocusEvent| { add_event(&runner, document, |_, _: FocusEvent| {
}); });
add_event(&runner, document, |elrs, event: KeyDownEvent| {
stdweb::event_loop(); // TODO: this is only necessary for stdweb emscripten, should it be here?
}
pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy {
data: self.elw.p.data.clone()
}
}
pub fn window_target(&self) -> &RootELW<T> {
&self.elw
}
}
impl<T> EventLoopWindowTarget<T> {
pub fn register_window(&self, other: &Window) {
let canvas = &other.canvas;
self.add_event(canvas, |mut data, event: KeyDownEvent| {
let key = event.key(); let key = event.key();
let mut characters = key.chars(); let mut characters = key.chars();
let first = characters.next(); let first = characters.next();
let second = characters.next(); let second = characters.next();
if let (Some(key), None) = (first, second) { if let (Some(key), None) = (first, second) {
data.events.push_back(Event::WindowEvent { elrs.send_event(Event::WindowEvent {
window_id: RootWI(WindowId), window_id: RootWI(WindowId),
event: WindowEvent::ReceivedCharacter(key) event: WindowEvent::ReceivedCharacter(key)
}); });
} }
data.events.push_back(Event::WindowEvent { elrs.send_event(Event::WindowEvent {
window_id: RootWI(WindowId), window_id: RootWI(WindowId),
event: WindowEvent::KeyboardInput { event: WindowEvent::KeyboardInput {
// TODO: is there a way to get keyboard device? // TODO: is there a way to get keyboard device?
@ -124,8 +140,8 @@ impl<T> EventLoopWindowTarget<T> {
} }
}); });
}); });
self.add_event(canvas, |mut data, event: KeyUpEvent| { add_event(&runner, document, |elrs, event: KeyUpEvent| {
data.events.push_back(Event::WindowEvent { elrs.send_event(Event::WindowEvent {
window_id: RootWI(WindowId), window_id: RootWI(WindowId),
event: WindowEvent::KeyboardInput { event: WindowEvent::KeyboardInput {
// TODO: is there a way to get keyboard device? // TODO: is there a way to get keyboard device?
@ -139,24 +155,43 @@ impl<T> EventLoopWindowTarget<T> {
} }
}); });
}); });
self.add_event(canvas, |mut data, event: PointerOutEvent| { stdweb::event_loop(); // TODO: this is only necessary for stdweb emscripten, should it be here?
data.events.push_back(Event::WindowEvent { js! {
throw "Using exceptions for control flow, don't mind me";
}
unreachable!();
}
pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy {
runner: self.runner.clone()
}
}
pub fn window_target(&self) -> &RootELW<T> {
&self.elw
}
}
fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &CanvasElement) {
add_event(elrs, canvas, |elrs, event: PointerOutEvent| {
elrs.send_event(Event::WindowEvent {
window_id: RootWI(WindowId), window_id: RootWI(WindowId),
event: WindowEvent::CursorLeft { event: WindowEvent::CursorLeft {
device_id: RootDI(DeviceId(event.pointer_id())) device_id: RootDI(DeviceId(event.pointer_id()))
} }
}); });
}); });
self.add_event(canvas, |mut data, event: PointerOverEvent| { add_event(elrs, canvas, |elrs, event: PointerOverEvent| {
data.events.push_back(Event::WindowEvent { elrs.send_event(Event::WindowEvent {
window_id: RootWI(WindowId), window_id: RootWI(WindowId),
event: WindowEvent::CursorEntered { event: WindowEvent::CursorEntered {
device_id: RootDI(DeviceId(event.pointer_id())) device_id: RootDI(DeviceId(event.pointer_id()))
} }
}); });
}); });
self.add_event(canvas, |mut data, event: PointerMoveEvent| { add_event(elrs, canvas, |elrs, event: PointerMoveEvent| {
data.events.push_back(Event::WindowEvent { elrs.send_event(Event::WindowEvent {
window_id: RootWI(WindowId), window_id: RootWI(WindowId),
event: WindowEvent::CursorMoved { event: WindowEvent::CursorMoved {
device_id: RootDI(DeviceId(event.pointer_id())), device_id: RootDI(DeviceId(event.pointer_id())),
@ -168,8 +203,8 @@ impl<T> EventLoopWindowTarget<T> {
} }
}); });
}); });
self.add_event(canvas, |mut data, event: PointerUpEvent| { add_event(elrs, canvas, |elrs, event: PointerUpEvent| {
data.events.push_back(Event::WindowEvent { elrs.send_event(Event::WindowEvent {
window_id: RootWI(WindowId), window_id: RootWI(WindowId),
event: WindowEvent::MouseInput { event: WindowEvent::MouseInput {
device_id: RootDI(DeviceId(event.pointer_id())), device_id: RootDI(DeviceId(event.pointer_id())),
@ -179,8 +214,8 @@ impl<T> EventLoopWindowTarget<T> {
} }
}); });
}); });
self.add_event(canvas, |mut data, event: PointerDownEvent| { add_event(elrs, canvas, |elrs, event: PointerDownEvent| {
data.events.push_back(Event::WindowEvent { elrs.send_event(Event::WindowEvent {
window_id: RootWI(WindowId), window_id: RootWI(WindowId),
event: WindowEvent::MouseInput { event: WindowEvent::MouseInput {
device_id: RootDI(DeviceId(event.pointer_id())), device_id: RootDI(DeviceId(event.pointer_id())),
@ -190,33 +225,47 @@ impl<T> EventLoopWindowTarget<T> {
} }
}); });
}); });
} }
fn add_event<T: 'static, E, F>(elrs: &EventLoopRunnerShared<T>, target: &impl IEventTarget, mut handler: F)
fn add_event<E, F>(&self, target: &impl IEventTarget, mut handler: F) where E: ConcreteEvent, F: FnMut(&EventLoopRunnerShared<T>, E) + 'static {
where E: ConcreteEvent, F: FnMut(RefMut<EventLoopData<T>>, E) + 'static { let elrs = elrs.clone(); // TODO: necessary?
let data = self.data.clone();
target.add_event_listener(move |event: E| { target.add_event_listener(move |event: E| {
event.prevent_default(); event.prevent_default();
event.stop_propagation(); event.stop_propagation();
event.cancel_bubble(); event.cancel_bubble();
handler(data.borrow_mut(), event); handler(&elrs, event);
});
}
impl<T> ELRShared<T> {
fn blank() -> ELRShared<T> {
ELRShared {
runner: RefCell::new(None),
events: RefCell::new(VecDeque::new())
}
}
fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>) {
*self.runner.borrow_mut() = Some(EventLoopRunner {
control: ControlFlow::Poll,
event_handler
}); });
} }
}
#[derive(Clone)] // TODO: handle event loop closures
pub struct EventLoopProxy<T> { // TODO: handle event buffer
data: Rc<RefCell<EventLoopData<T>>> fn send_event(&self, event: Event<T>) {
} match *self.runner.borrow_mut() {
Some(ref mut runner) => {
impl<T> EventLoopProxy<T> { // TODO: bracket this in control flow events?
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { (runner.event_handler)(event, &mut runner.control);
self.data.borrow_mut().events.push_back(Event::UserEvent(event));
Ok(())
} }
None => ()
}
}
} }

View file

@ -197,6 +197,6 @@ pub fn keyboard_modifiers_state(event: &impl IKeyboardEvent) -> ModifiersState {
} }
pub fn scancode<T: JsSerialize>(event: &T) -> ScanCode { pub fn scancode<T: JsSerialize>(event: &T) -> ScanCode {
let which = js! ( return @{event}.which(); ); let which = js! ( return @{event}.which; );
which.try_into().expect("The which value should be a number") which.try_into().expect("The which value should be a number")
} }

View file

@ -63,6 +63,7 @@ impl Window {
document().body() document().body()
.ok_or_else(|| CreationError::OsError("Failed to find body node".to_owned()))? .ok_or_else(|| CreationError::OsError("Failed to find body node".to_owned()))?
.append_child(&canvas); .append_child(&canvas);
target.canvases.borrow_mut().push(canvas.clone());
let window = Window { canvas }; let window = Window { canvas };
if let Some(dimensions) = attr.dimensions { if let Some(dimensions) = attr.dimensions {
window.set_inner_size(dimensions); window.set_inner_size(dimensions);
@ -87,7 +88,6 @@ impl Window {
window.set_decorations(attr.decorations); window.set_decorations(attr.decorations);
window.set_always_on_top(attr.always_on_top); window.set_always_on_top(attr.always_on_top);
window.set_window_icon(attr.window_icon); window.set_window_icon(attr.window_icon);
target.register_window(&window);
Ok(window) Ok(window)
} }