mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-26 10:40:54 +00:00
Checkpoint: Working toward compatibility with themes
This commit is contained in:
parent
48d3e2d9b9
commit
d763946b18
5 changed files with 180 additions and 114 deletions
|
@ -1,8 +1,9 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::{num::ParseIntError, ops::Range};
|
||||
|
||||
use serde::de::{self, Deserialize, Deserializer, Visitor};
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::{num::ParseIntError, ops::Range};
|
||||
|
||||
pub fn rgb<C: From<Rgba>>(hex: u32) -> C {
|
||||
let r = ((hex >> 16) & 0xFF) as f32 / 255.0;
|
||||
|
@ -19,6 +20,40 @@ pub struct Rgba {
|
|||
pub a: f32,
|
||||
}
|
||||
|
||||
struct RgbaVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for RgbaVisitor {
|
||||
type Value = Rgba;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a string in the format #rrggbb or #rrggbbaa")
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Rgba, E> {
|
||||
if value.len() == 7 || value.len() == 9 {
|
||||
let r = u8::from_str_radix(&value[1..3], 16).unwrap() as f32 / 255.0;
|
||||
let g = u8::from_str_radix(&value[3..5], 16).unwrap() as f32 / 255.0;
|
||||
let b = u8::from_str_radix(&value[5..7], 16).unwrap() as f32 / 255.0;
|
||||
let a = if value.len() == 9 {
|
||||
u8::from_str_radix(&value[7..9], 16).unwrap() as f32 / 255.0
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
Ok(Rgba { r, g, b, a })
|
||||
} else {
|
||||
Err(E::custom(
|
||||
"Bad format for RGBA. Expected #rrggbb or #rrggbbaa.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Rgba {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_str(RgbaVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Lerp {
|
||||
fn lerp(&self, level: f32) -> Hsla;
|
||||
}
|
||||
|
@ -219,6 +254,19 @@ impl Into<gpui::color::Color> for Hsla {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Hsla {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// First, deserialize it into Rgba
|
||||
let rgba = Rgba::deserialize(deserializer)?;
|
||||
|
||||
// Then, use the From<Rgba> for Hsla implementation to convert it
|
||||
Ok(Hsla::from(rgba))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ColorScale {
|
||||
colors: SmallVec<[Hsla; 2]>,
|
||||
positions: SmallVec<[f32; 2]>,
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
interactive::Interactive,
|
||||
style::StyleHelpers,
|
||||
text::ArcCow,
|
||||
themes::Theme,
|
||||
// themes::Theme,
|
||||
};
|
||||
use gpui::{platform::MouseButton, ViewContext};
|
||||
use playground_macros::Element;
|
||||
|
@ -82,10 +82,10 @@ impl<V: 'static, D: 'static> Button<V, D> {
|
|||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> impl IntoElement<V> + Interactive<V> {
|
||||
let colors = &cx.theme::<Theme>().colors;
|
||||
// let colors = &cx.theme::<Theme>().colors;
|
||||
|
||||
let button = div()
|
||||
.fill(colors.error(0.5))
|
||||
// .fill(colors.error(0.5))
|
||||
.h_4()
|
||||
.children(self.label.clone());
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#![allow(dead_code, unused_variables)]
|
||||
use element::Element;
|
||||
use crate::element::Element;
|
||||
use gpui::{
|
||||
geometry::{rect::RectF, vector::vec2f},
|
||||
platform::WindowOptions,
|
||||
};
|
||||
use log::LevelFilter;
|
||||
use simplelog::SimpleLogger;
|
||||
use themes::{rose_pine, Theme, ThemeColors};
|
||||
use themes::Theme;
|
||||
use view::view;
|
||||
use workspace::workspace;
|
||||
|
||||
|
@ -39,13 +39,7 @@ fn main() {
|
|||
center: true,
|
||||
..Default::default()
|
||||
},
|
||||
|_| {
|
||||
view(|cx| {
|
||||
playground(Theme {
|
||||
colors: rose_pine::dawn(),
|
||||
})
|
||||
})
|
||||
},
|
||||
|_| view(|cx| playground(Theme::default())),
|
||||
);
|
||||
cx.platform().activate(true);
|
||||
});
|
||||
|
|
|
@ -1,107 +1,134 @@
|
|||
use crate::{
|
||||
color::{Hsla, Lerp},
|
||||
color::Hsla,
|
||||
element::{Element, PaintContext},
|
||||
layout_context::LayoutContext,
|
||||
};
|
||||
use gpui::{AppContext, WindowContext};
|
||||
use std::{marker::PhantomData, ops::Range};
|
||||
use gpui::WindowContext;
|
||||
use serde::{de::Visitor, Deserialize, Deserializer};
|
||||
use std::{collections::HashMap, fmt, marker::PhantomData};
|
||||
|
||||
pub mod rose_pine;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Deserialize, Clone, Default, Debug)]
|
||||
pub struct Theme {
|
||||
pub colors: ThemeColors,
|
||||
name: String,
|
||||
is_light: bool,
|
||||
lowest: Layer,
|
||||
middle: Layer,
|
||||
highest: Layer,
|
||||
popover_shadow: Shadow,
|
||||
modal_shadow: Shadow,
|
||||
#[serde(deserialize_with = "deserialize_player_colors")]
|
||||
players: Vec<PlayerColors>,
|
||||
#[serde(deserialize_with = "deserialize_syntax_colors")]
|
||||
syntax: HashMap<String, Hsla>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Default, Debug)]
|
||||
pub struct Layer {
|
||||
base: StyleSet,
|
||||
variant: StyleSet,
|
||||
on: StyleSet,
|
||||
accent: StyleSet,
|
||||
positive: StyleSet,
|
||||
warning: StyleSet,
|
||||
negative: StyleSet,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Default, Debug)]
|
||||
pub struct StyleSet {
|
||||
#[serde(rename = "default")]
|
||||
default: ContainerColors,
|
||||
hovered: ContainerColors,
|
||||
pressed: ContainerColors,
|
||||
active: ContainerColors,
|
||||
disabled: ContainerColors,
|
||||
inverted: ContainerColors,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Default, Debug)]
|
||||
pub struct ContainerColors {
|
||||
background: Hsla,
|
||||
foreground: Hsla,
|
||||
border: Hsla,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Default, Debug)]
|
||||
pub struct PlayerColors {
|
||||
selection: Hsla,
|
||||
cursor: Hsla,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Default, Debug)]
|
||||
pub struct Shadow {
|
||||
blur: u8,
|
||||
color: Hsla,
|
||||
offset: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn theme<'a>(cx: &'a WindowContext) -> &'a Theme {
|
||||
cx.theme::<Theme>()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ThemeColors {
|
||||
pub base: Range<Hsla>,
|
||||
pub surface: Range<Hsla>,
|
||||
pub overlay: Range<Hsla>,
|
||||
pub muted: Range<Hsla>,
|
||||
pub subtle: Range<Hsla>,
|
||||
pub text: Range<Hsla>,
|
||||
pub highlight_low: Range<Hsla>,
|
||||
pub highlight_med: Range<Hsla>,
|
||||
pub highlight_high: Range<Hsla>,
|
||||
pub success: Range<Hsla>,
|
||||
pub warning: Range<Hsla>,
|
||||
pub error: Range<Hsla>,
|
||||
pub inserted: Range<Hsla>,
|
||||
pub deleted: Range<Hsla>,
|
||||
pub modified: Range<Hsla>,
|
||||
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)
|
||||
}
|
||||
|
||||
impl ThemeColors {
|
||||
fn current(cx: &AppContext) -> &Self {
|
||||
cx.global::<Vec<Self>>()
|
||||
.last()
|
||||
.expect("must call within a theme provider")
|
||||
}
|
||||
fn deserialize_syntax_colors<'de, D>(deserializer: D) -> Result<HashMap<String, Hsla>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct SyntaxVisitor;
|
||||
|
||||
pub fn base(&self, level: f32) -> Hsla {
|
||||
self.base.lerp(level)
|
||||
}
|
||||
impl<'de> Visitor<'de> for SyntaxVisitor {
|
||||
type Value = HashMap<String, Hsla>;
|
||||
|
||||
pub fn surface(&self, level: f32) -> Hsla {
|
||||
self.surface.lerp(level)
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
pub fn overlay(&self, level: f32) -> Hsla {
|
||||
self.overlay.lerp(level)
|
||||
}
|
||||
|
||||
pub fn muted(&self, level: f32) -> Hsla {
|
||||
self.muted.lerp(level)
|
||||
}
|
||||
|
||||
pub fn subtle(&self, level: f32) -> Hsla {
|
||||
self.subtle.lerp(level)
|
||||
}
|
||||
|
||||
pub fn text(&self, level: f32) -> Hsla {
|
||||
self.text.lerp(level)
|
||||
}
|
||||
|
||||
pub fn highlight_low(&self, level: f32) -> Hsla {
|
||||
self.highlight_low.lerp(level)
|
||||
}
|
||||
|
||||
pub fn highlight_med(&self, level: f32) -> Hsla {
|
||||
self.highlight_med.lerp(level)
|
||||
}
|
||||
|
||||
pub fn highlight_high(&self, level: f32) -> Hsla {
|
||||
self.highlight_high.lerp(level)
|
||||
}
|
||||
|
||||
pub fn success(&self, level: f32) -> Hsla {
|
||||
self.success.lerp(level)
|
||||
}
|
||||
|
||||
pub fn warning(&self, level: f32) -> Hsla {
|
||||
self.warning.lerp(level)
|
||||
}
|
||||
|
||||
pub fn error(&self, level: f32) -> Hsla {
|
||||
self.error.lerp(level)
|
||||
}
|
||||
|
||||
pub fn inserted(&self, level: f32) -> Hsla {
|
||||
self.inserted.lerp(level)
|
||||
}
|
||||
|
||||
pub fn deleted(&self, level: f32) -> Hsla {
|
||||
self.deleted.lerp(level)
|
||||
}
|
||||
|
||||
pub fn modified(&self, level: f32) -> Hsla {
|
||||
self.modified.lerp(level)
|
||||
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 hsla: Hsla = map.next_value()?; // Deserialize values as Hsla
|
||||
result.insert(key, hsla);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_map(SyntaxVisitor)
|
||||
}
|
||||
|
||||
pub struct Themed<V: 'static, E> {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::div::div;
|
||||
use crate::element::{IntoElement, ParentElement};
|
||||
use crate::style::StyleHelpers;
|
||||
use crate::themes::theme;
|
||||
use crate::{element::Element, themes::Theme};
|
||||
use gpui::geometry::pixels;
|
||||
use gpui::ViewContext;
|
||||
use crate::{
|
||||
div::div,
|
||||
element::{Element, IntoElement, ParentElement},
|
||||
style::StyleHelpers,
|
||||
};
|
||||
use gpui::{geometry::pixels, ViewContext};
|
||||
use playground_macros::Element;
|
||||
|
||||
use crate as playground;
|
||||
|
@ -17,29 +16,27 @@ pub fn workspace<V: 'static>() -> impl Element<V> {
|
|||
|
||||
impl WorkspaceElement {
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = &cx.theme::<Theme>().colors;
|
||||
// let theme = &cx.theme::<Theme>().colors;
|
||||
div()
|
||||
.full()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.fill(theme.base(0.5))
|
||||
// .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> {
|
||||
let colors = &theme(cx).colors;
|
||||
div().h(pixels(cx.titlebar_height())).fill(colors.base(0.))
|
||||
// let colors = &theme(cx).colors;
|
||||
div().h(pixels(cx.titlebar_height())) //.fill(colors.base(0.))
|
||||
}
|
||||
|
||||
fn status_bar<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let colors = &theme(cx).colors;
|
||||
div().h(pixels(cx.titlebar_height())).fill(colors.base(0.))
|
||||
div().h(pixels(cx.titlebar_height())) //.fill(colors.base(0.))
|
||||
}
|
||||
|
||||
fn stage<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let colors = &theme(cx).colors;
|
||||
div().flex_grow()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue