Extract most colors in codebase into theme file. switch to dark
This commit is contained in:
parent
c306ac007c
commit
372d2ccb6d
10 changed files with 275 additions and 130 deletions
|
@ -20,6 +20,7 @@ pub struct Label {
|
||||||
family_id: FamilyId,
|
family_id: FamilyId,
|
||||||
font_properties: Properties,
|
font_properties: Properties,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
|
default_color: ColorU,
|
||||||
highlights: Option<Highlights>,
|
highlights: Option<Highlights>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +37,16 @@ impl Label {
|
||||||
family_id,
|
family_id,
|
||||||
font_properties: Properties::new(),
|
font_properties: Properties::new(),
|
||||||
font_size,
|
font_size,
|
||||||
|
default_color: ColorU::black(),
|
||||||
highlights: None,
|
highlights: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_default_color(mut self, color: ColorU) -> Self {
|
||||||
|
self.default_color = color;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_highlights(
|
pub fn with_highlights(
|
||||||
mut self,
|
mut self,
|
||||||
color: ColorU,
|
color: ColorU,
|
||||||
|
@ -69,7 +76,7 @@ impl Label {
|
||||||
|
|
||||||
for (char_ix, c) in self.text.char_indices() {
|
for (char_ix, c) in self.text.char_indices() {
|
||||||
let mut font_id = font_id;
|
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 let Some(highlight_ix) = highlight_indices.peek() {
|
||||||
if char_ix == *highlight_ix {
|
if char_ix == *highlight_ix {
|
||||||
font_id = highlight_font_id;
|
font_id = highlight_font_id;
|
||||||
|
@ -97,7 +104,7 @@ impl Label {
|
||||||
|
|
||||||
runs
|
runs
|
||||||
} else {
|
} else {
|
||||||
smallvec![(self.text.len(), font_id, ColorU::black())]
|
smallvec![(self.text.len(), font_id, self.default_color)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
38
zed/assets/themes/dark.toml
Normal file
38
zed/assets/themes/dark.toml
Normal 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
|
|
@ -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
|
|
|
@ -15,7 +15,27 @@
|
||||||
(function_item name: (identifier) @function.definition)
|
(function_item name: (identifier) @function.definition)
|
||||||
(function_signature_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"
|
"async"
|
||||||
"break"
|
"break"
|
||||||
"const"
|
"const"
|
||||||
|
|
|
@ -2353,6 +2353,7 @@ impl Snapshot {
|
||||||
viewport_height: f32,
|
viewport_height: f32,
|
||||||
font_cache: &FontCache,
|
font_cache: &FontCache,
|
||||||
layout_cache: &TextLayoutCache,
|
layout_cache: &TextLayoutCache,
|
||||||
|
theme: &Theme,
|
||||||
) -> Result<Vec<Option<text_layout::Line>>> {
|
) -> Result<Vec<Option<text_layout::Line>>> {
|
||||||
let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
|
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(
|
layouts.push(Some(layout_cache.layout_str(
|
||||||
&line_number,
|
&line_number,
|
||||||
self.font_size,
|
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 buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx));
|
||||||
|
|
||||||
let settings = settings::channel(&font_cache).unwrap().1;
|
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| {
|
let layouts = editor.update(cx, |editor, cx| {
|
||||||
editor
|
editor
|
||||||
.snapshot(cx)
|
.snapshot(cx)
|
||||||
.layout_line_numbers(1000.0, &font_cache, &layout_cache)
|
.layout_line_numbers(1000.0, &font_cache, &layout_cache, &settings.borrow().theme)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
});
|
});
|
||||||
assert_eq!(layouts.len(), 6);
|
assert_eq!(layouts.len(), 6);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::time::ReplicaId;
|
|
||||||
|
|
||||||
use super::{DisplayPoint, Editor, SelectAction, Snapshot};
|
use super::{DisplayPoint, Editor, SelectAction, Snapshot};
|
||||||
|
use crate::time::ReplicaId;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
color::ColorU,
|
color::ColorU,
|
||||||
geometry::{
|
geometry::{
|
||||||
|
@ -184,12 +183,14 @@ impl EditorElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, cx: &mut PaintContext) {
|
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;
|
let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
|
||||||
|
|
||||||
cx.scene.push_layer(Some(rect));
|
cx.scene.push_layer(Some(rect));
|
||||||
cx.scene.push_quad(Quad {
|
cx.scene.push_quad(Quad {
|
||||||
bounds: rect,
|
bounds: rect,
|
||||||
background: Some(ColorU::white()),
|
background: Some(theme.editor.gutter_background.0),
|
||||||
border: Border::new(0., ColorU::transparent_black()),
|
border: Border::new(0., ColorU::transparent_black()),
|
||||||
corner_radius: 0.,
|
corner_radius: 0.,
|
||||||
});
|
});
|
||||||
|
@ -214,6 +215,8 @@ impl EditorElement {
|
||||||
|
|
||||||
fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, cx: &mut PaintContext) {
|
fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, cx: &mut PaintContext) {
|
||||||
let view = self.view(cx.app);
|
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 scroll_position = layout.snapshot.scroll_position();
|
||||||
let start_row = scroll_position.y() as u32;
|
let start_row = scroll_position.y() as u32;
|
||||||
let scroll_top = scroll_position.y() * layout.line_height;
|
let scroll_top = scroll_position.y() * layout.line_height;
|
||||||
|
@ -224,26 +227,19 @@ impl EditorElement {
|
||||||
cx.scene.push_layer(Some(bounds));
|
cx.scene.push_layer(Some(bounds));
|
||||||
cx.scene.push_quad(Quad {
|
cx.scene.push_quad(Quad {
|
||||||
bounds,
|
bounds,
|
||||||
background: Some(ColorU::white()),
|
background: Some(theme.background.0),
|
||||||
border: Border::new(0., ColorU::transparent_black()),
|
border: Border::new(0., ColorU::transparent_black()),
|
||||||
corner_radius: 0.,
|
corner_radius: 0.,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw selections
|
// Draw selections
|
||||||
let corner_radius = 2.5;
|
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 mut cursors = SmallVec::<[Cursor; 32]>::new();
|
||||||
|
|
||||||
let content_origin = bounds.origin() + layout.text_offset;
|
let content_origin = bounds.origin() + layout.text_offset;
|
||||||
|
|
||||||
for (replica_id, selections) in &layout.selections {
|
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 {
|
for selection in selections {
|
||||||
if selection.start != selection.end {
|
if selection.start != selection.end {
|
||||||
|
@ -257,7 +253,7 @@ impl EditorElement {
|
||||||
};
|
};
|
||||||
|
|
||||||
let selection = Selection {
|
let selection = Selection {
|
||||||
color: selection_color,
|
color: replica_theme.selection.0,
|
||||||
line_height: layout.line_height,
|
line_height: layout.line_height,
|
||||||
start_y: content_origin.y() + row_range.start as f32 * layout.line_height
|
start_y: content_origin.y() + row_range.start as f32 * layout.line_height
|
||||||
- scroll_top,
|
- scroll_top,
|
||||||
|
@ -300,7 +296,7 @@ impl EditorElement {
|
||||||
- scroll_left;
|
- scroll_left;
|
||||||
let y = selection.end.row() as f32 * layout.line_height - scroll_top;
|
let y = selection.end.row() as f32 * layout.line_height - scroll_top;
|
||||||
cursors.push(Cursor {
|
cursors.push(Cursor {
|
||||||
color: cursor_color,
|
color: replica_theme.cursor.0,
|
||||||
origin: content_origin + vec2f(x, y),
|
origin: content_origin + vec2f(x, y),
|
||||||
line_height: layout.line_height,
|
line_height: layout.line_height,
|
||||||
});
|
});
|
||||||
|
@ -392,7 +388,19 @@ impl Element for EditorElement {
|
||||||
});
|
});
|
||||||
|
|
||||||
let line_number_layouts = if snapshot.gutter_visible {
|
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) => {
|
Err(error) => {
|
||||||
log::error!("error laying out line numbers: {}", error);
|
log::error!("error laying out line numbers: {}", error);
|
||||||
return (size, None);
|
return (size, None);
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
worktree::{match_paths, PathMatch, Worktree},
|
worktree::{match_paths, PathMatch, Worktree},
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
color::{ColorF, ColorU},
|
color::ColorF,
|
||||||
elements::*,
|
elements::*,
|
||||||
fonts::{Properties, Weight},
|
fonts::{Properties, Weight},
|
||||||
geometry::vector::vec2f,
|
geometry::vector::vec2f,
|
||||||
|
@ -69,6 +69,8 @@ impl View for FileFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&self, _: &AppContext) -> ElementBox {
|
fn render(&self, _: &AppContext) -> ElementBox {
|
||||||
|
let settings = self.settings.borrow();
|
||||||
|
|
||||||
Align::new(
|
Align::new(
|
||||||
ConstrainedBox::new(
|
ConstrainedBox::new(
|
||||||
Container::new(
|
Container::new(
|
||||||
|
@ -80,8 +82,8 @@ impl View for FileFinder {
|
||||||
.with_margin_top(12.0)
|
.with_margin_top(12.0)
|
||||||
.with_uniform_padding(6.0)
|
.with_uniform_padding(6.0)
|
||||||
.with_corner_radius(6.0)
|
.with_corner_radius(6.0)
|
||||||
.with_background_color(ColorU::from_u32(0xf2f2f2ff))
|
.with_background_color(settings.theme.ui.modal_background)
|
||||||
.with_shadow(vec2f(0., 4.), 12., ColorF::new(0.0, 0.0, 0.0, 0.25).to_u8())
|
.with_shadow(vec2f(0., 4.), 12., ColorF::new(0.0, 0.0, 0.0, 0.5).to_u8())
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_max_width(600.0)
|
.with_max_width(600.0)
|
||||||
|
@ -113,6 +115,7 @@ impl FileFinder {
|
||||||
settings.ui_font_family,
|
settings.ui_font_family,
|
||||||
settings.ui_font_size,
|
settings.ui_font_size,
|
||||||
)
|
)
|
||||||
|
.with_default_color(settings.theme.editor.default_text.0)
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_margin_top(6.0)
|
.with_margin_top(6.0)
|
||||||
|
@ -136,8 +139,6 @@ impl FileFinder {
|
||||||
);
|
);
|
||||||
|
|
||||||
Container::new(list.boxed())
|
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)
|
.with_margin_top(6.0)
|
||||||
.named("matches")
|
.named("matches")
|
||||||
}
|
}
|
||||||
|
@ -148,11 +149,12 @@ impl FileFinder {
|
||||||
index: usize,
|
index: usize,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> Option<ElementBox> {
|
) -> Option<ElementBox> {
|
||||||
|
let settings = self.settings.borrow();
|
||||||
|
let theme = &settings.theme.ui;
|
||||||
self.labels_for_match(path_match, cx).map(
|
self.labels_for_match(path_match, cx).map(
|
||||||
|(file_name, file_name_positions, full_path, full_path_positions)| {
|
|(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 bold = *Properties::new().weight(Weight::BOLD);
|
||||||
|
let selected_index = self.selected_index();
|
||||||
let mut container = Container::new(
|
let mut container = Container::new(
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_child(
|
.with_child(
|
||||||
|
@ -177,7 +179,12 @@ impl FileFinder {
|
||||||
settings.ui_font_family,
|
settings.ui_font_family,
|
||||||
settings.ui_font_size,
|
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(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_child(
|
.with_child(
|
||||||
|
@ -186,7 +193,12 @@ impl FileFinder {
|
||||||
settings.ui_font_family,
|
settings.ui_font_family,
|
||||||
settings.ui_font_size,
|
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(),
|
||||||
)
|
)
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
@ -195,16 +207,16 @@ impl FileFinder {
|
||||||
)
|
)
|
||||||
.boxed(),
|
.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 {
|
if index == selected_index || index < self.matches.len() - 1 {
|
||||||
container =
|
container =
|
||||||
container.with_border(Border::bottom(1.0, ColorU::from_u32(0xdbdbdcff)));
|
container.with_border(Border::bottom(1.0, theme.modal_match_border));
|
||||||
}
|
|
||||||
|
|
||||||
if index == selected_index {
|
|
||||||
container = container.with_background_color(ColorU::from_u32(0xdbdbdcff));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = (path_match.tree_id, path_match.path.clone());
|
let entry = (path_match.tree_id, path_match.path.clone());
|
||||||
|
|
|
@ -7,7 +7,12 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use postage::watch;
|
use postage::watch;
|
||||||
use serde::Deserialize;
|
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);
|
const DEFAULT_STYLE_ID: StyleId = StyleId(u32::MAX);
|
||||||
|
|
||||||
|
@ -23,12 +28,50 @@ pub struct Settings {
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Theme {
|
pub struct Theme {
|
||||||
pub background_color: ColorU,
|
pub ui: UiTheme,
|
||||||
pub line_number_color: ColorU,
|
pub editor: EditorTheme,
|
||||||
pub default_text_color: ColorU,
|
syntax: Vec<(String, ColorU, FontProperties)>,
|
||||||
syntax_styles: 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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ThemeMap(Arc<[StyleId]>);
|
pub struct ThemeMap(Arc<[StyleId]>);
|
||||||
|
|
||||||
|
@ -44,7 +87,7 @@ impl Settings {
|
||||||
ui_font_family: font_cache.load_family(&["SF Pro", "Helvetica"])?,
|
ui_font_family: font_cache.load_family(&["SF Pro", "Helvetica"])?,
|
||||||
ui_font_size: 12.0,
|
ui_font_size: 12.0,
|
||||||
theme: Arc::new(
|
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"),
|
.expect("Failed to parse built-in theme"),
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
@ -61,17 +104,19 @@ impl Theme {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct ThemeToml {
|
struct ThemeToml {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
syntax: HashMap<String, StyleToml>,
|
ui: UiTheme,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
ui: HashMap<String, u32>,
|
editor: EditorTheme,
|
||||||
|
#[serde(default)]
|
||||||
|
syntax: HashMap<String, StyleToml>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
enum StyleToml {
|
enum StyleToml {
|
||||||
Color(u32),
|
Color(Color),
|
||||||
Full {
|
Full {
|
||||||
color: Option<u32>,
|
color: Option<Color>,
|
||||||
weight: Option<toml::Value>,
|
weight: Option<toml::Value>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
italic: bool,
|
italic: bool,
|
||||||
|
@ -81,7 +126,7 @@ impl Theme {
|
||||||
let theme_toml: ThemeToml =
|
let theme_toml: ThemeToml =
|
||||||
toml::from_slice(source.as_ref()).context("failed to parse theme TOML")?;
|
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 {
|
for (key, style) in theme_toml.syntax {
|
||||||
let (color, weight, italic) = match style {
|
let (color, weight, italic) = match style {
|
||||||
StyleToml::Color(color) => (color, None, false),
|
StyleToml::Color(color) => (color, None, false),
|
||||||
|
@ -89,55 +134,37 @@ impl Theme {
|
||||||
color,
|
color,
|
||||||
weight,
|
weight,
|
||||||
italic,
|
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) => {
|
Ok(i) | Err(i) => {
|
||||||
let mut properties = FontProperties::new();
|
let mut properties = FontProperties::new();
|
||||||
properties.weight = deserialize_weight(weight)?;
|
properties.weight = deserialize_weight(weight)?;
|
||||||
if italic {
|
if italic {
|
||||||
properties.style = FontStyle::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 {
|
Ok(Theme {
|
||||||
background_color,
|
ui: theme_toml.ui,
|
||||||
line_number_color,
|
editor: theme_toml.editor,
|
||||||
default_text_color,
|
syntax,
|
||||||
syntax_styles,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syntax_style(&self, id: StyleId) -> (ColorU, FontProperties) {
|
pub fn syntax_style(&self, id: StyleId) -> (ColorU, FontProperties) {
|
||||||
self.syntax_styles
|
self.syntax.get(id.0 as usize).map_or(
|
||||||
.get(id.0 as usize)
|
(self.editor.default_text.0, FontProperties::new()),
|
||||||
.map_or((self.default_text_color, FontProperties::new()), |entry| {
|
|entry| (entry.1, entry.2),
|
||||||
(entry.1, entry.2)
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn syntax_style_name(&self, id: StyleId) -> Option<&str> {
|
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()
|
.iter()
|
||||||
.map(|capture_name| {
|
.map(|capture_name| {
|
||||||
theme
|
theme
|
||||||
.syntax_styles
|
.syntax
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(i, (key, _, _))| {
|
.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(
|
pub fn channel(
|
||||||
font_cache: &FontCache,
|
font_cache: &FontCache,
|
||||||
) -> Result<(watch::Sender<Settings>, watch::Receiver<Settings>)> {
|
) -> Result<(watch::Sender<Settings>, watch::Receiver<Settings>)> {
|
||||||
Ok(watch::channel_with(Settings::new(font_cache)?))
|
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> {
|
fn deserialize_weight(weight: Option<toml::Value>) -> Result<FontWeight> {
|
||||||
match &weight {
|
match &weight {
|
||||||
None => return Ok(FontWeight::NORMAL),
|
None => return Ok(FontWeight::NORMAL),
|
||||||
|
@ -228,8 +292,11 @@ mod tests {
|
||||||
let theme = Theme::parse(
|
let theme = Theme::parse(
|
||||||
r#"
|
r#"
|
||||||
[ui]
|
[ui]
|
||||||
|
tab_background_active = 0x100000
|
||||||
|
|
||||||
|
[editor]
|
||||||
background = 0x00ed00
|
background = 0x00ed00
|
||||||
line_numbers = 0xdddddd
|
line_number = 0xdddddd
|
||||||
|
|
||||||
[syntax]
|
[syntax]
|
||||||
"beta.two" = 0xAABBCC
|
"beta.two" = 0xAABBCC
|
||||||
|
@ -239,24 +306,25 @@ mod tests {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(theme.background_color, ColorU::from_u32(0x00ED00FF));
|
assert_eq!(theme.ui.tab_background_active, ColorU::from_u32(0x100000ff));
|
||||||
assert_eq!(theme.line_number_color, ColorU::from_u32(0xddddddff));
|
assert_eq!(theme.editor.background, ColorU::from_u32(0x00ed00ff));
|
||||||
|
assert_eq!(theme.editor.line_number, ColorU::from_u32(0xddddddff));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
theme.syntax_styles,
|
theme.syntax,
|
||||||
&[
|
&[
|
||||||
(
|
(
|
||||||
"alpha.one".to_string(),
|
"alpha.one".to_string(),
|
||||||
ColorU::from_u32(0x112233FF),
|
ColorU::from_u32(0x112233ff),
|
||||||
*FontProperties::new().weight(FontWeight::BOLD)
|
*FontProperties::new().weight(FontWeight::BOLD)
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"beta.two".to_string(),
|
"beta.two".to_string(),
|
||||||
ColorU::from_u32(0xAABBCCFF),
|
ColorU::from_u32(0xaabbccff),
|
||||||
*FontProperties::new().weight(FontWeight::NORMAL)
|
*FontProperties::new().weight(FontWeight::NORMAL)
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"gamma.three".to_string(),
|
"gamma.three".to_string(),
|
||||||
ColorU::from_u32(0x000000FF),
|
ColorU::from_u32(0x00000000),
|
||||||
*FontProperties::new()
|
*FontProperties::new()
|
||||||
.weight(FontWeight::LIGHT)
|
.weight(FontWeight::LIGHT)
|
||||||
.style(FontStyle::Italic),
|
.style(FontStyle::Italic),
|
||||||
|
@ -273,10 +341,9 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_theme_map() {
|
fn test_theme_map() {
|
||||||
let theme = Theme {
|
let theme = Theme {
|
||||||
default_text_color: Default::default(),
|
ui: Default::default(),
|
||||||
background_color: ColorU::default(),
|
editor: Default::default(),
|
||||||
line_number_color: ColorU::default(),
|
syntax: [
|
||||||
syntax_styles: [
|
|
||||||
("function", ColorU::from_u32(0x100000ff)),
|
("function", ColorU::from_u32(0x100000ff)),
|
||||||
("function.method", ColorU::from_u32(0x200000ff)),
|
("function.method", ColorU::from_u32(0x200000ff)),
|
||||||
("function.async", ColorU::from_u32(0x300000ff)),
|
("function.async", ColorU::from_u32(0x300000ff)),
|
||||||
|
|
|
@ -12,9 +12,9 @@ use crate::{
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
color::rgbu, elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, AppContext,
|
elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, AppContext, ClipboardItem,
|
||||||
ClipboardItem, Entity, ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, Task,
|
Entity, ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, Task, View,
|
||||||
View, ViewContext, ViewHandle, WeakModelHandle,
|
ViewContext, ViewHandle, WeakModelHandle,
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
pub use pane::*;
|
pub use pane::*;
|
||||||
|
@ -880,14 +880,14 @@ impl View for Workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&self, _: &AppContext) -> ElementBox {
|
fn render(&self, _: &AppContext) -> ElementBox {
|
||||||
|
let settings = self.settings.borrow();
|
||||||
Container::new(
|
Container::new(
|
||||||
// self.center.render(bump)
|
|
||||||
Stack::new()
|
Stack::new()
|
||||||
.with_child(self.center.render())
|
.with_child(self.center.render())
|
||||||
.with_children(self.modal.as_ref().map(|m| ChildView::new(m.id()).boxed()))
|
.with_children(self.modal.as_ref().map(|m| ChildView::new(m.id()).boxed()))
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_background_color(rgbu(0xea, 0xea, 0xeb))
|
.with_background_color(settings.theme.editor.background)
|
||||||
.named("workspace")
|
.named("workspace")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{ItemViewHandle, SplitDirection};
|
use super::{ItemViewHandle, SplitDirection};
|
||||||
use crate::settings::Settings;
|
use crate::settings::{Settings, UiTheme};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
color::ColorU,
|
color::ColorU,
|
||||||
elements::*,
|
elements::*,
|
||||||
|
@ -180,7 +180,7 @@ impl Pane {
|
||||||
|
|
||||||
fn render_tabs(&self, cx: &AppContext) -> ElementBox {
|
fn render_tabs(&self, cx: &AppContext) -> ElementBox {
|
||||||
let settings = self.settings.borrow();
|
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(
|
let line_height = cx.font_cache().line_height(
|
||||||
cx.font_cache().default_font(settings.ui_font_family),
|
cx.font_cache().default_font(settings.ui_font_family),
|
||||||
settings.ui_font_size,
|
settings.ui_font_size,
|
||||||
|
@ -189,6 +189,8 @@ impl Pane {
|
||||||
let mut row = Flex::row();
|
let mut row = Flex::row();
|
||||||
let last_item_ix = self.items.len() - 1;
|
let last_item_ix = self.items.len() - 1;
|
||||||
for (ix, item) in self.items.iter().enumerate() {
|
for (ix, item) in self.items.iter().enumerate() {
|
||||||
|
let is_active = ix == self.active_item;
|
||||||
|
|
||||||
enum Tab {}
|
enum Tab {}
|
||||||
|
|
||||||
row.add_child(
|
row.add_child(
|
||||||
|
@ -197,7 +199,7 @@ impl Pane {
|
||||||
MouseEventHandler::new::<Tab, _>(item.id(), cx, |mouse_state| {
|
MouseEventHandler::new::<Tab, _>(item.id(), cx, |mouse_state| {
|
||||||
let title = item.title(cx);
|
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.left = ix > 0;
|
||||||
border.right = ix == last_item_ix;
|
border.right = ix == last_item_ix;
|
||||||
border.bottom = ix != self.active_item;
|
border.bottom = ix != self.active_item;
|
||||||
|
@ -211,6 +213,11 @@ impl Pane {
|
||||||
settings.ui_font_family,
|
settings.ui_font_family,
|
||||||
settings.ui_font_size,
|
settings.ui_font_size,
|
||||||
)
|
)
|
||||||
|
.with_default_color(if is_active {
|
||||||
|
theme.tab_text_active.0
|
||||||
|
} else {
|
||||||
|
theme.tab_text.0
|
||||||
|
})
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
@ -222,6 +229,7 @@ impl Pane {
|
||||||
mouse_state.hovered,
|
mouse_state.hovered,
|
||||||
item.is_dirty(cx),
|
item.is_dirty(cx),
|
||||||
item.has_conflict(cx),
|
item.has_conflict(cx),
|
||||||
|
theme,
|
||||||
cx,
|
cx,
|
||||||
))
|
))
|
||||||
.right()
|
.right()
|
||||||
|
@ -232,13 +240,12 @@ impl Pane {
|
||||||
.with_horizontal_padding(10.)
|
.with_horizontal_padding(10.)
|
||||||
.with_border(border);
|
.with_border(border);
|
||||||
|
|
||||||
if ix == self.active_item {
|
if is_active {
|
||||||
container = container
|
container = container
|
||||||
.with_background_color(ColorU::white())
|
.with_background_color(theme.tab_background_active)
|
||||||
.with_padding_bottom(border.width);
|
.with_padding_bottom(border.width);
|
||||||
} else {
|
} else {
|
||||||
container =
|
container = container.with_background_color(theme.tab_background);
|
||||||
container.with_background_color(ColorU::from_u32(0xeaeaebff));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstrainedBox::new(
|
ConstrainedBox::new(
|
||||||
|
@ -264,7 +271,7 @@ impl Pane {
|
||||||
row.add_child(
|
row.add_child(
|
||||||
ConstrainedBox::new(
|
ConstrainedBox::new(
|
||||||
Container::new(Empty::new().boxed())
|
Container::new(Empty::new().boxed())
|
||||||
.with_border(Border::bottom(1.0, border_color))
|
.with_border(Border::bottom(1.0, theme.tab_border))
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_min_width(20.)
|
.with_min_width(20.)
|
||||||
|
@ -275,7 +282,7 @@ impl Pane {
|
||||||
Expanded::new(
|
Expanded::new(
|
||||||
0.0,
|
0.0,
|
||||||
Container::new(Empty::new().boxed())
|
Container::new(Empty::new().boxed())
|
||||||
.with_border(Border::bottom(1.0, border_color))
|
.with_border(Border::bottom(1.0, theme.tab_border))
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.named("filler"),
|
.named("filler"),
|
||||||
|
@ -292,25 +299,25 @@ impl Pane {
|
||||||
tab_hovered: bool,
|
tab_hovered: bool,
|
||||||
is_dirty: bool,
|
is_dirty: bool,
|
||||||
has_conflict: bool,
|
has_conflict: bool,
|
||||||
|
theme: &UiTheme,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
enum TabCloseButton {}
|
enum TabCloseButton {}
|
||||||
|
|
||||||
let dirty_color = ColorU::from_u32(0x556de8ff);
|
let mut clicked_color = theme.tab_icon_dirty;
|
||||||
let conflict_color = ColorU::from_u32(0xe45349ff);
|
|
||||||
let mut clicked_color = dirty_color;
|
|
||||||
clicked_color.a = 180;
|
clicked_color.a = 180;
|
||||||
|
|
||||||
let current_color = if has_conflict {
|
let current_color = if has_conflict {
|
||||||
Some(conflict_color)
|
Some(theme.tab_icon_conflict)
|
||||||
} else if is_dirty {
|
} else if is_dirty {
|
||||||
Some(dirty_color)
|
Some(theme.tab_icon_dirty)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let icon = if tab_hovered {
|
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| {
|
MouseEventHandler::new::<TabCloseButton, _>(item_id, cx, |mouse_state| {
|
||||||
if mouse_state.hovered {
|
if mouse_state.hovered {
|
||||||
|
@ -318,14 +325,11 @@ impl Pane {
|
||||||
.with_background_color(if mouse_state.clicked {
|
.with_background_color(if mouse_state.clicked {
|
||||||
clicked_color
|
clicked_color
|
||||||
} else {
|
} else {
|
||||||
dirty_color
|
theme.tab_icon_dirty
|
||||||
})
|
})
|
||||||
.with_corner_radius(close_icon_size / 2.)
|
.with_corner_radius(close_icon_size / 2.)
|
||||||
.boxed()
|
.boxed()
|
||||||
} else {
|
} else {
|
||||||
if let Some(current_color) = current_color {
|
|
||||||
icon = icon.with_color(current_color);
|
|
||||||
}
|
|
||||||
icon.boxed()
|
icon.boxed()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -339,7 +343,7 @@ impl Pane {
|
||||||
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
|
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
|
||||||
cx.scene.push_quad(Quad {
|
cx.scene.push_quad(Quad {
|
||||||
bounds: square,
|
bounds: square,
|
||||||
background: Some(current_color),
|
background: Some(current_color.0),
|
||||||
border: Default::default(),
|
border: Default::default(),
|
||||||
corner_radius: diameter / 2.,
|
corner_radius: diameter / 2.,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue