Detailed changes
@@ -5194,26 +5194,6 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
-[[package]]
-name = "playground"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "derive_more",
- "gpui",
- "gpui2_macros",
- "log",
- "parking_lot 0.11.2",
- "refineable",
- "rust-embed",
- "serde",
- "settings",
- "simplelog",
- "smallvec",
- "theme",
- "util",
-]
-
[[package]]
name = "plist"
version = "1.5.0"
@@ -7320,6 +7300,21 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+[[package]]
+name = "storybook"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "gpui2",
+ "log",
+ "rust-embed",
+ "serde",
+ "settings",
+ "simplelog",
+ "theme",
+ "util",
+]
+
[[package]]
name = "stringprep"
version = "0.1.3"
@@ -32,7 +32,6 @@ members = [
"crates/git",
"crates/go_to_line",
"crates/gpui",
- "crates/gpui/playground",
"crates/gpui_macros",
"crates/gpui2",
"crates/gpui2_macros",
@@ -64,6 +63,7 @@ members = [
"crates/sqlez",
"crates/sqlez_macros",
"crates/feature_flags",
+ "crates/storybook",
"crates/sum_tree",
"crates/terminal",
"crates/text",
@@ -1,28 +0,0 @@
-[package]
-name = "playground"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-[[bin]]
-name = "playground"
-path = "src/playground.rs"
-
-[dependencies]
-anyhow.workspace = true
-derive_more.workspace = true
-gpui = { path = ".." }
-log.workspace = true
-gpui2_macros = { path = "../../gpui2_macros" }
-parking_lot.workspace = true
-refineable.workspace = true
-rust-embed.workspace = true
-serde.workspace = true
-settings = { path = "../../settings" }
-simplelog = "0.9"
-smallvec.workspace = true
-theme = { path = "../../theme" }
-util = { path = "../../util" }
-
-[dev-dependencies]
-gpui = { path = "..", features = ["test-support"] }
@@ -1,78 +0,0 @@
-use crate::{layout_context::LayoutContext, paint_context::PaintContext};
-use gpui::{geometry::rect::RectF, LayoutEngine, LayoutId};
-use util::ResultExt;
-
-/// Makes a new, playground-style element into a legacy element.
-pub struct AdapterElement<V>(pub(crate) crate::element::AnyElement<V>);
-
-impl<V: 'static> gpui::Element<V> for AdapterElement<V> {
- type LayoutState = Option<(LayoutEngine, LayoutId)>;
- type PaintState = ();
-
- fn layout(
- &mut self,
- constraint: gpui::SizeConstraint,
- view: &mut V,
- cx: &mut gpui::LayoutContext<V>,
- ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
- cx.push_layout_engine(LayoutEngine::new());
-
- let size = constraint.max;
- let mut cx = LayoutContext::new(cx);
- let layout_id = self.0.layout(view, &mut cx).log_err();
- if let Some(layout_id) = layout_id {
- cx.layout_engine()
- .unwrap()
- .compute_layout(layout_id, constraint.max)
- .log_err();
- }
-
- let layout_engine = cx.pop_layout_engine();
- debug_assert!(layout_engine.is_some(),
- "unexpected layout stack state. is there an unmatched pop_layout_engine in the called code?"
- );
-
- (constraint.max, layout_engine.zip(layout_id))
- }
-
- fn paint(
- &mut self,
- scene: &mut gpui::SceneBuilder,
- bounds: RectF,
- visible_bounds: RectF,
- layout_data: &mut Option<(LayoutEngine, LayoutId)>,
- view: &mut V,
- legacy_cx: &mut gpui::PaintContext<V>,
- ) -> Self::PaintState {
- let (layout_engine, layout_id) = layout_data.take().unwrap();
- legacy_cx.push_layout_engine(layout_engine);
- let mut cx = PaintContext::new(legacy_cx, scene);
- self.0.paint(view, bounds.origin(), &mut cx);
- *layout_data = legacy_cx.pop_layout_engine().zip(Some(layout_id));
- debug_assert!(layout_data.is_some());
- }
-
- fn rect_for_text_range(
- &self,
- range_utf16: std::ops::Range<usize>,
- bounds: RectF,
- visible_bounds: RectF,
- layout: &Self::LayoutState,
- paint: &Self::PaintState,
- view: &V,
- cx: &gpui::ViewContext<V>,
- ) -> Option<RectF> {
- todo!("implement before merging to main")
- }
-
- fn debug(
- &self,
- bounds: RectF,
- layout: &Self::LayoutState,
- paint: &Self::PaintState,
- view: &V,
- cx: &gpui::ViewContext<V>,
- ) -> gpui::serde_json::Value {
- todo!("implement before merging to main")
- }
-}
@@ -1,101 +0,0 @@
-use crate::{
- div::div,
- element::{IntoElement, ParentElement},
- interactive::Interactive,
- style::StyleHelpers,
- text::ArcCow,
- // themes::Theme,
-};
-use gpui::{platform::MouseButton, ViewContext};
-use gpui2_macros::Element;
-use std::{marker::PhantomData, rc::Rc};
-
-struct ButtonHandlers<V, D> {
- click: Option<Rc<dyn Fn(&mut V, &D, &mut ViewContext<V>)>>,
-}
-
-impl<V, D> Default for ButtonHandlers<V, D> {
- fn default() -> Self {
- Self { click: None }
- }
-}
-
-use crate as gpui2;
-#[derive(Element)]
-pub struct Button<V: 'static, D: 'static> {
- handlers: ButtonHandlers<V, D>,
- label: Option<ArcCow<'static, str>>,
- icon: Option<ArcCow<'static, str>>,
- data: Rc<D>,
- view_type: PhantomData<V>,
-}
-
-// Impl block for buttons without data.
-// See below for an impl block for any button.
-impl<V: 'static> Button<V, ()> {
- fn new() -> Self {
- Self {
- handlers: ButtonHandlers::default(),
- label: None,
- icon: None,
- data: Rc::new(()),
- view_type: PhantomData,
- }
- }
-
- pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
- Button {
- handlers: ButtonHandlers::default(),
- label: self.label,
- icon: self.icon,
- data: Rc::new(data),
- view_type: PhantomData,
- }
- }
-}
-
-// Impl block for button regardless of its data type.
-impl<V: 'static, D: 'static> Button<V, D> {
- pub fn label(mut self, label: impl Into<ArcCow<'static, str>>) -> Self {
- self.label = Some(label.into());
- self
- }
-
- pub fn icon(mut self, icon: impl Into<ArcCow<'static, str>>) -> Self {
- self.icon = Some(icon.into());
- self
- }
-
- pub fn on_click(mut self, handler: impl Fn(&mut V, &D, &mut ViewContext<V>) + 'static) -> Self {
- self.handlers.click = Some(Rc::new(handler));
- self
- }
-}
-
-pub fn button<V>() -> Button<V, ()> {
- Button::new()
-}
-
-impl<V: 'static, D: 'static> Button<V, D> {
- fn render(
- &mut self,
- view: &mut V,
- cx: &mut ViewContext<V>,
- ) -> impl IntoElement<V> + Interactive<V> {
- // let colors = &cx.theme::<Theme>().colors;
-
- let button = div()
- // .fill(colors.error(0.5))
- .h_4()
- .children(self.label.clone());
-
- if let Some(handler) = self.handlers.click.clone() {
- let data = self.data.clone();
- button.on_mouse_down(MouseButton::Left, move |view, event, cx| {
- handler(view, data.as_ref(), cx)
- })
- } else {
- button
- }
- }
-}
@@ -1,116 +0,0 @@
-use crate::{
- element::{AnyElement, Element, IntoElement, Layout, ParentElement},
- interactive::{InteractionHandlers, Interactive},
- layout_context::LayoutContext,
- paint_context::PaintContext,
- style::{Style, StyleHelpers, Styleable},
-};
-use anyhow::Result;
-use gpui::{LayoutId, RenderContext};
-use refineable::{Refineable, RefinementCascade};
-use smallvec::SmallVec;
-
-pub struct Div<V: 'static> {
- styles: RefinementCascade<Style>,
- handlers: InteractionHandlers<V>,
- children: SmallVec<[AnyElement<V>; 2]>,
-}
-
-pub fn div<V>() -> Div<V> {
- Div {
- styles: Default::default(),
- handlers: Default::default(),
- children: Default::default(),
- }
-}
-
-impl<V: 'static> Element<V> for Div<V> {
- type PaintState = ();
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> Result<(LayoutId, Self::PaintState)>
- where
- Self: Sized,
- {
- let style = self.computed_style();
- let pop_text_style = style.text_style().map_or(false, |style| {
- cx.push_text_style(cx.text_style().clone().refined(&style));
- true
- });
-
- let children = self
- .children
- .iter_mut()
- .map(|child| child.layout(view, cx))
- .collect::<Result<Vec<LayoutId>>>()?;
-
- if pop_text_style {
- cx.pop_text_style();
- }
-
- Ok((cx.add_layout_node(style, children)?, ()))
- }
-
- fn paint(
- &mut self,
- view: &mut V,
- layout: &Layout,
- paint_state: &mut Self::PaintState,
- cx: &mut PaintContext<V>,
- ) where
- Self: Sized,
- {
- let style = &self.computed_style();
- let pop_text_style = style.text_style().map_or(false, |style| {
- let style = cx.text_style().clone().refined(&style);
- cx.push_text_style(style);
- true
- });
- style.paint_background(layout.bounds, cx);
- self.interaction_handlers()
- .paint(layout.order, layout.bounds, cx);
- for child in &mut self.children {
- child.paint(view, layout.bounds.origin(), cx);
- }
- if pop_text_style {
- cx.pop_text_style();
- }
- }
-}
-
-impl<V> Styleable for Div<V> {
- type Style = Style;
-
- fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
- &mut self.styles
- }
-
- fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
- self.styles.base()
- }
-}
-
-impl<V> StyleHelpers for Div<V> {}
-
-impl<V> Interactive<V> for Div<V> {
- fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
- &mut self.handlers
- }
-}
-
-impl<V: 'static> ParentElement<V> for Div<V> {
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
- &mut self.children
- }
-}
-
-impl<V: 'static> IntoElement<V> for Div<V> {
- type Element = Self;
-
- fn into_element(self) -> Self::Element {
- self
- }
-}
@@ -1,170 +0,0 @@
-use std::marker::PhantomData;
-
-pub use crate::layout_context::LayoutContext;
-pub use crate::paint_context::PaintContext;
-use crate::themes::{Theme, Themed};
-use anyhow::Result;
-use gpui::geometry::vector::Vector2F;
-pub use gpui::{Layout, LayoutId};
-use smallvec::SmallVec;
-
-pub trait Element<V: 'static>: 'static {
- type PaintState;
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> Result<(LayoutId, Self::PaintState)>
- where
- Self: Sized;
-
- fn paint(
- &mut self,
- view: &mut V,
- layout: &Layout,
- state: &mut Self::PaintState,
- cx: &mut PaintContext<V>,
- ) where
- Self: Sized;
-
- fn into_any(self) -> AnyElement<V>
- where
- Self: 'static + Sized,
- {
- AnyElement(Box::new(StatefulElement {
- element: self,
- phase: ElementPhase::Init,
- }))
- }
-
- fn themed(self, theme: Theme) -> Themed<V, Self>
- where
- Self: Sized,
- {
- crate::themes::Themed {
- child: self,
- theme,
- view_type: PhantomData,
- }
- }
-}
-
-/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
-trait AnyStatefulElement<V> {
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId>;
- fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>);
-}
-
-/// A wrapper around an element that stores its layout state.
-struct StatefulElement<V: 'static, E: Element<V>> {
- element: E,
- phase: ElementPhase<V, E>,
-}
-
-enum ElementPhase<V: 'static, E: Element<V>> {
- Init,
- PostLayout {
- layout_id: LayoutId,
- paint_state: E::PaintState,
- },
- PostPaint {
- layout: Layout,
- paint_state: E::PaintState,
- },
- Error(String),
-}
-
-impl<V: 'static, E: Element<V>> Default for ElementPhase<V, E> {
- fn default() -> Self {
- Self::Init
- }
-}
-
-/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
-impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
- let result;
- self.phase = match self.element.layout(view, cx) {
- Ok((layout_id, paint_state)) => {
- result = Ok(layout_id);
- ElementPhase::PostLayout {
- layout_id,
- paint_state,
- }
- }
- Err(error) => {
- let message = error.to_string();
- result = Err(error);
- ElementPhase::Error(message)
- }
- };
- result
- }
-
- fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>) {
- self.phase = match std::mem::take(&mut self.phase) {
- ElementPhase::PostLayout {
- layout_id,
- mut paint_state,
- } => match cx.computed_layout(layout_id) {
- Ok(mut layout) => {
- layout.bounds = layout.bounds + parent_origin;
- self.element.paint(view, &layout, &mut paint_state, cx);
- ElementPhase::PostPaint {
- layout,
- paint_state,
- }
- }
- Err(error) => ElementPhase::Error(error.to_string()),
- },
- phase @ ElementPhase::Error(_) => phase,
- _ => panic!("invalid element phase to call paint"),
- };
- }
-}
-
-/// A dynamic element.
-pub struct AnyElement<V>(Box<dyn AnyStatefulElement<V>>);
-
-impl<V> AnyElement<V> {
- pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
- self.0.layout(view, cx)
- }
-
- pub fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>) {
- self.0.paint(view, parent_origin, cx)
- }
-}
-
-pub trait ParentElement<V: 'static> {
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
-
- fn child(mut self, child: impl IntoElement<V>) -> Self
- where
- Self: Sized,
- {
- self.children_mut().push(child.into_element().into_any());
- self
- }
-
- fn children<I, E>(mut self, children: I) -> Self
- where
- I: IntoIterator<Item = E>,
- E: IntoElement<V>,
- Self: Sized,
- {
- self.children_mut().extend(
- children
- .into_iter()
- .map(|child| child.into_element().into_any()),
- );
- self
- }
-}
-
-pub trait IntoElement<V: 'static> {
- type Element: Element<V>;
-
- fn into_element(self) -> Self::Element;
-}
@@ -1,104 +0,0 @@
-use crate::{
- element::{AnyElement, Element, IntoElement, Layout, ParentElement},
- interactive::{InteractionHandlers, Interactive},
- layout_context::LayoutContext,
- paint_context::PaintContext,
- style::{Style, StyleHelpers, Styleable},
-};
-use anyhow::Result;
-use gpui::{platform::MouseMovedEvent, LayoutId};
-use refineable::{CascadeSlot, Refineable, RefinementCascade};
-use smallvec::SmallVec;
-use std::{cell::Cell, rc::Rc};
-
-pub struct Hoverable<E: Styleable> {
- hovered: Rc<Cell<bool>>,
- cascade_slot: CascadeSlot,
- hovered_style: <E::Style as Refineable>::Refinement,
- child: E,
-}
-
-pub fn hoverable<E: Styleable>(mut child: E) -> Hoverable<E> {
- Hoverable {
- hovered: Rc::new(Cell::new(false)),
- cascade_slot: child.style_cascade().reserve(),
- hovered_style: Default::default(),
- child,
- }
-}
-
-impl<E: Styleable> Styleable for Hoverable<E> {
- type Style = E::Style;
-
- fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
- self.child.style_cascade()
- }
-
- fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
- &mut self.hovered_style
- }
-}
-
-impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
- type PaintState = E::PaintState;
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> Result<(LayoutId, Self::PaintState)>
- where
- Self: Sized,
- {
- Ok(self.child.layout(view, cx)?)
- }
-
- fn paint(
- &mut self,
- view: &mut V,
- layout: &Layout,
- paint_state: &mut Self::PaintState,
- cx: &mut PaintContext<V>,
- ) where
- Self: Sized,
- {
- self.hovered
- .set(layout.bounds.contains_point(cx.mouse_position()));
-
- let slot = self.cascade_slot;
- let style = self.hovered.get().then_some(self.hovered_style.clone());
- self.style_cascade().set(slot, style);
-
- let hovered = self.hovered.clone();
- let bounds = layout.bounds;
- cx.on_event(layout.order, move |view, event: &MouseMovedEvent, cx| {
- if bounds.contains_point(cx.mouse_position()) != hovered.get() {
- cx.repaint();
- }
- });
-
- self.child.paint(view, layout, paint_state, cx);
- }
-}
-
-impl<E: Styleable<Style = Style>> StyleHelpers for Hoverable<E> {}
-
-impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Hoverable<E> {
- fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
- self.child.interaction_handlers()
- }
-}
-
-impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Hoverable<E> {
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
- self.child.children_mut()
- }
-}
-
-impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Hoverable<E> {
- type Element = Self;
-
- fn into_element(self) -> Self::Element {
- self
- }
-}
@@ -1,147 +0,0 @@
-use gpui::{
- geometry::rect::RectF,
- platform::{MouseButton, MouseButtonEvent},
- EventContext,
-};
-use smallvec::SmallVec;
-use std::{cell::Cell, rc::Rc};
-
-use crate::element::PaintContext;
-
-pub trait Interactive<V: 'static> {
- fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V>;
-
- fn on_mouse_down(
- mut self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.interaction_handlers()
- .mouse_down
- .push(Rc::new(handler));
- self
- }
-
- fn on_mouse_up(
- mut self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.interaction_handlers().mouse_up.push(Rc::new(handler));
- self
- }
-
- fn on_mouse_down_out(
- mut self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.interaction_handlers()
- .mouse_down_out
- .push(Rc::new(handler));
- self
- }
-
- fn on_mouse_up_out(
- mut self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.interaction_handlers()
- .mouse_up_out
- .push(Rc::new(handler));
- self
- }
-
- fn on_click(
- self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- let pressed = Rc::new(Cell::new(false));
- self.on_mouse_down(button, {
- let pressed = pressed.clone();
- move |_, _, _| {
- pressed.set(true);
- }
- })
- .on_mouse_up_out(button, {
- let pressed = pressed.clone();
- move |_, _, _| {
- pressed.set(false);
- }
- })
- .on_mouse_up(button, move |view, event, cx| {
- if pressed.get() {
- pressed.set(false);
- handler(view, event, cx);
- }
- })
- }
-}
-
-pub struct InteractionHandlers<V: 'static> {
- mouse_down: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
- mouse_down_out: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
- mouse_up: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
- mouse_up_out: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
-}
-
-impl<V: 'static> InteractionHandlers<V> {
- pub fn paint(&self, order: u32, bounds: RectF, cx: &mut PaintContext<V>) {
- for handler in self.mouse_down.iter().cloned() {
- cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
- if event.is_down && bounds.contains_point(event.position) {
- handler(view, event, cx);
- }
- })
- }
- for handler in self.mouse_up.iter().cloned() {
- cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
- if !event.is_down && bounds.contains_point(event.position) {
- handler(view, event, cx);
- }
- })
- }
- for handler in self.mouse_down_out.iter().cloned() {
- cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
- if event.is_down && !bounds.contains_point(event.position) {
- handler(view, event, cx);
- }
- })
- }
- for handler in self.mouse_up_out.iter().cloned() {
- cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
- if !event.is_down && !bounds.contains_point(event.position) {
- handler(view, event, cx);
- }
- })
- }
- }
-}
-
-impl<V> Default for InteractionHandlers<V> {
- fn default() -> Self {
- Self {
- mouse_down: Default::default(),
- mouse_up: Default::default(),
- mouse_down_out: Default::default(),
- mouse_up_out: Default::default(),
- }
- }
-}
@@ -1,64 +0,0 @@
-use crate::{element::LayoutId, style::Style};
-use anyhow::{anyhow, Result};
-use derive_more::{Deref, DerefMut};
-use gpui::{geometry::Size, MeasureParams, RenderContext, ViewContext};
-pub use gpui::{taffy::tree::NodeId, LayoutContext as LegacyLayoutContext};
-
-#[derive(Deref, DerefMut)]
-pub struct LayoutContext<'a, 'b, 'c, 'd, V> {
- #[deref]
- #[deref_mut]
- pub(crate) legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>,
-}
-
-impl<'a, 'b, V> RenderContext<'a, 'b, V> for LayoutContext<'a, 'b, '_, '_, V> {
- fn text_style(&self) -> gpui::fonts::TextStyle {
- self.legacy_cx.text_style()
- }
-
- fn push_text_style(&mut self, style: gpui::fonts::TextStyle) {
- self.legacy_cx.push_text_style(style)
- }
-
- fn pop_text_style(&mut self) {
- self.legacy_cx.pop_text_style()
- }
-
- fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
- &mut self.view_context
- }
-}
-
-impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> {
- pub fn new(legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>) -> Self {
- Self { legacy_cx }
- }
-
- pub fn add_layout_node(
- &mut self,
- style: Style,
- children: impl IntoIterator<Item = NodeId>,
- ) -> Result<LayoutId> {
- let rem_size = self.rem_pixels();
- let id = self
- .legacy_cx
- .layout_engine()
- .ok_or_else(|| anyhow!("no layout engine"))?
- .add_node(style.to_taffy(rem_size), children)?;
-
- Ok(id)
- }
-
- pub fn add_measured_layout_node<F>(&mut self, style: Style, measure: F) -> Result<LayoutId>
- where
- F: Fn(MeasureParams) -> Size<f32> + Sync + Send + 'static,
- {
- let rem_size = self.rem_pixels();
- let layout_id = self
- .layout_engine()
- .ok_or_else(|| anyhow!("no layout engine"))?
- .add_measured_node(style.to_taffy(rem_size), measure)?;
-
- Ok(layout_id)
- }
-}
@@ -1,54 +0,0 @@
-use anyhow::{anyhow, Result};
-use derive_more::{Deref, DerefMut};
-pub use gpui::taffy::tree::NodeId;
-use gpui::{
- scene::EventHandler, EventContext, Layout, LayoutId, PaintContext as LegacyPaintContext,
-};
-use std::{any::TypeId, rc::Rc};
-
-#[derive(Deref, DerefMut)]
-pub struct PaintContext<'a, 'b, 'c, 'd, V> {
- #[deref]
- #[deref_mut]
- pub(crate) legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
- pub(crate) scene: &'d mut gpui::SceneBuilder,
-}
-
-impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
- pub fn new(
- legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
- scene: &'d mut gpui::SceneBuilder,
- ) -> Self {
- Self { legacy_cx, scene }
- }
-
- pub fn on_event<E: 'static>(
- &mut self,
- order: u32,
- handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
- ) {
- let view = self.weak_handle();
-
- self.scene.event_handlers.push(EventHandler {
- order,
- handler: Rc::new(move |event, window_cx| {
- if let Some(view) = view.upgrade(window_cx) {
- view.update(window_cx, |view, view_cx| {
- let mut event_cx = EventContext::new(view_cx);
- handler(view, event.downcast_ref().unwrap(), &mut event_cx);
- event_cx.bubble
- })
- } else {
- true
- }
- }),
- event_type: TypeId::of::<E>(),
- })
- }
-
- pub(crate) fn computed_layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
- self.layout_engine()
- .ok_or_else(|| anyhow!("no layout engine present"))?
- .computed_layout(layout_id)
- }
-}
@@ -1,99 +0,0 @@
-#![allow(dead_code, unused_variables)]
-use crate::element::Element;
-use gpui::{
- geometry::{rect::RectF, vector::vec2f},
- platform::WindowOptions,
- serde_json, ViewContext,
-};
-use log::LevelFilter;
-use settings::{default_settings, SettingsStore};
-use simplelog::SimpleLogger;
-use theme::ThemeSettings;
-use themes::Theme;
-use view::view;
-use workspace::workspace;
-
-mod adapter;
-mod color;
-mod components;
-mod div;
-mod element;
-mod hoverable;
-mod interactive;
-mod layout_context;
-mod paint_context;
-mod pressable;
-mod style;
-mod text;
-mod themes;
-mod view;
-mod workspace;
-
-fn main() {
- SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
-
- gpui::App::new(()).unwrap().run(|cx| {
- let mut store = SettingsStore::default();
- store
- .set_default_settings(default_settings().as_ref(), cx)
- .unwrap();
- cx.set_global(store);
- theme::init(Assets, cx);
-
- cx.add_window(
- WindowOptions {
- bounds: gpui::platform::WindowBounds::Fixed(RectF::new(
- vec2f(0., 0.),
- vec2f(400., 300.),
- )),
- center: true,
- ..Default::default()
- },
- |_| view(|cx| playground(cx)),
- );
- cx.platform().activate(true);
- });
-}
-
-fn playground<V: 'static>(cx: &mut ViewContext<V>) -> impl Element<V> {
- workspace().themed(current_theme(cx))
-}
-
-// Nathan: During the transition, we will include the base theme on the legacy Theme struct.
-fn current_theme<V: 'static>(cx: &mut ViewContext<V>) -> Theme {
- settings::get::<ThemeSettings>(cx)
- .theme
- .deserialized_base_theme
- .lock()
- .get_or_insert_with(|| {
- let theme: Theme =
- serde_json::from_value(settings::get::<ThemeSettings>(cx).theme.base_theme.clone())
- .unwrap();
- Box::new(theme)
- })
- .downcast_ref::<Theme>()
- .unwrap()
- .clone()
-}
-
-use anyhow::{anyhow, Result};
-use gpui::AssetSource;
-use rust_embed::RustEmbed;
-
-#[derive(RustEmbed)]
-#[folder = "../../../assets"]
-#[include = "themes/**/*"]
-#[exclude = "*.DS_Store"]
-pub struct Assets;
-
-impl AssetSource for Assets {
- fn load(&self, path: &str) -> Result<std::borrow::Cow<[u8]>> {
- Self::get(path)
- .map(|f| f.data)
- .ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
- }
-
- fn list(&self, path: &str) -> Vec<std::borrow::Cow<'static, str>> {
- Self::iter().filter(|p| p.starts_with(path)).collect()
- }
-}
@@ -1,379 +0,0 @@
-use crate::{
- color::Hsla,
- hoverable::{hoverable, Hoverable},
- paint_context::PaintContext,
- pressable::{pressable, Pressable},
-};
-pub use gpui::taffy::style::{
- AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
- Overflow, Position,
-};
-use gpui::{
- fonts::TextStyleRefinement,
- geometry::{
- rect::RectF, relative, AbsoluteLength, DefiniteLength, Edges, EdgesRefinement, Length,
- Point, PointRefinement, Size, SizeRefinement,
- },
- taffy,
-};
-use gpui2_macros::styleable_helpers;
-use refineable::{Refineable, RefinementCascade};
-
-#[derive(Clone, Refineable)]
-pub struct Style {
- /// What layout strategy should be used?
- pub display: Display,
-
- // Overflow properties
- /// How children overflowing their container should affect layout
- #[refineable]
- pub overflow: Point<Overflow>,
- /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
- pub scrollbar_width: f32,
-
- // Position properties
- /// What should the `position` value of this struct use as a base offset?
- pub position: Position,
- /// How should the position of this element be tweaked relative to the layout defined?
- #[refineable]
- pub inset: Edges<Length>,
-
- // Size properies
- /// Sets the initial size of the item
- #[refineable]
- pub size: Size<Length>,
- /// Controls the minimum size of the item
- #[refineable]
- pub min_size: Size<Length>,
- /// Controls the maximum size of the item
- #[refineable]
- pub max_size: Size<Length>,
- /// Sets the preferred aspect ratio for the item. The ratio is calculated as width divided by height.
- pub aspect_ratio: Option<f32>,
-
- // Spacing Properties
- /// How large should the margin be on each side?
- #[refineable]
- pub margin: Edges<Length>,
- /// How large should the padding be on each side?
- #[refineable]
- pub padding: Edges<DefiniteLength>,
- /// How large should the border be on each side?
- #[refineable]
- pub border: Edges<DefiniteLength>,
-
- // Alignment properties
- /// How this node's children aligned in the cross/block axis?
- pub align_items: Option<AlignItems>,
- /// How this node should be aligned in the cross/block axis. Falls back to the parents [`AlignItems`] if not set
- pub align_self: Option<AlignSelf>,
- /// How should content contained within this item be aligned in the cross/block axis
- pub align_content: Option<AlignContent>,
- /// How should contained within this item be aligned in the main/inline axis
- pub justify_content: Option<JustifyContent>,
- /// How large should the gaps between items in a flex container be?
- #[refineable]
- pub gap: Size<DefiniteLength>,
-
- // Flexbox properies
- /// Which direction does the main axis flow in?
- pub flex_direction: FlexDirection,
- /// Should elements wrap, or stay in a single line?
- pub flex_wrap: FlexWrap,
- /// Sets the initial main axis size of the item
- pub flex_basis: Length,
- /// The relative rate at which this item grows when it is expanding to fill space, 0.0 is the default value, and this value must be positive.
- pub flex_grow: f32,
- /// The relative rate at which this item shrinks when it is contracting to fit into space, 1.0 is the default value, and this value must be positive.
- pub flex_shrink: f32,
-
- /// The fill color of this element
- pub fill: Option<Fill>,
- /// The radius of the corners of this element
- #[refineable]
- pub corner_radii: CornerRadii,
- /// The color of text within this element. Cascades to children unless overridden.
- pub text_color: Option<Hsla>,
-}
-
-impl Style {
- pub fn to_taffy(&self, rem_size: f32) -> taffy::style::Style {
- taffy::style::Style {
- display: self.display,
- overflow: self.overflow.clone().into(),
- scrollbar_width: self.scrollbar_width,
- position: self.position,
- inset: self.inset.to_taffy(rem_size),
- size: self.size.to_taffy(rem_size),
- min_size: self.min_size.to_taffy(rem_size),
- max_size: self.max_size.to_taffy(rem_size),
- aspect_ratio: self.aspect_ratio,
- margin: self.margin.to_taffy(rem_size),
- padding: self.padding.to_taffy(rem_size),
- border: self.border.to_taffy(rem_size),
- align_items: self.align_items,
- align_self: self.align_self,
- align_content: self.align_content,
- justify_content: self.justify_content,
- gap: self.gap.to_taffy(rem_size),
- flex_direction: self.flex_direction,
- flex_wrap: self.flex_wrap,
- flex_basis: self.flex_basis.to_taffy(rem_size).into(),
- flex_grow: self.flex_grow,
- flex_shrink: self.flex_shrink,
- ..Default::default() // Ignore grid properties for now
- }
- }
-
- /// Paints the background of an element styled with this style.
- /// Return the bounds in which to paint the content.
- pub fn paint_background<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
- let rem_size = cx.rem_pixels();
- if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
- cx.scene.push_quad(gpui::Quad {
- bounds,
- background: Some(color.into()),
- corner_radii: self.corner_radii.to_gpui(rem_size),
- border: Default::default(),
- });
- }
- }
-
- pub fn text_style(&self) -> Option<TextStyleRefinement> {
- if let Some(color) = self.text_color {
- Some(TextStyleRefinement {
- color: Some(color.into()),
- ..Default::default()
- })
- } else {
- None
- }
- }
-}
-
-impl Default for Style {
- fn default() -> Self {
- Style {
- display: Display::Block,
- overflow: Point {
- x: Overflow::Visible,
- y: Overflow::Visible,
- },
- scrollbar_width: 0.0,
- position: Position::Relative,
- inset: Edges::auto(),
- margin: Edges::<Length>::zero(),
- padding: Edges::<DefiniteLength>::zero(),
- border: Edges::<DefiniteLength>::zero(),
- size: Size::auto(),
- min_size: Size::auto(),
- max_size: Size::auto(),
- aspect_ratio: None,
- gap: Size::zero(),
- // Aligment
- align_items: None,
- align_self: None,
- align_content: None,
- justify_content: None,
- // Flexbox
- flex_direction: FlexDirection::Row,
- flex_wrap: FlexWrap::NoWrap,
- flex_grow: 0.0,
- flex_shrink: 1.0,
- flex_basis: Length::Auto,
- fill: None,
- text_color: None,
- corner_radii: CornerRadii::default(),
- }
- }
-}
-
-impl StyleRefinement {
- pub fn text_style(&self) -> Option<TextStyleRefinement> {
- self.text_color.map(|color| TextStyleRefinement {
- color: Some(color.into()),
- ..Default::default()
- })
- }
-}
-
-pub struct OptionalTextStyle {
- color: Option<Hsla>,
-}
-
-impl OptionalTextStyle {
- pub fn apply(&self, style: &mut gpui::fonts::TextStyle) {
- if let Some(color) = self.color {
- style.color = color.into();
- }
- }
-}
-
-#[derive(Clone, Debug)]
-pub enum Fill {
- Color(Hsla),
-}
-
-impl Fill {
- pub fn color(&self) -> Option<Hsla> {
- match self {
- Fill::Color(color) => Some(*color),
- }
- }
-}
-
-impl Default for Fill {
- fn default() -> Self {
- Self::Color(Hsla::default())
- }
-}
-
-impl From<Hsla> for Fill {
- fn from(color: Hsla) -> Self {
- Self::Color(color)
- }
-}
-
-#[derive(Clone, Refineable, Default)]
-pub struct CornerRadii {
- top_left: AbsoluteLength,
- top_right: AbsoluteLength,
- bottom_left: AbsoluteLength,
- bottom_right: AbsoluteLength,
-}
-
-impl CornerRadii {
- pub fn to_gpui(&self, rem_size: f32) -> gpui::scene::CornerRadii {
- gpui::scene::CornerRadii {
- top_left: self.top_left.to_pixels(rem_size),
- top_right: self.top_right.to_pixels(rem_size),
- bottom_left: self.bottom_left.to_pixels(rem_size),
- bottom_right: self.bottom_right.to_pixels(rem_size),
- }
- }
-}
-
-pub trait Styleable {
- type Style: Refineable + Default;
-
- fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
- fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
-
- fn computed_style(&mut self) -> Self::Style {
- Self::Style::from_refinement(&self.style_cascade().merged())
- }
-
- fn hovered(self) -> Hoverable<Self>
- where
- Self: Sized,
- {
- hoverable(self)
- }
-
- fn pressed(self) -> Pressable<Self>
- where
- Self: Sized,
- {
- pressable(self)
- }
-}
-
-// Helpers methods that take and return mut self. This includes tailwind style methods for standard sizes etc.
-//
-// Example:
-// // Sets the padding to 0.5rem, just like class="p-2" in Tailwind.
-// fn p_2(mut self) -> Self where Self: Sized;
-pub trait StyleHelpers: Styleable<Style = Style> {
- styleable_helpers!();
-
- fn h(mut self, height: Length) -> Self
- where
- Self: Sized,
- {
- self.declared_style().size.height = Some(height);
- self
- }
-
- fn full(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().size.width = Some(relative(1.));
- self.declared_style().size.height = Some(relative(1.));
- self
- }
-
- fn relative(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().position = Some(Position::Relative);
- self
- }
-
- fn absolute(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().position = Some(Position::Absolute);
- self
- }
-
- fn block(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().display = Some(Display::Block);
- self
- }
-
- fn flex(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().display = Some(Display::Flex);
- self
- }
-
- fn flex_col(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().flex_direction = Some(FlexDirection::Column);
- self
- }
-
- fn flex_row(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().flex_direction = Some(FlexDirection::Row);
- self
- }
-
- fn flex_grow(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().flex_grow = Some(1.);
- self
- }
-
- fn fill<F>(mut self, fill: F) -> Self
- where
- F: Into<Fill>,
- Self: Sized,
- {
- self.declared_style().fill = Some(fill.into());
- self
- }
-
- fn text_color<C>(mut self, color: C) -> Self
- where
- C: Into<Hsla>,
- Self: Sized,
- {
- self.declared_style().text_color = Some(color.into());
- self
- }
-}
@@ -1,175 +0,0 @@
-use crate::{
- color::Hsla,
- element::{Element, PaintContext},
- layout_context::LayoutContext,
-};
-use gpui::WindowContext;
-use serde::{de::Visitor, Deserialize, Deserializer};
-use std::{collections::HashMap, fmt, marker::PhantomData};
-
-#[derive(Deserialize, Clone, Default, Debug)]
-pub struct Theme {
- pub name: String,
- pub is_light: bool,
- pub lowest: Layer,
- pub middle: Layer,
- pub highest: Layer,
- pub popover_shadow: Shadow,
- pub modal_shadow: Shadow,
- #[serde(deserialize_with = "deserialize_player_colors")]
- pub players: Vec<PlayerColors>,
- #[serde(deserialize_with = "deserialize_syntax_colors")]
- pub syntax: HashMap<String, Hsla>,
-}
-
-#[derive(Deserialize, Clone, Default, Debug)]
-pub struct Layer {
- pub base: StyleSet,
- pub variant: StyleSet,
- pub on: StyleSet,
- pub accent: StyleSet,
- pub positive: StyleSet,
- pub warning: StyleSet,
- pub negative: StyleSet,
-}
-
-#[derive(Deserialize, Clone, Default, Debug)]
-pub struct StyleSet {
- #[serde(rename = "default")]
- pub default: ContainerColors,
- pub hovered: ContainerColors,
- pub pressed: ContainerColors,
- pub active: ContainerColors,
- pub disabled: ContainerColors,
- pub inverted: ContainerColors,
-}
-
-#[derive(Deserialize, Clone, Default, Debug)]
-pub struct ContainerColors {
- pub background: Hsla,
- pub foreground: Hsla,
- pub border: Hsla,
-}
-
-#[derive(Deserialize, Clone, Default, Debug)]
-pub struct PlayerColors {
- pub selection: Hsla,
- pub cursor: Hsla,
-}
-
-#[derive(Deserialize, Clone, Default, Debug)]
-pub struct Shadow {
- pub blur: u8,
- pub color: Hsla,
- pub offset: Vec<u8>,
-}
-
-pub fn theme<'a>(cx: &'a WindowContext) -> &'a Theme {
- cx.theme::<Theme>()
-}
-
-fn deserialize_player_colors<'de, D>(deserializer: D) -> Result<Vec<PlayerColors>, D::Error>
-where
- D: Deserializer<'de>,
-{
- struct PlayerArrayVisitor;
-
- impl<'de> Visitor<'de> for PlayerArrayVisitor {
- type Value = Vec<PlayerColors>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("an object with integer keys")
- }
-
- fn visit_map<A: serde::de::MapAccess<'de>>(
- self,
- mut map: A,
- ) -> Result<Self::Value, A::Error> {
- let mut players = Vec::with_capacity(8);
- while let Some((key, value)) = map.next_entry::<usize, PlayerColors>()? {
- if key < 8 {
- players.push(value);
- } else {
- return Err(serde::de::Error::invalid_value(
- serde::de::Unexpected::Unsigned(key as u64),
- &"a key in range 0..7",
- ));
- }
- }
- Ok(players)
- }
- }
-
- deserializer.deserialize_map(PlayerArrayVisitor)
-}
-
-fn deserialize_syntax_colors<'de, D>(deserializer: D) -> Result<HashMap<String, Hsla>, D::Error>
-where
- D: serde::Deserializer<'de>,
-{
- #[derive(Deserialize)]
- struct ColorWrapper {
- color: Hsla,
- }
-
- struct SyntaxVisitor;
-
- impl<'de> Visitor<'de> for SyntaxVisitor {
- type Value = HashMap<String, Hsla>;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("a map with keys and objects with a single color field as values")
- }
-
- fn visit_map<M>(self, mut map: M) -> Result<HashMap<String, Hsla>, M::Error>
- where
- M: serde::de::MapAccess<'de>,
- {
- let mut result = HashMap::new();
- while let Some(key) = map.next_key()? {
- let wrapper: ColorWrapper = map.next_value()?; // Deserialize values as Hsla
- result.insert(key, wrapper.color);
- }
- Ok(result)
- }
- }
- deserializer.deserialize_map(SyntaxVisitor)
-}
-
-pub struct Themed<V: 'static, E> {
- pub(crate) theme: Theme,
- pub(crate) child: E,
- pub(crate) view_type: PhantomData<V>,
-}
-
-impl<V: 'static, E: Element<V>> Element<V> for Themed<V, E> {
- type PaintState = E::PaintState;
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> anyhow::Result<(gpui::LayoutId, Self::PaintState)>
- where
- Self: Sized,
- {
- cx.push_theme(self.theme.clone());
- let result = self.child.layout(view, cx);
- cx.pop_theme();
- result
- }
-
- fn paint(
- &mut self,
- view: &mut V,
- layout: &gpui::Layout,
- state: &mut Self::PaintState,
- cx: &mut PaintContext<V>,
- ) where
- Self: Sized,
- {
- cx.push_theme(self.theme.clone());
- self.child.paint(view, layout, state, cx);
- cx.pop_theme();
- }
-}
@@ -1,133 +0,0 @@
-use std::ops::Range;
-
-use crate::{
- color::{hsla, rgb, Hsla},
- ThemeColors,
-};
-
-pub struct RosePineThemes {
- pub default: RosePinePalette,
- pub dawn: RosePinePalette,
- pub moon: RosePinePalette,
-}
-
-#[derive(Clone, Copy, Debug)]
-pub struct RosePinePalette {
- pub base: Hsla,
- pub surface: Hsla,
- pub overlay: Hsla,
- pub muted: Hsla,
- pub subtle: Hsla,
- pub text: Hsla,
- pub love: Hsla,
- pub gold: Hsla,
- pub rose: Hsla,
- pub pine: Hsla,
- pub foam: Hsla,
- pub iris: Hsla,
- pub highlight_low: Hsla,
- pub highlight_med: Hsla,
- pub highlight_high: Hsla,
-}
-
-impl RosePinePalette {
- pub fn default() -> RosePinePalette {
- RosePinePalette {
- 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() -> RosePinePalette {
- RosePinePalette {
- 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() -> RosePinePalette {
- RosePinePalette {
- 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),
- }
- }
-}
-
-pub fn default() -> ThemeColors {
- theme_colors(&RosePinePalette::default())
-}
-
-pub fn moon() -> ThemeColors {
- theme_colors(&RosePinePalette::moon())
-}
-
-pub fn dawn() -> ThemeColors {
- theme_colors(&RosePinePalette::dawn())
-}
-
-fn theme_colors(p: &RosePinePalette) -> ThemeColors {
- ThemeColors {
- base: scale_sl(p.base, (0.8, 0.8), (1.2, 1.2)),
- surface: scale_sl(p.surface, (0.8, 0.8), (1.2, 1.2)),
- overlay: scale_sl(p.overlay, (0.8, 0.8), (1.2, 1.2)),
- muted: scale_sl(p.muted, (0.8, 0.8), (1.2, 1.2)),
- subtle: scale_sl(p.subtle, (0.8, 0.8), (1.2, 1.2)),
- text: scale_sl(p.text, (0.8, 0.8), (1.2, 1.2)),
- highlight_low: scale_sl(p.highlight_low, (0.8, 0.8), (1.2, 1.2)),
- highlight_med: scale_sl(p.highlight_med, (0.8, 0.8), (1.2, 1.2)),
- highlight_high: scale_sl(p.highlight_high, (0.8, 0.8), (1.2, 1.2)),
- success: scale_sl(p.foam, (0.8, 0.8), (1.2, 1.2)),
- warning: scale_sl(p.gold, (0.8, 0.8), (1.2, 1.2)),
- error: scale_sl(p.love, (0.8, 0.8), (1.2, 1.2)),
- inserted: scale_sl(p.foam, (0.8, 0.8), (1.2, 1.2)),
- deleted: scale_sl(p.love, (0.8, 0.8), (1.2, 1.2)),
- modified: scale_sl(p.rose, (0.8, 0.8), (1.2, 1.2)),
- }
-}
-
-/// Produces a range by multiplying the saturation and lightness of the base color by the given
-/// start and end factors.
-fn scale_sl(base: Hsla, (start_s, start_l): (f32, f32), (end_s, end_l): (f32, f32)) -> Range<Hsla> {
- let start = hsla(base.h, base.s * start_s, base.l * start_l, base.a);
- let end = hsla(base.h, base.s * end_s, base.l * end_l, base.a);
- Range { start, end }
-}
@@ -1,26 +0,0 @@
-use crate::{
- adapter::AdapterElement,
- element::{AnyElement, Element},
-};
-use gpui::ViewContext;
-
-pub fn view<F, E>(mut render: F) -> ViewFn
-where
- F: 'static + FnMut(&mut ViewContext<ViewFn>) -> E,
- E: Element<ViewFn>,
-{
- ViewFn(Box::new(move |cx| (render)(cx).into_any()))
-}
-
-pub struct ViewFn(Box<dyn FnMut(&mut ViewContext<ViewFn>) -> AnyElement<ViewFn>>);
-
-impl gpui::Entity for ViewFn {
- type Event = ();
-}
-
-impl gpui::View for ViewFn {
- fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::AnyElement<Self> {
- use gpui::Element as _;
- AdapterElement((self.0)(cx)).into_any()
- }
-}
@@ -3459,7 +3459,7 @@ pub trait RenderContext<'a, 'b, V> {
}
pub struct LayoutContext<'a, 'b, 'c, V> {
- // Nathan: Making this is public while I work on playground.
+ // Nathan: Making this is public while I work on gpui2.
pub view_context: &'c mut ViewContext<'a, 'b, V>,
pub refreshing: bool,
}
@@ -31,7 +31,7 @@ pub struct SceneBuilder {
scale_factor: f32,
stacking_contexts: Vec<StackingContext>,
active_stacking_context_stack: Vec<usize>,
- /// Used by the playground crate.
+ /// Used by the gpui2 crate.
pub event_handlers: Vec<EventHandler>,
#[cfg(debug_assertions)]
mouse_region_ids: HashSet<MouseRegionId>,
@@ -8,6 +8,9 @@ publish = false
name = "gpui2"
path = "src/gpui2.rs"
+[features]
+test-support = ["gpui/test-support"]
+
[dependencies]
anyhow.workspace = true
derive_more.workspace = true
@@ -2,7 +2,7 @@ use crate::{layout_context::LayoutContext, paint_context::PaintContext};
use gpui::{geometry::rect::RectF, LayoutEngine, LayoutId};
use util::ResultExt;
-/// Makes a new, playground-style element into a legacy element.
+/// Makes a new, gpui2-style element into a legacy element.
pub struct AdapterElement<V>(pub(crate) crate::element::AnyElement<V>);
impl<V: 'static> gpui::Element<V> for AdapterElement<V> {
@@ -17,7 +17,6 @@ impl<V: 'static> gpui::Element<V> for AdapterElement<V> {
) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
cx.push_layout_engine(LayoutEngine::new());
- let size = constraint.max;
let mut cx = LayoutContext::new(cx);
let layout_id = self.0.layout(view, &mut cx).log_err();
if let Some(layout_id) = layout_id {
@@ -2,7 +2,6 @@ use std::marker::PhantomData;
pub use crate::layout_context::LayoutContext;
pub use crate::paint_context::PaintContext;
-use crate::themes::{Theme, Themed};
use anyhow::Result;
use gpui::geometry::vector::Vector2F;
pub use gpui::{Layout, LayoutId};
@@ -37,17 +36,6 @@ pub trait Element<V: 'static>: 'static {
phase: ElementPhase::Init,
}))
}
-
- fn themed(self, theme: Theme) -> Themed<V, Self>
- where
- Self: Sized,
- {
- crate::themes::Themed {
- child: self,
- theme,
- view_type: PhantomData,
- }
- }
}
/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
@@ -0,0 +1,6 @@
+pub mod div;
+pub mod hoverable;
+pub mod pressable;
+pub mod text;
+
+pub use div::div;
@@ -1,9 +1,9 @@
use crate::{
element::{AnyElement, Element, IntoElement, Layout, ParentElement},
- interactive::{InteractionHandlers, Interactive},
layout_context::LayoutContext,
paint_context::PaintContext,
style::{Style, StyleHelpers, Styleable},
+ InteractionHandlers, Interactive,
};
use anyhow::Result;
use gpui::{LayoutId, RenderContext};
@@ -58,7 +58,7 @@ impl<V: 'static> Element<V> for Div<V> {
&mut self,
view: &mut V,
layout: &Layout,
- paint_state: &mut Self::PaintState,
+ _: &mut Self::PaintState,
cx: &mut PaintContext<V>,
) where
Self: Sized,
@@ -71,7 +71,7 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
let hovered = self.hovered.clone();
let bounds = layout.bounds;
- cx.on_event(layout.order, move |view, event: &MouseMovedEvent, cx| {
+ cx.on_event(layout.order, move |_view, _: &MouseMovedEvent, cx| {
if bounds.contains_point(cx.mouse_position()) != hovered.get() {
cx.repaint();
}
@@ -68,7 +68,7 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
let pressed = self.pressed.clone();
let bounds = layout.bounds;
- cx.on_event(layout.order, move |view, event: &MouseButtonEvent, cx| {
+ cx.on_event(layout.order, move |_view, event: &MouseButtonEvent, cx| {
if event.is_down {
if bounds.contains_point(event.position) {
pressed.set(true);
@@ -25,10 +25,9 @@ impl<V: 'static> Element<V> for Text {
fn layout(
&mut self,
- view: &mut V,
+ _view: &mut V,
cx: &mut LayoutContext<V>,
) -> Result<(LayoutId, Self::PaintState)> {
- let rem_size = cx.rem_pixels();
let fonts = cx.platform().fonts();
let text_style = cx.text_style();
let line_height = cx.font_cache().line_height(text_style.font_size);
@@ -63,7 +62,7 @@ impl<V: 'static> Element<V> for Text {
fn paint<'a>(
&mut self,
- view: &mut V,
+ _view: &mut V,
layout: &Layout,
paint_state: &mut Self::PaintState,
cx: &mut PaintContext<V>,
@@ -1,36 +1,22 @@
-#![allow(dead_code, unused_variables)]
-use gpui::{serde_json, ViewContext};
-use theme::ThemeSettings;
-use themes::Theme;
+pub mod adapter;
+pub mod color;
+pub mod element;
+pub mod elements;
+pub mod interactive;
+pub mod layout_context;
+pub mod paint_context;
+pub mod style;
+pub mod view;
-mod adapter;
-mod color;
-mod components;
-mod div;
-mod element;
-mod hoverable;
-mod interactive;
-mod layout_context;
-mod paint_context;
-mod pressable;
-mod style;
-mod text;
-mod themes;
-mod view;
-
-// Nathan: During the transition, we will include the base theme on the legacy Theme struct.
-fn current_theme<V: 'static>(cx: &mut ViewContext<V>) -> Theme {
- settings::get::<ThemeSettings>(cx)
- .theme
- .deserialized_base_theme
- .lock()
- .get_or_insert_with(|| {
- let theme: Theme =
- serde_json::from_value(settings::get::<ThemeSettings>(cx).theme.base_theme.clone())
- .unwrap();
- Box::new(theme)
- })
- .downcast_ref::<Theme>()
- .unwrap()
- .clone()
-}
+pub use color::*;
+pub use element::{AnyElement, Element, IntoElement, Layout, ParentElement};
+pub use geometry::{
+ rect::RectF,
+ vector::{vec2f, Vector2F},
+};
+pub use gpui::*;
+pub use gpui2_macros::{Element, *};
+pub use interactive::*;
+pub use layout_context::LayoutContext;
+pub use platform::{WindowBounds, WindowOptions};
+pub use view::*;
@@ -21,7 +21,11 @@ pub trait Interactive<V: 'static> {
{
self.interaction_handlers()
.mouse_down
- .push(Rc::new(handler));
+ .push(Rc::new(move |view, event, cx| {
+ if event.button == button {
+ handler(view, event, cx)
+ }
+ }));
self
}
@@ -33,7 +37,13 @@ pub trait Interactive<V: 'static> {
where
Self: Sized,
{
- self.interaction_handlers().mouse_up.push(Rc::new(handler));
+ self.interaction_handlers()
+ .mouse_up
+ .push(Rc::new(move |view, event, cx| {
+ if event.button == button {
+ handler(view, event, cx)
+ }
+ }));
self
}
@@ -47,7 +57,11 @@ pub trait Interactive<V: 'static> {
{
self.interaction_handlers()
.mouse_down_out
- .push(Rc::new(handler));
+ .push(Rc::new(move |view, event, cx| {
+ if event.button == button {
+ handler(view, event, cx)
+ }
+ }));
self
}
@@ -61,7 +75,11 @@ pub trait Interactive<V: 'static> {
{
self.interaction_handlers()
.mouse_up_out
- .push(Rc::new(handler));
+ .push(Rc::new(move |view, event, cx| {
+ if event.button == button {
+ handler(view, event, cx)
+ }
+ }));
self
}
@@ -1,107 +0,0 @@
-use crate::{
- element::{AnyElement, Element, IntoElement, Layout, ParentElement},
- interactive::{InteractionHandlers, Interactive},
- layout_context::LayoutContext,
- paint_context::PaintContext,
- style::{Style, StyleHelpers, Styleable},
-};
-use anyhow::Result;
-use gpui::{platform::MouseButtonEvent, LayoutId};
-use refineable::{CascadeSlot, Refineable, RefinementCascade};
-use smallvec::SmallVec;
-use std::{cell::Cell, rc::Rc};
-
-pub struct Pressable<E: Styleable> {
- pressed: Rc<Cell<bool>>,
- pressed_style: <E::Style as Refineable>::Refinement,
- cascade_slot: CascadeSlot,
- child: E,
-}
-
-pub fn pressable<E: Styleable>(mut child: E) -> Pressable<E> {
- Pressable {
- pressed: Rc::new(Cell::new(false)),
- pressed_style: Default::default(),
- cascade_slot: child.style_cascade().reserve(),
- child,
- }
-}
-
-impl<E: Styleable> Styleable for Pressable<E> {
- type Style = E::Style;
-
- fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
- &mut self.pressed_style
- }
-
- fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
- self.child.style_cascade()
- }
-}
-
-impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
- type PaintState = E::PaintState;
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> Result<(LayoutId, Self::PaintState)>
- where
- Self: Sized,
- {
- self.child.layout(view, cx)
- }
-
- fn paint(
- &mut self,
- view: &mut V,
- layout: &Layout,
- paint_state: &mut Self::PaintState,
- cx: &mut PaintContext<V>,
- ) where
- Self: Sized,
- {
- let slot = self.cascade_slot;
- let style = self.pressed.get().then_some(self.pressed_style.clone());
- self.style_cascade().set(slot, style);
-
- let pressed = self.pressed.clone();
- let bounds = layout.bounds;
- cx.on_event(layout.order, move |view, event: &MouseButtonEvent, cx| {
- if event.is_down {
- if bounds.contains_point(event.position) {
- pressed.set(true);
- cx.repaint();
- }
- } else if pressed.get() {
- pressed.set(false);
- cx.repaint();
- }
- });
-
- self.child.paint(view, layout, paint_state, cx);
- }
-}
-
-impl<E: Styleable<Style = Style>> StyleHelpers for Pressable<E> {}
-
-impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
- fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
- self.child.interaction_handlers()
- }
-}
-
-impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Pressable<E> {
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
- self.child.children_mut()
- }
-}
-
-impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
- type Element = Self;
-
- fn into_element(self) -> Self::Element {
- self
- }
-}
@@ -1,8 +1,8 @@
use crate::{
color::Hsla,
- hoverable::{hoverable, Hoverable},
+ elements::hoverable::{hoverable, Hoverable},
+ elements::pressable::{pressable, Pressable},
paint_context::PaintContext,
- pressable::{pressable, Pressable},
};
pub use gpui::taffy::style::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
@@ -1,148 +0,0 @@
-use crate::{
- element::{Element, IntoElement, Layout},
- layout_context::LayoutContext,
- paint_context::PaintContext,
-};
-use anyhow::Result;
-use gpui::{geometry::Size, text_layout::LineLayout, LayoutId, RenderContext};
-use parking_lot::Mutex;
-use std::sync::Arc;
-
-impl<V: 'static, S: Into<ArcCow<'static, str>>> IntoElement<V> for S {
- type Element = Text;
-
- fn into_element(self) -> Self::Element {
- Text { text: self.into() }
- }
-}
-
-pub struct Text {
- text: ArcCow<'static, str>,
-}
-
-impl<V: 'static> Element<V> for Text {
- type PaintState = Arc<Mutex<Option<TextLayout>>>;
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> Result<(LayoutId, Self::PaintState)> {
- let rem_size = cx.rem_pixels();
- let fonts = cx.platform().fonts();
- let text_style = cx.text_style();
- let line_height = cx.font_cache().line_height(text_style.font_size);
- let text = self.text.clone();
- let paint_state = Arc::new(Mutex::new(None));
-
- let layout_id = cx.add_measured_layout_node(Default::default(), {
- let paint_state = paint_state.clone();
- move |params| {
- let line_layout = fonts.layout_line(
- text.as_ref(),
- text_style.font_size,
- &[(text.len(), text_style.to_run())],
- );
-
- let size = Size {
- width: line_layout.width,
- height: line_height,
- };
-
- paint_state.lock().replace(TextLayout {
- line_layout: Arc::new(line_layout),
- line_height,
- });
-
- size
- }
- });
-
- Ok((layout_id?, paint_state))
- }
-
- fn paint<'a>(
- &mut self,
- view: &mut V,
- layout: &Layout,
- paint_state: &mut Self::PaintState,
- cx: &mut PaintContext<V>,
- ) {
- let line_layout;
- let line_height;
- {
- let paint_state = paint_state.lock();
- let paint_state = paint_state
- .as_ref()
- .expect("measurement has not been performed");
- line_layout = paint_state.line_layout.clone();
- line_height = paint_state.line_height;
- }
-
- let text_style = cx.text_style();
- let line =
- gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]);
-
- let origin = layout.bounds.origin();
- // TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
- let visible_bounds = layout.bounds;
- line.paint(cx.scene, origin, visible_bounds, line_height, cx.legacy_cx);
- }
-}
-
-pub struct TextLayout {
- line_layout: Arc<LineLayout>,
- line_height: f32,
-}
-
-pub enum ArcCow<'a, T: ?Sized> {
- Borrowed(&'a T),
- Owned(Arc<T>),
-}
-
-impl<'a, T: ?Sized> Clone for ArcCow<'a, T> {
- fn clone(&self) -> Self {
- match self {
- Self::Borrowed(borrowed) => Self::Borrowed(borrowed),
- Self::Owned(owned) => Self::Owned(owned.clone()),
- }
- }
-}
-
-impl<'a, T: ?Sized> From<&'a T> for ArcCow<'a, T> {
- fn from(s: &'a T) -> Self {
- Self::Borrowed(s)
- }
-}
-
-impl<T> From<Arc<T>> for ArcCow<'_, T> {
- fn from(s: Arc<T>) -> Self {
- Self::Owned(s)
- }
-}
-
-impl From<String> for ArcCow<'_, str> {
- fn from(value: String) -> Self {
- Self::Owned(value.into())
- }
-}
-
-impl<T: ?Sized> std::ops::Deref for ArcCow<'_, T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- match self {
- ArcCow::Borrowed(s) => s,
- ArcCow::Owned(s) => s.as_ref(),
- }
- }
-}
-
-impl<T: ?Sized> AsRef<T> for ArcCow<'_, T> {
- fn as_ref(&self) -> &T {
- match self {
- ArcCow::Borrowed(borrowed) => borrowed,
- ArcCow::Owned(owned) => owned.as_ref(),
- }
- }
-}
@@ -1,133 +0,0 @@
-use std::ops::Range;
-
-use crate::{
- color::{hsla, rgb, Hsla},
- ThemeColors,
-};
-
-pub struct RosePineThemes {
- pub default: RosePinePalette,
- pub dawn: RosePinePalette,
- pub moon: RosePinePalette,
-}
-
-#[derive(Clone, Copy, Debug)]
-pub struct RosePinePalette {
- pub base: Hsla,
- pub surface: Hsla,
- pub overlay: Hsla,
- pub muted: Hsla,
- pub subtle: Hsla,
- pub text: Hsla,
- pub love: Hsla,
- pub gold: Hsla,
- pub rose: Hsla,
- pub pine: Hsla,
- pub foam: Hsla,
- pub iris: Hsla,
- pub highlight_low: Hsla,
- pub highlight_med: Hsla,
- pub highlight_high: Hsla,
-}
-
-impl RosePinePalette {
- pub fn default() -> RosePinePalette {
- RosePinePalette {
- 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() -> RosePinePalette {
- RosePinePalette {
- 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() -> RosePinePalette {
- RosePinePalette {
- 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),
- }
- }
-}
-
-pub fn default() -> ThemeColors {
- theme_colors(&RosePinePalette::default())
-}
-
-pub fn moon() -> ThemeColors {
- theme_colors(&RosePinePalette::moon())
-}
-
-pub fn dawn() -> ThemeColors {
- theme_colors(&RosePinePalette::dawn())
-}
-
-fn theme_colors(p: &RosePinePalette) -> ThemeColors {
- ThemeColors {
- base: scale_sl(p.base, (0.8, 0.8), (1.2, 1.2)),
- surface: scale_sl(p.surface, (0.8, 0.8), (1.2, 1.2)),
- overlay: scale_sl(p.overlay, (0.8, 0.8), (1.2, 1.2)),
- muted: scale_sl(p.muted, (0.8, 0.8), (1.2, 1.2)),
- subtle: scale_sl(p.subtle, (0.8, 0.8), (1.2, 1.2)),
- text: scale_sl(p.text, (0.8, 0.8), (1.2, 1.2)),
- highlight_low: scale_sl(p.highlight_low, (0.8, 0.8), (1.2, 1.2)),
- highlight_med: scale_sl(p.highlight_med, (0.8, 0.8), (1.2, 1.2)),
- highlight_high: scale_sl(p.highlight_high, (0.8, 0.8), (1.2, 1.2)),
- success: scale_sl(p.foam, (0.8, 0.8), (1.2, 1.2)),
- warning: scale_sl(p.gold, (0.8, 0.8), (1.2, 1.2)),
- error: scale_sl(p.love, (0.8, 0.8), (1.2, 1.2)),
- inserted: scale_sl(p.foam, (0.8, 0.8), (1.2, 1.2)),
- deleted: scale_sl(p.love, (0.8, 0.8), (1.2, 1.2)),
- modified: scale_sl(p.rose, (0.8, 0.8), (1.2, 1.2)),
- }
-}
-
-/// Produces a range by multiplying the saturation and lightness of the base color by the given
-/// start and end factors.
-fn scale_sl(base: Hsla, (start_s, start_l): (f32, f32), (end_s, end_l): (f32, f32)) -> Range<Hsla> {
- let start = hsla(base.h, base.s * start_s, base.l * start_l, base.a);
- let end = hsla(base.h, base.s * end_s, base.l * end_l, base.a);
- Range { start, end }
-}
@@ -1686,7 +1686,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
-name = "playground"
+name = "storybook"
version = "0.1.0"
dependencies = [
"gpui",
@@ -0,0 +1,23 @@
+[package]
+name = "storybook"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[[bin]]
+name = "storybook"
+path = "src/storybook.rs"
+
+[dependencies]
+gpui2 = { path = "../gpui2" }
+anyhow.workspace = true
+log.workspace = true
+rust-embed.workspace = true
+serde.workspace = true
+settings = { path = "../settings" }
+simplelog = "0.9"
+theme = { path = "../theme" }
+util = { path = "../util" }
+
+[dev-dependencies]
+gpui2 = { path = "../gpui2", features = ["test-support"] }
@@ -1,13 +1,7 @@
-use crate::{
- div::div,
- element::{IntoElement, ParentElement},
- interactive::Interactive,
- style::StyleHelpers,
- text::ArcCow,
- // themes::Theme,
+use gpui2::{
+ elements::div, elements::text::ArcCow, interactive::Interactive, platform::MouseButton,
+ style::StyleHelpers, Element, IntoElement, ParentElement, ViewContext,
};
-use gpui::{platform::MouseButton, ViewContext};
-use gpui2_macros::Element;
use std::{marker::PhantomData, rc::Rc};
struct ButtonHandlers<V, D> {
@@ -20,7 +14,6 @@ impl<V, D> Default for ButtonHandlers<V, D> {
}
}
-use crate as gpui2;
#[derive(Element)]
pub struct Button<V: 'static, D: 'static> {
handlers: ButtonHandlers<V, D>,
@@ -0,0 +1,22 @@
+use crate::theme::{Theme, Themed};
+use gpui2::Element;
+use std::marker::PhantomData;
+
+pub trait ElementExt<V: 'static>: Element<V> {
+ fn themed(self, theme: Theme) -> Themed<V, Self>
+ where
+ Self: Sized;
+}
+
+impl<V: 'static, E: Element<V>> ElementExt<V> for E {
+ fn themed(self, theme: Theme) -> Themed<V, Self>
+ where
+ Self: Sized,
+ {
+ Themed {
+ child: self,
+ theme,
+ view_type: PhantomData,
+ }
+ }
+}
@@ -1,61 +1,43 @@
#![allow(dead_code, unused_variables)]
-use crate::element::Element;
-use gpui::{
- geometry::{rect::RectF, vector::vec2f},
- platform::WindowOptions,
- serde_json, ViewContext,
-};
+use crate::theme::Theme;
+use ::theme as legacy_theme;
+use element_ext::ElementExt;
+use gpui2::{serde_json, vec2f, view, Element, RectF, ViewContext, WindowBounds};
+use legacy_theme::ThemeSettings;
use log::LevelFilter;
use settings::{default_settings, SettingsStore};
use simplelog::SimpleLogger;
-use theme::ThemeSettings;
-use themes::Theme;
-use view::view;
use workspace::workspace;
-mod adapter;
-mod color;
mod components;
-mod div;
-mod element;
-mod hoverable;
-mod interactive;
-mod layout_context;
-mod paint_context;
-mod pressable;
-mod style;
-mod text;
-mod themes;
-mod view;
+mod element_ext;
+mod theme;
mod workspace;
fn main() {
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
- gpui::App::new(()).unwrap().run(|cx| {
+ gpui2::App::new(()).unwrap().run(|cx| {
let mut store = SettingsStore::default();
store
.set_default_settings(default_settings().as_ref(), cx)
.unwrap();
cx.set_global(store);
- theme::init(Assets, cx);
+ legacy_theme::init(Assets, cx);
cx.add_window(
- WindowOptions {
- bounds: gpui::platform::WindowBounds::Fixed(RectF::new(
- vec2f(0., 0.),
- vec2f(400., 300.),
- )),
+ gpui2::WindowOptions {
+ bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(400., 300.))),
center: true,
..Default::default()
},
- |_| view(|cx| playground(cx)),
+ |_| view(|cx| storybook(cx)),
);
cx.platform().activate(true);
});
}
-fn playground<V: 'static>(cx: &mut ViewContext<V>) -> impl Element<V> {
+fn storybook<V: 'static>(cx: &mut ViewContext<V>) -> impl Element<V> {
workspace().themed(current_theme(cx))
}
@@ -77,11 +59,11 @@ fn current_theme<V: 'static>(cx: &mut ViewContext<V>) -> Theme {
}
use anyhow::{anyhow, Result};
-use gpui::AssetSource;
+use gpui2::AssetSource;
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
-#[folder = "../../../assets"]
+#[folder = "../../assets"]
#[include = "themes/**/*"]
#[exclude = "*.DS_Store"]
pub struct Assets;
@@ -1,11 +1,12 @@
-use crate::{
+use gpui2::{
color::Hsla,
element::{Element, PaintContext},
layout_context::LayoutContext,
+ serde_json, AppContext, WindowContext,
};
-use gpui::WindowContext;
use serde::{de::Visitor, Deserialize, Deserializer};
use std::{collections::HashMap, fmt, marker::PhantomData};
+use theme::ThemeSettings;
#[derive(Deserialize, Clone, Default, Debug)]
pub struct Theme {
@@ -64,10 +65,6 @@ pub struct Shadow {
pub offset: Vec<u8>,
}
-pub fn theme<'a>(cx: &'a WindowContext) -> &'a Theme {
- cx.theme::<Theme>()
-}
-
fn deserialize_player_colors<'de, D>(deserializer: D) -> Result<Vec<PlayerColors>, D::Error>
where
D: Deserializer<'de>,
@@ -149,7 +146,7 @@ impl<V: 'static, E: Element<V>> Element<V> for Themed<V, E> {
&mut self,
view: &mut V,
cx: &mut LayoutContext<V>,
- ) -> anyhow::Result<(gpui::LayoutId, Self::PaintState)>
+ ) -> anyhow::Result<(gpui2::LayoutId, Self::PaintState)>
where
Self: Sized,
{
@@ -162,7 +159,7 @@ impl<V: 'static, E: Element<V>> Element<V> for Themed<V, E> {
fn paint(
&mut self,
view: &mut V,
- layout: &gpui::Layout,
+ layout: &gpui2::Layout,
state: &mut Self::PaintState,
cx: &mut PaintContext<V>,
) where
@@ -173,3 +170,23 @@ impl<V: 'static, E: Element<V>> Element<V> for Themed<V, E> {
cx.pop_theme();
}
}
+
+fn preferred_theme<V: 'static>(cx: &AppContext) -> Theme {
+ settings::get::<ThemeSettings>(cx)
+ .theme
+ .deserialized_base_theme
+ .lock()
+ .get_or_insert_with(|| {
+ let theme: Theme =
+ serde_json::from_value(settings::get::<ThemeSettings>(cx).theme.base_theme.clone())
+ .unwrap();
+ Box::new(theme)
+ })
+ .downcast_ref::<Theme>()
+ .unwrap()
+ .clone()
+}
+
+pub fn theme<'a>(cx: &'a WindowContext) -> &'a Theme {
+ cx.theme::<Theme>()
+}
@@ -1,13 +1,9 @@
-use crate::{
- div::div,
- element::{Element, IntoElement, ParentElement},
- style::StyleHelpers,
- themes::theme,
+use crate::theme::theme;
+use gpui2::{
+ elements::div, geometry::pixels, style::StyleHelpers, Element, IntoElement, ParentElement,
+ ViewContext,
};
-use gpui::{geometry::pixels, ViewContext};
-use gpui2_macros::Element;
-use crate as playground;
#[derive(Element)]
struct WorkspaceElement;
@@ -4484,7 +4484,7 @@ mod element {
.layout_engine()
.unwrap()
.computed_layout(*layout_node_id)
- .expect("you can currently only use playground elements within an adapter"),
+ .expect("make sure you're using this within a gpui2 adapter element"),
from_element: element_layout.as_mut(),
};
let style = self.element.style();
@@ -5601,12 +5601,12 @@ fn main() {
center: true,
..Default::default()
},
- |_| view(|_| playground(&rose_pine::moon())),
+ |_| view(|_| storybook(&rose_pine::moon())),
);
cx.platform().activate(true);
});
}
-fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
+fn storybook<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
frame()
.text_color(black())
.h_full()