Cleanup first version impls (#132)

This commit is contained in:
Jason Lee 2024-08-11 14:46:55 +08:00 committed by GitHub
parent 8f71b807aa
commit bb6d8d8f60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 152 additions and 300 deletions

View file

@ -14,7 +14,7 @@ use ui::{
popover::Popover, popover::Popover,
popup_menu::PopupMenu, popup_menu::PopupMenu,
theme::{ActiveTheme, Theme}, theme::{ActiveTheme, Theme},
Clickable as _, IconName, Sizable, IconName, Sizable,
}; };
use crate::app_state::AppState; use crate::app_state::AppState;

View file

@ -9,7 +9,7 @@ use ui::{
h_flex, h_flex,
prelude::FluentBuilder, prelude::FluentBuilder,
theme::ActiveTheme, theme::ActiveTheme,
v_flex, Clickable, Disableable as _, Icon, IconName, Selectable as _, Sizable as _, v_flex, Disableable as _, Icon, IconName, Selectable as _, Sizable as _,
}; };
use crate::section; use crate::section;

View file

@ -7,7 +7,7 @@ use ui::{
dropdown::{Dropdown, DropdownEvent, DropdownItem, SearchableVec}, dropdown::{Dropdown, DropdownEvent, DropdownItem, SearchableVec},
h_flex, h_flex,
theme::ActiveTheme, theme::ActiveTheme,
v_flex, IconName, Selection, Sizable, v_flex, IconName, Sizable,
}; };
struct Country { struct Country {
@ -129,11 +129,6 @@ impl DropdownStory {
}) })
} }
#[allow(unused)]
fn on_click(sel: &Selection, cx: &mut WindowContext) {
println!("Check value changed: {}", sel);
}
fn on_dropdown_event( fn on_dropdown_event(
&mut self, &mut self,
_: View<Dropdown<Vec<Country>>>, _: View<Dropdown<Vec<Country>>>,

View file

@ -10,7 +10,7 @@ use ui::{
h_flex, h_flex,
input::{InputEvent, OtpInput, TextInput}, input::{InputEvent, OtpInput, TextInput},
prelude::FluentBuilder as _, prelude::FluentBuilder as _,
v_flex, Clickable, FocusableCycle, IconName, Selection, Sizable, v_flex, FocusableCycle, IconName, Sizable,
}; };
use crate::section; use crate::section;
@ -170,7 +170,7 @@ impl InputStory {
}; };
} }
fn toggle_opt_masked(&mut self, _: &Selection, cx: &mut ViewContext<Self>) { fn toggle_opt_masked(&mut self, _: &bool, cx: &mut ViewContext<Self>) {
self.otp_masked = !self.otp_masked; self.otp_masked = !self.otp_masked;
self.otp_input self.otp_input
.update(cx, |input, cx| input.set_masked(self.otp_masked, cx)); .update(cx, |input, cx| input.set_masked(self.otp_masked, cx));

View file

@ -12,7 +12,7 @@ use ui::{
h_flex, h_flex,
list::{List, ListDelegate, ListItem}, list::{List, ListDelegate, ListItem},
theme::ActiveTheme as _, theme::ActiveTheme as _,
v_flex, Clickable as _, Icon, IconName, StyledExt, v_flex, Icon, IconName, StyledExt,
}; };
pub struct ListItemDeletegate { pub struct ListItemDeletegate {
@ -272,7 +272,11 @@ impl Render for PickerStory {
.occlude() .occlude()
.w(px(450.)) .w(px(450.))
.h(px(350.)) .h(px(350.))
.elevation_3(cx) .bg(cx.theme().popover)
.border_1()
.border_color(cx.theme().border)
.shadow_lg()
.rounded_lg()
.child(self.list.clone()) .child(self.list.clone())
.on_mouse_down_out(cx.listener(|this, _, cx| { .on_mouse_down_out(cx.listener(|this, _, cx| {
this.open = false; this.open = false;

View file

@ -13,7 +13,7 @@ use ui::{
popup_menu::PopupMenuExt, popup_menu::PopupMenuExt,
prelude::FluentBuilder, prelude::FluentBuilder,
switch::Switch, switch::Switch,
v_flex, Clickable as _, IconName, Sizable, v_flex, IconName, Sizable,
}; };
actions!( actions!(

View file

@ -10,7 +10,7 @@ use ui::{
progress::Progress, progress::Progress,
skeleton::Skeleton, skeleton::Skeleton,
slider::{Slider, SliderEvent}, slider::{Slider, SliderEvent},
v_flex, Clickable, IconName, Sizable, v_flex, IconName, Sizable,
}; };
pub struct ProgressStory { pub struct ProgressStory {

View file

@ -9,7 +9,7 @@ use ui::button::Button;
use ui::divider::Divider; use ui::divider::Divider;
use ui::scroll::{Scrollbar, ScrollbarAxis, ScrollbarState}; use ui::scroll::{Scrollbar, ScrollbarAxis, ScrollbarState};
use ui::theme::ActiveTheme; use ui::theme::ActiveTheme;
use ui::{h_flex, v_flex, Clickable, StyledExt as _}; use ui::{h_flex, v_flex, StyledExt as _};
pub struct ScrollableStory { pub struct ScrollableStory {
scroll_handle: ScrollHandle, scroll_handle: ScrollHandle,

View file

@ -9,7 +9,7 @@ use ui::{
label::Label, label::Label,
table::{ColSort, Table, TableDelegate, TableEvent}, table::{ColSort, Table, TableDelegate, TableEvent},
theme::ActiveTheme as _, theme::ActiveTheme as _,
v_flex, Icon, IconName, Selectable, Selection, v_flex, Icon, IconName, Selectable,
}; };
struct Customer { struct Customer {
@ -226,10 +226,18 @@ impl TableDelegate for CustomerTableDelegate {
} }
fn col_sort(&self, col_ix: usize) -> Option<ColSort> { fn col_sort(&self, col_ix: usize) -> Option<ColSort> {
if !self.col_sort {
return None;
}
self.columns.get(col_ix).and_then(|c| c.sort) self.columns.get(col_ix).and_then(|c| c.sort)
} }
fn perform_sort(&mut self, col_ix: usize, sort: ColSort, _: &mut ViewContext<Table<Self>>) { fn perform_sort(&mut self, col_ix: usize, sort: ColSort, _: &mut ViewContext<Table<Self>>) {
if !self.col_sort {
return;
}
if let Some(col) = self.columns.get_mut(col_ix) { if let Some(col) = self.columns.get_mut(col_ix) {
col.sort = Some(sort); col.sort = Some(sort);
let asc = matches!(sort, ColSort::Ascending); let asc = matches!(sort, ColSort::Ascending);
@ -328,34 +336,35 @@ impl TableStory {
Self { table } Self { table }
} }
fn toggle_loop_selection(&mut self, s: &Selection, cx: &mut ViewContext<Self>) { fn toggle_loop_selection(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone(); let table = self.table.clone();
table.update(cx, |table, cx| { table.update(cx, |table, cx| {
table.delegate_mut().loop_selection = s.is_selected(); table.delegate_mut().loop_selection = *checked;
cx.notify(); cx.notify();
}); });
} }
fn toggle_col_resize(&mut self, s: &Selection, cx: &mut ViewContext<Self>) { fn toggle_col_resize(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone(); let table = self.table.clone();
table.update(cx, |table, cx| { table.update(cx, |table, cx| {
table.delegate_mut().col_resize = s.is_selected(); table.delegate_mut().col_resize = *checked;
cx.notify(); cx.notify();
}); });
} }
fn toggle_col_order(&mut self, s: &Selection, cx: &mut ViewContext<Self>) { fn toggle_col_order(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone(); let table = self.table.clone();
table.update(cx, |table, cx| { table.update(cx, |table, cx| {
table.delegate_mut().col_order = s.is_selected(); table.delegate_mut().col_order = *checked;
cx.notify(); cx.notify();
}); });
} }
fn toggle_col_sort(&mut self, s: &Selection, cx: &mut ViewContext<Self>) { fn toggle_col_sort(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone(); let table = self.table.clone();
table.update(cx, |table, cx| { table.update(cx, |table, cx| {
table.delegate_mut().col_sort = s.is_selected(); println!("- toggle_col_sort: {}", checked);
table.delegate_mut().col_sort = *checked;
cx.notify(); cx.notify();
}); });
} }

View file

@ -11,28 +11,28 @@ use ui::{
label::Label, label::Label,
link::Link, link::Link,
radio::Radio, radio::Radio,
v_flex, Clickable, Disableable as _, IconName, Selection, StyledExt, v_flex, Disableable as _, IconName, StyledExt,
}; };
use crate::section; use crate::section;
pub struct TextStory { pub struct TextStory {
check1: Selection, check1: bool,
check2: Selection, check2: bool,
check3: Selection, check3: bool,
select1: bool, radio_check1: bool,
select2: bool, radio_check2: bool,
masked: bool, masked: bool,
} }
impl TextStory { impl TextStory {
pub(crate) fn new(_cx: &mut WindowContext) -> Self { pub(crate) fn new(_cx: &mut WindowContext) -> Self {
Self { Self {
check1: Selection::Unselected, check1: false,
check2: Selection::Indeterminate, check2: false,
check3: Selection::Selected, check3: true,
select1: false, radio_check1: false,
select2: true, radio_check2: true,
masked: false, masked: false,
} }
} }
@ -42,8 +42,8 @@ impl TextStory {
} }
#[allow(unused)] #[allow(unused)]
fn on_click(sel: &Selection, cx: &mut WindowContext) { fn on_click(checked: &bool, cx: &mut WindowContext) {
println!("Check value changed: {}", sel); println!("Check value changed: {}", checked);
} }
} }
@ -122,7 +122,7 @@ impl Render for TextStory {
Checkbox::new("check1") Checkbox::new("check1")
.checked(self.check1) .checked(self.check1)
.on_click(cx.listener(|v, _, _| { .on_click(cx.listener(|v, _, _| {
v.check1 = v.check1.inverse(); v.check1 = !v.check1;
})), })),
) )
.child( .child(
@ -130,7 +130,7 @@ impl Render for TextStory {
.checked(self.check2) .checked(self.check2)
.label("Subscribe to newsletter") .label("Subscribe to newsletter")
.on_click(cx.listener(|v, _, _| { .on_click(cx.listener(|v, _, _| {
v.check2 = v.check2.inverse(); v.check2 = !v.check2;
})), })),
) )
.child( .child(
@ -138,7 +138,7 @@ impl Render for TextStory {
.checked(self.check3) .checked(self.check3)
.label("Remember me") .label("Remember me")
.on_click(cx.listener(|v, _, _| { .on_click(cx.listener(|v, _, _| {
v.check3 = v.check3.inverse(); v.check3 = !v.check3;
})), })),
) )
.child( .child(
@ -158,21 +158,15 @@ impl Render for TextStory {
.child( .child(
Checkbox::new("check3") Checkbox::new("check3")
.label("Disabled Checked") .label("Disabled Checked")
.checked(Selection::Selected) .checked(true)
.disabled(true), .disabled(true),
) )
.child( .child(
Checkbox::new("check3_1") Checkbox::new("check3_1")
.label("Disabled Unchecked") .label("Disabled Unchecked")
.checked(Selection::Unselected) .checked(false)
.disabled(true), .disabled(true),
) )
.child(
Checkbox::new("check3_2")
.label("Disabled Indeterminate")
.checked(Selection::Indeterminate)
.disabled(true),
),
), ),
) )
.child( .child(
@ -183,30 +177,30 @@ impl Render for TextStory {
.items_start() .items_start()
.child( .child(
Radio::new("radio1") Radio::new("radio1")
.selected(self.select1) .checked(self.radio_check1)
.on_click(cx.listener(|this, v, _cx| { .on_click(cx.listener(|this, v, _cx| {
this.select1 = *v; this.radio_check1 = *v;
})), })),
) )
.child( .child(
Radio::new("radio2") Radio::new("radio2")
.label("Radio") .label("Radio")
.selected(self.select2) .checked(self.radio_check2)
.on_click(cx.listener(|this, v, _cx| { .on_click(cx.listener(|this, v, _cx| {
this.select2 = *v; this.radio_check2 = *v;
})), })),
) )
.child( .child(
Radio::new("radio3") Radio::new("radio3")
.label("Disabled Radio") .label("Disabled Radio")
.selected(true) .checked(true)
.disabled(true), .disabled(true),
) )
.child( .child(
div().w(px(200.)).child( div().w(px(200.)).child(
Radio::new("radio3") Radio::new("radio3")
.label("Warp: A long long long text radio label") .label("Warp: A long long long text radio label")
.selected(true) .checked(true)
.disabled(true), .disabled(true),
), ),
) )

View file

@ -9,7 +9,7 @@ use ui::{
h_flex, h_flex,
label::Label, label::Label,
tooltip::Tooltip, tooltip::Tooltip,
v_flex, Selection, v_flex,
}; };
pub struct TooltipStory; pub struct TooltipStory;
@ -51,11 +51,7 @@ impl Render for TooltipStory {
.child( .child(
div() div()
.cursor(CursorStyle::PointingHand) .cursor(CursorStyle::PointingHand)
.child( .child(Checkbox::new("check").label("Remember me").checked(true))
Checkbox::new("check")
.label("Remember me")
.checked(Selection::Selected),
)
.id("tooltip-4") .id("tooltip-4")
.tooltip(|cx| Tooltip::new("Checked!", cx)), .tooltip(|cx| Tooltip::new("Checked!", cx)),
) )

View file

@ -9,7 +9,7 @@ use ui::{
theme::ActiveTheme, theme::ActiveTheme,
v_flex, v_flex,
webview::WebView, webview::WebView,
Clickable, IconName, IconName,
}; };
pub struct WebViewStory { pub struct WebViewStory {

View file

@ -1,9 +1,8 @@
use crate::{ use crate::{
h_flex, h_flex,
indicator::Indicator, indicator::Indicator,
styled_ext::Sizable,
theme::{ActiveTheme, Colorize as _}, theme::{ActiveTheme, Colorize as _},
Clickable, Disableable, Icon, Selectable, Size, Disableable, Icon, Selectable, Sizable, Size,
}; };
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, px, AnyElement, ClickEvent, Div, ElementId, FocusHandle, div, prelude::FluentBuilder as _, px, AnyElement, ClickEvent, Div, ElementId, FocusHandle,
@ -226,6 +225,11 @@ impl Button {
self.compact = true; self.compact = true;
self self
} }
pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Box::new(handler));
self
}
} }
impl Disableable for Button { impl Disableable for Button {
@ -242,13 +246,6 @@ impl Selectable for Button {
} }
} }
impl Clickable for Button {
fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Box::new(handler));
self
}
}
impl Sizable for Button { impl Sizable for Button {
fn with_size(mut self, size: impl Into<Size>) -> Self { fn with_size(mut self, size: impl Into<Size>) -> Self {
self.size = size.into(); self.size = size.into();

View file

@ -5,29 +5,25 @@ use gpui::{
}; };
use crate::{ use crate::{
disableable::Disableable, h_flex,
selectable::{Selectable, Selection},
stack::{h_flex, v_flex},
theme::{ActiveTheme, Colorize as _}, theme::{ActiveTheme, Colorize as _},
IconName, v_flex, Disableable, IconName, Selectable,
}; };
type OnClick = Box<dyn Fn(&Selection, &mut WindowContext) + 'static>;
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct Checkbox { pub struct Checkbox {
id: ElementId, id: ElementId,
checked: Selection, checked: bool,
disabled: bool, disabled: bool,
label: Option<SharedString>, label: Option<SharedString>,
on_click: Option<OnClick>, on_click: Option<Box<dyn Fn(&bool, &mut WindowContext) + 'static>>,
} }
impl Checkbox { impl Checkbox {
pub fn new(id: impl Into<ElementId>) -> Self { pub fn new(id: impl Into<ElementId>) -> Self {
Self { Self {
id: id.into(), id: id.into(),
checked: Selection::Unselected, checked: false,
disabled: false, disabled: false,
label: None, label: None,
on_click: None, on_click: None,
@ -39,12 +35,12 @@ impl Checkbox {
self self
} }
pub fn checked(mut self, checked: impl Into<Selection>) -> Self { pub fn checked(mut self, checked: bool) -> Self {
self.checked = checked.into(); self.checked = checked;
self self
} }
pub fn on_click(mut self, handler: impl Fn(&Selection, &mut WindowContext) + 'static) -> Self { pub fn on_click(mut self, handler: impl Fn(&bool, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Box::new(handler)); self.on_click = Some(Box::new(handler));
self self
} }
@ -59,11 +55,7 @@ impl Disableable for Checkbox {
impl Selectable for Checkbox { impl Selectable for Checkbox {
fn selected(self, selected: bool) -> Self { fn selected(self, selected: bool) -> Self {
self.checked(if selected { self.checked(selected)
Selection::Selected
} else {
Selection::Unselected
})
} }
} }
@ -96,7 +88,7 @@ impl RenderOnce for Checkbox {
.size_4() .size_4()
.flex_shrink_0() .flex_shrink_0()
.map(|this| match self.checked { .map(|this| match self.checked {
Selection::Unselected => this.bg(theme.transparent), false => this.bg(theme.transparent),
_ => this.bg(color), _ => this.bg(color),
}) })
.group_hover(group_id, |this| { .group_hover(group_id, |this| {
@ -114,8 +106,7 @@ impl RenderOnce for Checkbox {
.size_3() .size_3()
.text_color(icon_color) .text_color(icon_color)
.map(|this| match self.checked { .map(|this| match self.checked {
Selection::Selected => this.path(IconName::Check.path()), true => this.path(IconName::Check.path()),
Selection::Indeterminate => this.path(IconName::Minus.path()),
_ => this, _ => this,
}), }),
), ),
@ -138,7 +129,8 @@ impl RenderOnce for Checkbox {
self.on_click.filter(|_| !self.disabled), self.on_click.filter(|_| !self.disabled),
|this, on_click| { |this, on_click| {
this.on_click(move |_, cx| { this.on_click(move |_, cx| {
on_click(&self.checked.inverse(), cx); let checked = !self.checked;
on_click(&checked, cx);
cx.refresh() cx.refresh()
}) })
}, },

View file

@ -1,5 +0,0 @@
use gpui::{ClickEvent, WindowContext};
pub trait Clickable {
fn on_click(self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self;
}

View file

@ -3,7 +3,7 @@ use gpui::{
RenderOnce, SharedString, Styled, WindowContext, RenderOnce, SharedString, Styled, WindowContext,
}; };
use crate::{button::Button, h_flex, Clickable, IconName, Sizable}; use crate::{button::Button, h_flex, IconName, Sizable};
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct Clipboard { pub struct Clipboard {

View file

@ -7,7 +7,7 @@ use gpui::{
Position, Stateful, Style, Styled as _, View, WindowContext, Position, Stateful, Style, Styled as _, View, WindowContext,
}; };
use crate::{popup_menu::PopupMenu, theme::ActiveTheme as _, StyledExt as _}; use crate::{popup_menu::PopupMenu, theme::ActiveTheme};
pub fn init(_cx: &mut AppContext) {} pub fn init(_cx: &mut AppContext) {}
@ -128,10 +128,11 @@ impl Element for ContextMenu {
this.child( this.child(
div() div()
.elevation_2(cx)
.bg(cx.theme().popover) .bg(cx.theme().popover)
.border_1() .border_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
.shadow_lg()
.rounded_lg()
.child(menu) .child(menu)
.on_mouse_down_out(move |_, cx| { .on_mouse_down_out(move |_, cx| {
*open.borrow_mut() = false; *open.borrow_mut() = false;

View file

@ -1,3 +0,0 @@
pub trait Disableable {
fn disabled(self, disabled: bool) -> Self;
}

View file

@ -46,7 +46,7 @@ impl RenderOnce for Divider {
self.base self.base
.map(|this| match self.axis { .map(|this| match self.axis {
Axis::Vertical => this.v_flex().h_full(), Axis::Vertical => this.flex().flex_row().items_center().h_full(),
Axis::Horizontal => this.h_flex().w_full(), Axis::Horizontal => this.h_flex().w_full(),
}) })
.child( .child(

View file

@ -10,9 +10,8 @@ use crate::{
h_flex, h_flex,
input::ClearButton, input::ClearButton,
list::{self, List, ListDelegate, ListItem}, list::{self, List, ListDelegate, ListItem},
styled_ext::StyleSized,
theme::ActiveTheme, theme::ActiveTheme,
Clickable, Icon, IconName, Sizable, Size, StyledExt, Icon, IconName, Sizable, Size, StyleSized, StyledExt,
}; };
actions!(dropdown, [Up, Down, Enter, Escape]); actions!(dropdown, [Up, Down, Enter, Escape]);

View file

@ -1,4 +1,4 @@
use crate::{styled_ext::Sizable, theme::ActiveTheme, Size}; use crate::{theme::ActiveTheme, Sizable, Size};
use gpui::{ use gpui::{
prelude::FluentBuilder as _, svg, AnyElement, Hsla, IntoElement, Render, RenderOnce, prelude::FluentBuilder as _, svg, AnyElement, Hsla, IntoElement, Render, RenderOnce,
SharedString, StyleRefinement, Styled, Svg, View, VisualContext, WindowContext, SharedString, StyleRefinement, Styled, Svg, View, VisualContext, WindowContext,

View file

@ -9,10 +9,10 @@ use super::blink_cursor::BlinkCursor;
use super::history::History; use super::history::History;
use super::ClearButton; use super::ClearButton;
use crate::indicator::Indicator; use crate::indicator::Indicator;
use crate::styled_ext::{Sizable, StyleSized};
use crate::theme::ActiveTheme; use crate::theme::ActiveTheme;
use crate::StyledExt as _;
use crate::{event::InteractiveElementExt as _, Size}; use crate::{event::InteractiveElementExt as _, Size};
use crate::{Clickable as _, StyledExt as _}; use crate::{Sizable, StyleSized};
use gpui::prelude::FluentBuilder as _; use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
actions, div, fill, point, px, relative, rems, size, AnyElement, AppContext, Bounds, actions, div, fill, point, px, relative, rems, size, AnyElement, AppContext, Bounds,

View file

@ -17,7 +17,6 @@ pub enum TextAlign {
pub struct Label { pub struct Label {
base: Div, base: Div,
label: SharedString, label: SharedString,
multiple_lines: bool,
align: TextAlign, align: TextAlign,
marked: bool, marked: bool,
} }
@ -27,17 +26,11 @@ impl Label {
Self { Self {
base: h_flex().line_height(rems(1.25)), base: h_flex().line_height(rems(1.25)),
label: label.into(), label: label.into(),
multiple_lines: true,
align: TextAlign::default(), align: TextAlign::default(),
marked: false, marked: false,
} }
} }
pub fn multiple_lines(mut self) -> Self {
self.multiple_lines = true;
self
}
pub fn text_align(mut self, align: TextAlign) -> Self { pub fn text_align(mut self, align: TextAlign) -> Self {
self.align = align; self.align = align;
self self
@ -74,11 +67,7 @@ const MASKED: &'static str = "•";
impl RenderOnce for Label { impl RenderOnce for Label {
fn render(self, cx: &mut WindowContext) -> impl IntoElement { fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let text = if !self.multiple_lines { let text = self.label;
SharedString::from(self.label.replace('\n', ""))
} else {
self.label
};
let text_display = if self.marked { let text_display = if self.marked {
MASKED.repeat(text.chars().count()) MASKED.repeat(text.chars().count())

View file

@ -1,13 +1,9 @@
mod clickable;
mod colors; mod colors;
mod disableable;
mod event; mod event;
mod focusable; mod focusable;
mod icon; mod icon;
mod selectable; mod styled;
mod stack;
mod styled_ext;
mod svg_img; mod svg_img;
mod time; mod time;
@ -43,17 +39,14 @@ use std::ops::Deref;
// re-export // re-export
pub use wry; pub use wry;
pub use clickable::Clickable; pub use crate::Disableable;
pub use disableable::Disableable;
pub use event::InteractiveElementExt; pub use event::InteractiveElementExt;
pub use focusable::FocusableCycle; pub use focusable::FocusableCycle;
pub use selectable::{Selectable, Selection}; pub use styled::*;
pub use styled_ext::{Sizable, Size, StyledExt};
pub use time::*; pub use time::*;
pub use colors::*; pub use colors::*;
pub use icon::*; pub use icon::*;
pub use stack::*;
pub use svg_img::*; pub use svg_img::*;
rust_i18n::i18n!("locales", fallback = "en"); rust_i18n::i18n!("locales", fallback = "en");

View file

@ -5,9 +5,7 @@ use gpui::{
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::{ use crate::{h_flex, theme::ActiveTheme, Disableable, Icon, IconName, Selectable, Sizable as _};
h_flex, styled_ext::Sizable as _, theme::ActiveTheme, Disableable, Icon, IconName, Selectable,
};
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct ListItem { pub struct ListItem {

View file

@ -9,7 +9,7 @@ use gpui::{
}; };
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use crate::{theme::ActiveTheme, Selectable, StyledExt as _}; use crate::{theme::ActiveTheme, Selectable};
actions!(popover, [Open, Dismiss]); actions!(popover, [Open, Dismiss]);
@ -247,10 +247,11 @@ impl<M: ManagedView> Element for Popover<M> {
div() div()
.size_full() .size_full()
.occlude() .occlude()
.elevation_2(cx)
.bg(bg_color)
.border_1() .border_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
.shadow_lg()
.rounded_lg()
.bg(bg_color)
.map(|this| match anchor { .map(|this| match anchor {
AnchorCorner::TopLeft | AnchorCorner::TopRight => this.top_2(), AnchorCorner::TopLeft | AnchorCorner::TopRight => this.top_2(),
AnchorCorner::BottomLeft | AnchorCorner::BottomRight => { AnchorCorner::BottomLeft | AnchorCorner::BottomRight => {
@ -627,7 +628,8 @@ where
this.bg(cx.theme().popover) this.bg(cx.theme().popover)
.border_1() .border_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
.elevation_2(cx) .shadow_lg()
.rounded_lg()
}) })
.bg(cx.theme().popover) .bg(cx.theme().popover)
.child(self.view.clone()) .child(self.view.clone())

View file

@ -8,8 +8,8 @@ use gpui::{
}; };
use crate::{ use crate::{
button::Button, h_flex, list::ListItem, popover::Popover, styled_ext::Sizable as _, button::Button, h_flex, list::ListItem, popover::Popover, theme::ActiveTheme, v_flex, Icon,
theme::ActiveTheme, v_flex, Icon, IconName, Selectable, IconName, Selectable, Sizable as _,
}; };
actions!(menu, [Confirm, Dismiss, SelectNext, SelectPrev]); actions!(menu, [Confirm, Dismiss, SelectNext, SelectPrev]);

View file

@ -14,7 +14,7 @@ use crate::{
pub struct Radio { pub struct Radio {
id: ElementId, id: ElementId,
label: Option<SharedString>, label: Option<SharedString>,
selected: bool, checked: bool,
disabled: bool, disabled: bool,
on_click: Option<Box<dyn Fn(&bool, &mut WindowContext) + 'static>>, on_click: Option<Box<dyn Fn(&bool, &mut WindowContext) + 'static>>,
} }
@ -24,7 +24,7 @@ impl Radio {
Self { Self {
id: id.into(), id: id.into(),
label: None, label: None,
selected: false, checked: false,
disabled: false, disabled: false,
on_click: None, on_click: None,
} }
@ -35,8 +35,8 @@ impl Radio {
self self
} }
pub fn selected(mut self, selected: bool) -> Self { pub fn checked(mut self, checked: bool) -> Self {
self.selected = selected; self.checked = checked;
self self
} }
@ -73,7 +73,7 @@ impl RenderOnce for Radio {
.rounded_full() .rounded_full()
.border_1() .border_1()
.border_color(color) .border_color(color)
.when(self.selected, |this| this.bg(color)) .when(self.checked, |this| this.bg(color))
.child( .child(
svg() svg()
.absolute() .absolute()
@ -81,10 +81,10 @@ impl RenderOnce for Radio {
.left_px() .left_px()
.size_3() .size_3()
.text_color(color) .text_color(color)
.when(self.selected, |this| { .when(self.checked, |this| {
this.text_color(cx.theme().primary_foreground) this.text_color(cx.theme().primary_foreground)
}) })
.map(|this| match self.selected { .map(|this| match self.checked {
true => this.path(IconName::Check.path()), true => this.path(IconName::Check.path()),
false => this, false => this,
}), }),
@ -103,7 +103,7 @@ impl RenderOnce for Radio {
self.on_click.filter(|_| !self.disabled), self.on_click.filter(|_| !self.disabled),
|this, on_click| { |this, on_click| {
this.on_click(move |_event, cx| { this.on_click(move |_event, cx| {
on_click(&!self.selected, cx); on_click(&!self.checked, cx);
}) })
}, },
) )

View file

@ -6,7 +6,7 @@ use gpui::{
StatefulInteractiveElement, Styled, View, ViewContext, VisualContext as _, WindowContext, StatefulInteractiveElement, Styled, View, ViewContext, VisualContext as _, WindowContext,
}; };
use crate::{h_flex, styled_ext::AxisExt, theme::ActiveTheme, v_flex}; use crate::{h_flex, theme::ActiveTheme, v_flex, AxisExt};
#[derive(Clone, Render)] #[derive(Clone, Render)]
pub struct DragPanel(pub (EntityId, usize, Axis)); pub struct DragPanel(pub (EntityId, usize, Axis));

View file

@ -1,57 +0,0 @@
use std::fmt::Display;
/// A trait for elements that can be selected.
///
/// Generally used to enable "toggle" or "active" behavior and styles on an element through the [`Selection`] status.
pub trait Selectable {
/// Sets whether the element is selected.
fn selected(self, selected: bool) -> Self;
}
/// Represents the selection status of an element.
#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Selection {
/// The element is not selected.
#[default]
Unselected,
/// The selection state of the element is indeterminate.
Indeterminate,
/// The element is selected.
Selected,
}
impl From<bool> for Selection {
fn from(selected: bool) -> Self {
if selected {
Self::Selected
} else {
Self::Unselected
}
}
}
impl Display for Selection {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Unselected => write!(f, "Unselected"),
Self::Indeterminate => write!(f, "Indeterminate"),
Self::Selected => write!(f, "Selected"),
}
}
}
impl Selection {
/// Returns the inverse of the current selection status.
///
/// Indeterminate states become selected if inverted.
pub fn inverse(&self) -> Self {
match self {
Self::Unselected | Self::Indeterminate => Self::Selected,
Self::Selected => Self::Unselected,
}
}
pub fn is_selected(&self) -> bool {
matches!(self, Self::Selected)
}
}

View file

@ -1,19 +0,0 @@
use crate::StyledExt as _;
use gpui::{div, Div, Styled};
/// Horizontally stacks elements. Sets `flex()`, `flex_row()`, `items_center()`
#[track_caller]
pub fn h_flex() -> Div {
div().h_flex()
}
/// Vertically stacks elements. Sets `flex()`, `flex_col()`
#[track_caller]
pub fn v_flex() -> Div {
div().v_flex()
}
/// A horizontal divider. Sets `h_0.5()`, `bg()`, `bg_gray()`
pub fn span() -> Div {
div().w_auto()
}

View file

@ -3,53 +3,17 @@ use crate::{
theme::{ActiveTheme, Colorize}, theme::{ActiveTheme, Colorize},
}; };
use gpui::{ use gpui::{
hsla, point, px, rems, AnyView, Axis, BoxShadow, Element, Fill, FocusHandle, Pixels, Styled, div, px, rems, AnyView, Axis, Div, Element, Fill, FocusHandle, Pixels, Styled, WindowContext,
WindowContext,
}; };
use smallvec::{smallvec, SmallVec};
pub enum ElevationIndex { /// Returns a `Div` as horizontal flex layout.
Surface, pub fn h_flex() -> Div {
PopoverSurface, div().h_flex()
ModalSurface,
} }
impl ElevationIndex { /// Returns a `Div` as vertical flex layout.
pub fn shadow(self) -> SmallVec<[BoxShadow; 2]> { pub fn v_flex() -> Div {
match self { div().v_flex()
ElevationIndex::Surface => smallvec![],
ElevationIndex::PopoverSurface => smallvec![BoxShadow {
color: hsla(0., 0., 0., 0.12),
offset: point(px(0.), px(2.)),
blur_radius: px(3.),
spread_radius: px(0.),
}],
ElevationIndex::ModalSurface => smallvec![
BoxShadow {
color: hsla(0., 0., 0., 0.1),
offset: point(px(0.), px(4.)),
blur_radius: px(6.),
spread_radius: px(-1.),
},
BoxShadow {
color: hsla(0., 0., 0., 0.1),
offset: point(px(0.), px(2.)),
blur_radius: px(4.),
spread_radius: px(-2.),
}
],
}
}
}
fn elevated<E: Styled>(this: E, cx: &WindowContext, index: ElevationIndex) -> E {
this.bg(cx.theme().popover)
.rounded(px(8.))
.border_1()
.border_color(cx.theme().border)
.shadow(index.shadow())
} }
macro_rules! font_weight { macro_rules! font_weight {
@ -63,35 +27,16 @@ macro_rules! font_weight {
/// Extends [`gpui::Styled`] with specific styling methods. /// Extends [`gpui::Styled`] with specific styling methods.
pub trait StyledExt: Styled + Sized { pub trait StyledExt: Styled + Sized {
/// Horizontally stacks elements. /// Apply self into a horizontal flex layout.
///
/// Sets `flex()`, `flex_row()`, `items_center()`
fn h_flex(self) -> Self { fn h_flex(self) -> Self {
self.flex().flex_row().items_center() self.flex().flex_row().items_center()
} }
/// Vertically stacks elements. /// Apply self into a vertical flex layout.
///
/// Sets `flex()`, `flex_col()`
fn v_flex(self) -> Self { fn v_flex(self) -> Self {
self.flex().flex_col() self.flex().flex_col()
} }
/// Located above the app background
fn elevation_1(self, cx: &WindowContext) -> Self {
elevated(self, cx, ElevationIndex::Surface)
}
/// Appear above most UI elements
fn elevation_2(self, cx: &WindowContext) -> Self {
elevated(self, cx, ElevationIndex::PopoverSurface)
}
// Above all other UI elements and are located above the wash layer
fn elevation_3(self, cx: &WindowContext) -> Self {
elevated(self, cx, ElevationIndex::ModalSurface)
}
/// Render a border with a width of 1px, color red /// Render a border with a width of 1px, color red
fn debug_red(self) -> Self { fn debug_red(self) -> Self {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
@ -227,6 +172,18 @@ impl From<Pixels> for Size {
} }
} }
/// A trait for defining element that can be selected.
pub trait Selectable: Sized {
/// Set the selected state of the element.
fn selected(self, selected: bool) -> Self;
}
/// A trait for defining element that can be disabled.
pub trait Disableable {
/// Set the disabled state of the element.
fn disabled(self, disabled: bool) -> Self;
}
/// A trait for setting the size of an element. /// A trait for setting the size of an element.
pub trait Sizable: Sized { pub trait Sizable: Sized {
/// Set the ui::Size of this element. /// Set the ui::Size of this element.

View file

@ -1,7 +1,7 @@
use std::time::Duration; use std::time::Duration;
use crate::{ use crate::{
stack::h_flex, h_flex,
theme::{ActiveTheme, Colorize}, theme::{ActiveTheme, Colorize},
Disableable, Sizable, Size, Disableable, Sizable, Size,
}; };

View file

@ -1,5 +1,5 @@
use crate::selectable::Selectable;
use crate::theme::{ActiveTheme, Colorize}; use crate::theme::{ActiveTheme, Colorize};
use crate::Selectable;
use gpui::prelude::FluentBuilder as _; use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
div, AnyElement, Div, ElementId, InteractiveElement, IntoElement, ParentElement as _, div, AnyElement, Div, ElementId, InteractiveElement, IntoElement, ParentElement as _,

View file

@ -1,4 +1,4 @@
use crate::stack::h_flex; use crate::h_flex;
use crate::theme::ActiveTheme; use crate::theme::ActiveTheme;
use gpui::prelude::FluentBuilder as _; use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{

View file

@ -521,7 +521,7 @@ where
col_ix: usize, col_ix: usize,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Option<impl IntoElement> { ) -> Option<impl IntoElement> {
let sort = self.col_groups.get(col_ix).and_then(|g| g.sort); let sort = self.delegate().col_sort(col_ix);
if sort.is_none() { if sort.is_none() {
return None; return None;
} }

View file

@ -12,7 +12,7 @@ use crate::{
button::Button, button::Button,
h_flex, h_flex,
theme::{ActiveTheme, Colorize}, theme::{ActiveTheme, Colorize},
v_flex, Clickable, Disableable, IconName, Selectable, v_flex, Disableable as _, IconName, Selectable,
}; };
use super::utils::days_in_month; use super::utils::days_in_month;

View file

@ -7,8 +7,8 @@ use gpui::{
use rust_i18n::t; use rust_i18n::t;
use crate::{ use crate::{
dropdown::Escape, h_flex, input::ClearButton, styled_ext::StyleSized as _, dropdown::Escape, h_flex, input::ClearButton, theme::ActiveTheme as _, Icon, IconName, Sizable,
theme::ActiveTheme as _, Clickable, Icon, IconName, Sizable, Size, StyledExt as _, Size, StyleSized as _, StyledExt as _,
}; };
use super::calendar::{Calendar, CalendarEvent, Date}; use super::calendar::{Calendar, CalendarEvent, Date};
@ -223,7 +223,10 @@ impl Render for DatePicker {
.rounded_lg() .rounded_lg()
.p_3() .p_3()
.w(px(popover_width)) .w(px(popover_width))
.elevation_2(cx) .border_1()
.border_color(cx.theme().border)
.shadow_lg()
.rounded_lg()
.on_mouse_up_out( .on_mouse_up_out(
MouseButton::Left, MouseButton::Left,
cx.listener(|view, _, cx| view.escape(&Escape, cx)), cx.listener(|view, _, cx| view.escape(&Escape, cx)),

View file

@ -3,7 +3,7 @@ use gpui::{
VisualContext, WindowContext, VisualContext, WindowContext,
}; };
use crate::{theme::ActiveTheme, StyledExt}; use crate::theme::ActiveTheme;
pub struct Tooltip { pub struct Tooltip {
text: SharedString, text: SharedString,
@ -23,7 +23,10 @@ impl Render for Tooltip {
.m_3() .m_3()
.bg(cx.theme().popover) .bg(cx.theme().popover)
.text_color(cx.theme().popover_foreground) .text_color(cx.theme().popover_foreground)
.elevation_1(cx) .bg(cx.theme().popover)
.border_1()
.border_color(cx.theme().border)
.shadow_md()
.rounded(px(6.)) .rounded(px(6.))
.pt_1() .pt_1()
.pb_0p5() .pb_0p5()

View file

@ -8,7 +8,7 @@ use gpui::{
ViewContext, VisualContext, WindowContext, ViewContext, VisualContext, WindowContext,
}; };
use ui::{h_flex, label::Label, theme::ActiveTheme, v_flex, Icon, IconName, StyledExt}; use ui::{h_flex, label::Label, theme::ActiveTheme, v_flex, Icon, IconName};
use crate::Workspace; use crate::Workspace;
@ -210,7 +210,11 @@ impl MessageNotification {
impl Render for MessageNotification { impl Render for MessageNotification {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
v_flex() v_flex()
.elevation_3(cx) .bg(cx.theme().popover)
.border_1()
.border_color(cx.theme().border)
.shadow_xl()
.rounded_xl()
.p_4() .p_4()
.max_w_80() .max_w_80()
.bg(cx.theme().background) .bg(cx.theme().background)