implemented most of sketch into the architecture

This commit is contained in:
Well 2019-08-24 01:13:40 -03:00
parent cb8b0333e4
commit c6a9470cd9
8 changed files with 376 additions and 477 deletions

View File

@ -31,7 +31,7 @@ impl App {
title.to_string(),
background_color,
LayoutSize::new(800., 600.),
|c| content(c).into_box(),
|c| content(c).as_any(),
&self.event_loop,
self.event_loop.create_proxy(),
);
@ -92,15 +92,12 @@ impl App {
to_remove.push(win.id());
continue;
}
if win.update_layout {
win.layout();
}
if win.render_frame {
win.send_render_frame();
}
if win.redraw {
win.redraw_and_swap_buffers();
}
win.update();
}
for window_id in to_remove {

134
src/ui/color.rs Normal file
View File

@ -0,0 +1,134 @@
use super::{ColorF, GradientStop, LayoutPoint, LayoutRect, LayoutSize, RenderContext, Ui};
pub fn rgbf(r: f32, g: f32, b: f32) -> ColorF {
ColorF::new(r, g, b, 1.)
}
pub fn rgbaf(r: f32, g: f32, b: f32, a: f32) -> ColorF {
ColorF::new(r, g, b, a)
}
pub fn rgb(r: u8, g: u8, b: u8) -> ColorF {
ColorF::new(r as f32 / 255., g as f32 / 255., b as f32 / 255., 1.)
}
pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> ColorF {
ColorF::new(r as f32 / 255., g as f32 / 255., b as f32 / 255., a as f32 / 255.)
}
#[derive(Clone)]
pub struct FillColor {
color: ColorF,
}
impl FillColor {
pub fn new(color: ColorF) -> Self {
FillColor { color }
}
}
#[inline]
fn fill_measure(mut available_size: LayoutSize) -> LayoutSize {
if available_size.width.is_infinite() {
available_size.width = 0.;
}
if available_size.height.is_infinite() {
available_size.height = 0.;
}
available_size
}
impl Ui for FillColor {
type Child = ();
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
fill_measure(available_size)
}
fn render(&mut self, rc: &mut RenderContext) {
rc.push_rect(LayoutRect::from_size(rc.final_size()), self.color);
}
}
pub fn fill_color(color: ColorF) -> FillColor {
FillColor::new(color)
}
#[derive(Clone)]
pub struct FillGradient {
start: LayoutPoint,
end: LayoutPoint,
stops: Vec<GradientStop>,
}
impl FillGradient {
pub fn new(start: LayoutPoint, end: LayoutPoint, stops: Vec<GradientStop>) -> Self {
FillGradient { start, end, stops }
}
}
impl Ui for FillGradient {
type Child = ();
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
fill_measure(available_size)
}
fn render(&mut self, rc: &mut RenderContext) {
let final_size = rc.final_size();
let mut start = self.start;
let mut end = self.end;
start.x *= final_size.width;
start.y *= final_size.height;
end.x *= final_size.width;
end.y *= final_size.height;
rc.push_gradient(LayoutRect::from_size(final_size), start, end, self.stops.clone());
}
}
pub fn fill_gradient(start: LayoutPoint, end: LayoutPoint, stops: Vec<GradientStop>) -> FillGradient {
FillGradient::new(start, end, stops)
}
#[derive(Clone)]
pub struct BackgroundColor<T: Ui> {
child: T,
color: ColorF,
}
impl<T: Ui> BackgroundColor<T> {
pub fn new(child: T, color: ColorF) -> Self {
BackgroundColor { child, color }
}
}
impl<T: Ui> Ui for BackgroundColor<T> {
type Child = T;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
action(&mut self.child);
}
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
self.child.measure(available_size)
}
fn arrange(&mut self, final_size: LayoutSize) {
self.child.arrange(final_size)
}
fn render(&mut self, rc: &mut RenderContext) {
rc.push_rect(LayoutRect::from_size(rc.final_size()), self.color);
self.child.render(rc)
}
}
pub fn background_color<T: Ui>(child: T, color: ColorF) -> BackgroundColor<T> {
BackgroundColor::new(child, color)
}
pub trait BackgroundColorExt: Ui + Sized {
fn background_color(self, color: ColorF) -> BackgroundColor<Self> {
BackgroundColor::new(self, color)
}
}
impl<T: Ui> BackgroundColorExt for T {}

View File

@ -1,4 +1,4 @@
use super::{LayoutPoint, LayoutRect, LayoutSize, RenderContext, Ui, Update, KeyboardInput};
use super::{LayoutPoint, LayoutRect, LayoutSize, RenderContext, Ui};
use webrender::euclid;
/// Constrain a child to a size.
@ -15,8 +15,9 @@ impl<T: Ui> SizeChild<T> {
}
}
impl<T: Ui> Ui for SizeChild<T> {
fn on_keyboard_input(&mut self, input: &KeyboardInput) -> Update {
self.child.on_keyboard_input(input)
type Child = T;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
action(&mut self.child);
}
fn measure(&mut self, _: LayoutSize) -> LayoutSize {
@ -26,7 +27,7 @@ impl<T: Ui> Ui for SizeChild<T> {
fn arrange(&mut self, final_size: LayoutSize) {
self.child.arrange(final_size)
}
fn render(&self, c: RenderContext) {
fn render(&mut self, c: &mut RenderContext) {
self.child.render(c)
}
}
@ -55,8 +56,9 @@ impl<T: Ui> WidthChild<T> {
}
}
impl<T: Ui> Ui for WidthChild<T> {
fn on_keyboard_input(&mut self, input: &KeyboardInput) -> Update {
self.child.on_keyboard_input(input)
type Child = T;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
action(&mut self.child);
}
fn measure(&mut self, mut available_size: LayoutSize) -> LayoutSize {
@ -68,7 +70,7 @@ impl<T: Ui> Ui for WidthChild<T> {
fn arrange(&mut self, final_size: LayoutSize) {
self.child.arrange(final_size)
}
fn render(&self, c: RenderContext) {
fn render(&mut self, c: &mut RenderContext) {
self.child.render(c)
}
}
@ -93,8 +95,9 @@ impl<T: Ui> HeightChild<T> {
}
}
impl<T: Ui> Ui for HeightChild<T> {
fn on_keyboard_input(&mut self, input: &KeyboardInput) -> Update {
self.child.on_keyboard_input(input)
type Child = T;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
action(&mut self.child);
}
fn measure(&mut self, mut available_size: LayoutSize) -> LayoutSize {
@ -106,7 +109,7 @@ impl<T: Ui> Ui for HeightChild<T> {
fn arrange(&mut self, final_size: LayoutSize) {
self.child.arrange(final_size)
}
fn render(&self, c: RenderContext) {
fn render(&mut self, c: &mut RenderContext) {
self.child.render(c)
}
}
@ -134,10 +137,10 @@ impl<T: Ui> CenterChild<T> {
}
}
impl<T: Ui> Ui for CenterChild<T> {
fn on_keyboard_input(&mut self, input: &KeyboardInput) -> Update {
self.child.on_keyboard_input(input)
type Child = T;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
action(&mut self.child);
}
fn measure(&mut self, mut available_size: LayoutSize) -> LayoutSize {
self.child_rect.size = self.child.measure(available_size);
@ -160,8 +163,8 @@ impl<T: Ui> Ui for CenterChild<T> {
(final_size.height - self.child_rect.size.height) / 2.,
);
}
fn render(&self, mut c: RenderContext) {
c.push_child(&self.child, &self.child_rect);
fn render(&mut self, rc: &mut RenderContext) {
rc.push_child(&mut self.child, &self.child_rect);
}
}
pub fn center<T: Ui>(child: T) -> CenterChild<T> {
@ -202,8 +205,9 @@ impl<T: Ui> Margin<T> {
}
}
impl<T: Ui> Ui for Margin<T> {
fn on_keyboard_input(&mut self, input: &KeyboardInput) -> Update {
self.child.on_keyboard_input(input)
type Child = T;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
action(&mut self.child);
}
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
@ -217,15 +221,15 @@ impl<T: Ui> Ui for Margin<T> {
final_size.height -= self.top + self.bottom;
self.child.arrange(final_size);
}
fn render(&self, mut c: RenderContext) {
let sz = c.final_size();
fn render(&mut self, rc: &mut RenderContext) {
let sz = rc.final_size();
let rect = euclid::rect(
self.left,
self.top,
sz.width - self.left - self.right,
sz.height - self.top - self.bottom,
);
c.push_child(&self.child, &rect);
rc.push_child(&mut self.child, &rect);
}
}
pub trait MarginExt: Ui + Sized {

View File

@ -1,16 +1,19 @@
mod color;
mod layout;
mod stack;
mod text;
pub use crate::window::NextUpdate;
pub use color::*;
pub use layout::*;
pub use stack::*;
pub use text::*;
use app_units::Au;
use font_loader::system_fonts;
pub use glutin::event::KeyboardInput;
use std::collections::HashMap;
use webrender::api::*;
pub use glutin::event::KeyboardInput;
pub use webrender::api::{LayoutPoint, LayoutRect, LayoutSize};
pub struct InitContext {
@ -109,7 +112,7 @@ impl<'b> RenderContext<'b> {
}
}
pub fn push_child(&mut self, child: &impl Ui, final_rect: &LayoutRect) {
pub fn push_child(&mut self, child: &mut impl Ui, final_rect: &LayoutRect) {
let spatial_id = self.builder.push_reference_frame(
final_rect,
self.spatial_id,
@ -117,7 +120,7 @@ impl<'b> RenderContext<'b> {
PropertyBinding::Value(LayoutTransform::default()),
ReferenceFrameKind::Transform,
);
child.render(RenderContext::new(self.builder, spatial_id, final_rect.size));
child.render(&mut RenderContext::new(self.builder, spatial_id, final_rect.size));
self.builder.pop_reference_frame();
// about Stacking Contexts
@ -173,179 +176,140 @@ impl<'b> RenderContext<'b> {
}
}
#[derive(Clone, Copy)]
pub enum Update {
None,
Render,
Layout
}
pub trait Ui {
fn on_keyboard_input(&mut self, _input: &KeyboardInput) -> Update { Update::None }
type Child: Ui;
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize;
fn arrange(&mut self, _final_size: LayoutSize) {}
fn render(&self, c: RenderContext);
fn for_each_child(&mut self, _action: impl FnMut(&mut Self::Child)) {}
fn into_box(self) -> Box<dyn Ui>
where
Self: Sized + 'static,
{
Box::new(self)
}
}
impl Ui for Box<dyn Ui> {
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
self.as_mut().measure(available_size)
let mut desired_size = LayoutSize::default();
let mut have_child = false;
self.for_each_child(|c| {
have_child = true;
let child_desired_size = c.measure(available_size);
desired_size = desired_size.max(child_desired_size);
});
if have_child {
desired_size
} else {
desired_size = available_size;
if desired_size.width.is_infinite() {
desired_size.width = 0.;
}
if desired_size.height.is_infinite() {
desired_size.height = 0.;
}
desired_size
}
}
fn arrange(&mut self, final_size: LayoutSize) {
self.as_mut().arrange(final_size)
self.for_each_child(|c| c.arrange(final_size));
}
fn render(&self, c: RenderContext) {
self.as_ref().render(c)
fn render(&mut self, rc: &mut RenderContext) {
self.for_each_child(|c| c.render(rc));
}
fn into_box(self) -> Box<dyn Ui>
fn keyboard_input(&mut self, input: &KeyboardInput, update: &mut NextUpdate) {
self.for_each_child(|c| c.keyboard_input(input, update));
}
fn close_request(&mut self, update: &mut NextUpdate) {
self.for_each_child(|c| c.close_request(update));
}
fn as_any(self) -> AnyUi
where
Self: Sized + 'static,
{
AnyUi::new(self)
}
}
mod any_ui {
use super::*;
use std::any::Any;
pub trait UiFns: Any {
fn measure(&mut self, _: LayoutSize) -> LayoutSize;
fn arrange(&mut self, _: LayoutSize);
fn render(&mut self, _: &mut RenderContext);
fn keyboard_input(&mut self, input: &KeyboardInput, update: &mut NextUpdate);
fn close_request(&mut self, update: &mut NextUpdate);
}
impl<T: Ui + 'static> UiFns for T {
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
Ui::measure(self, available_size)
}
fn arrange(&mut self, final_size: LayoutSize) {
Ui::arrange(self, final_size)
}
fn render(&mut self, rc: &mut RenderContext) {
Ui::render(self, rc)
}
fn keyboard_input(&mut self, input: &KeyboardInput, update: &mut NextUpdate) {
Ui::keyboard_input(self, input, update)
}
fn close_request(&mut self, update: &mut NextUpdate) {
Ui::close_request(self, update)
}
}
}
pub struct AnyUi {
ui: Box<dyn any_ui::UiFns>,
}
impl AnyUi {
fn new<T: any_ui::UiFns>(ui: T) -> Self {
Self { ui: Box::new(ui) }
}
}
impl Ui for AnyUi {
type Child = ();
fn for_each_child(&mut self, _: impl FnMut(&mut Self::Child)) {
panic!("Ui::for_each_child must not be called directly")
}
fn as_any(self) -> AnyUi {
self
}
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
self.ui.measure(available_size)
}
fn arrange(&mut self, final_size: LayoutSize) {
self.ui.arrange(final_size)
}
fn render(&mut self, rc: &mut RenderContext) {
self.ui.render(rc)
}
fn keyboard_input(&mut self, input: &KeyboardInput, update: &mut NextUpdate) {
self.ui.keyboard_input(input, update)
}
fn close_request(&mut self, update: &mut NextUpdate) {
self.ui.close_request(update)
}
}
impl Ui for () {
type Child = ();
fn measure(&mut self, _: LayoutSize) -> LayoutSize {
LayoutSize::default()
}
fn render(&self, _: RenderContext) {}
fn render(&mut self, _: &mut RenderContext) {}
}
pub fn rgbf(r: f32, g: f32, b: f32) -> ColorF {
ColorF::new(r, g, b, 1.)
}
pub fn rgbaf(r: f32, g: f32, b: f32, a: f32) -> ColorF {
ColorF::new(r, g, b, a)
}
pub fn rgb(r: u8, g: u8, b: u8) -> ColorF {
ColorF::new(r as f32 / 255., g as f32 / 255., b as f32 / 255., 1.)
}
pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> ColorF {
ColorF::new(r as f32 / 255., g as f32 / 255., b as f32 / 255., a as f32 / 255.)
}
#[derive(Clone)]
pub struct FillColor {
color: ColorF,
}
impl FillColor {
pub fn new(color: ColorF) -> Self {
FillColor { color }
}
}
#[inline]
fn fill_measure(mut available_size: LayoutSize) -> LayoutSize {
if available_size.width.is_infinite() {
available_size.width = 0.;
}
if available_size.height.is_infinite() {
available_size.height = 0.;
}
available_size
}
impl Ui for FillColor {
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
fill_measure(available_size)
}
fn render(&self, mut c: RenderContext) {
c.push_rect(LayoutRect::from_size(c.final_size()), self.color);
}
}
pub fn fill_color(color: ColorF) -> FillColor {
FillColor::new(color)
}
#[derive(Clone)]
pub struct FillGradient {
start: LayoutPoint,
end: LayoutPoint,
stops: Vec<GradientStop>,
}
impl FillGradient {
pub fn new(start: LayoutPoint, end: LayoutPoint, stops: Vec<GradientStop>) -> Self {
FillGradient { start, end, stops }
}
}
impl Ui for FillGradient {
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
fill_measure(available_size)
}
fn render(&self, mut c: RenderContext) {
let final_size = c.final_size();
let mut start = self.start;
let mut end = self.end;
start.x *= final_size.width;
start.y *= final_size.height;
end.x *= final_size.width;
end.y *= final_size.height;
c.push_gradient(LayoutRect::from_size(final_size), start, end, self.stops.clone());
}
}
pub fn fill_gradient(start: LayoutPoint, end: LayoutPoint, stops: Vec<GradientStop>) -> FillGradient {
FillGradient::new(start, end, stops)
}
#[derive(Clone)]
pub struct BackgroundColor<T: Ui> {
child: T,
color: ColorF,
}
impl<T: Ui> BackgroundColor<T> {
pub fn new(child: T, color: ColorF) -> Self {
BackgroundColor { child, color }
}
}
impl<T: Ui> Ui for BackgroundColor<T> {
fn on_keyboard_input(&mut self, input: &KeyboardInput) -> Update {
self.child.on_keyboard_input(input)
}
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
self.child.measure(available_size)
}
fn arrange(&mut self, final_size: LayoutSize) {
self.child.arrange(final_size)
}
fn render(&self, mut c: RenderContext) {
c.push_rect(LayoutRect::from_size(c.final_size()), self.color);
self.child.render(c)
}
}
pub fn background_color<T: Ui>(child: T, color: ColorF) -> BackgroundColor<T> {
BackgroundColor::new(child, color)
}
pub trait BackgroundColorExt: Ui + Sized {
fn background_color(self, color: ColorF) -> BackgroundColor<Self> {
BackgroundColor::new(self, color)
}
}
impl<T: Ui> BackgroundColorExt for T {}

View File

@ -1,14 +1,14 @@
use super::{LayoutRect, LayoutSize, RenderContext, Ui, KeyboardInput, Update};
use super::{AnyUi, LayoutRect, LayoutSize, RenderContext, Ui};
pub struct StackChild {
child: Box<dyn Ui>,
child: AnyUi,
rect: LayoutRect,
}
impl StackChild {
pub fn new(child: impl Ui + 'static) -> Self {
StackChild {
child: child.into_box(),
child: child.as_any(),
rect: LayoutRect::default(),
}
}
@ -55,6 +55,13 @@ macro_rules! stack {
}
}
impl Ui for $Stack {
type Child = AnyUi;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
for c in self.children.iter_mut() {
action(&mut c.child)
}
}
fn measure(&mut self, mut available_size: LayoutSize) -> LayoutSize {
let mut total_size = LayoutSize::default();
@ -76,9 +83,9 @@ macro_rules! stack {
c.child.arrange(c.rect.size);
}
}
fn render(&self, mut r: RenderContext) {
for c in self.children.iter() {
r.push_child(&c.child, &c.rect);
fn render(&mut self, rc: &mut RenderContext) {
for c in self.children.iter_mut() {
rc.push_child(&mut c.child, &c.rect);
}
}
}
@ -108,26 +115,12 @@ impl ZStack {
}
}
impl Ui for ZStack {
fn on_keyboard_input(&mut self, input: &KeyboardInput) -> Update {
let mut update_layout = false;
let mut update_render = false;
type Child = AnyUi;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
for c in self.children.iter_mut() {
match c.child.on_keyboard_input(input) {
Update::Layout => update_layout = true,
Update::Render => update_render = true,
_ => {}
}
action(&mut c.child)
}
if update_layout {
return Update::Layout;
}
if update_render {
return Update::Render;
}
Update::None
}
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
@ -148,9 +141,9 @@ impl Ui for ZStack {
}
}
fn render(&self, mut r: RenderContext) {
for c in self.children.iter() {
r.push_child(&c.child, &c.rect);
fn render(&mut self, rc: &mut RenderContext) {
for c in self.children.iter_mut() {
rc.push_child(&mut c.child, &c.rect);
}
}
}

View File

@ -58,12 +58,14 @@ pub fn text(c: &mut InitContext, text: &str, color: ColorF, font_family: &str, f
}
impl Ui for Text {
type Child = ();
fn measure(&mut self, _: LayoutSize) -> LayoutSize {
self.size
}
fn render(&self, mut c: RenderContext) {
c.push_text(
fn render(&mut self, rc: &mut RenderContext) {
rc.push_text(
LayoutRect::from_size(self.size),
&self.glyphs,
self.font_instance_key,

View File

@ -1,240 +0,0 @@
pub struct RenderContext;
#[derive(Default, Clone, Copy)]
pub struct LayoutSize {
width: f32,
height: f32,
}
impl LayoutSize {
pub fn max(&self, other: LayoutSize) -> LayoutSize {
unimplemented!()
}
}
pub struct KeyboardInput {}
enum Invalidate {
Render,
Layout,
}
enum CloseRequest {
Window,
App,
}
#[derive(Clone, Copy)]
pub struct WorkKey(usize);
pub struct UpdateContext {
next_work_key: WorkKey,
invalidate: Option<Invalidate>,
close: Option<CloseRequest>,
cancel_close: bool,
new_window_title: Option<String>,
new_work: Vec<(WorkKey, Box<dyn FnOnce()>)>,
cancel_work: Vec<WorkKey>
}
impl UpdateContext {
pub fn invalidate_layout(&mut self) {
self.invalidate = Some(Invalidate::Layout);
}
pub fn invalidate_render(&mut self) {
if let Some(Invalidate::Layout) = self.invalidate {
return;
}
self.invalidate = Some(Invalidate::Render);
}
pub fn close_window(&mut self) {
if let Some(CloseRequest::App) = self.close {
return;
}
self.close = Some(CloseRequest::Window);
}
pub fn close_app(&mut self) {
self.close = Some(CloseRequest::App);
}
pub fn cancel_close(&mut self) {
self.cancel_close = true;
}
pub fn set_window_title(&mut self, title: String) {
self.new_window_title = Some(title);
}
pub fn start_work(&mut self, work: impl FnOnce() + 'static) -> WorkKey {
let key = self.next_work_key;
self.new_work.push((key, Box::new(work)));
self.next_work_key = WorkKey(key.0.wrapping_add(1));
key
}
pub fn cancel_work(&mut self, work_key: WorkKey) {
self.cancel_work.push(work_key)
}
}
pub trait Ui {
type Child: Ui;
fn for_each_child(&mut self, action: impl FnMut(&mut Self::Child));
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
let mut desired_size = LayoutSize::default();
let mut have_child = false;
self.for_each_child(|c| {
have_child = true;
let child_desired_size = c.measure(available_size);
desired_size = desired_size.max(child_desired_size);
});
if have_child {
desired_size
} else {
desired_size = available_size;
if desired_size.width.is_infinite() {
desired_size.width = 0.;
}
if desired_size.height.is_infinite() {
desired_size.height = 0.;
}
desired_size
}
}
fn arrange(&mut self, final_size: LayoutSize) {
self.for_each_child(|c| c.arrange(final_size));
}
fn render(&mut self, rc: &mut RenderContext) {
self.for_each_child(|c| c.render(rc));
}
fn keyboard_input(&mut self, input: &KeyboardInput, update: &mut UpdateContext) {
self.for_each_child(|c| c.keyboard_input(input, update));
}
fn close_request(&mut self, update: &mut UpdateContext) {
self.for_each_child(|c| c.close_request(update));
}
fn as_any(self) -> AnyUi
where
Self: Sized + 'static,
{
AnyUi::new(self)
}
}
impl Ui for () {
type Child = ();
fn for_each_child(&mut self, _: impl FnMut(&mut Self::Child)) {}
fn measure(&mut self, _: LayoutSize) -> LayoutSize {
LayoutSize::default()
}
fn arrange(&mut self, _: LayoutSize) {}
fn render(&mut self, _: &mut RenderContext) {}
fn keyboard_input(&mut self, _: &KeyboardInput, _: &mut UpdateContext) {}
fn close_request(&mut self, _: &mut UpdateContext) {}
}
mod any_ui {
use super::*;
use std::any::Any;
pub trait UiFns: Any {
fn measure(&mut self, _: LayoutSize) -> LayoutSize;
fn arrange(&mut self, _: LayoutSize);
fn render(&mut self, _: &mut RenderContext);
fn keyboard_input(&mut self, input: &KeyboardInput, update: &mut UpdateContext);
fn close_request(&mut self, update: &mut UpdateContext);
}
impl<T: Ui + 'static> UiFns for T {
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
Ui::measure(self, available_size)
}
fn arrange(&mut self, final_size: LayoutSize) {
Ui::arrange(self, final_size)
}
fn render(&mut self, rc: &mut RenderContext) {
Ui::render(self, rc)
}
fn keyboard_input(&mut self, input: &KeyboardInput, update: &mut UpdateContext) {
Ui::keyboard_input(self, input, update)
}
fn close_request(&mut self, update: &mut UpdateContext) {
Ui::close_request(self, update)
}
}
}
pub struct AnyUi {
ui: Box<dyn any_ui::UiFns>,
}
impl AnyUi {
fn new<T: any_ui::UiFns>(ui: T) -> Self {
Self { ui: Box::new(ui) }
}
}
impl Ui for AnyUi {
type Child = ();
fn for_each_child(&mut self, _: impl FnMut(&mut Self::Child)) {
panic!("Ui::for_each_child must not be called directly")
}
fn as_any(self) -> AnyUi {
self
}
fn measure(&mut self, available_size: LayoutSize) -> LayoutSize {
self.ui.measure(available_size)
}
fn arrange(&mut self, final_size: LayoutSize) {
self.ui.arrange(final_size)
}
fn render(&mut self, rc: &mut RenderContext) {
self.ui.render(rc)
}
fn keyboard_input(&mut self, input: &KeyboardInput, update: &mut UpdateContext) {
self.ui.keyboard_input(input, update)
}
fn close_request(&mut self, update: &mut UpdateContext) {
self.ui.close_request(update)
}
}
struct Container<T: Ui> {
child: T,
}
impl<T: Ui> Ui for Container<T> {
type Child = T;
fn for_each_child(&mut self, mut action: impl FnMut(&mut Self::Child)) {
action(&mut self.child);
}
}

View File

@ -1,4 +1,4 @@
use crate::ui::{self, InitContext, RenderContext, Ui};
use crate::ui::{AnyUi, InitContext, RenderContext, Ui};
use gleam::gl;
use glutin::dpi::LogicalSize;
use glutin::event::WindowEvent;
@ -32,6 +32,45 @@ impl RenderNotifier for Notifier {
}
}
pub struct NextUpdate {
update_layout: bool,
render_frame: bool,
_request_close: bool,
}
impl NextUpdate {
fn update_layout(&mut self) {
self.update_layout = true;
}
fn render_frame(&mut self) {
self.render_frame = true;
}
//-------idea---------
//
//pub fn close_app(&mut self) {
// self.close = Some(CloseRequest::App);
//}
//pub fn cancel_close(&mut self) {
// self.cancel_close = true;
//}
//pub fn set_window_title(&mut self, title: String) {
// self.new_window_title = Some(title);
//}
//pub fn start_work(&mut self, work: impl FnOnce() + 'static) -> WorkKey {
// let key = self.next_work_key;
// self.new_work.push((key, Box::new(work)));
// self.next_work_key = WorkKey(key.0.wrapping_add(1));
// key
//}
//pub fn cancel_work(&mut self, work_key: WorkKey) {
// self.cancel_work.push(work_key)
//}
}
pub struct Window {
context: Option<WindowedContext<NotCurrent>>,
@ -44,13 +83,12 @@ pub struct Window {
dpi_factor: f32,
inner_size: LayoutSize,
content: Box<dyn Ui>,
content: AnyUi,
content_size: LayoutSize,
first_draw: bool,
pub update_layout: bool,
pub render_frame: bool,
pub next_update: NextUpdate,
pub redraw: bool,
pub close: bool,
@ -61,7 +99,7 @@ impl Window {
name: String,
clear_color: ColorF,
inner_size: LayoutSize,
content: impl Fn(&mut InitContext) -> Box<dyn Ui>,
content: impl Fn(&mut InitContext) -> AnyUi,
event_loop: &EventLoopWindowTarget<WebRenderEvent>,
event_loop_proxy: EventLoopProxy<WebRenderEvent>,
) -> Self {
@ -127,9 +165,11 @@ impl Window {
content_size: LayoutSize::default(),
first_draw: true,
update_layout: true,
render_frame: true,
next_update: NextUpdate {
update_layout: true,
render_frame: true,
_request_close: false,
},
redraw: false,
close: false,
@ -143,20 +183,16 @@ impl Window {
WindowEvent::Resized(new_size) => {
// open issue on resize delay: https://github.com/servo/webrender/issues/1640
self.inner_size = LayoutSize::new(new_size.width as f32, new_size.height as f32);
self.update_layout = true;
self.next_update.update_layout();
}
WindowEvent::HiDpiFactorChanged(new_dpi_factor) => {
self.dpi_factor = new_dpi_factor as f32;
self.update_layout = true;
self.next_update.update_layout();
}
WindowEvent::RedrawRequested => self.redraw = true,
WindowEvent::CloseRequested => self.close = true,
WindowEvent::KeyboardInput { input, .. } => match self.content.on_keyboard_input(&input) {
ui::Update::Layout => self.update_layout = true,
ui::Update::Render => self.render_frame = true,
_ => {}
}
WindowEvent::KeyboardInput { input, .. } => self.content.keyboard_input(&input, &mut self.next_update),
_ => has_update = false,
}
@ -168,10 +204,17 @@ impl Window {
DeviceIntSize::new(size.width as i32, size.height as i32)
}
pub fn update(&mut self) {
self.update_layout();
self.send_render_frame();
}
/// Updates the content layout and flags `render_frame`.
pub fn layout(&mut self) {
assert!(self.update_layout);
self.update_layout = false;
fn update_layout(&mut self) {
if !self.next_update.update_layout {
return;
}
self.next_update.update_layout = false;
let device_size = self.device_size();
@ -185,19 +228,21 @@ impl Window {
self.content_size = self.content.measure(self.inner_size).min(self.inner_size);
self.content.arrange(self.content_size);
self.render_frame = true;
self.next_update.render_frame();
}
/// Generates window content display list and sends a new frame request to webrender.
/// Webrender will request a redraw when the frame is done.
pub fn send_render_frame(&mut self) {
assert!(self.render_frame);
self.render_frame = false;
fn send_render_frame(&mut self) {
if !self.next_update.render_frame {
return;
}
self.next_update.render_frame = false;
let mut txn = Transaction::new();
let mut builder = DisplayListBuilder::new(self.pipeline_id, self.inner_size);
self.content.render(RenderContext::new(
self.content.render(&mut RenderContext::new(
&mut builder,
SpatialId::root_reference_frame(self.pipeline_id),
self.content_size,