This commit is contained in:
Nathan Sobo 2023-07-27 13:00:28 -06:00
parent 70c9959ebc
commit 2ef19e48bc
3 changed files with 80 additions and 79 deletions

View file

@ -14,10 +14,10 @@ fn main() {
} }
#[derive(Clone, Default)] #[derive(Clone, Default)]
struct Playground(playground_ui::Playground); struct Playground(playground_ui::Playground<Self>);
impl Deref for Playground { impl Deref for Playground {
type Target = playground_ui::Playground; type Target = playground_ui::Playground<Self>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0

View file

@ -2,16 +2,16 @@ use gpui::{
elements::node::{column, length::auto, row, text}, elements::node::{column, length::auto, row, text},
AnyElement, Element, LayoutContext, View, ViewContext, AnyElement, Element, LayoutContext, View, ViewContext,
}; };
use std::{borrow::Cow, marker::PhantomData}; use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc};
use tokens::{margin::m4, text::lg}; use tokens::{margin::m4, text::lg};
mod tokens; mod tokens;
#[derive(Element, Clone, Default)] #[derive(Element, Clone, Default)]
pub struct Playground; pub struct Playground<V: View>(PhantomData<V>);
impl Playground { impl<V: View> Playground<V> {
pub fn render<V: View>(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> { pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> {
column() column()
.width(auto()) .width(auto())
.child( .child(
@ -22,30 +22,25 @@ impl Playground {
.into_any() .into_any()
} }
fn action_1(&mut self, data: &usize, _: &mut ViewContext<Self>) { fn action_1(_: &mut V, data: &usize, _: &mut ViewContext<V>) {
println!("action 1: data is {}", *data); println!("action 1: data is {}", *data);
} }
fn action_2(&mut self, data: &usize, _: &mut ViewContext<Self>) { fn action_2(_: &mut V, data: &usize, _: &mut ViewContext<V>) {
println!("action 1: data is {}", *data); println!("action 1: data is {}", *data);
} }
} }
pub trait DialogDelegate<V: View>: 'static { pub trait DialogDelegate<V: View>: 'static {}
fn handle_confirm<B>(&mut self, view: &mut V, button: B);
}
impl<V: View> DialogDelegate<V> for () { impl<V: View> DialogDelegate<V> for () {}
fn handle_cancel<B>(&mut self, view: &mut V, button: B) {}
fn handle_confirm<B>(&mut self, _: &mut V, _: B) {}
}
#[derive(Element)] #[derive(Element)]
pub struct Dialog<V: View, D: DialogDelegate<V>> { pub struct Dialog<V: View, D: DialogDelegate<V>> {
title: Cow<'static, str>, title: Cow<'static, str>,
description: Cow<'static, str>, description: Cow<'static, str>,
delegate: Option<Rc<RefCell<D>>>, delegate: Option<Rc<RefCell<D>>>,
buttons: Vec<Box<dyn Fn() -> Button>>, buttons: Vec<Box<dyn FnOnce() -> AnyElement<V>>>,
view_type: PhantomData<V>, view_type: PhantomData<V>,
} }
@ -64,19 +59,21 @@ pub fn dialog<V: View>(
impl<V: View, D: DialogDelegate<V>> Dialog<V, D> { impl<V: View, D: DialogDelegate<V>> Dialog<V, D> {
pub fn delegate(mut self, delegate: D) -> Dialog<V, D> { pub fn delegate(mut self, delegate: D) -> Dialog<V, D> {
let old_delegate = self.delegate.replace(delegate); let old_delegate = self.delegate.replace(Rc::new(RefCell::new(delegate)));
debug_assert!(old_delegate.is_none(), "delegate already set"); debug_assert!(old_delegate.is_none(), "delegate already set");
self self
} }
pub fn button<L, D, H>(mut self, label: L, data: D, handler: H) -> Self pub fn button<L, Data, H>(mut self, label: L, data: Data, handler: H) -> Self
where where
L: Into<Cow<'static, str>>, L: 'static + Into<Cow<'static, str>>,
D: 'static, Data: 'static + Clone,
H: ClickHandler<V, D>, H: ClickHandler<V, Data>,
{ {
self.buttons let label = label.into();
.push(|| button(label).data(data).click(handler)); self.buttons.push(Box::new(move || {
button(label).data(data).click(handler).into_any()
}));
self self
} }
} }
@ -128,7 +125,7 @@ where
impl<V: View> Button<V, (), ()> { impl<V: View> Button<V, (), ()> {
fn data<D>(self, data: D) -> Button<V, D, ()> fn data<D>(self, data: D) -> Button<V, D, ()>
where where
D: 'static + FnOnce(&mut V, &D, &mut ViewContext<V>), D: 'static,
{ {
Button { Button {
label: self.label, label: self.label,
@ -142,7 +139,7 @@ impl<V: View> Button<V, (), ()> {
impl<V: View, D> Button<V, D, ()> { impl<V: View, D> Button<V, D, ()> {
fn click<H>(self, handler: H) -> Button<V, D, H> fn click<H>(self, handler: H) -> Button<V, D, H>
where where
H: 'static + Fn(&mut V, &D, &mut ViewContext<V>), H: 'static + ClickHandler<V, D>,
{ {
Button { Button {
label: self.label, label: self.label,
@ -155,12 +152,10 @@ impl<V: View, D> Button<V, D, ()> {
impl<V: View, D: DialogDelegate<V>> Dialog<V, D> { impl<V: View, D: DialogDelegate<V>> Dialog<V, D> {
pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> { pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> {
let delegate = self.delegate.clone();
column() column()
.child(text(self.title.clone()).text_size(lg())) .child(text(self.title.clone()).text_size(lg()))
.child(text(self.description.clone()).margins(m4(), auto())) .child(text(self.description.clone()).margins(m4(), auto()))
.child(row().children(self.buttons.iter().map(|button| (button)()))) .child(row().children(self.buttons.drain(..).map(|button| (button)())))
.into_any() .into_any()
} }
} }

View file

@ -273,7 +273,7 @@ impl<V: View> Node<V> {
} }
} }
fn paint_2d_children( fn paint_children_xy(
&mut self, &mut self,
scene: &mut SceneBuilder, scene: &mut SceneBuilder,
axis: Axis2d, axis: Axis2d,
@ -395,15 +395,7 @@ impl<V: View> Element<V> for Node<V> {
let mut layout = NodeLayout::default(); let mut layout = NodeLayout::default();
let size = if let Some(axis) = self.style.axis.to_2d() { let size = if let Some(axis) = self.style.axis.to_2d() {
self.layout_xy( self.layout_xy(axis, constraint.max, cx.rem_pixels(), &mut layout, view, cx)
axis,
constraint.max,
cx.rem_pixels(),
&mut layout,
&mut layout.padding,
view,
cx,
)
} else { } else {
todo!() todo!()
}; };
@ -421,11 +413,6 @@ impl<V: View> Element<V> for Node<V> {
cx: &mut PaintContext<V>, cx: &mut PaintContext<V>,
) -> Self::PaintState { ) -> Self::PaintState {
let rem_pixels = cx.rem_pixels(); let rem_pixels = cx.rem_pixels();
// let margin: Edges<f32> = todo!(); // &self.style.margin.to_pixels(rem_size);
//
let size = bounds.size();
let margined_bounds = RectF::from_points( let margined_bounds = RectF::from_points(
bounds.origin() + vec2f(layout.margins.left, layout.margins.top), bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom), bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
@ -434,7 +421,7 @@ impl<V: View> Element<V> for Node<V> {
// Paint drop shadow // Paint drop shadow
for shadow in &self.style.shadows { for shadow in &self.style.shadows {
scene.push_shadow(scene::Shadow { scene.push_shadow(scene::Shadow {
bounds: margin_bounds + shadow.offset, bounds: margined_bounds + shadow.offset,
corner_radius: self.style.corner_radius, corner_radius: self.style.corner_radius,
sigma: shadow.blur, sigma: shadow.blur,
color: shadow.color, color: shadow.color,
@ -451,7 +438,7 @@ impl<V: View> Element<V> for Node<V> {
// } // }
// } // }
// Render the background and/or the border (if it not an overlay border). // Render the background and/or the border.
let Fill::Color(fill_color) = self.style.fill; let Fill::Color(fill_color) = self.style.fill;
let is_fill_visible = !fill_color.is_fully_transparent(); let is_fill_visible = !fill_color.is_fully_transparent();
if is_fill_visible || self.style.borders.is_visible() { if is_fill_visible || self.style.borders.is_visible() {
@ -472,38 +459,25 @@ impl<V: View> Element<V> for Node<V> {
} }
if !self.children.is_empty() { if !self.children.is_empty() {
let padded_bounds = RectF::from_points(
margined_bounds.origin() + vec2f(layout.padding.left, layout.padding.top),
margined_bounds.lower_right() - vec2f(layout.padding.right, layout.padding.bottom),
);
// Account for padding first. // Account for padding first.
let padding: Edges<f32> = todo!(); // &self.style.padding.to_pixels(rem_size); let borders = &self.style.borders;
let padded_bounds = RectF::from_points( let padded_bounds = RectF::from_points(
margined_bounds.origin() + vec2f(padding.left, padding.top), margined_bounds.origin()
margined_bounds.lower_right() - vec2f(padding.right, padding.top), + vec2f(
borders.left_width() + layout.padding.left,
borders.top_width() + layout.padding.top,
),
margined_bounds.lower_right()
- vec2f(
layout.padding.right + borders.right_width(),
layout.padding.bottom + borders.bottom_width(),
),
); );
match self.style.axis { if let Some(axis) = self.style.axis.to_2d() {
Axis3d::X => self.paint_2d_children( self.paint_children_xy(scene, axis, padded_bounds, visible_bounds, layout, view, cx)
scene, } else {
Axis2d::X, todo!();
padded_bounds,
visible_bounds,
layout,
view,
cx,
),
Axis3d::Y => self.paint_2d_children(
scene,
Axis2d::Y,
padded_bounds,
visible_bounds,
layout,
view,
cx,
),
Axis3d::Z => todo!(),
} }
} }
} }
@ -631,7 +605,7 @@ pub struct NodeStyle {
text: OptionalTextStyle, text: OptionalTextStyle,
opacity: f32, opacity: f32,
fill: Fill, fill: Fill,
borders: Border, borders: Borders,
corner_radius: f32, corner_radius: f32,
shadows: Vec<Shadow>, shadows: Vec<Shadow>,
} }
@ -673,7 +647,7 @@ struct Size<T> {
height: T, height: T,
} }
impl<T> Size<T> { impl<T: Copy> Size<T> {
fn get(&self, axis: Axis2d) -> T { fn get(&self, axis: Axis2d) -> T {
match axis { match axis {
Axis2d::X => self.width, Axis2d::X => self.width,
@ -682,7 +656,7 @@ impl<T> Size<T> {
} }
} }
impl<T: Add<Output = T>> Size<Option<T>> { impl<T: Copy + Add<Output = T>> Size<Option<T>> {
fn add_assign_optional(&mut self, rhs: Size<Option<T>>) { fn add_assign_optional(&mut self, rhs: Size<Option<T>>) {
self.width = optional_add(self.width, rhs.width); self.width = optional_add(self.width, rhs.width);
self.height = optional_add(self.height, rhs.height); self.height = optional_add(self.height, rhs.height);
@ -843,7 +817,7 @@ impl Default for Fill {
} }
#[derive(Clone, Default)] #[derive(Clone, Default)]
struct Border { struct Borders {
color: Color, color: Color,
width: f32, width: f32,
top: bool, top: bool,
@ -852,13 +826,45 @@ struct Border {
right: bool, right: bool,
} }
impl Border { impl Borders {
fn is_visible(&self) -> bool { fn is_visible(&self) -> bool {
self.width > 0. self.width > 0.
&& !self.color.is_fully_transparent() && !self.color.is_fully_transparent()
&& (self.top || self.bottom || self.left || self.right) && (self.top || self.bottom || self.left || self.right)
} }
fn top_width(&self) -> f32 {
if self.top {
self.width
} else {
0.
}
}
fn bottom_width(&self) -> f32 {
if self.bottom {
self.width
} else {
0.
}
}
fn left_width(&self) -> f32 {
if self.left {
self.width
} else {
0.
}
}
fn right_width(&self) -> f32 {
if self.right {
self.width
} else {
0.
}
}
fn size(&self) -> Vector2F { fn size(&self) -> Vector2F {
let width = let width =
if self.left { self.width } else { 0. } + if self.right { self.width } else { 0. }; if self.left { self.width } else { 0. } + if self.right { self.width } else { 0. };
@ -1078,7 +1084,7 @@ pub fn text<V: View>(text: impl Into<Cow<'static, str>>) -> Node<V> {
} }
#[derive(Default)] #[derive(Default)]
struct NodeLayout { pub struct NodeLayout {
content_size: Vector2F, content_size: Vector2F,
margins: Edges<f32>, margins: Edges<f32>,
padding: Edges<f32>, padding: Edges<f32>,