Detailed changes
@@ -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)]
}
}
}
@@ -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_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"
@@ -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);
@@ -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);
@@ -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());
@@ -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)]
+ editor: EditorTheme,
#[serde(default)]
- ui: HashMap<String, u32>,
+ 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)),
@@ -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")
}
@@ -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.,
});