Implement debug view and load system fonts
This commit is contained in:
parent
ef056d8489
commit
2c6bfdbc8c
17 changed files with 418 additions and 241 deletions
|
|
@ -7,6 +7,9 @@ description = "A winit runtime for Iced"
|
|||
license = "MIT"
|
||||
repository = "https://github.com/hecrj/iced"
|
||||
|
||||
[features]
|
||||
debug = []
|
||||
|
||||
[dependencies]
|
||||
iced_native = { version = "0.1.0-alpha", path = "../native" }
|
||||
winit = { version = "0.20.0-alpha3", git = "https://github.com/rust-windowing/winit", rev = "709808eb4e69044705fcb214bcc30556db761405"}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ use crate::{
|
|||
column, conversion,
|
||||
input::{keyboard, mouse},
|
||||
renderer::{Target, Windowed},
|
||||
Cache, Column, Element, Event, Length, MouseCursor, UserInterface,
|
||||
Cache, Column, Debug, Element, Event, Length, MouseCursor, UserInterface,
|
||||
};
|
||||
|
||||
pub trait Application {
|
||||
type Renderer: Windowed + column::Renderer;
|
||||
|
||||
type Message;
|
||||
type Message: std::fmt::Debug;
|
||||
|
||||
fn update(&mut self, message: Self::Message);
|
||||
|
||||
|
|
@ -24,6 +24,9 @@ pub trait Application {
|
|||
window::WindowBuilder,
|
||||
};
|
||||
|
||||
let mut debug = Debug::new();
|
||||
|
||||
debug.startup_started();
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
// TODO: Ask for window settings and configure this properly
|
||||
|
|
@ -50,16 +53,22 @@ pub trait Application {
|
|||
&renderer,
|
||||
);
|
||||
|
||||
debug.layout_started();
|
||||
let user_interface = UserInterface::build(
|
||||
document(&mut self, size),
|
||||
document(&mut self, size, &mut debug),
|
||||
Cache::default(),
|
||||
&renderer,
|
||||
);
|
||||
debug.layout_finished();
|
||||
|
||||
debug.draw_started();
|
||||
let mut primitive = user_interface.draw(&mut renderer);
|
||||
debug.draw_finished();
|
||||
|
||||
let mut cache = Some(user_interface.into_cache());
|
||||
let mut events = Vec::new();
|
||||
let mut mouse_cursor = MouseCursor::OutOfBounds;
|
||||
debug.startup_finished();
|
||||
|
||||
window.request_redraw();
|
||||
|
||||
|
|
@ -70,17 +79,23 @@ pub trait Application {
|
|||
//
|
||||
// This will allow us to rebuild it only when a message is
|
||||
// handled.
|
||||
debug.layout_started();
|
||||
let mut user_interface = UserInterface::build(
|
||||
document(&mut self, size),
|
||||
document(&mut self, size, &mut debug),
|
||||
cache.take().unwrap(),
|
||||
&renderer,
|
||||
);
|
||||
debug.layout_finished();
|
||||
|
||||
debug.event_processing_started();
|
||||
let messages =
|
||||
user_interface.update(&renderer, events.drain(..));
|
||||
debug.event_processing_finished();
|
||||
|
||||
if messages.is_empty() {
|
||||
debug.draw_started();
|
||||
primitive = user_interface.draw(&mut renderer);
|
||||
debug.draw_finished();
|
||||
|
||||
cache = Some(user_interface.into_cache());
|
||||
} else {
|
||||
|
|
@ -91,16 +106,24 @@ pub trait Application {
|
|||
for message in messages {
|
||||
log::debug!("Updating");
|
||||
|
||||
debug.log_message(&message);
|
||||
|
||||
debug.update_started();
|
||||
self.update(message);
|
||||
debug.update_finished();
|
||||
}
|
||||
|
||||
debug.layout_started();
|
||||
let user_interface = UserInterface::build(
|
||||
document(&mut self, size),
|
||||
document(&mut self, size, &mut debug),
|
||||
temp_cache,
|
||||
&renderer,
|
||||
);
|
||||
debug.layout_finished();
|
||||
|
||||
debug.draw_started();
|
||||
primitive = user_interface.draw(&mut renderer);
|
||||
debug.draw_finished();
|
||||
|
||||
cache = Some(user_interface.into_cache());
|
||||
}
|
||||
|
|
@ -108,6 +131,8 @@ pub trait Application {
|
|||
window.request_redraw();
|
||||
}
|
||||
event::Event::RedrawRequested(_) => {
|
||||
debug.render_started();
|
||||
|
||||
if let Some(new_size) = new_size.take() {
|
||||
target.resize(new_size.width, new_size.height, &renderer);
|
||||
|
||||
|
|
@ -115,7 +140,9 @@ pub trait Application {
|
|||
}
|
||||
|
||||
let new_mouse_cursor =
|
||||
renderer.draw(&primitive, None, &mut target);
|
||||
renderer.draw(&primitive, &debug.overlay(), &mut target);
|
||||
|
||||
debug.render_finished();
|
||||
|
||||
if new_mouse_cursor != mouse_cursor {
|
||||
window.set_cursor_icon(conversion::mouse_cursor(
|
||||
|
|
@ -191,6 +218,14 @@ pub trait Application {
|
|||
},
|
||||
..
|
||||
} => {
|
||||
match (virtual_keycode, state) {
|
||||
(
|
||||
winit::event::VirtualKeyCode::F12,
|
||||
winit::event::ElementState::Pressed,
|
||||
) => debug.toggle(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
events.push(Event::Keyboard(keyboard::Event::Input {
|
||||
key_code: conversion::key_code(virtual_keycode),
|
||||
state: conversion::button_state(state),
|
||||
|
|
@ -229,17 +264,22 @@ impl From<winit::dpi::PhysicalSize> for Size {
|
|||
}
|
||||
}
|
||||
|
||||
fn document<Application>(
|
||||
application: &mut Application,
|
||||
fn document<'a, Application>(
|
||||
application: &'a mut Application,
|
||||
size: Size,
|
||||
) -> Element<Application::Message, Application::Renderer>
|
||||
debug: &mut Debug,
|
||||
) -> Element<'a, Application::Message, Application::Renderer>
|
||||
where
|
||||
Application: self::Application,
|
||||
Application::Message: 'static,
|
||||
{
|
||||
debug.view_started();
|
||||
let view = application.view();
|
||||
debug.view_finished();
|
||||
|
||||
Column::new()
|
||||
.width(Length::Units(size.width))
|
||||
.height(Length::Units(size.height))
|
||||
.push(application.view())
|
||||
.push(view)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
206
winit/src/debug/basic.rs
Normal file
206
winit/src/debug/basic.rs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::time;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Debug {
|
||||
is_enabled: bool,
|
||||
|
||||
startup_start: time::Instant,
|
||||
startup_duration: time::Duration,
|
||||
|
||||
update_start: time::Instant,
|
||||
update_durations: TimeBuffer,
|
||||
|
||||
view_start: time::Instant,
|
||||
view_durations: TimeBuffer,
|
||||
|
||||
layout_start: time::Instant,
|
||||
layout_durations: TimeBuffer,
|
||||
|
||||
event_start: time::Instant,
|
||||
event_durations: TimeBuffer,
|
||||
|
||||
draw_start: time::Instant,
|
||||
draw_durations: TimeBuffer,
|
||||
|
||||
render_start: time::Instant,
|
||||
render_durations: TimeBuffer,
|
||||
|
||||
message_count: usize,
|
||||
last_messages: VecDeque<String>,
|
||||
}
|
||||
|
||||
impl Debug {
|
||||
pub fn new() -> Self {
|
||||
let now = time::Instant::now();
|
||||
|
||||
Self {
|
||||
is_enabled: false,
|
||||
startup_start: now,
|
||||
startup_duration: time::Duration::from_secs(0),
|
||||
|
||||
update_start: now,
|
||||
update_durations: TimeBuffer::new(200),
|
||||
|
||||
view_start: now,
|
||||
view_durations: TimeBuffer::new(200),
|
||||
|
||||
layout_start: now,
|
||||
layout_durations: TimeBuffer::new(200),
|
||||
|
||||
event_start: now,
|
||||
event_durations: TimeBuffer::new(200),
|
||||
|
||||
draw_start: now,
|
||||
draw_durations: TimeBuffer::new(200),
|
||||
|
||||
render_start: now,
|
||||
render_durations: TimeBuffer::new(50),
|
||||
|
||||
message_count: 0,
|
||||
last_messages: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self) {
|
||||
self.is_enabled = !self.is_enabled;
|
||||
}
|
||||
|
||||
pub fn startup_started(&mut self) {
|
||||
self.startup_start = time::Instant::now();
|
||||
}
|
||||
|
||||
pub fn startup_finished(&mut self) {
|
||||
self.startup_duration = time::Instant::now() - self.startup_start;
|
||||
}
|
||||
|
||||
pub fn update_started(&mut self) {
|
||||
self.update_start = time::Instant::now();
|
||||
}
|
||||
|
||||
pub fn update_finished(&mut self) {
|
||||
self.update_durations
|
||||
.push(time::Instant::now() - self.update_start);
|
||||
}
|
||||
|
||||
pub fn view_started(&mut self) {
|
||||
self.view_start = time::Instant::now();
|
||||
}
|
||||
|
||||
pub fn view_finished(&mut self) {
|
||||
self.view_durations
|
||||
.push(time::Instant::now() - self.view_start);
|
||||
}
|
||||
|
||||
pub fn layout_started(&mut self) {
|
||||
self.layout_start = time::Instant::now();
|
||||
}
|
||||
|
||||
pub fn layout_finished(&mut self) {
|
||||
self.layout_durations
|
||||
.push(time::Instant::now() - self.layout_start);
|
||||
}
|
||||
|
||||
pub fn event_processing_started(&mut self) {
|
||||
self.event_start = time::Instant::now();
|
||||
}
|
||||
|
||||
pub fn event_processing_finished(&mut self) {
|
||||
self.event_durations
|
||||
.push(time::Instant::now() - self.event_start);
|
||||
}
|
||||
|
||||
pub fn draw_started(&mut self) {
|
||||
self.draw_start = time::Instant::now();
|
||||
}
|
||||
|
||||
pub fn draw_finished(&mut self) {
|
||||
self.draw_durations
|
||||
.push(time::Instant::now() - self.draw_start);
|
||||
}
|
||||
|
||||
pub fn render_started(&mut self) {
|
||||
self.render_start = time::Instant::now();
|
||||
}
|
||||
|
||||
pub fn render_finished(&mut self) {
|
||||
self.render_durations
|
||||
.push(time::Instant::now() - self.render_start);
|
||||
}
|
||||
|
||||
pub fn log_message<Message: std::fmt::Debug>(&mut self, message: &Message) {
|
||||
self.last_messages.push_back(format!("{:?}", message));
|
||||
|
||||
if self.last_messages.len() > 10 {
|
||||
let _ = self.last_messages.pop_front();
|
||||
}
|
||||
|
||||
self.message_count += 1;
|
||||
}
|
||||
|
||||
pub fn overlay(&self) -> Vec<String> {
|
||||
if !self.is_enabled {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mut lines = Vec::new();
|
||||
|
||||
fn key_value<T: std::fmt::Debug>(key: &str, value: T) -> String {
|
||||
format!("{: <30} {:?}", key, value)
|
||||
}
|
||||
|
||||
lines.push(key_value("Startup:", self.startup_duration));
|
||||
lines.push(key_value("Update:", self.update_durations.average()));
|
||||
lines.push(key_value("View:", self.view_durations.average()));
|
||||
lines.push(key_value("Layout:", self.layout_durations.average()));
|
||||
lines.push(key_value(
|
||||
"Event processing:",
|
||||
self.event_durations.average(),
|
||||
));
|
||||
lines.push(key_value(
|
||||
"Primitive generation:",
|
||||
self.draw_durations.average(),
|
||||
));
|
||||
lines.push(key_value("Render:", self.render_durations.average()));
|
||||
lines.push(key_value("Message count:", self.message_count));
|
||||
lines.push(String::from("Last messages:"));
|
||||
lines.extend(
|
||||
self.last_messages.iter().map(|msg| format!(" {}", msg)),
|
||||
);
|
||||
|
||||
lines
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TimeBuffer {
|
||||
head: usize,
|
||||
size: usize,
|
||||
contents: Vec<time::Duration>,
|
||||
}
|
||||
|
||||
impl TimeBuffer {
|
||||
fn new(capacity: usize) -> TimeBuffer {
|
||||
TimeBuffer {
|
||||
head: 0,
|
||||
size: 0,
|
||||
contents: vec![time::Duration::from_secs(0); capacity],
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, duration: time::Duration) {
|
||||
self.head = (self.head + 1) % self.contents.len();
|
||||
self.contents[self.head] = duration;
|
||||
self.size = (self.size + 1).min(self.contents.len());
|
||||
}
|
||||
|
||||
fn average(&self) -> time::Duration {
|
||||
let sum: time::Duration = if self.size == self.contents.len() {
|
||||
self.contents[..].iter().sum()
|
||||
} else {
|
||||
self.contents[..self.size].iter().sum()
|
||||
};
|
||||
|
||||
sum / self.size.max(1) as u32
|
||||
}
|
||||
}
|
||||
48
winit/src/debug/null.rs
Normal file
48
winit/src/debug/null.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#[derive(Debug)]
|
||||
pub struct Debug;
|
||||
|
||||
impl Debug {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self) {}
|
||||
|
||||
pub fn startup_started(&mut self) {}
|
||||
|
||||
pub fn startup_finished(&mut self) {}
|
||||
|
||||
pub fn update_started(&mut self) {}
|
||||
|
||||
pub fn update_finished(&mut self) {}
|
||||
|
||||
pub fn view_started(&mut self) {}
|
||||
|
||||
pub fn view_finished(&mut self) {}
|
||||
|
||||
pub fn layout_started(&mut self) {}
|
||||
|
||||
pub fn layout_finished(&mut self) {}
|
||||
|
||||
pub fn event_processing_started(&mut self) {}
|
||||
|
||||
pub fn event_processing_finished(&mut self) {}
|
||||
|
||||
pub fn draw_started(&mut self) {}
|
||||
|
||||
pub fn draw_finished(&mut self) {}
|
||||
|
||||
pub fn render_started(&mut self) {}
|
||||
|
||||
pub fn render_finished(&mut self) {}
|
||||
|
||||
pub fn log_message<Message: std::fmt::Debug>(
|
||||
&mut self,
|
||||
_message: &Message,
|
||||
) {
|
||||
}
|
||||
|
||||
pub fn overlay(&self) -> Vec<String> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
|
@ -6,3 +6,14 @@ pub mod conversion;
|
|||
mod application;
|
||||
|
||||
pub use application::Application;
|
||||
|
||||
// We disable debug capabilities on release builds unless the `debug` feature
|
||||
// is explicitly enabled.
|
||||
#[cfg_attr(any(debug_assertions, feature = "debug"), path = "debug/basic.rs")]
|
||||
#[cfg_attr(
|
||||
not(any(debug_assertions, feature = "debug")),
|
||||
path = "debug/null.rs"
|
||||
)]
|
||||
mod debug;
|
||||
|
||||
use debug::Debug;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue