native_windows_gui/controls/
treeview_iterator.rs

1use winapi::shared::windef::HWND;
2use winapi::um::commctrl::{HTREEITEM, TVGN_ROOT, TVGN_CHILD, TVGN_NEXT, TVGN_PARENT};
3use crate::{TreeView, TreeItem};
4use crate::win32::window_helper as wh;
5
6
7#[derive(Copy, Clone)]
8#[repr(usize)]
9enum NextAction {
10    Root = TVGN_ROOT,
11    Child = TVGN_CHILD,
12    Sibling = TVGN_NEXT,
13    Parent = TVGN_PARENT,
14}
15
16/** 
17A structure to iterate over the items of a `TreeView`
18Requires the feature `tree-view-iterator` and `tree-view`
19
20```rust
21use native_windows_gui as nwg;
22fn iter_tree_view(tree: &mut nwg::TreeView) {
23    for item in tree.iter() {
24        println!("{:?}", tree.item_text(&item));
25    }
26}
27```
28*/
29#[allow(unused)]
30pub struct TreeViewIterator<'a> {
31    tree_view: &'a TreeView,
32    tree_view_handle: HWND,
33    base_item: HTREEITEM,
34    current_item: HTREEITEM,
35    action: NextAction,
36}
37
38impl<'a> TreeViewIterator<'a> {
39
40    /// Use `TreeView.iter` to create a `TreeViewIterator`
41    pub(crate) fn new(tree_view: &'a TreeView, current_item: HTREEITEM) -> TreeViewIterator {
42        let tree_view_handle = tree_view.handle.hwnd().unwrap();
43
44        let action = match current_item.is_null() {
45            true => NextAction::Root,
46            false => NextAction::Child
47        };
48
49        TreeViewIterator {
50            tree_view,
51            tree_view_handle,
52            base_item: current_item,
53            current_item,
54            action,
55        }
56    }
57
58}
59
60impl<'a> Iterator for TreeViewIterator<'a> {
61    type Item = TreeItem;
62
63    fn next(&mut self) -> Option<TreeItem> {
64        use NextAction::*;
65
66        let mut item: Option<TreeItem>;
67
68        loop {
69            item = next_item(self.tree_view_handle, self.action, self.current_item);
70            self.action = match (self.action, item.is_some()) {
71                (Root, _) => Child,
72                (Child, true) => Child,
73                (Child, false) => Sibling,
74                (Sibling, true) => Child,
75                (Sibling, false) => Parent,
76                (Parent, true) => {
77                    // Use the parent as current item for the next loop run
78                    self.current_item = item.as_ref().map(|i| i.handle).unwrap();
79
80                    // If we are iterating over an item, and we are back to it, finish the iteration.
81                    if self.base_item == self.current_item {
82                        return None;
83                    }
84
85                    // Do not return parents has they have already been iterated upon
86                    item = None;  
87
88                    Sibling
89                }
90                (Parent, false) => { return None; }
91            };
92
93            if item.is_some() {
94                self.current_item = item.as_ref().map(|i| i.handle).unwrap();
95                break;
96            }
97        }
98
99        item
100    }
101}
102
103
104fn next_item(tree: HWND, action: NextAction, handle: HTREEITEM) -> Option<TreeItem> {
105    use winapi::shared::minwindef::{WPARAM, LPARAM};
106    use winapi::um::commctrl::TVM_GETNEXTITEM;
107
108    let handle = wh::send_message(tree, TVM_GETNEXTITEM, action as WPARAM, handle as LPARAM) as HTREEITEM;
109    if handle.is_null() {
110        None
111    } else {
112        Some(TreeItem { handle })
113    }
114}