Skip to main content

native_windows_gui2/controls/
treeview_iterator.rs

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