diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 175aa8c142..78e26f7ca7 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -503,8 +503,7 @@ impl GitPanel { let new_selected_entry = if selected_entry > 0 { selected_entry - 1 } else { - self.selected_entry = Some(item_count - 1); - item_count - 1 + selected_entry }; self.selected_entry = Some(new_selected_entry); @@ -550,7 +549,7 @@ impl GitPanel { cx.notify(); } - fn select_first_entry(&mut self, cx: &mut ViewContext) { + fn select_first_entry_if_none(&mut self, cx: &mut ViewContext) { if !self.no_entries() && self.selected_entry.is_none() { self.selected_entry = Some(0); self.scroll_to_selected_entry(cx); @@ -559,7 +558,7 @@ impl GitPanel { } fn focus_changes_list(&mut self, _: &FocusChanges, cx: &mut ViewContext) { - self.select_first_entry(cx); + self.select_first_entry_if_none(cx); cx.focus_self(); cx.notify(); @@ -776,6 +775,9 @@ impl GitPanel { // Sort entries by path to maintain consistent order self.visible_entries .sort_by(|a, b| a.repo_path.cmp(&b.repo_path)); + + self.select_first_entry_if_none(cx); + cx.notify(); } @@ -830,41 +832,64 @@ impl GitPanel { n => format!("{} changes", n), }; + // for our use case treat None as false + let all_staged = self.all_staged.unwrap_or(false); + h_flex() .h(px(32.)) .items_center() - .px_3() + .px_2() .bg(ElevationIndex::Surface.bg(cx)) .child( h_flex() .gap_2() - .child(Checkbox::new( - "all-changes", - self.all_staged - .map_or(ToggleState::Indeterminate, ToggleState::from), - )) + .child( + Checkbox::new( + "all-changes", + if self.no_entries() { + ToggleState::Selected + } else { + self.all_staged + .map_or(ToggleState::Indeterminate, ToggleState::from) + }, + ) + .fill() + .elevation(ElevationIndex::Surface) + .tooltip(move |cx| { + if all_staged { + Tooltip::text("Unstage all changes", cx) + } else { + Tooltip::text("Stage all changes", cx) + } + }) + .on_click(cx.listener(move |git_panel, _, cx| match all_staged { + true => git_panel.unstage_all(&UnstageAll, cx), + false => git_panel.stage_all(&StageAll, cx), + })), + ) .child(div().text_buffer(cx).text_ui_sm(cx).child(changes_string)), ) .child(div().flex_grow()) .child( h_flex() .gap_2() - .child( - IconButton::new("discard-changes", IconName::Undo) - .tooltip({ - let focus_handle = focus_handle.clone(); - move |cx| { - Tooltip::for_action_in( - "Discard all changes", - &RevertAll, - &focus_handle, - cx, - ) - } - }) - .icon_size(IconSize::Small) - .disabled(true), - ) + // TODO: Re-add once revert all is added + // .child( + // IconButton::new("discard-changes", IconName::Undo) + // .tooltip({ + // let focus_handle = focus_handle.clone(); + // move |cx| { + // Tooltip::for_action_in( + // "Discard all changes", + // &RevertAll, + // &focus_handle, + // cx, + // ) + // } + // }) + // .icon_size(IconSize::Small) + // .disabled(true), + // ) .child(if self.all_staged.unwrap_or(false) { self.panel_button("unstage-all", "Unstage All") .tooltip({ @@ -878,6 +903,11 @@ impl GitPanel { ) } }) + .key_binding(ui::KeyBinding::for_action_in( + &UnstageAll, + &focus_handle, + cx, + )) .on_click( cx.listener(move |this, _, cx| this.unstage_all(&UnstageAll, cx)), ) @@ -894,6 +924,11 @@ impl GitPanel { ) } }) + .key_binding(ui::KeyBinding::for_action_in( + &StageAll, + &focus_handle, + cx, + )) .on_click(cx.listener(move |this, _, cx| this.stage_all(&StageAll, cx))) }), ) @@ -1119,9 +1154,9 @@ impl GitPanel { }); if view_mode == GitViewMode::Tree { - entry = entry.pl(px(12. + 12. * entry_details.depth as f32)) + entry = entry.pl(px(8. + 12. * entry_details.depth as f32)) } else { - entry = entry.pl(px(12.)) + entry = entry.pl(px(8.)) } if selected { diff --git a/crates/ui/src/components/toggle.rs b/crates/ui/src/components/toggle.rs index 45d0cb5bf7..73e363ff33 100644 --- a/crates/ui/src/components/toggle.rs +++ b/crates/ui/src/components/toggle.rs @@ -1,4 +1,4 @@ -use gpui::{div, hsla, prelude::*, ElementId, Hsla, IntoElement, Styled, WindowContext}; +use gpui::{div, hsla, prelude::*, AnyView, ElementId, Hsla, IntoElement, Styled, WindowContext}; use std::sync::Arc; use crate::utils::is_light; @@ -44,6 +44,7 @@ pub struct Checkbox { on_click: Option>, filled: bool, style: ToggleStyle, + tooltip: Option AnyView>>, } impl Checkbox { @@ -56,6 +57,7 @@ impl Checkbox { on_click: None, filled: false, style: ToggleStyle::default(), + tooltip: None, } } @@ -91,6 +93,12 @@ impl Checkbox { self.style = ToggleStyle::ElevationBased(elevation); self } + + /// Sets the tooltip for the checkbox. + pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self { + self.tooltip = Some(Box::new(tooltip)); + self + } } impl Checkbox { @@ -176,6 +184,9 @@ impl RenderOnce for Checkbox { this.on_click(move |_, cx| on_click(&self.toggle_state.inverse(), cx)) }, ) + .when_some(self.tooltip, |this, tooltip| { + this.tooltip(move |cx| tooltip(cx)) + }) } }