Detailed changes
@@ -332,10 +332,11 @@ impl AgentConfiguration {
.full_width()
.style(ButtonStyle::Outlined)
.layer(ElevationIndex::ModalSurface)
- .icon_position(IconPosition::Start)
- .icon(IconName::Thread)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::Thread)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.label_size(LabelSize::Small)
.on_click(cx.listener({
let provider = provider.clone();
@@ -357,10 +358,11 @@ impl AgentConfiguration {
)
.full_width()
.style(ButtonStyle::Outlined)
- .icon_position(IconPosition::Start)
- .icon(IconName::Trash)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::Trash)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.label_size(LabelSize::Small)
.on_click(cx.listener({
let provider = provider.clone();
@@ -426,10 +428,11 @@ impl AgentConfiguration {
.trigger(
Button::new("add-provider", "Add Provider")
.style(ButtonStyle::Outlined)
- .icon_position(IconPosition::Start)
- .icon(IconName::Plus)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::Plus)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.label_size(LabelSize::Small),
)
.menu({
@@ -525,10 +528,11 @@ impl AgentConfiguration {
.trigger(
Button::new("add-server", "Add Server")
.style(ButtonStyle::Outlined)
- .icon_position(IconPosition::Start)
- .icon(IconName::Plus)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::Plus)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.label_size(LabelSize::Small),
)
.menu({
@@ -970,10 +974,11 @@ impl AgentConfiguration {
.trigger(
Button::new("add-agent", "Add Agent")
.style(ButtonStyle::Outlined)
- .icon_position(IconPosition::Start)
- .icon(IconName::Plus)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::Plus)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.label_size(LabelSize::Small),
)
.menu({
@@ -340,10 +340,11 @@ impl AddLlmProviderModal {
.child(Label::new("Models").size(LabelSize::Small))
.child(
Button::new("add-model", "Add Model")
- .icon(IconName::Plus)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::Plus)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
.label_size(LabelSize::Small)
.on_click(cx.listener(|this, _, window, cx| {
this.input.add_model(window, cx);
@@ -446,10 +447,11 @@ impl AddLlmProviderModal {
.when(has_more_than_one_model, |this| {
this.child(
Button::new(("remove-model", ix), "Remove Model")
- .icon(IconName::Trash)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::Trash)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
.label_size(LabelSize::Small)
.style(ButtonStyle::Outlined)
.full_width()
@@ -693,9 +693,11 @@ impl ConfigureContextServerModal {
{
Some(
Button::new("open-repository", "Open Repository")
- .icon(IconName::ArrowUpRight)
- .icon_color(Color::Muted)
- .icon_size(IconSize::Small)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.tooltip({
let repository_url = repository_url.clone();
move |_window, cx| {
@@ -686,10 +686,11 @@ impl Render for AgentDiffPane {
.child(
Button::new("continue-iterating", "Continue Iterating")
.style(ButtonStyle::Filled)
- .icon(IconName::ForwardArrow)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::ForwardArrow)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.full_width()
.key_binding(KeyBinding::for_action_in(
&ToggleFocus,
@@ -9,7 +9,7 @@ use language_model::IconOrSvg;
use picker::popover_menu::PickerPopoverMenu;
use settings::update_settings_file;
use std::sync::Arc;
-use ui::{ButtonLike, PopoverMenuHandle, TintColor, Tooltip, prelude::*};
+use ui::{PopoverMenuHandle, Tooltip, prelude::*};
pub struct AgentModelSelector {
selector: Entity<LanguageModelSelector>,
@@ -112,9 +112,11 @@ impl Render for AgentModelSelector {
PickerPopoverMenu::new(
self.selector.clone(),
- ButtonLike::new("active-model")
+ Button::new("active-model", model_name)
+ .label_size(LabelSize::Small)
+ .color(color)
.when_some(provider_icon, |this, icon| {
- this.child(
+ this.start_icon(
match icon {
IconOrSvg::Svg(path) => Icon::from_external_svg(path),
IconOrSvg::Icon(name) => Icon::new(name),
@@ -123,14 +125,7 @@ impl Render for AgentModelSelector {
.size(IconSize::XSmall),
)
})
- .selected_style(ButtonStyle::Tinted(TintColor::Accent))
- .child(
- Label::new(model_name)
- .color(color)
- .size(LabelSize::Small)
- .ml_0p5(),
- )
- .child(
+ .end_icon(
Icon::new(IconName::ChevronDown)
.color(color)
.size(IconSize::XSmall),
@@ -80,9 +80,8 @@ use search::{BufferSearchBar, buffer_search};
use settings::{Settings, update_settings_file};
use theme::ThemeSettings;
use ui::{
- Button, ButtonLike, Callout, ContextMenu, ContextMenuEntry, DocumentationSide, Indicator,
- KeyBinding, PopoverMenu, PopoverMenuHandle, SpinnerLabel, Tab, TintColor, Tooltip, prelude::*,
- utils::WithRemSize,
+ Button, Callout, ContextMenu, ContextMenuEntry, DocumentationSide, Indicator, KeyBinding,
+ PopoverMenu, PopoverMenuHandle, SpinnerLabel, Tab, Tooltip, prelude::*, utils::WithRemSize,
};
use util::{ResultExt as _, debug_panic};
use workspace::{
@@ -3632,11 +3631,7 @@ impl AgentPanel {
};
let trigger_button = Button::new("thread-target-trigger", trigger_label)
- .icon(icon)
- .icon_size(IconSize::XSmall)
- .icon_position(IconPosition::End)
- .icon_color(Color::Muted)
- .selected_style(ButtonStyle::Tinted(TintColor::Accent))
+ .end_icon(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted))
.disabled(is_creating);
let dock_position = AgentSettings::get_global(cx).dock;
@@ -4290,32 +4285,22 @@ impl AgentPanel {
(IconName::ChevronDown, Color::Muted, Color::Default)
};
- let agent_icon_element: AnyElement =
- if let Some(icon_path) = selected_agent_custom_icon_for_button {
- Icon::from_external_svg(icon_path)
- .size(IconSize::Small)
- .color(icon_color)
- .into_any_element()
- } else {
- let icon_name = selected_agent_builtin_icon.unwrap_or(IconName::ZedAgent);
- Icon::new(icon_name)
- .size(IconSize::Small)
- .color(icon_color)
- .into_any_element()
- };
+ let agent_icon = if let Some(icon_path) = selected_agent_custom_icon_for_button {
+ Icon::from_external_svg(icon_path)
+ .size(IconSize::Small)
+ .color(icon_color)
+ } else {
+ let icon_name = selected_agent_builtin_icon.unwrap_or(IconName::ZedAgent);
+ Icon::new(icon_name).size(IconSize::Small).color(icon_color)
+ };
- let agent_selector_button = ButtonLike::new("agent-selector-trigger")
- .selected_style(ButtonStyle::Tinted(TintColor::Accent))
- .child(
- h_flex()
- .gap_1()
- .child(agent_icon_element)
- .child(Label::new(selected_agent_label).color(label_color).ml_0p5())
- .child(
- Icon::new(chevron_icon)
- .color(icon_color)
- .size(IconSize::XSmall),
- ),
+ let agent_selector_button = Button::new("agent-selector-trigger", selected_agent_label)
+ .start_icon(agent_icon)
+ .color(label_color)
+ .end_icon(
+ Icon::new(chevron_icon)
+ .color(icon_color)
+ .size(IconSize::XSmall),
);
let agent_selector_menu = PopoverMenu::new("new_thread_menu")
@@ -467,10 +467,11 @@ impl AgentRegistryPage {
let agent_id = agent.id().to_string();
Button::new(button_id, "Install")
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
- .icon(IconName::Download)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, _, cx| {
let agent_id = agent_id.clone();
update_settings_file(fs.clone(), cx, move |settings, _| {
@@ -541,9 +542,11 @@ impl Render for AgentRegistryPage {
Button::new("learn-more", "Learn More")
.style(ButtonStyle::Outlined)
.size(ButtonSize::Medium)
- .icon(IconName::ArrowUpRight)
- .icon_color(Color::Muted)
- .icon_size(IconSize::Small)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, _, cx| {
cx.open_url(&zed_urls::acp_registry_blog(cx))
}),
@@ -350,10 +350,7 @@ impl ConfigOptionSelector {
)
.label_size(LabelSize::Small)
.color(Color::Muted)
- .icon(icon)
- .icon_size(IconSize::XSmall)
- .icon_position(IconPosition::End)
- .icon_color(Color::Muted)
+ .end_icon(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted))
.disabled(self.setting_value)
}
}
@@ -3826,11 +3826,8 @@ impl ThreadView {
.child(Divider::horizontal())
.child(
Button::new("restore-checkpoint", "Restore Checkpoint")
- .icon(IconName::Undo)
- .icon_size(IconSize::XSmall)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::Undo).size(IconSize::XSmall).color(Color::Muted))
.label_size(LabelSize::XSmall)
- .icon_color(Color::Muted)
.color(Color::Muted)
.tooltip(Tooltip::text("Restores all files in the project to the content they had at this point in the conversation."))
.on_click(cx.listener(move |this, _, _window, cx| {
@@ -5783,10 +5780,11 @@ impl ThreadView {
.gap_0p5()
.child(
Button::new(("allow-btn", entry_ix), "Allow")
- .icon(IconName::Check)
- .icon_color(Color::Success)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::XSmall)
+ .start_icon(
+ Icon::new(IconName::Check)
+ .size(IconSize::XSmall)
+ .color(Color::Success),
+ )
.label_size(LabelSize::Small)
.when(is_first, |this| {
this.key_binding(
@@ -5817,10 +5815,11 @@ impl ThreadView {
)
.child(
Button::new(("deny-btn", entry_ix), "Deny")
- .icon(IconName::Close)
- .icon_color(Color::Error)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::XSmall)
+ .start_icon(
+ Icon::new(IconName::Close)
+ .size(IconSize::XSmall)
+ .color(Color::Error),
+ )
.label_size(LabelSize::Small)
.when(is_first, |this| {
this.key_binding(
@@ -5887,9 +5886,11 @@ impl ThreadView {
.with_handle(permission_dropdown_handle)
.trigger(
Button::new(("granularity-trigger", entry_ix), current_label)
- .icon(IconName::ChevronDown)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ChevronDown)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
.label_size(LabelSize::Small)
.when(is_first, |this| {
this.key_binding(
@@ -5962,24 +5963,35 @@ impl ThreadView {
let option_id = SharedString::from(option.option_id.0.clone());
Button::new((option_id, entry_ix), option.name.clone())
.map(|this| {
- let (this, action) = match option.kind {
+ let (icon, action) = match option.kind {
acp::PermissionOptionKind::AllowOnce => (
- this.icon(IconName::Check).icon_color(Color::Success),
+ Icon::new(IconName::Check)
+ .size(IconSize::XSmall)
+ .color(Color::Success),
Some(&AllowOnce as &dyn Action),
),
acp::PermissionOptionKind::AllowAlways => (
- this.icon(IconName::CheckDouble).icon_color(Color::Success),
+ Icon::new(IconName::CheckDouble)
+ .size(IconSize::XSmall)
+ .color(Color::Success),
Some(&AllowAlways as &dyn Action),
),
acp::PermissionOptionKind::RejectOnce => (
- this.icon(IconName::Close).icon_color(Color::Error),
+ Icon::new(IconName::Close)
+ .size(IconSize::XSmall)
+ .color(Color::Error),
Some(&RejectOnce as &dyn Action),
),
- acp::PermissionOptionKind::RejectAlways | _ => {
- (this.icon(IconName::Close).icon_color(Color::Error), None)
- }
+ acp::PermissionOptionKind::RejectAlways | _ => (
+ Icon::new(IconName::Close)
+ .size(IconSize::XSmall)
+ .color(Color::Error),
+ None,
+ ),
};
+ let this = this.start_icon(icon);
+
let Some(action) = action else {
return this;
};
@@ -5995,8 +6007,6 @@ impl ThreadView {
.map(|kb| kb.size(rems_from_px(10.))),
)
})
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::XSmall)
.label_size(LabelSize::Small)
.on_click(cx.listener({
let session_id = session_id.clone();
@@ -6373,9 +6383,11 @@ impl ThreadView {
.color(Color::Muted)
.truncate(true)
.when(is_file.is_none(), |this| {
- this.icon(IconName::ArrowUpRight)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ this.end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
})
.on_click(cx.listener({
let workspace = self.workspace.clone();
@@ -7470,19 +7482,16 @@ impl ThreadView {
.title("Codex on Windows")
.description("For best performance, run Codex in Windows Subsystem for Linux (WSL2)")
.actions_slot(
- Button::new("open-wsl-modal", "Open in WSL")
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .on_click(cx.listener({
- move |_, _, _window, cx| {
- #[cfg(windows)]
- _window.dispatch_action(
- zed_actions::wsl_actions::OpenWsl::default().boxed_clone(),
- cx,
- );
- cx.notify();
- }
- })),
+ Button::new("open-wsl-modal", "Open in WSL").on_click(cx.listener({
+ move |_, _, _window, cx| {
+ #[cfg(windows)]
+ _window.dispatch_action(
+ zed_actions::wsl_actions::OpenWsl::default().boxed_clone(),
+ cx,
+ );
+ cx.notify();
+ }
+ })),
)
.dismiss_action(
IconButton::new("dismiss", IconName::Close)
@@ -796,9 +796,11 @@ impl<T: 'static> PromptEditor<T> {
vec![
Button::new("start", mode.start_label())
.label_size(LabelSize::Small)
- .icon(IconName::Return)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::Return)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
.on_click(
cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::StartRequested)),
)
@@ -33,7 +33,7 @@ use rope::Point;
use settings::Settings;
use std::{cell::RefCell, fmt::Write, ops::Range, rc::Rc, sync::Arc};
use theme::ThemeSettings;
-use ui::{ButtonLike, ButtonStyle, ContextMenu, Disclosure, ElevationIndex, prelude::*};
+use ui::{ContextMenu, Disclosure, ElevationIndex, prelude::*};
use util::paths::PathStyle;
use util::{ResultExt, debug_panic};
use workspace::{CollaboratorId, Workspace};
@@ -1161,11 +1161,9 @@ impl MessageEditor {
render: Arc::new({
let title = title.clone();
move |_fold_id, _fold_range, _cx| {
- ButtonLike::new("crease")
- .style(ButtonStyle::Filled)
+ Button::new("crease", title.clone())
.layer(ElevationIndex::ElevatedSurface)
- .child(Icon::new(icon))
- .child(Label::new(title.clone()).single_line())
+ .start_icon(Icon::new(icon))
.into_any_element()
}
}),
@@ -169,10 +169,7 @@ impl Render for ModeSelector {
let trigger_button = Button::new("mode-selector-trigger", current_mode_name)
.label_size(LabelSize::Small)
.color(Color::Muted)
- .icon(icon)
- .icon_size(IconSize::XSmall)
- .icon_position(IconPosition::End)
- .icon_color(Color::Muted)
+ .end_icon(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted))
.disabled(self.setting_mode);
PopoverMenu::new("mode-selector")
@@ -5,7 +5,7 @@ use acp_thread::{AgentModelIcon, AgentModelInfo, AgentModelSelector};
use fs::Fs;
use gpui::{AnyView, Entity, FocusHandle};
use picker::popover_menu::PickerPopoverMenu;
-use ui::{ButtonLike, PopoverMenuHandle, TintColor, Tooltip, prelude::*};
+use ui::{PopoverMenuHandle, Tooltip, prelude::*};
use crate::ui::ModelSelectorTooltip;
use crate::{ModelSelector, model_selector::acp_model_selector};
@@ -96,11 +96,12 @@ impl Render for ModelSelectorPopover {
PickerPopoverMenu::new(
self.selector.clone(),
- ButtonLike::new("active-model")
+ Button::new("active-model", model_name)
+ .label_size(LabelSize::Small)
+ .color(color)
.disabled(self.disabled)
- .selected_style(ButtonStyle::Tinted(TintColor::Accent))
.when_some(model_icon, |this, icon| {
- this.child(
+ this.start_icon(
match icon {
AgentModelIcon::Path(path) => Icon::from_external_svg(path),
AgentModelIcon::Named(icon_name) => Icon::new(icon_name),
@@ -109,13 +110,7 @@ impl Render for ModelSelectorPopover {
.size(IconSize::XSmall),
)
})
- .child(
- Label::new(model_name)
- .color(color)
- .size(LabelSize::Small)
- .ml_0p5(),
- )
- .child(
+ .end_icon(
Icon::new(icon)
.map(|this| {
if self.disabled {
@@ -16,7 +16,7 @@ use std::{
};
use ui::{
DocumentationAside, DocumentationSide, HighlightedLabel, KeyBinding, LabelSize, ListItem,
- ListItemSpacing, PopoverMenuHandle, TintColor, Tooltip, prelude::*,
+ ListItemSpacing, PopoverMenuHandle, Tooltip, prelude::*,
};
/// Trait for types that can provide and manage agent profiles
@@ -192,11 +192,7 @@ impl Render for ProfileSelector {
.disabled(self.disabled)
.label_size(LabelSize::Small)
.color(Color::Muted)
- .icon(icon)
- .icon_size(IconSize::XSmall)
- .icon_position(IconPosition::End)
- .icon_color(Color::Muted)
- .selected_style(ButtonStyle::Tinted(TintColor::Accent));
+ .end_icon(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted));
let disabled = self.disabled;
@@ -1775,10 +1775,11 @@ impl Sidebar {
)
.full_width()
.style(ButtonStyle::Outlined)
- .icon(IconName::Plus)
- .icon_color(Color::Muted)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Plus)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.toggle_state(is_selected)
.on_click(cx.listener(move |this, _, window, cx| {
this.selection = None;
@@ -1833,10 +1834,11 @@ impl Sidebar {
.full_width()
.label_size(LabelSize::Small)
.style(ButtonStyle::Outlined)
- .icon(IconName::Archive)
- .icon_color(Color::Muted)
- .icon_size(IconSize::XSmall)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Archive)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
.on_click(cx.listener(|this, _, window, cx| {
this.show_archive(window, cx);
})),
@@ -1191,11 +1191,11 @@ impl TextThreadEditor {
Button::new("show-error", "Error")
.color(Color::Error)
.selected_label_color(Color::Error)
- .selected_icon_color(Color::Error)
- .icon(IconName::XCircle)
- .icon_color(Color::Error)
- .icon_size(IconSize::XSmall)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::XCircle)
+ .size(IconSize::XSmall)
+ .color(Color::Error),
+ )
.tooltip(Tooltip::text("View Details"))
.on_click({
let text_thread = text_thread.clone();
@@ -2287,20 +2287,11 @@ impl TextThreadEditor {
PickerPopoverMenu::new(
self.language_model_selector.clone(),
- ButtonLike::new("active-model")
- .selected_style(ButtonStyle::Tinted(TintColor::Accent))
- .child(
- h_flex()
- .gap_0p5()
- .child(provider_icon_element)
- .child(
- Label::new(model_name)
- .color(color)
- .size(LabelSize::Small)
- .ml_0p5(),
- )
- .child(Icon::new(icon).color(color).size(IconSize::XSmall)),
- ),
+ Button::new("active-model", model_name)
+ .color(color)
+ .label_size(LabelSize::Small)
+ .start_icon(provider_icon_element)
+ .end_icon(Icon::new(icon).color(color).size(IconSize::XSmall)),
tooltip,
gpui::Corner::BottomRight,
cx,
@@ -193,15 +193,16 @@ impl Render for AcpOnboardingModal {
let copy = "Bring the agent of your choice to Zed via our new Agent Client Protocol (ACP), starting with Google's Gemini CLI integration.";
let open_panel_button = Button::new("open-panel", "Start with Gemini CLI")
- .icon_size(IconSize::Indicator)
.style(ButtonStyle::Tinted(TintColor::Accent))
.full_width()
.on_click(cx.listener(Self::open_panel));
let docs_button = Button::new("add-other-agents", "Add Other Agents")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Indicator)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Indicator)
+ .color(Color::Muted),
+ )
.full_width()
.on_click(cx.listener(Self::open_agent_registry));
@@ -201,15 +201,16 @@ impl Render for ClaudeCodeOnboardingModal {
let copy = "Powered by the Agent Client Protocol, you can now run Claude Agent as\na first-class citizen in Zed's agent panel.";
let open_panel_button = Button::new("open-panel", "Start with Claude Agent")
- .icon_size(IconSize::Indicator)
.style(ButtonStyle::Tinted(TintColor::Accent))
.full_width()
.on_click(cx.listener(Self::open_panel));
let docs_button = Button::new("add-other-agents", "Add Other Agents")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Indicator)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Indicator)
+ .color(Color::Muted),
+ )
.full_width()
.on_click(cx.listener(Self::view_docs));
@@ -2347,9 +2347,7 @@ impl CollabPanel {
.gap_2()
.child(
Button::new("sign_in", button_label)
- .icon_color(Color::Muted)
- .icon(IconName::Github)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::Github).color(Color::Muted))
.style(ButtonStyle::Filled)
.full_width()
.disabled(is_signing_in)
@@ -2597,9 +2595,9 @@ impl CollabPanel {
Section::Channels => {
Some(
h_flex()
- .gap_1()
.child(
IconButton::new("filter-active-channels", IconName::ListFilter)
+ .icon_size(IconSize::Small)
.toggle_state(self.filter_active_channels)
.when(!self.filter_active_channels, |button| {
button.visible_on_hover("section-header")
@@ -544,9 +544,7 @@ impl Render for NotificationPanel {
.p_4()
.child(
Button::new("connect_prompt_button", "Connect")
- .icon_color(Color::Muted)
- .icon(IconName::Github)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::Github).color(Color::Muted))
.style(ButtonStyle::Filled)
.full_width()
.on_click({
@@ -387,10 +387,11 @@ impl CopilotCodeVerification {
.full_width()
.style(ButtonStyle::Outlined)
.size(ButtonSize::Medium)
- .icon(IconName::Download)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, window, cx| {
reinstall_and_sign_in(copilot.clone(), window, cx)
}),
@@ -570,10 +571,11 @@ impl ConfigurationView {
}
})
.style(ButtonStyle::Outlined)
- .icon(IconName::Github)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(
+ Icon::new(IconName::Github)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.when(edit_prediction, |this| this.tab_index(0isize))
.on_click(|_, window, cx| {
if let Some(app_state) = AppState::global(cx).upgrade()
@@ -600,10 +602,11 @@ impl ConfigurationView {
}
})
.style(ButtonStyle::Outlined)
- .icon(IconName::Download)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(|_, window, cx| {
if let Some(app_state) = AppState::global(cx).upgrade()
&& let Some(copilot) = GlobalCopilotAuth::try_get_or_init(app_state, cx)
@@ -1821,20 +1821,22 @@ impl Render for DebugPanel {
.gap_2()
.child(
Button::new("spawn-new-session-empty-state", "New Session")
- .icon(IconName::Plus)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Plus)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(|_, window, cx| {
window.dispatch_action(crate::Start.boxed_clone(), cx);
}),
)
.child(
Button::new("edit-debug-settings", "Edit debug.json")
- .icon(IconName::Code)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Code)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(|_, window, cx| {
window.dispatch_action(
zed_actions::OpenProjectDebugTasks.boxed_clone(),
@@ -1844,10 +1846,11 @@ impl Render for DebugPanel {
)
.child(
Button::new("open-debugger-docs", "Debugger Docs")
- .icon(IconName::Book)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Book)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(|_, _, cx| cx.open_url("https://zed.dev/docs/debugger")),
)
.child(
@@ -1855,10 +1858,11 @@ impl Render for DebugPanel {
"spawn-new-session-install-extensions",
"Debugger Extensions",
)
- .icon(IconName::Blocks)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Blocks)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(|_, window, cx| {
window.dispatch_action(
zed_actions::Extensions {
@@ -765,9 +765,7 @@ impl RatePredictionsModal {
.gap_1()
.child(
Button::new("bad", "Bad Prediction")
- .icon(IconName::ThumbsDown)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::ThumbsDown).size(IconSize::Small))
.disabled(rated || feedback_empty)
.when(feedback_empty, |this| {
this.tooltip(Tooltip::text(
@@ -791,9 +789,7 @@ impl RatePredictionsModal {
)
.child(
Button::new("good", "Good Prediction")
- .icon(IconName::ThumbsUp)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::ThumbsUp).size(IconSize::Small))
.disabled(rated)
.key_binding(KeyBinding::for_action_in(
&ThumbsUpActivePrediction,
@@ -1056,10 +1056,11 @@ impl ExtensionsPage {
"Install",
)
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
- .icon(IconName::Download)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click({
let extension_id = extension.id.clone();
move |_, _, cx| {
@@ -1078,10 +1079,11 @@ impl ExtensionsPage {
"Install",
)
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
- .icon(IconName::Download)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.disabled(true),
configure: None,
upgrade: None,
@@ -1479,10 +1481,11 @@ impl ExtensionsPage {
}
});
let open_registry_button = Button::new("open_registry", "Learn More")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::End)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click({
move |_event, _window, cx| {
telemetry::event!(
@@ -1520,9 +1523,7 @@ impl ExtensionsPage {
cx: &mut Context<Self>,
) -> impl IntoElement {
let docs_url_button = Button::new("open_docs", "View Documentation")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::End)
+ .end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::Small))
.on_click({
move |_event, _window, cx| {
telemetry::event!(
@@ -1494,10 +1494,9 @@ impl GitGraph {
this.child(
Button::new("author-email-copy", author_email.clone())
- .icon(icon)
- .icon_size(IconSize::Small)
- .icon_color(icon_color)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(icon).size(IconSize::Small).color(icon_color),
+ )
.label_size(LabelSize::Small)
.truncate(true)
.color(Color::Muted)
@@ -1542,10 +1541,9 @@ impl GitGraph {
};
Button::new("sha-button", &full_sha)
- .icon(icon)
- .icon_size(IconSize::Small)
- .icon_color(icon_color)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(icon).size(IconSize::Small).color(icon_color),
+ )
.label_size(LabelSize::Small)
.truncate(true)
.color(Color::Muted)
@@ -1602,10 +1600,9 @@ impl GitGraph {
"view-on-provider",
format!("View on {}", provider_name),
)
- .icon(icon)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(icon).size(IconSize::Small).color(Color::Muted),
+ )
.label_size(LabelSize::Small)
.truncate(true)
.color(Color::Muted)
@@ -322,10 +322,11 @@ impl BlameRenderer for GitBlameRenderer {
format!("#{}", pr.number),
)
.color(Color::Muted)
- .icon(IconName::PullRequest)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(
+ Icon::new(IconName::PullRequest)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, _, cx| {
cx.stop_propagation();
cx.open_url(pr.url.as_str())
@@ -339,10 +340,11 @@ impl BlameRenderer for GitBlameRenderer {
short_commit_id.clone(),
)
.color(Color::Muted)
- .icon(IconName::FileGit)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(
+ Icon::new(IconName::FileGit)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, window, cx| {
CommitView::open(
commit_summary.sha.clone().into(),
@@ -366,11 +366,12 @@ impl CommitModal {
.unwrap_or_else(|| "<no branch>".to_owned());
let branch_picker_button = panel_button(branch)
- .icon(IconName::GitBranch)
- .icon_size(IconSize::Small)
- .icon_color(Color::Placeholder)
+ .start_icon(
+ Icon::new(IconName::GitBranch)
+ .size(IconSize::Small)
+ .color(Color::Placeholder),
+ )
.color(Color::Muted)
- .icon_position(IconPosition::Start)
.on_click(cx.listener(|_, _, window, cx| {
window.dispatch_action(zed_actions::git::Branch.boxed_clone(), cx);
}))
@@ -336,9 +336,10 @@ impl Render for CommitTooltip {
format!("#{}", pr.number),
)
.color(Color::Muted)
- .icon(IconName::PullRequest)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::PullRequest)
+ .color(Color::Muted),
+ )
.style(ButtonStyle::Subtle)
.on_click(move |_, _, cx| {
cx.stop_propagation();
@@ -354,9 +355,9 @@ impl Render for CommitTooltip {
)
.style(ButtonStyle::Subtle)
.color(Color::Muted)
- .icon(IconName::FileGit)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::FileGit).color(Color::Muted),
+ )
.on_click(
move |_, window, cx| {
CommitView::open(
@@ -524,10 +524,11 @@ impl CommitView {
.when(self.stash.is_none(), |this| {
this.child(
Button::new("sha", "Commit SHA")
- .icon(copy_icon)
- .icon_color(copy_icon_color)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(
+ Icon::new(copy_icon)
+ .size(IconSize::Small)
+ .color(copy_icon_color),
+ )
.tooltip({
let commit_sha = commit_sha.clone();
move |_, cx| {
@@ -453,10 +453,11 @@ fn render_conflict_buttons(
this.child(Divider::vertical()).child(
Button::new("resolve-with-agent", "Resolve with Agent")
.label_size(LabelSize::Small)
- .icon(IconName::ZedAssistant)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::ZedAssistant)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click({
let conflict = conflict.clone();
move |_, window, cx| {
@@ -429,10 +429,11 @@ impl Render for FileHistoryView {
Button::new("load-more", "Load More")
.disabled(self.loading_more)
.label_size(LabelSize::Small)
- .icon(IconName::ArrowCircle)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::ArrowCircle)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(cx.listener(|this, _, window, cx| {
this.load_more(window, cx);
})),
@@ -872,8 +872,7 @@ impl Render for GitCloneModal {
.child(
Button::new("learn-more", "Learn More")
.label_size(LabelSize::Small)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::XSmall)
+ .end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::XSmall))
.on_click(|_, _, cx| {
cx.open_url("https://github.com/git-guides/git-clone");
}),
@@ -1592,8 +1592,11 @@ fn render_send_review_to_agent_button(review_count: usize, focus_handle: &FocusH
"send-review",
format!("Send Review to Agent ({})", review_count),
)
- .icon(IconName::ZedAssistant)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::ZedAssistant)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.tooltip(Tooltip::for_action_title_in(
"Send all review comments to the Agent panel",
&SendReviewToAgent,
@@ -1686,10 +1689,11 @@ impl Render for BranchDiffToolbar {
let focus_handle = focus_handle.clone();
this.child(Divider::vertical()).child(
Button::new("review-diff", "Review Diff")
- .icon(IconName::ZedAssistant)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::ZedAssistant)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.key_binding(KeyBinding::for_action_in(&ReviewDiff, &focus_handle, cx))
.tooltip(move |_, cx| {
Tooltip::with_meta_in(
@@ -2928,9 +2928,11 @@ impl Render for KeybindingEditorModal {
.child(
Button::new("show_matching", "View")
.label_size(LabelSize::Small)
- .icon(IconName::ArrowUpRight)
- .icon_color(Color::Muted)
- .icon_size(IconSize::Small)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(cx.listener(
|this, _, window, cx| {
this.show_matching_bindings(
@@ -1574,7 +1574,8 @@ impl Render for ConfigurationView {
}
v_flex()
- .size_full()
+ .min_w_0()
+ .w_full()
.track_focus(&self.focus_handle)
.on_action(cx.listener(Self::on_tab))
.on_action(cx.listener(Self::on_tab_prev))
@@ -1126,6 +1126,7 @@ impl RenderOnce for ZedAiConfiguration {
let manage_subscription_buttons = if is_pro {
Button::new("manage_settings", "Manage Subscription")
.full_width()
+ .label_size(LabelSize::Small)
.style(ButtonStyle::Tinted(TintColor::Accent))
.on_click(|_, _, cx| cx.open_url(&zed_urls::account_url(cx)))
.into_any_element()
@@ -1149,10 +1150,7 @@ impl RenderOnce for ZedAiConfiguration {
.child(Label::new("Sign in to have access to Zed's complete agentic experience with hosted models."))
.child(
Button::new("sign_in", "Sign In to use Zed AI")
- .icon_color(Color::Muted)
- .icon(IconName::Github)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::Github).size(IconSize::Small).color(Color::Muted))
.full_width()
.on_click({
let callback = self.sign_in_callback.clone();
@@ -820,9 +820,7 @@ impl ConfigurationView {
.child(
Button::new("reset-api-url", "Reset API URL")
.label_size(LabelSize::Small)
- .icon(IconName::Undo)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::Undo).size(IconSize::Small))
.layer(ElevationIndex::ModalSurface)
.on_click(
cx.listener(|this, _, _window, cx| this.reset_api_url(_window, cx)),
@@ -918,9 +916,11 @@ impl Render for ConfigurationView {
this.child(
Button::new("lmstudio-site", "LM Studio")
.style(ButtonStyle::Subtle)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, _window, cx| {
cx.open_url(LMSTUDIO_SITE)
})
@@ -933,9 +933,11 @@ impl Render for ConfigurationView {
"Download LM Studio",
)
.style(ButtonStyle::Subtle)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, _window, cx| {
cx.open_url(LMSTUDIO_DOWNLOAD_URL)
})
@@ -946,9 +948,11 @@ impl Render for ConfigurationView {
.child(
Button::new("view-models", "Model Catalog")
.style(ButtonStyle::Subtle)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, _window, cx| {
cx.open_url(LMSTUDIO_CATALOG_URL)
}),
@@ -981,9 +985,9 @@ impl Render for ConfigurationView {
} else {
this.child(
Button::new("retry_lmstudio_models", "Connect")
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::XSmall)
- .icon(IconName::PlayFilled)
+ .start_icon(
+ Icon::new(IconName::PlayFilled).size(IconSize::XSmall),
+ )
.on_click(cx.listener(move |this, _, _window, cx| {
this.retry_connection(_window, cx)
})),
@@ -858,9 +858,7 @@ impl ConfigurationView {
.child(
Button::new("reset-context-window", "Reset")
.label_size(LabelSize::Small)
- .icon(IconName::Undo)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::Undo).size(IconSize::Small))
.layer(ElevationIndex::ModalSurface)
.on_click(
cx.listener(|this, _, window, cx| {
@@ -905,9 +903,7 @@ impl ConfigurationView {
.child(
Button::new("reset-api-url", "Reset API URL")
.label_size(LabelSize::Small)
- .icon(IconName::Undo)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::Undo).size(IconSize::Small))
.layer(ElevationIndex::ModalSurface)
.on_click(
cx.listener(|this, _, window, cx| this.reset_api_url(window, cx)),
@@ -949,9 +945,11 @@ impl Render for ConfigurationView {
this.child(
Button::new("ollama-site", "Ollama")
.style(ButtonStyle::Subtle)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
.on_click(move |_, _, cx| cx.open_url(OLLAMA_SITE))
.into_any_element(),
)
@@ -959,9 +957,11 @@ impl Render for ConfigurationView {
this.child(
Button::new("download_ollama_button", "Download Ollama")
.style(ButtonStyle::Subtle)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
.on_click(move |_, _, cx| {
cx.open_url(OLLAMA_DOWNLOAD_URL)
})
@@ -972,9 +972,11 @@ impl Render for ConfigurationView {
.child(
Button::new("view-models", "View All Models")
.style(ButtonStyle::Subtle)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
.on_click(move |_, _, cx| cx.open_url(OLLAMA_LIBRARY_URL)),
),
)
@@ -1005,9 +1007,9 @@ impl Render for ConfigurationView {
} else {
this.child(
Button::new("retry_ollama_models", "Connect")
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::XSmall)
- .icon(IconName::PlayOutlined)
+ .start_icon(
+ Icon::new(IconName::PlayOutlined).size(IconSize::XSmall),
+ )
.on_click(cx.listener(move |this, _, window, cx| {
this.retry_connection(window, cx)
})),
@@ -1415,9 +1415,11 @@ impl Render for ConfigurationView {
)
.child(
Button::new("docs", "Learn More")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, _window, cx| {
cx.open_url("https://zed.dev/docs/ai/llm-providers#openai-api-compatible")
}),
@@ -545,9 +545,7 @@ impl Render for ConfigurationView {
.child(
Button::new("reset-api-key", "Reset API Key")
.label_size(LabelSize::Small)
- .icon(IconName::Undo)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::Undo).size(IconSize::Small))
.layer(ElevationIndex::ModalSurface)
.when(env_var_set, |this| {
this.tooltip(Tooltip::text(format!("To reset your API key, unset the {env_var_name} environment variable.")))
@@ -56,10 +56,8 @@ impl Render for BasedPyrightBanner {
.gap_0p5()
.child(
Button::new("learn-more", "Learn More")
- .icon(IconName::ArrowUpRight)
.label_size(LabelSize::Small)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::XSmall).color(Color::Muted))
.on_click(|_, _, cx| {
cx.open_url("https://zed.dev/docs/languages/python")
}),
@@ -18,7 +18,7 @@ use project::{
};
use proto::toggle_lsp_logs::LogType;
use std::{any::TypeId, borrow::Cow, sync::Arc};
-use ui::{Button, Checkbox, ContextMenu, Label, PopoverMenu, ToggleState, prelude::*};
+use ui::{Checkbox, ContextMenu, PopoverMenu, ToggleState, prelude::*};
use util::ResultExt as _;
use workspace::{
SplitDirection, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, WorkspaceId,
@@ -969,9 +969,11 @@ impl Render for LspLogToolbarItemView {
})
.unwrap_or_else(|| "No server selected".into()),
)
- .icon(IconName::ChevronDown)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted),
+ .end_icon(
+ Icon::new(IconName::ChevronDown)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ ),
)
.menu({
let log_view = log_view.clone();
@@ -1030,10 +1032,11 @@ impl Render for LspLogToolbarItemView {
PopoverMenu::new("LspViewSelector")
.anchor(Corner::TopLeft)
.trigger(
- Button::new("language_server_menu_header", label)
- .icon(IconName::ChevronDown)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted),
+ Button::new("language_server_menu_header", label).end_icon(
+ Icon::new(IconName::ChevronDown)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ ),
)
.menu(move |window, cx| {
let log_toolbar_view = log_toolbar_view.upgrade()?;
@@ -1125,9 +1128,11 @@ impl Render for LspLogToolbarItemView {
"language_server_trace_level_selector",
"Trace level",
)
- .icon(IconName::ChevronDown)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted),
+ .end_icon(
+ Icon::new(IconName::ChevronDown)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ ),
)
.menu({
let log_view = log_view;
@@ -1193,9 +1198,11 @@ impl Render for LspLogToolbarItemView {
"language_server_log_level_selector",
"Log level",
)
- .icon(IconName::ChevronDown)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted),
+ .end_icon(
+ Icon::new(IconName::ChevronDown)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ ),
)
.menu({
let log_view = log_view;
@@ -10,9 +10,8 @@ use theme::{
ThemeSettings,
};
use ui::{
- Divider, ParentElement as _, StatefulInteractiveElement, SwitchField, TintColor,
- ToggleButtonGroup, ToggleButtonGroupSize, ToggleButtonSimple, ToggleButtonWithIcon, Tooltip,
- prelude::*, rems_from_px,
+ Divider, StatefulInteractiveElement, SwitchField, TintColor, ToggleButtonGroup,
+ ToggleButtonGroupSize, ToggleButtonSimple, ToggleButtonWithIcon, Tooltip, prelude::*,
};
use vim_mode_setting::VimModeSetting;
@@ -477,8 +476,7 @@ fn render_setting_import_button(
.toggle_state(imported)
.tab_index(tab_index)
.when(imported, |this| {
- this.icon(IconName::Check)
- .icon_size(IconSize::Small)
+ this.end_icon(Icon::new(IconName::Check).size(IconSize::Small))
.color(Color::Success)
})
.on_click(move |_, window, cx| {
@@ -158,10 +158,11 @@ impl Render for MultibufferHint {
)
.child(
Button::new("open_docs", "Learn More")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::End)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_event, _, cx| {
cx.open_url("https://zed.dev/docs/multibuffers")
}),
@@ -52,7 +52,6 @@ pub fn panel_button(label: impl Into<SharedString>) -> ui::Button {
let id = ElementId::Name(label.to_lowercase().replace(' ', "_").into());
ui::Button::new(id, label)
.label_size(ui::LabelSize::Small)
- .icon_size(ui::IconSize::Small)
// TODO: Change this once we use on_surface_bg in button_like
.layer(ui::ElevationIndex::ModalSurface)
.size(ui::ButtonSize::Compact)
@@ -2,11 +2,7 @@ use gpui::{ClickEvent, DismissEvent, EventEmitter, FocusHandle, Focusable, Rende
use project::project_settings::ProjectSettings;
use remote::RemoteConnectionOptions;
use settings::Settings;
-use ui::{
- Button, ButtonCommon, ButtonStyle, Clickable, Context, ElevationIndex, FluentBuilder, Headline,
- HeadlineSize, IconName, IconPosition, InteractiveElement, IntoElement, Label, Modal,
- ModalFooter, ModalHeader, ParentElement, Section, Styled, StyledExt, Window, div, h_flex, rems,
-};
+use ui::{ElevationIndex, Modal, ModalFooter, ModalHeader, Section, prelude::*};
use workspace::{
ModalView, MultiWorkspace, OpenOptions, Workspace, notifications::DetachAndPromptErr,
};
@@ -207,8 +203,7 @@ impl Render for DisconnectedOverlay {
Button::new("reconnect", "Reconnect")
.style(ButtonStyle::Filled)
.layer(ElevationIndex::ModalSurface)
- .icon(IconName::ArrowCircle)
- .icon_position(IconPosition::Start)
+ .start_icon(Icon::new(IconName::ArrowCircle))
.on_click(cx.listener(Self::handle_reconnect)),
)
}),
@@ -2117,8 +2117,10 @@ impl RemoteServerProjects {
.child(
Button::new("learn-more", "Learn More")
.label_size(LabelSize::Small)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::XSmall)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::XSmall),
+ )
.on_click(|_, _, cx| {
cx.open_url(
"https://zed.dev/docs/remote-development",
@@ -431,10 +431,11 @@ impl PickerDelegate for KernelPickerDelegate {
.gap_4()
.child(
Button::new("kernel-docs", "Kernel Docs")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::End)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(move |_, _, cx| cx.open_url(KERNEL_DOCS_URL)),
)
.into_any(),
@@ -1117,10 +1117,11 @@ impl NotebookEditor {
worktree_id,
Button::new("kernel-selector", kernel_name.clone())
.label_size(LabelSize::Small)
- .icon(status_icon)
- .icon_size(IconSize::Small)
- .icon_color(status_color)
- .icon_position(IconPosition::Start),
+ .start_icon(
+ Icon::new(status_icon)
+ .size(IconSize::Small)
+ .color(status_color),
+ ),
Tooltip::text(format!(
"Kernel: {} ({}). Click to change.",
kernel_name,
@@ -1170,10 +1170,11 @@ impl RulesLibrary {
Button::new("new-rule", "New Rule")
.full_width()
.style(ButtonStyle::Outlined)
- .icon(IconName::Plus)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
- .icon_color(Color::Muted)
+ .start_icon(
+ Icon::new(IconName::Plus)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(|_, window, cx| {
window.dispatch_action(Box::new(NewRule), cx);
}),
@@ -1583,9 +1583,7 @@ impl ProjectSearchView {
)
.child(
Button::new("filter-paths", "Include/exclude specific paths")
- .icon(IconName::Filter)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(Icon::new(IconName::Filter).size(IconSize::Small))
.key_binding(KeyBinding::for_action_in(&ToggleFilters, &focus_handle, cx))
.on_click(|_event, window, cx| {
window.dispatch_action(ToggleFilters.boxed_clone(), cx)
@@ -1593,9 +1591,7 @@ impl ProjectSearchView {
)
.child(
Button::new("find-replace", "Find and replace")
- .icon(IconName::Replace)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(Icon::new(IconName::Replace).size(IconSize::Small))
.key_binding(KeyBinding::for_action_in(&ToggleReplace, &focus_handle, cx))
.on_click(|_event, window, cx| {
window.dispatch_action(ToggleReplace.boxed_clone(), cx)
@@ -1603,9 +1599,7 @@ impl ProjectSearchView {
)
.child(
Button::new("regex", "Match with regex")
- .icon(IconName::Regex)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(Icon::new(IconName::Regex).size(IconSize::Small))
.key_binding(KeyBinding::for_action_in(&ToggleRegex, &focus_handle, cx))
.on_click(|_event, window, cx| {
window.dispatch_action(ToggleRegex.boxed_clone(), cx)
@@ -1613,9 +1607,7 @@ impl ProjectSearchView {
)
.child(
Button::new("match-case", "Match case")
- .icon(IconName::CaseSensitive)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(Icon::new(IconName::CaseSensitive).size(IconSize::Small))
.key_binding(KeyBinding::for_action_in(
&ToggleCaseSensitive,
&focus_handle,
@@ -1627,9 +1619,7 @@ impl ProjectSearchView {
)
.child(
Button::new("match-whole-words", "Match whole words")
- .icon(IconName::WholeWord)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
+ .start_icon(Icon::new(IconName::WholeWord).size(IconSize::Small))
.key_binding(KeyBinding::for_action_in(
&ToggleWholeWord,
&focus_handle,
@@ -275,10 +275,11 @@ fn render_tool_list_item(
.tab_index(tool_index as isize)
.style(ButtonStyle::OutlinedGhost)
.size(ButtonSize::Medium)
- .icon(IconName::ChevronRight)
- .icon_position(IconPosition::End)
- .icon_color(Color::Muted)
- .icon_size(IconSize::Small)
+ .end_icon(
+ Icon::new(IconName::ChevronRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(cx.listener(move |this, _, window, cx| {
this.push_dynamic_sub_page(
tool_name,
@@ -1090,9 +1091,7 @@ fn render_global_default_mode_section(current_mode: ToolPermissionMode) -> AnyEl
.tab_index(0_isize)
.style(ButtonStyle::Outlined)
.size(ButtonSize::Medium)
- .icon(IconName::ChevronDown)
- .icon_position(IconPosition::End)
- .icon_size(IconSize::Small),
+ .end_icon(Icon::new(IconName::ChevronDown).size(IconSize::Small)),
)
.menu(move |window, cx| {
Some(ContextMenu::build(window, cx, move |menu, _, _| {
@@ -1141,9 +1140,7 @@ fn render_default_mode_section(
.tab_index(0_isize)
.style(ButtonStyle::Outlined)
.size(ButtonSize::Medium)
- .icon(IconName::ChevronDown)
- .icon_position(IconPosition::End)
- .icon_size(IconSize::Small),
+ .end_icon(Icon::new(IconName::ChevronDown).size(IconSize::Small)),
)
.menu(move |window, cx| {
let tool_id = tool_id_owned.clone();
@@ -925,9 +925,7 @@ impl SettingsPageItem {
Button::new("error-warning", warning)
.style(ButtonStyle::Outlined)
.size(ButtonSize::Medium)
- .icon(Some(IconName::Debug))
- .icon_position(IconPosition::Start)
- .icon_color(Color::Error)
+ .start_icon(Icon::new(IconName::Debug).color(Color::Error))
.tab_index(0_isize)
.tooltip(Tooltip::text(setting_item.field.type_name()))
.into_any_element(),
@@ -992,11 +990,12 @@ impl SettingsPageItem {
("sub-page".into(), sub_page_link.title.clone()),
"Configure",
)
- .icon(IconName::ChevronRight)
.tab_index(0_isize)
- .icon_position(IconPosition::End)
- .icon_color(Color::Muted)
- .icon_size(IconSize::Small)
+ .end_icon(
+ Icon::new(IconName::ChevronRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.style(ButtonStyle::OutlinedGhost)
.size(ButtonSize::Medium)
.on_click({
@@ -1125,11 +1124,12 @@ impl SettingsPageItem {
("action-link".into(), action_link.title.clone()),
action_link.button_text.clone(),
)
- .icon(IconName::ArrowUpRight)
.tab_index(0_isize)
- .icon_position(IconPosition::End)
- .icon_color(Color::Muted)
- .icon_size(IconSize::Small)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.style(ButtonStyle::OutlinedGhost)
.size(ButtonSize::Medium)
.on_click({
@@ -4174,10 +4174,11 @@ fn render_picker_trigger_button(id: SharedString, label: SharedString) -> Button
.tab_index(0_isize)
.style(ButtonStyle::Outlined)
.size(ButtonSize::Medium)
- .icon(IconName::ChevronUpDown)
- .icon_color(Color::Muted)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::End)
+ .end_icon(
+ Icon::new(IconName::ChevronUpDown)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
}
fn render_font_picker(
@@ -311,10 +311,11 @@ impl PickerDelegate for IconThemeSelectorDelegate {
.border_color(cx.theme().colors().border_variant)
.child(
Button::new("docs", "View Icon Theme Docs")
- .icon(IconName::ArrowUpRight)
- .icon_position(IconPosition::End)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(|_event, _window, cx| {
cx.open_url("https://zed.dev/docs/icon-themes");
}),
@@ -497,10 +497,11 @@ impl PickerDelegate for ThemeSelectorDelegate {
.border_color(cx.theme().colors().border_variant)
.child(
Button::new("docs", "View Theme Docs")
- .icon(IconName::ArrowUpRight)
- .icon_position(IconPosition::End)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.on_click(cx.listener(|_, _, _, cx| {
cx.open_url("https://zed.dev/docs/themes");
})),
@@ -583,10 +583,11 @@ impl TitleBar {
.style(ButtonStyle::Tinted(TintColor::Warning))
.label_size(LabelSize::Small)
.color(Color::Warning)
- .icon(IconName::Warning)
- .icon_color(Color::Warning)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Warning)
+ .size(IconSize::Small)
+ .color(Color::Warning),
+ )
.tooltip(|_, cx| {
Tooltip::with_meta(
"You're in Restricted Mode",
@@ -697,9 +698,11 @@ impl TitleBar {
Button::new("project_name_trigger", display_name)
.label_size(LabelSize::Small)
.when(self.worktree_count(cx) > 1, |this| {
- this.icon(IconName::ChevronDown)
- .icon_color(Color::Muted)
- .icon_size(IconSize::XSmall)
+ this.end_icon(
+ Icon::new(IconName::ChevronDown)
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
})
.selected_style(ButtonStyle::Tinted(TintColor::Accent))
.when(!is_project_selected, |s| s.color(Color::Muted)),
@@ -779,11 +782,9 @@ impl TitleBar {
.color(Color::Muted)
.when(settings.show_branch_icon, |branch_button| {
let (icon, icon_color) = icon_info;
- branch_button
- .icon(icon)
- .icon_position(IconPosition::Start)
- .icon_color(icon_color)
- .icon_size(IconSize::Indicator)
+ branch_button.start_icon(
+ Icon::new(icon).size(IconSize::Indicator).color(icon_color),
+ )
}),
move |_window, cx| {
Tooltip::with_meta(
@@ -133,10 +133,11 @@ impl RenderOnce for ConfiguredApiCard {
elem.tab_index(tab_index)
})
.label_size(LabelSize::Small)
- .icon(IconName::Undo)
- .icon_size(IconSize::Small)
- .icon_color(Color::Muted)
- .icon_position(IconPosition::Start)
+ .start_icon(
+ Icon::new(IconName::Undo)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
.disabled(self.disabled)
.when_some(self.tooltip_label, |this, label| {
this.tooltip(Tooltip::text(label))
@@ -8,16 +8,14 @@ use gpui::{AnyElement, IntoElement, ParentElement, Styled};
///
/// ```
/// use ui::prelude::*;
-/// use ui::{Banner, Button, IconName, IconPosition, IconSize, Label, Severity};
+/// use ui::{Banner, Button, Icon, IconName, IconSize, Label, Severity};
///
/// Banner::new()
/// .severity(Severity::Success)
/// .children([Label::new("This is a success message")])
/// .action_slot(
/// Button::new("learn-more", "Learn More")
-/// .icon(IconName::ArrowUpRight)
-/// .icon_size(IconSize::Small)
-/// .icon_position(IconPosition::End)
+/// .end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
/// );
/// ```
#[derive(IntoElement, RegisterComponent)]
@@ -151,9 +149,7 @@ impl Component for Banner {
.child(Label::new("This is an informational message"))
.action_slot(
Button::new("learn-more", "Learn More")
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::End),
+ .end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
)
.into_any_element(),
),
@@ -1,5 +1,4 @@
mod button;
-mod button_icon;
mod button_like;
mod button_link;
mod copy_button;
@@ -2,15 +2,12 @@ use crate::component_prelude::*;
use gpui::{AnyElement, AnyView, DefiniteLength};
use ui_macros::RegisterComponent;
-use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize, Label};
+use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, Label};
use crate::{
- Color, DynamicSpacing, ElevationIndex, IconPosition, KeyBinding, KeybindingPosition, TintColor,
- prelude::*,
+ Color, DynamicSpacing, ElevationIndex, KeyBinding, KeybindingPosition, TintColor, prelude::*,
};
-use super::button_icon::ButtonIcon;
-
-/// An element that creates a button with a label and an optional icon.
+/// An element that creates a button with a label and optional icons.
///
/// Common buttons:
/// - Label, Icon + Label: [`Button`] (this component)
@@ -42,7 +39,7 @@ use super::button_icon::ButtonIcon;
/// use ui::prelude::*;
///
/// Button::new("button_id", "Click me!")
-/// .icon(IconName::Check)
+/// .start_icon(Icon::new(IconName::Check))
/// .toggle_state(true)
/// .on_click(|event, window, cx| {
/// // Handle click event
@@ -85,12 +82,8 @@ pub struct Button {
label_size: Option<LabelSize>,
selected_label: Option<SharedString>,
selected_label_color: Option<Color>,
- icon: Option<IconName>,
- icon_position: Option<IconPosition>,
- icon_size: Option<IconSize>,
- icon_color: Option<Color>,
- selected_icon: Option<IconName>,
- selected_icon_color: Option<Color>,
+ start_icon: Option<Icon>,
+ end_icon: Option<Icon>,
key_binding: Option<KeyBinding>,
key_binding_position: KeybindingPosition,
alpha: Option<f32>,
@@ -112,12 +105,8 @@ impl Button {
label_size: None,
selected_label: None,
selected_label_color: None,
- icon: None,
- icon_position: None,
- icon_size: None,
- icon_color: None,
- selected_icon: None,
- selected_icon_color: None,
+ start_icon: None,
+ end_icon: None,
key_binding: None,
key_binding_position: KeybindingPosition::default(),
alpha: None,
@@ -149,39 +138,19 @@ impl Button {
self
}
- /// Assigns an icon to the button.
- pub fn icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
- self.icon = icon.into();
- self
- }
-
- /// Sets the position of the icon relative to the label.
- pub fn icon_position(mut self, icon_position: impl Into<Option<IconPosition>>) -> Self {
- self.icon_position = icon_position.into();
- self
- }
-
- /// Specifies the size of the button's icon.
- pub fn icon_size(mut self, icon_size: impl Into<Option<IconSize>>) -> Self {
- self.icon_size = icon_size.into();
- self
- }
-
- /// Sets the color of the button's icon.
- pub fn icon_color(mut self, icon_color: impl Into<Option<Color>>) -> Self {
- self.icon_color = icon_color.into();
- self
- }
-
- /// Chooses an icon to display when the button is in a selected state.
- pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
- self.selected_icon = icon.into();
+ /// Sets an icon to display at the start (left) of the button label.
+ ///
+ /// The icon's color will be overridden to `Color::Disabled` when the button is disabled.
+ pub fn start_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
+ self.start_icon = icon.into();
self
}
- /// Sets the icon color used when the button is in a selected state.
- pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
- self.selected_icon_color = color.into();
+ /// Sets an icon to display at the end (right) of the button label.
+ ///
+ /// The icon's color will be overridden to `Color::Disabled` when the button is disabled.
+ pub fn end_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
+ self.end_icon = icon.into();
self
}
@@ -219,22 +188,24 @@ impl Button {
impl Toggleable for Button {
/// Sets the selected state of the button.
///
- /// This method allows the selection state of the button to be specified.
- /// It modifies the button's appearance to reflect its selected state.
- ///
/// # Examples
///
+ /// Create a toggleable button that changes appearance when selected:
+ ///
/// ```
/// use ui::prelude::*;
+ /// use ui::TintColor;
///
- /// Button::new("button_id", "Click me!")
- /// .toggle_state(true)
+ /// let selected = true;
+ ///
+ /// Button::new("toggle_button", "Toggle Me")
+ /// .start_icon(Icon::new(IconName::Check))
+ /// .toggle_state(selected)
+ /// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
/// .on_click(|event, window, cx| {
- /// // Handle click event
+ /// // Toggle the selected state
/// });
/// ```
- ///
- /// Use [`selected_style`](Button::selected_style) to change the style of the button when it is selected.
fn toggle_state(mut self, selected: bool) -> Self {
self.base = self.base.toggle_state(selected);
self
@@ -242,22 +213,20 @@ impl Toggleable for Button {
}
impl SelectableButton for Button {
- /// Sets the style for the button when selected.
+ /// Sets the style for the button in a selected state.
///
/// # Examples
///
+ /// Customize the selected appearance of a button:
+ ///
/// ```
/// use ui::prelude::*;
/// use ui::TintColor;
///
- /// Button::new("button_id", "Click me!")
+ /// Button::new("styled_button", "Styled Button")
/// .toggle_state(true)
- /// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
- /// .on_click(|event, window, cx| {
- /// // Handle click event
- /// });
+ /// .selected_style(ButtonStyle::Tinted(TintColor::Accent));
/// ```
- /// This results in a button with a blue tinted background when selected.
fn selected_style(mut self, style: ButtonStyle) -> Self {
self.base = self.base.selected_style(style);
self
@@ -265,36 +234,27 @@ impl SelectableButton for Button {
}
impl Disableable for Button {
- /// Disables the button.
+ /// Disables the button, preventing interaction and changing its appearance.
///
- /// This method allows the button to be disabled. When a button is disabled,
- /// it doesn't react to user interactions and its appearance is updated to reflect this.
+ /// When disabled, the button's icon and label will use `Color::Disabled`.
///
/// # Examples
///
+ /// Create a disabled button:
+ ///
/// ```
/// use ui::prelude::*;
///
- /// Button::new("button_id", "Click me!")
- /// .disabled(true)
- /// .on_click(|event, window, cx| {
- /// // Handle click event
- /// });
+ /// Button::new("disabled_button", "Can't Click Me")
+ /// .disabled(true);
/// ```
- ///
- /// This results in a button that is disabled and does not respond to click events.
fn disabled(mut self, disabled: bool) -> Self {
self.base = self.base.disabled(disabled);
- self.key_binding = self
- .key_binding
- .take()
- .map(|binding| binding.disabled(disabled));
self
}
}
impl Clickable for Button {
- /// Sets the click event handler for the button.
fn on_click(
mut self,
handler: impl Fn(&gpui::ClickEvent, &mut Window, &mut App) + 'static,
@@ -310,44 +270,35 @@ impl Clickable for Button {
}
impl FixedWidth for Button {
- /// Sets a fixed width for the button.
- ///
- /// This function allows a button to have a fixed width instead of automatically growing or shrinking.
/// Sets a fixed width for the button.
///
/// # Examples
///
+ /// Create a button with a fixed width of 100 pixels:
+ ///
/// ```
/// use ui::prelude::*;
///
- /// Button::new("button_id", "Click me!")
- /// .width(px(100.))
- /// .on_click(|event, window, cx| {
- /// // Handle click event
- /// });
+ /// Button::new("fixed_width_button", "Fixed Width")
+ /// .width(px(100.0));
/// ```
- ///
- /// This sets the button's width to be exactly 100 pixels.
fn width(mut self, width: impl Into<DefiniteLength>) -> Self {
self.base = self.base.width(width);
self
}
- /// Sets the button to occupy the full width of its container.
+ /// Makes the button take up the full width of its container.
///
/// # Examples
///
+ /// Create a button that takes up the full width of its container:
+ ///
/// ```
/// use ui::prelude::*;
///
- /// Button::new("button_id", "Click me!")
- /// .full_width()
- /// .on_click(|event, window, cx| {
- /// // Handle click event
- /// });
+ /// Button::new("full_width_button", "Full Width")
+ /// .full_width();
/// ```
- ///
- /// This stretches the button to the full width of its container.
fn full_width(mut self) -> Self {
self.base = self.base.full_width();
self
@@ -355,43 +306,34 @@ impl FixedWidth for Button {
}
impl ButtonCommon for Button {
- /// Sets the button's id.
fn id(&self) -> &ElementId {
self.base.id()
}
- /// Sets the visual style of the button using a [`ButtonStyle`].
+ /// Sets the visual style of the button.
fn style(mut self, style: ButtonStyle) -> Self {
self.base = self.base.style(style);
self
}
- /// Sets the button's size using a [`ButtonSize`].
+ /// Sets the size of the button.
fn size(mut self, size: ButtonSize) -> Self {
self.base = self.base.size(size);
self
}
- /// Sets a tooltip for the button.
- ///
- /// This method allows a tooltip to be set for the button. The tooltip is a function that
- /// takes a mutable references to [`Window`] and [`App`], and returns an [`AnyView`]. The
- /// tooltip is displayed when the user hovers over the button.
+ /// Sets a tooltip that appears on hover.
///
/// # Examples
///
- /// ```
- /// use ui::prelude::*;
- /// use ui::Tooltip;
+ /// Add a tooltip to a button:
///
- /// Button::new("button_id", "Click me!")
- /// .tooltip(Tooltip::text("This is a tooltip"))
- /// .on_click(|event, window, cx| {
- /// // Handle click event
- /// });
/// ```
+ /// use ui::{Tooltip, prelude::*};
///
- /// This will create a button with a tooltip that displays "This is a tooltip" when hovered over.
+ /// Button::new("tooltip_button", "Hover Me")
+ /// .tooltip(Tooltip::text("This is a tooltip"));
+ /// ```
fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
self.base = self.base.tooltip(tooltip);
self
@@ -436,16 +378,12 @@ impl RenderOnce for Button {
h_flex()
.when(self.truncate, |this| this.min_w_0().overflow_hidden())
.gap(DynamicSpacing::Base04.rems(cx))
- .when(self.icon_position == Some(IconPosition::Start), |this| {
- this.children(self.icon.map(|icon| {
- ButtonIcon::new(icon)
- .disabled(is_disabled)
- .toggle_state(is_selected)
- .selected_icon(self.selected_icon)
- .selected_icon_color(self.selected_icon_color)
- .size(self.icon_size)
- .color(self.icon_color)
- }))
+ .when_some(self.start_icon, |this, icon| {
+ this.child(if is_disabled {
+ icon.color(Color::Disabled)
+ } else {
+ icon
+ })
})
.child(
h_flex()
@@ -465,16 +403,12 @@ impl RenderOnce for Button {
)
.children(self.key_binding),
)
- .when(self.icon_position != Some(IconPosition::Start), |this| {
- this.children(self.icon.map(|icon| {
- ButtonIcon::new(icon)
- .disabled(is_disabled)
- .toggle_state(is_selected)
- .selected_icon(self.selected_icon)
- .selected_icon_color(self.selected_icon_color)
- .size(self.icon_size)
- .color(self.icon_color)
- }))
+ .when_some(self.end_icon, |this, icon| {
+ this.child(if is_disabled {
+ icon.color(Color::Disabled)
+ } else {
+ icon
+ })
}),
)
}
@@ -585,24 +519,28 @@ impl Component for Button {
"Buttons with Icons",
vec![
single_example(
- "Icon Start",
- Button::new("icon_start", "Icon Start")
- .icon(IconName::Check)
- .icon_position(IconPosition::Start)
+ "Start Icon",
+ Button::new("icon_start", "Start Icon")
+ .start_icon(Icon::new(IconName::Check))
+ .into_any_element(),
+ ),
+ single_example(
+ "End Icon",
+ Button::new("icon_end", "End Icon")
+ .end_icon(Icon::new(IconName::Check))
.into_any_element(),
),
single_example(
- "Icon End",
- Button::new("icon_end", "Icon End")
- .icon(IconName::Check)
- .icon_position(IconPosition::End)
+ "Both Icons",
+ Button::new("both_icons", "Both Icons")
+ .start_icon(Icon::new(IconName::Check))
+ .end_icon(Icon::new(IconName::ChevronDown))
.into_any_element(),
),
single_example(
"Icon Color",
Button::new("icon_color", "Icon Color")
- .icon(IconName::Check)
- .icon_color(Color::Accent)
+ .start_icon(Icon::new(IconName::Check).color(Color::Accent))
.into_any_element(),
),
],
@@ -1,199 +0,0 @@
-use crate::{Icon, IconName, IconSize, IconWithIndicator, Indicator, prelude::*};
-use gpui::Hsla;
-
-/// An icon that appears within a button.
-///
-/// Can be used as either an icon alongside a label, like in [`Button`](crate::Button),
-/// or as a standalone icon, like in [`IconButton`](crate::IconButton).
-#[derive(IntoElement, RegisterComponent)]
-pub(super) struct ButtonIcon {
- icon: IconName,
- size: IconSize,
- color: Color,
- disabled: bool,
- selected: bool,
- selected_icon: Option<IconName>,
- selected_icon_color: Option<Color>,
- selected_style: Option<ButtonStyle>,
- indicator: Option<Indicator>,
- indicator_border_color: Option<Hsla>,
-}
-
-impl ButtonIcon {
- pub fn new(icon: IconName) -> Self {
- Self {
- icon,
- size: IconSize::default(),
- color: Color::default(),
- disabled: false,
- selected: false,
- selected_icon: None,
- selected_icon_color: None,
- selected_style: None,
- indicator: None,
- indicator_border_color: None,
- }
- }
-
- pub fn size(mut self, size: impl Into<Option<IconSize>>) -> Self {
- if let Some(size) = size.into() {
- self.size = size;
- }
- self
- }
-
- pub fn color(mut self, color: impl Into<Option<Color>>) -> Self {
- if let Some(color) = color.into() {
- self.color = color;
- }
- self
- }
-
- pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
- self.selected_icon = icon.into();
- self
- }
-
- pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
- self.selected_icon_color = color.into();
- self
- }
-
- pub fn indicator(mut self, indicator: Indicator) -> Self {
- self.indicator = Some(indicator);
- self
- }
-
- pub fn indicator_border_color(mut self, color: Option<Hsla>) -> Self {
- self.indicator_border_color = color;
- self
- }
-}
-
-impl Disableable for ButtonIcon {
- fn disabled(mut self, disabled: bool) -> Self {
- self.disabled = disabled;
- self
- }
-}
-
-impl Toggleable for ButtonIcon {
- fn toggle_state(mut self, selected: bool) -> Self {
- self.selected = selected;
- self
- }
-}
-
-impl SelectableButton for ButtonIcon {
- fn selected_style(mut self, style: ButtonStyle) -> Self {
- self.selected_style = Some(style);
- self
- }
-}
-
-impl RenderOnce for ButtonIcon {
- fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
- let icon = self
- .selected_icon
- .filter(|_| self.selected)
- .unwrap_or(self.icon);
-
- let icon_color = if self.disabled {
- Color::Disabled
- } else if self.selected_style.is_some() && self.selected {
- self.selected_style.unwrap().into()
- } else if self.selected {
- self.selected_icon_color.unwrap_or(Color::Selected)
- } else {
- self.color
- };
-
- let icon = Icon::new(icon).size(self.size).color(icon_color);
-
- match self.indicator {
- Some(indicator) => IconWithIndicator::new(icon, Some(indicator))
- .indicator_border_color(self.indicator_border_color)
- .into_any_element(),
- None => icon.into_any_element(),
- }
- }
-}
-
-impl Component for ButtonIcon {
- fn scope() -> ComponentScope {
- ComponentScope::Input
- }
-
- fn name() -> &'static str {
- "ButtonIcon"
- }
-
- fn description() -> Option<&'static str> {
- Some("An icon component specifically designed for use within buttons.")
- }
-
- fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
- Some(
- v_flex()
- .gap_6()
- .children(vec![
- example_group_with_title(
- "Basic Usage",
- vec![
- single_example(
- "Default",
- ButtonIcon::new(IconName::Star).into_any_element(),
- ),
- single_example(
- "Custom Size",
- ButtonIcon::new(IconName::Star)
- .size(IconSize::Medium)
- .into_any_element(),
- ),
- single_example(
- "Custom Color",
- ButtonIcon::new(IconName::Star)
- .color(Color::Accent)
- .into_any_element(),
- ),
- ],
- ),
- example_group_with_title(
- "States",
- vec![
- single_example(
- "Selected",
- ButtonIcon::new(IconName::Star)
- .toggle_state(true)
- .into_any_element(),
- ),
- single_example(
- "Disabled",
- ButtonIcon::new(IconName::Star)
- .disabled(true)
- .into_any_element(),
- ),
- ],
- ),
- example_group_with_title(
- "With Indicator",
- vec![
- single_example(
- "Default Indicator",
- ButtonIcon::new(IconName::Star)
- .indicator(Indicator::dot())
- .into_any_element(),
- ),
- single_example(
- "Custom Indicator",
- ButtonIcon::new(IconName::Star)
- .indicator(Indicator::dot().color(Color::Error))
- .into_any_element(),
- ),
- ],
- ),
- ])
- .into_any_element(),
- )
- }
-}
@@ -1,11 +1,11 @@
use gpui::{AnyView, DefiniteLength, Hsla};
use super::button_like::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle};
-use crate::{ElevationIndex, Indicator, SelectableButton, TintColor, prelude::*};
+use crate::{
+ ElevationIndex, Icon, IconWithIndicator, Indicator, SelectableButton, TintColor, prelude::*,
+};
use crate::{IconName, IconSize};
-use super::button_icon::ButtonIcon;
-
/// The shape of an [`IconButton`].
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub enum IconButtonShape {
@@ -22,6 +22,7 @@ pub struct IconButton {
icon_color: Color,
selected_icon: Option<IconName>,
selected_icon_color: Option<Color>,
+ selected_style: Option<ButtonStyle>,
indicator: Option<Indicator>,
indicator_border_color: Option<Hsla>,
alpha: Option<f32>,
@@ -37,6 +38,7 @@ impl IconButton {
icon_color: Color::Default,
selected_icon: None,
selected_icon_color: None,
+ selected_style: None,
indicator: None,
indicator_border_color: None,
alpha: None,
@@ -112,6 +114,7 @@ impl Toggleable for IconButton {
impl SelectableButton for IconButton {
fn selected_style(mut self, style: ButtonStyle) -> Self {
+ self.selected_style = Some(style);
self.base = self.base.selected_style(style);
self
}
@@ -192,9 +195,25 @@ impl RenderOnce for IconButton {
fn render(self, window: &mut Window, cx: &mut App) -> ButtonLike {
let is_disabled = self.base.disabled;
let is_selected = self.base.selected;
- let selected_style = self.base.selected_style;
- let color = self.icon_color.color(cx).opacity(self.alpha.unwrap_or(1.0));
+ let icon = self
+ .selected_icon
+ .filter(|_| is_selected)
+ .unwrap_or(self.icon);
+
+ let icon_color = if is_disabled {
+ Color::Disabled
+ } else if self.selected_style.is_some() && is_selected {
+ self.selected_style.unwrap().into()
+ } else if is_selected {
+ self.selected_icon_color.unwrap_or(Color::Selected)
+ } else {
+ let base_color = self.icon_color.color(cx);
+ Color::Custom(base_color.opacity(self.alpha.unwrap_or(1.0)))
+ };
+
+ let icon_element = Icon::new(icon).size(self.icon_size).color(icon_color);
+
self.base
.map(|this| match self.shape {
IconButtonShape::Square => {
@@ -203,20 +222,12 @@ impl RenderOnce for IconButton {
}
IconButtonShape::Wide => this,
})
- .child(
- ButtonIcon::new(self.icon)
- .disabled(is_disabled)
- .toggle_state(is_selected)
- .selected_icon(self.selected_icon)
- .selected_icon_color(self.selected_icon_color)
- .when_some(selected_style, |this, style| this.selected_style(style))
- .when_some(self.indicator, |this, indicator| {
- this.indicator(indicator)
- .indicator_border_color(self.indicator_border_color)
- })
- .size(self.icon_size)
- .color(Color::Custom(color)),
- )
+ .child(match self.indicator {
+ Some(indicator) => IconWithIndicator::new(icon_element, Some(indicator))
+ .indicator_border_color(self.indicator_border_color)
+ .into_any_element(),
+ None => icon_element.into_any_element(),
+ })
}
}
@@ -163,11 +163,10 @@ impl RenderOnce for DropdownMenu {
Some(
Button::new(self.id.clone(), text)
.style(button_style)
- .when(self.chevron, |this| {
- this.icon(self.trigger_icon)
- .icon_position(IconPosition::End)
- .icon_size(IconSize::XSmall)
- .icon_color(Color::Muted)
+ .when_some(self.trigger_icon.filter(|_| self.chevron), |this, icon| {
+ this.end_icon(
+ Icon::new(icon).size(IconSize::XSmall).color(Color::Muted),
+ )
})
.when(full_width, |this| this.full_width())
.size(trigger_size)
@@ -917,11 +917,11 @@ pub mod simple_message_notification {
}));
if let Some(icon) = self.primary_icon {
- button = button
- .icon(icon)
- .icon_color(self.primary_icon_color.unwrap_or(Color::Muted))
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small);
+ button = button.start_icon(
+ Icon::new(icon)
+ .size(IconSize::Small)
+ .color(self.primary_icon_color.unwrap_or(Color::Muted)),
+ );
}
button
@@ -937,11 +937,11 @@ pub mod simple_message_notification {
}));
if let Some(icon) = self.secondary_icon {
- button = button
- .icon(icon)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Small)
- .icon_color(self.secondary_icon_color.unwrap_or(Color::Muted));
+ button = button.start_icon(
+ Icon::new(icon)
+ .size(IconSize::Small)
+ .color(self.secondary_icon_color.unwrap_or(Color::Muted)),
+ );
}
button
@@ -955,9 +955,11 @@ pub mod simple_message_notification {
let url = url.clone();
Button::new(message.clone(), message.clone())
.label_size(LabelSize::Small)
- .icon(IconName::ArrowUpRight)
- .icon_size(IconSize::Indicator)
- .icon_color(Color::Muted)
+ .end_icon(
+ Icon::new(IconName::ArrowUpRight)
+ .size(IconSize::Indicator)
+ .color(Color::Muted),
+ )
.on_click(cx.listener(move |_, _, _, cx| {
cx.open_url(&url);
}))