Detailed changes
@@ -5291,24 +5291,13 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
name = "playground"
version = "0.1.0"
dependencies = [
- "gpui",
- "log",
- "playground_ui",
- "simplelog",
-]
-
-[[package]]
-name = "playground_ui"
-version = "0.1.0"
-dependencies = [
- "collections",
"derive_more",
"gpui",
"log",
"optional_struct",
"serde",
+ "simplelog",
"smallvec",
- "util",
]
[[package]]
@@ -29,7 +29,6 @@ members = [
"crates/go_to_line",
"crates/gpui",
"crates/gpui/playground",
- "crates/gpui/playground/ui",
"crates/gpui_macros",
"crates/install_cli",
"crates/journal",
@@ -8,11 +8,13 @@ version = "0.1.0"
edition = "2021"
[dependencies]
-playground_ui = { path = "ui" }
-
+derive_more.workspace = true
gpui = { path = ".." }
log.workspace = true
+optional_struct = "0.3.1"
+serde.workspace = true
simplelog = "0.9"
+smallvec.workspace = true
[dev-dependencies]
gpui = { path = "..", features = ["test-support"] }
@@ -35,6 +35,12 @@ impl Lerp for Range<Hsla> {
}
}
+impl From<gpui::color::Color> for Rgba {
+ fn from(value: gpui::color::Color) -> Self {
+ todo!()
+ }
+}
+
impl From<Hsla> for Rgba {
fn from(color: Hsla) -> Self {
let h = color.h;
@@ -88,7 +94,7 @@ impl Into<gpui::color::Color> for Rgba {
}
}
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Hsla {
pub h: f32,
pub s: f32,
@@ -97,7 +103,12 @@ pub struct Hsla {
}
pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
- Hsla { h, s, l, a }
+ Hsla {
+ h: h.clamp(0., 1.),
+ s: s.clamp(0., 1.),
+ l: l.clamp(0., 1.),
+ a: a.clamp(0., 1.),
+ }
}
impl From<Rgba> for Hsla {
@@ -182,6 +193,12 @@ impl Hsla {
}
}
+impl From<gpui::color::Color> for Hsla {
+ fn from(value: gpui::color::Color) -> Self {
+ Rgba::from(value).into()
+ }
+}
+
pub struct ColorScale {
colors: SmallVec<[Hsla; 2]>,
positions: SmallVec<[f32; 2]>,
@@ -1,10 +1,9 @@
#![allow(unused_variables, dead_code)]
use derive_more::{Add, Deref, DerefMut};
-use gpui::elements::layout_highlighted_chunks;
-use gpui::Entity;
use gpui::{
color::Color,
+ elements::layout_highlighted_chunks,
fonts::HighlightStyle,
geometry::{
rect::RectF,
@@ -14,15 +13,17 @@ use gpui::{
scene,
serde_json::Value,
text_layout::{Line, ShapedBoundary},
- AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder,
- SizeConstraint, View, ViewContext,
+ AnyElement, AppContext, Element, Entity, LayoutContext, PaintContext, Quad, SceneBuilder,
+ SizeConstraint, View, ViewContext, WindowContext,
};
use length::{Length, Rems};
use log::warn;
use optional_struct::*;
use std::{any::Any, borrow::Cow, f32, ops::Range, sync::Arc};
-use crate::color::Rgba;
+use crate::color::{Hsla, Rgba};
+
+use self::length::rems;
pub struct Frame<V> {
style: FrameStyle,
@@ -76,6 +77,12 @@ impl<V: 'static> Element<V> for Frame<V> {
view: &mut V,
cx: &mut LayoutContext<V>,
) -> (Vector2F, Self::LayoutState) {
+ if self.style.text.is_some() {
+ let mut style = TextStyle::from_legacy(&cx.text_style(), cx);
+ self.style.text.clone().apply_to(&mut style);
+ cx.push_text_style(style.to_legacy());
+ }
+
let layout = if let Some(axis) = self.style.axis.to_2d() {
self.layout_xy(axis, constraint, cx.rem_pixels(), view, cx)
} else {
@@ -263,6 +270,11 @@ impl<V: 'static> Frame<V> {
self
}
+ pub fn text_color(mut self, color: Hsla) -> Self {
+ self.style.text.color = Some(color);
+ self
+ }
+
pub fn margins(mut self, margins: impl Into<Edges<Length>>) -> Self {
self.style.margins = margins.into();
self
@@ -327,6 +339,8 @@ impl<V: 'static> Frame<V> {
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 {
@@ -608,8 +622,67 @@ struct TextStyle {
font_family: Arc<str>,
weight: FontWeight,
style: FontStyle,
+ color: Hsla,
}
+impl TextStyle {
+ fn from_legacy(text_style: &gpui::fonts::TextStyle, _cx: &WindowContext) -> Self {
+ Self {
+ size: rems(text_style.font_size / 16.), // TODO: Get this from the context!
+ font_family: text_style.font_family_name.clone(),
+ weight: text_style.font_properties.weight.into(),
+ style: text_style.font_properties.style.into(),
+ color: text_style.color.into(),
+ }
+ }
+
+ fn to_legacy(&self, cx: &WindowContext) -> Result<gpui::fonts::TextStyle> {
+ let font_family_id = cx.font_cache().load_family(
+ &[self.font_family.as_ref()],
+ &gpui::fonts::Features::default(),
+ )?;
+ let font_properties = gpui::fonts::Properties {
+ style: self.style.into(),
+ weight: self.weight.into(),
+ stretch: Default::default(),
+ };
+ let font_id = cx
+ .font_cache()
+ .select_font(font_family_id, &font_properties);
+
+ Ok(gpui::fonts::TextStyle {
+ color: self.color.into(),
+ font_family_name: self.font_family.clone(),
+ font_family_id,
+ font_id,
+ font_size: todo!(),
+ font_properties,
+ underline: todo!(),
+ soft_wrap: true,
+ })
+ }
+}
+
+impl OptionalTextStyle {
+ pub fn is_some(&self) -> bool {
+ self.size.is_some()
+ && self.font_family.is_some()
+ && self.weight.is_some()
+ && self.style.is_some()
+ && self.color.is_some()
+ }
+}
+
+// pub color: Color,
+// pub font_family_name: Arc<str>,
+// pub font_family_id: FamilyId,
+// pub font_id: FontId,
+// pub font_size: f32,
+// #[schemars(with = "PropertiesDef")]
+// pub font_properties: Properties,
+// pub underline: Underline,
+// pub soft_wrap: bool,
+
#[derive(Add, Default, Clone)]
pub struct Size<T> {
width: T,
@@ -1126,6 +1199,18 @@ enum FontStyle {
Oblique,
}
+impl From<gpui::fonts::Style> for FontStyle {
+ fn from(value: gpui::fonts::Style) -> Self {
+ use gpui::fonts::Style;
+
+ match value {
+ Style::Normal => FontStyle::Normal,
+ Style::Italic => FontStyle::Italic,
+ Style::Oblique => FontStyle::Oblique,
+ }
+ }
+}
+
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
enum FontWeight {
Thin,
@@ -1140,6 +1225,24 @@ enum FontWeight {
Black,
}
+impl From<gpui::fonts::Weight> for FontWeight {
+ fn from(value: gpui::fonts::Weight) -> Self {
+ use gpui::fonts::Weight;
+
+ match value {
+ Weight::THIN => FontWeight::Thin,
+ Weight::EXTRA_LIGHT => FontWeight::ExtraLight,
+ Weight::LIGHT => FontWeight::Light,
+ Weight::NORMAL => FontWeight::Normal,
+ Weight::MEDIUM => FontWeight::Medium,
+ Weight::SEMIBOLD => FontWeight::Semibold,
+ Weight::BOLD => FontWeight::Bold,
+ Weight::EXTRA_BOLD => FontWeight::ExtraBold,
+ Weight::BLACK => FontWeight::Black,
+ }
+ }
+}
+
#[derive(Default)]
pub struct Text {
text: Cow<'static, str>,
@@ -1,17 +1,11 @@
+#![allow(dead_code, unused_variables)]
+
use gpui::{
platform::{TitlebarOptions, WindowOptions},
- AnyElement, Element, Entity, View,
+ AnyElement, Element,
};
use log::LevelFilter;
use simplelog::SimpleLogger;
-use std::ops::{Deref, DerefMut};
-
-// dymod! {
-// #[path = "../ui/src/playground_ui.rs"]
-// pub mod ui {
-// // fn workspace<V>(theme: &ThemeColors) -> impl Element<V>;
-// }
-// }
fn main() {
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
@@ -26,38 +20,213 @@ fn main() {
}),
..Default::default()
},
- |_| Playground::default(),
+ |_| view(|_| Playground::new()),
);
});
}
-#[derive(Clone, Default)]
-struct Playground(playground_ui::Playground<Self>);
+use frame::{length::auto, *};
+use gpui::{LayoutContext, ViewContext};
+use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc};
+use themes::{rose_pine, ThemeColors};
+use tokens::{margin::m4, text::lg};
-impl Deref for Playground {
- type Target = playground_ui::Playground<Self>;
+mod color;
+mod frame;
+mod themes;
+mod tokens;
+
+#[derive(Element, Clone)]
+pub struct Playground<V: 'static>(PhantomData<V>);
+
+impl<V> Playground<V> {
+ pub fn new() -> Self {
+ Self(PhantomData)
+ }
- fn deref(&self) -> &Self::Target {
- &self.0
+ pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> impl Element<V> {
+ workspace(&rose_pine::dawn())
}
}
-impl DerefMut for Playground {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
+fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
+ column()
+ .size(auto())
+ .fill(theme.base(0.5))
+ .text_color(theme.text(0.5))
+ .child(title_bar(theme))
+ .child(stage(theme))
+ .child(status_bar(theme))
+}
+
+fn title_bar<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
+ row()
+ .fill(theme.base(0.2))
+ .justify(0.)
+ .width(auto())
+ .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 Entity for Playground {
- type Event = ();
+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
+ }
}
-impl View for Playground {
- fn ui_name() -> &'static str {
- "PlaygroundView"
+#[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> {
+// active: bool,
+// }
+
+// impl<V> Tab<V>
+// where
+// 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,
+ }
}
+}
- fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> AnyElement<Playground> {
- self.0.clone().into_any()
+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()
}
}
@@ -1,22 +0,0 @@
-[package]
-name = "playground_ui"
-version = "0.1.0"
-edition = "2021"
-
-[lib]
-name = "playground_ui"
-path = "src/playground_ui.rs"
-crate-type = ["dylib"]
-
-[dependencies]
-collections = { path = "../../../collections" }
-util = { path = "../../../util" }
-gpui = { path = "../.." }
-derive_more = "0.99.17"
-log.workspace = true
-optional_struct = "0.3.1"
-smallvec.workspace = true
-serde.workspace = true
-
-[dev-dependencies]
-gpui = { path = "../..", features = ["test-support"] }
@@ -1,200 +0,0 @@
-#![allow(dead_code, unused_variables)]
-
-use frame::{length::auto, *};
-use gpui::{AnyElement, Element, LayoutContext, ViewContext};
-use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc};
-use themes::{rose_pine, ThemeColors};
-use tokens::{margin::m4, text::lg};
-
-mod color;
-mod frame;
-mod themes;
-mod tokens;
-
-#[derive(Element, Clone, Default)]
-pub struct Playground<V: 'static>(PhantomData<V>);
-
-impl<V> Frame<V> {}
-
-impl<V> Playground<V> {
- pub fn render(&mut self, _: &mut V, _: &mut gpui::ViewContext<V>) -> impl Element<V> {
- workspace(&rose_pine::dawn())
- }
-}
-
-fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
- column()
- .size(auto())
- .fill(theme.base(0.1))
- .child(title_bar(theme))
- .child(stage(theme))
- .child(status_bar(theme))
-}
-
-fn title_bar<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
- row().fill(theme.surface(1.0))
-}
-
-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> {
-// active: bool,
-// }
-
-// impl<V> Tab<V>
-// where
-// 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()
- }
-}
@@ -3440,14 +3440,22 @@ impl<'a, 'b, 'c, V> LayoutContext<'a, 'b, 'c, V> {
.unwrap_or(Arc::new(TextStyle::default(&self.font_cache)))
}
+ pub fn push_text_style<S: Into<Arc<TextStyle>>>(&mut self, style: S) {
+ self.text_style_stack.push(style.into());
+ }
+
+ pub fn pop_text_style(&mut self) {
+ self.text_style_stack.pop();
+ }
+
pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T
where
S: Into<Arc<TextStyle>>,
F: FnOnce(&mut Self) -> T,
{
- self.text_style_stack.push(style.into());
+ self.push_text_style(style);
let result = f(self);
- self.text_style_stack.pop();
+ self.pop_text_style();
result
}
}
@@ -15,7 +15,7 @@ use serde_json::json;
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, JsonSchema)]
#[repr(transparent)]
-pub struct Color(#[schemars(with = "String")] ColorU);
+pub struct Color(#[schemars(with = "String")] pub ColorU);
pub fn color(rgba: u32) -> Color {
Color::from_u32(rgba)