Extract most colors in codebase into theme file. switch to dark

This commit is contained in:
Max Brunsfeld 2021-07-29 17:25:35 -07:00
parent c306ac007c
commit 372d2ccb6d
10 changed files with 275 additions and 130 deletions

View File

@ -20,6 +20,7 @@ pub struct Label {
family_id: FamilyId,
font_properties: Properties,
font_size: f32,
default_color: ColorU,
highlights: Option<Highlights>,
}
@ -36,10 +37,16 @@ impl Label {
family_id,
font_properties: Properties::new(),
font_size,
default_color: ColorU::black(),
highlights: None,
}
}
pub fn with_default_color(mut self, color: ColorU) -> Self {
self.default_color = color;
self
}
pub fn with_highlights(
mut self,
color: ColorU,
@ -69,7 +76,7 @@ impl Label {
for (char_ix, c) in self.text.char_indices() {
let mut font_id = font_id;
let mut color = ColorU::black();
let mut color = self.default_color;
if let Some(highlight_ix) = highlight_indices.peek() {
if char_ix == *highlight_ix {
font_id = highlight_font_id;
@ -97,7 +104,7 @@ impl Label {
runs
} else {
smallvec![(self.text.len(), font_id, ColorU::black())]
smallvec![(self.text.len(), font_id, self.default_color)]
}
}
}

View File

@ -0,0 +1,38 @@
[ui]
tab_background = 0x131415
tab_background_active = 0x1c1d1e
tab_text = 0x5a5a5b
tab_text_active = 0xffffff
tab_border = 0x000000
tab_icon_close = 0x383839
tab_icon_dirty = 0x556de8
tab_icon_conflict = 0xe45349
modal_background = 0x3a3b3c
modal_match_background = 0x424344
modal_match_background_active = 0x094771
modal_match_border = 0x000000
modal_match_text = 0xcccccc
modal_match_text_highlight = 0x18a3ff
[editor]
background = 0x1c1d1e
gutter_background = 0x1c1d1e
line_number = 0x5a5a5b
line_number_active = 0xffffff
default_text = 0xd4d4d4
replicas = [
{ selection = 0x264f78, cursor = 0xffffff },
{ selection = 0x504f31, cursor = 0xfcf154 },
]
[syntax]
keyword = 0xc586c0
function = 0xdcdcaa
string = 0xcb8f77
type = 0x4ec9b0
number = 0xb5cea8
comment = 0x6a9955
property = 0x4e94ce
variant = 0x4fc1ff
constant = 0x9cdcfe

View File

@ -1,13 +0,0 @@
[ui]
background = 0xffffff
line_numbers = 0x237791
text = 0x0d0d0d
[syntax]
keyword = 0xaf00db
function = 0x795e26
string = 0xa31515
type = 0x267599
number = 0x0d885b
comment = 0x048204
property = 0x001080

View File

@ -15,7 +15,27 @@
(function_item name: (identifier) @function.definition)
(function_signature_item name: (identifier) @function.definition)
; Identifier conventions
; Assume uppercase names are enum constructors
((identifier) @variant
(#match? @variant "^[A-Z]"))
; Assume that uppercase names in paths are types
((scoped_identifier
path: (identifier) @type)
(#match? @type "^[A-Z]"))
((scoped_identifier
path: (scoped_identifier
name: (identifier) @type))
(#match? @type "^[A-Z]"))
; Assume all-caps names are constants
((identifier) @constant
(#match? @constant "^[A-Z][A-Z\\d_]+$'"))
[
"as"
"async"
"break"
"const"

View File

@ -2353,6 +2353,7 @@ impl Snapshot {
viewport_height: f32,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
theme: &Theme,
) -> Result<Vec<Option<text_layout::Line>>> {
let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
@ -2378,7 +2379,7 @@ impl Snapshot {
layouts.push(Some(layout_cache.layout_str(
&line_number,
self.font_size,
&[(line_number.len(), font_id, ColorU::black())],
&[(line_number.len(), font_id, theme.editor.line_number.0)],
)));
}
}
@ -2785,12 +2786,13 @@ mod tests {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx));
let settings = settings::channel(&font_cache).unwrap().1;
let (_, editor) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx));
let (_, editor) =
cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings.clone(), cx));
let layouts = editor.update(cx, |editor, cx| {
editor
.snapshot(cx)
.layout_line_numbers(1000.0, &font_cache, &layout_cache)
.layout_line_numbers(1000.0, &font_cache, &layout_cache, &settings.borrow().theme)
.unwrap()
});
assert_eq!(layouts.len(), 6);

View File

@ -1,6 +1,5 @@
use crate::time::ReplicaId;
use super::{DisplayPoint, Editor, SelectAction, Snapshot};
use crate::time::ReplicaId;
use gpui::{
color::ColorU,
geometry::{
@ -184,12 +183,14 @@ impl EditorElement {
}
fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, cx: &mut PaintContext) {
let settings = self.view(cx.app).settings.borrow();
let theme = &settings.theme;
let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
cx.scene.push_layer(Some(rect));
cx.scene.push_quad(Quad {
bounds: rect,
background: Some(ColorU::white()),
background: Some(theme.editor.gutter_background.0),
border: Border::new(0., ColorU::transparent_black()),
corner_radius: 0.,
});
@ -214,6 +215,8 @@ impl EditorElement {
fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, cx: &mut PaintContext) {
let view = self.view(cx.app);
let settings = self.view(cx.app).settings.borrow();
let theme = &settings.theme.editor;
let scroll_position = layout.snapshot.scroll_position();
let start_row = scroll_position.y() as u32;
let scroll_top = scroll_position.y() * layout.line_height;
@ -224,26 +227,19 @@ impl EditorElement {
cx.scene.push_layer(Some(bounds));
cx.scene.push_quad(Quad {
bounds,
background: Some(ColorU::white()),
background: Some(theme.background.0),
border: Border::new(0., ColorU::transparent_black()),
corner_radius: 0.,
});
// Draw selections
let corner_radius = 2.5;
let colors = [
(ColorU::from_u32(0xa3d6ffff), ColorU::from_u32(0x000000ff)),
(ColorU::from_u32(0xffaf87ff), ColorU::from_u32(0xff8e72ff)),
(ColorU::from_u32(0x86eaccff), ColorU::from_u32(0x377771ff)),
(ColorU::from_u32(0xb8b8ffff), ColorU::from_u32(0x9381ffff)),
(ColorU::from_u32(0xf5cce8ff), ColorU::from_u32(0x4a2040ff)),
];
let mut cursors = SmallVec::<[Cursor; 32]>::new();
let content_origin = bounds.origin() + layout.text_offset;
for (replica_id, selections) in &layout.selections {
let (selection_color, cursor_color) = colors[*replica_id as usize % colors.len()];
let replica_theme = theme.replicas[*replica_id as usize % theme.replicas.len()];
for selection in selections {
if selection.start != selection.end {
@ -257,7 +253,7 @@ impl EditorElement {
};
let selection = Selection {
color: selection_color,
color: replica_theme.selection.0,
line_height: layout.line_height,
start_y: content_origin.y() + row_range.start as f32 * layout.line_height
- scroll_top,
@ -300,7 +296,7 @@ impl EditorElement {
- scroll_left;
let y = selection.end.row() as f32 * layout.line_height - scroll_top;
cursors.push(Cursor {
color: cursor_color,
color: replica_theme.cursor.0,
origin: content_origin + vec2f(x, y),
line_height: layout.line_height,
});
@ -392,7 +388,19 @@ impl Element for EditorElement {
});
let line_number_layouts = if snapshot.gutter_visible {
match snapshot.layout_line_numbers(size.y(), cx.font_cache, cx.text_layout_cache) {
let settings = self
.view
.upgrade(cx.app)
.unwrap()
.read(cx.app)
.settings
.borrow();
match snapshot.layout_line_numbers(
size.y(),
cx.font_cache,
cx.text_layout_cache,
&settings.theme,
) {
Err(error) => {
log::error!("error laying out line numbers: {}", error);
return (size, None);

View File

@ -6,7 +6,7 @@ use crate::{
worktree::{match_paths, PathMatch, Worktree},
};
use gpui::{
color::{ColorF, ColorU},
color::ColorF,
elements::*,
fonts::{Properties, Weight},
geometry::vector::vec2f,
@ -69,6 +69,8 @@ impl View for FileFinder {
}
fn render(&self, _: &AppContext) -> ElementBox {
let settings = self.settings.borrow();
Align::new(
ConstrainedBox::new(
Container::new(
@ -80,8 +82,8 @@ impl View for FileFinder {
.with_margin_top(12.0)
.with_uniform_padding(6.0)
.with_corner_radius(6.0)
.with_background_color(ColorU::from_u32(0xf2f2f2ff))
.with_shadow(vec2f(0., 4.), 12., ColorF::new(0.0, 0.0, 0.0, 0.25).to_u8())
.with_background_color(settings.theme.ui.modal_background)
.with_shadow(vec2f(0., 4.), 12., ColorF::new(0.0, 0.0, 0.0, 0.5).to_u8())
.boxed(),
)
.with_max_width(600.0)
@ -113,6 +115,7 @@ impl FileFinder {
settings.ui_font_family,
settings.ui_font_size,
)
.with_default_color(settings.theme.editor.default_text.0)
.boxed(),
)
.with_margin_top(6.0)
@ -136,8 +139,6 @@ impl FileFinder {
);
Container::new(list.boxed())
.with_background_color(ColorU::from_u32(0xf7f7f7ff))
.with_border(Border::all(1.0, ColorU::from_u32(0xdbdbdcff)))
.with_margin_top(6.0)
.named("matches")
}
@ -148,11 +149,12 @@ impl FileFinder {
index: usize,
cx: &AppContext,
) -> Option<ElementBox> {
let settings = self.settings.borrow();
let theme = &settings.theme.ui;
self.labels_for_match(path_match, cx).map(
|(file_name, file_name_positions, full_path, full_path_positions)| {
let settings = self.settings.borrow();
let highlight_color = ColorU::from_u32(0x304ee2ff);
let bold = *Properties::new().weight(Weight::BOLD);
let selected_index = self.selected_index();
let mut container = Container::new(
Flex::row()
.with_child(
@ -177,7 +179,12 @@ impl FileFinder {
settings.ui_font_family,
settings.ui_font_size,
)
.with_highlights(highlight_color, bold, file_name_positions)
.with_default_color(theme.modal_match_text.0)
.with_highlights(
theme.modal_match_text_highlight.0,
bold,
file_name_positions,
)
.boxed(),
)
.with_child(
@ -186,7 +193,12 @@ impl FileFinder {
settings.ui_font_family,
settings.ui_font_size,
)
.with_highlights(highlight_color, bold, full_path_positions)
.with_default_color(theme.modal_match_text.0)
.with_highlights(
theme.modal_match_text_highlight.0,
bold,
full_path_positions,
)
.boxed(),
)
.boxed(),
@ -195,16 +207,16 @@ impl FileFinder {
)
.boxed(),
)
.with_uniform_padding(6.0);
.with_uniform_padding(6.0)
.with_background_color(if index == selected_index {
theme.modal_match_background_active.0
} else {
theme.modal_match_background.0
});
let selected_index = self.selected_index();
if index == selected_index || index < self.matches.len() - 1 {
container =
container.with_border(Border::bottom(1.0, ColorU::from_u32(0xdbdbdcff)));
}
if index == selected_index {
container = container.with_background_color(ColorU::from_u32(0xdbdbdcff));
container.with_border(Border::bottom(1.0, theme.modal_match_border));
}
let entry = (path_match.tree_id, path_match.path.clone());

View File

@ -7,7 +7,12 @@ use gpui::{
};
use postage::watch;
use serde::Deserialize;
use std::{collections::HashMap, sync::Arc};
use std::{
collections::HashMap,
fmt,
ops::{Deref, DerefMut},
sync::Arc,
};
const DEFAULT_STYLE_ID: StyleId = StyleId(u32::MAX);
@ -23,12 +28,50 @@ pub struct Settings {
#[derive(Clone, Default)]
pub struct Theme {
pub background_color: ColorU,
pub line_number_color: ColorU,
pub default_text_color: ColorU,
syntax_styles: Vec<(String, ColorU, FontProperties)>,
pub ui: UiTheme,
pub editor: EditorTheme,
syntax: Vec<(String, ColorU, FontProperties)>,
}
#[derive(Clone, Default, Deserialize)]
#[serde(default)]
pub struct UiTheme {
pub tab_background: Color,
pub tab_background_active: Color,
pub tab_text: Color,
pub tab_text_active: Color,
pub tab_border: Color,
pub tab_icon_close: Color,
pub tab_icon_dirty: Color,
pub tab_icon_conflict: Color,
pub modal_background: Color,
pub modal_match_background: Color,
pub modal_match_background_active: Color,
pub modal_match_border: Color,
pub modal_match_text: Color,
pub modal_match_text_highlight: Color,
}
#[derive(Clone, Default, Deserialize)]
#[serde(default)]
pub struct EditorTheme {
pub background: Color,
pub gutter_background: Color,
pub line_number: Color,
pub line_number_active: Color,
pub default_text: Color,
pub replicas: Vec<ReplicaTheme>,
}
#[derive(Clone, Copy, Deserialize)]
pub struct ReplicaTheme {
pub cursor: Color,
pub selection: Color,
}
#[derive(Clone, Copy, Default)]
pub struct Color(pub ColorU);
#[derive(Clone, Debug)]
pub struct ThemeMap(Arc<[StyleId]>);
@ -44,7 +87,7 @@ impl Settings {
ui_font_family: font_cache.load_family(&["SF Pro", "Helvetica"])?,
ui_font_size: 12.0,
theme: Arc::new(
Theme::parse(Assets::get("themes/light.toml").unwrap())
Theme::parse(Assets::get("themes/dark.toml").unwrap())
.expect("Failed to parse built-in theme"),
),
})
@ -61,17 +104,19 @@ impl Theme {
#[derive(Deserialize)]
struct ThemeToml {
#[serde(default)]
syntax: HashMap<String, StyleToml>,
ui: UiTheme,
#[serde(default)]
ui: HashMap<String, u32>,
editor: EditorTheme,
#[serde(default)]
syntax: HashMap<String, StyleToml>,
}
#[derive(Deserialize)]
#[serde(untagged)]
enum StyleToml {
Color(u32),
Color(Color),
Full {
color: Option<u32>,
color: Option<Color>,
weight: Option<toml::Value>,
#[serde(default)]
italic: bool,
@ -81,7 +126,7 @@ impl Theme {
let theme_toml: ThemeToml =
toml::from_slice(source.as_ref()).context("failed to parse theme TOML")?;
let mut syntax_styles = Vec::<(String, ColorU, FontProperties)>::new();
let mut syntax = Vec::<(String, ColorU, FontProperties)>::new();
for (key, style) in theme_toml.syntax {
let (color, weight, italic) = match style {
StyleToml::Color(color) => (color, None, false),
@ -89,55 +134,37 @@ impl Theme {
color,
weight,
italic,
} => (color.unwrap_or(0), weight, italic),
} => (color.unwrap_or(Color::default()), weight, italic),
};
match syntax_styles.binary_search_by_key(&&key, |e| &e.0) {
match syntax.binary_search_by_key(&&key, |e| &e.0) {
Ok(i) | Err(i) => {
let mut properties = FontProperties::new();
properties.weight = deserialize_weight(weight)?;
if italic {
properties.style = FontStyle::Italic;
}
syntax_styles.insert(i, (key, deserialize_color(color), properties));
syntax.insert(i, (key, color.0, properties));
}
}
}
let background_color = theme_toml
.ui
.get("background")
.copied()
.map_or(ColorU::from_u32(0xffffffff), deserialize_color);
let line_number_color = theme_toml
.ui
.get("line_numbers")
.copied()
.map_or(ColorU::black(), deserialize_color);
let default_text_color = theme_toml
.ui
.get("text")
.copied()
.map_or(ColorU::black(), deserialize_color);
Ok(Theme {
background_color,
line_number_color,
default_text_color,
syntax_styles,
ui: theme_toml.ui,
editor: theme_toml.editor,
syntax,
})
}
pub fn syntax_style(&self, id: StyleId) -> (ColorU, FontProperties) {
self.syntax_styles
.get(id.0 as usize)
.map_or((self.default_text_color, FontProperties::new()), |entry| {
(entry.1, entry.2)
})
self.syntax.get(id.0 as usize).map_or(
(self.editor.default_text.0, FontProperties::new()),
|entry| (entry.1, entry.2),
)
}
#[cfg(test)]
pub fn syntax_style_name(&self, id: StyleId) -> Option<&str> {
self.syntax_styles.get(id.0 as usize).map(|e| e.0.as_str())
self.syntax.get(id.0 as usize).map(|e| e.0.as_str())
}
}
@ -151,7 +178,7 @@ impl ThemeMap {
.iter()
.map(|capture_name| {
theme
.syntax_styles
.syntax
.iter()
.enumerate()
.filter_map(|(i, (key, _, _))| {
@ -193,16 +220,53 @@ impl Default for StyleId {
}
}
impl<'de> Deserialize<'de> for Color {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let rgba_value = u32::deserialize(deserializer)?;
Ok(Self(ColorU::from_u32((rgba_value << 8) + 0xFF)))
}
}
impl Into<ColorU> for Color {
fn into(self) -> ColorU {
self.0
}
}
impl Deref for Color {
type Target = ColorU;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Color {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl fmt::Debug for Color {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl PartialEq<ColorU> for Color {
fn eq(&self, other: &ColorU) -> bool {
self.0.eq(other)
}
}
pub fn channel(
font_cache: &FontCache,
) -> Result<(watch::Sender<Settings>, watch::Receiver<Settings>)> {
Ok(watch::channel_with(Settings::new(font_cache)?))
}
fn deserialize_color(color: u32) -> ColorU {
ColorU::from_u32((color << 8) + 0xFF)
}
fn deserialize_weight(weight: Option<toml::Value>) -> Result<FontWeight> {
match &weight {
None => return Ok(FontWeight::NORMAL),
@ -228,8 +292,11 @@ mod tests {
let theme = Theme::parse(
r#"
[ui]
tab_background_active = 0x100000
[editor]
background = 0x00ed00
line_numbers = 0xdddddd
line_number = 0xdddddd
[syntax]
"beta.two" = 0xAABBCC
@ -239,24 +306,25 @@ mod tests {
)
.unwrap();
assert_eq!(theme.background_color, ColorU::from_u32(0x00ED00FF));
assert_eq!(theme.line_number_color, ColorU::from_u32(0xddddddff));
assert_eq!(theme.ui.tab_background_active, ColorU::from_u32(0x100000ff));
assert_eq!(theme.editor.background, ColorU::from_u32(0x00ed00ff));
assert_eq!(theme.editor.line_number, ColorU::from_u32(0xddddddff));
assert_eq!(
theme.syntax_styles,
theme.syntax,
&[
(
"alpha.one".to_string(),
ColorU::from_u32(0x112233FF),
ColorU::from_u32(0x112233ff),
*FontProperties::new().weight(FontWeight::BOLD)
),
(
"beta.two".to_string(),
ColorU::from_u32(0xAABBCCFF),
ColorU::from_u32(0xaabbccff),
*FontProperties::new().weight(FontWeight::NORMAL)
),
(
"gamma.three".to_string(),
ColorU::from_u32(0x000000FF),
ColorU::from_u32(0x00000000),
*FontProperties::new()
.weight(FontWeight::LIGHT)
.style(FontStyle::Italic),
@ -273,10 +341,9 @@ mod tests {
#[test]
fn test_theme_map() {
let theme = Theme {
default_text_color: Default::default(),
background_color: ColorU::default(),
line_number_color: ColorU::default(),
syntax_styles: [
ui: Default::default(),
editor: Default::default(),
syntax: [
("function", ColorU::from_u32(0x100000ff)),
("function.method", ColorU::from_u32(0x200000ff)),
("function.async", ColorU::from_u32(0x300000ff)),

View File

@ -12,9 +12,9 @@ use crate::{
};
use anyhow::{anyhow, Result};
use gpui::{
color::rgbu, elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, AppContext,
ClipboardItem, Entity, ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, Task,
View, ViewContext, ViewHandle, WeakModelHandle,
elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, AppContext, ClipboardItem,
Entity, ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, Task, View,
ViewContext, ViewHandle, WeakModelHandle,
};
use log::error;
pub use pane::*;
@ -880,14 +880,14 @@ impl View for Workspace {
}
fn render(&self, _: &AppContext) -> ElementBox {
let settings = self.settings.borrow();
Container::new(
// self.center.render(bump)
Stack::new()
.with_child(self.center.render())
.with_children(self.modal.as_ref().map(|m| ChildView::new(m.id()).boxed()))
.boxed(),
)
.with_background_color(rgbu(0xea, 0xea, 0xeb))
.with_background_color(settings.theme.editor.background)
.named("workspace")
}

View File

@ -1,5 +1,5 @@
use super::{ItemViewHandle, SplitDirection};
use crate::settings::Settings;
use crate::settings::{Settings, UiTheme};
use gpui::{
color::ColorU,
elements::*,
@ -180,7 +180,7 @@ impl Pane {
fn render_tabs(&self, cx: &AppContext) -> ElementBox {
let settings = self.settings.borrow();
let border_color = ColorU::from_u32(0xdbdbdcff);
let theme = &settings.theme.ui;
let line_height = cx.font_cache().line_height(
cx.font_cache().default_font(settings.ui_font_family),
settings.ui_font_size,
@ -189,6 +189,8 @@ impl Pane {
let mut row = Flex::row();
let last_item_ix = self.items.len() - 1;
for (ix, item) in self.items.iter().enumerate() {
let is_active = ix == self.active_item;
enum Tab {}
row.add_child(
@ -197,7 +199,7 @@ impl Pane {
MouseEventHandler::new::<Tab, _>(item.id(), cx, |mouse_state| {
let title = item.title(cx);
let mut border = Border::new(1.0, border_color);
let mut border = Border::new(1.0, theme.tab_border.0);
border.left = ix > 0;
border.right = ix == last_item_ix;
border.bottom = ix != self.active_item;
@ -211,6 +213,11 @@ impl Pane {
settings.ui_font_family,
settings.ui_font_size,
)
.with_default_color(if is_active {
theme.tab_text_active.0
} else {
theme.tab_text.0
})
.boxed(),
)
.boxed(),
@ -222,6 +229,7 @@ impl Pane {
mouse_state.hovered,
item.is_dirty(cx),
item.has_conflict(cx),
theme,
cx,
))
.right()
@ -232,13 +240,12 @@ impl Pane {
.with_horizontal_padding(10.)
.with_border(border);
if ix == self.active_item {
if is_active {
container = container
.with_background_color(ColorU::white())
.with_background_color(theme.tab_background_active)
.with_padding_bottom(border.width);
} else {
container =
container.with_background_color(ColorU::from_u32(0xeaeaebff));
container = container.with_background_color(theme.tab_background);
}
ConstrainedBox::new(
@ -264,7 +271,7 @@ impl Pane {
row.add_child(
ConstrainedBox::new(
Container::new(Empty::new().boxed())
.with_border(Border::bottom(1.0, border_color))
.with_border(Border::bottom(1.0, theme.tab_border))
.boxed(),
)
.with_min_width(20.)
@ -275,7 +282,7 @@ impl Pane {
Expanded::new(
0.0,
Container::new(Empty::new().boxed())
.with_border(Border::bottom(1.0, border_color))
.with_border(Border::bottom(1.0, theme.tab_border))
.boxed(),
)
.named("filler"),
@ -292,25 +299,25 @@ impl Pane {
tab_hovered: bool,
is_dirty: bool,
has_conflict: bool,
theme: &UiTheme,
cx: &AppContext,
) -> ElementBox {
enum TabCloseButton {}
let dirty_color = ColorU::from_u32(0x556de8ff);
let conflict_color = ColorU::from_u32(0xe45349ff);
let mut clicked_color = dirty_color;
let mut clicked_color = theme.tab_icon_dirty;
clicked_color.a = 180;
let current_color = if has_conflict {
Some(conflict_color)
Some(theme.tab_icon_conflict)
} else if is_dirty {
Some(dirty_color)
Some(theme.tab_icon_dirty)
} else {
None
};
let icon = if tab_hovered {
let mut icon = Svg::new("icons/x.svg");
let close_color = current_color.unwrap_or(theme.tab_icon_close).0;
let icon = Svg::new("icons/x.svg").with_color(close_color);
MouseEventHandler::new::<TabCloseButton, _>(item_id, cx, |mouse_state| {
if mouse_state.hovered {
@ -318,14 +325,11 @@ impl Pane {
.with_background_color(if mouse_state.clicked {
clicked_color
} else {
dirty_color
theme.tab_icon_dirty
})
.with_corner_radius(close_icon_size / 2.)
.boxed()
} else {
if let Some(current_color) = current_color {
icon = icon.with_color(current_color);
}
icon.boxed()
}
})
@ -339,7 +343,7 @@ impl Pane {
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
cx.scene.push_quad(Quad {
bounds: square,
background: Some(current_color),
background: Some(current_color.0),
border: Default::default(),
corner_radius: diameter / 2.,
});