1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::co;
use crate::decl::*;
use crate::gui::*;
use crate::kernel::privs::*;
use crate::msg::*;
use crate::prelude::*;
/// Exposes the methods of a [`Tab`](crate::gui::Tab) control.
///
/// You cannot directly instantiate this object, it is created internally by the
/// control.
pub struct TabItems<'a> {
owner: &'a Tab,
}
impl<'a> TabItems<'a> {
#[must_use]
pub(in crate::gui) const fn new(owner: &'a Tab) -> Self {
Self { owner }
}
/// Manually appends a new tab by sending a
/// [`tcm::InsertItem`](crate::msg::tcm::InsertItem) message, and returns
/// the newly added item.
///
/// # Safety
///
/// By adding a tab item manually, you are responsible for all the message
/// handling. Prefer adding items automatically by filling the
/// [`TabOpts::pages`](crate::gui::TabOpts::pages) member when calling the
/// [`Tab::new`](crate::gui::Tab::new) function.
pub unsafe fn add(&self, title: &str) -> TabItem<'a> {
let mut wtitle = WString::from_str(title);
let mut tci = TCITEM::default();
tci.mask = co::TCIF::TEXT;
tci.set_pszText(Some(&mut wtitle));
let idx = unsafe {
self.owner.hwnd().SendMessage(tcm::InsertItem {
index: 0x0fff_ffff, // insert as the last item
item: &tci,
})
}
.unwrap();
self.get(idx)
}
/// Retrieves the total number of items by sending an
/// [`tcm::GetItemCount`](crate::msg::tcm::GetItemCount) message.
#[must_use]
pub fn count(&self) -> SysResult<u32> {
unsafe { self.owner.hwnd().SendMessage(tcm::GetItemCount {}) }
}
/// Deletes all items by sending a
/// [`tcm::DeleteAllItems`](crate::msg::tcm::DeleteAllItems) message.
///
/// # Safety
///
/// If you delete a tab automatically created, which has a container window
/// attached to it, the rendering will be out-of-order.
pub unsafe fn delete_all(&self) -> SysResult<()> {
unsafe { self.owner.hwnd().SendMessage(tcm::DeleteAllItems {}) }
}
/// Retrieves the item at the given zero-based position.
///
/// **Note:** This method is cheap – even if `index` is beyond the range of
/// existing items, an object will still be returned. However, operations
/// upon this object will produce no effect.
#[must_use]
pub const fn get(&self, index: u32) -> TabItem<'a> {
TabItem::new(self.owner, index)
}
/// Returns an iterator over all items.
#[must_use]
pub fn iter(&self) -> SysResult<impl DoubleEndedIterator<Item = TabItem<'a>> + 'a> {
TabItemIter::new(self.owner)
}
/// Returns the focused item by sending a
/// [`tcm::GetCurFocus`](crate::msg::tcm::GetCurFocus) message.
#[must_use]
pub fn focused(&self) -> Option<TabItem<'a>> {
unsafe { self.owner.hwnd().SendMessage(tcm::GetCurFocus {}) }.map(|i| self.get(i))
}
/// Returns the selected item by sending a
/// [`tcm::GetCurSel`](crate::msg::tcm::GetCurSel) message.
#[must_use]
pub fn selected(&self) -> Option<TabItem<'a>> {
unsafe { self.owner.hwnd().SendMessage(tcm::GetCurSel {}) }.map(|i| self.get(i))
}
}
struct TabItemIter<'a> {
owner: &'a Tab,
double_idx: DoubleIterIndex,
}
impl<'a> Iterator for TabItemIter<'a> {
type Item = TabItem<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.grab(true)
}
}
impl<'a> DoubleEndedIterator for TabItemIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.grab(false)
}
}
impl<'a> TabItemIter<'a> {
#[must_use]
fn new(owner: &'a Tab) -> SysResult<Self> {
Ok(Self {
owner,
double_idx: DoubleIterIndex::new(owner.items().count()?),
})
}
fn grab(&mut self, is_front: bool) -> Option<TabItem<'a>> {
self.double_idx.grab(is_front, |cur_idx| {
let item = self.owner.items().get(cur_idx);
DoubleIter::Yield(item)
})
}
}