Skip to content

Commit

Permalink
Implement explicit text caching in the widget state tree
Browse files Browse the repository at this point in the history
  • Loading branch information
hecrj committed Aug 30, 2023
1 parent c9bd487 commit ed34543
Show file tree
Hide file tree
Showing 79 changed files with 1,913 additions and 1,708 deletions.
6 changes: 4 additions & 2 deletions core/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,11 @@ where

fn layout(
&self,
tree: &Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
self.widget.layout(renderer, limits)
self.widget.layout(tree, renderer, limits)
}

fn operate(
Expand Down Expand Up @@ -491,10 +492,11 @@ where

fn layout(
&self,
tree: &Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
self.element.widget.layout(renderer, limits)
self.element.widget.layout(tree, renderer, limits)
}

fn operate(
Expand Down
28 changes: 27 additions & 1 deletion core/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub mod flex;
pub use limits::Limits;
pub use node::Node;

use crate::{Point, Rectangle, Vector};
use crate::{Point, Rectangle, Size, Vector};

/// The bounds of a [`Node`] and its children, using absolute coordinates.
#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -63,3 +63,29 @@ impl<'a> Layout<'a> {
})
}
}

/// Produces a [`Node`] with two children nodes one right next to each other.
pub fn next_to_each_other(
limits: &Limits,
spacing: f32,
left: impl FnOnce(&Limits) -> Node,
right: impl FnOnce(&Limits) -> Node,
) -> Node {
let left_node = left(limits);
let left_size = left_node.size();

let right_limits = limits.shrink(Size::new(left_size.width + spacing, 0.0));

let mut right_node = right(&right_limits);
let right_size = right_node.size();

right_node.move_to(Point::new(left_size.width + spacing, 0.0));

Node::with_children(
Size::new(
left_size.width + spacing + right_size.width,
left_size.height.max(right_size.height),
),
vec![left_node, right_node],
)
}
12 changes: 8 additions & 4 deletions core/src/layout/flex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use crate::Element;

use crate::layout::{Limits, Node};
use crate::widget;
use crate::{Alignment, Padding, Point, Size};

/// The main axis of a flex layout.
Expand Down Expand Up @@ -66,6 +67,7 @@ pub fn resolve<Message, Renderer>(
spacing: f32,
align_items: Alignment,
items: &[Element<'_, Message, Renderer>],
trees: &[widget::Tree],
) -> Node
where
Renderer: crate::Renderer,
Expand All @@ -81,7 +83,7 @@ where
let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
nodes.resize(items.len(), Node::default());

for (i, child) in items.iter().enumerate() {
for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
let fill_factor = match axis {
Axis::Horizontal => child.as_widget().width(),
Axis::Vertical => child.as_widget().height(),
Expand All @@ -94,7 +96,8 @@ where
let child_limits =
Limits::new(Size::ZERO, Size::new(max_width, max_height));

let layout = child.as_widget().layout(renderer, &child_limits);
let layout =
child.as_widget().layout(tree, renderer, &child_limits);
let size = layout.size();

available -= axis.main(size);
Expand All @@ -108,7 +111,7 @@ where

let remaining = available.max(0.0);

for (i, child) in items.iter().enumerate() {
for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
let fill_factor = match axis {
Axis::Horizontal => child.as_widget().width(),
Axis::Vertical => child.as_widget().height(),
Expand All @@ -133,7 +136,8 @@ where
Size::new(max_width, max_height),
);

let layout = child.as_widget().layout(renderer, &child_limits);
let layout =
child.as_widget().layout(tree, renderer, &child_limits);
cross = cross.max(axis.cross(layout.size()));

nodes[i] = layout;
Expand Down
15 changes: 1 addition & 14 deletions core/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,13 @@ mod null;
#[cfg(debug_assertions)]
pub use null::Null;

use crate::layout;
use crate::{Background, BorderRadius, Color, Element, Rectangle, Vector};
use crate::{Background, BorderRadius, Color, Rectangle, Vector};

/// A component that can be used by widgets to draw themselves on a screen.
pub trait Renderer: Sized {
/// The supported theme of the [`Renderer`].
type Theme;

/// Lays out the elements of a user interface.
///
/// You should override this if you need to perform any operations before or
/// after layouting. For instance, trimming the measurements cache.
fn layout<Message>(
&mut self,
element: &Element<'_, Message, Self>,
limits: &layout::Limits,
) -> layout::Node {
element.as_widget().layout(self, limits)
}

/// Draws the primitives recorded in the given closure in a new layer.
///
/// The layer will clip its contents to the provided `bounds`.
Expand Down
96 changes: 72 additions & 24 deletions core/src/renderer/null.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::alignment;
use crate::renderer::{self, Renderer};
use crate::text::{self, Text};
use crate::{Background, Font, Point, Rectangle, Size, Vector};
use crate::{Background, Color, Font, Pixels, Point, Rectangle, Size, Vector};

use std::borrow::Cow;

Expand Down Expand Up @@ -41,6 +42,7 @@ impl Renderer for Null {

impl text::Renderer for Null {
type Font = Font;
type Paragraph = ();

const ICON_FONT: Font = Font::DEFAULT;
const CHECKMARK_ICON: char = '0';
Expand All @@ -50,37 +52,83 @@ impl text::Renderer for Null {
Font::default()
}

fn default_size(&self) -> f32 {
16.0
fn default_size(&self) -> Pixels {
Pixels(16.0)
}

fn load_font(&mut self, _font: Cow<'static, [u8]>) {}

fn measure(
&self,
_content: &str,
_size: f32,
_line_height: text::LineHeight,
_font: Font,
_bounds: Size,
_shaping: text::Shaping,
) -> Size {
Size::new(0.0, 20.0)
fn create_paragraph(&self, _text: Text<'_, Self::Font>) -> Self::Paragraph {
}

fn hit_test(
fn resize_paragraph(
&self,
_contents: &str,
_size: f32,
_line_height: text::LineHeight,
_font: Self::Font,
_bounds: Size,
_shaping: text::Shaping,
_point: Point,
_nearest_only: bool,
) -> Option<text::Hit> {
_paragraph: &mut Self::Paragraph,
_new_bounds: Size,
) {
}

fn fill_paragraph(
&mut self,
_paragraph: &Self::Paragraph,
_position: Point,
_color: Color,
) {
}

fn fill_text(
&mut self,
_paragraph: Text<'_, Self::Font>,
_position: Point,
_color: Color,
) {
}
}

impl text::Paragraph for () {
type Font = Font;

fn content(&self) -> &str {
""
}

fn text_size(&self) -> Pixels {
Pixels(16.0)
}

fn font(&self) -> Self::Font {
Font::default()
}

fn line_height(&self) -> text::LineHeight {
text::LineHeight::default()
}

fn shaping(&self) -> text::Shaping {
text::Shaping::default()
}

fn horizontal_alignment(&self) -> alignment::Horizontal {
alignment::Horizontal::Left
}

fn vertical_alignment(&self) -> alignment::Vertical {
alignment::Vertical::Top
}

fn grapheme_position(&self, _line: usize, _index: usize) -> Option<Point> {
None
}

fn fill_text(&mut self, _text: Text<'_, Self::Font>) {}
fn bounds(&self) -> Size {
Size::ZERO
}

fn min_bounds(&self) -> Size {
Size::ZERO
}

fn hit_test(&self, _point: Point) -> Option<text::Hit> {
None
}
}
Loading

0 comments on commit ed34543

Please sign in to comment.