debugger: Refine session modal design (#33004)

Danilo Leal created

This PR makes all footer elements in the debugger session modal more
consistent, as well as fixes some weird UI quirks with leaking borders
and whatnot. Took the opportunity to do some light style clean up and
use `prelude::*` for UI imports.

Release Notes:

- N/A

Change summary

crates/debugger_ui/src/new_process_modal.rs | 232 +++++++++++-----------
crates/tasks_ui/src/modal.rs                |  24 -
2 files changed, 121 insertions(+), 135 deletions(-)

Detailed changes

crates/debugger_ui/src/new_process_modal.rs 🔗

@@ -28,12 +28,10 @@ use settings::{Settings, initial_local_debug_tasks_content};
 use task::{DebugScenario, RevealTarget, 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, StyledTypography, ToggleButton, ToggleState, Toggleable,
-    Tooltip, Window, div, h_flex, px, relative, rems, v_flex,
+    ActiveTheme, CheckboxWithLabel, Clickable, Context, ContextMenu, Disableable, DropdownMenu,
+    FluentBuilder, IconWithIndicator, Indicator, IntoElement, KeyBinding, ListItem,
+    ListItemSpacing, ParentElement, StyledExt, ToggleButton, ToggleState, Toggleable, Tooltip,
+    Window, div, prelude::*, px, relative, rems,
 };
 use util::ResultExt;
 use workspace::{ModalView, Workspace, pane};
@@ -683,16 +681,16 @@ impl Render for NewProcessModal {
         cx: &mut ui::Context<Self>,
     ) -> impl ui::IntoElement {
         v_flex()
-            .size_full()
-            .w(rems(34.))
             .key_context({
                 let mut key_context = KeyContext::new_with_defaults();
                 key_context.add("Pane");
                 key_context.add("RunModal");
                 key_context
             })
+            .size_full()
+            .w(rems(34.))
             .elevation_3(cx)
-            .bg(cx.theme().colors().elevated_surface_background)
+            .overflow_hidden()
             .on_action(cx.listener(|_, _: &menu::Cancel, _, cx| {
                 cx.emit(DismissEvent);
             }))
@@ -720,100 +718,93 @@ impl Render for NewProcessModal {
             )
             .child(
                 h_flex()
-                    .w_full()
-                    .justify_around()
                     .p_2()
+                    .w_full()
+                    .border_b_1()
+                    .border_color(cx.theme().colors().border_variant)
                     .child(
-                        h_flex()
-                            .justify_start()
-                            .w_full()
-                            .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;
-
-                                    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(),
-                                )
-                                .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(),
-                            ),
+                        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(),
                     )
-                    .justify_between()
-                    .border_color(cx.theme().colors().border_variant)
-                    .border_b_1(),
+                    .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;
+
+                            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(),
+                        )
+                        .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(),
+                    ),
             )
             .child(v_flex().child(self.render_mode(window, cx)))
             .map(|el| {
                 let container = h_flex()
-                    .justify_between()
+                    .w_full()
+                    .p_1p5()
                     .gap_2()
-                    .p_2()
-                    .border_color(cx.theme().colors().border_variant)
+                    .justify_between()
                     .border_t_1()
-                    .w_full();
+                    .border_color(cx.theme().colors().border_variant);
                 match self.mode {
                     NewProcessMode::Launch => el.child(
                         container
@@ -825,7 +816,7 @@ impl Render for NewProcessModal {
                                         InteractiveText::new(
                                             "open-debug-json",
                                             StyledText::new(
-                                                "Open .zed/debug.json for advanced configuration",
+                                                "Open .zed/debug.json for advanced configuration.",
                                             )
                                             .with_highlights([(
                                                 5..20,
@@ -1003,35 +994,43 @@ impl ConfigureMode {
         v_flex()
             .p_2()
             .w_full()
-            .gap_3()
+            .gap_2()
             .track_focus(&self.program.focus_handle(cx))
             .child(
                 h_flex()
+                    .gap_2()
                     .child(
                         Label::new("Debugger")
-                            .size(ui::LabelSize::Small)
+                            .size(LabelSize::Small)
                             .color(Color::Muted),
                     )
-                    .gap(ui::DynamicSpacing::Base08.rems(cx))
                     .child(adapter_menu),
             )
             .child(
-                Label::new("Program")
-                    .size(ui::LabelSize::Small)
-                    .color(Color::Muted),
+                v_flex()
+                    .gap_0p5()
+                    .child(
+                        Label::new("Program")
+                            .size(LabelSize::Small)
+                            .color(Color::Muted),
+                    )
+                    .child(render_editor(&self.program, window, cx)),
             )
-            .child(render_editor(&self.program, window, cx))
             .child(
-                Label::new("Working Directory")
-                    .size(ui::LabelSize::Small)
-                    .color(Color::Muted),
+                v_flex()
+                    .gap_0p5()
+                    .child(
+                        Label::new("Working Directory")
+                            .size(LabelSize::Small)
+                            .color(Color::Muted),
+                    )
+                    .child(render_editor(&self.cwd, window, cx)),
             )
-            .child(render_editor(&self.cwd, window, cx))
             .child(
                 CheckboxWithLabel::new(
                     "debugger-stop-on-entry",
                     Label::new("Stop on Entry")
-                        .size(ui::LabelSize::Small)
+                        .size(LabelSize::Small)
                         .color(Color::Muted),
                     self.stop_on_entry,
                     {
@@ -1050,7 +1049,7 @@ impl ConfigureMode {
                 CheckboxWithLabel::new(
                     "debugger-save-to-debug-json",
                     Label::new("Save to debug.json")
-                        .size(ui::LabelSize::Small)
+                        .size(LabelSize::Small)
                         .color(Color::Muted),
                     self.save_to_debug_json,
                     {
@@ -1471,17 +1470,14 @@ impl PickerDelegate for DebugDelegate {
         let current_modifiers = window.modifiers();
         let footer = h_flex()
             .w_full()
-            .h_8()
-            .p_2()
-            .justify_between()
-            .rounded_b_sm()
-            .bg(cx.theme().colors().ghost_element_selected)
+            .p_1p5()
+            .justify_end()
             .border_t_1()
             .border_color(cx.theme().colors().border_variant)
-            .child(
-                // TODO: add button to open selected task in debug.json
-                h_flex().into_any_element(),
-            )
+            // .child(
+            //     // TODO: add button to open selected task in debug.json
+            //     h_flex().into_any_element(),
+            // )
             .map(|this| {
                 if (current_modifiers.alt || self.matches.is_empty()) && !self.prompt.is_empty() {
                     let action = picker::ConfirmInput {
@@ -1490,7 +1486,6 @@ impl PickerDelegate for DebugDelegate {
                     .boxed_clone();
                     this.children(KeyBinding::for_action(&*action, window, cx).map(|keybind| {
                         Button::new("launch-custom", "Launch Custom")
-                            .label_size(LabelSize::Small)
                             .key_binding(keybind)
                             .on_click(move |_, window, cx| {
                                 window.dispatch_action(action.boxed_clone(), cx)
@@ -1505,7 +1500,6 @@ impl PickerDelegate for DebugDelegate {
                                 if is_recent_selected { "Rerun" } else { "Spawn" };
 
                             Button::new("spawn", run_entry_label)
-                                .label_size(LabelSize::Small)
                                 .key_binding(keybind)
                                 .on_click(|_, window, cx| {
                                     window.dispatch_action(menu::Confirm.boxed_clone(), cx);

crates/tasks_ui/src/modal.rs 🔗

@@ -13,10 +13,9 @@ use picker::{Picker, PickerDelegate, highlighted_match_with_paths::HighlightedMa
 use project::{TaskSourceKind, task_store::TaskStore};
 use task::{DebugScenario, ResolvedTask, RevealTarget, TaskContext, TaskTemplate};
 use ui::{
-    ActiveTheme, Button, ButtonCommon, ButtonSize, Clickable, Color, FluentBuilder as _, Icon,
-    IconButton, IconButtonShape, IconName, IconSize, IconWithIndicator, Indicator, IntoElement,
-    KeyBinding, Label, LabelSize, ListItem, ListItemSpacing, RenderOnce, Toggleable, Tooltip, div,
-    h_flex, v_flex,
+    ActiveTheme, Clickable, FluentBuilder as _, IconButtonShape, IconWithIndicator, Indicator,
+    IntoElement, KeyBinding, ListItem, ListItemSpacing, RenderOnce, Toggleable, Tooltip, div,
+    prelude::*,
 };
 
 use util::{ResultExt, truncate_and_trailoff};
@@ -644,11 +643,8 @@ impl PickerDelegate for TasksModalDelegate {
         Some(
             h_flex()
                 .w_full()
-                .h_8()
-                .p_2()
+                .p_1p5()
                 .justify_between()
-                .rounded_b_sm()
-                .bg(cx.theme().colors().ghost_element_selected)
                 .border_t_1()
                 .border_color(cx.theme().colors().border_variant)
                 .child(
@@ -657,7 +653,6 @@ impl PickerDelegate for TasksModalDelegate {
                             let keybind = KeyBinding::for_action(&*action, window, cx);
 
                             Button::new("edit-current-task", label)
-                                .label_size(LabelSize::Small)
                                 .when_some(keybind, |this, keybind| this.key_binding(keybind))
                                 .on_click(move |_, window, cx| {
                                     window.dispatch_action(action.boxed_clone(), cx);
@@ -681,7 +676,6 @@ impl PickerDelegate for TasksModalDelegate {
                             };
 
                             Button::new("spawn-onehshot", spawn_oneshot_label)
-                                .label_size(LabelSize::Small)
                                 .key_binding(keybind)
                                 .on_click(move |_, window, cx| {
                                     window.dispatch_action(action.boxed_clone(), cx)
@@ -696,15 +690,14 @@ impl PickerDelegate for TasksModalDelegate {
                                     } else {
                                         "Spawn Without History"
                                     };
-                                    Button::new("spawn", label)
-                                        .label_size(LabelSize::Small)
-                                        .key_binding(keybind)
-                                        .on_click(move |_, window, cx| {
+                                    Button::new("spawn", label).key_binding(keybind).on_click(
+                                        move |_, window, cx| {
                                             window.dispatch_action(
                                                 menu::SecondaryConfirm.boxed_clone(),
                                                 cx,
                                             )
-                                        })
+                                        },
+                                    )
                                 },
                             ),
                         )
@@ -715,7 +708,6 @@ impl PickerDelegate for TasksModalDelegate {
                                     if is_recent_selected { "Rerun" } else { "Spawn" };
 
                                 Button::new("spawn", run_entry_label)
-                                    .label_size(LabelSize::Small)
                                     .key_binding(keybind)
                                     .on_click(|_, window, cx| {
                                         window.dispatch_action(menu::Confirm.boxed_clone(), cx);