mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 06:03:35 +03:00
Ditch the hot reloading approach
This commit is contained in:
parent
0bf607cd2d
commit
d6eaa3c6b8
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -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;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
#[derive(Element, Clone)]
|
||||
pub struct Playground<V: 'static>(PhantomData<V>);
|
||||
|
||||
impl<V> Playground<V> {
|
||||
pub fn new() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
|
||||
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 View for Playground {
|
||||
fn ui_name() -> &'static str {
|
||||
"PlaygroundView"
|
||||
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
|
||||
}
|
||||
|
||||
fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> AnyElement<Playground> {
|
||||
self.0.clone().into_any()
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user