Skip to content

Commit

Permalink
Add virtual_list with selections (#251)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoxc authored Jan 3, 2024
1 parent f982ba9 commit b4b5a19
Show file tree
Hide file tree
Showing 19 changed files with 444 additions and 126 deletions.
8 changes: 4 additions & 4 deletions examples/layout/src/draggable_sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use floem::{
style::{CursorStyle, Position},
view::View,
views::{
container, h_stack, label, scroll, virtual_stack, Decorators, VirtualStackDirection,
VirtualStackItemSize,
container, h_stack, label, scroll, virtual_stack, Decorators, VirtualDirection,
VirtualItemSize,
},
EventPropagation,
};
Expand All @@ -21,8 +21,8 @@ pub fn draggable_sidebar_view() -> impl View {

let side_bar = scroll({
virtual_stack(
VirtualStackDirection::Vertical,
VirtualStackItemSize::Fixed(Box::new(|| 22.0)),
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(|| 22.0)),
move || long_list.get(),
move |item| *item,
move |item| {
Expand Down
12 changes: 6 additions & 6 deletions examples/layout/src/holy_grail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use floem::{
style::Position,
view::View,
views::{
container, h_stack, label, scroll, v_stack, virtual_stack, Decorators,
VirtualStackDirection, VirtualStackItemSize,
container, h_stack, label, scroll, v_stack, virtual_stack, Decorators, VirtualDirection,
VirtualItemSize,
},
};

Expand All @@ -22,8 +22,8 @@ pub fn holy_grail_view() -> impl View {

let side_bar_right = scroll({
virtual_stack(
VirtualStackDirection::Vertical,
VirtualStackItemSize::Fixed(Box::new(|| 22.0)),
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(|| 22.0)),
move || long_list.get(),
move |item| *item,
move |item| {
Expand All @@ -49,8 +49,8 @@ pub fn holy_grail_view() -> impl View {

let side_bar_left = scroll({
virtual_stack(
VirtualStackDirection::Vertical,
VirtualStackItemSize::Fixed(Box::new(|| 22.0)),
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(|| 22.0)),
move || long_list.get(),
move |item| *item,
move |item| {
Expand Down
8 changes: 4 additions & 4 deletions examples/layout/src/left_sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use floem::{
style::Position,
view::View,
views::{
container, h_stack, label, scroll, v_stack, virtual_stack, Decorators,
VirtualStackDirection, VirtualStackItemSize,
container, h_stack, label, scroll, v_stack, virtual_stack, Decorators, VirtualDirection,
VirtualItemSize,
},
};

Expand All @@ -22,8 +22,8 @@ pub fn left_sidebar_view() -> impl View {

let side_bar = scroll({
virtual_stack(
VirtualStackDirection::Vertical,
VirtualStackItemSize::Fixed(Box::new(|| 22.0)),
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(|| 22.0)),
move || long_list.get(),
move |item| *item,
move |item| {
Expand Down
8 changes: 4 additions & 4 deletions examples/layout/src/right_sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use floem::{
style::Position,
view::View,
views::{
container, h_stack, label, scroll, v_stack, virtual_stack, Decorators,
VirtualStackDirection, VirtualStackItemSize,
container, h_stack, label, scroll, v_stack, virtual_stack, Decorators, VirtualDirection,
VirtualItemSize,
},
};

Expand All @@ -22,8 +22,8 @@ pub fn right_sidebar_view() -> impl View {

let side_bar = scroll({
virtual_stack(
VirtualStackDirection::Vertical,
VirtualStackItemSize::Fixed(Box::new(|| 22.0)),
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(|| 22.0)),
move || long_list.get(),
move |item| *item,
move |item| {
Expand Down
6 changes: 3 additions & 3 deletions examples/virtual_list/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use floem::{
view::View,
views::virtual_stack,
views::Decorators,
views::{container, label, scroll, VirtualStackDirection, VirtualStackItemSize},
views::{container, label, scroll, VirtualDirection, VirtualItemSize},
};

fn app_view() -> impl View {
Expand All @@ -14,8 +14,8 @@ fn app_view() -> impl View {
container(
scroll(
virtual_stack(
VirtualStackDirection::Vertical,
VirtualStackItemSize::Fixed(Box::new(|| 20.0)),
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(|| 20.0)),
move || long_list.get(),
move |item| *item,
move |item| label(move || item.to_string()).style(|s| s.height(20.0)),
Expand Down
70 changes: 14 additions & 56 deletions examples/widget-gallery/src/lists.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
use floem::{
cosmic_text::Weight,
event::{Event, EventListener},
keyboard::{Key, NamedKey},
peniko::Color,
reactive::create_signal,
style::{CursorStyle, JustifyContent},
style::JustifyContent,
view::View,
views::{
container, label, scroll, stack, virtual_stack, Decorators, VirtualStackDirection,
VirtualStackItemSize,
container, label, scroll, stack, Decorators, VirtualDirection, VirtualItemSize,
VirtualVector,
},
widgets::{checkbox, list},
EventPropagation,
widgets::{checkbox, list, virtual_list},
};

use crate::form::{form, form_item};
Expand All @@ -37,21 +34,15 @@ fn enhanced_list() -> impl View {
let long_list: im::Vector<i32> = (0..100).collect();
let (long_list, set_long_list) = create_signal(long_list);

let (selected, set_selected) = create_signal(0);
let list_width = 180.0;
let item_height = 32.0;
scroll(
virtual_stack(
VirtualStackDirection::Vertical,
VirtualStackItemSize::Fixed(Box::new(|| 32.0)),
move || long_list.get(),
move |item| *item,
move |item| {
let index = long_list
.get_untracked()
.iter()
.position(|it| *it == item)
.unwrap();
virtual_list(
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(|| 32.0)),
move || long_list.get().enumerate(),
move |(_, item)| *item,
move |(index, item)| {
let (is_checked, set_is_checked) = create_signal(true);
container({
stack({
Expand Down Expand Up @@ -87,45 +78,12 @@ fn enhanced_list() -> impl View {
}),
)
})
.style(move |s| s.height(item_height).width_full().items_center())
.style(move |s| s.height_full().width_full().items_center())
})
.on_click_stop(move |_| {
set_selected.update(|v: &mut usize| {
*v = long_list.get().iter().position(|it| *it == item).unwrap();
});
})
.on_event(EventListener::KeyDown, move |e| {
if let Event::KeyDown(key_event) = e {
let sel = selected.get();
match key_event.key.logical_key {
Key::Named(NamedKey::ArrowUp) => {
if sel > 0 {
set_selected.update(|v| *v -= 1);
}
EventPropagation::Stop
}
Key::Named(NamedKey::ArrowDown) => {
if sel < long_list.get().len() - 1 {
set_selected.update(|v| *v += 1);
}
EventPropagation::Stop
}
_ => EventPropagation::Continue,
}
} else {
EventPropagation::Continue
}
})
.keyboard_navigatable()
.style(move |s| {
s.flex_row()
.height(item_height)
.apply_if(index == selected.get(), |s| s.background(Color::GRAY))
.apply_if(index != 0, |s| {
s.border_top(1.0).border_color(Color::LIGHT_GRAY)
})
.focus_visible(|s| s.border(2.).border_color(Color::BLUE))
.hover(|s| s.background(Color::LIGHT_GRAY).cursor(CursorStyle::Pointer))
s.flex_row().height(item_height).apply_if(index != 0, |s| {
s.border_top(1.0).border_color(Color::LIGHT_GRAY)
})
})
},
)
Expand Down
6 changes: 3 additions & 3 deletions examples/widget-gallery/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use floem::{
view::View,
views::{
container, container_box, h_stack, label, scroll, stack, tab, v_stack, virtual_stack,
Decorators, VirtualStackDirection, VirtualStackItemSize,
Decorators, VirtualDirection, VirtualItemSize,
},
widgets::button,
EventPropagation,
Expand All @@ -45,8 +45,8 @@ fn app_view() -> impl View {

let list = scroll({
virtual_stack(
VirtualStackDirection::Vertical,
VirtualStackItemSize::Fixed(Box::new(|| 36.0)),
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(|| 36.0)),
move || tabs.get(),
move |item| *item,
move |item| {
Expand Down
1 change: 1 addition & 0 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,7 @@ impl<'a> ComputeLayoutCx<'a> {
.get_mut(&id)
.and_then(|s| s.move_listener.as_mut())
}

/// Internal method used by Floem. This method derives its calculations based on the [Taffy Node](taffy::prelude::Node) returned by the `View::layout` method.
///
/// It's responsible for:
Expand Down
6 changes: 3 additions & 3 deletions src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use std::{any::Any, cell::RefCell, collections::HashMap, sync::atomic::AtomicU64};

use kurbo::Point;
use kurbo::{Point, Rect};

use crate::{
animate::Animation,
Expand Down Expand Up @@ -217,8 +217,8 @@ impl Id {
self.add_update_message(UpdateMessage::PopoutMenu { id: *self, menu });
}

pub fn scroll_to(&self) {
self.add_update_message(UpdateMessage::ScrollTo { id: *self });
pub fn scroll_to(&self, rect: Option<Rect>) {
self.add_update_message(UpdateMessage::ScrollTo { id: *self, rect });
}

pub fn inspect(&self) {
Expand Down
3 changes: 2 additions & 1 deletion src/update.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{any::Any, cell::RefCell, collections::HashMap};

use kurbo::{Point, Size, Vec2};
use kurbo::{Point, Rect, Size, Vec2};
use winit::window::ResizeDirection;

use crate::{
Expand Down Expand Up @@ -124,6 +124,7 @@ pub(crate) enum UpdateMessage {
Inspect,
ScrollTo {
id: Id,
rect: Option<Rect>,
},
FocusWindow,
SetImeAllowed {
Expand Down
8 changes: 4 additions & 4 deletions src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,13 @@ pub trait View {

/// Scrolls the view and all direct and indirect children to bring the `target` view to be
/// visible. Returns true if this view contains or is the target.
fn scroll_to(&mut self, cx: &mut AppState, target: Id) -> bool {
fn scroll_to(&mut self, cx: &mut AppState, target: Id, rect: Option<Rect>) -> bool {
if self.id() == target {
return true;
}
let mut found = false;
self.for_each_child_mut(&mut |child| {
found |= child.scroll_to(cx, target);
found |= child.scroll_to(cx, target, rect);
found
});
found
Expand Down Expand Up @@ -700,7 +700,7 @@ impl View for Box<dyn View> {
(**self).paint(cx)
}

fn scroll_to(&mut self, cx: &mut AppState, target: Id) -> bool {
(**self).scroll_to(cx, target)
fn scroll_to(&mut self, cx: &mut AppState, target: Id, rect: Option<Rect>) -> bool {
(**self).scroll_to(cx, target, rect)
}
}
12 changes: 6 additions & 6 deletions src/views/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ enum ListUpdate {
ScrollToSelected,
}

struct Item {
data: ViewData,
index: usize,
selection: RwSignal<Option<usize>>,
child: Box<dyn View>,
pub(crate) struct Item {
pub(crate) data: ViewData,
pub(crate) index: usize,
pub(crate) selection: RwSignal<Option<usize>>,
pub(crate) child: Box<dyn View>,
}

pub struct List {
Expand Down Expand Up @@ -171,7 +171,7 @@ impl View for List {
}
ListUpdate::ScrollToSelected => {
if let Some(index) = self.selection.get_untracked() {
self.child.children[index].id().scroll_to();
self.child.children[index].id().scroll_to(None);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/views/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub use decorator::*;
mod list;
pub use list::*;

mod virtual_list;
pub use virtual_list::*;

mod virtual_stack;
pub use virtual_stack::*;

Expand Down
28 changes: 22 additions & 6 deletions src/views/scroll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,9 +580,25 @@ impl Scroll {
}
}

fn do_scroll_to_view(&mut self, app_state: &mut AppState, target: Id) {
fn do_scroll_to_view(
&mut self,
app_state: &mut AppState,
target: Id,
target_rect: Option<Rect>,
) {
if app_state.get_layout(target).is_some() && !app_state.is_hidden_recursive(target) {
let rect = app_state.get_layout_rect(target);
let mut rect = app_state.get_layout_rect(target);

if let Some(target_rect) = target_rect {
rect = rect + target_rect.origin().to_vec2();

let new_size = target_rect
.size()
.to_rect()
.intersect(rect.size().to_rect())
.size();
rect = rect.with_size(new_size);
}

// `get_layout_rect` is window-relative so we have to
// convert it to child view relative.
Expand Down Expand Up @@ -651,7 +667,7 @@ impl View for Scroll {
self.scroll_to(cx.app_state, point);
}
ScrollState::ScrollToView(id) => {
self.do_scroll_to_view(cx.app_state, id);
self.do_scroll_to_view(cx.app_state, id, None);
}
ScrollState::HiddenBar(hide) => {
self.hide = hide;
Expand All @@ -667,10 +683,10 @@ impl View for Scroll {
}
}

fn scroll_to(&mut self, cx: &mut AppState, target: Id) -> bool {
let found = self.child.scroll_to(cx, target);
fn scroll_to(&mut self, cx: &mut AppState, target: Id, rect: Option<Rect>) -> bool {
let found = self.child.scroll_to(cx, target, rect);
if found {
self.do_scroll_to_view(cx, target);
self.do_scroll_to_view(cx, target, rect);
}
found
}
Expand Down
Loading

0 comments on commit b4b5a19

Please sign in to comment.