Render more than one item
This commit is contained in:
parent
fa153a0d56
commit
ff15ddf3e0
3 changed files with 82 additions and 68 deletions
|
@ -147,6 +147,7 @@ impl PickerDelegate for CommandPaletteDelegate {
|
||||||
type ListItem = Div<Picker<Self>>;
|
type ListItem = Div<Picker<Self>>;
|
||||||
|
|
||||||
fn match_count(&self) -> usize {
|
fn match_count(&self) -> usize {
|
||||||
|
dbg!(self.matches.len());
|
||||||
self.matches.len()
|
self.matches.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,44 +164,11 @@ impl PickerDelegate for CommandPaletteDelegate {
|
||||||
query: String,
|
query: String,
|
||||||
cx: &mut ViewContext<Picker<Self>>,
|
cx: &mut ViewContext<Picker<Self>>,
|
||||||
) -> gpui::Task<()> {
|
) -> gpui::Task<()> {
|
||||||
let view_id = &self.previous_focus_handle;
|
let mut commands = self.commands.clone();
|
||||||
let window = cx.window();
|
|
||||||
cx.spawn(move |picker, mut cx| async move {
|
cx.spawn(move |picker, mut cx| async move {
|
||||||
let mut actions = picker
|
|
||||||
.update(&mut cx, |this, _| this.delegate.commands.clone())
|
|
||||||
.expect("todo: handle picker no longer being around");
|
|
||||||
// _ = window
|
|
||||||
// .available_actions(view_id, &cx)
|
|
||||||
// .into_iter()
|
|
||||||
// .flatten()
|
|
||||||
// .filter_map(|(name, action, bindings)| {
|
|
||||||
// let filtered = cx.read(|cx| {
|
|
||||||
// if cx.has_global::<CommandPaletteFilter>() {
|
|
||||||
// let filter = cx.global::<CommandPaletteFilter>();
|
|
||||||
// filter.filtered_namespaces.contains(action.namespace())
|
|
||||||
// } else {
|
|
||||||
// false
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if filtered {
|
|
||||||
// None
|
|
||||||
// } else {
|
|
||||||
// Some(Command {
|
|
||||||
// name: humanize_action_name(name),
|
|
||||||
// action,
|
|
||||||
// keystrokes: bindings
|
|
||||||
// .iter()
|
|
||||||
// .map(|binding| binding.keystrokes())
|
|
||||||
// .last()
|
|
||||||
// .map_or(Vec::new(), |keystrokes| keystrokes.to_vec()),
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .collect::<Vec<_>>();
|
|
||||||
|
|
||||||
cx.read_global::<HitCounts, _>(|hit_counts, _| {
|
cx.read_global::<HitCounts, _>(|hit_counts, _| {
|
||||||
actions.sort_by_key(|action| {
|
commands.sort_by_key(|action| {
|
||||||
(
|
(
|
||||||
Reverse(hit_counts.0.get(&action.name).cloned()),
|
Reverse(hit_counts.0.get(&action.name).cloned()),
|
||||||
action.name.clone(),
|
action.name.clone(),
|
||||||
|
@ -209,7 +177,7 @@ impl PickerDelegate for CommandPaletteDelegate {
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
let candidates = actions
|
let candidates = commands
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(ix, command)| StringMatchCandidate {
|
.map(|(ix, command)| StringMatchCandidate {
|
||||||
|
@ -240,15 +208,13 @@ impl PickerDelegate for CommandPaletteDelegate {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
let mut intercept_result = None;
|
|
||||||
// todo!() for vim mode
|
let mut intercept_result = cx
|
||||||
// cx.read(|cx| {
|
.try_read_global(|interceptor: &CommandPaletteInterceptor, cx| {
|
||||||
// if cx.has_global::<CommandPaletteInterceptor>() {
|
(interceptor)(&query, cx)
|
||||||
// cx.global::<CommandPaletteInterceptor>()(&query, cx)
|
})
|
||||||
// } else {
|
.flatten();
|
||||||
// None
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
if *RELEASE_CHANNEL == ReleaseChannel::Dev {
|
if *RELEASE_CHANNEL == ReleaseChannel::Dev {
|
||||||
if parse_zed_link(&query).is_some() {
|
if parse_zed_link(&query).is_some() {
|
||||||
intercept_result = Some(CommandInterceptResult {
|
intercept_result = Some(CommandInterceptResult {
|
||||||
|
@ -266,11 +232,11 @@ impl PickerDelegate for CommandPaletteDelegate {
|
||||||
{
|
{
|
||||||
if let Some(idx) = matches
|
if let Some(idx) = matches
|
||||||
.iter()
|
.iter()
|
||||||
.position(|m| actions[m.candidate_id].action.type_id() == action.type_id())
|
.position(|m| commands[m.candidate_id].action.type_id() == action.type_id())
|
||||||
{
|
{
|
||||||
matches.remove(idx);
|
matches.remove(idx);
|
||||||
}
|
}
|
||||||
actions.push(Command {
|
commands.push(Command {
|
||||||
name: string.clone(),
|
name: string.clone(),
|
||||||
action,
|
action,
|
||||||
keystrokes: vec![],
|
keystrokes: vec![],
|
||||||
|
@ -278,7 +244,7 @@ impl PickerDelegate for CommandPaletteDelegate {
|
||||||
matches.insert(
|
matches.insert(
|
||||||
0,
|
0,
|
||||||
StringMatch {
|
StringMatch {
|
||||||
candidate_id: actions.len() - 1,
|
candidate_id: commands.len() - 1,
|
||||||
string,
|
string,
|
||||||
positions,
|
positions,
|
||||||
score: 0.0,
|
score: 0.0,
|
||||||
|
@ -288,7 +254,8 @@ impl PickerDelegate for CommandPaletteDelegate {
|
||||||
picker
|
picker
|
||||||
.update(&mut cx, |picker, _| {
|
.update(&mut cx, |picker, _| {
|
||||||
let delegate = &mut picker.delegate;
|
let delegate = &mut picker.delegate;
|
||||||
delegate.commands = actions;
|
dbg!(&matches);
|
||||||
|
delegate.commands = commands;
|
||||||
delegate.matches = matches;
|
delegate.matches = matches;
|
||||||
if delegate.matches.is_empty() {
|
if delegate.matches.is_empty() {
|
||||||
delegate.selected_ix = 0;
|
delegate.selected_ix = 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
|
point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element,
|
||||||
ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Point, Size,
|
ElementId, ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Point, Size,
|
||||||
StatefulInteractive, StatefulInteractivity, StatelessInteractive, StatelessInteractivity,
|
StatefulInteractive, StatefulInteractivity, StatelessInteractive, StatelessInteractivity,
|
||||||
StyleRefinement, Styled, ViewContext,
|
StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
|
@ -86,8 +86,14 @@ impl<V: 'static> Styled for UniformList<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct UniformListState {
|
||||||
|
interactive: InteractiveElementState,
|
||||||
|
item_size: Size<Pixels>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<V: 'static> Element<V> for UniformList<V> {
|
impl<V: 'static> Element<V> for UniformList<V> {
|
||||||
type ElementState = InteractiveElementState;
|
type ElementState = UniformListState;
|
||||||
|
|
||||||
fn id(&self) -> Option<crate::ElementId> {
|
fn id(&self) -> Option<crate::ElementId> {
|
||||||
Some(self.id.clone())
|
Some(self.id.clone())
|
||||||
|
@ -95,20 +101,49 @@ impl<V: 'static> Element<V> for UniformList<V> {
|
||||||
|
|
||||||
fn initialize(
|
fn initialize(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &mut V,
|
view_state: &mut V,
|
||||||
element_state: Option<Self::ElementState>,
|
element_state: Option<Self::ElementState>,
|
||||||
_: &mut ViewContext<V>,
|
cx: &mut ViewContext<V>,
|
||||||
) -> Self::ElementState {
|
) -> Self::ElementState {
|
||||||
element_state.unwrap_or_default()
|
element_state.unwrap_or_else(|| {
|
||||||
|
let item_size = self.measure_first_item(view_state, None, cx);
|
||||||
|
UniformListState {
|
||||||
|
interactive: InteractiveElementState::default(),
|
||||||
|
item_size,
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_view_state: &mut V,
|
_view_state: &mut V,
|
||||||
_element_state: &mut Self::ElementState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<V>,
|
cx: &mut ViewContext<V>,
|
||||||
) -> LayoutId {
|
) -> LayoutId {
|
||||||
cx.request_layout(&self.computed_style(), None)
|
let max_items = self.item_count;
|
||||||
|
let item_size = element_state.item_size;
|
||||||
|
let rem_size = cx.rem_size();
|
||||||
|
cx.request_measured_layout(
|
||||||
|
self.computed_style(),
|
||||||
|
rem_size,
|
||||||
|
move |known_dimensions: Size<Option<Pixels>>, available_space: Size<AvailableSpace>| {
|
||||||
|
let desired_height = item_size.height * max_items;
|
||||||
|
let width = known_dimensions
|
||||||
|
.width
|
||||||
|
.unwrap_or(match available_space.width {
|
||||||
|
AvailableSpace::Definite(x) => x,
|
||||||
|
AvailableSpace::MinContent => item_size.width,
|
||||||
|
AvailableSpace::MaxContent => item_size.width,
|
||||||
|
});
|
||||||
|
let height = match available_space.height {
|
||||||
|
AvailableSpace::Definite(x) => desired_height.min(x),
|
||||||
|
AvailableSpace::MinContent => desired_height,
|
||||||
|
AvailableSpace::MaxContent => desired_height,
|
||||||
|
};
|
||||||
|
dbg!(known_dimensions, available_space, size(width, height));
|
||||||
|
size(width, height)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
|
@ -133,12 +168,15 @@ impl<V: 'static> Element<V> for UniformList<V> {
|
||||||
cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
|
cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
|
||||||
let content_size;
|
let content_size;
|
||||||
if self.item_count > 0 {
|
if self.item_count > 0 {
|
||||||
let item_height = self.measure_item_height(view_state, padded_bounds, cx);
|
let item_height = self
|
||||||
|
.measure_first_item(view_state, Some(padded_bounds.size.width), cx)
|
||||||
|
.height;
|
||||||
|
dbg!(item_height, padded_bounds);
|
||||||
if let Some(scroll_handle) = self.scroll_handle.clone() {
|
if let Some(scroll_handle) = self.scroll_handle.clone() {
|
||||||
scroll_handle.0.lock().replace(ScrollHandleState {
|
scroll_handle.0.lock().replace(ScrollHandleState {
|
||||||
item_height,
|
item_height,
|
||||||
list_height: padded_bounds.size.height,
|
list_height: padded_bounds.size.height,
|
||||||
scroll_offset: element_state.track_scroll_offset(),
|
scroll_offset: element_state.interactive.track_scroll_offset(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let visible_item_count = if item_height > px(0.) {
|
let visible_item_count = if item_height > px(0.) {
|
||||||
|
@ -146,7 +184,9 @@ impl<V: 'static> Element<V> for UniformList<V> {
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
dbg!(visible_item_count);
|
||||||
let scroll_offset = element_state
|
let scroll_offset = element_state
|
||||||
|
.interactive
|
||||||
.scroll_offset()
|
.scroll_offset()
|
||||||
.map_or((0.0).into(), |offset| offset.y);
|
.map_or((0.0).into(), |offset| offset.y);
|
||||||
let first_visible_element_ix = (-scroll_offset / item_height).floor() as usize;
|
let first_visible_element_ix = (-scroll_offset / item_height).floor() as usize;
|
||||||
|
@ -190,20 +230,25 @@ impl<V: 'static> Element<V> for UniformList<V> {
|
||||||
let overflow = point(style.overflow.x, Overflow::Scroll);
|
let overflow = point(style.overflow.x, Overflow::Scroll);
|
||||||
|
|
||||||
cx.with_z_index(0, |cx| {
|
cx.with_z_index(0, |cx| {
|
||||||
self.interactivity
|
self.interactivity.paint(
|
||||||
.paint(bounds, content_size, overflow, element_state, cx);
|
bounds,
|
||||||
|
content_size,
|
||||||
|
overflow,
|
||||||
|
&mut element_state.interactive,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> UniformList<V> {
|
impl<V> UniformList<V> {
|
||||||
fn measure_item_height(
|
fn measure_first_item(
|
||||||
&self,
|
&self,
|
||||||
view_state: &mut V,
|
view_state: &mut V,
|
||||||
list_bounds: Bounds<Pixels>,
|
list_width: Option<Pixels>,
|
||||||
cx: &mut ViewContext<V>,
|
cx: &mut ViewContext<V>,
|
||||||
) -> Pixels {
|
) -> Size<Pixels> {
|
||||||
let mut items = (self.render_items)(view_state, 0..1, cx);
|
let mut items = (self.render_items)(view_state, 0..1, cx);
|
||||||
debug_assert!(items.len() == 1);
|
debug_assert!(items.len() == 1);
|
||||||
let mut item_to_measure = items.pop().unwrap();
|
let mut item_to_measure = items.pop().unwrap();
|
||||||
|
@ -212,11 +257,13 @@ impl<V> UniformList<V> {
|
||||||
cx.compute_layout(
|
cx.compute_layout(
|
||||||
layout_id,
|
layout_id,
|
||||||
Size {
|
Size {
|
||||||
width: AvailableSpace::Definite(list_bounds.size.width),
|
width: list_width.map_or(AvailableSpace::MinContent, |width| {
|
||||||
|
AvailableSpace::Definite(width)
|
||||||
|
}),
|
||||||
height: AvailableSpace::MinContent,
|
height: AvailableSpace::MinContent,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
cx.layout_bounds(layout_id).size.height
|
cx.layout_bounds(layout_id).size
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self {
|
pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self {
|
||||||
|
|
|
@ -145,7 +145,7 @@ impl<V> Eq for WeakView<V> {}
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AnyView {
|
pub struct AnyView {
|
||||||
model: AnyModel,
|
model: AnyModel,
|
||||||
pub initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
|
initialize: fn(&AnyView, &mut WindowContext) -> AnyBox,
|
||||||
layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
|
layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
|
||||||
paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
|
paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue