Mainline GPUI2 UI work (#3099)
This PR mainlines the current state of new GPUI2-based UI from the `gpui2-ui` branch. Included in this is a performance improvement to make use of the `TextLayoutCache` when calling `layout` for `Text` elements. Release Notes: - N/A --------- Co-authored-by: Nate Butler <iamnbutler@gmail.com> Co-authored-by: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
parent
c46137e40d
commit
456baaa112
18 changed files with 371 additions and 19 deletions
|
@ -71,7 +71,7 @@ pub struct Window {
|
|||
pub(crate) hovered_region_ids: Vec<MouseRegionId>,
|
||||
pub(crate) clicked_region_ids: Vec<MouseRegionId>,
|
||||
pub(crate) clicked_region: Option<(MouseRegionId, MouseButton)>,
|
||||
text_layout_cache: TextLayoutCache,
|
||||
text_layout_cache: Arc<TextLayoutCache>,
|
||||
refreshing: bool,
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ impl Window {
|
|||
cursor_regions: Default::default(),
|
||||
mouse_regions: Default::default(),
|
||||
event_handlers: Default::default(),
|
||||
text_layout_cache: TextLayoutCache::new(cx.font_system.clone()),
|
||||
text_layout_cache: Arc::new(TextLayoutCache::new(cx.font_system.clone())),
|
||||
last_mouse_moved_event: None,
|
||||
last_mouse_position: Vector2F::zero(),
|
||||
pressed_buttons: Default::default(),
|
||||
|
@ -303,7 +303,7 @@ impl<'a> WindowContext<'a> {
|
|||
self.window.refreshing
|
||||
}
|
||||
|
||||
pub fn text_layout_cache(&self) -> &TextLayoutCache {
|
||||
pub fn text_layout_cache(&self) -> &Arc<TextLayoutCache> {
|
||||
&self.window.text_layout_cache
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
use anyhow::Result;
|
||||
use gpui::{
|
||||
geometry::{vector::Vector2F, Size},
|
||||
text_layout::LineLayout,
|
||||
text_layout::Line,
|
||||
LayoutId,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
|
@ -32,7 +32,7 @@ impl<V: 'static> Element<V> for Text {
|
|||
_view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Result<(LayoutId, Self::PaintState)> {
|
||||
let fonts = cx.platform().fonts();
|
||||
let layout_cache = cx.text_layout_cache().clone();
|
||||
let text_style = cx.text_style();
|
||||
let line_height = cx.font_cache().line_height(text_style.font_size);
|
||||
let text = self.text.clone();
|
||||
|
@ -41,14 +41,14 @@ impl<V: 'static> Element<V> for Text {
|
|||
let layout_id = cx.add_measured_layout_node(Default::default(), {
|
||||
let paint_state = paint_state.clone();
|
||||
move |_params| {
|
||||
let line_layout = fonts.layout_line(
|
||||
let line_layout = layout_cache.layout_str(
|
||||
text.as_ref(),
|
||||
text_style.font_size,
|
||||
&[(text.len(), text_style.to_run())],
|
||||
);
|
||||
|
||||
let size = Size {
|
||||
width: line_layout.width,
|
||||
width: line_layout.width(),
|
||||
height: line_height,
|
||||
};
|
||||
|
||||
|
@ -85,13 +85,9 @@ impl<V: 'static> Element<V> for Text {
|
|||
line_height = paint_state.line_height;
|
||||
}
|
||||
|
||||
let text_style = cx.text_style();
|
||||
let line =
|
||||
gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]);
|
||||
|
||||
// TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
|
||||
let visible_bounds = bounds;
|
||||
line.paint(bounds.origin(), visible_bounds, line_height, cx.legacy_cx);
|
||||
line_layout.paint(bounds.origin(), visible_bounds, line_height, cx.legacy_cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,6 +100,6 @@ impl<V: 'static> IntoElement<V> for Text {
|
|||
}
|
||||
|
||||
pub struct TextLayout {
|
||||
line_layout: Arc<LineLayout>,
|
||||
line_layout: Arc<Line>,
|
||||
line_height: f32,
|
||||
}
|
||||
|
|
|
@ -6,13 +6,17 @@ pub mod collab_panel;
|
|||
pub mod context_menu;
|
||||
pub mod facepile;
|
||||
pub mod keybinding;
|
||||
pub mod language_selector;
|
||||
pub mod multi_buffer;
|
||||
pub mod palette;
|
||||
pub mod panel;
|
||||
pub mod project_panel;
|
||||
pub mod recent_projects;
|
||||
pub mod status_bar;
|
||||
pub mod tab;
|
||||
pub mod tab_bar;
|
||||
pub mod terminal;
|
||||
pub mod theme_selector;
|
||||
pub mod title_bar;
|
||||
pub mod toolbar;
|
||||
pub mod traffic_lights;
|
||||
|
|
16
crates/storybook/src/stories/components/language_selector.rs
Normal file
16
crates/storybook/src/stories/components/language_selector.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use ui::prelude::*;
|
||||
use ui::LanguageSelector;
|
||||
|
||||
use crate::story::Story;
|
||||
|
||||
#[derive(Element, Default)]
|
||||
pub struct LanguageSelectorStory {}
|
||||
|
||||
impl LanguageSelectorStory {
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<_, LanguageSelector>(cx))
|
||||
.child(Story::label(cx, "Default"))
|
||||
.child(LanguageSelector::new())
|
||||
}
|
||||
}
|
24
crates/storybook/src/stories/components/multi_buffer.rs
Normal file
24
crates/storybook/src/stories/components/multi_buffer.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use ui::prelude::*;
|
||||
use ui::{hello_world_rust_buffer_example, MultiBuffer};
|
||||
|
||||
use crate::story::Story;
|
||||
|
||||
#[derive(Element, Default)]
|
||||
pub struct MultiBufferStory {}
|
||||
|
||||
impl MultiBufferStory {
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<_, MultiBuffer<V>>(cx))
|
||||
.child(Story::label(cx, "Default"))
|
||||
.child(MultiBuffer::new(vec![
|
||||
hello_world_rust_buffer_example(&theme),
|
||||
hello_world_rust_buffer_example(&theme),
|
||||
hello_world_rust_buffer_example(&theme),
|
||||
hello_world_rust_buffer_example(&theme),
|
||||
hello_world_rust_buffer_example(&theme),
|
||||
]))
|
||||
}
|
||||
}
|
16
crates/storybook/src/stories/components/recent_projects.rs
Normal file
16
crates/storybook/src/stories/components/recent_projects.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use ui::prelude::*;
|
||||
use ui::RecentProjects;
|
||||
|
||||
use crate::story::Story;
|
||||
|
||||
#[derive(Element, Default)]
|
||||
pub struct RecentProjectsStory {}
|
||||
|
||||
impl RecentProjectsStory {
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<_, RecentProjects>(cx))
|
||||
.child(Story::label(cx, "Default"))
|
||||
.child(RecentProjects::new())
|
||||
}
|
||||
}
|
16
crates/storybook/src/stories/components/theme_selector.rs
Normal file
16
crates/storybook/src/stories/components/theme_selector.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use ui::prelude::*;
|
||||
use ui::ThemeSelector;
|
||||
|
||||
use crate::story::Story;
|
||||
|
||||
#[derive(Element, Default)]
|
||||
pub struct ThemeSelectorStory {}
|
||||
|
||||
impl ThemeSelectorStory {
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<_, ThemeSelector>(cx))
|
||||
.child(Story::label(cx, "Default"))
|
||||
.child(ThemeSelector::new())
|
||||
}
|
||||
}
|
|
@ -42,13 +42,17 @@ pub enum ComponentStory {
|
|||
CollabPanel,
|
||||
Facepile,
|
||||
Keybinding,
|
||||
LanguageSelector,
|
||||
MultiBuffer,
|
||||
Palette,
|
||||
Panel,
|
||||
ProjectPanel,
|
||||
RecentProjects,
|
||||
StatusBar,
|
||||
Tab,
|
||||
TabBar,
|
||||
Terminal,
|
||||
ThemeSelector,
|
||||
TitleBar,
|
||||
Toolbar,
|
||||
TrafficLights,
|
||||
|
@ -69,15 +73,25 @@ impl ComponentStory {
|
|||
Self::CollabPanel => components::collab_panel::CollabPanelStory::default().into_any(),
|
||||
Self::Facepile => components::facepile::FacepileStory::default().into_any(),
|
||||
Self::Keybinding => components::keybinding::KeybindingStory::default().into_any(),
|
||||
Self::LanguageSelector => {
|
||||
components::language_selector::LanguageSelectorStory::default().into_any()
|
||||
}
|
||||
Self::MultiBuffer => components::multi_buffer::MultiBufferStory::default().into_any(),
|
||||
Self::Palette => components::palette::PaletteStory::default().into_any(),
|
||||
Self::Panel => components::panel::PanelStory::default().into_any(),
|
||||
Self::ProjectPanel => {
|
||||
components::project_panel::ProjectPanelStory::default().into_any()
|
||||
}
|
||||
Self::RecentProjects => {
|
||||
components::recent_projects::RecentProjectsStory::default().into_any()
|
||||
}
|
||||
Self::StatusBar => components::status_bar::StatusBarStory::default().into_any(),
|
||||
Self::Tab => components::tab::TabStory::default().into_any(),
|
||||
Self::TabBar => components::tab_bar::TabBarStory::default().into_any(),
|
||||
Self::Terminal => components::terminal::TerminalStory::default().into_any(),
|
||||
Self::ThemeSelector => {
|
||||
components::theme_selector::ThemeSelectorStory::default().into_any()
|
||||
}
|
||||
Self::TitleBar => components::title_bar::TitleBarStory::default().into_any(),
|
||||
Self::Toolbar => components::toolbar::ToolbarStory::default().into_any(),
|
||||
Self::TrafficLights => {
|
||||
|
|
|
@ -9,17 +9,22 @@ mod editor_pane;
|
|||
mod facepile;
|
||||
mod icon_button;
|
||||
mod keybinding;
|
||||
mod language_selector;
|
||||
mod list;
|
||||
mod multi_buffer;
|
||||
mod palette;
|
||||
mod panel;
|
||||
mod panes;
|
||||
mod player_stack;
|
||||
mod project_panel;
|
||||
mod recent_projects;
|
||||
mod status_bar;
|
||||
mod tab;
|
||||
mod tab_bar;
|
||||
mod terminal;
|
||||
mod theme_selector;
|
||||
mod title_bar;
|
||||
mod toast;
|
||||
mod toolbar;
|
||||
mod traffic_lights;
|
||||
mod workspace;
|
||||
|
@ -35,17 +40,22 @@ pub use editor_pane::*;
|
|||
pub use facepile::*;
|
||||
pub use icon_button::*;
|
||||
pub use keybinding::*;
|
||||
pub use language_selector::*;
|
||||
pub use list::*;
|
||||
pub use multi_buffer::*;
|
||||
pub use palette::*;
|
||||
pub use panel::*;
|
||||
pub use panes::*;
|
||||
pub use player_stack::*;
|
||||
pub use project_panel::*;
|
||||
pub use recent_projects::*;
|
||||
pub use status_bar::*;
|
||||
pub use tab::*;
|
||||
pub use tab_bar::*;
|
||||
pub use terminal::*;
|
||||
pub use theme_selector::*;
|
||||
pub use title_bar::*;
|
||||
pub use toast::*;
|
||||
pub use toolbar::*;
|
||||
pub use traffic_lights::*;
|
||||
pub use workspace::*;
|
||||
|
|
36
crates/ui/src/components/language_selector.rs
Normal file
36
crates/ui/src/components/language_selector.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{OrderMethod, Palette, PaletteItem};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct LanguageSelector {
|
||||
scroll_state: ScrollState,
|
||||
}
|
||||
|
||||
impl LanguageSelector {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scroll_state: ScrollState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
div().child(
|
||||
Palette::new(self.scroll_state.clone())
|
||||
.items(vec![
|
||||
PaletteItem::new("C"),
|
||||
PaletteItem::new("C++"),
|
||||
PaletteItem::new("CSS"),
|
||||
PaletteItem::new("Elixir"),
|
||||
PaletteItem::new("Elm"),
|
||||
PaletteItem::new("ERB"),
|
||||
PaletteItem::new("Rust (current)"),
|
||||
PaletteItem::new("Scheme"),
|
||||
PaletteItem::new("TOML"),
|
||||
PaletteItem::new("TypeScript"),
|
||||
])
|
||||
.placeholder("Select a language...")
|
||||
.empty_string("No matches")
|
||||
.default_order(OrderMethod::Ascending),
|
||||
)
|
||||
}
|
||||
}
|
42
crates/ui/src/components/multi_buffer.rs
Normal file
42
crates/ui/src/components/multi_buffer.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{v_stack, Buffer, Icon, IconButton, Label, LabelSize};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct MultiBuffer<V: 'static> {
|
||||
view_type: PhantomData<V>,
|
||||
buffers: Vec<Buffer>,
|
||||
}
|
||||
|
||||
impl<V: 'static> MultiBuffer<V> {
|
||||
pub fn new(buffers: Vec<Buffer>) -> Self {
|
||||
Self {
|
||||
view_type: PhantomData,
|
||||
buffers,
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let theme = theme(cx);
|
||||
|
||||
v_stack()
|
||||
.w_full()
|
||||
.h_full()
|
||||
.flex_1()
|
||||
.children(self.buffers.clone().into_iter().map(|buffer| {
|
||||
v_stack()
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.p_4()
|
||||
.fill(theme.lowest.base.default.background)
|
||||
.child(Label::new("main.rs").size(LabelSize::Small))
|
||||
.child(IconButton::new(Icon::ArrowUpRight)),
|
||||
)
|
||||
.child(buffer)
|
||||
}))
|
||||
}
|
||||
}
|
|
@ -93,19 +93,17 @@ impl<V: 'static> Palette<V> {
|
|||
.fill(theme.lowest.base.hovered.background)
|
||||
.active()
|
||||
.fill(theme.lowest.base.pressed.background)
|
||||
.child(
|
||||
PaletteItem::new(item.label)
|
||||
.keybinding(item.keybinding.clone()),
|
||||
)
|
||||
.child(item.clone())
|
||||
})),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Element)]
|
||||
#[derive(Element, Clone)]
|
||||
pub struct PaletteItem {
|
||||
pub label: &'static str,
|
||||
pub sublabel: Option<&'static str>,
|
||||
pub keybinding: Option<Keybinding>,
|
||||
}
|
||||
|
||||
|
@ -113,6 +111,7 @@ impl PaletteItem {
|
|||
pub fn new(label: &'static str) -> Self {
|
||||
Self {
|
||||
label,
|
||||
sublabel: None,
|
||||
keybinding: None,
|
||||
}
|
||||
}
|
||||
|
@ -122,6 +121,11 @@ impl PaletteItem {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn sublabel<L: Into<Option<&'static str>>>(mut self, sublabel: L) -> Self {
|
||||
self.sublabel = sublabel.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn keybinding<K>(mut self, keybinding: K) -> Self
|
||||
where
|
||||
K: Into<Option<Keybinding>>,
|
||||
|
@ -138,7 +142,11 @@ impl PaletteItem {
|
|||
.flex_row()
|
||||
.grow()
|
||||
.justify_between()
|
||||
.child(Label::new(self.label))
|
||||
.child(
|
||||
v_stack()
|
||||
.child(Label::new(self.label))
|
||||
.children(self.sublabel.map(|sublabel| Label::new(sublabel))),
|
||||
)
|
||||
.children(self.keybinding.clone())
|
||||
}
|
||||
}
|
||||
|
|
32
crates/ui/src/components/recent_projects.rs
Normal file
32
crates/ui/src/components/recent_projects.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{OrderMethod, Palette, PaletteItem};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct RecentProjects {
|
||||
scroll_state: ScrollState,
|
||||
}
|
||||
|
||||
impl RecentProjects {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scroll_state: ScrollState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
div().child(
|
||||
Palette::new(self.scroll_state.clone())
|
||||
.items(vec![
|
||||
PaletteItem::new("zed").sublabel("~/projects/zed"),
|
||||
PaletteItem::new("saga").sublabel("~/projects/saga"),
|
||||
PaletteItem::new("journal").sublabel("~/journal"),
|
||||
PaletteItem::new("dotfiles").sublabel("~/dotfiles"),
|
||||
PaletteItem::new("zed.dev").sublabel("~/projects/zed.dev"),
|
||||
PaletteItem::new("laminar").sublabel("~/projects/laminar"),
|
||||
])
|
||||
.placeholder("Recent Projects...")
|
||||
.empty_string("No matches")
|
||||
.default_order(OrderMethod::Ascending),
|
||||
)
|
||||
}
|
||||
}
|
37
crates/ui/src/components/theme_selector.rs
Normal file
37
crates/ui/src/components/theme_selector.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{OrderMethod, Palette, PaletteItem};
|
||||
|
||||
#[derive(Element)]
|
||||
pub struct ThemeSelector {
|
||||
scroll_state: ScrollState,
|
||||
}
|
||||
|
||||
impl ThemeSelector {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scroll_state: ScrollState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
div().child(
|
||||
Palette::new(self.scroll_state.clone())
|
||||
.items(vec![
|
||||
PaletteItem::new("One Dark"),
|
||||
PaletteItem::new("Rosé Pine"),
|
||||
PaletteItem::new("Rosé Pine Moon"),
|
||||
PaletteItem::new("Sandcastle"),
|
||||
PaletteItem::new("Solarized Dark"),
|
||||
PaletteItem::new("Summercamp"),
|
||||
PaletteItem::new("Atelier Cave Light"),
|
||||
PaletteItem::new("Atelier Dune Light"),
|
||||
PaletteItem::new("Atelier Estuary Light"),
|
||||
PaletteItem::new("Atelier Forest Light"),
|
||||
PaletteItem::new("Atelier Heath Light"),
|
||||
])
|
||||
.placeholder("Select Theme...")
|
||||
.empty_string("No matches")
|
||||
.default_order(OrderMethod::Ascending),
|
||||
)
|
||||
}
|
||||
}
|
66
crates/ui/src/components/toast.rs
Normal file
66
crates/ui/src/components/toast.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum ToastOrigin {
|
||||
#[default]
|
||||
Bottom,
|
||||
BottomRight,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum ToastVariant {
|
||||
#[default]
|
||||
Toast,
|
||||
Status,
|
||||
}
|
||||
|
||||
/// A toast is a small, temporary window that appears to show a message to the user
|
||||
/// or indicate a required action.
|
||||
///
|
||||
/// Toasts should not persist on the screen for more than a few seconds unless
|
||||
/// they are actively showing the a process in progress.
|
||||
///
|
||||
/// Only one toast may be visible at a time.
|
||||
#[derive(Element)]
|
||||
pub struct Toast<V: 'static> {
|
||||
origin: ToastOrigin,
|
||||
children: HackyChildren<V>,
|
||||
payload: HackyChildrenPayload,
|
||||
}
|
||||
|
||||
impl<V: 'static> Toast<V> {
|
||||
pub fn new(
|
||||
origin: ToastOrigin,
|
||||
children: HackyChildren<V>,
|
||||
payload: HackyChildrenPayload,
|
||||
) -> Self {
|
||||
Self {
|
||||
origin,
|
||||
children,
|
||||
payload,
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
|
||||
let color = ThemeColor::new(cx);
|
||||
|
||||
let mut div = div();
|
||||
|
||||
if self.origin == ToastOrigin::Bottom {
|
||||
div = div.right_1_2();
|
||||
} else {
|
||||
div = div.right_4();
|
||||
}
|
||||
|
||||
div.absolute()
|
||||
.bottom_4()
|
||||
.flex()
|
||||
.py_2()
|
||||
.px_1p5()
|
||||
.min_w_40()
|
||||
.rounded_md()
|
||||
.fill(color.elevated_surface)
|
||||
.max_w_64()
|
||||
.children_any((self.children)(cx, self.payload.as_ref()))
|
||||
}
|
||||
}
|
|
@ -82,6 +82,7 @@ impl WorkspaceElement {
|
|||
);
|
||||
|
||||
div()
|
||||
.relative()
|
||||
.size_full()
|
||||
.flex()
|
||||
.flex_col()
|
||||
|
@ -169,5 +170,17 @@ impl WorkspaceElement {
|
|||
),
|
||||
)
|
||||
.child(StatusBar::new())
|
||||
// An example of a toast is below
|
||||
// Currently because of stacking order this gets obscured by other elements
|
||||
|
||||
// .child(Toast::new(
|
||||
// ToastOrigin::Bottom,
|
||||
// |_, payload| {
|
||||
// let theme = payload.downcast_ref::<Arc<Theme>>().unwrap();
|
||||
|
||||
// vec![Label::new("label").into_any()]
|
||||
// },
|
||||
// Box::new(theme.clone()),
|
||||
// ))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ pub enum Icon {
|
|||
ChevronUp,
|
||||
Close,
|
||||
ExclamationTriangle,
|
||||
ExternalLink,
|
||||
File,
|
||||
FileGeneric,
|
||||
FileDoc,
|
||||
|
@ -109,6 +110,7 @@ impl Icon {
|
|||
Icon::ChevronUp => "icons/chevron_up.svg",
|
||||
Icon::Close => "icons/x.svg",
|
||||
Icon::ExclamationTriangle => "icons/warning.svg",
|
||||
Icon::ExternalLink => "icons/external_link.svg",
|
||||
Icon::File => "icons/file.svg",
|
||||
Icon::FileGeneric => "icons/file_icons/file.svg",
|
||||
Icon::FileDoc => "icons/file_icons/book.svg",
|
||||
|
|
|
@ -29,6 +29,26 @@ impl SystemColor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ThemeColor {
|
||||
pub border: Hsla,
|
||||
pub border_variant: Hsla,
|
||||
/// The background color of an elevated surface, like a modal, tooltip or toast.
|
||||
pub elevated_surface: Hsla,
|
||||
}
|
||||
|
||||
impl ThemeColor {
|
||||
pub fn new(cx: &WindowContext) -> Self {
|
||||
let theme = theme(cx);
|
||||
|
||||
Self {
|
||||
border: theme.lowest.base.default.border,
|
||||
border_variant: theme.lowest.variant.default.border,
|
||||
elevated_surface: theme.middle.base.default.background,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, EnumIter, Clone, Copy)]
|
||||
pub enum HighlightColor {
|
||||
#[default]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue