what is this

This commit is contained in:
Richard 2022-07-12 10:26:16 -03:00 committed by bungoboingo
parent 64e21535c7
commit 97914daaab
3 changed files with 293 additions and 162 deletions

View file

@ -1,7 +1,7 @@
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// TODO(derezzedex) /// TODO(derezzedex)
pub struct Id(u64); pub struct Id(u64);

View file

@ -301,144 +301,182 @@ async fn run_instance<A, E, C>(
use iced_futures::futures::stream::StreamExt; use iced_futures::futures::stream::StreamExt;
use winit::event; use winit::event;
// TODO(derezzedex)
let mut clipboard = let mut clipboard =
Clipboard::connect(windows.values().next().expect("No window found")); Clipboard::connect(windows.values().next().expect("No window found"));
let mut cache = user_interface::Cache::default(); let mut cache = user_interface::Cache::default();
let mut surface = compositor let mut window_ids: HashMap<_, _> = windows
.create_surface(&windows.values().next().expect("No window found")); .iter()
.map(|(&id, window)| (window.id(), id))
.collect();
// TODO(derezzedex) let mut states = HashMap::new();
let mut state = State::new( let mut interfaces = ManuallyDrop::new(HashMap::new());
&application,
windows.values().next().expect("No window found"),
);
let mut viewport_version = state.viewport_version();
let physical_size = state.physical_size(); for (&id, window) in windows.keys().zip(windows.values()) {
let mut surface = compositor.create_surface(window);
compositor.configure_surface( let state = State::new(&application, window);
&mut surface,
physical_size.width,
physical_size.height,
);
run_command( let physical_size = state.physical_size();
&application,
&mut cache, compositor.configure_surface(
&state, &mut surface,
&mut renderer, physical_size.width,
init_command, physical_size.height,
&mut runtime, );
&mut clipboard,
&mut proxy, let user_interface = build_user_interface(
&mut debug, &application,
&windows, user_interface::Cache::default(),
|| compositor.fetch_information(), &mut renderer,
); state.logical_size(),
&mut debug,
);
let window_state: WindowState<A, C> = WindowState { surface, state };
let _ = states.insert(id, window_state);
let _ = interfaces.insert(id, user_interface);
}
{
// TODO(derezzedex)
let window_state = states.values().next().expect("No state found");
run_command(
&application,
&mut cache,
&window_state.state,
&mut renderer,
init_command,
&mut runtime,
&mut clipboard,
&mut proxy,
&mut debug,
&windows,
|| compositor.fetch_information(),
);
}
runtime.track(application.subscription().map(Event::Application)); runtime.track(application.subscription().map(Event::Application));
let mut user_interface = ManuallyDrop::new(build_user_interface(
&application,
user_interface::Cache::default(),
&mut renderer,
state.logical_size(),
&mut debug,
));
let mut mouse_interaction = mouse::Interaction::default(); let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new(); let mut events = Vec::new();
let mut messages = Vec::new(); let mut messages = Vec::new();
debug.startup_finished(); debug.startup_finished();
while let Some(event) = receiver.next().await { 'main: while let Some(event) = receiver.next().await {
match event { match event {
event::Event::MainEventsCleared => { event::Event::MainEventsCleared => {
if events.is_empty() && messages.is_empty() { dbg!(states.keys().collect::<Vec<_>>());
continue; for id in states.keys().copied().collect::<Vec<_>>() {
} let cursor_position =
states.get(&id).unwrap().state.cursor_position();
let window = windows.get(&id).unwrap();
debug.event_processing_started(); if events.is_empty() && messages.is_empty() {
continue;
let (interface_state, statuses) = user_interface.update(
&events,
state.cursor_position(),
&mut renderer,
&mut clipboard,
&mut messages,
);
debug.event_processing_finished();
for event in events.drain(..).zip(statuses.into_iter()) {
runtime.broadcast(event);
}
if !messages.is_empty()
|| matches!(
interface_state,
user_interface::State::Outdated,
)
{
let mut cache =
ManuallyDrop::into_inner(user_interface).into_cache();
// Update application
update(
&mut application,
&mut cache,
&state,
&mut renderer,
&mut runtime,
&mut clipboard,
&mut proxy,
&mut debug,
&mut messages,
&windows,
|| compositor.fetch_information(),
);
// Update window
state.synchronize(&application, &windows, &proxy);
let should_exit = application.should_exit();
user_interface = ManuallyDrop::new(build_user_interface(
&application,
cache,
&mut renderer,
state.logical_size(),
&mut debug,
));
if should_exit {
break;
} }
debug.event_processing_started();
let (interface_state, statuses) = {
let user_interface = interfaces.get_mut(&id).unwrap();
user_interface.update(
&events,
cursor_position,
&mut renderer,
&mut clipboard,
&mut messages,
)
};
debug.event_processing_finished();
// TODO(derezzedex): only drain events for this window
for event in events.drain(..).zip(statuses.into_iter()) {
runtime.broadcast(event);
}
if !messages.is_empty()
|| matches!(
interface_state,
user_interface::State::Outdated,
)
{
let state = &mut states.get_mut(&id).unwrap().state;
let pure_states: HashMap<_, _> =
ManuallyDrop::into_inner(interfaces)
.drain()
.map(
|(id, interface): (
window::Id,
UserInterface<'_, _, _>,
)| {
(id, interface.into_cache())
},
)
.collect();
// Update application
update(
&mut application,
&mut cache,
state,
&mut renderer,
&mut runtime,
&mut clipboard,
&mut proxy,
&mut debug,
&mut messages,
&windows,
|| compositor.fetch_information(),
);
// Update window
state.synchronize(&application, &windows, &proxy);
let should_exit = application.should_exit();
interfaces = ManuallyDrop::new(build_user_interfaces(
&application,
&mut renderer,
&mut debug,
&states,
pure_states,
));
if should_exit {
break 'main;
}
}
debug.draw_started();
let new_mouse_interaction = {
let user_interface = interfaces.get_mut(&id).unwrap();
let state = &states.get(&id).unwrap().state;
user_interface.draw(
&mut renderer,
state.theme(),
&renderer::Style {
text_color: state.text_color(),
},
state.cursor_position(),
)
};
debug.draw_finished();
if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction(
new_mouse_interaction,
));
mouse_interaction = new_mouse_interaction;
}
window.request_redraw();
} }
debug.draw_started();
let new_mouse_interaction = user_interface.draw(
&mut renderer,
state.theme(),
&renderer::Style {
text_color: state.text_color(),
},
state.cursor_position(),
);
debug.draw_finished();
// TODO(derezzedex)
let window = windows.values().next().expect("No window found");
if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction(
new_mouse_interaction,
));
mouse_interaction = new_mouse_interaction;
}
window.request_redraw();
} }
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS( event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url), event::MacOS::ReceivedUrl(url),
@ -456,43 +494,81 @@ async fn run_instance<A, E, C>(
messages.push(message); messages.push(message);
} }
Event::WindowCreated(id, window) => { Event::WindowCreated(id, window) => {
let mut surface = compositor.create_surface(&window);
let state = State::new(&application, &window);
let physical_size = state.physical_size();
compositor.configure_surface(
&mut surface,
physical_size.width,
physical_size.height,
);
let user_interface = build_user_interface(
&application,
user_interface::Cache::default(),
&mut renderer,
state.logical_size(),
&mut debug,
);
let window_state: WindowState<A, C> =
WindowState { surface, state };
let _ = states.insert(id, window_state);
let _ = interfaces.insert(id, user_interface);
let _ = window_ids.insert(window.id(), id);
let _ = windows.insert(id, window); let _ = windows.insert(id, window);
} }
Event::NewWindow(_, _) => unreachable!(), Event::NewWindow(_, _) => unreachable!(),
}, },
event::Event::RedrawRequested(_) => { event::Event::RedrawRequested(id) => {
let physical_size = state.physical_size(); let window_state = window_ids
.get(&id)
.and_then(|id| states.get_mut(id))
.unwrap();
let mut user_interface = window_ids
.get(&id)
.and_then(|id| interfaces.remove(id))
.unwrap();
let physical_size = window_state.state.physical_size();
if physical_size.width == 0 || physical_size.height == 0 { if physical_size.width == 0 || physical_size.height == 0 {
continue; continue;
} }
debug.render_started(); debug.render_started();
let current_viewport_version = state.viewport_version();
if viewport_version != current_viewport_version { if window_state.state.viewport_changed() {
let logical_size = state.logical_size(); let logical_size = window_state.state.logical_size();
debug.layout_started(); debug.layout_started();
user_interface = ManuallyDrop::new( user_interface =
ManuallyDrop::into_inner(user_interface) user_interface.relayout(logical_size, &mut renderer);
.relayout(logical_size, &mut renderer),
);
debug.layout_finished(); debug.layout_finished();
debug.draw_started(); debug.draw_started();
let new_mouse_interaction = user_interface.draw( let new_mouse_interaction = {
&mut renderer, let state = &window_state.state;
state.theme(),
&renderer::Style {
text_color: state.text_color(),
},
state.cursor_position(),
);
// TODO(derezzedex) user_interface.draw(
let window = &mut renderer,
windows.values().next().expect("No window found"); state.theme(),
&renderer::Style {
text_color: state.text_color(),
},
state.cursor_position(),
)
};
let window = window_ids
.get(&id)
.and_then(|id| windows.get(id))
.unwrap();
if new_mouse_interaction != mouse_interaction { if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction( window.set_cursor_icon(conversion::mouse_interaction(
new_mouse_interaction, new_mouse_interaction,
@ -502,20 +578,21 @@ async fn run_instance<A, E, C>(
} }
debug.draw_finished(); debug.draw_finished();
let _ = interfaces
.insert(*window_ids.get(&id).unwrap(), user_interface);
compositor.configure_surface( compositor.configure_surface(
&mut surface, &mut window_state.surface,
physical_size.width, physical_size.width,
physical_size.height, physical_size.height,
); );
viewport_version = current_viewport_version;
} }
match compositor.present( match compositor.present(
&mut renderer, &mut renderer,
&mut surface, &mut window_state.surface,
state.viewport(), window_state.state.viewport(),
state.background_color(), window_state.state.background_color(),
&debug.overlay(), &debug.overlay(),
) { ) {
Ok(()) => { Ok(()) => {
@ -545,22 +622,30 @@ async fn run_instance<A, E, C>(
} }
event::Event::WindowEvent { event::Event::WindowEvent {
event: window_event, event: window_event,
.. window_id,
} => { } => {
if requests_exit(&window_event, state.modifiers()) // dbg!(window_id);
let window = window_ids
.get(&window_id)
.and_then(|id| windows.get(id))
.unwrap();
let window_state = window_ids
.get(&window_id)
.and_then(|id| states.get_mut(id))
.unwrap();
if requests_exit(&window_event, window_state.state.modifiers())
&& exit_on_close_request && exit_on_close_request
{ {
break; break;
} }
// TODO(derezzedex) window_state.state.update(window, &window_event, &mut debug);
let window = windows.values().next().expect("No window found");
state.update(window, &window_event, &mut debug);
if let Some(event) = conversion::window_event( if let Some(event) = conversion::window_event(
&window_event, &window_event,
state.scale_factor(), window_state.state.scale_factor(),
state.modifiers(), window_state.state.modifiers(),
) { ) {
events.push(event); events.push(event);
} }
@ -570,7 +655,7 @@ async fn run_instance<A, E, C>(
} }
// Manually drop the user interface // Manually drop the user interface
drop(ManuallyDrop::into_inner(user_interface)); // drop(ManuallyDrop::into_inner(user_interface));
} }
/// Returns true if the provided event should cause an [`Application`] to /// Returns true if the provided event should cause an [`Application`] to
@ -791,6 +876,54 @@ pub fn run_command<A, E>(
} }
} }
struct WindowState<A, C>
where
A: Application,
C: iced_graphics::window::Compositor<Renderer = A::Renderer>,
<A::Renderer as crate::Renderer>::Theme: StyleSheet,
{
surface: <C as iced_graphics::window::Compositor>::Surface,
state: State<A>,
}
fn build_user_interfaces<'a, A, C>(
application: &'a A,
renderer: &mut A::Renderer,
debug: &mut Debug,
states: &HashMap<window::Id, WindowState<A, C>>,
mut pure_states: HashMap<window::Id, user_interface::Cache>,
) -> HashMap<
window::Id,
UserInterface<
'a,
<A as Application>::Message,
<A as Application>::Renderer,
>,
>
where
A: Application + 'static,
C: iced_graphics::window::Compositor<Renderer = A::Renderer> + 'static,
<A::Renderer as crate::Renderer>::Theme: StyleSheet,
{
let mut interfaces = HashMap::new();
for (id, pure_state) in pure_states.drain() {
let state = &states.get(&id).unwrap().state;
let user_interface = build_user_interface(
application,
pure_state,
renderer,
state.logical_size(),
debug,
);
let _ = interfaces.insert(id, user_interface);
}
interfaces
}
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
mod platform { mod platform {
pub fn run<T, F>( pub fn run<T, F>(

View file

@ -19,7 +19,7 @@ where
title: String, title: String,
scale_factor: f64, scale_factor: f64,
viewport: Viewport, viewport: Viewport,
viewport_version: usize, viewport_changed: bool,
cursor_position: winit::dpi::PhysicalPosition<f64>, cursor_position: winit::dpi::PhysicalPosition<f64>,
modifiers: winit::event::ModifiersState, modifiers: winit::event::ModifiersState,
theme: <A::Renderer as crate::Renderer>::Theme, theme: <A::Renderer as crate::Renderer>::Theme,
@ -51,7 +51,7 @@ where
title, title,
scale_factor, scale_factor,
viewport, viewport,
viewport_version: 0, viewport_changed: false,
// TODO: Encode cursor availability in the type-system // TODO: Encode cursor availability in the type-system
cursor_position: winit::dpi::PhysicalPosition::new(-1.0, -1.0), cursor_position: winit::dpi::PhysicalPosition::new(-1.0, -1.0),
modifiers: winit::event::ModifiersState::default(), modifiers: winit::event::ModifiersState::default(),
@ -66,11 +66,9 @@ where
&self.viewport &self.viewport
} }
/// Returns the version of the [`Viewport`] of the [`State`]. /// TODO(derezzedex)
/// pub fn viewport_changed(&self) -> bool {
/// The version is incremented every time the [`Viewport`] changes. self.viewport_changed
pub fn viewport_version(&self) -> usize {
self.viewport_version
} }
/// Returns the physical [`Size`] of the [`Viewport`] of the [`State`]. /// Returns the physical [`Size`] of the [`Viewport`] of the [`State`].
@ -133,7 +131,7 @@ where
window.scale_factor() * self.scale_factor, window.scale_factor() * self.scale_factor,
); );
self.viewport_version = self.viewport_version.wrapping_add(1); self.viewport_changed = true;
} }
WindowEvent::ScaleFactorChanged { WindowEvent::ScaleFactorChanged {
scale_factor: new_scale_factor, scale_factor: new_scale_factor,
@ -147,7 +145,7 @@ where
new_scale_factor * self.scale_factor, new_scale_factor * self.scale_factor,
); );
self.viewport_version = self.viewport_version.wrapping_add(1); self.viewport_changed = true;
} }
WindowEvent::CursorMoved { position, .. } WindowEvent::CursorMoved { position, .. }
| WindowEvent::Touch(Touch { | WindowEvent::Touch(Touch {