WIP: Everything shredded
This commit is contained in:
parent
7536645eea
commit
6638407ff9
26 changed files with 1136 additions and 1354 deletions
|
@ -1,20 +1,18 @@
|
|||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json,
|
||||
window::MeasurementContext,
|
||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||
json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use json::ToJson;
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
pub struct Align {
|
||||
child: ElementBox,
|
||||
pub struct Align<V: View> {
|
||||
child: ElementBox<V>,
|
||||
alignment: Vector2F,
|
||||
}
|
||||
|
||||
impl Align {
|
||||
pub fn new(child: ElementBox) -> Self {
|
||||
impl<V: View> Align<V> {
|
||||
pub fn new(child: ElementBox<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
alignment: Vector2F::zero(),
|
||||
|
@ -42,18 +40,19 @@ impl Align {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for Align {
|
||||
impl<V: View> Element<V> for Align<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view: &mut V,
|
||||
mut constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let mut size = constraint.max;
|
||||
constraint.min = Vector2F::zero();
|
||||
let child_size = self.child.layout(constraint, cx);
|
||||
let child_size = self.child.layout(view, constraint, cx);
|
||||
if size.x().is_infinite() {
|
||||
size.set_x(child_size.x());
|
||||
}
|
||||
|
@ -65,10 +64,12 @@ impl Element for Align {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
view: &mut V,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
let my_center = bounds.size() / 2.;
|
||||
let my_target = my_center + my_center * self.alignment;
|
||||
|
@ -77,6 +78,8 @@ impl Element for Align {
|
|||
let child_target = child_center + child_center * self.alignment;
|
||||
|
||||
self.child.paint(
|
||||
view,
|
||||
scene,
|
||||
bounds.origin() - (child_target - my_target),
|
||||
visible_bounds,
|
||||
cx,
|
||||
|
@ -85,28 +88,30 @@ impl Element for Align {
|
|||
|
||||
fn rect_for_text_range(
|
||||
&self,
|
||||
view: &V,
|
||||
range_utf16: std::ops::Range<usize>,
|
||||
_: RectF,
|
||||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(view, range_utf16, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
&self,
|
||||
view: &V,
|
||||
bounds: pathfinder_geometry::rect::RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
cx: &ViewContext<V>,
|
||||
) -> json::Value {
|
||||
json!({
|
||||
"type": "Align",
|
||||
"bounds": bounds.to_json(),
|
||||
"alignment": self.alignment.to_json(),
|
||||
"child": self.child.debug(cx),
|
||||
"child": self.child.debug(view, cx),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use super::Element;
|
||||
use crate::{
|
||||
json::{self, json},
|
||||
window::MeasurementContext,
|
||||
DebugContext, PaintContext,
|
||||
SceneBuilder, View, ViewContext,
|
||||
};
|
||||
use json::ToJson;
|
||||
use pathfinder_geometry::{
|
||||
|
@ -10,20 +9,20 @@ use pathfinder_geometry::{
|
|||
vector::{vec2f, Vector2F},
|
||||
};
|
||||
|
||||
pub struct Canvas<F>(F);
|
||||
pub struct Canvas<V, F>(F);
|
||||
|
||||
impl<F> Canvas<F>
|
||||
impl<V: View, F> Canvas<V, F>
|
||||
where
|
||||
F: FnMut(RectF, RectF, &mut PaintContext),
|
||||
F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>),
|
||||
{
|
||||
pub fn new(f: F) -> Self {
|
||||
Self(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Element for Canvas<F>
|
||||
impl<V, F> Element<V> for Canvas<V, F>
|
||||
where
|
||||
F: FnMut(RectF, RectF, &mut PaintContext),
|
||||
F: FnMut(RectF, RectF, &mut ViewContext<V>),
|
||||
{
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
@ -48,10 +47,12 @@ where
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
self.0(bounds, visible_bounds, cx)
|
||||
}
|
||||
|
@ -63,7 +64,8 @@ where
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &MeasurementContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
None
|
||||
}
|
||||
|
@ -73,7 +75,8 @@ where
|
|||
bounds: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &DebugContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> json::Value {
|
||||
json!({"type": "Canvas", "bounds": bounds.to_json()})
|
||||
}
|
||||
|
|
|
@ -3,42 +3,43 @@ use std::ops::Range;
|
|||
use pathfinder_geometry::{rect::RectF, vector::Vector2F};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
json, DebugContext, Element, ElementBox, LayoutContext, MeasurementContext, PaintContext,
|
||||
SizeConstraint,
|
||||
};
|
||||
use crate::{json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext};
|
||||
|
||||
pub struct Clipped {
|
||||
child: ElementBox,
|
||||
pub struct Clipped<V: View> {
|
||||
child: ElementBox<V>,
|
||||
}
|
||||
|
||||
impl Clipped {
|
||||
pub fn new(child: ElementBox) -> Self {
|
||||
impl<V: View> Clipped<V> {
|
||||
pub fn new(child: ElementBox<V>) -> Self {
|
||||
Self { child }
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for Clipped {
|
||||
impl<V: View> Element<V> for Clipped<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
(self.child.layout(constraint, cx), ())
|
||||
(self.child.layout(constraint, view, cx), ())
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
cx.scene.push_layer(Some(bounds));
|
||||
self.child.paint(bounds.origin(), visible_bounds, cx);
|
||||
self.child
|
||||
.paint(scene, bounds.origin(), visible_bounds, view, cx);
|
||||
cx.scene.pop_layer();
|
||||
}
|
||||
|
||||
|
@ -49,9 +50,10 @@ impl Element for Clipped {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -59,11 +61,12 @@ impl Element for Clipped {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> json::Value {
|
||||
json!({
|
||||
"type": "Clipped",
|
||||
"child": self.child.debug(cx)
|
||||
"child": self.child.debug(view, cx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,22 +5,20 @@ use serde_json::json;
|
|||
|
||||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json,
|
||||
window::MeasurementContext,
|
||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||
json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
|
||||
pub struct ConstrainedBox {
|
||||
child: ElementBox,
|
||||
constraint: Constraint,
|
||||
pub struct ConstrainedBox<V: View> {
|
||||
child: ElementBox<V>,
|
||||
constraint: Constraint<V>,
|
||||
}
|
||||
|
||||
pub enum Constraint {
|
||||
pub enum Constraint<V: View> {
|
||||
Static(SizeConstraint),
|
||||
Dynamic(Box<dyn FnMut(SizeConstraint, &mut LayoutContext) -> SizeConstraint>),
|
||||
Dynamic(Box<dyn FnMut(SizeConstraint, &mut V, &mut ViewContext<V>) -> SizeConstraint>),
|
||||
}
|
||||
|
||||
impl ToJson for Constraint {
|
||||
impl<V: View> ToJson for Constraint<V> {
|
||||
fn to_json(&self) -> serde_json::Value {
|
||||
match self {
|
||||
Constraint::Static(constraint) => constraint.to_json(),
|
||||
|
@ -29,8 +27,8 @@ impl ToJson for Constraint {
|
|||
}
|
||||
}
|
||||
|
||||
impl ConstrainedBox {
|
||||
pub fn new(child: ElementBox) -> Self {
|
||||
impl<V: View> ConstrainedBox<V> {
|
||||
pub fn new(child: ElementBox<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
constraint: Constraint::Static(Default::default()),
|
||||
|
@ -39,7 +37,7 @@ impl ConstrainedBox {
|
|||
|
||||
pub fn dynamically(
|
||||
mut self,
|
||||
constraint: impl 'static + FnMut(SizeConstraint, &mut LayoutContext) -> SizeConstraint,
|
||||
constraint: impl 'static + FnMut(SizeConstraint, &mut V, &mut ViewContext<V>) -> SizeConstraint,
|
||||
) -> Self {
|
||||
self.constraint = Constraint::Dynamic(Box::new(constraint));
|
||||
self
|
||||
|
@ -120,41 +118,48 @@ impl ConstrainedBox {
|
|||
fn constraint(
|
||||
&mut self,
|
||||
input_constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> SizeConstraint {
|
||||
match &mut self.constraint {
|
||||
Constraint::Static(constraint) => *constraint,
|
||||
Constraint::Dynamic(compute_constraint) => compute_constraint(input_constraint, cx),
|
||||
Constraint::Dynamic(compute_constraint) => {
|
||||
compute_constraint(input_constraint, view, cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for ConstrainedBox {
|
||||
impl<V: View> Element<V> for ConstrainedBox<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
mut parent_constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let constraint = self.constraint(parent_constraint, cx);
|
||||
let constraint = self.constraint(parent_constraint, view, cx);
|
||||
parent_constraint.min = parent_constraint.min.max(constraint.min);
|
||||
parent_constraint.max = parent_constraint.max.min(constraint.max);
|
||||
parent_constraint.max = parent_constraint.max.max(parent_constraint.min);
|
||||
let size = self.child.layout(parent_constraint, cx);
|
||||
let size = self.child.layout(parent_constraint, view, cx);
|
||||
(size, ())
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
cx.paint_layer(Some(visible_bounds), |cx| {
|
||||
self.child.paint(bounds.origin(), visible_bounds, cx);
|
||||
self.child
|
||||
.paint(scene, bounds.origin(), visible_bounds, view, cx);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -165,9 +170,10 @@ impl Element for ConstrainedBox {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -175,8 +181,9 @@ impl Element for ConstrainedBox {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> json::Value {
|
||||
json!({"type": "ConstrainedBox", "assigned_constraint": self.constraint.to_json(), "child": self.child.debug(cx)})
|
||||
json!({"type": "ConstrainedBox", "assigned_constraint": self.constraint.to_json(), "child": self.child.debug(view, cx)})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,7 @@ use crate::{
|
|||
json::ToJson,
|
||||
platform::CursorStyle,
|
||||
scene::{self, Border, CursorRegion, Quad},
|
||||
window::MeasurementContext,
|
||||
Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||
Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
@ -36,13 +35,13 @@ pub struct ContainerStyle {
|
|||
pub cursor: Option<CursorStyle>,
|
||||
}
|
||||
|
||||
pub struct Container {
|
||||
child: ElementBox,
|
||||
pub struct Container<V: View> {
|
||||
child: ElementBox<V>,
|
||||
style: ContainerStyle,
|
||||
}
|
||||
|
||||
impl Container {
|
||||
pub fn new(child: ElementBox) -> Self {
|
||||
impl<V: View> Container<V> {
|
||||
pub fn new(child: ElementBox<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
style: Default::default(),
|
||||
|
@ -185,14 +184,15 @@ impl Container {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for Container {
|
||||
impl<V: View> Element<V> for Container<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let mut size_buffer = self.margin_size() + self.padding_size();
|
||||
if !self.style.border.overlay {
|
||||
|
@ -202,16 +202,18 @@ impl Element for Container {
|
|||
min: (constraint.min - size_buffer).max(Vector2F::zero()),
|
||||
max: (constraint.max - size_buffer).max(Vector2F::zero()),
|
||||
};
|
||||
let child_size = self.child.layout(child_constraint, cx);
|
||||
let child_size = self.child.layout(child_constraint, view, cx);
|
||||
(child_size + size_buffer, ())
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
let quad_bounds = RectF::from_points(
|
||||
bounds.origin() + vec2f(self.style.margin.left, self.style.margin.top),
|
||||
|
@ -247,7 +249,8 @@ impl Element for Container {
|
|||
corner_radius: self.style.corner_radius,
|
||||
});
|
||||
|
||||
self.child.paint(child_origin, visible_bounds, cx);
|
||||
self.child
|
||||
.paint(scene, child_origin, visible_bounds, view, cx);
|
||||
|
||||
cx.scene.push_layer(None);
|
||||
cx.scene.push_quad(Quad {
|
||||
|
@ -270,7 +273,8 @@ impl Element for Container {
|
|||
self.style.border.left_width(),
|
||||
self.style.border.top_width(),
|
||||
);
|
||||
self.child.paint(child_origin, visible_bounds, cx);
|
||||
self.child
|
||||
.paint(scene, child_origin, visible_bounds, view, cx);
|
||||
|
||||
if self.style.overlay_color.is_some() {
|
||||
cx.scene.push_layer(None);
|
||||
|
@ -292,9 +296,10 @@ impl Element for Container {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -302,13 +307,14 @@ impl Element for Container {
|
|||
bounds: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
view: &V,
|
||||
cx: &crate::DebugContext,
|
||||
) -> serde_json::Value {
|
||||
json!({
|
||||
"type": "Container",
|
||||
"bounds": bounds.to_json(),
|
||||
"details": self.style.to_json(),
|
||||
"child": self.child.debug(cx),
|
||||
"child": self.child.debug(view, cx),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,9 @@ use crate::{
|
|||
vector::{vec2f, Vector2F},
|
||||
},
|
||||
json::{json, ToJson},
|
||||
window::MeasurementContext,
|
||||
DebugContext,
|
||||
SceneBuilder, View, ViewContext,
|
||||
};
|
||||
use crate::{Element, LayoutContext, PaintContext, SizeConstraint};
|
||||
use crate::{Element, SizeConstraint};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Empty {
|
||||
|
@ -27,14 +26,15 @@ impl Empty {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for Empty {
|
||||
impl<V: View> Element<V> for Empty {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
_: &mut LayoutContext,
|
||||
_: &V,
|
||||
_: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let x = if constraint.max.x().is_finite() && !self.collapsed {
|
||||
constraint.max.x()
|
||||
|
@ -52,10 +52,11 @@ impl Element for Empty {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_: &mut SceneBuilder,
|
||||
_: RectF,
|
||||
_: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
_: &mut PaintContext,
|
||||
_: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
}
|
||||
|
||||
|
@ -66,7 +67,8 @@ impl Element for Empty {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &MeasurementContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
None
|
||||
}
|
||||
|
@ -76,7 +78,8 @@ impl Element for Empty {
|
|||
bounds: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &DebugContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
json!({
|
||||
"type": "Empty",
|
||||
|
|
|
@ -2,20 +2,18 @@ use std::ops::Range;
|
|||
|
||||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json,
|
||||
window::MeasurementContext,
|
||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||
json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
pub struct Expanded {
|
||||
child: ElementBox,
|
||||
pub struct Expanded<V: View> {
|
||||
child: ElementBox<V>,
|
||||
full_width: bool,
|
||||
full_height: bool,
|
||||
}
|
||||
|
||||
impl Expanded {
|
||||
pub fn new(child: ElementBox) -> Self {
|
||||
impl<V: View> Expanded<V> {
|
||||
pub fn new(child: ElementBox<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
full_width: true,
|
||||
|
@ -36,14 +34,15 @@ impl Expanded {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for Expanded {
|
||||
impl<V: View> Element<V> for Expanded<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
mut constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
if self.full_width {
|
||||
constraint.min.set_x(constraint.max.x());
|
||||
|
@ -51,18 +50,21 @@ impl Element for Expanded {
|
|||
if self.full_height {
|
||||
constraint.min.set_y(constraint.max.y());
|
||||
}
|
||||
let size = self.child.layout(constraint, cx);
|
||||
let size = self.child.layout(constraint, view, cx);
|
||||
(size, ())
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
self.child.paint(bounds.origin(), visible_bounds, cx);
|
||||
self.child
|
||||
.paint(scene, bounds.origin(), visible_bounds, view, cx);
|
||||
}
|
||||
|
||||
fn rect_for_text_range(
|
||||
|
@ -72,9 +74,10 @@ impl Element for Expanded {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -82,13 +85,14 @@ impl Element for Expanded {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> json::Value {
|
||||
json!({
|
||||
"type": "Expanded",
|
||||
"full_width": self.full_width,
|
||||
"full_height": self.full_height,
|
||||
"child": self.child.debug(cx)
|
||||
"child": self.child.debug(view, cx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,8 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc};
|
|||
|
||||
use crate::{
|
||||
json::{self, ToJson, Value},
|
||||
window::MeasurementContext,
|
||||
Axis, DebugContext, Element, ElementBox, ElementStateHandle, LayoutContext, PaintContext,
|
||||
RenderContext, SizeConstraint, Vector2FExt, View,
|
||||
Axis, Element, ElementBox, ElementStateHandle, SceneBuilder, SizeConstraint, Vector2FExt, View,
|
||||
ViewContext,
|
||||
};
|
||||
use pathfinder_geometry::{
|
||||
rect::RectF,
|
||||
|
@ -18,14 +17,14 @@ struct ScrollState {
|
|||
scroll_position: Cell<f32>,
|
||||
}
|
||||
|
||||
pub struct Flex {
|
||||
pub struct Flex<V: View> {
|
||||
axis: Axis,
|
||||
children: Vec<ElementBox>,
|
||||
children: Vec<ElementBox<V>>,
|
||||
scroll_state: Option<(ElementStateHandle<Rc<ScrollState>>, usize)>,
|
||||
child_alignment: f32,
|
||||
}
|
||||
|
||||
impl Flex {
|
||||
impl<V: View> Flex<V> {
|
||||
pub fn new(axis: Axis) -> Self {
|
||||
Self {
|
||||
axis,
|
||||
|
@ -52,15 +51,14 @@ impl Flex {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn scrollable<Tag, V>(
|
||||
pub fn scrollable<Tag>(
|
||||
mut self,
|
||||
element_id: usize,
|
||||
scroll_to: Option<usize>,
|
||||
cx: &mut RenderContext<V>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self
|
||||
where
|
||||
Tag: 'static,
|
||||
V: View,
|
||||
{
|
||||
let scroll_state = cx.default_element_state::<Tag, Rc<ScrollState>>(element_id);
|
||||
scroll_state.read(cx).scroll_to.set(scroll_to);
|
||||
|
@ -75,7 +73,8 @@ impl Flex {
|
|||
remaining_space: &mut f32,
|
||||
remaining_flex: &mut f32,
|
||||
cross_axis_max: &mut f32,
|
||||
cx: &mut LayoutContext,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let cross_axis = self.axis.invert();
|
||||
for child in &mut self.children {
|
||||
|
@ -112,20 +111,21 @@ impl Flex {
|
|||
}
|
||||
}
|
||||
|
||||
impl Extend<ElementBox> for Flex {
|
||||
fn extend<T: IntoIterator<Item = ElementBox>>(&mut self, children: T) {
|
||||
impl<V: View> Extend<ElementBox<V>> for Flex<V> {
|
||||
fn extend<T: IntoIterator<Item = ElementBox<V>>>(&mut self, children: T) {
|
||||
self.children.extend(children);
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for Flex {
|
||||
impl<V: View> Element<V> for Flex<V> {
|
||||
type LayoutState = f32;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let mut total_flex = None;
|
||||
let mut fixed_space = 0.0;
|
||||
|
@ -150,7 +150,7 @@ impl Element for Flex {
|
|||
vec2f(constraint.max.x(), INFINITY),
|
||||
),
|
||||
};
|
||||
let size = child.layout(child_constraint, cx);
|
||||
let size = child.layout(child_constraint, view, cx);
|
||||
fixed_space += size.along(self.axis);
|
||||
cross_axis_max = cross_axis_max.max(size.along(cross_axis));
|
||||
}
|
||||
|
@ -168,6 +168,7 @@ impl Element for Flex {
|
|||
&mut remaining_space,
|
||||
&mut remaining_flex,
|
||||
&mut cross_axis_max,
|
||||
view,
|
||||
cx,
|
||||
);
|
||||
self.layout_flex_children(
|
||||
|
@ -176,6 +177,7 @@ impl Element for Flex {
|
|||
&mut remaining_space,
|
||||
&mut remaining_flex,
|
||||
&mut cross_axis_max,
|
||||
view,
|
||||
cx,
|
||||
);
|
||||
|
||||
|
@ -247,10 +249,12 @@ impl Element for Flex {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
remaining_space: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
|
||||
|
||||
|
@ -343,7 +347,7 @@ impl Element for Flex {
|
|||
aligned_child_origin
|
||||
};
|
||||
|
||||
child.paint(aligned_child_origin, visible_bounds, cx);
|
||||
child.paint(scene, aligned_child_origin, visible_bounds, view, cx);
|
||||
|
||||
match self.axis {
|
||||
Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
|
||||
|
@ -363,11 +367,12 @@ impl Element for Flex {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.children
|
||||
.iter()
|
||||
.find_map(|child| child.rect_for_text_range(range_utf16.clone(), cx))
|
||||
.find_map(|child| child.rect_for_text_range(view, range_utf16.clone(), cx))
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -375,13 +380,14 @@ impl Element for Flex {
|
|||
bounds: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> json::Value {
|
||||
json!({
|
||||
"type": "Flex",
|
||||
"bounds": bounds.to_json(),
|
||||
"axis": self.axis.to_json(),
|
||||
"children": self.children.iter().map(|child| child.debug(cx)).collect::<Vec<json::Value>>()
|
||||
"children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -391,13 +397,13 @@ struct FlexParentData {
|
|||
float: bool,
|
||||
}
|
||||
|
||||
pub struct FlexItem {
|
||||
pub struct FlexItem<V: View> {
|
||||
metadata: FlexParentData,
|
||||
child: ElementBox,
|
||||
child: ElementBox<V>,
|
||||
}
|
||||
|
||||
impl FlexItem {
|
||||
pub fn new(child: ElementBox) -> Self {
|
||||
impl<V: View> FlexItem<V> {
|
||||
pub fn new(child: ElementBox<V>) -> Self {
|
||||
FlexItem {
|
||||
metadata: FlexParentData {
|
||||
flex: None,
|
||||
|
@ -418,14 +424,15 @@ impl FlexItem {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for FlexItem {
|
||||
impl<V: View> Element<V> for FlexItem<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let size = self.child.layout(constraint, cx);
|
||||
(size, ())
|
||||
|
@ -433,12 +440,15 @@ impl Element for FlexItem {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
view: &V,
|
||||
cx: &mut PaintContext,
|
||||
) -> Self::PaintState {
|
||||
self.child.paint(bounds.origin(), visible_bounds, cx)
|
||||
self.child
|
||||
.paint(scene, bounds.origin(), visible_bounds, view, cx)
|
||||
}
|
||||
|
||||
fn rect_for_text_range(
|
||||
|
@ -448,9 +458,10 @@ impl Element for FlexItem {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Option<&dyn Any> {
|
||||
|
@ -462,12 +473,14 @@ impl Element for FlexItem {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
|
||||
cx: &ViewContext<V>,
|
||||
) -> Value {
|
||||
json!({
|
||||
"type": "Flexible",
|
||||
"flex": self.metadata.flex,
|
||||
"child": self.child.debug(cx)
|
||||
"child": self.child.debug(view, cx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,17 +3,16 @@ use std::ops::Range;
|
|||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json::json,
|
||||
window::MeasurementContext,
|
||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||
Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
|
||||
pub struct Hook {
|
||||
child: ElementBox,
|
||||
after_layout: Option<Box<dyn FnMut(Vector2F, &mut LayoutContext)>>,
|
||||
pub struct Hook<V: View> {
|
||||
child: ElementBox<V>,
|
||||
after_layout: Option<Box<dyn FnMut(Vector2F, &mut ViewContext<V>)>>,
|
||||
}
|
||||
|
||||
impl Hook {
|
||||
pub fn new(child: ElementBox) -> Self {
|
||||
impl<V: View> Hook<V> {
|
||||
pub fn new(child: ElementBox<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
after_layout: None,
|
||||
|
@ -22,23 +21,24 @@ impl Hook {
|
|||
|
||||
pub fn on_after_layout(
|
||||
mut self,
|
||||
f: impl 'static + FnMut(Vector2F, &mut LayoutContext),
|
||||
f: impl 'static + FnMut(Vector2F, &mut ViewContext<V>),
|
||||
) -> Self {
|
||||
self.after_layout = Some(Box::new(f));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for Hook {
|
||||
impl<V: View> Element<V> for Hook<V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let size = self.child.layout(constraint, cx);
|
||||
let size = self.child.layout(constraint, view, cx);
|
||||
if let Some(handler) = self.after_layout.as_mut() {
|
||||
handler(size, cx);
|
||||
}
|
||||
|
@ -47,12 +47,15 @@ impl Element for Hook {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
self.child.paint(bounds.origin(), visible_bounds, cx);
|
||||
self.child
|
||||
.paint(scene, bounds.origin(), visible_bounds, view, cx);
|
||||
}
|
||||
|
||||
fn rect_for_text_range(
|
||||
|
@ -62,9 +65,10 @@ impl Element for Hook {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -72,11 +76,12 @@ impl Element for Hook {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
json!({
|
||||
"type": "Hooks",
|
||||
"child": self.child.debug(cx),
|
||||
"child": self.child.debug(view, cx),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,7 @@ use crate::{
|
|||
vector::{vec2f, Vector2F},
|
||||
},
|
||||
json::{json, ToJson},
|
||||
scene,
|
||||
window::MeasurementContext,
|
||||
Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint,
|
||||
scene, Border, Element, ImageData, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::{ops::Range, sync::Arc};
|
||||
|
@ -57,14 +55,15 @@ impl Image {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for Image {
|
||||
impl<V: View> Element<V> for Image {
|
||||
type LayoutState = Option<Arc<ImageData>>;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let data = match &self.source {
|
||||
ImageSource::Path(path) => match cx.asset_cache.png(path) {
|
||||
|
@ -91,13 +90,15 @@ impl Element for Image {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
_: RectF,
|
||||
layout: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
_: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
if let Some(data) = layout {
|
||||
cx.scene.push_image(scene::Image {
|
||||
scene.push_image(scene::Image {
|
||||
bounds,
|
||||
border: self.style.border,
|
||||
corner_radius: self.style.corner_radius,
|
||||
|
@ -114,7 +115,8 @@ impl Element for Image {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &MeasurementContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
None
|
||||
}
|
||||
|
@ -124,7 +126,8 @@ impl Element for Image {
|
|||
bounds: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &DebugContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
json!({
|
||||
"type": "Image",
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
elements::*,
|
||||
fonts::TextStyle,
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
Action, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||
Action, ElementBox, SizeConstraint,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
|
@ -34,15 +34,16 @@ impl KeystrokeLabel {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for KeystrokeLabel {
|
||||
type LayoutState = ElementBox;
|
||||
impl<V: View> Element<V> for KeystrokeLabel {
|
||||
type LayoutState = ElementBox<V>;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
) -> (Vector2F, ElementBox) {
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, ElementBox<V>) {
|
||||
let mut element = if let Some(keystrokes) =
|
||||
cx.app
|
||||
.keystrokes_for_action(self.window_id, self.view_id, self.action.as_ref())
|
||||
|
@ -59,18 +60,20 @@ impl Element for KeystrokeLabel {
|
|||
Empty::new().collapsed().boxed()
|
||||
};
|
||||
|
||||
let size = element.layout(constraint, cx);
|
||||
let size = element.layout(constraint, view, cx);
|
||||
(size, element)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
element: &mut ElementBox,
|
||||
cx: &mut PaintContext,
|
||||
element: &mut ElementBox<V>,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
element.paint(bounds.origin(), visible_bounds, cx);
|
||||
element.paint(scene, bounds.origin(), visible_bounds, view, cx);
|
||||
}
|
||||
|
||||
fn rect_for_text_range(
|
||||
|
@ -80,7 +83,8 @@ impl Element for KeystrokeLabel {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &MeasurementContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
None
|
||||
}
|
||||
|
@ -88,14 +92,15 @@ impl Element for KeystrokeLabel {
|
|||
fn debug(
|
||||
&self,
|
||||
_: RectF,
|
||||
element: &ElementBox,
|
||||
element: &ElementBox<V>,
|
||||
_: &(),
|
||||
cx: &crate::DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
json!({
|
||||
"type": "KeystrokeLabel",
|
||||
"action": self.action.name(),
|
||||
"child": element.debug(cx)
|
||||
"child": element.debug(view, cx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@ use crate::{
|
|||
},
|
||||
json::{ToJson, Value},
|
||||
text_layout::{Line, RunStyle},
|
||||
window::MeasurementContext,
|
||||
DebugContext, Element, LayoutContext, PaintContext, SizeConstraint,
|
||||
Element, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
@ -128,14 +127,15 @@ impl Label {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for Label {
|
||||
impl<V: View> Element<V> for Label {
|
||||
type LayoutState = Line;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let runs = self.compute_runs();
|
||||
let line =
|
||||
|
@ -155,12 +155,20 @@ impl Element for Label {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
line: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
_: &V,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self::PaintState {
|
||||
line.paint(bounds.origin(), visible_bounds, bounds.size().y(), cx)
|
||||
line.paint(
|
||||
scene,
|
||||
bounds.origin(),
|
||||
visible_bounds,
|
||||
bounds.size().y(),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
fn rect_for_text_range(
|
||||
|
@ -170,7 +178,8 @@ impl Element for Label {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &MeasurementContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
None
|
||||
}
|
||||
|
@ -180,7 +189,8 @@ impl Element for Label {
|
|||
bounds: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &DebugContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> Value {
|
||||
json!({
|
||||
"type": "Label",
|
||||
|
|
|
@ -4,19 +4,17 @@ use crate::{
|
|||
vector::{vec2f, Vector2F},
|
||||
},
|
||||
json::json,
|
||||
window::MeasurementContext,
|
||||
DebugContext, Element, ElementBox, ElementRc, EventContext, LayoutContext, MouseRegion,
|
||||
PaintContext, RenderContext, SizeConstraint, View, ViewContext,
|
||||
Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc};
|
||||
use sum_tree::{Bias, SumTree};
|
||||
|
||||
pub struct List {
|
||||
state: ListState,
|
||||
pub struct List<V: View> {
|
||||
state: ListState<V>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ListState(Rc<RefCell<StateInner>>);
|
||||
pub struct ListState<V: View>(Rc<RefCell<StateInner<V>>>);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Orientation {
|
||||
|
@ -24,16 +22,16 @@ pub enum Orientation {
|
|||
Bottom,
|
||||
}
|
||||
|
||||
struct StateInner {
|
||||
struct StateInner<V: View> {
|
||||
last_layout_width: Option<f32>,
|
||||
render_item: Box<dyn FnMut(usize, &mut LayoutContext) -> Option<ElementBox>>,
|
||||
render_item: Box<dyn FnMut(usize, &V, &mut ViewContext<V>) -> Option<ElementBox<V>>>,
|
||||
rendered_range: Range<usize>,
|
||||
items: SumTree<ListItem>,
|
||||
items: SumTree<ListItem<V>>,
|
||||
logical_scroll_top: Option<ListOffset>,
|
||||
orientation: Orientation,
|
||||
overdraw: f32,
|
||||
#[allow(clippy::type_complexity)]
|
||||
scroll_handler: Option<Box<dyn FnMut(Range<usize>, &mut EventContext)>>,
|
||||
scroll_handler: Option<Box<dyn FnMut(Range<usize>, &mut V, &mut ViewContext<V>)>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
|
@ -43,13 +41,13 @@ pub struct ListOffset {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum ListItem {
|
||||
enum ListItem<V: View> {
|
||||
Unrendered,
|
||||
Rendered(ElementRc),
|
||||
Rendered(Rc<ElementBox<V>>),
|
||||
Removed(f32),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ListItem {
|
||||
impl<V: View> std::fmt::Debug for ListItem<V> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Unrendered => write!(f, "Unrendered"),
|
||||
|
@ -79,20 +77,21 @@ struct UnrenderedCount(usize);
|
|||
#[derive(Clone, Debug, Default)]
|
||||
struct Height(f32);
|
||||
|
||||
impl List {
|
||||
pub fn new(state: ListState) -> Self {
|
||||
impl<V: View> List<V> {
|
||||
pub fn new(state: ListState<V>) -> Self {
|
||||
Self { state }
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for List {
|
||||
impl<V: View> Element<V> for List<V> {
|
||||
type LayoutState = ListOffset;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let state = &mut *self.state.0.borrow_mut();
|
||||
let size = constraint.max;
|
||||
|
@ -134,6 +133,7 @@ impl Element for List {
|
|||
scroll_top.item_ix + ix,
|
||||
existing_element,
|
||||
item_constraint,
|
||||
view,
|
||||
cx,
|
||||
) {
|
||||
rendered_height += element.size().y();
|
||||
|
@ -151,7 +151,7 @@ impl Element for List {
|
|||
cursor.prev(&());
|
||||
if cursor.item().is_some() {
|
||||
if let Some(element) =
|
||||
state.render_item(cursor.start().0, None, item_constraint, cx)
|
||||
state.render_item(cursor.start().0, None, item_constraint, view, cx)
|
||||
{
|
||||
rendered_height += element.size().y();
|
||||
rendered_items.push_front(ListItem::Rendered(element));
|
||||
|
@ -187,7 +187,7 @@ impl Element for List {
|
|||
cursor.prev(&());
|
||||
if let Some(item) = cursor.item() {
|
||||
if let Some(element) =
|
||||
state.render_item(cursor.start().0, Some(item), item_constraint, cx)
|
||||
state.render_item(cursor.start().0, Some(item), item_constraint, view, cx)
|
||||
{
|
||||
leading_overdraw += element.size().y();
|
||||
rendered_items.push_front(ListItem::Rendered(element));
|
||||
|
@ -241,10 +241,12 @@ impl Element for List {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
scroll_top: &mut ListOffset,
|
||||
cx: &mut PaintContext,
|
||||
view: &V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
|
||||
cx.scene.push_layer(Some(visible_bounds));
|
||||
|
@ -268,7 +270,7 @@ impl Element for List {
|
|||
|
||||
let state = &mut *self.state.0.borrow_mut();
|
||||
for (mut element, origin) in state.visible_elements(bounds, scroll_top) {
|
||||
element.paint(origin, visible_bounds, cx);
|
||||
element.paint(scene, origin, visible_bounds, view, cx);
|
||||
}
|
||||
|
||||
cx.scene.pop_layer();
|
||||
|
@ -281,7 +283,8 @@ impl Element for List {
|
|||
_: RectF,
|
||||
scroll_top: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
let state = self.state.0.borrow();
|
||||
let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
|
||||
|
@ -293,7 +296,7 @@ impl Element for List {
|
|||
}
|
||||
|
||||
if let ListItem::Rendered(element) = item {
|
||||
if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), cx) {
|
||||
if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), view, cx) {
|
||||
return Some(rect);
|
||||
}
|
||||
|
||||
|
@ -312,12 +315,13 @@ impl Element for List {
|
|||
bounds: RectF,
|
||||
scroll_top: &Self::LayoutState,
|
||||
_: &(),
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
let state = self.state.0.borrow_mut();
|
||||
let visible_elements = state
|
||||
.visible_elements(bounds, scroll_top)
|
||||
.map(|e| e.0.debug(cx))
|
||||
.map(|e| e.0.debug(view, cx))
|
||||
.collect::<Vec<_>>();
|
||||
let visible_range = scroll_top.item_ix..(scroll_top.item_ix + visible_elements.len());
|
||||
json!({
|
||||
|
@ -328,8 +332,8 @@ impl Element for List {
|
|||
}
|
||||
}
|
||||
|
||||
impl ListState {
|
||||
pub fn new<F, V>(
|
||||
impl<V: View> ListState<V> {
|
||||
pub fn new<F>(
|
||||
element_count: usize,
|
||||
orientation: Orientation,
|
||||
overdraw: f32,
|
||||
|
@ -338,7 +342,7 @@ impl ListState {
|
|||
) -> Self
|
||||
where
|
||||
V: View,
|
||||
F: 'static + FnMut(&mut V, usize, &mut RenderContext<V>) -> ElementBox,
|
||||
F: 'static + FnMut(&mut V, usize, &mut ViewContext<V>) -> ElementBox<V>,
|
||||
{
|
||||
let mut items = SumTree::new();
|
||||
items.extend((0..element_count).map(|_| ListItem::Unrendered), &());
|
||||
|
@ -406,7 +410,7 @@ impl ListState {
|
|||
|
||||
pub fn set_scroll_handler(
|
||||
&mut self,
|
||||
handler: impl FnMut(Range<usize>, &mut EventContext) + 'static,
|
||||
handler: impl FnMut(Range<usize>, &mut V, &mut ViewContext<V>) + 'static,
|
||||
) {
|
||||
self.0.borrow_mut().scroll_handler = Some(Box::new(handler))
|
||||
}
|
||||
|
@ -426,14 +430,15 @@ impl ListState {
|
|||
}
|
||||
}
|
||||
|
||||
impl StateInner {
|
||||
impl<V: View> StateInner<V> {
|
||||
fn render_item(
|
||||
&mut self,
|
||||
ix: usize,
|
||||
existing_element: Option<&ListItem>,
|
||||
existing_element: Option<&ListItem<V>>,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
) -> Option<ElementRc> {
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Option<Rc<ElementBox<V>>> {
|
||||
if let Some(ListItem::Rendered(element)) = existing_element {
|
||||
Some(element.clone())
|
||||
} else {
|
||||
|
@ -455,7 +460,7 @@ impl StateInner {
|
|||
&'a self,
|
||||
bounds: RectF,
|
||||
scroll_top: &ListOffset,
|
||||
) -> impl Iterator<Item = (ElementRc, Vector2F)> + 'a {
|
||||
) -> impl Iterator<Item = (Rc<ElementBox>, Vector2F)> + 'a {
|
||||
let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
|
||||
let mut cursor = self.items.cursor::<Count>();
|
||||
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
|
||||
|
@ -485,7 +490,8 @@ impl StateInner {
|
|||
height: f32,
|
||||
mut delta: Vector2F,
|
||||
precise: bool,
|
||||
cx: &mut EventContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
if !precise {
|
||||
delta *= 20.;
|
||||
|
@ -538,7 +544,7 @@ impl StateInner {
|
|||
}
|
||||
}
|
||||
|
||||
impl ListItem {
|
||||
impl<V: View> ListItem<V> {
|
||||
fn remove(&self) -> Self {
|
||||
match self {
|
||||
ListItem::Unrendered => ListItem::Unrendered,
|
||||
|
@ -548,7 +554,7 @@ impl ListItem {
|
|||
}
|
||||
}
|
||||
|
||||
impl sum_tree::Item for ListItem {
|
||||
impl<V: View> sum_tree::Item for ListItem<V> {
|
||||
type Summary = ListItemSummary;
|
||||
|
||||
fn summary(&self) -> Self::Summary {
|
||||
|
@ -900,7 +906,7 @@ mod tests {
|
|||
"TestView"
|
||||
}
|
||||
|
||||
fn render(&mut self, _: &mut RenderContext<'_, Self>) -> ElementBox {
|
||||
fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
|
||||
Empty::new().boxed()
|
||||
}
|
||||
}
|
||||
|
@ -919,15 +925,28 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for TestElement {
|
||||
impl<V: View> Element<V> for TestElement {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(&mut self, _: SizeConstraint, _: &mut LayoutContext) -> (Vector2F, ()) {
|
||||
fn layout(
|
||||
&mut self,
|
||||
_: SizeConstraint,
|
||||
_: &mut V,
|
||||
_: &mut ViewContext<V>,
|
||||
) -> (Vector2F, ()) {
|
||||
(self.size, ())
|
||||
}
|
||||
|
||||
fn paint(&mut self, _: RectF, _: RectF, _: &mut (), _: &mut PaintContext) {
|
||||
fn paint(
|
||||
&mut self,
|
||||
_: &mut SceneBuilder,
|
||||
_: RectF,
|
||||
_: RectF,
|
||||
_: &mut (),
|
||||
_: &mut V,
|
||||
_: &mut ViewContext<V>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -938,12 +957,13 @@ mod tests {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
_: &MeasurementContext,
|
||||
_: &V,
|
||||
_: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn debug(&self, _: RectF, _: &(), _: &(), _: &DebugContext) -> serde_json::Value {
|
||||
fn debug(&self, _: RectF, _: &(), _: &(), _: &V, _: &ViewContext<V>) -> serde_json::Value {
|
||||
self.id.into()
|
||||
}
|
||||
|
||||
|
|
|
@ -10,14 +10,13 @@ use crate::{
|
|||
CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover,
|
||||
MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
|
||||
},
|
||||
DebugContext, Element, ElementBox, EventContext, LayoutContext, MeasurementContext,
|
||||
MouseRegion, MouseState, PaintContext, RenderContext, SizeConstraint, View,
|
||||
Element, ElementBox, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::{marker::PhantomData, ops::Range};
|
||||
|
||||
pub struct MouseEventHandler<Tag: 'static> {
|
||||
child: ElementBox,
|
||||
pub struct MouseEventHandler<Tag: 'static, V: View> {
|
||||
child: ElementBox<V>,
|
||||
region_id: usize,
|
||||
cursor_style: Option<CursorStyle>,
|
||||
handlers: HandlerSet,
|
||||
|
@ -31,14 +30,14 @@ pub struct MouseEventHandler<Tag: 'static> {
|
|||
|
||||
/// Element which provides a render_child callback with a MouseState and paints a mouse
|
||||
/// region under (or above) it for easy mouse event handling.
|
||||
impl<Tag> MouseEventHandler<Tag> {
|
||||
pub fn new<V, F>(region_id: usize, cx: &mut RenderContext<V>, render_child: F) -> Self
|
||||
impl<Tag, V: View> MouseEventHandler<Tag, V> {
|
||||
pub fn new<F>(region_id: usize, view: &mut V, cx: &mut ViewContext<V>, render_child: F) -> Self
|
||||
where
|
||||
V: View,
|
||||
F: FnOnce(&mut MouseState, &mut RenderContext<V>) -> ElementBox,
|
||||
F: FnOnce(&mut MouseState, &mut V, &mut ViewContext<V>) -> ElementBox<V>,
|
||||
{
|
||||
let mut mouse_state = cx.mouse_state::<Tag>(region_id);
|
||||
let child = render_child(&mut mouse_state, cx);
|
||||
let child = render_child(&mut mouse_state, view, cx);
|
||||
let notify_on_hover = mouse_state.accessed_hovered();
|
||||
let notify_on_click = mouse_state.accessed_clicked();
|
||||
Self {
|
||||
|
@ -58,12 +57,17 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
/// Modifies the MouseEventHandler to render the MouseRegion above the child element. Useful
|
||||
/// for drag and drop handling and similar events which should be captured before the child
|
||||
/// gets the opportunity
|
||||
pub fn above<V, F>(region_id: usize, cx: &mut RenderContext<V>, render_child: F) -> Self
|
||||
pub fn above<F>(
|
||||
region_id: usize,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
render_child: F,
|
||||
) -> Self
|
||||
where
|
||||
V: View,
|
||||
F: FnOnce(&mut MouseState, &mut RenderContext<V>) -> ElementBox,
|
||||
F: FnOnce(&mut MouseState, &mut V, &mut ViewContext<V>) -> ElementBox<V>,
|
||||
{
|
||||
let mut handler = Self::new(region_id, cx, render_child);
|
||||
let mut handler = Self::new(region_id, view, cx, render_child);
|
||||
handler.above = true;
|
||||
handler
|
||||
}
|
||||
|
@ -78,14 +82,14 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self {
|
||||
pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut ViewContext<V>) + 'static) -> Self {
|
||||
self.handlers = self.handlers.on_move(handler);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_move_out(
|
||||
mut self,
|
||||
handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static,
|
||||
handler: impl Fn(MouseMoveOut, &mut ViewContext<V>) + 'static,
|
||||
) -> Self {
|
||||
self.handlers = self.handlers.on_move_out(handler);
|
||||
self
|
||||
|
@ -94,7 +98,7 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
pub fn on_down(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(MouseDown, &mut EventContext) + 'static,
|
||||
handler: impl Fn(MouseDown, &mut ViewContext<V>) + 'static,
|
||||
) -> Self {
|
||||
self.handlers = self.handlers.on_down(button, handler);
|
||||
self
|
||||
|
@ -103,7 +107,7 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
pub fn on_up(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(MouseUp, &mut EventContext) + 'static,
|
||||
handler: impl Fn(MouseUp, &mut ViewContext<V>) + 'static,
|
||||
) -> Self {
|
||||
self.handlers = self.handlers.on_up(button, handler);
|
||||
self
|
||||
|
@ -112,7 +116,7 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
pub fn on_click(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(MouseClick, &mut EventContext) + 'static,
|
||||
handler: impl Fn(MouseClick, &mut ViewContext<V>) + 'static,
|
||||
) -> Self {
|
||||
self.handlers = self.handlers.on_click(button, handler);
|
||||
self
|
||||
|
@ -121,7 +125,7 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
pub fn on_down_out(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(MouseDownOut, &mut EventContext) + 'static,
|
||||
handler: impl Fn(MouseDownOut, &mut ViewContext<V>) + 'static,
|
||||
) -> Self {
|
||||
self.handlers = self.handlers.on_down_out(button, handler);
|
||||
self
|
||||
|
@ -130,7 +134,7 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
pub fn on_up_out(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(MouseUpOut, &mut EventContext) + 'static,
|
||||
handler: impl Fn(MouseUpOut, &mut ViewContext<V>) + 'static,
|
||||
) -> Self {
|
||||
self.handlers = self.handlers.on_up_out(button, handler);
|
||||
self
|
||||
|
@ -139,20 +143,20 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
pub fn on_drag(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(MouseDrag, &mut EventContext) + 'static,
|
||||
handler: impl Fn(MouseDrag, &mut ViewContext<V>) + 'static,
|
||||
) -> Self {
|
||||
self.handlers = self.handlers.on_drag(button, handler);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self {
|
||||
pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut ViewContext<V>) + 'static) -> Self {
|
||||
self.handlers = self.handlers.on_hover(handler);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_scroll(
|
||||
mut self,
|
||||
handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static,
|
||||
handler: impl Fn(MouseScrollWheel, &mut ViewContext<V>) + 'static,
|
||||
) -> Self {
|
||||
self.handlers = self.handlers.on_scroll(handler);
|
||||
self
|
||||
|
@ -176,7 +180,13 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
.round_out()
|
||||
}
|
||||
|
||||
fn paint_regions(&self, bounds: RectF, visible_bounds: RectF, cx: &mut PaintContext) {
|
||||
fn paint_regions(
|
||||
&self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
|
||||
let hit_bounds = self.hit_bounds(visible_bounds);
|
||||
|
||||
|
@ -200,34 +210,37 @@ impl<Tag> MouseEventHandler<Tag> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Tag> Element for MouseEventHandler<Tag> {
|
||||
impl<Tag, V: View> Element<V> for MouseEventHandler<Tag, V> {
|
||||
type LayoutState = ();
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
(self.child.layout(constraint, cx), ())
|
||||
(self.child.layout(constraint, view, cx), ())
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
_: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
if self.above {
|
||||
self.child.paint(bounds.origin(), visible_bounds, cx);
|
||||
self.child.paint(bounds.origin(), visible_bounds, view, cx);
|
||||
|
||||
cx.paint_layer(None, |cx| {
|
||||
self.paint_regions(bounds, visible_bounds, cx);
|
||||
});
|
||||
} else {
|
||||
self.paint_regions(bounds, visible_bounds, cx);
|
||||
self.child.paint(bounds.origin(), visible_bounds, cx);
|
||||
self.child.paint(bounds.origin(), visible_bounds, view, cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,9 +251,10 @@ impl<Tag> Element for MouseEventHandler<Tag> {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<Self>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -248,11 +262,12 @@ impl<Tag> Element for MouseEventHandler<Tag> {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
json!({
|
||||
"type": "MouseEventHandler",
|
||||
"child": self.child.debug(cx),
|
||||
"child": self.child.debug(view, cx),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,12 @@ use std::ops::Range;
|
|||
use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json::ToJson,
|
||||
window::MeasurementContext,
|
||||
Axis, DebugContext, Element, ElementBox, LayoutContext, MouseRegion, PaintContext,
|
||||
SizeConstraint,
|
||||
Axis, Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
pub struct Overlay {
|
||||
child: ElementBox,
|
||||
pub struct Overlay<V: View> {
|
||||
child: ElementBox<V>,
|
||||
anchor_position: Option<Vector2F>,
|
||||
anchor_corner: AnchorCorner,
|
||||
fit_mode: OverlayFitMode,
|
||||
|
@ -74,8 +72,8 @@ impl AnchorCorner {
|
|||
}
|
||||
}
|
||||
|
||||
impl Overlay {
|
||||
pub fn new(child: ElementBox) -> Self {
|
||||
impl<V: View> Overlay<V> {
|
||||
pub fn new(child: ElementBox<V>) -> Self {
|
||||
Self {
|
||||
child,
|
||||
anchor_position: None,
|
||||
|
@ -118,14 +116,15 @@ impl Overlay {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for Overlay {
|
||||
impl<V: View> Element<V> for Overlay<V> {
|
||||
type LayoutState = Vector2F;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
let constraint = if self.anchor_position.is_some() {
|
||||
SizeConstraint::new(Vector2F::zero(), cx.window_size)
|
||||
|
@ -138,10 +137,12 @@ impl Element for Overlay {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: SceneBuilder,
|
||||
bounds: RectF,
|
||||
_: RectF,
|
||||
size: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let (anchor_position, mut bounds) = match self.position_mode {
|
||||
OverlayPositionMode::Window => {
|
||||
|
@ -224,8 +225,10 @@ impl Element for Overlay {
|
|||
}
|
||||
|
||||
self.child.paint(
|
||||
scene,
|
||||
bounds.origin(),
|
||||
RectF::new(Vector2F::zero(), cx.window_size),
|
||||
view,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
@ -238,9 +241,10 @@ impl Element for Overlay {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
self.child.rect_for_text_range(range_utf16, cx)
|
||||
self.child.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -248,12 +252,13 @@ impl Element for Overlay {
|
|||
_: RectF,
|
||||
_: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
json!({
|
||||
"type": "Overlay",
|
||||
"abs_position": self.anchor_position.to_json(),
|
||||
"child": self.child.debug(cx),
|
||||
"child": self.child.debug(view, cx),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{Element, EventContext, LayoutContext, PaintContext, SizeConstraint};
|
||||
use super::{Element, SizeConstraint};
|
||||
use crate::{
|
||||
geometry::{
|
||||
rect::RectF,
|
||||
|
@ -7,8 +7,7 @@ use crate::{
|
|||
json::{self, json},
|
||||
platform::ScrollWheelEvent,
|
||||
scene::MouseScrollWheel,
|
||||
window::MeasurementContext,
|
||||
ElementBox, MouseRegion, RenderContext, View,
|
||||
ElementBox, MouseRegion, SceneBuilder, View, ViewContext,
|
||||
};
|
||||
use json::ToJson;
|
||||
use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
|
||||
|
@ -38,33 +37,33 @@ struct StateInner {
|
|||
scroll_to: Option<ScrollTarget>,
|
||||
}
|
||||
|
||||
pub struct LayoutState {
|
||||
pub struct LayoutState<V: View> {
|
||||
scroll_max: f32,
|
||||
item_height: f32,
|
||||
items: Vec<ElementBox>,
|
||||
items: Vec<ElementBox<V>>,
|
||||
}
|
||||
|
||||
pub struct UniformList {
|
||||
pub struct UniformList<V: View> {
|
||||
state: UniformListState,
|
||||
item_count: usize,
|
||||
#[allow(clippy::type_complexity)]
|
||||
append_items: Box<dyn Fn(Range<usize>, &mut Vec<ElementBox>, &mut LayoutContext)>,
|
||||
append_items: Box<dyn Fn(Range<usize>, &mut Vec<ElementBox<V>>, &mut V, &mut ViewContext<V>)>,
|
||||
padding_top: f32,
|
||||
padding_bottom: f32,
|
||||
get_width_from_item: Option<usize>,
|
||||
view_id: usize,
|
||||
}
|
||||
|
||||
impl UniformList {
|
||||
pub fn new<F, V>(
|
||||
impl<V: View> UniformList<V> {
|
||||
pub fn new<F>(
|
||||
state: UniformListState,
|
||||
item_count: usize,
|
||||
cx: &mut RenderContext<V>,
|
||||
cx: &mut ViewContext<V>,
|
||||
append_items: F,
|
||||
) -> Self
|
||||
where
|
||||
V: View,
|
||||
F: 'static + Fn(&mut V, Range<usize>, &mut Vec<ElementBox>, &mut RenderContext<V>),
|
||||
F: 'static + Fn(&mut V, Range<usize>, &mut Vec<ElementBox<V>>, &mut V, &mut ViewContext<V>),
|
||||
{
|
||||
let handle = cx.handle();
|
||||
Self {
|
||||
|
@ -160,14 +159,15 @@ impl UniformList {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element for UniformList {
|
||||
type LayoutState = LayoutState;
|
||||
impl<V: View> Element<V> for UniformList<V> {
|
||||
type LayoutState = LayoutState<V>;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
cx: &mut LayoutContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> (Vector2F, Self::LayoutState) {
|
||||
if constraint.max.y().is_infinite() {
|
||||
unimplemented!(
|
||||
|
@ -262,7 +262,7 @@ impl Element for UniformList {
|
|||
}
|
||||
|
||||
for item in &mut items {
|
||||
let item_size = item.layout(item_constraint, cx);
|
||||
let item_size = item.layout(item_constraint, view, cx);
|
||||
if item_size.x() > size.x() {
|
||||
size.set_x(item_size.x());
|
||||
}
|
||||
|
@ -280,10 +280,12 @@ impl Element for UniformList {
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
layout: &mut Self::LayoutState,
|
||||
cx: &mut PaintContext,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
|
||||
|
||||
|
@ -322,7 +324,7 @@ impl Element for UniformList {
|
|||
);
|
||||
|
||||
for item in &mut layout.items {
|
||||
item.paint(item_origin, visible_bounds, cx);
|
||||
item.paint(scene, item_origin, visible_bounds, view, cx);
|
||||
item_origin += vec2f(0.0, layout.item_height);
|
||||
}
|
||||
|
||||
|
@ -336,12 +338,13 @@ impl Element for UniformList {
|
|||
_: RectF,
|
||||
layout: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &MeasurementContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
layout
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|child| child.rect_for_text_range(range.clone(), cx))
|
||||
.find_map(|child| child.rect_for_text_range(range.clone(), view, cx))
|
||||
}
|
||||
|
||||
fn debug(
|
||||
|
@ -349,14 +352,15 @@ impl Element for UniformList {
|
|||
bounds: RectF,
|
||||
layout: &Self::LayoutState,
|
||||
_: &Self::PaintState,
|
||||
cx: &crate::DebugContext,
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> json::Value {
|
||||
json!({
|
||||
"type": "UniformList",
|
||||
"bounds": bounds.to_json(),
|
||||
"scroll_max": layout.scroll_max,
|
||||
"item_height": layout.item_height,
|
||||
"items": layout.items.iter().map(|item| item.debug(cx)).collect::<Vec<json::Value>>()
|
||||
"items": layout.items.iter().map(|item| item.debug(view, cx)).collect::<Vec<json::Value>>()
|
||||
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue