list: Refactor ListDelegate to easy access delegate. (#1713)
Continue #1712 ## Break Changes - The argument type of `render_item`, `render_section_header`, `render_section_footer`, `render_empty`, `render_initial`, `render_loading` in `ListDelegate` has been changed to has `&mut self` and `&mut Context<ListState<Self>>`. ```diff - fn render_item(&self, ix: IndexPath, window: &mut Window, cx: &mut App) -> Option<Self::Item> + fn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<ListState<Self>>) -> Option<Self::Item> ```
This commit is contained in:
parent
001b1795f1
commit
c0f801dd8c
8 changed files with 89 additions and 52 deletions
|
|
@ -225,10 +225,10 @@ impl ListDelegate for CompanyListDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_section_header(
|
fn render_section_header(
|
||||||
&self,
|
&mut self,
|
||||||
section: usize,
|
section: usize,
|
||||||
_: &mut Window,
|
_: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut Context<ListState<Self>>,
|
||||||
) -> Option<impl IntoElement> {
|
) -> Option<impl IntoElement> {
|
||||||
let Some(industry) = self.industries.get(section) else {
|
let Some(industry) = self.industries.get(section) else {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -247,10 +247,10 @@ impl ListDelegate for CompanyListDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_section_footer(
|
fn render_section_footer(
|
||||||
&self,
|
&mut self,
|
||||||
section: usize,
|
section: usize,
|
||||||
_: &mut Window,
|
_: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut Context<ListState<Self>>,
|
||||||
) -> Option<impl IntoElement> {
|
) -> Option<impl IntoElement> {
|
||||||
let Some(_) = self.industries.get(section) else {
|
let Some(_) = self.industries.get(section) else {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -270,7 +270,7 @@ impl ListDelegate for CompanyListDelegate {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_item(&self, ix: IndexPath, _: &mut Window, _: &mut App) -> Option<Self::Item> {
|
fn render_item(&mut self, ix: IndexPath, _: &mut Window, _: &mut Context<ListState<Self>>) -> Option<Self::Item> {
|
||||||
let selected = Some(ix) == self.selected_index || Some(ix) == self.confirmed_index;
|
let selected = Some(ix) == self.selected_index || Some(ix) == self.confirmed_index;
|
||||||
if let Some(company) = self.matched_companies[ix.section].get(ix.row) {
|
if let Some(company) = self.matched_companies[ix.section].get(ix.row) {
|
||||||
return Some(CompanyListItem::new(ix, company.clone(), selected));
|
return Some(CompanyListItem::new(ix, company.clone(), selected));
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ impl ListDelegate for DropdownListDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_item(
|
fn render_item(
|
||||||
&self,
|
&mut self,
|
||||||
ix: gpui_component::IndexPath,
|
ix: gpui_component::IndexPath,
|
||||||
_: &mut Window,
|
_: &mut Window,
|
||||||
_: &mut App,
|
_: &mut Context<ListState<Self>>,
|
||||||
) -> Option<Self::Item> {
|
) -> Option<Self::Item> {
|
||||||
Some(ListItem::new(ix).child(format!("Item {}", ix.row)))
|
Some(ListItem::new(ix).child(format!("Item {}", ix.row)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ impl ListDelegate for ListItemDeletegate {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_item(&self, ix: IndexPath, _: &mut Window, _: &mut App) -> Option<Self::Item> {
|
fn render_item(&mut self, ix: IndexPath, _: &mut Window, _: &mut Context<ListState<Self>>) -> Option<Self::Item> {
|
||||||
let confirmed = Some(ix.row) == self.confirmed_index;
|
let confirmed = Some(ix.row) == self.confirmed_index;
|
||||||
|
|
||||||
if let Some(item) = self.matches.get(ix.row) {
|
if let Some(item) = self.matches.get(ix.row) {
|
||||||
|
|
@ -97,7 +97,11 @@ impl ListDelegate for ListItemDeletegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_empty(&self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render_empty(
|
||||||
|
&mut self,
|
||||||
|
_: &mut Window,
|
||||||
|
cx: &mut Context<ListState<Self>>,
|
||||||
|
) -> impl IntoElement {
|
||||||
v_flex()
|
v_flex()
|
||||||
.size_full()
|
.size_full()
|
||||||
.child(
|
.child(
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
canvas, deferred, div, prelude::FluentBuilder, px, relative, Action, AnyElement, App,
|
Action, AnyElement, App, AppContext, Bounds, Context, DismissEvent, Empty, Entity,
|
||||||
AppContext, Bounds, Context, DismissEvent, Empty, Entity, EventEmitter,
|
EventEmitter, InteractiveElement as _, IntoElement, ParentElement, Pixels, Point, Render,
|
||||||
InteractiveElement as _, IntoElement, ParentElement, Pixels, Point, Render, RenderOnce,
|
RenderOnce, SharedString, Styled, StyledText, Subscription, Window, canvas, deferred, div,
|
||||||
SharedString, Styled, StyledText, Subscription, Window,
|
prelude::FluentBuilder, px, relative,
|
||||||
};
|
};
|
||||||
use lsp_types::CodeAction;
|
use lsp_types::CodeAction;
|
||||||
|
|
||||||
|
|
@ -12,10 +12,9 @@ const MAX_MENU_WIDTH: Pixels = px(320.);
|
||||||
const MAX_MENU_HEIGHT: Pixels = px(480.);
|
const MAX_MENU_HEIGHT: Pixels = px(480.);
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
actions, h_flex,
|
ActiveTheme, IndexPath, Selectable, actions, h_flex,
|
||||||
input::{self, popovers::editor_popover, InputState},
|
input::{self, InputState, popovers::editor_popover},
|
||||||
list::{List, ListDelegate, ListEvent, ListState},
|
list::{List, ListDelegate, ListEvent, ListState},
|
||||||
ActiveTheme, IndexPath, Selectable,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -110,7 +109,12 @@ impl ListDelegate for MenuDelegate {
|
||||||
self.items.len()
|
self.items.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_item(&self, ix: crate::IndexPath, _: &mut Window, _: &mut App) -> Option<Self::Item> {
|
fn render_item(
|
||||||
|
&mut self,
|
||||||
|
ix: crate::IndexPath,
|
||||||
|
_: &mut Window,
|
||||||
|
_: &mut Context<ListState<Self>>,
|
||||||
|
) -> Option<Self::Item> {
|
||||||
let item = self.items.get(ix.row)?;
|
let item = self.items.get(ix.row)?;
|
||||||
Some(MenuItem::new(ix.row, item.clone()))
|
Some(MenuItem::new(ix.row, item.clone()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
canvas, deferred, div, prelude::FluentBuilder, px, relative, Action, AnyElement, App,
|
Action, AnyElement, App, AppContext, Bounds, Context, DismissEvent, Empty, Entity,
|
||||||
AppContext, Bounds, Context, DismissEvent, Empty, Entity, EventEmitter, HighlightStyle,
|
EventEmitter, HighlightStyle, InteractiveElement as _, IntoElement, ParentElement, Pixels,
|
||||||
InteractiveElement as _, IntoElement, ParentElement, Pixels, Point, Render, RenderOnce,
|
Point, Render, RenderOnce, SharedString, Styled, StyledText, Subscription, Window, canvas,
|
||||||
SharedString, Styled, StyledText, Subscription, Window,
|
deferred, div, prelude::FluentBuilder, px, relative,
|
||||||
};
|
};
|
||||||
use lsp_types::{CompletionItem, CompletionTextEdit};
|
use lsp_types::{CompletionItem, CompletionTextEdit};
|
||||||
|
|
||||||
|
|
@ -13,15 +13,13 @@ const MAX_MENU_HEIGHT: Pixels = px(240.);
|
||||||
const POPOVER_GAP: Pixels = px(4.);
|
const POPOVER_GAP: Pixels = px(4.);
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
actions, h_flex,
|
ActiveTheme, IndexPath, Selectable, actions, h_flex,
|
||||||
input::{
|
input::{
|
||||||
self,
|
self, InputState, RopeExt,
|
||||||
popovers::{editor_popover, render_markdown},
|
popovers::{editor_popover, render_markdown},
|
||||||
InputState, RopeExt,
|
|
||||||
},
|
},
|
||||||
label::Label,
|
label::Label,
|
||||||
list::{List, ListDelegate, ListEvent, ListState},
|
list::{List, ListDelegate, ListEvent, ListState},
|
||||||
ActiveTheme, IndexPath, Selectable,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContextMenuDelegate {
|
struct ContextMenuDelegate {
|
||||||
|
|
@ -137,7 +135,12 @@ impl ListDelegate for ContextMenuDelegate {
|
||||||
self.items.len()
|
self.items.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_item(&self, ix: crate::IndexPath, _: &mut Window, _: &mut App) -> Option<Self::Item> {
|
fn render_item(
|
||||||
|
&mut self,
|
||||||
|
ix: crate::IndexPath,
|
||||||
|
_: &mut Window,
|
||||||
|
_: &mut Context<ListState<Self>>,
|
||||||
|
) -> Option<Self::Item> {
|
||||||
let item = self.items.get(ix.row)?;
|
let item = self.items.get(ix.row)?;
|
||||||
Some(CompletionMenuItem::new(ix.row, item.clone()).highlight_prefix(self.query.clone()))
|
Some(CompletionMenuItem::new(ix.row, item.clone()).highlight_prefix(self.query.clone()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
use gpui::{AnyElement, App, Context, IntoElement, ParentElement as _, Styled as _, Task, Window};
|
use gpui::{AnyElement, App, Context, IntoElement, ParentElement as _, Styled as _, Task, Window};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
h_flex,
|
ActiveTheme as _, Icon, IconName, IndexPath, Selectable, h_flex,
|
||||||
list::{loading::Loading, ListState},
|
list::{ListState, loading::Loading},
|
||||||
ActiveTheme as _, Icon, IconName, IndexPath, Selectable,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A delegate for the List.
|
/// A delegate for the List.
|
||||||
|
|
@ -35,16 +34,21 @@ pub trait ListDelegate: Sized + 'static {
|
||||||
/// Return None will skip the item.
|
/// Return None will skip the item.
|
||||||
///
|
///
|
||||||
/// NOTE: Every item should have same height.
|
/// NOTE: Every item should have same height.
|
||||||
fn render_item(&self, ix: IndexPath, window: &mut Window, cx: &mut App) -> Option<Self::Item>;
|
fn render_item(
|
||||||
|
&mut self,
|
||||||
|
ix: IndexPath,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<ListState<Self>>,
|
||||||
|
) -> Option<Self::Item>;
|
||||||
|
|
||||||
/// Render the section header at the given index, default is None.
|
/// Render the section header at the given index, default is None.
|
||||||
///
|
///
|
||||||
/// NOTE: Every header should have same height.
|
/// NOTE: Every header should have same height.
|
||||||
fn render_section_header(
|
fn render_section_header(
|
||||||
&self,
|
&mut self,
|
||||||
section: usize,
|
section: usize,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut Context<ListState<Self>>,
|
||||||
) -> Option<impl IntoElement> {
|
) -> Option<impl IntoElement> {
|
||||||
None::<AnyElement>
|
None::<AnyElement>
|
||||||
}
|
}
|
||||||
|
|
@ -53,16 +57,20 @@ pub trait ListDelegate: Sized + 'static {
|
||||||
///
|
///
|
||||||
/// NOTE: Every footer should have same height.
|
/// NOTE: Every footer should have same height.
|
||||||
fn render_section_footer(
|
fn render_section_footer(
|
||||||
&self,
|
&mut self,
|
||||||
section: usize,
|
section: usize,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut Context<ListState<Self>>,
|
||||||
) -> Option<impl IntoElement> {
|
) -> Option<impl IntoElement> {
|
||||||
None::<AnyElement>
|
None::<AnyElement>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a Element to show when list is empty.
|
/// Return a Element to show when list is empty.
|
||||||
fn render_empty(&self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render_empty(
|
||||||
|
&mut self,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<ListState<Self>>,
|
||||||
|
) -> impl IntoElement {
|
||||||
h_flex()
|
h_flex()
|
||||||
.size_full()
|
.size_full()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
|
|
@ -79,7 +87,11 @@ pub trait ListDelegate: Sized + 'static {
|
||||||
/// For example: The last search results, or the last selected item.
|
/// For example: The last search results, or the last selected item.
|
||||||
///
|
///
|
||||||
/// Default is None, that means no initial state.
|
/// Default is None, that means no initial state.
|
||||||
fn render_initial(&self, window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
fn render_initial(
|
||||||
|
&mut self,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<ListState<Self>>,
|
||||||
|
) -> Option<AnyElement> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +102,11 @@ pub trait ListDelegate: Sized + 'static {
|
||||||
|
|
||||||
/// Returns a Element to show when loading, default is built-in Skeleton
|
/// Returns a Element to show when loading, default is built-in Skeleton
|
||||||
/// loading view.
|
/// loading view.
|
||||||
fn render_loading(&self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render_loading(
|
||||||
|
&mut self,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<ListState<Self>>,
|
||||||
|
) -> impl IntoElement {
|
||||||
Loading
|
Loading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -430,7 +430,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_list_item(
|
fn render_list_item(
|
||||||
&self,
|
&mut self,
|
||||||
ix: IndexPath,
|
ix: IndexPath,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
|
|
@ -474,7 +474,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_items(
|
fn render_items(
|
||||||
&self,
|
&mut self,
|
||||||
items_count: usize,
|
items_count: usize,
|
||||||
entities_count: usize,
|
entities_count: usize,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
|
|
@ -526,11 +526,11 @@ where
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
),
|
),
|
||||||
RowEntry::SectionHeader(section_ix) => list
|
RowEntry::SectionHeader(section_ix) => list
|
||||||
.delegate()
|
.delegate_mut()
|
||||||
.render_section_header(section_ix, window, cx)
|
.render_section_header(section_ix, window, cx)
|
||||||
.map(|r| r.into_any_element()),
|
.map(|r| r.into_any_element()),
|
||||||
RowEntry::SectionFooter(section_ix) => list
|
RowEntry::SectionFooter(section_ix) => list
|
||||||
.delegate()
|
.delegate_mut()
|
||||||
.render_section_footer(section_ix, window, cx)
|
.render_section_footer(section_ix, window, cx)
|
||||||
.map(|r| r.into_any_element()),
|
.map(|r| r.into_any_element()),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,20 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, canvas, deferred, div, prelude::FluentBuilder, px, rems, AnyElement, App, AppContext,
|
AnyElement, App, AppContext, Bounds, ClickEvent, Context, DismissEvent, Edges, ElementId,
|
||||||
Bounds, ClickEvent, Context, DismissEvent, Edges, ElementId, Entity, EventEmitter, FocusHandle,
|
Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding,
|
||||||
Focusable, InteractiveElement, IntoElement, KeyBinding, Length, ParentElement, Pixels, Render,
|
Length, ParentElement, Pixels, Render, RenderOnce, SharedString, StatefulInteractiveElement,
|
||||||
RenderOnce, SharedString, StatefulInteractiveElement, StyleRefinement, Styled, Subscription,
|
StyleRefinement, Styled, Subscription, Task, WeakEntity, Window, anchored, canvas, deferred,
|
||||||
Task, WeakEntity, Window,
|
div, prelude::FluentBuilder, px, rems,
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
ActiveTheme, Disableable, Icon, IconName, IndexPath, Selectable, Sizable, Size, StyleSized,
|
||||||
|
StyledExt,
|
||||||
actions::{Cancel, Confirm, SelectDown, SelectUp},
|
actions::{Cancel, Confirm, SelectDown, SelectUp},
|
||||||
h_flex,
|
h_flex,
|
||||||
input::clear_button,
|
input::clear_button,
|
||||||
list::{List, ListDelegate, ListState},
|
list::{List, ListDelegate, ListState},
|
||||||
v_flex, ActiveTheme, Disableable, Icon, IconName, IndexPath, Selectable, Sizable, Size,
|
v_flex,
|
||||||
StyleSized, StyledExt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const CONTEXT: &str = "Select";
|
const CONTEXT: &str = "Select";
|
||||||
|
|
@ -167,10 +168,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_section_header(
|
fn render_section_header(
|
||||||
&self,
|
&mut self,
|
||||||
section: usize,
|
section: usize,
|
||||||
_: &mut Window,
|
_: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut Context<ListState<Self>>,
|
||||||
) -> Option<impl IntoElement> {
|
) -> Option<impl IntoElement> {
|
||||||
let state = self.state.upgrade()?.read(cx);
|
let state = self.state.upgrade()?.read(cx);
|
||||||
let Some(item) = self.delegate.section(section) else {
|
let Some(item) = self.delegate.section(section) else {
|
||||||
|
|
@ -188,7 +189,12 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_item(&self, ix: IndexPath, window: &mut Window, cx: &mut App) -> Option<Self::Item> {
|
fn render_item(
|
||||||
|
&mut self,
|
||||||
|
ix: IndexPath,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<ListState<Self>>,
|
||||||
|
) -> Option<Self::Item> {
|
||||||
let selected = self
|
let selected = self
|
||||||
.selected_index
|
.selected_index
|
||||||
.map_or(false, |selected_index| selected_index == ix);
|
.map_or(false, |selected_index| selected_index == ix);
|
||||||
|
|
@ -273,7 +279,11 @@ where
|
||||||
self.selected_index = ix;
|
self.selected_index = ix;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_empty(&self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render_empty(
|
||||||
|
&mut self,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<ListState<Self>>,
|
||||||
|
) -> impl IntoElement {
|
||||||
if let Some(empty) = self
|
if let Some(empty) = self
|
||||||
.state
|
.state
|
||||||
.upgrade()
|
.upgrade()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue