list: Add secondary confirm support to list. (#769)
This commit is contained in:
parent
c91dce3139
commit
a60acd7e4d
18 changed files with 187 additions and 134 deletions
|
|
@ -249,7 +249,7 @@ impl InputStory {
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
InputEvent::Change(text) => println!("Change: {}", text),
|
InputEvent::Change(text) => println!("Change: {}", text),
|
||||||
InputEvent::PressEnter => println!("PressEnter"),
|
InputEvent::PressEnter { secondary } => println!("PressEnter secondary: {}", secondary),
|
||||||
InputEvent::Focus => println!("Focus"),
|
InputEvent::Focus => println!("Focus"),
|
||||||
InputEvent::Blur => println!("Blur"),
|
InputEvent::Blur => println!("Blur"),
|
||||||
};
|
};
|
||||||
|
|
@ -270,7 +270,9 @@ impl InputStory {
|
||||||
}
|
}
|
||||||
println!("Change: {}", text);
|
println!("Change: {}", text);
|
||||||
}
|
}
|
||||||
InputEvent::PressEnter => println!("PressEnter"),
|
InputEvent::PressEnter { secondary } => {
|
||||||
|
println!("PressEnter secondary: {}", secondary)
|
||||||
|
}
|
||||||
InputEvent::Focus => println!("Focus"),
|
InputEvent::Focus => println!("Focus"),
|
||||||
InputEvent::Blur => println!("Blur"),
|
InputEvent::Blur => println!("Blur"),
|
||||||
},
|
},
|
||||||
|
|
@ -306,7 +308,9 @@ impl InputStory {
|
||||||
}
|
}
|
||||||
println!("Change: {}", text);
|
println!("Change: {}", text);
|
||||||
}
|
}
|
||||||
InputEvent::PressEnter => println!("PressEnter"),
|
InputEvent::PressEnter { secondary } => {
|
||||||
|
println!("PressEnter secondary: {}", secondary);
|
||||||
|
}
|
||||||
InputEvent::Focus => println!("Focus"),
|
InputEvent::Focus => println!("Focus"),
|
||||||
InputEvent::Blur => println!("Blur"),
|
InputEvent::Blur => println!("Blur"),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -174,8 +174,8 @@ impl ListDelegate for CompanyListDelegate {
|
||||||
Task::ready(())
|
Task::ready(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm(&mut self, ix: usize, window: &mut Window, cx: &mut Context<List<Self>>) {
|
fn confirm(&mut self, secondary: bool, window: &mut Window, cx: &mut Context<List<Self>>) {
|
||||||
self.confirmed_index = Some(ix);
|
println!("Confirmed with secondary: {}", secondary);
|
||||||
window.dispatch_action(Box::new(SelectedCompany), cx);
|
window.dispatch_action(Box::new(SelectedCompany), cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -368,7 +368,6 @@ impl StoryWorkspace {
|
||||||
Arc::new(StoryContainer::panel::<AccordionStory>(window, cx)),
|
Arc::new(StoryContainer::panel::<AccordionStory>(window, cx)),
|
||||||
Arc::new(StoryContainer::panel::<SidebarStory>(window, cx)),
|
Arc::new(StoryContainer::panel::<SidebarStory>(window, cx)),
|
||||||
Arc::new(StoryContainer::panel::<FormStory>(window, cx)),
|
Arc::new(StoryContainer::panel::<FormStory>(window, cx)),
|
||||||
Arc::new(StoryContainer::panel::<WebViewStory>(window, cx)),
|
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
&dock_area,
|
&dock_area,
|
||||||
|
|
|
||||||
|
|
@ -128,11 +128,13 @@ impl ListDelegate for ListItemDeletegate {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm(&mut self, ix: usize, window: &mut Window, cx: &mut Context<List<Self>>) {
|
fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context<List<Self>>) {
|
||||||
_ = self.story.update(cx, |this, cx| {
|
_ = self.story.update(cx, |this, cx| {
|
||||||
self.confirmed_index = Some(ix);
|
self.confirmed_index = self.selected_index;
|
||||||
if let Some(item) = self.matches.get(ix) {
|
if let Some(ix) = self.confirmed_index {
|
||||||
this.selected_value = Some(SharedString::from(item.to_string()));
|
if let Some(item) = self.matches.get(ix) {
|
||||||
|
this.selected_value = Some(SharedString::from(item.to_string()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.close_drawer(cx);
|
window.close_drawer(cx);
|
||||||
|
|
|
||||||
|
|
@ -660,7 +660,7 @@ impl TableStory {
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
// Update when the user presses Enter or the input loses focus
|
// Update when the user presses Enter or the input loses focus
|
||||||
InputEvent::PressEnter | InputEvent::Blur => {
|
InputEvent::PressEnter { .. } | InputEvent::Blur => {
|
||||||
let text = self.num_stocks_input.read(cx).text().to_string();
|
let text = self.num_stocks_input.read(cx).text().to_string();
|
||||||
if let Ok(num) = text.parse::<usize>() {
|
if let Ok(num) = text.parse::<usize>() {
|
||||||
self.table.update(cx, |table, _| {
|
self.table.update(cx, |table, _| {
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ impl WebViewStory {
|
||||||
cx.subscribe(
|
cx.subscribe(
|
||||||
&address_input,
|
&address_input,
|
||||||
|this: &mut Self, input, event: &InputEvent, cx| match event {
|
|this: &mut Self, input, event: &InputEvent, cx| match event {
|
||||||
InputEvent::PressEnter => {
|
InputEvent::PressEnter { .. } => {
|
||||||
let url = input.read(cx).text();
|
let url = input.read(cx).text();
|
||||||
this.webview.update(cx, |view, _| {
|
this.webview.update(cx, |view, _| {
|
||||||
view.load_url(&url);
|
view.load_url(&url);
|
||||||
|
|
|
||||||
11
crates/ui/src/actions.rs
Normal file
11
crates/ui/src/actions.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use gpui::{actions, impl_internal_actions};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||||
|
pub struct Confirm {
|
||||||
|
/// Is confirm with secondary.
|
||||||
|
pub secondary: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
actions!(list, [Cancel, SelectPrev, SelectNext]);
|
||||||
|
impl_internal_actions!(list, [Confirm]);
|
||||||
|
|
@ -6,19 +6,19 @@ use gpui::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
actions::Cancel,
|
||||||
button::{Button, ButtonVariants},
|
button::{Button, ButtonVariants},
|
||||||
divider::Divider,
|
divider::Divider,
|
||||||
h_flex,
|
h_flex,
|
||||||
input::{InputEvent, TextInput},
|
input::{InputEvent, TextInput},
|
||||||
popover::Escape,
|
|
||||||
tooltip::Tooltip,
|
tooltip::Tooltip,
|
||||||
v_flex, ActiveTheme as _, Colorize as _, Icon, Selectable as _, Sizable, Size, StyleSized,
|
v_flex, ActiveTheme as _, Colorize as _, Icon, Selectable as _, Sizable, Size, StyleSized,
|
||||||
};
|
};
|
||||||
|
|
||||||
const KEY_CONTEXT: &'static str = "ColorPicker";
|
const CONTEXT: &'static str = "ColorPicker";
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
cx.bind_keys([KeyBinding::new("escape", Escape, Some(KEY_CONTEXT))])
|
cx.bind_keys([KeyBinding::new("escape", Cancel, Some(CONTEXT))])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -73,7 +73,7 @@ pub struct ColorPicker {
|
||||||
|
|
||||||
impl ColorPicker {
|
impl ColorPicker {
|
||||||
pub fn new(id: impl Into<ElementId>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
pub fn new(id: impl Into<ElementId>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let color_input = cx.new(|cx| TextInput::new(window, cx).xsmall());
|
let color_input = cx.new(|cx| TextInput::new(window, cx).small());
|
||||||
|
|
||||||
let _subscriptions = vec![cx.subscribe_in(
|
let _subscriptions = vec![cx.subscribe_in(
|
||||||
&color_input,
|
&color_input,
|
||||||
|
|
@ -85,7 +85,7 @@ impl ColorPicker {
|
||||||
this.hovered_color = Some(color);
|
this.hovered_color = Some(color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PressEnter => {
|
InputEvent::PressEnter { .. } => {
|
||||||
let val = this.color_input.read(cx).text();
|
let val = this.color_input.read(cx).text();
|
||||||
if let Ok(color) = Hsla::parse_hex(&val) {
|
if let Ok(color) = Hsla::parse_hex(&val) {
|
||||||
this.open = false;
|
this.open = false;
|
||||||
|
|
@ -170,8 +170,11 @@ impl ColorPicker {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_escape(&mut self, _: &Escape, _: &mut Window, cx: &mut Context<Self>) {
|
fn on_escape(&mut self, _: &Cancel, _: &mut Window, cx: &mut Context<Self>) {
|
||||||
cx.propagate();
|
if !self.open {
|
||||||
|
cx.propagate();
|
||||||
|
}
|
||||||
|
|
||||||
self.open = false;
|
self.open = false;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +317,7 @@ impl Render for ColorPicker {
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id(self.id.clone())
|
.id(self.id.clone())
|
||||||
.key_context(KEY_CONTEXT)
|
.key_context(CONTEXT)
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.on_action(cx.listener(Self::on_escape))
|
.on_action(cx.listener(Self::on_escape))
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -358,10 +361,6 @@ impl Render for ColorPicker {
|
||||||
})
|
})
|
||||||
.when_some(self.label.clone(), |this, label| this.child(label))
|
.when_some(self.label.clone(), |this, label| this.child(label))
|
||||||
.on_click(cx.listener(Self::toggle_picker))
|
.on_click(cx.listener(Self::toggle_picker))
|
||||||
.on_mouse_up_out(
|
|
||||||
MouseButton::Left,
|
|
||||||
cx.listener(|view, _, window, cx| view.on_escape(&Escape, window, cx)),
|
|
||||||
)
|
|
||||||
.child(
|
.child(
|
||||||
canvas(
|
canvas(
|
||||||
move |bounds, _, cx| view.update(cx, |r, _| r.bounds = bounds),
|
move |bounds, _, cx| view.update(cx, |r, _| r.bounds = bounds),
|
||||||
|
|
@ -394,7 +393,13 @@ impl Render for ColorPicker {
|
||||||
.shadow_lg()
|
.shadow_lg()
|
||||||
.rounded(cx.theme().radius)
|
.rounded(cx.theme().radius)
|
||||||
.bg(cx.theme().background)
|
.bg(cx.theme().background)
|
||||||
.child(self.render_colors(window, cx)),
|
.child(self.render_colors(window, cx))
|
||||||
|
.on_mouse_up_out(
|
||||||
|
MouseButton::Left,
|
||||||
|
cx.listener(|view, _, window, cx| {
|
||||||
|
view.on_escape(&Cancel, window, cx)
|
||||||
|
}),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.with_priority(1),
|
.with_priority(1),
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
use std::{rc::Rc, time::Duration};
|
use std::{rc::Rc, time::Duration};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, div, point, prelude::FluentBuilder as _, px, Animation, AnimationExt as _,
|
anchored, div, point, prelude::FluentBuilder as _, px, Animation, AnimationExt as _,
|
||||||
AnyElement, App, ClickEvent, DefiniteLength, DismissEvent, Div, EventEmitter, FocusHandle,
|
AnyElement, App, ClickEvent, DefiniteLength, DismissEvent, Div, EventEmitter, FocusHandle,
|
||||||
InteractiveElement as _, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels,
|
InteractiveElement as _, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels,
|
||||||
RenderOnce, Styled, Window,
|
RenderOnce, Styled, Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
actions::Cancel,
|
||||||
button::{Button, ButtonVariants as _},
|
button::{Button, ButtonVariants as _},
|
||||||
h_flex,
|
h_flex,
|
||||||
modal::overlay_color,
|
modal::overlay_color,
|
||||||
|
|
@ -17,11 +18,9 @@ use crate::{
|
||||||
v_flex, ActiveTheme, IconName, Placement, Sizable, StyledExt as _,
|
v_flex, ActiveTheme, IconName, Placement, Sizable, StyledExt as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
actions!(drawer, [Escape]);
|
|
||||||
|
|
||||||
const CONTEXT: &str = "Drawer";
|
const CONTEXT: &str = "Drawer";
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
cx.bind_keys([KeyBinding::new("escape", Escape, Some(CONTEXT))])
|
cx.bind_keys([KeyBinding::new("escape", Cancel, Some(CONTEXT))])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
|
|
@ -154,7 +153,9 @@ impl RenderOnce for Drawer {
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.on_action({
|
.on_action({
|
||||||
let on_close = self.on_close.clone();
|
let on_close = self.on_close.clone();
|
||||||
move |_: &Escape, window, cx| {
|
move |_: &Cancel, window, cx| {
|
||||||
|
cx.propagate();
|
||||||
|
|
||||||
on_close(&ClickEvent::default(), window, cx);
|
on_close(&ClickEvent::default(), window, cx);
|
||||||
window.close_drawer(cx);
|
window.close_drawer(cx);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,19 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, canvas, deferred, div, prelude::FluentBuilder, px, rems, AnyElement, App,
|
anchored, canvas, deferred, div, prelude::FluentBuilder, px, rems, AnyElement, App, AppContext,
|
||||||
AppContext, Bounds, ClickEvent, Context, DismissEvent, ElementId, Entity, EventEmitter,
|
Bounds, ClickEvent, Context, DismissEvent, ElementId, Entity, EventEmitter, FocusHandle,
|
||||||
FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding, Length, ParentElement,
|
Focusable, InteractiveElement, IntoElement, KeyBinding, Length, ParentElement, Pixels, Render,
|
||||||
Pixels, Render, SharedString, StatefulInteractiveElement, Styled, Subscription, Task,
|
SharedString, StatefulInteractiveElement, Styled, Subscription, Task, WeakEntity, Window,
|
||||||
WeakEntity, Window,
|
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
actions::{Cancel, Confirm, SelectNext, SelectPrev},
|
||||||
h_flex,
|
h_flex,
|
||||||
input::clear_button,
|
input::clear_button,
|
||||||
list::{self, List, ListDelegate, ListItem},
|
list::{List, ListDelegate, ListItem},
|
||||||
v_flex, ActiveTheme, Disableable as _, Icon, IconName, Sizable, Size, StyleSized, StyledExt,
|
v_flex, ActiveTheme, Disableable as _, Icon, IconName, Sizable, Size, StyleSized, StyledExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
actions!(dropdown, [Up, Down, Enter, Escape]);
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ListEvent {
|
pub enum ListEvent {
|
||||||
/// Single click or move to selected row.
|
/// Single click or move to selected row.
|
||||||
|
|
@ -29,10 +27,15 @@ pub enum ListEvent {
|
||||||
const CONTEXT: &str = "Dropdown";
|
const CONTEXT: &str = "Dropdown";
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
cx.bind_keys([
|
cx.bind_keys([
|
||||||
KeyBinding::new("up", Up, Some(CONTEXT)),
|
KeyBinding::new("up", SelectPrev, Some(CONTEXT)),
|
||||||
KeyBinding::new("down", Down, Some(CONTEXT)),
|
KeyBinding::new("down", SelectNext, Some(CONTEXT)),
|
||||||
KeyBinding::new("enter", Enter, Some(CONTEXT)),
|
KeyBinding::new("enter", Confirm { secondary: false }, Some(CONTEXT)),
|
||||||
KeyBinding::new("escape", Escape, Some(CONTEXT)),
|
KeyBinding::new(
|
||||||
|
"secondary-enter",
|
||||||
|
Confirm { secondary: true },
|
||||||
|
Some(CONTEXT),
|
||||||
|
),
|
||||||
|
KeyBinding::new("escape", Cancel, Some(CONTEXT)),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,9 +176,7 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm(&mut self, ix: usize, window: &mut Window, cx: &mut Context<List<Self>>) {
|
fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context<List<Self>>) {
|
||||||
self.selected_index = Some(ix);
|
|
||||||
|
|
||||||
let selected_value = self
|
let selected_value = self
|
||||||
.selected_index
|
.selected_index
|
||||||
.and_then(|ix| self.delegate.get(ix))
|
.and_then(|ix| self.delegate.get(ix))
|
||||||
|
|
@ -495,24 +496,25 @@ where
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&mut self, _: &Up, window: &mut Window, cx: &mut Context<Self>) {
|
fn up(&mut self, _: &SelectPrev, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
if !self.open {
|
if !self.open {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.list.focus_handle(cx).focus(window);
|
self.list.focus_handle(cx).focus(window);
|
||||||
cx.dispatch_action(&list::SelectPrev);
|
cx.propagate();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn down(&mut self, _: &Down, window: &mut Window, cx: &mut Context<Self>) {
|
fn down(&mut self, _: &SelectNext, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
if !self.open {
|
if !self.open {
|
||||||
self.open = true;
|
self.open = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.list.focus_handle(cx).focus(window);
|
self.list.focus_handle(cx).focus(window);
|
||||||
cx.dispatch_action(&list::SelectNext);
|
cx.propagate();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter(&mut self, _: &Enter, window: &mut Window, cx: &mut Context<Self>) {
|
fn enter(&mut self, _: &Confirm, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
// Propagate the event to the parent view, for example to the Modal to support ENTER to confirm.
|
// Propagate the event to the parent view, for example to the Modal to support ENTER to confirm.
|
||||||
cx.propagate();
|
cx.propagate();
|
||||||
|
|
||||||
|
|
@ -521,7 +523,6 @@ where
|
||||||
cx.notify();
|
cx.notify();
|
||||||
} else {
|
} else {
|
||||||
self.list.focus_handle(cx).focus(window);
|
self.list.focus_handle(cx).focus(window);
|
||||||
cx.dispatch_action(&list::Confirm);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -535,9 +536,10 @@ where
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn escape(&mut self, _: &Escape, _: &mut Window, cx: &mut Context<Self>) {
|
fn escape(&mut self, _: &Cancel, _: &mut Window, cx: &mut Context<Self>) {
|
||||||
// Propagate the event to the parent view, for example to the Modal to support ESC to close.
|
if !self.open {
|
||||||
cx.propagate();
|
cx.propagate();
|
||||||
|
}
|
||||||
|
|
||||||
self.open = false;
|
self.open = false;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
@ -734,13 +736,10 @@ where
|
||||||
.border_color(cx.theme().border)
|
.border_color(cx.theme().border)
|
||||||
.rounded(popup_radius)
|
.rounded(popup_radius)
|
||||||
.shadow_md()
|
.shadow_md()
|
||||||
.on_mouse_down_out(|_, _, cx| {
|
|
||||||
cx.dispatch_action(&Escape);
|
|
||||||
})
|
|
||||||
.child(self.list.clone()),
|
.child(self.list.clone()),
|
||||||
)
|
)
|
||||||
.on_mouse_down_out(cx.listener(|this, _, window, cx| {
|
.on_mouse_down_out(cx.listener(|this, _, window, cx| {
|
||||||
this.escape(&Escape, window, cx);
|
this.escape(&Cancel, window, cx);
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
//! Based on the `Input` example from the `gpui` crate.
|
//! Based on the `Input` example from the `gpui` crate.
|
||||||
//! https://github.com/zed-industries/zed/blob/main/crates/gpui/examples/input.rs
|
//! https://github.com/zed-industries/zed/blob/main/crates/gpui/examples/input.rs
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
@ -11,12 +12,12 @@ use unicode_segmentation::*;
|
||||||
|
|
||||||
use gpui::prelude::FluentBuilder as _;
|
use gpui::prelude::FluentBuilder as _;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, point, px, relative, AnyElement, App, AppContext, Bounds, ClickEvent,
|
actions, div, impl_internal_actions, point, px, relative, AnyElement, App, AppContext, Bounds,
|
||||||
ClipboardItem, Context, DefiniteLength, Entity, EntityInputHandler, EventEmitter, FocusHandle,
|
ClickEvent, ClipboardItem, Context, DefiniteLength, Entity, EntityInputHandler, EventEmitter,
|
||||||
Focusable, InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, MouseButton,
|
FocusHandle, Focusable, InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent,
|
||||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Rems, Render,
|
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point,
|
||||||
ScrollHandle, ScrollWheelEvent, SharedString, Styled as _, Subscription, UTF16Selection,
|
Rems, Render, ScrollHandle, ScrollWheelEvent, SharedString, Styled as _, Subscription,
|
||||||
Window, WrappedLine,
|
UTF16Selection, Window, WrappedLine,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
|
|
@ -37,6 +38,14 @@ use crate::{ActiveTheme, Root};
|
||||||
use crate::{IconName, Size};
|
use crate::{IconName, Size};
|
||||||
use crate::{Sizable, StyleSized};
|
use crate::{Sizable, StyleSized};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||||
|
pub struct Enter {
|
||||||
|
/// Is confirm with secondary.
|
||||||
|
pub secondary: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_internal_actions!(input, [Enter]);
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
input,
|
input,
|
||||||
[
|
[
|
||||||
|
|
@ -46,7 +55,6 @@ actions!(
|
||||||
DeleteToEndOfLine,
|
DeleteToEndOfLine,
|
||||||
DeleteToPreviousWordStart,
|
DeleteToPreviousWordStart,
|
||||||
DeleteToNextWordEnd,
|
DeleteToNextWordEnd,
|
||||||
Enter,
|
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
Left,
|
Left,
|
||||||
|
|
@ -83,7 +91,7 @@ actions!(
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum InputEvent {
|
pub enum InputEvent {
|
||||||
Change(SharedString),
|
Change(SharedString),
|
||||||
PressEnter,
|
PressEnter { secondary: bool },
|
||||||
Focus,
|
Focus,
|
||||||
Blur,
|
Blur,
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +114,8 @@ pub fn init(cx: &mut App) {
|
||||||
KeyBinding::new("alt-delete", DeleteToNextWordEnd, Some(CONTEXT)),
|
KeyBinding::new("alt-delete", DeleteToNextWordEnd, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-delete", DeleteToNextWordEnd, Some(CONTEXT)),
|
KeyBinding::new("ctrl-delete", DeleteToNextWordEnd, Some(CONTEXT)),
|
||||||
KeyBinding::new("enter", Enter, Some(CONTEXT)),
|
KeyBinding::new("enter", Enter { secondary: false }, Some(CONTEXT)),
|
||||||
|
KeyBinding::new("secondary-enter", Enter { secondary: true }, Some(CONTEXT)),
|
||||||
KeyBinding::new("up", Up, Some(CONTEXT)),
|
KeyBinding::new("up", Up, Some(CONTEXT)),
|
||||||
KeyBinding::new("down", Down, Some(CONTEXT)),
|
KeyBinding::new("down", Down, Some(CONTEXT)),
|
||||||
KeyBinding::new("left", Left, Some(CONTEXT)),
|
KeyBinding::new("left", Left, Some(CONTEXT)),
|
||||||
|
|
@ -1004,7 +1013,7 @@ impl TextInput {
|
||||||
self.pause_blink_cursor(cx);
|
self.pause_blink_cursor(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter(&mut self, _: &Enter, window: &mut Window, cx: &mut Context<Self>) {
|
fn enter(&mut self, action: &Enter, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
if self.is_multi_line() {
|
if self.is_multi_line() {
|
||||||
let is_eof = self.selected_range.end == self.text.len();
|
let is_eof = self.selected_range.end == self.text.len();
|
||||||
self.replace_text_in_range(None, "\n", window, cx);
|
self.replace_text_in_range(None, "\n", window, cx);
|
||||||
|
|
@ -1017,7 +1026,9 @@ impl TextInput {
|
||||||
self.move_to(new_offset, window, cx);
|
self.move_to(new_offset, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.emit(InputEvent::PressEnter);
|
cx.emit(InputEvent::PressEnter {
|
||||||
|
secondary: action.secondary,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_to_auto_grow(&mut self, _: &mut Window, cx: &mut Context<Self>) {
|
fn check_to_auto_grow(&mut self, _: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ mod title_bar;
|
||||||
mod virtual_list;
|
mod virtual_list;
|
||||||
mod window_border;
|
mod window_border;
|
||||||
|
|
||||||
|
pub(crate) mod actions;
|
||||||
|
|
||||||
pub mod accordion;
|
pub mod accordion;
|
||||||
pub mod alert;
|
pub mod alert;
|
||||||
pub mod animation;
|
pub mod animation;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{cell::Cell, rc::Rc};
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
|
||||||
|
use crate::actions::{Cancel, Confirm, SelectNext, SelectPrev};
|
||||||
use crate::Icon;
|
use crate::Icon;
|
||||||
use crate::{
|
use crate::{
|
||||||
input::{InputEvent, TextInput},
|
input::{InputEvent, TextInput},
|
||||||
|
|
@ -8,23 +9,22 @@ use crate::{
|
||||||
v_flex, ActiveTheme, IconName, Size,
|
v_flex, ActiveTheme, IconName, Size,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, prelude::FluentBuilder, uniform_list, AnyElement, AppContext, Entity,
|
div, prelude::FluentBuilder, uniform_list, AnyElement, AppContext, Entity, FocusHandle,
|
||||||
FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding, Length,
|
Focusable, InteractiveElement, IntoElement, KeyBinding, Length, ListSizingBehavior,
|
||||||
ListSizingBehavior, MouseButton, ParentElement, Render, SharedString, Styled, Task,
|
MouseButton, ParentElement, Render, SharedString, Styled, Task, UniformListScrollHandle,
|
||||||
UniformListScrollHandle, Window,
|
Window,
|
||||||
};
|
};
|
||||||
use gpui::{px, App, Context, EventEmitter, ScrollStrategy, Subscription};
|
use gpui::{px, App, Context, EventEmitter, MouseDownEvent, ScrollStrategy, Subscription};
|
||||||
use smol::Timer;
|
use smol::Timer;
|
||||||
|
|
||||||
use super::loading::Loading;
|
use super::loading::Loading;
|
||||||
|
|
||||||
actions!(list, [Cancel, Confirm, SelectPrev, SelectNext]);
|
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
let context: Option<&str> = Some("List");
|
let context: Option<&str> = Some("List");
|
||||||
cx.bind_keys([
|
cx.bind_keys([
|
||||||
KeyBinding::new("escape", Cancel, context),
|
KeyBinding::new("escape", Cancel, context),
|
||||||
KeyBinding::new("enter", Confirm, context),
|
KeyBinding::new("enter", Confirm { secondary: false }, context),
|
||||||
|
KeyBinding::new("secondary-enter", Confirm { secondary: true }, context),
|
||||||
KeyBinding::new("up", SelectPrev, context),
|
KeyBinding::new("up", SelectPrev, context),
|
||||||
KeyBinding::new("down", SelectNext, context),
|
KeyBinding::new("down", SelectNext, context),
|
||||||
]);
|
]);
|
||||||
|
|
@ -112,7 +112,9 @@ pub trait ListDelegate: Sized + 'static {
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Set the confirm and give the selected index, this is means user have clicked the item or pressed Enter.
|
/// Set the confirm and give the selected index, this is means user have clicked the item or pressed Enter.
|
||||||
fn confirm(&mut self, ix: usize, window: &mut Window, cx: &mut Context<List<Self>>) {}
|
///
|
||||||
|
/// This will always to `set_selected_index` before confirm.
|
||||||
|
fn confirm(&mut self, secondary: bool, window: &mut Window, cx: &mut Context<List<Self>>) {}
|
||||||
|
|
||||||
/// Cancel the selection, e.g.: Pressed ESC.
|
/// Cancel the selection, e.g.: Pressed ESC.
|
||||||
fn cancel(&mut self, window: &mut Window, cx: &mut Context<List<Self>>) {}
|
fn cancel(&mut self, window: &mut Window, cx: &mut Context<List<Self>>) {}
|
||||||
|
|
@ -347,7 +349,13 @@ where
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
InputEvent::PressEnter => self.on_action_confirm(&Confirm, window, cx),
|
InputEvent::PressEnter { secondary } => self.on_action_confirm(
|
||||||
|
&Confirm {
|
||||||
|
secondary: *secondary,
|
||||||
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -389,15 +397,25 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_action_cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
|
fn on_action_cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
if self.selected_index.is_none() {
|
||||||
|
cx.propagate();
|
||||||
|
}
|
||||||
|
|
||||||
if self.reset_on_cancel {
|
if self.reset_on_cancel {
|
||||||
self.set_selected_index(None, window, cx);
|
self.set_selected_index(None, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.delegate.cancel(window, cx);
|
self.delegate.cancel(window, cx);
|
||||||
cx.emit(ListEvent::Cancel);
|
cx.emit(ListEvent::Cancel);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_action_confirm(&mut self, _: &Confirm, window: &mut Window, cx: &mut Context<Self>) {
|
fn on_action_confirm(
|
||||||
|
&mut self,
|
||||||
|
confirm: &Confirm,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
if self.delegate.items_count(cx) == 0 {
|
if self.delegate.items_count(cx) == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -406,7 +424,9 @@ where
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.delegate.confirm(ix, window, cx);
|
self.delegate
|
||||||
|
.set_selected_index(self.selected_index, window, cx);
|
||||||
|
self.delegate.confirm(confirm.secondary, window, cx);
|
||||||
cx.emit(ListEvent::Confirm(ix));
|
cx.emit(ListEvent::Confirm(ix));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
@ -496,10 +516,16 @@ where
|
||||||
})
|
})
|
||||||
.on_mouse_down(
|
.on_mouse_down(
|
||||||
MouseButton::Left,
|
MouseButton::Left,
|
||||||
cx.listener(move |this, _, window, cx| {
|
cx.listener(move |this, ev: &MouseDownEvent, window, cx| {
|
||||||
this.right_clicked_index = None;
|
this.right_clicked_index = None;
|
||||||
this.selected_index = Some(ix);
|
this.selected_index = Some(ix);
|
||||||
this.on_action_confirm(&Confirm, window, cx);
|
this.on_action_confirm(
|
||||||
|
&Confirm {
|
||||||
|
secondary: ev.modifiers.secondary(),
|
||||||
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.on_mouse_down(
|
.on_mouse_down(
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,25 @@
|
||||||
use std::{rc::Rc, time::Duration};
|
use std::{rc::Rc, time::Duration};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, div, hsla, point, prelude::FluentBuilder, px, relative, Animation,
|
anchored, div, hsla, point, prelude::FluentBuilder, px, relative, Animation, AnimationExt as _,
|
||||||
AnimationExt as _, AnyElement, App, Bounds, ClickEvent, Div, FocusHandle, Hsla,
|
AnyElement, App, Bounds, ClickEvent, Div, FocusHandle, Hsla, InteractiveElement, IntoElement,
|
||||||
InteractiveElement, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point,
|
KeyBinding, MouseButton, ParentElement, Pixels, Point, RenderOnce, SharedString, Styled,
|
||||||
RenderOnce, SharedString, Styled, Window,
|
Window,
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
actions::{Cancel, Confirm},
|
||||||
animation::cubic_bezier,
|
animation::cubic_bezier,
|
||||||
button::{Button, ButtonVariant, ButtonVariants as _},
|
button::{Button, ButtonVariant, ButtonVariants as _},
|
||||||
h_flex, v_flex, ActiveTheme as _, ContextModal, IconName, Sizable as _, StyledExt,
|
h_flex, v_flex, ActiveTheme as _, ContextModal, IconName, Sizable as _, StyledExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
actions!(modal, [Escape, Enter]);
|
|
||||||
|
|
||||||
const CONTEXT: &str = "Modal";
|
const CONTEXT: &str = "Modal";
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
cx.bind_keys([
|
cx.bind_keys([
|
||||||
KeyBinding::new("escape", Escape, Some(CONTEXT)),
|
KeyBinding::new("escape", Cancel, Some(CONTEXT)),
|
||||||
KeyBinding::new("enter", Enter, Some(CONTEXT)),
|
KeyBinding::new("enter", Confirm { secondary: false }, Some(CONTEXT)),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -382,7 +381,7 @@ impl RenderOnce for Modal {
|
||||||
this.on_action({
|
this.on_action({
|
||||||
let on_cancel = on_cancel.clone();
|
let on_cancel = on_cancel.clone();
|
||||||
let on_close = on_close.clone();
|
let on_close = on_close.clone();
|
||||||
move |_: &Escape, window, cx| {
|
move |_: &Cancel, window, cx| {
|
||||||
// FIXME:
|
// FIXME:
|
||||||
//
|
//
|
||||||
// Here some Modal have no focus_handle, so it will not work will Escape key.
|
// Here some Modal have no focus_handle, so it will not work will Escape key.
|
||||||
|
|
@ -395,7 +394,7 @@ impl RenderOnce for Modal {
|
||||||
.on_action({
|
.on_action({
|
||||||
let on_ok = on_ok.clone();
|
let on_ok = on_ok.clone();
|
||||||
let on_close = on_close.clone();
|
let on_close = on_close.clone();
|
||||||
move |_: &Enter, window, cx| {
|
move |_: &Confirm, window, cx| {
|
||||||
if on_ok(&ClickEvent::default(), window, cx) {
|
if on_ok(&ClickEvent::default(), window, cx) {
|
||||||
on_close(&ClickEvent::default(), window, cx);
|
on_close(&ClickEvent::default(), window, cx);
|
||||||
window.close_modal(cx);
|
window.close_modal(cx);
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, deferred, div, prelude::FluentBuilder as _, px, AnyElement, App, Bounds,
|
anchored, deferred, div, prelude::FluentBuilder as _, px, AnyElement, App, Bounds, Context,
|
||||||
Context, Corner, DismissEvent, DispatchPhase, Element, ElementId, Entity, EventEmitter,
|
Corner, DismissEvent, DispatchPhase, Element, ElementId, Entity, EventEmitter, FocusHandle,
|
||||||
FocusHandle, Focusable, GlobalElementId, Hitbox, InteractiveElement as _, IntoElement,
|
Focusable, GlobalElementId, Hitbox, InteractiveElement as _, IntoElement, KeyBinding, LayoutId,
|
||||||
KeyBinding, LayoutId, ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point,
|
ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render, Style,
|
||||||
Render, Style, StyleRefinement, Styled, Window,
|
StyleRefinement, Styled, Window,
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use crate::{Selectable, StyledExt as _};
|
use crate::{actions::Cancel, Selectable, StyledExt as _};
|
||||||
|
|
||||||
const CONTEXT: &str = "Popover";
|
const CONTEXT: &str = "Popover";
|
||||||
|
|
||||||
actions!(popover, [Escape]);
|
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
cx.bind_keys([KeyBinding::new("escape", Escape, Some(CONTEXT))])
|
cx.bind_keys([KeyBinding::new("escape", Cancel, Some(CONTEXT))])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PopoverContent {
|
pub struct PopoverContent {
|
||||||
|
|
@ -55,7 +53,10 @@ impl Render for PopoverContent {
|
||||||
div()
|
div()
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.key_context(CONTEXT)
|
.key_context(CONTEXT)
|
||||||
.on_action(cx.listener(|_, _: &Escape, _, cx| cx.emit(DismissEvent)))
|
.on_action(cx.listener(|_, _: &Cancel, _, cx| {
|
||||||
|
cx.propagate();
|
||||||
|
cx.emit(DismissEvent);
|
||||||
|
}))
|
||||||
.p_2()
|
.p_2()
|
||||||
.when_some(self.max_width, |this, v| this.max_w(v))
|
.when_some(self.max_width, |this, v| this.max_w(v))
|
||||||
.child(self.content.clone()(window, cx))
|
.child(self.content.clone()(window, cx))
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::actions::{Cancel, Confirm, SelectNext, SelectPrev};
|
||||||
use crate::scroll::{Scrollbar, ScrollbarState};
|
use crate::scroll::{Scrollbar, ScrollbarState};
|
||||||
use crate::{
|
use crate::{
|
||||||
button::Button, h_flex, list::ListItem, popover::Popover, v_flex, ActiveTheme, Icon, IconName,
|
button::Button, h_flex, list::ListItem, popover::Popover, v_flex, ActiveTheme, Icon, IconName,
|
||||||
|
|
@ -6,24 +7,22 @@ use crate::{
|
||||||
use crate::{Kbd, StyledExt};
|
use crate::{Kbd, StyledExt};
|
||||||
use gpui::Subscription;
|
use gpui::Subscription;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, canvas, div, prelude::FluentBuilder, px, rems, Action, AnyElement, App,
|
anchored, canvas, div, prelude::FluentBuilder, px, rems, Action, AnyElement, App, AppContext,
|
||||||
AppContext, Bounds, Context, Corner, DismissEvent, Edges, Entity, EventEmitter, FocusHandle,
|
Bounds, Context, Corner, DismissEvent, Edges, Entity, EventEmitter, FocusHandle, Focusable,
|
||||||
Focusable, InteractiveElement, IntoElement, KeyBinding, ParentElement, Pixels, Render,
|
InteractiveElement, IntoElement, KeyBinding, ParentElement, Pixels, Render, ScrollHandle,
|
||||||
ScrollHandle, SharedString, StatefulInteractiveElement, Styled, WeakEntity, Window,
|
SharedString, StatefulInteractiveElement, Styled, WeakEntity, Window,
|
||||||
};
|
};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
actions!(menu, [Confirm, Dismiss, SelectNext, SelectPrev]);
|
|
||||||
|
|
||||||
const ITEM_HEIGHT: Pixels = px(26.);
|
const ITEM_HEIGHT: Pixels = px(26.);
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
let context = Some("PopupMenu");
|
let context = Some("PopupMenu");
|
||||||
cx.bind_keys([
|
cx.bind_keys([
|
||||||
KeyBinding::new("enter", Confirm, context),
|
KeyBinding::new("enter", Confirm { secondary: false }, context),
|
||||||
KeyBinding::new("escape", Dismiss, context),
|
KeyBinding::new("escape", Cancel, context),
|
||||||
KeyBinding::new("up", SelectPrev, context),
|
KeyBinding::new("up", SelectPrev, context),
|
||||||
KeyBinding::new("down", SelectNext, context),
|
KeyBinding::new("down", SelectNext, context),
|
||||||
]);
|
]);
|
||||||
|
|
@ -127,7 +126,7 @@ impl PopupMenu {
|
||||||
let _subscriptions =
|
let _subscriptions =
|
||||||
vec![
|
vec![
|
||||||
cx.on_blur(&focus_handle, window, |this: &mut PopupMenu, window, cx| {
|
cx.on_blur(&focus_handle, window, |this: &mut PopupMenu, window, cx| {
|
||||||
this.dismiss(&Dismiss, window, cx)
|
this.dismiss(&Cancel, window, cx)
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -544,7 +543,7 @@ impl PopupMenu {
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
window.prevent_default();
|
window.prevent_default();
|
||||||
self.selected_index = Some(ix);
|
self.selected_index = Some(ix);
|
||||||
self.confirm(&Confirm, window, cx);
|
self.confirm(&Confirm { secondary: false }, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm(&mut self, _: &Confirm, window: &mut Window, cx: &mut Context<Self>) {
|
fn confirm(&mut self, _: &Confirm, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
|
@ -554,11 +553,11 @@ impl PopupMenu {
|
||||||
match item {
|
match item {
|
||||||
Some(PopupMenuItem::Item { handler, .. }) => {
|
Some(PopupMenuItem::Item { handler, .. }) => {
|
||||||
handler(window, cx);
|
handler(window, cx);
|
||||||
self.dismiss(&Dismiss, window, cx)
|
self.dismiss(&Cancel, window, cx)
|
||||||
}
|
}
|
||||||
Some(PopupMenuItem::ElementItem { handler, .. }) => {
|
Some(PopupMenuItem::ElementItem { handler, .. }) => {
|
||||||
handler(window, cx);
|
handler(window, cx);
|
||||||
self.dismiss(&Dismiss, window, cx)
|
self.dismiss(&Cancel, window, cx)
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -601,7 +600,7 @@ impl PopupMenu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dismiss(&mut self, _: &Dismiss, window: &mut Window, cx: &mut Context<Self>) {
|
fn dismiss(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
if self.active_submenu().is_some() {
|
if self.active_submenu().is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -620,7 +619,7 @@ impl PopupMenu {
|
||||||
// Dismiss parent menu, when this menu is dismissed
|
// Dismiss parent menu, when this menu is dismissed
|
||||||
_ = parent_menu.update(cx, |view, cx| {
|
_ = parent_menu.update(cx, |view, cx| {
|
||||||
view.hovered_menu_ix = None;
|
view.hovered_menu_ix = None;
|
||||||
view.dismiss(&Dismiss, window, cx);
|
view.dismiss(&Cancel, window, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -883,9 +882,7 @@ impl Render for PopupMenu {
|
||||||
.on_action(cx.listener(Self::select_prev))
|
.on_action(cx.listener(Self::select_prev))
|
||||||
.on_action(cx.listener(Self::confirm))
|
.on_action(cx.listener(Self::confirm))
|
||||||
.on_action(cx.listener(Self::dismiss))
|
.on_action(cx.listener(Self::dismiss))
|
||||||
.on_mouse_down_out(
|
.on_mouse_down_out(cx.listener(|this, _, window, cx| this.dismiss(&Cancel, window, cx)))
|
||||||
cx.listener(|this, _, window, cx| this.dismiss(&Dismiss, window, cx)),
|
|
||||||
)
|
|
||||||
.popover_style(cx)
|
.popover_style(cx)
|
||||||
.text_color(cx.theme().popover_foreground)
|
.text_color(cx.theme().popover_foreground)
|
||||||
.relative()
|
.relative()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{cell::Cell, ops::Range, rc::Rc, time::Duration};
|
use std::{cell::Cell, ops::Range, rc::Rc, time::Duration};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
actions::{Cancel, SelectNext, SelectPrev},
|
||||||
context_menu::ContextMenuExt,
|
context_menu::ContextMenuExt,
|
||||||
h_flex,
|
h_flex,
|
||||||
popup_menu::PopupMenu,
|
popup_menu::PopupMenu,
|
||||||
|
|
@ -18,16 +19,7 @@ use gpui::{
|
||||||
|
|
||||||
mod loading;
|
mod loading;
|
||||||
|
|
||||||
actions!(
|
actions!(table, [SelectPrevColumn, SelectNextColumn]);
|
||||||
table,
|
|
||||||
[
|
|
||||||
Cancel,
|
|
||||||
SelectPrev,
|
|
||||||
SelectNext,
|
|
||||||
SelectPrevColumn,
|
|
||||||
SelectNextColumn
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
let context = Some("Table");
|
let context = Some("Table");
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ use gpui::{
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
actions::Cancel,
|
||||||
button::{Button, ButtonVariants as _},
|
button::{Button, ButtonVariants as _},
|
||||||
dropdown::Escape,
|
|
||||||
h_flex,
|
h_flex,
|
||||||
input::clear_button,
|
input::clear_button,
|
||||||
v_flex, ActiveTheme, Icon, IconName, Sizable, Size, StyleSized as _, StyledExt as _,
|
v_flex, ActiveTheme, Icon, IconName, Sizable, Size, StyleSized as _, StyledExt as _,
|
||||||
|
|
@ -19,7 +19,7 @@ use super::calendar::{Calendar, CalendarEvent, Date, Matcher};
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
let context = Some("DatePicker");
|
let context = Some("DatePicker");
|
||||||
cx.bind_keys([KeyBinding::new("escape", Escape, context)])
|
cx.bind_keys([KeyBinding::new("escape", Cancel, context)])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -208,7 +208,11 @@ impl DatePicker {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn escape(&mut self, _: &Escape, window: &mut Window, cx: &mut Context<Self>) {
|
fn escape(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
if !self.open {
|
||||||
|
cx.propagate();
|
||||||
|
}
|
||||||
|
|
||||||
self.focus_back_if_need(window, cx);
|
self.focus_back_if_need(window, cx);
|
||||||
self.open = false;
|
self.open = false;
|
||||||
|
|
||||||
|
|
@ -364,7 +368,7 @@ impl Render for DatePicker {
|
||||||
.on_mouse_up_out(
|
.on_mouse_up_out(
|
||||||
MouseButton::Left,
|
MouseButton::Left,
|
||||||
cx.listener(|view, _, window, cx| {
|
cx.listener(|view, _, window, cx| {
|
||||||
view.escape(&Escape, window, cx);
|
view.escape(&Cancel, window, cx);
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue