Checkpoint

This commit is contained in:
Nathan Sobo
2023-09-19 21:55:49 -06:00
parent 37d0f06e07
commit 7885eaf974
13 changed files with 909 additions and 32 deletions
+11 -1
View File
@@ -1,3 +1,5 @@
use smallvec::SmallVec;
use super::{Handle, Layout, LayoutId, Pixels, Point, Result, ViewContext, WindowContext};
use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
@@ -21,7 +23,15 @@ pub trait Element: 'static {
}
pub trait ParentElement<S> {
fn child(self, child: impl IntoAnyElement<S>) -> Self;
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]>;
fn child(mut self, child: impl IntoAnyElement<S>) -> Self
where
Self: Sized,
{
self.children_mut().push(child.into_any());
self
}
}
trait ElementObject<S> {
-1
View File
@@ -2,7 +2,6 @@ pub mod div;
pub mod editor;
use super::*;
use std::marker::PhantomData;
pub use div::div;
pub use editor::field;
+274 -17
View File
@@ -1,38 +1,295 @@
use super::{
Element, IntoAnyElement, Layout, LayoutId, ParentElement, PhantomData, Result, ViewContext,
use crate::{
AnyElement, Bounds, Element, Layout, LayoutId, Overflow, ParentElement, Pixels, Point,
Refineable, RefinementCascade, Result, Style, Styled, ViewContext,
};
use smallvec::SmallVec;
use std::{cell::Cell, rc::Rc};
use util::ResultExt;
pub struct Div<S>(PhantomData<S>);
pub struct Div<S: 'static> {
styles: RefinementCascade<Style>,
// handlers: InteractionHandlers<V>,
children: SmallVec<[AnyElement<S>; 2]>,
scroll_state: Option<ScrollState>,
}
pub fn div<S>() -> Div<S> {
Div {
styles: Default::default(),
// handlers: Default::default(),
children: Default::default(),
scroll_state: None,
}
}
impl<S: 'static> Element for Div<S> {
type State = S;
type FrameState = ();
type FrameState = Vec<LayoutId>;
fn layout(
&mut self,
_state: &mut Self::State,
_cx: &mut ViewContext<Self::State>,
view: &mut S,
cx: &mut ViewContext<S>,
) -> Result<(LayoutId, Self::FrameState)> {
todo!()
let style = self.computed_style();
let pop_text_style = style
.text_style(cx)
.map(|style| cx.push_text_style(style))
.is_some();
let children = self
.children
.iter_mut()
.map(|child| child.layout(view, cx))
.collect::<Result<Vec<LayoutId>>>()?;
if pop_text_style {
cx.pop_text_style();
}
Ok((cx.request_layout(style, children.clone())?, children))
}
fn paint(
&mut self,
_layout: Layout,
_state: &mut Self::State,
_frame_state: &mut Self::FrameState,
_cx: &mut ViewContext<Self::State>,
layout: Layout,
state: &mut S,
child_layouts: &mut Self::FrameState,
cx: &mut ViewContext<S>,
) -> Result<()> {
todo!()
let Layout { order, bounds } = layout;
let style = self.computed_style();
let pop_text_style = style
.text_style(cx)
.map(|style| cx.push_text_style(style))
.is_some();
style.paint_background(bounds, cx);
// self.interaction_handlers().paint(order, bounds, cx);
let scrolled_origin = bounds.origin - self.scroll_offset(&style.overflow);
// // TODO: Support only one dimension being hidden
// let mut pop_layer = false;
// if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible {
// cx.scene().push_layer(Some(bounds));
// pop_layer = true;
// }
for child in &mut self.children {
child.paint(scrolled_origin, state, cx);
}
// if pop_layer {
// cx.scene().pop_layer();
// }
style.paint_foreground(bounds, cx);
if pop_text_style {
cx.pop_text_style();
}
self.handle_scroll(order, bounds, style.overflow.clone(), child_layouts, cx);
// if cx.is_inspector_enabled() {
// self.paint_inspector(parent_origin, layout, cx);
// }
//
Ok(())
}
}
impl<S> ParentElement<S> for Div<S> {
fn child(self, _child: impl IntoAnyElement<S>) -> Self {
todo!()
impl<V: 'static> Div<V> {
pub fn overflow_hidden(mut self) -> Self {
self.declared_style().overflow.x = Some(Overflow::Hidden);
self.declared_style().overflow.y = Some(Overflow::Hidden);
self
}
pub fn overflow_hidden_x(mut self) -> Self {
self.declared_style().overflow.x = Some(Overflow::Hidden);
self
}
pub fn overflow_hidden_y(mut self) -> Self {
self.declared_style().overflow.y = Some(Overflow::Hidden);
self
}
pub fn overflow_scroll(mut self, scroll_state: ScrollState) -> Self {
self.scroll_state = Some(scroll_state);
self.declared_style().overflow.x = Some(Overflow::Scroll);
self.declared_style().overflow.y = Some(Overflow::Scroll);
self
}
pub fn overflow_x_scroll(mut self, scroll_state: ScrollState) -> Self {
self.scroll_state = Some(scroll_state);
self.declared_style().overflow.x = Some(Overflow::Scroll);
self
}
pub fn overflow_y_scroll(mut self, scroll_state: ScrollState) -> Self {
self.scroll_state = Some(scroll_state);
self.declared_style().overflow.y = Some(Overflow::Scroll);
self
}
fn scroll_offset(&self, overflow: &Point<Overflow>) -> Point<Pixels> {
let mut offset = Point::default();
if overflow.y == Overflow::Scroll {
offset.y = self.scroll_state.as_ref().unwrap().y();
}
if overflow.x == Overflow::Scroll {
offset.x = self.scroll_state.as_ref().unwrap().x();
}
offset
}
fn handle_scroll(
&mut self,
order: u32,
bounds: Bounds<Pixels>,
overflow: Point<Overflow>,
child_layout_ids: &[LayoutId],
cx: &mut ViewContext<V>,
) {
if overflow.y == Overflow::Scroll || overflow.x == Overflow::Scroll {
let mut scroll_max = Point::default();
for child_layout_id in child_layout_ids {
if let Some(child_layout) = cx.layout(*child_layout_id).log_err() {
scroll_max = scroll_max.max(&child_layout.bounds.lower_right());
}
}
scroll_max -= bounds.size;
// let scroll_state = self.scroll_state.as_ref().unwrap().clone();
// cx.on_event(order, move |_, event: &ScrollWheelEvent, cx| {
// if bounds.contains_point(event.position) {
// let scroll_delta = match event.delta {
// ScrollDelta::Pixels(delta) => delta,
// ScrollDelta::Lines(delta) => cx.text_style().font_size * delta,
// };
// if overflow.x == Overflow::Scroll {
// scroll_state.set_x(
// (scroll_state.x() - scroll_delta.x())
// .max(px(0.))
// .min(scroll_max.x),
// );
// }
// if overflow.y == Overflow::Scroll {
// scroll_state.set_y(
// (scroll_state.y() - scroll_delta.y())
// .max(px(0.))
// .min(scroll_max.y),
// );
// }
// cx.repaint();
// } else {
// cx.bubble_event();
// }
// })
}
}
fn paint_inspector(
&self,
parent_origin: Point<Pixels>,
layout: &Layout,
cx: &mut ViewContext<V>,
) {
let style = self.styles.merged();
let bounds = layout.bounds;
let hovered = bounds.contains_point(cx.mouse_position());
if hovered {
let rem_size = cx.rem_size();
// cx.scene().push_quad(scene::Quad {
// bounds,
// background: Some(hsla(0., 0., 1., 0.05).into()),
// border: gpui::Border {
// color: hsla(0., 0., 1., 0.2).into(),
// top: 1.,
// right: 1.,
// bottom: 1.,
// left: 1.,
// },
// corner_radii: CornerRadii::default()
// .refined(&style.corner_radii)
// .to_gpui(bounds.size(), rem_size),
// })
}
// let pressed = Cell::new(hovered && cx.is_mouse_down(MouseButton::Left));
// cx.on_event(layout.order, move |_, event: &MouseButtonEvent, _| {
// if bounds.contains_point(event.position) {
// if event.is_down {
// pressed.set(true);
// } else if pressed.get() {
// pressed.set(false);
// eprintln!("clicked div {:?} {:#?}", bounds, style);
// }
// }
// });
// let hovered = Cell::new(hovered);
// cx.on_event(layout.order, move |_, event: &MouseMovedEvent, cx| {
// cx.bubble_event();
// let hovered_now = bounds.contains_point(event.position);
// if hovered.get() != hovered_now {
// hovered.set(hovered_now);
// cx.repaint();
// }
// });
}
}
pub fn div<S>() -> Div<S> {
todo!()
impl<V> Styled for Div<V> {
type Style = Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
&mut self.styles
}
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
self.styles.base()
}
}
// impl<V> Interactive<V> for Div<V> {
// fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
// &mut self.handlers
// }
// }
impl<V: 'static> ParentElement<V> for Div<V> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
&mut self.children
}
}
#[derive(Default, Clone)]
pub struct ScrollState(Rc<Cell<Point<Pixels>>>);
impl ScrollState {
pub fn x(&self) -> Pixels {
self.0.get().x
}
pub fn set_x(&self, value: Pixels) {
let mut current_value = self.0.get();
current_value.x = value;
self.0.set(current_value);
}
pub fn y(&self) -> Pixels {
self.0.get().y
}
pub fn set_y(&self, value: Pixels) {
let mut current_value = self.0.get();
current_value.y = value;
self.0.set(current_value);
}
}
+105
View File
@@ -0,0 +1,105 @@
use crate::{
element::{AnyElement, Element, IntoElement, Layout, ParentElement},
interactive::{InteractionHandlers, Interactive},
style::{Style, StyleHelpers, Styleable},
ViewContext,
};
use anyhow::Result;
use gpui::{geometry::vector::Vector2F, platform::MouseMovedEvent, LayoutId};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use smallvec::SmallVec;
use std::{cell::Cell, rc::Rc};
pub struct Hoverable<E: Styleable> {
hovered: Rc<Cell<bool>>,
cascade_slot: CascadeSlot,
hovered_style: <E::Style as Refineable>::Refinement,
child: E,
}
pub fn hoverable<E: Styleable>(mut child: E) -> Hoverable<E> {
Hoverable {
hovered: Rc::new(Cell::new(false)),
cascade_slot: child.style_cascade().reserve(),
hovered_style: Default::default(),
child,
}
}
impl<E: Styleable> Styleable for Hoverable<E> {
type Style = E::Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
self.child.style_cascade()
}
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
&mut self.hovered_style
}
}
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
type PaintState = E::PaintState;
fn layout(
&mut self,
view: &mut V,
cx: &mut ViewContext<V>,
) -> Result<(LayoutId, Self::PaintState)>
where
Self: Sized,
{
Ok(self.child.layout(view, cx)?)
}
fn paint(
&mut self,
view: &mut V,
parent_origin: Vector2F,
layout: &Layout,
paint_state: &mut Self::PaintState,
cx: &mut ViewContext<V>,
) where
Self: Sized,
{
let bounds = layout.bounds + parent_origin;
self.hovered.set(bounds.contains_point(cx.mouse_position()));
let slot = self.cascade_slot;
let style = self.hovered.get().then_some(self.hovered_style.clone());
self.style_cascade().set(slot, style);
let hovered = self.hovered.clone();
cx.on_event(layout.order, move |_view, _: &MouseMovedEvent, cx| {
cx.bubble_event();
if bounds.contains_point(cx.mouse_position()) != hovered.get() {
cx.repaint();
}
});
self.child
.paint(view, parent_origin, layout, paint_state, cx);
}
}
impl<E: Styleable<Style = Style>> StyleHelpers for Hoverable<E> {}
impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Hoverable<E> {
fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
self.child.interaction_handlers()
}
}
impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Hoverable<E> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
self.child.children_mut()
}
}
impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Hoverable<E> {
type Element = Self;
fn into_element(self) -> Self::Element {
self
}
}
+110
View File
@@ -0,0 +1,110 @@
use crate as gpui2;
use crate::{
style::{Style, StyleHelpers, Styleable},
Element,
};
use futures::FutureExt;
use gpui::geometry::vector::Vector2F;
use gpui::scene;
use gpui2_macros::IntoElement;
use refineable::RefinementCascade;
use util::arc_cow::ArcCow;
use util::ResultExt;
#[derive(IntoElement)]
pub struct Img {
style: RefinementCascade<Style>,
uri: Option<ArcCow<'static, str>>,
}
pub fn img() -> Img {
Img {
style: RefinementCascade::default(),
uri: None,
}
}
impl Img {
pub fn uri(mut self, uri: impl Into<ArcCow<'static, str>>) -> Self {
self.uri = Some(uri.into());
self
}
}
impl<V: 'static> Element<V> for Img {
type PaintState = ();
fn layout(
&mut self,
_: &mut V,
cx: &mut crate::ViewContext<V>,
) -> anyhow::Result<(gpui::LayoutId, Self::PaintState)>
where
Self: Sized,
{
let style = self.computed_style();
let layout_id = cx.add_layout_node(style, [])?;
Ok((layout_id, ()))
}
fn paint(
&mut self,
_: &mut V,
parent_origin: Vector2F,
layout: &gpui::Layout,
_: &mut Self::PaintState,
cx: &mut crate::ViewContext<V>,
) where
Self: Sized,
{
let style = self.computed_style();
let bounds = layout.bounds + parent_origin;
style.paint_background(bounds, cx);
if let Some(uri) = &self.uri {
let image_future = cx.image_cache.get(uri.clone());
if let Some(data) = image_future
.clone()
.now_or_never()
.and_then(ResultExt::log_err)
{
let rem_size = cx.rem_size();
cx.scene().push_image(scene::Image {
bounds,
border: gpui::Border {
color: style.border_color.unwrap_or_default().into(),
top: style.border_widths.top.to_pixels(rem_size),
right: style.border_widths.right.to_pixels(rem_size),
bottom: style.border_widths.bottom.to_pixels(rem_size),
left: style.border_widths.left.to_pixels(rem_size),
},
corner_radii: style.corner_radii.to_gpui(bounds.size(), rem_size),
grayscale: false,
data,
})
} else {
cx.spawn(|this, mut cx| async move {
if image_future.await.log_err().is_some() {
this.update(&mut cx, |_, cx| cx.notify()).ok();
}
})
.detach();
}
}
}
}
impl Styleable for Img {
type Style = Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
&mut self.style
}
fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
self.style.base()
}
}
impl StyleHelpers for Img {}
+108
View File
@@ -0,0 +1,108 @@
use crate::{
element::{AnyElement, Element, IntoElement, Layout, ParentElement},
interactive::{InteractionHandlers, Interactive},
style::{Style, StyleHelpers, Styleable},
ViewContext,
};
use anyhow::Result;
use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use smallvec::SmallVec;
use std::{cell::Cell, rc::Rc};
pub struct Pressable<E: Styleable> {
pressed: Rc<Cell<bool>>,
pressed_style: <E::Style as Refineable>::Refinement,
cascade_slot: CascadeSlot,
child: E,
}
pub fn pressable<E: Styleable>(mut child: E) -> Pressable<E> {
Pressable {
pressed: Rc::new(Cell::new(false)),
pressed_style: Default::default(),
cascade_slot: child.style_cascade().reserve(),
child,
}
}
impl<E: Styleable> Styleable for Pressable<E> {
type Style = E::Style;
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
&mut self.pressed_style
}
fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
self.child.style_cascade()
}
}
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
type PaintState = E::PaintState;
fn layout(
&mut self,
view: &mut V,
cx: &mut ViewContext<V>,
) -> Result<(LayoutId, Self::PaintState)>
where
Self: Sized,
{
self.child.layout(view, cx)
}
fn paint(
&mut self,
view: &mut V,
parent_origin: Vector2F,
layout: &Layout,
paint_state: &mut Self::PaintState,
cx: &mut ViewContext<V>,
) where
Self: Sized,
{
let slot = self.cascade_slot;
let style = self.pressed.get().then_some(self.pressed_style.clone());
self.style_cascade().set(slot, style);
let pressed = self.pressed.clone();
let bounds = layout.bounds + parent_origin;
cx.on_event(layout.order, move |_view, event: &MouseButtonEvent, cx| {
if event.is_down {
if bounds.contains_point(event.position) {
pressed.set(true);
cx.repaint();
}
} else if pressed.get() {
pressed.set(false);
cx.repaint();
}
});
self.child
.paint(view, parent_origin, layout, paint_state, cx);
}
}
impl<E: Styleable<Style = Style>> StyleHelpers for Pressable<E> {}
impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
self.child.interaction_handlers()
}
}
impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Pressable<E> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
self.child.children_mut()
}
}
impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
type Element = Self;
fn into_element(self) -> Self::Element {
self
}
}
+84
View File
@@ -0,0 +1,84 @@
use crate::{
self as gpui2, scene,
style::{Style, StyleHelpers, Styleable},
Element, IntoElement, Layout, LayoutId, Rgba,
};
use gpui::geometry::vector::Vector2F;
use refineable::RefinementCascade;
use std::borrow::Cow;
use util::ResultExt;
#[derive(IntoElement)]
pub struct Svg {
path: Option<Cow<'static, str>>,
style: RefinementCascade<Style>,
}
pub fn svg() -> Svg {
Svg {
path: None,
style: RefinementCascade::<Style>::default(),
}
}
impl Svg {
pub fn path(mut self, path: impl Into<Cow<'static, str>>) -> Self {
self.path = Some(path.into());
self
}
}
impl<V: 'static> Element<V> for Svg {
type PaintState = ();
fn layout(
&mut self,
_: &mut V,
cx: &mut crate::ViewContext<V>,
) -> anyhow::Result<(LayoutId, Self::PaintState)>
where
Self: Sized,
{
let style = self.computed_style();
Ok((cx.add_layout_node(style, [])?, ()))
}
fn paint(
&mut self,
_: &mut V,
parent_origin: Vector2F,
layout: &Layout,
_: &mut Self::PaintState,
cx: &mut crate::ViewContext<V>,
) where
Self: Sized,
{
let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
if let Some(svg_tree) = cx.asset_cache.svg(path).log_err() {
let icon = scene::Icon {
bounds: layout.bounds + parent_origin,
svg: svg_tree,
path: path.clone(),
color: Rgba::from(fill_color).into(),
};
cx.scene().push_icon(icon);
}
}
}
}
impl Styleable for Svg {
type Style = Style;
fn style_cascade(&mut self) -> &mut refineable::RefinementCascade<Self::Style> {
&mut self.style
}
fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
self.style.base()
}
}
impl StyleHelpers for Svg {}
+119
View File
@@ -0,0 +1,119 @@
use crate::{
element::{Element, IntoElement, Layout},
ViewContext,
};
use anyhow::Result;
use gpui::{
geometry::{vector::Vector2F, Size},
text_layout::LineLayout,
LayoutId,
};
use parking_lot::Mutex;
use std::sync::Arc;
use util::arc_cow::ArcCow;
impl<V: 'static> IntoElement<V> for ArcCow<'static, str> {
type Element = Text;
fn into_element(self) -> Self::Element {
Text { text: self }
}
}
impl<V: 'static> IntoElement<V> for &'static str {
type Element = Text;
fn into_element(self) -> Self::Element {
Text {
text: ArcCow::from(self),
}
}
}
pub struct Text {
text: ArcCow<'static, str>,
}
impl<V: 'static> Element<V> for Text {
type PaintState = Arc<Mutex<Option<TextLayout>>>;
fn layout(
&mut self,
_view: &mut V,
cx: &mut ViewContext<V>,
) -> Result<(LayoutId, Self::PaintState)> {
let fonts = cx.platform().fonts();
let text_style = cx.text_style();
let line_height = cx.font_cache().line_height(text_style.font_size);
let text = self.text.clone();
let paint_state = Arc::new(Mutex::new(None));
let layout_id = cx.add_measured_layout_node(Default::default(), {
let paint_state = paint_state.clone();
move |_params| {
let line_layout = fonts.layout_line(
text.as_ref(),
text_style.font_size,
&[(text.len(), text_style.to_run())],
);
let size = Size {
width: line_layout.width,
height: line_height,
};
paint_state.lock().replace(TextLayout {
line_layout: Arc::new(line_layout),
line_height,
});
size
}
});
Ok((layout_id?, paint_state))
}
fn paint<'a>(
&mut self,
_view: &mut V,
parent_origin: Vector2F,
layout: &Layout,
paint_state: &mut Self::PaintState,
cx: &mut ViewContext<V>,
) {
let bounds = layout.bounds + parent_origin;
let line_layout;
let line_height;
{
let paint_state = paint_state.lock();
let paint_state = paint_state
.as_ref()
.expect("measurement has not been performed");
line_layout = paint_state.line_layout.clone();
line_height = paint_state.line_height;
}
let text_style = cx.text_style();
let line =
gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]);
// TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
let visible_bounds = bounds;
line.paint(bounds.origin(), visible_bounds, line_height, cx.legacy_cx);
}
}
impl<V: 'static> IntoElement<V> for Text {
type Element = Self;
fn into_element(self) -> Self::Element {
self
}
}
pub struct TextLayout {
line_layout: Arc<LineLayout>,
line_height: f32,
}
+53 -11
View File
@@ -2,9 +2,11 @@ use bytemuck::{Pod, Zeroable};
use core::fmt::Debug;
use derive_more::{Add, AddAssign, Div, Mul, Sub, SubAssign};
use refineable::Refineable;
use std::ops::{Add, Mul};
use std::ops::{Add, Mul, Sub, SubAssign};
#[derive(Refineable, Default, Add, AddAssign, Sub, Mul, Div, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(
Refineable, Default, Add, AddAssign, Sub, SubAssign, Mul, Div, Copy, Debug, PartialEq, Eq, Hash,
)]
#[refineable(debug)]
#[repr(C)]
pub struct Point<T: Clone + Debug> {
@@ -29,6 +31,30 @@ impl<T: Clone + Debug> Point<T> {
}
}
impl<T: Clone + Debug + Sub<Output = T>> SubAssign<Size<T>> for Point<T> {
fn sub_assign(&mut self, rhs: Size<T>) {
self.x = self.x.clone() - rhs.width;
self.y = self.y.clone() - rhs.height;
}
}
impl<T: Clone + Debug + std::cmp::PartialOrd> Point<T> {
pub fn max(&self, other: &Self) -> Self {
Point {
x: if self.x >= other.x {
self.x.clone()
} else {
other.x.clone()
},
y: if self.y >= other.y {
self.y.clone()
} else {
other.y.clone()
},
}
}
}
impl<T: Clone + Debug> Clone for Point<T> {
fn clone(&self) -> Self {
Self {
@@ -94,6 +120,22 @@ impl<T: Clone + Debug + Copy + Add<T, Output = T>> Bounds<T> {
y: self.origin.y,
}
}
pub fn lower_right(&self) -> Point<T> {
Point {
x: self.origin.x + self.size.width,
y: self.origin.y + self.size.height,
}
}
}
impl<T: Clone + Debug + Copy + PartialOrd + Add<T, Output = T>> Bounds<T> {
pub fn contains_point(&self, point: Point<T>) -> bool {
point.x >= self.origin.x
&& point.x <= self.origin.x + self.size.width
&& point.y >= self.origin.y
&& point.y <= self.origin.y + self.size.height
}
}
impl<T: Clone + Debug + Copy> Copy for Bounds<T> {}
@@ -168,9 +210,9 @@ impl Edges<Pixels> {
#[repr(transparent)]
pub struct Pixels(pub(crate) f32);
impl From<Pixels> for f64 {
fn from(pixels: Pixels) -> Self {
pixels.0.into()
impl Pixels {
pub fn round(&self) -> Self {
Self(self.0.round())
}
}
@@ -190,12 +232,6 @@ impl Mul<Pixels> for Pixels {
}
}
impl Pixels {
pub fn round(&self) -> Self {
Self(self.0.round())
}
}
impl Eq for Pixels {}
impl Ord for Pixels {
@@ -231,6 +267,12 @@ impl From<&Pixels> for f32 {
}
}
impl From<Pixels> for f64 {
fn from(pixels: Pixels) -> Self {
pixels.0 as f64
}
}
#[derive(Clone, Copy, Default, Add, Sub, Mul, Div)]
pub struct Rems(f32);
+4
View File
@@ -9,6 +9,7 @@ mod platform;
mod renderer;
mod scene;
mod style;
mod styled;
mod taffy;
mod text;
mod util;
@@ -23,10 +24,13 @@ pub use executor::*;
pub use fonts::*;
pub use geometry::*;
pub use platform::*;
pub use refineable::*;
pub use scene::*;
pub use smallvec;
pub use smol::Timer;
use std::ops::{Deref, DerefMut};
pub use style::*;
pub use styled::*;
pub use taffy::LayoutId;
use taffy::TaffyLayoutEngine;
use text::*;
-1
View File
@@ -28,7 +28,6 @@ use objc::{
pub use platform::*;
pub use screen::*;
pub use window::*;
use window_appearence::*;
trait BoolExt {
fn to_objc(self) -> BOOL;
+26
View File
@@ -0,0 +1,26 @@
use crate::{Refineable, RefinementCascade};
pub trait Styled {
type Style: Refineable + Default;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
fn computed_style(&mut self) -> Self::Style {
Self::Style::from_refinement(&self.style_cascade().merged())
}
// fn hover(self) -> Hoverable<Self>
// where
// Self: Sized,
// {
// hoverable(self)
// }
// fn active(self) -> Pressable<Self>
// where
// Self: Sized,
// {
// pressable(self)
// }
}
+15 -1
View File
@@ -1,4 +1,4 @@
use crate::PlatformWindow;
use crate::{PlatformWindow, Point, TextStyleRefinement};
use super::{
px, taffy::LayoutId, AppContext, Bounds, Context, EntityId, Handle, Pixels, Reference, Style,
@@ -18,6 +18,7 @@ pub struct Window {
platform_window: Box<dyn PlatformWindow>,
rem_size: Pixels,
layout_engine: TaffyLayoutEngine,
text_style_stack: Vec<TextStyleRefinement>,
pub(crate) root_view: Option<Box<dyn Any>>,
}
@@ -28,6 +29,7 @@ impl Window {
platform_window,
rem_size: px(16.),
layout_engine: TaffyLayoutEngine::new(),
text_style_stack: Vec::new(),
root_view: None,
}
}
@@ -82,6 +84,18 @@ impl<'a, 'w> WindowContext<'a, 'w> {
self.window.rem_size
}
pub fn push_text_style(&mut self, text_style: TextStyleRefinement) {
self.window.text_style_stack.push(text_style);
}
pub fn pop_text_style(&mut self) {
self.window.text_style_stack.pop();
}
pub fn mouse_position(&self) -> Point<Pixels> {
self.window.platform_window.mouse_position()
}
fn update_window<R>(
&mut self,
window_id: WindowId,