implemented most of sketch into the architecture
This commit is contained in:
parent
cb8b0333e4
commit
c6a9470cd9
11
src/app.rs
11
src/app.rs
|
@ -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 {
|
||||
|
|
|
@ -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 {}
|
|
@ -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 {
|
||||
|
|
280
src/ui/mod.rs
280
src/ui/mod.rs
|
@ -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 {}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue