11use iced:: widget:: text:: Wrapping ;
22use iced:: widget:: { column, container, row, scrollable, svg, text} ;
33use iced:: { Element , Length , alignment} ;
4+ use otty_ui_tree:: { TreeNode , TreeRowContext , TreeView } ;
45
56use crate :: icons:: { FILE , FOLDER , FOLDER_OPENED } ;
67use crate :: style:: { thin_scroll_style, tree_row_style} ;
78use crate :: theme:: { IcedColorPalette , ThemeProps } ;
89use crate :: widgets:: explorer:: event:: ExplorerIntent ;
9- use crate :: widgets:: explorer:: model:: {
10- ExplorerTreeViewModel , FileNode , TreePath ,
11- } ;
10+ use crate :: widgets:: explorer:: model:: { ExplorerTreeViewModel , FileNode } ;
1211
1312const HEADER_HEIGHT : f32 = 22.0 ;
1413const HEADER_PADDING_X : f32 = 10.0 ;
@@ -117,24 +116,19 @@ fn explorer_tree<'a>(
117116 vm : & ExplorerTreeViewModel < ' a > ,
118117 palette : & ' a IcedColorPalette ,
119118) -> Element < ' a , ExplorerIntent , iced:: Theme , iced:: Renderer > {
120- let mut entries: Vec <
121- Element < ' _ , ExplorerIntent , iced:: Theme , iced:: Renderer > ,
122- > = Vec :: new ( ) ;
123-
124- render_children ( vm. tree , & [ ] , 0 , vm, palette, & mut entries) ;
125-
126- if entries. is_empty ( ) {
127- entries. push (
128- container ( iced:: widget:: Space :: new ( ) )
129- . width ( Length :: Fill )
130- . height ( Length :: Fill )
131- . into ( ) ,
132- ) ;
133- }
134-
135- let content = column ( entries) . width ( Length :: Fill ) . spacing ( 0 ) ;
136-
137- let scrollable = scrollable:: Scrollable :: new ( content)
119+ let icon_color = palette. dim_foreground ;
120+ let tree_view = TreeView :: new ( vm. tree , move |context| {
121+ render_entry ( context, icon_color)
122+ } )
123+ . selected_row ( vm. selected_path )
124+ . hovered_row ( vm. hovered_path )
125+ . on_press ( |path| ExplorerIntent :: NodePressed { path } )
126+ . on_hover ( |path| ExplorerIntent :: NodeHovered { path } )
127+ . row_style ( move |context| nav_row_style ( palette, context) )
128+ . indent_size ( TREE_INDENT )
129+ . spacing ( 0.0 ) ;
130+
131+ let scrollable = scrollable:: Scrollable :: new ( tree_view. view ( ) )
138132 . width ( Length :: Fill )
139133 . height ( Length :: Fill )
140134 . direction ( scrollable:: Direction :: Vertical (
@@ -151,59 +145,12 @@ fn explorer_tree<'a>(
151145 . into ( )
152146}
153147
154- /// Recursively render tree children.
155- fn render_children < ' a > (
156- children : & ' a [ FileNode ] ,
157- parent_path : & [ String ] ,
158- depth : usize ,
159- vm : & ExplorerTreeViewModel < ' a > ,
160- palette : & ' a IcedColorPalette ,
161- entries : & mut Vec < Element < ' a , ExplorerIntent , iced:: Theme , iced:: Renderer > > ,
162- ) {
163- for node in children {
164- let mut path = parent_path. to_vec ( ) ;
165- path. push ( node. name ( ) . to_string ( ) ) ;
166-
167- let is_selected = vm. selected_path . map ( |s| s == & path) . unwrap_or ( false ) ;
168- let is_hovered = vm. hovered_path . map ( |h| h == & path) . unwrap_or ( false ) ;
169-
170- entries. push ( render_tree_row (
171- node,
172- & path,
173- depth,
174- is_selected,
175- is_hovered,
176- palette,
177- ) ) ;
178-
179- // Recurse into expanded folders.
180- if node. is_folder ( ) && node. is_expanded ( ) {
181- render_children (
182- node. children ( ) ,
183- & path,
184- depth + 1 ,
185- vm,
186- palette,
187- entries,
188- ) ;
189- }
190- }
191- }
192-
193- /// Render a single tree row with icon, label, and interaction events.
194- fn render_tree_row < ' a > (
195- node : & ' a FileNode ,
196- path : & TreePath ,
197- depth : usize ,
198- is_selected : bool ,
199- is_hovered : bool ,
200- palette : & ' a IcedColorPalette ,
148+ fn render_entry < ' a > (
149+ context : & TreeRowContext < ' a , FileNode > ,
150+ icon_color : iced:: Color ,
201151) -> Element < ' a , ExplorerIntent , iced:: Theme , iced:: Renderer > {
202- let indent = depth as f32 * TREE_INDENT ;
203-
204- let icon_color = palette. dim_foreground ;
205- let icon_data = if node. is_folder ( ) {
206- if node. is_expanded ( ) {
152+ let icon_data = if context. entry . node . is_folder ( ) {
153+ if context. entry . node . is_expanded ( ) {
207154 FOLDER_OPENED
208155 } else {
209156 FOLDER
@@ -228,7 +175,7 @@ fn render_tree_row<'a>(
228175 } ;
229176
230177 let title = container (
231- text ( node. name ( ) )
178+ text ( context . entry . node . name ( ) )
232179 . size ( TREE_FONT_SIZE )
233180 . width ( Length :: Fill )
234181 . wrapping ( Wrapping :: None )
@@ -242,32 +189,42 @@ fn render_tree_row<'a>(
242189 . spacing ( 0 )
243190 . align_y ( alignment:: Vertical :: Center ) ;
244191
245- let content = row ! [
246- iced:: widget:: Space :: new( ) . width( Length :: Fixed ( indent) ) ,
247- leading,
248- title,
249- ]
250- . spacing ( TREE_ROW_SPACING )
251- . align_y ( alignment:: Vertical :: Center ) ;
192+ container (
193+ row ! [ leading, title]
194+ . spacing ( TREE_ROW_SPACING )
195+ . align_y ( alignment:: Vertical :: Center ) ,
196+ )
197+ . width ( Length :: Fill )
198+ . height ( Length :: Fixed ( TREE_ROW_HEIGHT ) )
199+ . padding ( [ 0.0 , TREE_ROW_PADDING_X ] )
200+ . into ( )
201+ }
252202
253- let row_style = tree_row_style ( palette, is_selected, is_hovered) ;
203+ fn nav_row_style (
204+ palette : & IcedColorPalette ,
205+ context : & TreeRowContext < ' _ , FileNode > ,
206+ ) -> iced:: widget:: container:: Style {
207+ tree_row_style ( palette, context. is_selected , context. is_hovered )
208+ }
254209
255- let styled_row = container ( content)
256- . width ( Length :: Fill )
257- . height ( Length :: Fixed ( TREE_ROW_HEIGHT ) )
258- . padding ( [ 0.0 , TREE_ROW_PADDING_X ] )
259- . style ( move |_| row_style) ;
210+ impl TreeNode for FileNode {
211+ fn title ( & self ) -> & str {
212+ self . name ( )
213+ }
260214
261- let path_for_hover = path. clone ( ) ;
262- let path_for_press = path. clone ( ) ;
215+ fn children ( & self ) -> Option < & [ Self ] > {
216+ if self . is_folder ( ) {
217+ Some ( self . children ( ) )
218+ } else {
219+ None
220+ }
221+ }
263222
264- let interactive = iced:: widget:: mouse_area ( styled_row)
265- . on_enter ( ExplorerIntent :: NodeHovered {
266- path : Some ( path_for_hover) ,
267- } )
268- . on_press ( ExplorerIntent :: NodePressed {
269- path : path_for_press,
270- } ) ;
223+ fn expanded ( & self ) -> bool {
224+ self . is_expanded ( )
225+ }
271226
272- interactive. into ( )
227+ fn is_folder ( & self ) -> bool {
228+ self . is_folder ( )
229+ }
273230}
0 commit comments