use gpui::prelude::*;
use gpui::*;
actions!(ccf_focus, [FocusNext, FocusPrev]);
pub fn register_keybindings(cx: &mut App) {
cx.bind_keys([
KeyBinding::new("tab", FocusNext, None),
KeyBinding::new("shift-tab", FocusPrev, None),
]);
}
pub fn handle_tab_navigation(event: &KeyDownEvent, window: &mut Window) -> bool {
if event.keystroke.key == "tab" {
if event.keystroke.modifiers.shift {
window.focus_prev();
} else {
window.focus_next();
}
true
} else {
false
}
}
pub fn with_focus_actions<V: 'static, E: InteractiveElement>(element: E, cx: &mut Context<V>) -> E {
element
.on_action(cx.listener(|_this, _: &FocusNext, window, _cx| {
window.focus_next();
}))
.on_action(cx.listener(|_this, _: &FocusPrev, window, _cx| {
window.focus_prev();
}))
}
pub trait EnabledCursorExt: Styled + Sized + FluentBuilder {
fn cursor_for_enabled(self, enabled: bool) -> Self {
self.when(enabled, |d| d.cursor_pointer())
.when(!enabled, |d| d.cursor_default())
}
}
impl<E: Styled + Sized + FluentBuilder> EnabledCursorExt for E {}
use crate::theme::Theme;
use super::repeatable_text_input::ActivateButton as RepeatableActivateButton;
#[allow(clippy::too_many_arguments)] pub fn repeatable_remove_button<V: 'static>(
id: impl Into<SharedString>,
focus_handle: &FocusHandle,
theme: &Theme,
enabled: bool,
is_focused: bool,
on_action_activate: impl Fn(&mut V, &mut Window, &mut Context<V>) + 'static,
on_click_activate: impl Fn(&mut V, &mut Window, &mut Context<V>) + 'static,
cx: &mut Context<V>,
) -> Stateful<Div> {
let line_color = if enabled { theme.text_label } else { theme.disabled_text };
let mut button = with_focus_actions(
div()
.id(id.into())
.key_context("CcfRepeatableButton")
.track_focus(focus_handle)
.tab_stop(enabled),
cx,
)
.flex()
.items_center()
.justify_center()
.h(px(28.))
.w(px(28.))
.rounded_md()
.border_2()
.cursor_for_enabled(enabled)
.when(enabled, |d| {
d.bg(rgb(theme.delete_bg))
.hover(|d| d.bg(rgb(theme.delete_bg_hover)))
.border_color(if is_focused { rgb(theme.border_focus) } else { rgba(0x00000000) })
})
.when(!enabled, |d| {
d.bg(rgb(theme.disabled_bg))
.border_color(rgba(0x00000000))
})
.child(
div()
.w(px(10.))
.h(px(2.))
.rounded_sm()
.bg(rgb(line_color))
);
if enabled {
button = button
.on_action(cx.listener(move |this, _: &RepeatableActivateButton, window, cx| {
on_action_activate(this, window, cx);
}))
.on_click(cx.listener(move |this, _event, window, cx| {
on_click_activate(this, window, cx);
}));
}
button
}
#[allow(clippy::too_many_arguments)] pub fn repeatable_add_button<V: 'static>(
id: impl Into<SharedString>,
focus_handle: &FocusHandle,
theme: &Theme,
enabled: bool,
is_focused: bool,
on_action_activate: impl Fn(&mut V, &mut Window, &mut Context<V>) + 'static,
on_click_activate: impl Fn(&mut V, &mut Window, &mut Context<V>) + 'static,
cx: &mut Context<V>,
) -> Stateful<Div> {
let line_color = if enabled { theme.text_label } else { theme.disabled_text };
let mut button = with_focus_actions(
div()
.id(id.into())
.key_context("CcfRepeatableButton")
.track_focus(focus_handle)
.tab_stop(enabled),
cx,
)
.flex()
.items_center()
.justify_center()
.h(px(28.))
.w(px(28.))
.rounded_md()
.border_2()
.cursor_for_enabled(enabled)
.when(enabled, |d| {
d.bg(rgb(theme.bg_input_hover))
.hover(|d| d.bg(rgb(theme.bg_hover)))
.border_color(if is_focused { rgb(theme.border_focus) } else { rgba(0x00000000) })
})
.when(!enabled, |d| {
d.bg(rgb(theme.disabled_bg))
.border_color(rgba(0x00000000))
})
.child(
div()
.relative()
.w(px(10.))
.h(px(10.))
.child(
div()
.absolute()
.top(px(4.))
.left(px(0.))
.w(px(10.))
.h(px(2.))
.rounded_sm()
.bg(rgb(line_color))
)
.child(
div()
.absolute()
.top(px(0.))
.left(px(4.))
.w(px(2.))
.h(px(10.))
.rounded_sm()
.bg(rgb(line_color))
)
);
if enabled {
button = button
.on_action(cx.listener(move |this, _: &RepeatableActivateButton, window, cx| {
on_action_activate(this, window, cx);
}))
.on_click(cx.listener(move |this, _event, window, cx| {
on_click_activate(this, window, cx);
}));
}
button
}