ui: Remove the ToggleButton component (#43115)
This PR removes the old `ToggleButton` component, replacing it with the newer `ToggleButtonGroup` component in the couple of places that used to use it. Ended up also adding a few more methods to the newer toggle button group so the UI for the extensions page and the debugger main picker didn't get visually impacted much. Then, as I was already in the extensions page, decided to bake in some reasonably small UI improvements to it as well. Release Notes: - N/A
This commit is contained in:
@@ -25,12 +25,9 @@ use settings::Settings;
|
||||
use task::{DebugScenario, RevealTarget, VariableName, ZedDebugConfig};
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
ActiveTheme, Button, ButtonCommon, ButtonSize, CheckboxWithLabel, Clickable, Color, Context,
|
||||
ContextMenu, Disableable, DropdownMenu, FluentBuilder, Icon, IconName, IconSize,
|
||||
IconWithIndicator, Indicator, InteractiveElement, IntoElement, KeyBinding, Label,
|
||||
LabelCommon as _, LabelSize, ListItem, ListItemSpacing, ParentElement, RenderOnce,
|
||||
SharedString, Styled, StyledExt, ToggleButton, ToggleState, Toggleable, Tooltip, Window, div,
|
||||
h_flex, relative, rems, v_flex,
|
||||
CheckboxWithLabel, ContextMenu, DropdownMenu, FluentBuilder, IconWithIndicator, Indicator,
|
||||
KeyBinding, ListItem, ListItemSpacing, ToggleButtonGroup, ToggleButtonSimple, ToggleState,
|
||||
Tooltip, prelude::*,
|
||||
};
|
||||
use util::{ResultExt, rel_path::RelPath, shell::ShellKind};
|
||||
use workspace::{ModalView, Workspace, notifications::DetachAndPromptErr, pane};
|
||||
@@ -620,72 +617,64 @@ impl Render for NewProcessModal {
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.child(
|
||||
ToggleButton::new(
|
||||
"debugger-session-ui-tasks-button",
|
||||
NewProcessMode::Task.to_string(),
|
||||
)
|
||||
.size(ButtonSize::Default)
|
||||
.toggle_state(matches!(self.mode, NewProcessMode::Task))
|
||||
.style(ui::ButtonStyle::Subtle)
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.mode = NewProcessMode::Task;
|
||||
this.mode_focus_handle(cx).focus(window);
|
||||
cx.notify();
|
||||
}))
|
||||
.tooltip(Tooltip::text("Run predefined task"))
|
||||
.first(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(
|
||||
"debugger-session-ui-launch-button",
|
||||
NewProcessMode::Debug.to_string(),
|
||||
)
|
||||
.size(ButtonSize::Default)
|
||||
.style(ui::ButtonStyle::Subtle)
|
||||
.toggle_state(matches!(self.mode, NewProcessMode::Debug))
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.mode = NewProcessMode::Debug;
|
||||
this.mode_focus_handle(cx).focus(window);
|
||||
cx.notify();
|
||||
}))
|
||||
.tooltip(Tooltip::text("Start a predefined debug scenario"))
|
||||
.middle(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(
|
||||
"debugger-session-ui-attach-button",
|
||||
NewProcessMode::Attach.to_string(),
|
||||
)
|
||||
.size(ButtonSize::Default)
|
||||
.toggle_state(matches!(self.mode, NewProcessMode::Attach))
|
||||
.style(ui::ButtonStyle::Subtle)
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.mode = NewProcessMode::Attach;
|
||||
ToggleButtonGroup::single_row(
|
||||
"debugger-mode-buttons",
|
||||
[
|
||||
ToggleButtonSimple::new(
|
||||
NewProcessMode::Task.to_string(),
|
||||
cx.listener(|this, _, window, cx| {
|
||||
this.mode = NewProcessMode::Task;
|
||||
this.mode_focus_handle(cx).focus(window);
|
||||
cx.notify();
|
||||
}),
|
||||
)
|
||||
.tooltip(Tooltip::text("Run predefined task")),
|
||||
ToggleButtonSimple::new(
|
||||
NewProcessMode::Debug.to_string(),
|
||||
cx.listener(|this, _, window, cx| {
|
||||
this.mode = NewProcessMode::Debug;
|
||||
this.mode_focus_handle(cx).focus(window);
|
||||
cx.notify();
|
||||
}),
|
||||
)
|
||||
.tooltip(Tooltip::text("Start a predefined debug scenario")),
|
||||
ToggleButtonSimple::new(
|
||||
NewProcessMode::Attach.to_string(),
|
||||
cx.listener(|this, _, window, cx| {
|
||||
this.mode = NewProcessMode::Attach;
|
||||
|
||||
if let Some(debugger) = this.debugger.as_ref() {
|
||||
Self::update_attach_picker(&this.attach_mode, debugger, window, cx);
|
||||
}
|
||||
this.mode_focus_handle(cx).focus(window);
|
||||
cx.notify();
|
||||
}))
|
||||
.tooltip(Tooltip::text("Attach the debugger to a running process"))
|
||||
.middle(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(
|
||||
"debugger-session-ui-custom-button",
|
||||
NewProcessMode::Launch.to_string(),
|
||||
if let Some(debugger) = this.debugger.as_ref() {
|
||||
Self::update_attach_picker(
|
||||
&this.attach_mode,
|
||||
debugger,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
this.mode_focus_handle(cx).focus(window);
|
||||
cx.notify();
|
||||
}),
|
||||
)
|
||||
.tooltip(Tooltip::text("Attach the debugger to a running process")),
|
||||
ToggleButtonSimple::new(
|
||||
NewProcessMode::Launch.to_string(),
|
||||
cx.listener(|this, _, window, cx| {
|
||||
this.mode = NewProcessMode::Launch;
|
||||
this.mode_focus_handle(cx).focus(window);
|
||||
cx.notify();
|
||||
}),
|
||||
)
|
||||
.tooltip(Tooltip::text("Launch a new process with a debugger")),
|
||||
],
|
||||
)
|
||||
.size(ButtonSize::Default)
|
||||
.toggle_state(matches!(self.mode, NewProcessMode::Launch))
|
||||
.style(ui::ButtonStyle::Subtle)
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.mode = NewProcessMode::Launch;
|
||||
this.mode_focus_handle(cx).focus(window);
|
||||
cx.notify();
|
||||
}))
|
||||
.tooltip(Tooltip::text("Launch a new process with a debugger"))
|
||||
.last(),
|
||||
.label_size(LabelSize::Default)
|
||||
.auto_width()
|
||||
.selected_index(match self.mode {
|
||||
NewProcessMode::Task => 0,
|
||||
NewProcessMode::Debug => 1,
|
||||
NewProcessMode::Attach => 2,
|
||||
NewProcessMode::Launch => 3,
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(v_flex().child(self.render_mode(window, cx)))
|
||||
|
||||
@@ -24,8 +24,9 @@ use settings::{Settings, SettingsContent};
|
||||
use strum::IntoEnumIterator as _;
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
Banner, Chip, ContextMenu, Divider, PopoverMenu, ScrollableHandle, Switch, ToggleButton,
|
||||
Tooltip, WithScrollbar, prelude::*,
|
||||
Banner, Chip, ContextMenu, Divider, PopoverMenu, ScrollableHandle, Switch, ToggleButtonGroup,
|
||||
ToggleButtonGroupSize, ToggleButtonGroupStyle, ToggleButtonSimple, Tooltip, WithScrollbar,
|
||||
prelude::*,
|
||||
};
|
||||
use vim_mode_setting::VimModeSetting;
|
||||
use workspace::{
|
||||
@@ -805,37 +806,47 @@ impl ExtensionsPage {
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.justify_between()
|
||||
.child(
|
||||
Icon::new(IconName::Person)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(
|
||||
Label::new(extension.manifest.authors.join(", "))
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted)
|
||||
.truncate(),
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
Icon::new(IconName::Person)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(
|
||||
Label::new(extension.manifest.authors.join(", "))
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted)
|
||||
.truncate(),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.ml_auto()
|
||||
.gap_1()
|
||||
.child(
|
||||
.child({
|
||||
let repo_url_for_tooltip = repository_url.clone();
|
||||
|
||||
IconButton::new(
|
||||
SharedString::from(format!("repository-{}", extension.id)),
|
||||
IconName::Github,
|
||||
)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(cx.listener({
|
||||
let repository_url = repository_url.clone();
|
||||
.tooltip(move |_, cx| {
|
||||
Tooltip::with_meta(
|
||||
"Visit Extension Repository",
|
||||
None,
|
||||
repo_url_for_tooltip.clone(),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_click(cx.listener(
|
||||
move |_, _, _, cx| {
|
||||
cx.open_url(&repository_url);
|
||||
}
|
||||
}))
|
||||
.tooltip(Tooltip::text(repository_url)),
|
||||
)
|
||||
},
|
||||
))
|
||||
})
|
||||
.child(
|
||||
PopoverMenu::new(SharedString::from(format!(
|
||||
"more-{}",
|
||||
@@ -1136,15 +1147,14 @@ impl ExtensionsPage {
|
||||
h_flex()
|
||||
.key_context(key_context)
|
||||
.h_8()
|
||||
.flex_1()
|
||||
.min_w(rems_from_px(384.))
|
||||
.flex_1()
|
||||
.pl_1p5()
|
||||
.pr_2()
|
||||
.py_1()
|
||||
.gap_2()
|
||||
.border_1()
|
||||
.border_color(editor_border)
|
||||
.rounded_lg()
|
||||
.rounded_md()
|
||||
.child(Icon::new(IconName::MagnifyingGlass).color(Color::Muted))
|
||||
.child(self.render_text_input(&self.query_editor, cx))
|
||||
}
|
||||
@@ -1544,13 +1554,13 @@ impl Render for ExtensionsPage {
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.gap_2()
|
||||
.gap_1p5()
|
||||
.justify_between()
|
||||
.child(Headline::new("Extensions").size(HeadlineSize::XLarge))
|
||||
.child(
|
||||
Button::new("install-dev-extension", "Install Dev Extension")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.size(ButtonSize::Medium)
|
||||
.on_click(|_event, window, cx| {
|
||||
window.dispatch_action(Box::new(InstallDevExtension), cx)
|
||||
}),
|
||||
@@ -1559,58 +1569,51 @@ impl Render for ExtensionsPage {
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.gap_4()
|
||||
.flex_wrap()
|
||||
.gap_2()
|
||||
.child(self.render_search(cx))
|
||||
.child(
|
||||
h_flex()
|
||||
.child(
|
||||
ToggleButton::new("filter-all", "All")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.toggle_state(self.filter == ExtensionFilter::All)
|
||||
.on_click(cx.listener(|this, _event, _, cx| {
|
||||
this.filter = ExtensionFilter::All;
|
||||
this.filter_extension_entries(cx);
|
||||
this.scroll_to_top(cx);
|
||||
}))
|
||||
.tooltip(move |_, cx| {
|
||||
Tooltip::simple("Show all extensions", cx)
|
||||
})
|
||||
.first(),
|
||||
div().child(
|
||||
ToggleButtonGroup::single_row(
|
||||
"filter-buttons",
|
||||
[
|
||||
ToggleButtonSimple::new(
|
||||
"All",
|
||||
cx.listener(|this, _event, _, cx| {
|
||||
this.filter = ExtensionFilter::All;
|
||||
this.filter_extension_entries(cx);
|
||||
this.scroll_to_top(cx);
|
||||
}),
|
||||
),
|
||||
ToggleButtonSimple::new(
|
||||
"Installed",
|
||||
cx.listener(|this, _event, _, cx| {
|
||||
this.filter = ExtensionFilter::Installed;
|
||||
this.filter_extension_entries(cx);
|
||||
this.scroll_to_top(cx);
|
||||
}),
|
||||
),
|
||||
ToggleButtonSimple::new(
|
||||
"Not Installed",
|
||||
cx.listener(|this, _event, _, cx| {
|
||||
this.filter = ExtensionFilter::NotInstalled;
|
||||
this.filter_extension_entries(cx);
|
||||
this.scroll_to_top(cx);
|
||||
}),
|
||||
),
|
||||
],
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new("filter-installed", "Installed")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.toggle_state(self.filter == ExtensionFilter::Installed)
|
||||
.on_click(cx.listener(|this, _event, _, cx| {
|
||||
this.filter = ExtensionFilter::Installed;
|
||||
this.filter_extension_entries(cx);
|
||||
this.scroll_to_top(cx);
|
||||
}))
|
||||
.tooltip(move |_, cx| {
|
||||
Tooltip::simple("Show installed extensions", cx)
|
||||
})
|
||||
.middle(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new("filter-not-installed", "Not Installed")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.toggle_state(
|
||||
self.filter == ExtensionFilter::NotInstalled,
|
||||
)
|
||||
.on_click(cx.listener(|this, _event, _, cx| {
|
||||
this.filter = ExtensionFilter::NotInstalled;
|
||||
this.filter_extension_entries(cx);
|
||||
this.scroll_to_top(cx);
|
||||
}))
|
||||
.tooltip(move |_, cx| {
|
||||
Tooltip::simple("Show not installed extensions", cx)
|
||||
})
|
||||
.last(),
|
||||
),
|
||||
.style(ToggleButtonGroupStyle::Outlined)
|
||||
.size(ToggleButtonGroupSize::Custom(rems_from_px(30.))) // Perfectly matches the input
|
||||
.label_size(LabelSize::Default)
|
||||
.auto_width()
|
||||
.selected_index(match self.filter {
|
||||
ExtensionFilter::All => 0,
|
||||
ExtensionFilter::Installed => 1,
|
||||
ExtensionFilter::NotInstalled => 2,
|
||||
})
|
||||
.into_any_element(),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -28,7 +28,6 @@ pub enum ComponentStory {
|
||||
Tab,
|
||||
TabBar,
|
||||
Text,
|
||||
ToggleButton,
|
||||
ViewportUnits,
|
||||
WithRemSize,
|
||||
IndentGuides,
|
||||
@@ -58,7 +57,6 @@ impl ComponentStory {
|
||||
Self::Tab => cx.new(|_| ui::TabStory).into(),
|
||||
Self::TabBar => cx.new(|_| ui::TabBarStory).into(),
|
||||
Self::Text => TextStory::model(cx).into(),
|
||||
Self::ToggleButton => cx.new(|_| ui::ToggleButtonStory).into(),
|
||||
Self::ViewportUnits => cx.new(|_| crate::stories::ViewportUnitsStory).into(),
|
||||
Self::WithRemSize => cx.new(|_| crate::stories::WithRemSizeStory).into(),
|
||||
Self::IndentGuides => crate::stories::IndentGuidesStory::model(window, cx).into(),
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::rc::Rc;
|
||||
|
||||
use gpui::{AnyView, ClickEvent, relative};
|
||||
|
||||
use crate::{ButtonLike, ButtonLikeRounding, ElevationIndex, TintColor, Tooltip, prelude::*};
|
||||
use crate::{ButtonLike, ButtonLikeRounding, TintColor, Tooltip, prelude::*};
|
||||
|
||||
/// The position of a [`ToggleButton`] within a group of buttons.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
@@ -43,290 +43,6 @@ impl ToggleButtonPosition {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement, RegisterComponent)]
|
||||
pub struct ToggleButton {
|
||||
base: ButtonLike,
|
||||
position_in_group: Option<ToggleButtonPosition>,
|
||||
label: SharedString,
|
||||
label_color: Option<Color>,
|
||||
}
|
||||
|
||||
impl ToggleButton {
|
||||
pub fn new(id: impl Into<ElementId>, label: impl Into<SharedString>) -> Self {
|
||||
Self {
|
||||
base: ButtonLike::new(id),
|
||||
position_in_group: None,
|
||||
label: label.into(),
|
||||
label_color: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn color(mut self, label_color: impl Into<Option<Color>>) -> Self {
|
||||
self.label_color = label_color.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn position_in_group(mut self, position: ToggleButtonPosition) -> Self {
|
||||
self.position_in_group = Some(position);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn first(self) -> Self {
|
||||
self.position_in_group(ToggleButtonPosition::HORIZONTAL_FIRST)
|
||||
}
|
||||
|
||||
pub fn middle(self) -> Self {
|
||||
self.position_in_group(ToggleButtonPosition::HORIZONTAL_MIDDLE)
|
||||
}
|
||||
|
||||
pub fn last(self) -> Self {
|
||||
self.position_in_group(ToggleButtonPosition::HORIZONTAL_LAST)
|
||||
}
|
||||
}
|
||||
|
||||
impl Toggleable for ToggleButton {
|
||||
fn toggle_state(mut self, selected: bool) -> Self {
|
||||
self.base = self.base.toggle_state(selected);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectableButton for ToggleButton {
|
||||
fn selected_style(mut self, style: ButtonStyle) -> Self {
|
||||
self.base.selected_style = Some(style);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedWidth for ToggleButton {
|
||||
fn width(mut self, width: impl Into<DefiniteLength>) -> Self {
|
||||
self.base.width = Some(width.into());
|
||||
self
|
||||
}
|
||||
|
||||
fn full_width(mut self) -> Self {
|
||||
self.base.width = Some(relative(1.));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Disableable for ToggleButton {
|
||||
fn disabled(mut self, disabled: bool) -> Self {
|
||||
self.base = self.base.disabled(disabled);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Clickable for ToggleButton {
|
||||
fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
|
||||
self.base = self.base.on_click(handler);
|
||||
self
|
||||
}
|
||||
|
||||
fn cursor_style(mut self, cursor_style: gpui::CursorStyle) -> Self {
|
||||
self.base = self.base.cursor_style(cursor_style);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ButtonCommon for ToggleButton {
|
||||
fn id(&self) -> &ElementId {
|
||||
self.base.id()
|
||||
}
|
||||
|
||||
fn style(mut self, style: ButtonStyle) -> Self {
|
||||
self.base = self.base.style(style);
|
||||
self
|
||||
}
|
||||
|
||||
fn size(mut self, size: ButtonSize) -> Self {
|
||||
self.base = self.base.size(size);
|
||||
self
|
||||
}
|
||||
|
||||
fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
|
||||
self.base = self.base.tooltip(tooltip);
|
||||
self
|
||||
}
|
||||
|
||||
fn tab_index(mut self, tab_index: impl Into<isize>) -> Self {
|
||||
self.base = self.base.tab_index(tab_index);
|
||||
self
|
||||
}
|
||||
|
||||
fn layer(mut self, elevation: ElevationIndex) -> Self {
|
||||
self.base = self.base.layer(elevation);
|
||||
self
|
||||
}
|
||||
|
||||
fn track_focus(mut self, focus_handle: &gpui::FocusHandle) -> Self {
|
||||
self.base = self.base.track_focus(focus_handle);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for ToggleButton {
|
||||
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||
let is_disabled = self.base.disabled;
|
||||
let is_selected = self.base.selected;
|
||||
|
||||
let label_color = if is_disabled {
|
||||
Color::Disabled
|
||||
} else if is_selected {
|
||||
Color::Selected
|
||||
} else {
|
||||
self.label_color.unwrap_or_default()
|
||||
};
|
||||
|
||||
self.base
|
||||
.when_some(self.position_in_group, |this, position| {
|
||||
this.rounding(position.to_rounding())
|
||||
})
|
||||
.child(
|
||||
Label::new(self.label)
|
||||
.color(label_color)
|
||||
.line_height_style(LineHeightStyle::UiLabel),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for ToggleButton {
|
||||
fn scope() -> ComponentScope {
|
||||
ComponentScope::Input
|
||||
}
|
||||
|
||||
fn sort_name() -> &'static str {
|
||||
"ButtonC"
|
||||
}
|
||||
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||
Some(
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
example_group_with_title(
|
||||
"Button Styles",
|
||||
vec![
|
||||
single_example(
|
||||
"Off",
|
||||
ToggleButton::new("off", "Off")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"On",
|
||||
ToggleButton::new("on", "On")
|
||||
.layer(ElevationIndex::Background)
|
||||
.toggle_state(true)
|
||||
.style(ButtonStyle::Filled)
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Off – Disabled",
|
||||
ToggleButton::new("disabled_off", "Disabled Off")
|
||||
.layer(ElevationIndex::Background)
|
||||
.disabled(true)
|
||||
.style(ButtonStyle::Filled)
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"On – Disabled",
|
||||
ToggleButton::new("disabled_on", "Disabled On")
|
||||
.layer(ElevationIndex::Background)
|
||||
.disabled(true)
|
||||
.toggle_state(true)
|
||||
.style(ButtonStyle::Filled)
|
||||
.into_any_element(),
|
||||
),
|
||||
],
|
||||
),
|
||||
example_group_with_title(
|
||||
"Button Group",
|
||||
vec![
|
||||
single_example(
|
||||
"Three Buttons",
|
||||
h_flex()
|
||||
.child(
|
||||
ToggleButton::new("three_btn_first", "First")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.first()
|
||||
.into_any_element(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new("three_btn_middle", "Middle")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.middle()
|
||||
.toggle_state(true)
|
||||
.into_any_element(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new("three_btn_last", "Last")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.last()
|
||||
.into_any_element(),
|
||||
)
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Two Buttons",
|
||||
h_flex()
|
||||
.child(
|
||||
ToggleButton::new("two_btn_first", "First")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.first()
|
||||
.into_any_element(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new("two_btn_last", "Last")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.last()
|
||||
.into_any_element(),
|
||||
)
|
||||
.into_any_element(),
|
||||
),
|
||||
],
|
||||
),
|
||||
example_group_with_title(
|
||||
"Alternate Sizes",
|
||||
vec![
|
||||
single_example(
|
||||
"None",
|
||||
ToggleButton::new("none", "None")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::None)
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Compact",
|
||||
ToggleButton::new("compact", "Compact")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Compact)
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Large",
|
||||
ToggleButton::new("large", "Large")
|
||||
.layer(ElevationIndex::Background)
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.into_any_element(),
|
||||
),
|
||||
],
|
||||
),
|
||||
])
|
||||
.into_any_element(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ButtonConfiguration {
|
||||
label: SharedString,
|
||||
icon: Option<IconName>,
|
||||
@@ -447,6 +163,8 @@ pub enum ToggleButtonGroupStyle {
|
||||
pub enum ToggleButtonGroupSize {
|
||||
Default,
|
||||
Medium,
|
||||
Large,
|
||||
Custom(Rems),
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
@@ -458,7 +176,9 @@ where
|
||||
rows: [[T; COLS]; ROWS],
|
||||
style: ToggleButtonGroupStyle,
|
||||
size: ToggleButtonGroupSize,
|
||||
label_size: LabelSize,
|
||||
group_width: Option<DefiniteLength>,
|
||||
auto_width: bool,
|
||||
selected_index: usize,
|
||||
tab_index: Option<isize>,
|
||||
}
|
||||
@@ -470,7 +190,9 @@ impl<T: ButtonBuilder, const COLS: usize> ToggleButtonGroup<T, COLS> {
|
||||
rows: [buttons],
|
||||
style: ToggleButtonGroupStyle::Transparent,
|
||||
size: ToggleButtonGroupSize::Default,
|
||||
label_size: LabelSize::Small,
|
||||
group_width: None,
|
||||
auto_width: false,
|
||||
selected_index: 0,
|
||||
tab_index: None,
|
||||
}
|
||||
@@ -488,7 +210,9 @@ impl<T: ButtonBuilder, const COLS: usize> ToggleButtonGroup<T, COLS, 2> {
|
||||
rows: [first_row, second_row],
|
||||
style: ToggleButtonGroupStyle::Transparent,
|
||||
size: ToggleButtonGroupSize::Default,
|
||||
label_size: LabelSize::Small,
|
||||
group_width: None,
|
||||
auto_width: false,
|
||||
selected_index: 0,
|
||||
tab_index: None,
|
||||
}
|
||||
@@ -511,6 +235,18 @@ impl<T: ButtonBuilder, const COLS: usize, const ROWS: usize> ToggleButtonGroup<T
|
||||
self
|
||||
}
|
||||
|
||||
/// Makes the button group size itself to fit the content of the buttons,
|
||||
/// rather than filling the full width of its parent.
|
||||
pub fn auto_width(mut self) -> Self {
|
||||
self.auto_width = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn label_size(mut self, label_size: LabelSize) -> Self {
|
||||
self.label_size = label_size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the tab index for the toggle button group.
|
||||
/// The tab index is set to the initial value provided, then the
|
||||
/// value is incremented by the number of buttons in the group.
|
||||
@@ -543,6 +279,11 @@ impl<T: ButtonBuilder, const COLS: usize, const ROWS: usize> RenderOnce
|
||||
for ToggleButtonGroup<T, COLS, ROWS>
|
||||
{
|
||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let custom_height = match self.size {
|
||||
ToggleButtonGroupSize::Custom(height) => Some(height),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let entries =
|
||||
self.rows.into_iter().enumerate().map(|(row_index, row)| {
|
||||
let group_name = self.group_name.clone();
|
||||
@@ -558,7 +299,7 @@ impl<T: ButtonBuilder, const COLS: usize, const ROWS: usize> RenderOnce
|
||||
let entry_index = row_index * COLS + col_index;
|
||||
|
||||
ButtonLike::new((group_name.clone(), entry_index))
|
||||
.full_width()
|
||||
.when(!self.auto_width, |this| this.full_width())
|
||||
.rounding(Some(
|
||||
ToggleButtonPosition {
|
||||
leftmost: col_index == 0,
|
||||
@@ -581,13 +322,17 @@ impl<T: ButtonBuilder, const COLS: usize, const ROWS: usize> RenderOnce
|
||||
.when(self.size == ToggleButtonGroupSize::Medium, |button| {
|
||||
button.size(ButtonSize::Medium)
|
||||
})
|
||||
.when(self.size == ToggleButtonGroupSize::Large, |button| {
|
||||
button.size(ButtonSize::Large)
|
||||
})
|
||||
.when_some(custom_height, |button, height| button.height(height.into()))
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.px_2()
|
||||
.gap_1p5()
|
||||
.px_3()
|
||||
.py_1()
|
||||
.justify_center()
|
||||
.flex_none()
|
||||
.when_some(icon, |this, icon| {
|
||||
this.py_2()
|
||||
.child(Icon::new(icon).size(IconSize::XSmall).map(|this| {
|
||||
@@ -598,7 +343,7 @@ impl<T: ButtonBuilder, const COLS: usize, const ROWS: usize> RenderOnce
|
||||
}
|
||||
}))
|
||||
})
|
||||
.child(Label::new(label).size(LabelSize::Small).when(
|
||||
.child(Label::new(label).size(self.label_size).when(
|
||||
entry_index == self.selected_index || selected,
|
||||
|this| this.color(Color::Accent),
|
||||
)),
|
||||
@@ -620,6 +365,8 @@ impl<T: ButtonBuilder, const COLS: usize, const ROWS: usize> RenderOnce
|
||||
.map(|this| {
|
||||
if let Some(width) = self.group_width {
|
||||
this.w(width)
|
||||
} else if self.auto_width {
|
||||
this
|
||||
} else {
|
||||
this.w_full()
|
||||
}
|
||||
@@ -646,7 +393,7 @@ impl<T: ButtonBuilder, const COLS: usize, const ROWS: usize> RenderOnce
|
||||
.when(is_outlined_or_filled && !last_item, |this| {
|
||||
this.border_r_1().border_color(border_color)
|
||||
})
|
||||
.w(Self::button_width())
|
||||
.when(!self.auto_width, |this| this.w(Self::button_width()))
|
||||
.overflow_hidden()
|
||||
.child(item)
|
||||
}))
|
||||
|
||||
@@ -6,7 +6,6 @@ mod list_header;
|
||||
mod list_item;
|
||||
mod tab;
|
||||
mod tab_bar;
|
||||
mod toggle_button;
|
||||
|
||||
pub use context_menu::*;
|
||||
pub use icon_button::*;
|
||||
@@ -16,4 +15,3 @@ pub use list_header::*;
|
||||
pub use list_item::*;
|
||||
pub use tab::*;
|
||||
pub use tab_bar::*;
|
||||
pub use toggle_button::*;
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
use gpui::Render;
|
||||
use story::{Story, StoryItem, StorySection};
|
||||
|
||||
use crate::{ToggleButton, prelude::*};
|
||||
|
||||
pub struct ToggleButtonStory;
|
||||
|
||||
impl Render for ToggleButtonStory {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<ToggleButton>(cx))
|
||||
.child(
|
||||
StorySection::new().child(
|
||||
StoryItem::new(
|
||||
"Default",
|
||||
ToggleButton::new("default_toggle_button", "Hello"),
|
||||
)
|
||||
.description("Displays a toggle button.")
|
||||
.usage(""),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
StorySection::new().child(
|
||||
StoryItem::new(
|
||||
"Toggle button group",
|
||||
h_flex()
|
||||
.child(
|
||||
ToggleButton::new(1, "Apple")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.first(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(2, "Banana")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.middle(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(3, "Cherry")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.middle(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(4, "Dragonfruit")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.last(),
|
||||
),
|
||||
)
|
||||
.description("Displays a group of toggle buttons.")
|
||||
.usage(""),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
StorySection::new().child(
|
||||
StoryItem::new(
|
||||
"Toggle button group with selection",
|
||||
h_flex()
|
||||
.child(
|
||||
ToggleButton::new(1, "Apple")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.first(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(2, "Banana")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.toggle_state(true)
|
||||
.middle(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(3, "Cherry")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.middle(),
|
||||
)
|
||||
.child(
|
||||
ToggleButton::new(4, "Dragonfruit")
|
||||
.style(ButtonStyle::Filled)
|
||||
.size(ButtonSize::Large)
|
||||
.last(),
|
||||
),
|
||||
)
|
||||
.description("Displays a group of toggle buttons.")
|
||||
.usage(""),
|
||||
),
|
||||
)
|
||||
.into_element()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user