I want to use this on another branch, but it's a sweeping change, so this prepares the ground for it. This can always be reverted if it doesn't work out.
119 lines
2.8 KiB
Rust
119 lines
2.8 KiB
Rust
use crate::{
|
|
geometry::{rect::RectF, vector::Vector2F},
|
|
json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
|
|
ViewContext,
|
|
};
|
|
use json::ToJson;
|
|
|
|
use serde_json::json;
|
|
|
|
pub struct Align<V: View> {
|
|
child: AnyElement<V>,
|
|
alignment: Vector2F,
|
|
}
|
|
|
|
impl<V: View> Align<V> {
|
|
pub fn new(child: AnyElement<V>) -> Self {
|
|
Self {
|
|
child,
|
|
alignment: Vector2F::zero(),
|
|
}
|
|
}
|
|
|
|
pub fn top(mut self) -> Self {
|
|
self.alignment.set_y(-1.0);
|
|
self
|
|
}
|
|
|
|
pub fn bottom(mut self) -> Self {
|
|
self.alignment.set_y(1.0);
|
|
self
|
|
}
|
|
|
|
pub fn left(mut self) -> Self {
|
|
self.alignment.set_x(-1.0);
|
|
self
|
|
}
|
|
|
|
pub fn right(mut self) -> Self {
|
|
self.alignment.set_x(1.0);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<V: View> Element<V> for Align<V> {
|
|
type LayoutState = ();
|
|
type PaintState = ();
|
|
|
|
fn layout(
|
|
&mut self,
|
|
mut constraint: SizeConstraint,
|
|
view: &mut V,
|
|
cx: &mut LayoutContext<V>,
|
|
) -> (Vector2F, Self::LayoutState) {
|
|
let mut size = constraint.max;
|
|
constraint.min = Vector2F::zero();
|
|
let child_size = self.child.layout(constraint, view, cx);
|
|
if size.x().is_infinite() {
|
|
size.set_x(child_size.x());
|
|
}
|
|
if size.y().is_infinite() {
|
|
size.set_y(child_size.y());
|
|
}
|
|
(size, ())
|
|
}
|
|
|
|
fn paint(
|
|
&mut self,
|
|
scene: &mut SceneBuilder,
|
|
bounds: RectF,
|
|
visible_bounds: RectF,
|
|
_: &mut Self::LayoutState,
|
|
view: &mut V,
|
|
cx: &mut PaintContext<V>,
|
|
) -> Self::PaintState {
|
|
let my_center = bounds.size() / 2.;
|
|
let my_target = my_center + my_center * self.alignment;
|
|
|
|
let child_center = self.child.size() / 2.;
|
|
let child_target = child_center + child_center * self.alignment;
|
|
|
|
self.child.paint(
|
|
scene,
|
|
bounds.origin() - (child_target - my_target),
|
|
visible_bounds,
|
|
view,
|
|
cx,
|
|
);
|
|
}
|
|
|
|
fn rect_for_text_range(
|
|
&self,
|
|
range_utf16: std::ops::Range<usize>,
|
|
_: RectF,
|
|
_: RectF,
|
|
_: &Self::LayoutState,
|
|
_: &Self::PaintState,
|
|
view: &V,
|
|
cx: &ViewContext<V>,
|
|
) -> Option<RectF> {
|
|
self.child.rect_for_text_range(range_utf16, view, cx)
|
|
}
|
|
|
|
fn debug(
|
|
&self,
|
|
bounds: pathfinder_geometry::rect::RectF,
|
|
_: &Self::LayoutState,
|
|
_: &Self::PaintState,
|
|
view: &V,
|
|
cx: &ViewContext<V>,
|
|
) -> json::Value {
|
|
json!({
|
|
"type": "Align",
|
|
"bounds": bounds.to_json(),
|
|
"alignment": self.alignment.to_json(),
|
|
"child": self.child.debug(view, cx),
|
|
})
|
|
}
|
|
}
|