mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-26 10:40:54 +00:00
Provide themes to subtrees via context
Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
fd1633ac4b
commit
9371754942
8 changed files with 206 additions and 74 deletions
|
@ -65,7 +65,8 @@ impl<V: 'static> Element<V> for Div<V> {
|
|||
{
|
||||
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));
|
||||
let style = cx.text_style().clone().refined(&style);
|
||||
cx.push_text_style(style);
|
||||
true
|
||||
});
|
||||
style.paint_background(layout.bounds, cx);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
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};
|
||||
|
@ -34,6 +37,17 @@ 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>.
|
||||
|
@ -85,7 +99,6 @@ impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
|
|||
ElementPhase::Error(message)
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ use derive_more::{Deref, DerefMut};
|
|||
pub use gpui::taffy::tree::NodeId;
|
||||
use gpui::{
|
||||
scene::EventHandler, EventContext, Layout, LayoutId, PaintContext as LegacyPaintContext,
|
||||
RenderContext, ViewContext,
|
||||
};
|
||||
use std::{any::TypeId, rc::Rc};
|
||||
|
||||
|
@ -15,24 +14,6 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
|
|||
pub(crate) scene: &'d mut gpui::SceneBuilder,
|
||||
}
|
||||
|
||||
impl<'a, 'b, V> RenderContext<'a, 'b, V> for PaintContext<'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> PaintContext<'a, 'b, 'c, 'd, V> {
|
||||
pub fn new(
|
||||
legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
#![allow(dead_code, unused_variables)]
|
||||
use crate::{
|
||||
color::black, element::ParentElement, style::StyleHelpers, themes::rose_pine::RosePinePalette,
|
||||
};
|
||||
use element::Element;
|
||||
use crate::{element::ParentElement, style::StyleHelpers};
|
||||
use element::{Element, IntoElement};
|
||||
use gpui::{
|
||||
geometry::{pixels, rect::RectF, vector::vec2f},
|
||||
platform::WindowOptions,
|
||||
ViewContext,
|
||||
};
|
||||
use log::LevelFilter;
|
||||
use playground_macros::Element;
|
||||
use simplelog::SimpleLogger;
|
||||
use themes::{rose_pine, ThemeColors};
|
||||
use themes::{current_theme, rose_pine, Theme, ThemeColors};
|
||||
use view::view;
|
||||
|
||||
mod adapter;
|
||||
|
@ -41,30 +40,63 @@ fn main() {
|
|||
center: true,
|
||||
..Default::default()
|
||||
},
|
||||
|_| view(|cx| workspace(&rose_pine::moon(), cx)),
|
||||
|_| {
|
||||
view(|cx| {
|
||||
playground(Theme {
|
||||
colors: rose_pine::dawn(),
|
||||
})
|
||||
})
|
||||
},
|
||||
);
|
||||
cx.platform().activate(true);
|
||||
});
|
||||
}
|
||||
|
||||
fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
||||
use div::div;
|
||||
let p = RosePinePalette::dawn();
|
||||
|
||||
div()
|
||||
.text_color(black())
|
||||
.h_full()
|
||||
.w_full()
|
||||
.fill(p.rose)
|
||||
.child(div().fill(p.pine).child(div().fill(p.love).w_6().h_3()))
|
||||
.child(div().fill(p.gold).child(div().fill(p.iris).w_3().h_3()))
|
||||
fn playground<V: 'static>(theme: Theme) -> impl Element<V> {
|
||||
workspace().themed(theme)
|
||||
}
|
||||
|
||||
fn workspace<V: 'static>(theme: &ThemeColors, cx: &mut ViewContext<V>) -> impl Element<V> {
|
||||
use div::div;
|
||||
// one line change1!
|
||||
div()
|
||||
.full()
|
||||
.fill(theme.base(0.5))
|
||||
.child(div().h(pixels(cx.titlebar_height())).fill(theme.base(0.)))
|
||||
fn workspace<V: 'static>() -> impl Element<V> {
|
||||
WorkspaceElement
|
||||
}
|
||||
|
||||
use crate as playground;
|
||||
#[derive(Element)]
|
||||
struct WorkspaceElement;
|
||||
|
||||
impl WorkspaceElement {
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
|
||||
use div::div;
|
||||
let theme = &cx.theme::<Theme>().colors;
|
||||
// one line change1!
|
||||
div()
|
||||
.full()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.fill(theme.base(0.5))
|
||||
.child(self.title_bar(cx))
|
||||
.child(self.stage(cx))
|
||||
.child(self.status_bar(cx))
|
||||
}
|
||||
|
||||
fn title_bar<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
use div::div;
|
||||
|
||||
let theme = ¤t_theme(cx).colors;
|
||||
div().h(pixels(cx.titlebar_height())).fill(theme.base(0.))
|
||||
}
|
||||
|
||||
fn status_bar<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
use div::div;
|
||||
|
||||
let theme = ¤t_theme(cx).colors;
|
||||
div().h(pixels(cx.titlebar_height())).fill(theme.base(0.))
|
||||
}
|
||||
|
||||
fn stage<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
use div::div;
|
||||
|
||||
let theme = ¤t_theme(cx).colors;
|
||||
div().flex_grow()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -327,6 +327,38 @@ pub trait StyleHelpers: Styleable<Style = Style> {
|
|||
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>,
|
||||
|
|
|
@ -1,8 +1,23 @@
|
|||
use crate::color::{Hsla, Lerp};
|
||||
use std::ops::Range;
|
||||
use crate::{
|
||||
color::{Hsla, Lerp},
|
||||
element::{Element, PaintContext},
|
||||
layout_context::LayoutContext,
|
||||
};
|
||||
use gpui::{AppContext, WindowContext};
|
||||
use std::{marker::PhantomData, ops::Range};
|
||||
|
||||
pub mod rose_pine;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Theme {
|
||||
pub colors: ThemeColors,
|
||||
}
|
||||
|
||||
pub fn current_theme<'a>(cx: &'a WindowContext) -> &'a Theme {
|
||||
cx.theme::<Theme>()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ThemeColors {
|
||||
pub base: Range<Hsla>,
|
||||
pub surface: Range<Hsla>,
|
||||
|
@ -22,6 +37,12 @@ pub struct ThemeColors {
|
|||
}
|
||||
|
||||
impl ThemeColors {
|
||||
fn current(cx: &AppContext) -> &Self {
|
||||
cx.global::<Vec<Self>>()
|
||||
.last()
|
||||
.expect("must call within a theme provider")
|
||||
}
|
||||
|
||||
pub fn base(&self, level: f32) -> Hsla {
|
||||
self.base.lerp(level)
|
||||
}
|
||||
|
@ -82,3 +103,41 @@ impl ThemeColors {
|
|||
self.modified.lerp(level)
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3619,36 +3619,11 @@ impl<V> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
|
|||
|
||||
pub struct PaintContext<'a, 'b, 'c, V> {
|
||||
pub view_context: &'c mut ViewContext<'a, 'b, V>,
|
||||
text_style_stack: Vec<TextStyle>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V> PaintContext<'a, 'b, 'c, V> {
|
||||
pub fn new(view_context: &'c mut ViewContext<'a, 'b, V>) -> Self {
|
||||
Self {
|
||||
view_context,
|
||||
text_style_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V> RenderContext<'a, 'b, V> for PaintContext<'a, 'b, 'c, V> {
|
||||
fn text_style(&self) -> TextStyle {
|
||||
self.text_style_stack
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(TextStyle::default(&self.font_cache))
|
||||
}
|
||||
|
||||
fn push_text_style(&mut self, style: TextStyle) {
|
||||
self.text_style_stack.push(style);
|
||||
}
|
||||
|
||||
fn pop_text_style(&mut self) {
|
||||
self.text_style_stack.pop();
|
||||
}
|
||||
|
||||
fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
|
||||
&mut self.view_context
|
||||
Self { view_context }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{
|
||||
elements::AnyRootElement,
|
||||
fonts::TextStyle,
|
||||
geometry::{rect::RectF, Size},
|
||||
json::ToJson,
|
||||
keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult},
|
||||
|
@ -30,7 +31,7 @@ use sqlez::{
|
|||
statement::Statement,
|
||||
};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
any::{type_name, Any, TypeId},
|
||||
mem,
|
||||
ops::{Deref, DerefMut, Range, Sub},
|
||||
};
|
||||
|
@ -53,6 +54,8 @@ pub struct Window {
|
|||
pub(crate) invalidation: Option<WindowInvalidation>,
|
||||
pub(crate) platform_window: Box<dyn platform::Window>,
|
||||
pub(crate) rendered_views: HashMap<usize, Box<dyn AnyRootElement>>,
|
||||
pub(crate) text_style_stack: Vec<TextStyle>,
|
||||
pub(crate) theme_stack: Vec<Box<dyn Any>>,
|
||||
titlebar_height: f32,
|
||||
appearance: Appearance,
|
||||
cursor_regions: Vec<CursorRegion>,
|
||||
|
@ -100,6 +103,8 @@ impl Window {
|
|||
clicked_region: None,
|
||||
titlebar_height,
|
||||
appearance,
|
||||
text_style_stack: Vec::new(),
|
||||
theme_stack: Vec::new(),
|
||||
};
|
||||
|
||||
let mut window_context = WindowContext::mutable(cx, &mut window, handle);
|
||||
|
@ -1265,6 +1270,40 @@ impl<'a> WindowContext<'a> {
|
|||
};
|
||||
handle
|
||||
}
|
||||
|
||||
pub fn text_style(&self) -> TextStyle {
|
||||
self.window
|
||||
.text_style_stack
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(TextStyle::default(&self.font_cache))
|
||||
}
|
||||
|
||||
pub fn push_text_style(&mut self, style: TextStyle) {
|
||||
self.window.text_style_stack.push(style);
|
||||
}
|
||||
|
||||
pub fn pop_text_style(&mut self) {
|
||||
self.window.text_style_stack.pop();
|
||||
}
|
||||
|
||||
pub fn theme<T: 'static>(&self) -> &T {
|
||||
self.window
|
||||
.theme_stack
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|theme| theme.downcast_ref())
|
||||
.ok_or_else(|| anyhow!("no theme provided of type {}", type_name::<T>()))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn push_theme<T: 'static>(&mut self, theme: T) {
|
||||
self.window.theme_stack.push(Box::new(theme));
|
||||
}
|
||||
|
||||
pub fn pop_theme(&mut self) {
|
||||
self.window.theme_stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
Loading…
Reference in a new issue