add tree
This commit is contained in:
@@ -24,6 +24,7 @@ use gpui_native_core::toast::{Toast, ToastSeverity, Toasts, ToastsView};
|
||||
use gpui_native_core::toggle::Toggle;
|
||||
use gpui_native_core::tooltip::Tooltip;
|
||||
use gpui_native_data::list::{List, ListItem};
|
||||
use gpui_native_data::tree::{Tree, TreeItem};
|
||||
use gpui_native_icons::{IconAssets, IconRole, icon};
|
||||
use gpui_native_theme::{ActiveTheme as _, Theme};
|
||||
use gpui_platform::application;
|
||||
@@ -43,6 +44,66 @@ struct Gallery {
|
||||
toasts: Entity<Toasts>,
|
||||
scroll: gpui::ScrollHandle,
|
||||
list_selected: Option<usize>,
|
||||
tree_nodes: Vec<GalleryNode>,
|
||||
tree_selected: Option<usize>,
|
||||
}
|
||||
|
||||
/// A demo model for the tree section: the app owns the real tree and its
|
||||
/// expansion set, and flattens the visible nodes for the component.
|
||||
#[derive(Clone)]
|
||||
struct GalleryNode {
|
||||
label: SharedString,
|
||||
icon: Option<IconRole>,
|
||||
expanded: bool,
|
||||
children: Vec<GalleryNode>,
|
||||
}
|
||||
|
||||
fn flatten_tree(
|
||||
nodes: &[GalleryNode],
|
||||
depth: usize,
|
||||
prefix: &[usize],
|
||||
items: &mut Vec<TreeItem>,
|
||||
paths: &mut Vec<Vec<usize>>,
|
||||
) {
|
||||
for (index, node) in nodes.iter().enumerate() {
|
||||
let mut path = prefix.to_vec();
|
||||
path.push(index);
|
||||
|
||||
let mut item = TreeItem::new(node.label.clone())
|
||||
.depth(depth)
|
||||
.expandable(!node.children.is_empty())
|
||||
.expanded(node.expanded);
|
||||
if let Some(role) = node.icon {
|
||||
item = item.icon(role);
|
||||
}
|
||||
items.push(item);
|
||||
paths.push(path.clone());
|
||||
|
||||
if node.expanded {
|
||||
flatten_tree(&node.children, depth + 1, &path, items, paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_tree_path(nodes: &mut [GalleryNode], path: &[usize]) {
|
||||
let Some(index) = path.first() else { return };
|
||||
let Some(node) = nodes.get_mut(*index) else {
|
||||
return;
|
||||
};
|
||||
if path.len() == 1 {
|
||||
node.expanded = !node.expanded;
|
||||
} else {
|
||||
toggle_tree_path(&mut node.children, &path[1..]);
|
||||
}
|
||||
}
|
||||
|
||||
/// The visible-row paths of the current tree state, matching the flat index
|
||||
/// the tree component reports.
|
||||
fn tree_paths(nodes: &[GalleryNode]) -> Vec<Vec<usize>> {
|
||||
let mut items = Vec::new();
|
||||
let mut paths = Vec::new();
|
||||
flatten_tree(nodes, 0, &[], &mut items, &mut paths);
|
||||
paths
|
||||
}
|
||||
|
||||
impl Render for Gallery {
|
||||
@@ -377,6 +438,40 @@ impl Render for Gallery {
|
||||
.child(format!("selected: {:?}", self.list_selected)),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_2()
|
||||
.child(section_label(
|
||||
"tree · native refs — NSOutlineView, WinUI TreeView, Adwaita expander rows, Breeze",
|
||||
colors,
|
||||
))
|
||||
.child({
|
||||
let gallery = gallery.clone();
|
||||
let disclosure_gallery = gallery.clone();
|
||||
let mut items = Vec::new();
|
||||
let mut paths = Vec::new();
|
||||
flatten_tree(&self.tree_nodes, 0, &[], &mut items, &mut paths);
|
||||
|
||||
Tree::new("gallery-tree")
|
||||
.selected(self.tree_selected)
|
||||
.on_change(move |selected, _, cx| {
|
||||
gallery.update(cx, |gallery, cx| {
|
||||
gallery.tree_selected = selected;
|
||||
cx.notify();
|
||||
});
|
||||
})
|
||||
.on_disclosure(move |index, _, cx| {
|
||||
disclosure_gallery.update(cx, |gallery, cx| {
|
||||
let paths = tree_paths(&gallery.tree_nodes);
|
||||
if let Some(path) = paths.get(index) {
|
||||
toggle_tree_path(&mut gallery.tree_nodes, path);
|
||||
}
|
||||
cx.notify();
|
||||
});
|
||||
})
|
||||
.items(move |_, _| items.clone())
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_2()
|
||||
@@ -996,6 +1091,64 @@ fn main() {
|
||||
toasts,
|
||||
scroll: gpui::ScrollHandle::new(),
|
||||
list_selected: None,
|
||||
tree_selected: None,
|
||||
tree_nodes: vec![
|
||||
GalleryNode {
|
||||
label: "Workspace".into(),
|
||||
icon: Some(IconRole::Folder),
|
||||
expanded: true,
|
||||
children: vec![GalleryNode {
|
||||
label: "gpui-native-kit".into(),
|
||||
icon: Some(IconRole::Folder),
|
||||
expanded: true,
|
||||
children: vec![
|
||||
GalleryNode {
|
||||
label: "crates".into(),
|
||||
icon: Some(IconRole::Folder),
|
||||
expanded: true,
|
||||
children: vec![
|
||||
GalleryNode {
|
||||
label: "theme".into(),
|
||||
icon: None,
|
||||
expanded: false,
|
||||
children: Vec::new(),
|
||||
},
|
||||
GalleryNode {
|
||||
label: "core".into(),
|
||||
icon: None,
|
||||
expanded: false,
|
||||
children: Vec::new(),
|
||||
},
|
||||
GalleryNode {
|
||||
label: "data".into(),
|
||||
icon: None,
|
||||
expanded: false,
|
||||
children: Vec::new(),
|
||||
},
|
||||
],
|
||||
},
|
||||
GalleryNode {
|
||||
label: "docs".into(),
|
||||
icon: Some(IconRole::Folder),
|
||||
expanded: false,
|
||||
children: Vec::new(),
|
||||
},
|
||||
GalleryNode {
|
||||
label: "Cargo.toml".into(),
|
||||
icon: None,
|
||||
expanded: false,
|
||||
children: Vec::new(),
|
||||
},
|
||||
],
|
||||
}],
|
||||
},
|
||||
GalleryNode {
|
||||
label: "Archive.zip".into(),
|
||||
icon: None,
|
||||
expanded: false,
|
||||
children: Vec::new(),
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user