WIP
This commit is contained in:
parent
5e36040533
commit
4b4b949972
2 changed files with 108 additions and 584 deletions
|
@ -10,16 +10,16 @@ use gpui::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{json, ToJson},
|
json::{json, ToJson},
|
||||||
scene,
|
|
||||||
serde_json::Value,
|
serde_json::Value,
|
||||||
text_layout::{Line, ShapedBoundary},
|
text_layout::{Line, ShapedBoundary},
|
||||||
AnyElement, AppContext, Element, Entity, LayoutContext, PaintContext, Quad, SceneBuilder,
|
AnyElement, AppContext, Element, Entity, LayoutContext, PaintContext, SceneBuilder,
|
||||||
SizeConstraint, View, ViewContext, WindowContext,
|
SizeConstraint, View, ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
use length::{Length, Rems};
|
use length::{Length, Rems};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use optional_struct::*;
|
use optional_struct::*;
|
||||||
use std::{any::Any, borrow::Cow, f32, ops::Range, sync::Arc};
|
use std::{any::Any, borrow::Cow, f32, ops::Range, sync::Arc};
|
||||||
|
use taffy::prelude::Style as TaffyStyle;
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
use crate::color::{Hsla, Rgba};
|
use crate::color::{Hsla, Rgba};
|
||||||
|
@ -38,23 +38,11 @@ pub fn column<V>() -> Frame<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn row<V>() -> Frame<V> {
|
pub fn row<V>() -> Frame<V> {
|
||||||
Frame {
|
todo!()
|
||||||
style: FrameStyle {
|
|
||||||
axis: Axis3d::X,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack<V>() -> Frame<V> {
|
pub fn stack<V>() -> Frame<V> {
|
||||||
Frame {
|
todo!()
|
||||||
style: FrameStyle {
|
|
||||||
axis: Axis3d::Z,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Default for Frame<V> {
|
impl<V> Default for Frame<V> {
|
||||||
|
@ -88,17 +76,7 @@ impl<V: 'static> Element<V> for Frame<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = if let Some(axis) = self.style.axis.to_2d() {
|
(todo!(), todo!())
|
||||||
self.layout_xy(axis, constraint, cx.rem_pixels(), view, cx)
|
|
||||||
} else {
|
|
||||||
unimplemented!()
|
|
||||||
};
|
|
||||||
|
|
||||||
if pushed_text_style {
|
|
||||||
cx.pop_text_style();
|
|
||||||
}
|
|
||||||
|
|
||||||
(layout.size.max(constraint.min), layout)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
|
@ -114,27 +92,15 @@ impl<V: 'static> Element<V> for Frame<V> {
|
||||||
before_paint(bounds, layout, cx);
|
before_paint(bounds, layout, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bounds_center = bounds.size() / 2.;
|
// // Paint drop shadow
|
||||||
let bounds_target = bounds_center + (bounds_center * self.style.align.0);
|
// for shadow in &self.style.shadows {
|
||||||
let layout_center = layout.size / 2.;
|
// scene.push_shadow(scene::Shadow {
|
||||||
let layout_target = layout_center + layout_center * self.style.align.0;
|
// bounds: margined_bounds + shadow.offset,
|
||||||
let delta = bounds_target - layout_target;
|
// corner_radius: self.style.corner_radius,
|
||||||
|
// sigma: shadow.blur,
|
||||||
let aligned_bounds = RectF::new(bounds.origin() + delta, layout.size);
|
// color: shadow.color,
|
||||||
let margined_bounds = RectF::from_points(
|
// });
|
||||||
aligned_bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
|
// }
|
||||||
aligned_bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Paint drop shadow
|
|
||||||
for shadow in &self.style.shadows {
|
|
||||||
scene.push_shadow(scene::Shadow {
|
|
||||||
bounds: margined_bounds + shadow.offset,
|
|
||||||
corner_radius: self.style.corner_radius,
|
|
||||||
sigma: shadow.blur,
|
|
||||||
color: shadow.color,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// // Paint cursor style
|
// // Paint cursor style
|
||||||
// if let Some(hit_bounds) = content_bounds.intersection(visible_bounds) {
|
// if let Some(hit_bounds) = content_bounds.intersection(visible_bounds) {
|
||||||
|
@ -146,56 +112,56 @@ impl<V: 'static> Element<V> for Frame<V> {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Render the background and/or the 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.a > 0.;
|
// let is_fill_visible = fill_color.a > 0.;
|
||||||
if is_fill_visible || self.style.borders.is_visible() {
|
// if is_fill_visible || self.style.borders.is_visible() {
|
||||||
scene.push_quad(Quad {
|
// scene.push_quad(Quad {
|
||||||
bounds: margined_bounds,
|
// bounds: margined_bounds,
|
||||||
background: is_fill_visible.then_some(fill_color.into()),
|
// background: is_fill_visible.then_some(fill_color.into()),
|
||||||
border: scene::Border {
|
// border: scene::Border {
|
||||||
width: self.style.borders.width,
|
// width: self.style.borders.width,
|
||||||
color: self.style.borders.color,
|
// color: self.style.borders.color,
|
||||||
overlay: false,
|
// overlay: false,
|
||||||
top: self.style.borders.top,
|
// top: self.style.borders.top,
|
||||||
right: self.style.borders.right,
|
// right: self.style.borders.right,
|
||||||
bottom: self.style.borders.bottom,
|
// bottom: self.style.borders.bottom,
|
||||||
left: self.style.borders.left,
|
// left: self.style.borders.left,
|
||||||
},
|
// },
|
||||||
corner_radius: self.style.corner_radius,
|
// corner_radius: self.style.corner_radius,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
if !self.children.is_empty() {
|
// if !self.children.is_empty() {
|
||||||
// Account for padding first.
|
// // Account for padding first.
|
||||||
let borders = &self.style.borders;
|
// let borders = &self.style.borders;
|
||||||
let padded_bounds = RectF::from_points(
|
// let padded_bounds = RectF::from_points(
|
||||||
margined_bounds.origin()
|
// margined_bounds.origin()
|
||||||
+ vec2f(
|
// + vec2f(
|
||||||
borders.left_width() + layout.padding.left,
|
// borders.left_width() + layout.padding.left,
|
||||||
borders.top_width() + layout.padding.top,
|
// borders.top_width() + layout.padding.top,
|
||||||
),
|
// ),
|
||||||
margined_bounds.lower_right()
|
// margined_bounds.lower_right()
|
||||||
- vec2f(
|
// - vec2f(
|
||||||
layout.padding.right + borders.right_width(),
|
// layout.padding.right + borders.right_width(),
|
||||||
layout.padding.bottom + borders.bottom_width(),
|
// layout.padding.bottom + borders.bottom_width(),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
|
|
||||||
if let Some(axis) = self.style.axis.to_2d() {
|
// if let Some(axis) = self.style.axis.to_2d() {
|
||||||
// let parent_size = padded_bounds.size();
|
// // let parent_size = padded_bounds.size();
|
||||||
let mut child_origin = padded_bounds.origin();
|
// let mut child_origin = padded_bounds.origin();
|
||||||
|
|
||||||
for child in &mut self.children {
|
// for child in &mut self.children {
|
||||||
child.paint(scene, child_origin, visible_bounds, view, cx);
|
// child.paint(scene, child_origin, visible_bounds, view, cx);
|
||||||
|
|
||||||
// Advance along the primary axis by the size of this child
|
// // Advance along the primary axis by the size of this child
|
||||||
child_origin.set(axis, child_origin.get(axis) + child.size().get(axis));
|
// child_origin.set(axis, child_origin.get(axis) + child.size().get(axis));
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
unimplemented!();
|
// unimplemented!();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rect_for_text_range(
|
fn rect_for_text_range(
|
||||||
|
@ -255,21 +221,6 @@ impl<V: 'static> Frame<V> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(self, size: impl Into<Size<Length>>) -> Self {
|
|
||||||
let size = size.into();
|
|
||||||
self.width(size.width).height(size.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn width(mut self, width: impl Into<Length>) -> Self {
|
|
||||||
self.style.size.width = width.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn height(mut self, height: impl Into<Length>) -> Self {
|
|
||||||
self.style.size.height = height.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill(mut self, fill: impl Into<Fill>) -> Self {
|
pub fn fill(mut self, fill: impl Into<Fill>) -> Self {
|
||||||
self.style.fill = fill.into();
|
self.style.fill = fill.into();
|
||||||
self
|
self
|
||||||
|
@ -285,261 +236,6 @@ impl<V: 'static> Frame<V> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn margins(mut self, margins: impl Into<Edges<Length>>) -> Self {
|
|
||||||
self.style.margins = margins.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn margin_x(mut self, margin: impl Into<Length>) -> Self {
|
|
||||||
self.style.margins.set_x(margin.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn margin_y(mut self, margin: impl Into<Length>) -> Self {
|
|
||||||
self.style.margins.set_y(margin.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn margin_top(mut self, top: Length) -> Self {
|
|
||||||
self.style.margins.top = top;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn margin_bottom(mut self, bottom: Length) -> Self {
|
|
||||||
self.style.margins.bottom = bottom;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn margin_left(mut self, left: impl Into<Length>) -> Self {
|
|
||||||
self.style.margins.left = left.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn margin_right(mut self, right: impl Into<Length>) -> Self {
|
|
||||||
self.style.margins.right = right.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn align(mut self, alignment: f32) -> Self {
|
|
||||||
let cross_axis = self
|
|
||||||
.style
|
|
||||||
.axis
|
|
||||||
.to_2d()
|
|
||||||
.map(Axis2d::rotate)
|
|
||||||
.unwrap_or(Axis2d::Y);
|
|
||||||
self.style.align.set(cross_axis, alignment);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn justify(mut self, alignment: f32) -> Self {
|
|
||||||
let axis = self.style.axis.to_2d().unwrap_or(Axis2d::X);
|
|
||||||
self.style.align.set(axis, alignment);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id_string(&self) -> String {
|
|
||||||
self.id.as_deref().unwrap_or("<anonymous>").to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layout_xy(
|
|
||||||
&mut self,
|
|
||||||
primary_axis: Axis2d,
|
|
||||||
constraint: SizeConstraint,
|
|
||||||
rem_pixels: f32,
|
|
||||||
view: &mut V,
|
|
||||||
cx: &mut LayoutContext<V>,
|
|
||||||
) -> FrameLayout {
|
|
||||||
self.style.text.is_some();
|
|
||||||
|
|
||||||
let cross_axis = primary_axis.rotate();
|
|
||||||
let total_flex = self.style.flex();
|
|
||||||
let mut layout = FrameLayout {
|
|
||||||
size: Default::default(),
|
|
||||||
padding: self.style.padding.fixed_pixels(rem_pixels),
|
|
||||||
margins: self.style.margins.fixed_pixels(rem_pixels),
|
|
||||||
borders: self.style.borders.edges(),
|
|
||||||
};
|
|
||||||
let fixed_padding_size = layout.padding.size();
|
|
||||||
let fixed_margin_size = layout.margins.size();
|
|
||||||
let borders_size = layout.borders.size();
|
|
||||||
let fixed_constraint = constraint - fixed_margin_size - borders_size - fixed_padding_size;
|
|
||||||
|
|
||||||
// Determine the child constraints in each dimension based on the styled size
|
|
||||||
let mut child_constraint = SizeConstraint::default();
|
|
||||||
for axis in [Axis2d::X, Axis2d::Y] {
|
|
||||||
let length = self.style.size.get(axis);
|
|
||||||
let content_length = match length {
|
|
||||||
Length::Hug => {
|
|
||||||
// Tell the children not to expand
|
|
||||||
0.
|
|
||||||
}
|
|
||||||
Length::Fixed(fixed_length) => {
|
|
||||||
// Tell the children to expand up to the fixed length minus the padding.
|
|
||||||
fixed_length.to_pixels(rem_pixels) - fixed_padding_size.get(axis)
|
|
||||||
}
|
|
||||||
Length::Auto { .. } => {
|
|
||||||
// Tell the children to expand to fill their share of the flex space in this node.
|
|
||||||
length.flex_pixels(
|
|
||||||
rem_pixels,
|
|
||||||
&mut total_flex.get(axis),
|
|
||||||
&mut fixed_constraint.max.get(axis),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
child_constraint.max.set(axis, content_length);
|
|
||||||
if axis == cross_axis {
|
|
||||||
child_constraint.min.set(axis, content_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lay out inflexible children. Total up flex of flexible children for
|
|
||||||
// use in a second pass.
|
|
||||||
let mut remaining_length = child_constraint.max.get(primary_axis);
|
|
||||||
let mut remaining_flex = 0.;
|
|
||||||
let mut total_length = 0.;
|
|
||||||
let mut cross_axis_max: f32 = 0.;
|
|
||||||
|
|
||||||
for child in &mut self.children {
|
|
||||||
if let Some(child_flex) = child
|
|
||||||
.metadata::<FrameStyle>()
|
|
||||||
.map(|style| style.flex().get(primary_axis))
|
|
||||||
{
|
|
||||||
if child_flex > 0. {
|
|
||||||
remaining_flex += child_flex;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let child_size = child.layout(child_constraint, view, cx);
|
|
||||||
let child_length = child_size.get(primary_axis);
|
|
||||||
remaining_length -= child_length;
|
|
||||||
total_length += child_length;
|
|
||||||
cross_axis_max = cross_axis_max.max(child_size.get(cross_axis));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Distribute the remaining length among the flexible children.
|
|
||||||
for child in &mut self.children {
|
|
||||||
if let Some(child_flex) = child
|
|
||||||
.metadata::<FrameStyle>()
|
|
||||||
.map(|style| style.flex().get(primary_axis))
|
|
||||||
{
|
|
||||||
if child_flex > 0. {
|
|
||||||
let max_child_length = (child_flex / remaining_flex) * remaining_length;
|
|
||||||
child_constraint.max.set(primary_axis, max_child_length);
|
|
||||||
|
|
||||||
let child_size = child.layout(child_constraint, view, cx);
|
|
||||||
let child_length = child_size.get(primary_axis);
|
|
||||||
total_length += child_length;
|
|
||||||
remaining_length -= child_length;
|
|
||||||
remaining_flex -= child_flex;
|
|
||||||
cross_axis_max = cross_axis_max.max(child_size.get(cross_axis));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let content_size = match primary_axis {
|
|
||||||
Axis2d::X => vec2f(total_length, cross_axis_max),
|
|
||||||
Axis2d::Y => vec2f(cross_axis_max, total_length),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Distribute remaining space to flexible padding and margins.
|
|
||||||
for axis in [Axis2d::X, Axis2d::Y] {
|
|
||||||
let length = self.style.size.get(axis);
|
|
||||||
match length {
|
|
||||||
Length::Hug => {
|
|
||||||
let mut remaining_flex = total_flex.get(axis);
|
|
||||||
let mut remaining_length =
|
|
||||||
fixed_constraint.min.get(axis) - content_size.get(axis);
|
|
||||||
|
|
||||||
layout.padding.compute_flex_edges(
|
|
||||||
&self.style.padding,
|
|
||||||
axis,
|
|
||||||
&mut remaining_flex,
|
|
||||||
&mut remaining_length,
|
|
||||||
rem_pixels,
|
|
||||||
);
|
|
||||||
layout.margins.compute_flex_edges(
|
|
||||||
&self.style.margins,
|
|
||||||
axis,
|
|
||||||
&mut remaining_flex,
|
|
||||||
&mut remaining_length,
|
|
||||||
rem_pixels,
|
|
||||||
);
|
|
||||||
layout.size.set(
|
|
||||||
axis,
|
|
||||||
content_size.get(axis)
|
|
||||||
+ layout.padding.size().get(axis)
|
|
||||||
+ layout.borders.size().get(axis)
|
|
||||||
+ layout.margins.size().get(axis),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Length::Fixed(fixed_length) => {
|
|
||||||
let fixed_length = fixed_length.to_pixels(rem_pixels);
|
|
||||||
|
|
||||||
// With a fixed length, we can only distribute the space in the fixed-length container
|
|
||||||
// not consumed by the content.
|
|
||||||
let mut padding_flex = self.style.padding.flex().get(axis);
|
|
||||||
let mut max_padding_length = (fixed_length - content_size.get(axis)).max(0.);
|
|
||||||
layout.padding.compute_flex_edges(
|
|
||||||
&self.style.padding,
|
|
||||||
axis,
|
|
||||||
&mut padding_flex,
|
|
||||||
&mut max_padding_length,
|
|
||||||
rem_pixels,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Similarly, distribute the available space for margins so we preserve the fixed length
|
|
||||||
// of the container.
|
|
||||||
let mut margin_flex = self.style.margins.flex().get(axis);
|
|
||||||
let mut max_margin_length = constraint.max.get(axis) - fixed_length;
|
|
||||||
layout.margins.compute_flex_edges(
|
|
||||||
&self.style.margins,
|
|
||||||
axis,
|
|
||||||
&mut margin_flex,
|
|
||||||
&mut max_margin_length,
|
|
||||||
rem_pixels,
|
|
||||||
);
|
|
||||||
|
|
||||||
layout
|
|
||||||
.size
|
|
||||||
.set(axis, fixed_length + layout.margins.size().get(axis))
|
|
||||||
}
|
|
||||||
Length::Auto { .. } => {
|
|
||||||
let mut remaining_flex = total_flex.get(axis);
|
|
||||||
let mut remaining_length = fixed_constraint.max.get(axis);
|
|
||||||
let flex_length =
|
|
||||||
length.flex_pixels(rem_pixels, &mut remaining_flex, &mut remaining_length);
|
|
||||||
|
|
||||||
layout.padding.compute_flex_edges(
|
|
||||||
&self.style.padding,
|
|
||||||
axis,
|
|
||||||
&mut remaining_flex,
|
|
||||||
&mut remaining_length,
|
|
||||||
rem_pixels,
|
|
||||||
);
|
|
||||||
|
|
||||||
layout.margins.compute_flex_edges(
|
|
||||||
&self.style.margins,
|
|
||||||
axis,
|
|
||||||
&mut remaining_flex,
|
|
||||||
&mut remaining_length,
|
|
||||||
rem_pixels,
|
|
||||||
);
|
|
||||||
|
|
||||||
layout.size.set(
|
|
||||||
axis,
|
|
||||||
flex_length
|
|
||||||
+ layout.padding.size().get(axis)
|
|
||||||
+ layout.borders.size().get(axis)
|
|
||||||
+ layout.margins.size().get(axis),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout
|
|
||||||
}
|
|
||||||
|
|
||||||
fn before_paint<H>(mut self, handler: H) -> Self
|
fn before_paint<H>(mut self, handler: H) -> Self
|
||||||
where
|
where
|
||||||
H: 'static + FnMut(RectF, &mut FrameLayout, &mut PaintContext<V>),
|
H: 'static + FnMut(RectF, &mut FrameLayout, &mut PaintContext<V>),
|
||||||
|
@ -601,29 +297,13 @@ struct Interactive<Style> {
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct FrameStyle {
|
pub struct FrameStyle {
|
||||||
axis: Axis3d,
|
|
||||||
wrap: bool,
|
|
||||||
align: Alignment,
|
|
||||||
overflow_x: Overflow,
|
|
||||||
overflow_y: Overflow,
|
|
||||||
gap_x: Gap,
|
|
||||||
gap_y: Gap,
|
|
||||||
|
|
||||||
size: Size<Length>,
|
|
||||||
margins: Edges<Length>,
|
|
||||||
padding: Edges<Length>,
|
|
||||||
text: OptionalTextStyle,
|
text: OptionalTextStyle,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
fill: Fill,
|
fill: Fill,
|
||||||
borders: Borders,
|
borders: Borders,
|
||||||
corner_radius: f32,
|
corner_radius: f32,
|
||||||
shadows: Vec<Shadow>,
|
shadows: Vec<Shadow>,
|
||||||
}
|
layout: TaffyStyle,
|
||||||
|
|
||||||
impl FrameStyle {
|
|
||||||
fn flex(&self) -> Vector2F {
|
|
||||||
self.size.flex() + self.padding.flex() + self.margins.flex()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[optional_struct]
|
#[optional_struct]
|
||||||
|
@ -1682,36 +1362,36 @@ mod tests {
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
fn test_frame_layout(cx: &mut TestAppContext) {
|
fn test_frame_layout(cx: &mut TestAppContext) {
|
||||||
cx.add_window(|_| {
|
// cx.add_window(|_| {
|
||||||
view(|_| {
|
// view(|_| {
|
||||||
let theme = rose_pine::dawn();
|
// let theme = rose_pine::dawn();
|
||||||
column()
|
// column()
|
||||||
.width(auto())
|
// .width(auto())
|
||||||
.height(auto())
|
// .height(auto())
|
||||||
.justify(1.)
|
// .justify(1.)
|
||||||
.child(
|
// .child(
|
||||||
row()
|
// row()
|
||||||
.width(auto())
|
// .width(auto())
|
||||||
.height(rems(10.))
|
// .height(rems(10.))
|
||||||
.justify(1.)
|
// .justify(1.)
|
||||||
.child(
|
// .child(
|
||||||
row()
|
// row()
|
||||||
.width(rems(10.))
|
// .width(rems(10.))
|
||||||
.height(auto())
|
// .height(auto())
|
||||||
.fill(theme.surface(1.)),
|
// .fill(theme.surface(1.)),
|
||||||
)
|
// )
|
||||||
.before_paint(|bounds, layout, cx| {
|
// .before_paint(|bounds, layout, cx| {
|
||||||
assert_eq!(bounds.origin(), vec2f(0., 0.));
|
// assert_eq!(bounds.origin(), vec2f(0., 0.));
|
||||||
assert_eq!(layout.size.x(), cx.window_size().x());
|
// assert_eq!(layout.size.x(), cx.window_size().x());
|
||||||
assert_eq!(layout.size.y(), rems(10.).to_pixels(cx.rem_pixels()));
|
// assert_eq!(layout.size.y(), rems(10.).to_pixels(cx.rem_pixels()));
|
||||||
}),
|
// }),
|
||||||
)
|
// )
|
||||||
.child(row())
|
// .child(row())
|
||||||
.before_paint(|bounds, layout, cx| {
|
// .before_paint(|bounds, layout, cx| {
|
||||||
assert_eq!(layout.size, cx.window_size());
|
// assert_eq!(layout.size, cx.window_size());
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
.remove(cx);
|
// .remove(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,182 +51,26 @@ impl<V> Playground<V> {
|
||||||
|
|
||||||
fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
||||||
column()
|
column()
|
||||||
.size(auto())
|
// .size(auto())
|
||||||
.fill(theme.base(0.5))
|
// .fill(theme.base(0.5))
|
||||||
.text_color(theme.text(0.5))
|
// .text_color(theme.text(0.5))
|
||||||
.child(title_bar(theme))
|
// .child(title_bar(theme))
|
||||||
.child(stage(theme))
|
// .child(stage(theme))
|
||||||
.child(status_bar(theme))
|
// .child(status_bar(theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn title_bar<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
// fn title_bar<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
||||||
row()
|
// row()
|
||||||
.fill(theme.base(0.2))
|
// .fill(theme.base(0.2))
|
||||||
.justify(0.)
|
// .justify(0.)
|
||||||
.width(auto())
|
// .width(auto())
|
||||||
.child(text("Zed Playground"))
|
// .child(text("Zed Playground"))
|
||||||
}
|
|
||||||
|
|
||||||
fn stage<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
|
||||||
row().fill(theme.surface(0.9))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn status_bar<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
|
||||||
row().fill(theme.surface(0.1))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DialogDelegate<V>: 'static {}
|
|
||||||
|
|
||||||
impl<V> DialogDelegate<V> for () {}
|
|
||||||
|
|
||||||
#[derive(Element)]
|
|
||||||
pub struct Dialog<V: 'static, D: DialogDelegate<V>> {
|
|
||||||
title: Cow<'static, str>,
|
|
||||||
description: Cow<'static, str>,
|
|
||||||
delegate: Option<Rc<RefCell<D>>>,
|
|
||||||
buttons: Vec<Box<dyn FnOnce() -> AnyElement<V>>>,
|
|
||||||
view_type: PhantomData<V>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dialog<V>(
|
|
||||||
title: impl Into<Cow<'static, str>>,
|
|
||||||
description: impl Into<Cow<'static, str>>,
|
|
||||||
) -> Dialog<V, ()> {
|
|
||||||
Dialog {
|
|
||||||
title: title.into(),
|
|
||||||
description: description.into(),
|
|
||||||
delegate: None,
|
|
||||||
buttons: Vec::new(),
|
|
||||||
view_type: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V, D: DialogDelegate<V>> Dialog<V, D> {
|
|
||||||
pub fn delegate(mut self, delegate: D) -> Dialog<V, D> {
|
|
||||||
let old_delegate = self.delegate.replace(Rc::new(RefCell::new(delegate)));
|
|
||||||
debug_assert!(old_delegate.is_none(), "delegate already set");
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn button<L, Data, H>(mut self, label: L, data: Data, handler: H) -> Self
|
|
||||||
where
|
|
||||||
L: 'static + Into<Cow<'static, str>>,
|
|
||||||
Data: 'static + Clone,
|
|
||||||
H: ClickHandler<V, Data>,
|
|
||||||
{
|
|
||||||
let label = label.into();
|
|
||||||
self.buttons.push(Box::new(move || {
|
|
||||||
button(label).data(data).click(handler).into_any()
|
|
||||||
}));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Element)]
|
|
||||||
struct Button<V: 'static, D: 'static, H: ClickHandler<V, D>> {
|
|
||||||
label: Cow<'static, str>,
|
|
||||||
click_handler: Option<H>,
|
|
||||||
data: Option<D>,
|
|
||||||
view_type: PhantomData<V>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ClickHandler<V, D>: 'static {
|
|
||||||
fn handle(&self, view: &mut V, data: &D, cx: &mut ViewContext<V>);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V, M, F: 'static + Fn(&mut V, &M, &mut ViewContext<V>)> ClickHandler<V, M> for F {
|
|
||||||
fn handle(&self, view: &mut V, data: &M, cx: &mut ViewContext<V>) {
|
|
||||||
self(view, data, cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V, D> ClickHandler<V, D> for () {
|
|
||||||
fn handle(&self, view: &mut V, data: &D, cx: &mut ViewContext<V>) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn button<V>(label: impl Into<Cow<'static, str>>) -> Button<V, (), ()> {
|
|
||||||
Button {
|
|
||||||
label: label.into(),
|
|
||||||
click_handler: None,
|
|
||||||
data: None,
|
|
||||||
view_type: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V, D, F> Button<V, D, F>
|
|
||||||
where
|
|
||||||
F: ClickHandler<V, D>,
|
|
||||||
{
|
|
||||||
fn render(&mut self, _: &mut V, _: &mut LayoutContext<V>) -> AnyElement<V> {
|
|
||||||
// TODO! Handle click etc
|
|
||||||
row().child(text(self.label.clone())).into_any()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl<V, D, F> Button<V, D, F>
|
|
||||||
// where
|
|
||||||
// V,
|
|
||||||
// F: ClickHandler<V, D>,
|
|
||||||
// {
|
|
||||||
// fn render(&mut self, _: &mut V, _: &mut LayoutContext<V>) -> impl Element<V> {
|
|
||||||
// // TODO! Handle click etc
|
|
||||||
// row()
|
|
||||||
// .fill(theme.colors.primary(5))
|
|
||||||
// .child(text(self.label.clone()).text_color(theme.colors.on_primary()))
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// struct Tab<V> {
|
// fn stage<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
||||||
// active: bool,
|
// row().fill(theme.surface(0.9))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// impl<V> Tab<V>
|
// fn status_bar<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
||||||
// where
|
// row().fill(theme.surface(0.1))
|
||||||
// V,
|
|
||||||
// {
|
|
||||||
// fn tab(&mut self, _: &mut V, _: &mut LayoutContext<V>) -> impl Element<V> {
|
|
||||||
// let theme = todo!();
|
|
||||||
// // TODO! Handle click etc
|
|
||||||
// row()
|
|
||||||
// .fill(theme.colors.neutral(6))
|
|
||||||
// .child(text(self.label.clone()).text_color(theme.colors.on_neutral()))
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
impl<V> Button<V, (), ()> {
|
|
||||||
fn data<D>(self, data: D) -> Button<V, D, ()>
|
|
||||||
where
|
|
||||||
D: 'static,
|
|
||||||
{
|
|
||||||
Button {
|
|
||||||
label: self.label,
|
|
||||||
click_handler: self.click_handler,
|
|
||||||
data: Some(data),
|
|
||||||
view_type: self.view_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V, D> Button<V, D, ()> {
|
|
||||||
fn click<H>(self, handler: H) -> Button<V, D, H>
|
|
||||||
where
|
|
||||||
H: 'static + ClickHandler<V, D>,
|
|
||||||
{
|
|
||||||
Button {
|
|
||||||
label: self.label,
|
|
||||||
click_handler: Some(handler),
|
|
||||||
data: self.data,
|
|
||||||
view_type: self.view_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V, D: DialogDelegate<V>> Dialog<V, D> {
|
|
||||||
pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> {
|
|
||||||
column()
|
|
||||||
.child(text(self.title.clone()).text_size(lg()))
|
|
||||||
.child(text(self.description.clone()).margins((m4(), auto())))
|
|
||||||
.child(row().children(self.buttons.drain(..).map(|button| (button)())))
|
|
||||||
.into_any()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue