mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 10:29:35 +03:00
WIP
This commit is contained in:
parent
6f6096238d
commit
1dfde8eab5
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -5178,6 +5178,7 @@ dependencies = [
|
|||||||
"gpui",
|
"gpui",
|
||||||
"log",
|
"log",
|
||||||
"optional_struct",
|
"optional_struct",
|
||||||
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -13,3 +13,6 @@ playground_ui = { path = "ui" }
|
|||||||
gpui = { path = ".." }
|
gpui = { path = ".." }
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
simplelog = "0.9"
|
simplelog = "0.9"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
gpui = { path = "..", features = ["test-support"] }
|
||||||
|
@ -13,3 +13,7 @@ derive_more = "0.99.17"
|
|||||||
gpui = { path = "../.." }
|
gpui = { path = "../.." }
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
optional_struct = "0.3.1"
|
optional_struct = "0.3.1"
|
||||||
|
smallvec.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
gpui = { path = "../..", features = ["test-support"] }
|
||||||
|
189
crates/gpui/playground/ui/src/color.rs
Normal file
189
crates/gpui/playground/ui/src/color.rs
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
pub fn rgb(hex: u32) -> Rgba {
|
||||||
|
let r = ((hex >> 16) & 0xFF) as f32 / 255.0;
|
||||||
|
let g = ((hex >> 8) & 0xFF) as f32 / 255.0;
|
||||||
|
let b = (hex & 0xFF) as f32 / 255.0;
|
||||||
|
Rgba { r, g, b, a: 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, Debug)]
|
||||||
|
pub struct Rgba {
|
||||||
|
pub r: f32,
|
||||||
|
pub g: f32,
|
||||||
|
pub b: f32,
|
||||||
|
pub a: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Hsla> for Rgba {
|
||||||
|
fn from(color: Hsla) -> Self {
|
||||||
|
let h = color.h;
|
||||||
|
let s = color.s;
|
||||||
|
let l = color.l;
|
||||||
|
|
||||||
|
let c = (1.0 - (2.0 * l - 1.0).abs()) * s;
|
||||||
|
let x = c * (1.0 - ((h * 6.0) % 2.0 - 1.0).abs());
|
||||||
|
let m = l - c / 2.0;
|
||||||
|
let cm = c + m;
|
||||||
|
let xm = x + m;
|
||||||
|
|
||||||
|
let (r, g, b) = match (h * 6.0).floor() as i32 {
|
||||||
|
0 | 6 => (cm, xm, m),
|
||||||
|
1 => (xm, cm, m),
|
||||||
|
2 => (m, cm, xm),
|
||||||
|
3 => (m, xm, cm),
|
||||||
|
4 => (xm, m, cm),
|
||||||
|
_ => (cm, m, xm),
|
||||||
|
};
|
||||||
|
|
||||||
|
Rgba {
|
||||||
|
r,
|
||||||
|
g,
|
||||||
|
b,
|
||||||
|
a: color.a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<gpui::color::Color> for Rgba {
|
||||||
|
fn into(self) -> gpui::color::Color {
|
||||||
|
gpui::color::rgba(self.r, self.g, self.b, self.a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Hsla {
|
||||||
|
h: f32,
|
||||||
|
s: f32,
|
||||||
|
l: f32,
|
||||||
|
a: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Rgba> for Hsla {
|
||||||
|
fn from(color: Rgba) -> Self {
|
||||||
|
let r = color.r;
|
||||||
|
let g = color.g;
|
||||||
|
let b = color.b;
|
||||||
|
|
||||||
|
let max = r.max(g.max(b));
|
||||||
|
let min = r.min(g.min(b));
|
||||||
|
let delta = max - min;
|
||||||
|
|
||||||
|
let l = (max + min) / 2.0;
|
||||||
|
let s = match l {
|
||||||
|
0.0 | 1.0 => 0.0,
|
||||||
|
l if l < 0.5 => delta / (2.0 * l),
|
||||||
|
l => delta / (2.0 - 2.0 * l),
|
||||||
|
};
|
||||||
|
|
||||||
|
let h = if delta == 0.0 {
|
||||||
|
0.0
|
||||||
|
} else if max == r {
|
||||||
|
((g - b) / delta).rem_euclid(6.0) / 6.0
|
||||||
|
} else if max == g {
|
||||||
|
((b - r) / delta + 2.0) / 6.0
|
||||||
|
} else {
|
||||||
|
((r - g) / delta + 4.0) / 6.0
|
||||||
|
};
|
||||||
|
|
||||||
|
Hsla {
|
||||||
|
h,
|
||||||
|
s,
|
||||||
|
l,
|
||||||
|
a: color.a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hsla {
|
||||||
|
/// Increases the saturation of the color by a certain amount, with a max
|
||||||
|
/// value of 1.0.
|
||||||
|
pub fn saturate(mut self, amount: f32) -> Self {
|
||||||
|
self.s += amount;
|
||||||
|
self.s = self.s.clamp(0.0, 1.0);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decreases the saturation of the color by a certain amount, with a min
|
||||||
|
/// value of 0.0.
|
||||||
|
pub fn desaturate(mut self, amount: f32) -> Self {
|
||||||
|
self.s -= amount;
|
||||||
|
self.s = self.s.max(0.0);
|
||||||
|
if self.s < 0.0 {
|
||||||
|
self.s = 0.0;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Brightens the color by increasing the lightness by a certain amount,
|
||||||
|
/// with a max value of 1.0.
|
||||||
|
pub fn brighten(mut self, amount: f32) -> Self {
|
||||||
|
self.l += amount;
|
||||||
|
self.l = self.l.clamp(0.0, 1.0);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Darkens the color by decreasing the lightness by a certain amount,
|
||||||
|
/// with a max value of 0.0.
|
||||||
|
pub fn darken(mut self, amount: f32) -> Self {
|
||||||
|
self.l -= amount;
|
||||||
|
self.l = self.l.clamp(0.0, 1.0);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ColorScale {
|
||||||
|
colors: SmallVec<[Hsla; 2]>,
|
||||||
|
positions: SmallVec<[f32; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale<I, C>(colors: I) -> ColorScale
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = C>,
|
||||||
|
C: Into<Hsla>,
|
||||||
|
{
|
||||||
|
let mut scale = ColorScale {
|
||||||
|
colors: colors.into_iter().map(Into::into).collect(),
|
||||||
|
positions: SmallVec::new(),
|
||||||
|
};
|
||||||
|
let num_colors: f32 = scale.colors.len() as f32 - 1.0;
|
||||||
|
scale.positions = (0..scale.colors.len())
|
||||||
|
.map(|i| i as f32 / num_colors)
|
||||||
|
.collect();
|
||||||
|
scale
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorScale {
|
||||||
|
fn at(&self, t: f32) -> Hsla {
|
||||||
|
// Ensure that the input is within [0.0, 1.0]
|
||||||
|
debug_assert!(
|
||||||
|
0.0 <= t && t <= 1.0,
|
||||||
|
"t value {} is out of range. Expected value in range 0.0 to 1.0",
|
||||||
|
t
|
||||||
|
);
|
||||||
|
|
||||||
|
let position = match self
|
||||||
|
.positions
|
||||||
|
.binary_search_by(|a| a.partial_cmp(&t).unwrap())
|
||||||
|
{
|
||||||
|
Ok(index) | Err(index) => index,
|
||||||
|
};
|
||||||
|
let lower_bound = position.saturating_sub(1);
|
||||||
|
let upper_bound = position.min(self.colors.len() - 1);
|
||||||
|
let lower_color = &self.colors[lower_bound];
|
||||||
|
let upper_color = &self.colors[upper_bound];
|
||||||
|
|
||||||
|
match upper_bound.checked_sub(lower_bound) {
|
||||||
|
Some(0) | None => *lower_color,
|
||||||
|
Some(_) => {
|
||||||
|
let interval_t = (t - self.positions[lower_bound])
|
||||||
|
/ (self.positions[upper_bound] - self.positions[lower_bound]);
|
||||||
|
let h = lower_color.h + interval_t * (upper_color.h - lower_color.h);
|
||||||
|
let s = lower_color.s + interval_t * (upper_color.s - lower_color.s);
|
||||||
|
let l = lower_color.l + interval_t * (upper_color.l - lower_color.l);
|
||||||
|
let a = lower_color.a + interval_t * (upper_color.a - lower_color.a);
|
||||||
|
Hsla { h, s, l, a }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
165
crates/gpui/playground/ui/src/editor_layout_demo.rs
Normal file
165
crates/gpui/playground/ui/src/editor_layout_demo.rs
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
use gpui::{AnyElement, Element, LayoutContext, View, ViewContext};
|
||||||
|
|
||||||
|
#[derive(Element, Clone, Default)]
|
||||||
|
pub struct Playground<V: View>(PhantomData<V>);
|
||||||
|
|
||||||
|
// example layout design here: https://www.figma.com/file/5QLTmxjO0xQpDD3CD4hR6T/Untitled?type=design&node-id=0%3A1&mode=design&t=SoJieVVIvDDDKagv-1
|
||||||
|
|
||||||
|
impl<V: View> Playground<V> {
|
||||||
|
pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> impl Element<V> {
|
||||||
|
col() // fullscreen container with header and main in it
|
||||||
|
.width(flex(1.))
|
||||||
|
.height(flex(1.))
|
||||||
|
.fill(colors(gray.900))
|
||||||
|
.children([
|
||||||
|
row() // header container
|
||||||
|
.fill(colors(gray.900))
|
||||||
|
.width(flex(1.))
|
||||||
|
.children([
|
||||||
|
row() // tab bar
|
||||||
|
.width(flex(1.))
|
||||||
|
.gap(spacing(2))
|
||||||
|
.padding(spacing(3))
|
||||||
|
.overflow_x(scroll())
|
||||||
|
.chidren([
|
||||||
|
row() // tab
|
||||||
|
.padding_x(spacing(3))
|
||||||
|
.padding_y(spacing(2))
|
||||||
|
.corner_radius(6.)
|
||||||
|
.gap(spacing(3))
|
||||||
|
.align(center())
|
||||||
|
.fill(colors(gray.800))
|
||||||
|
.children([text("Tab title 1"), svg("icon_name")]),
|
||||||
|
row() // tab
|
||||||
|
.padding_x(spacing(3))
|
||||||
|
.padding_y(spacing(2))
|
||||||
|
.corner_radius(6.)
|
||||||
|
.gap(spacing(3))
|
||||||
|
.align(center())
|
||||||
|
.fill(colors(gray.800))
|
||||||
|
.children([text("Tab title 2"), svg("icon_name")]),
|
||||||
|
row() // tab
|
||||||
|
.padding_x(spacing(3))
|
||||||
|
.padding_y(spacing(2))
|
||||||
|
.corner_radius(6.)
|
||||||
|
.gap(spacing(3))
|
||||||
|
.align(center())
|
||||||
|
.fill(colors(gray.800))
|
||||||
|
.children([text("Tab title 3"), svg("icon_name")]),
|
||||||
|
]),
|
||||||
|
row() // tab bar actions
|
||||||
|
.border_left(colors(gray.700))
|
||||||
|
.gap(spacing(2))
|
||||||
|
.padding(spacing(3))
|
||||||
|
.chidren([
|
||||||
|
row()
|
||||||
|
.width(spacing(8))
|
||||||
|
.height(spacing(8))
|
||||||
|
.corner_radius(6.)
|
||||||
|
.justify(center())
|
||||||
|
.align(center())
|
||||||
|
.fill(colors(gray.800))
|
||||||
|
.child(svg(icon_name)),
|
||||||
|
row()
|
||||||
|
.width(spacing(8))
|
||||||
|
.height(spacing(8))
|
||||||
|
.corner_radius(6.)
|
||||||
|
.justify(center())
|
||||||
|
.align(center())
|
||||||
|
.fill(colors(gray.800))
|
||||||
|
.child(svg(icon_name)),
|
||||||
|
row()
|
||||||
|
.width(spacing(8))
|
||||||
|
.height(spacing(8))
|
||||||
|
.corner_radius(6.)
|
||||||
|
.justify(center())
|
||||||
|
.align(center())
|
||||||
|
.fill(colors(gray.800))
|
||||||
|
.child(svg(icon_name)),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
row() // main container
|
||||||
|
.width(flex(1.))
|
||||||
|
.height(flex(1.))
|
||||||
|
.children([
|
||||||
|
col() // left sidebar
|
||||||
|
.fill(colors(gray.800))
|
||||||
|
.border_right(colors(gray.700))
|
||||||
|
.height(flex(1.))
|
||||||
|
.width(260.)
|
||||||
|
.children([
|
||||||
|
col() // containter to hold list items and notification alert box
|
||||||
|
.justify(between())
|
||||||
|
.padding_x(spacing(6))
|
||||||
|
.padding_bottom(3)
|
||||||
|
.padding_top(spacing(6))
|
||||||
|
.children([
|
||||||
|
col().gap(spacing(3)).children([ // sidebar list
|
||||||
|
text("Item"),
|
||||||
|
text("Item"),
|
||||||
|
text("Item"),
|
||||||
|
text("Item"),
|
||||||
|
text("Item"),
|
||||||
|
text("Item"),
|
||||||
|
text("Item"),
|
||||||
|
text("Item"),
|
||||||
|
]),
|
||||||
|
col().align(center()).gap(spacing(1)).children([ // notification alert box
|
||||||
|
text("Title text").size("lg"),
|
||||||
|
text("Description text goes here")
|
||||||
|
.text_color(colors(rose.200)),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
row()
|
||||||
|
.padding_x(spacing(3))
|
||||||
|
.padding_y(spacing(2))
|
||||||
|
.border_top(1., colors(gray.700))
|
||||||
|
.align(center())
|
||||||
|
.gap(spacing(2))
|
||||||
|
.fill(colors(gray.900))
|
||||||
|
.children([
|
||||||
|
row() // avatar container
|
||||||
|
.width(spacing(8))
|
||||||
|
.height(spacing(8))
|
||||||
|
.corner_radius(spacing(8))
|
||||||
|
.justify(center())
|
||||||
|
.align(center())
|
||||||
|
.child(image(image_url)),
|
||||||
|
text("FirstName Lastname"), // user name
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
col() // primary content container
|
||||||
|
.align(center())
|
||||||
|
.justify(center())
|
||||||
|
.child(
|
||||||
|
col().justify(center()).gap(spacing(8)).children([ // detail container wrapper for center positioning
|
||||||
|
col() // blue rectangle
|
||||||
|
.width(rem(30.))
|
||||||
|
.height(rem(20.))
|
||||||
|
.corner_radius(16.)
|
||||||
|
.fill(colors(blue.200)),
|
||||||
|
col().gap(spacing(1)).children([ // center content text items
|
||||||
|
text("This is a title").size("lg"),
|
||||||
|
text("This is a description").text_color(colors(gray.500)),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
col(), // right sidebar
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// row(
|
||||||
|
// padding(),
|
||||||
|
// width(),
|
||||||
|
// fill(),
|
||||||
|
// )
|
||||||
|
|
||||||
|
// .width(flex(1.))
|
||||||
|
// .height(flex(1.))
|
||||||
|
// .justify(end())
|
||||||
|
// .align(start()) // default
|
||||||
|
// .fill(green)
|
||||||
|
// .child(other_tab_bar())
|
||||||
|
// .child(profile_menu())
|
@ -1,5 +1,6 @@
|
|||||||
use derive_more::Add;
|
use derive_more::{Add, Deref, DerefMut};
|
||||||
use gpui::elements::layout_highlighted_chunks;
|
use gpui::elements::layout_highlighted_chunks;
|
||||||
|
use gpui::Entity;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
color::Color,
|
color::Color,
|
||||||
fonts::HighlightStyle,
|
fonts::HighlightStyle,
|
||||||
@ -19,16 +20,14 @@ 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 crate::color::Rgba;
|
||||||
|
|
||||||
pub struct Node<V: View> {
|
pub struct Node<V: View> {
|
||||||
style: NodeStyle,
|
style: NodeStyle,
|
||||||
children: Vec<AnyElement<V>>,
|
children: Vec<AnyElement<V>>,
|
||||||
id: Option<Cow<'static, str>>,
|
id: Option<Cow<'static, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node<V: View>(child: impl Element<V>) -> Node<V> {
|
|
||||||
Node::default().child(child)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn column<V: View>() -> Node<V> {
|
pub fn column<V: View>() -> Node<V> {
|
||||||
Node::default()
|
Node::default()
|
||||||
}
|
}
|
||||||
@ -91,10 +90,22 @@ impl<V: View> Element<V> for Node<V> {
|
|||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut PaintContext<V>,
|
cx: &mut PaintContext<V>,
|
||||||
) -> Self::PaintState {
|
) -> Self::PaintState {
|
||||||
|
dbg!(self.id_string());
|
||||||
|
dbg!(bounds.origin(), bounds.size());
|
||||||
|
|
||||||
|
let bounds_center = dbg!(bounds.size()) / 2.;
|
||||||
|
let bounds_target = bounds_center + (bounds_center * self.style.align.0);
|
||||||
|
let layout_center = dbg!(layout.size) / 2.;
|
||||||
|
let layout_target = layout_center + layout_center * self.style.align.0;
|
||||||
|
let delta = bounds_target - layout_target;
|
||||||
|
|
||||||
|
let aligned_bounds = RectF::new(bounds.origin() + delta, layout.size);
|
||||||
|
dbg!(aligned_bounds.origin(), aligned_bounds.size());
|
||||||
let margined_bounds = RectF::from_points(
|
let margined_bounds = RectF::from_points(
|
||||||
bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
|
aligned_bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
|
||||||
bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
|
aligned_bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
|
||||||
);
|
);
|
||||||
|
dbg!(margined_bounds.origin(), margined_bounds.size());
|
||||||
|
|
||||||
// Paint drop shadow
|
// Paint drop shadow
|
||||||
for shadow in &self.style.shadows {
|
for shadow in &self.style.shadows {
|
||||||
@ -118,17 +129,11 @@ impl<V: View> Element<V> for Node<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.is_fully_transparent();
|
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() {
|
||||||
eprintln!(
|
|
||||||
"{}: paint background: {:?}",
|
|
||||||
self.id.as_deref().unwrap_or(""),
|
|
||||||
margined_bounds
|
|
||||||
);
|
|
||||||
|
|
||||||
scene.push_quad(Quad {
|
scene.push_quad(Quad {
|
||||||
bounds: margined_bounds,
|
bounds: margined_bounds,
|
||||||
background: is_fill_visible.then_some(fill_color),
|
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,
|
||||||
@ -162,35 +167,7 @@ impl<V: View> Element<V> for Node<V> {
|
|||||||
// 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();
|
||||||
|
|
||||||
// Align all children together along the primary axis
|
|
||||||
// let mut align_horizontally = false;
|
|
||||||
// let mut align_vertically = false;
|
|
||||||
// match axis {
|
|
||||||
// Axis2d::X => align_horizontally = true,
|
|
||||||
// Axis2d::Y => align_vertically = true,
|
|
||||||
// }
|
|
||||||
// align_child(
|
|
||||||
// &mut child_origin,
|
|
||||||
// parent_size,
|
|
||||||
// layout.content_size,
|
|
||||||
// self.style.align.0,
|
|
||||||
// align_horizontally,
|
|
||||||
// align_vertically,
|
|
||||||
// );
|
|
||||||
|
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
// Align each child along the cross axis
|
|
||||||
// align_horizontally = !align_horizontally;
|
|
||||||
// align_vertically = !align_vertically;
|
|
||||||
// align_child(
|
|
||||||
// &mut child_origin,
|
|
||||||
// parent_size,
|
|
||||||
// child.size(),
|
|
||||||
// self.style.align.0,
|
|
||||||
// align_horizontally,
|
|
||||||
// align_vertically,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
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
|
||||||
@ -284,6 +261,16 @@ impl<V: View> Node<V> {
|
|||||||
self
|
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 {
|
pub fn margin_top(mut self, top: Length) -> Self {
|
||||||
self.style.margins.top = top;
|
self.style.margins.top = top;
|
||||||
self
|
self
|
||||||
@ -304,6 +291,23 @@ impl<V: View> Node<V> {
|
|||||||
self
|
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 {
|
fn id_string(&self) -> String {
|
||||||
self.id.as_deref().unwrap_or("<anonymous>").to_string()
|
self.id.as_deref().unwrap_or("<anonymous>").to_string()
|
||||||
}
|
}
|
||||||
@ -458,7 +462,7 @@ impl<V: View> Node<V> {
|
|||||||
let mut margin_flex = self.style.margins.flex().get(axis);
|
let mut margin_flex = self.style.margins.flex().get(axis);
|
||||||
let mut max_margin_length = constraint.max.get(axis) - fixed_length;
|
let mut max_margin_length = constraint.max.get(axis) - fixed_length;
|
||||||
layout.margins.compute_flex_edges(
|
layout.margins.compute_flex_edges(
|
||||||
&self.style.padding,
|
&self.style.margins,
|
||||||
axis,
|
axis,
|
||||||
&mut margin_flex,
|
&mut margin_flex,
|
||||||
&mut max_margin_length,
|
&mut max_margin_length,
|
||||||
@ -502,7 +506,8 @@ impl<V: View> Node<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layout
|
dbg!(self.id_string());
|
||||||
|
dbg!(layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,27 +554,6 @@ impl From<Length> for LeftRight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn align_child(
|
|
||||||
child_origin: &mut Vector2F,
|
|
||||||
parent_size: Vector2F,
|
|
||||||
child_size: Vector2F,
|
|
||||||
alignment: Vector2F,
|
|
||||||
horizontal: bool,
|
|
||||||
vertical: bool,
|
|
||||||
) {
|
|
||||||
let parent_center = parent_size / 2.;
|
|
||||||
let parent_target = parent_center + parent_center * alignment;
|
|
||||||
let child_center = child_size / 2.;
|
|
||||||
let child_target = child_center + child_center * alignment;
|
|
||||||
|
|
||||||
if horizontal {
|
|
||||||
child_origin.set_x(child_origin.x() + parent_target.x() - child_target.x())
|
|
||||||
}
|
|
||||||
if vertical {
|
|
||||||
child_origin.set_y(child_origin.y() + parent_target.y() - child_target.y());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Interactive<Style> {
|
struct Interactive<Style> {
|
||||||
default: Style,
|
default: Style,
|
||||||
hovered: Style,
|
hovered: Style,
|
||||||
@ -581,7 +565,7 @@ struct Interactive<Style> {
|
|||||||
pub struct NodeStyle {
|
pub struct NodeStyle {
|
||||||
axis: Axis3d,
|
axis: Axis3d,
|
||||||
wrap: bool,
|
wrap: bool,
|
||||||
align: Align,
|
align: Alignment,
|
||||||
overflow_x: Overflow,
|
overflow_x: Overflow,
|
||||||
overflow_y: Overflow,
|
overflow_y: Overflow,
|
||||||
gap_x: Gap,
|
gap_x: Gap,
|
||||||
@ -697,6 +681,18 @@ impl<T> Edges<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Edges<T> {
|
||||||
|
pub fn set_x(&mut self, value: T) {
|
||||||
|
self.left = value.clone();
|
||||||
|
self.right = value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_y(&mut self, value: T) {
|
||||||
|
self.top = value.clone();
|
||||||
|
self.bottom = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Edges<f32> {
|
impl Edges<f32> {
|
||||||
fn size(&self) -> Vector2F {
|
fn size(&self) -> Vector2F {
|
||||||
vec2f(self.left + self.right, self.top + self.bottom)
|
vec2f(self.left + self.right, self.top + self.bottom)
|
||||||
@ -838,18 +834,18 @@ struct CornerRadii {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Fill {
|
pub enum Fill {
|
||||||
Color(Color),
|
Color(Rgba),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Color> for Fill {
|
impl<C: Into<Rgba>> From<C> for Fill {
|
||||||
fn from(value: Color) -> Self {
|
fn from(value: C) -> Self {
|
||||||
Fill::Color(value)
|
Fill::Color(value.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Fill {
|
impl Default for Fill {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Fill::Color(Color::default())
|
Fill::Color(Rgba::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1028,10 +1024,10 @@ pub mod length {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Deref, DerefMut)]
|
||||||
struct Align(Vector2F);
|
struct Alignment(Vector2F);
|
||||||
|
|
||||||
impl Default for Align {
|
impl Default for Alignment {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(vec2f(-1., -1.))
|
Self(vec2f(-1., -1.))
|
||||||
}
|
}
|
||||||
@ -1251,8 +1247,6 @@ impl<V: View> Element<V> for Text {
|
|||||||
_: &mut V,
|
_: &mut V,
|
||||||
cx: &mut PaintContext<V>,
|
cx: &mut PaintContext<V>,
|
||||||
) -> Self::PaintState {
|
) -> Self::PaintState {
|
||||||
dbg!(bounds);
|
|
||||||
|
|
||||||
let mut origin = bounds.origin();
|
let mut origin = bounds.origin();
|
||||||
let empty = Vec::new();
|
let empty = Vec::new();
|
||||||
let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {};
|
let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {};
|
||||||
@ -1466,7 +1460,7 @@ trait ElementExt<V: View> {
|
|||||||
where
|
where
|
||||||
Self: Element<V> + Sized,
|
Self: Element<V> + Sized,
|
||||||
{
|
{
|
||||||
node(self).margin_left(margin_left)
|
column().child(self).margin_left(margin_left)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1479,6 +1473,76 @@ where
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
node(self).margin_left(margin_left)
|
column().child(self).margin_left(margin_left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view<F, E>(mut function: F) -> ViewFn
|
||||||
|
where
|
||||||
|
F: 'static + FnMut(&mut ViewContext<ViewFn>) -> E,
|
||||||
|
E: Element<ViewFn>,
|
||||||
|
{
|
||||||
|
ViewFn(Box::new(move |cx| (function)(cx).into_any()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ViewFn(Box<dyn FnMut(&mut ViewContext<ViewFn>) -> AnyElement<ViewFn>>);
|
||||||
|
|
||||||
|
impl Entity for ViewFn {
|
||||||
|
type Event = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for ViewFn {
|
||||||
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||||
|
(self.0)(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::themes::rose_pine::{self, RosePineThemes};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
length::{auto, rems},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
use gpui::TestAppContext;
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn test_layout(cx: &mut TestAppContext) {
|
||||||
|
let view = cx
|
||||||
|
.add_window(|_| {
|
||||||
|
view(|_| {
|
||||||
|
let theme = rose_pine::dawn();
|
||||||
|
column()
|
||||||
|
.width(auto())
|
||||||
|
.height(auto())
|
||||||
|
.justify(1.)
|
||||||
|
.child(
|
||||||
|
row()
|
||||||
|
.width(auto())
|
||||||
|
.height(rems(10.))
|
||||||
|
.fill(theme.foam)
|
||||||
|
.justify(1.)
|
||||||
|
.child(row().width(rems(10.)).height(auto()).fill(theme.gold)),
|
||||||
|
)
|
||||||
|
.child(row())
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.1;
|
||||||
|
|
||||||
|
// tree.layout(
|
||||||
|
// SizeConstraint::strict(vec2f(100., 100.)),
|
||||||
|
// &mut (),
|
||||||
|
// LayoutContext::test(),
|
||||||
|
// );
|
||||||
|
|
||||||
|
// LayoutContext::new(
|
||||||
|
// cx,
|
||||||
|
// new_parents,
|
||||||
|
// views_to_notify_if_ancestors_change,
|
||||||
|
// refreshing,
|
||||||
|
// )
|
||||||
|
|
||||||
|
// tree.layout(SizeConstraint::strict(vec2f(100., 100.)), &mut (), cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,21 @@
|
|||||||
use gpui::{color::Color, AnyElement, Element, LayoutContext, View, ViewContext};
|
use gpui::{AnyElement, Element, LayoutContext, View, ViewContext};
|
||||||
use node::{
|
use node::{length::auto, *};
|
||||||
length::{auto, rems},
|
|
||||||
*,
|
|
||||||
};
|
|
||||||
use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc};
|
use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc};
|
||||||
use tokens::{margin::m4, text::lg};
|
use tokens::{margin::m4, text::lg};
|
||||||
|
|
||||||
|
mod color;
|
||||||
mod node;
|
mod node;
|
||||||
|
mod themes;
|
||||||
mod tokens;
|
mod tokens;
|
||||||
|
|
||||||
#[derive(Element, Clone, Default)]
|
#[derive(Element, Clone, Default)]
|
||||||
pub struct Playground<V: View>(PhantomData<V>);
|
pub struct Playground<V: View>(PhantomData<V>);
|
||||||
|
|
||||||
|
impl<V: View> Node<V> {}
|
||||||
|
|
||||||
impl<V: View> Playground<V> {
|
impl<V: View> Playground<V> {
|
||||||
pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> AnyElement<V> {
|
pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> impl Element<V> {
|
||||||
row()
|
column()
|
||||||
.id("green row")
|
|
||||||
.width(auto())
|
|
||||||
.height(rems(20.))
|
|
||||||
.fill(Color::green())
|
|
||||||
// .child(
|
|
||||||
// row()
|
|
||||||
// .id("blue box")
|
|
||||||
// .width(rems(20.))
|
|
||||||
// .height(auto())
|
|
||||||
// .margin_left(auto())
|
|
||||||
// .fill(Color::blue()),
|
|
||||||
// )
|
|
||||||
// .into_any()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
crates/gpui/playground/ui/src/themes.rs
Normal file
1
crates/gpui/playground/ui/src/themes.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod rose_pine;
|
86
crates/gpui/playground/ui/src/themes/rose_pine.rs
Normal file
86
crates/gpui/playground/ui/src/themes/rose_pine.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
use crate::color::{rgb, Rgba};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct ThemeColors {
|
||||||
|
pub base: Rgba,
|
||||||
|
pub surface: Rgba,
|
||||||
|
pub overlay: Rgba,
|
||||||
|
pub muted: Rgba,
|
||||||
|
pub subtle: Rgba,
|
||||||
|
pub text: Rgba,
|
||||||
|
pub love: Rgba,
|
||||||
|
pub gold: Rgba,
|
||||||
|
pub rose: Rgba,
|
||||||
|
pub pine: Rgba,
|
||||||
|
pub foam: Rgba,
|
||||||
|
pub iris: Rgba,
|
||||||
|
pub highlight_low: Rgba,
|
||||||
|
pub highlight_med: Rgba,
|
||||||
|
pub highlight_high: Rgba,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RosePineThemes {
|
||||||
|
pub default: ThemeColors,
|
||||||
|
pub dawn: ThemeColors,
|
||||||
|
pub moon: ThemeColors,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default() -> ThemeColors {
|
||||||
|
ThemeColors {
|
||||||
|
base: rgb(0x191724),
|
||||||
|
surface: rgb(0x1f1d2e),
|
||||||
|
overlay: rgb(0x26233a),
|
||||||
|
muted: rgb(0x6e6a86),
|
||||||
|
subtle: rgb(0x908caa),
|
||||||
|
text: rgb(0xe0def4),
|
||||||
|
love: rgb(0xeb6f92),
|
||||||
|
gold: rgb(0xf6c177),
|
||||||
|
rose: rgb(0xebbcba),
|
||||||
|
pine: rgb(0x31748f),
|
||||||
|
foam: rgb(0x9ccfd8),
|
||||||
|
iris: rgb(0xc4a7e7),
|
||||||
|
highlight_low: rgb(0x21202e),
|
||||||
|
highlight_med: rgb(0x403d52),
|
||||||
|
highlight_high: rgb(0x524f67),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn moon() -> ThemeColors {
|
||||||
|
ThemeColors {
|
||||||
|
base: rgb(0x232136),
|
||||||
|
surface: rgb(0x2a273f),
|
||||||
|
overlay: rgb(0x393552),
|
||||||
|
muted: rgb(0x6e6a86),
|
||||||
|
subtle: rgb(0x908caa),
|
||||||
|
text: rgb(0xe0def4),
|
||||||
|
love: rgb(0xeb6f92),
|
||||||
|
gold: rgb(0xf6c177),
|
||||||
|
rose: rgb(0xea9a97),
|
||||||
|
pine: rgb(0x3e8fb0),
|
||||||
|
foam: rgb(0x9ccfd8),
|
||||||
|
iris: rgb(0xc4a7e7),
|
||||||
|
highlight_low: rgb(0x2a283e),
|
||||||
|
highlight_med: rgb(0x44415a),
|
||||||
|
highlight_high: rgb(0x56526e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dawn() -> ThemeColors {
|
||||||
|
ThemeColors {
|
||||||
|
base: rgb(0xfaf4ed),
|
||||||
|
surface: rgb(0xfffaf3),
|
||||||
|
overlay: rgb(0xf2e9e1),
|
||||||
|
muted: rgb(0x9893a5),
|
||||||
|
subtle: rgb(0x797593),
|
||||||
|
text: rgb(0x575279),
|
||||||
|
love: rgb(0xb4637a),
|
||||||
|
gold: rgb(0xea9d34),
|
||||||
|
rose: rgb(0xd7827e),
|
||||||
|
pine: rgb(0x286983),
|
||||||
|
foam: rgb(0x56949f),
|
||||||
|
iris: rgb(0x907aa9),
|
||||||
|
highlight_low: rgb(0xf4ede8),
|
||||||
|
highlight_med: rgb(0xdfdad9),
|
||||||
|
highlight_high: rgb(0xcecacd),
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,13 @@
|
|||||||
pub mod color {}
|
pub mod color {
|
||||||
|
use crate::color::{scale, ColorScale, Hsla};
|
||||||
|
|
||||||
|
pub fn ramp(color: impl Into<Hsla>) -> ColorScale {
|
||||||
|
let color = color.into();
|
||||||
|
let end_color = color.desaturate(0.1).brighten(0.5);
|
||||||
|
let start_color = color.desaturate(0.1).darken(0.4);
|
||||||
|
scale([start_color, color, end_color])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod text {
|
pub mod text {
|
||||||
use crate::node::length::{rems, Rems};
|
use crate::node::length::{rems, Rems};
|
||||||
|
@ -42,7 +42,7 @@ pub use test_app_context::{ContextHandle, TestAppContext};
|
|||||||
use window_input_handler::WindowInputHandler;
|
use window_input_handler::WindowInputHandler;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
elements::{AnyElement, AnyRootElement, RootElement},
|
elements::{AnyElement, AnyRootElement, Empty, RootElement},
|
||||||
executor::{self, Task},
|
executor::{self, Task},
|
||||||
fonts::TextStyle,
|
fonts::TextStyle,
|
||||||
json,
|
json,
|
||||||
@ -53,7 +53,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
util::post_inc,
|
util::post_inc,
|
||||||
window::{Window, WindowContext},
|
window::{Window, WindowContext},
|
||||||
AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId,
|
AssetCache, AssetSource, ClipboardItem, Element, FontCache, MouseRegionId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::ref_counts::RefCounts;
|
use self::ref_counts::RefCounts;
|
||||||
@ -71,10 +71,12 @@ pub trait Entity: 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait View: Entity + Sized {
|
pub trait View: Entity + Sized {
|
||||||
fn ui_name() -> &'static str;
|
|
||||||
fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> AnyElement<Self>;
|
fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> AnyElement<Self>;
|
||||||
fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
|
fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
|
||||||
fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
|
fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
|
||||||
|
fn ui_name() -> &'static str {
|
||||||
|
type_name::<Self>()
|
||||||
|
}
|
||||||
fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext<Self>) -> bool {
|
fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext<Self>) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -125,6 +127,16 @@ pub trait View: Entity + Sized {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Entity for () {
|
||||||
|
type Event = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for () {
|
||||||
|
fn render(&mut self, _: &mut ViewContext<'_, '_, Self>) -> AnyElement<Self> {
|
||||||
|
Empty::new().into_any()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait BorrowAppContext {
|
pub trait BorrowAppContext {
|
||||||
fn read_with<T, F: FnOnce(&AppContext) -> T>(&self, f: F) -> T;
|
fn read_with<T, F: FnOnce(&AppContext) -> T>(&self, f: F) -> T;
|
||||||
fn update<T, F: FnOnce(&mut AppContext) -> T>(&mut self, f: F) -> T;
|
fn update<T, F: FnOnce(&mut AppContext) -> T>(&mut self, f: F) -> T;
|
||||||
@ -3364,7 +3376,7 @@ impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LayoutContext<'a, 'b, 'c, V: View> {
|
pub struct LayoutContext<'a, 'b, 'c, V> {
|
||||||
view_context: &'c mut ViewContext<'a, 'b, V>,
|
view_context: &'c mut ViewContext<'a, 'b, V>,
|
||||||
new_parents: &'c mut HashMap<usize, usize>,
|
new_parents: &'c mut HashMap<usize, usize>,
|
||||||
views_to_notify_if_ancestors_change: &'c mut HashMap<usize, SmallVec<[usize; 2]>>,
|
views_to_notify_if_ancestors_change: &'c mut HashMap<usize, SmallVec<[usize; 2]>>,
|
||||||
|
@ -161,6 +161,19 @@ impl TestAppContext {
|
|||||||
(window_id, view)
|
(window_id, view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_window2<T, F>(&mut self, build_root_view: F) -> WindowHandle<T>
|
||||||
|
where
|
||||||
|
T: View,
|
||||||
|
F: FnOnce(&mut ViewContext<T>) -> T,
|
||||||
|
{
|
||||||
|
let (window_id, view) = self
|
||||||
|
.cx
|
||||||
|
.borrow_mut()
|
||||||
|
.add_window(Default::default(), build_root_view);
|
||||||
|
self.simulate_window_activation(Some(window_id));
|
||||||
|
(window_id, view)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
|
pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
|
||||||
where
|
where
|
||||||
T: View,
|
T: View,
|
||||||
|
@ -141,6 +141,12 @@ impl<'de> Deserialize<'de> for Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<u32> for Color {
|
||||||
|
fn from(value: u32) -> Self {
|
||||||
|
Self(ColorU::from_u32(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToJson for Color {
|
impl ToJson for Color {
|
||||||
fn to_json(&self) -> serde_json::Value {
|
fn to_json(&self) -> serde_json::Value {
|
||||||
json!(format!(
|
json!(format!(
|
||||||
|
@ -201,7 +201,7 @@ pub trait Element<V: View>: 'static {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait AnyElementState<V: View> {
|
trait AnyElementState<V> {
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
constraint: SizeConstraint,
|
constraint: SizeConstraint,
|
||||||
|
@ -325,7 +325,7 @@ pub fn element_derive(input: TokenStream) -> TokenStream {
|
|||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut gpui::LayoutContext<V>,
|
cx: &mut gpui::LayoutContext<V>,
|
||||||
) -> (gpui::geometry::vector::Vector2F, gpui::elements::AnyElement<V>) {
|
) -> (gpui::geometry::vector::Vector2F, gpui::elements::AnyElement<V>) {
|
||||||
let mut element = self.render(view, cx);
|
let mut element = self.render(view, cx).into_any();
|
||||||
let size = element.layout(constraint, view, cx);
|
let size = element.layout(constraint, view, cx);
|
||||||
(size, element)
|
(size, element)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user