use super::{ControlBase, ControlHandle};
use crate::win32::base_helper::{check_hwnd, from_utf16, to_utf16};
use crate::win32::window_helper as wh;
use crate::{Font, NwgError};
use std::{mem, ptr};
use winapi::shared::minwindef::{LPARAM, WPARAM};
use winapi::um::commctrl::{HTREEITEM, TVIS_EXPANDED, TVIS_SELECTED, TVITEMW, TVS_SHOWSELALWAYS};
use winapi::um::winuser::{WS_DISABLED, WS_TABSTOP, WS_VISIBLE};
#[cfg(feature = "image-list")]
use winapi::um::commctrl::HIMAGELIST;
#[cfg(feature = "image-list")]
use crate::ImageList;
const NOT_BOUND: &'static str = "TreeView is not yet bound to a winapi object";
const BAD_HANDLE: &'static str = "INTERNAL ERROR: TreeView handle is not HWND!";
bitflags! {
pub struct TreeViewFlags: u32 {
const VISIBLE = WS_VISIBLE;
const DISABLED = WS_DISABLED;
const TAB_STOP = WS_TABSTOP;
const ALWAYS_SHOW_SELECTION = TVS_SHOWSELALWAYS;
}
}
bitflags! {
pub struct TreeItemState: u32 {
const SELECTED = TVIS_SELECTED;
const EXPANDED = TVIS_EXPANDED;
}
}
#[derive(Copy, Clone, Debug)]
pub enum TreeInsert {
First,
Last,
Root,
Sort,
After(HTREEITEM),
}
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum ExpandState {
Collapse,
CollapseReset,
Expand,
ExpandPartial,
Toggle,
}
#[derive(Copy, Clone, Debug)]
pub enum TreeItemAction {
Unknown,
Expand(ExpandState),
State {
old: TreeItemState,
new: TreeItemState,
},
}
#[derive(Debug)]
pub struct TreeItem {
pub handle: HTREEITEM,
}
impl TreeItem {
pub fn is_null(&self) -> bool {
self.handle.is_null()
}
}
#[derive(Default, PartialEq, Eq)]
pub struct TreeView {
pub handle: ControlHandle,
}
impl TreeView {
pub fn builder<'a>() -> TreeViewBuilder<'a> {
TreeViewBuilder {
size: (100, 200),
position: (0, 0),
enabled: true,
focus: false,
flags: None,
ex_flags: 0,
font: None,
parent: None,
#[cfg(feature = "image-list")]
image_list: None,
}
}
#[cfg(feature = "image-list")]
pub fn set_image_list(&self, list: Option<&ImageList>) {
use winapi::um::commctrl::{TVM_SETIMAGELIST, TVSIL_NORMAL};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let list_handle = list.map(|l| l.handle).unwrap_or(ptr::null_mut());
wh::send_message(handle, TVM_SETIMAGELIST, TVSIL_NORMAL, list_handle as _);
}
#[cfg(feature = "image-list")]
pub fn image_list(&self) -> Option<ImageList> {
use winapi::um::commctrl::{TVM_GETIMAGELIST, TVSIL_NORMAL};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let handle = wh::send_message(handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0) as HIMAGELIST;
if handle.is_null() {
None
} else {
Some(ImageList {
handle,
owned: false,
})
}
}
#[cfg(feature = "image-list")]
pub fn set_item_image(&self, item: &TreeItem, index: i32, on_select: bool) {
use winapi::um::commctrl::{TVIF_IMAGE, TVIF_SELECTEDIMAGE, TVM_SETITEMW};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut tree_item = blank_item();
tree_item.hItem = item.handle;
tree_item.mask = match on_select {
true => TVIF_SELECTEDIMAGE,
false => TVIF_IMAGE,
};
match on_select {
true => {
tree_item.iSelectedImage = index;
}
false => {
tree_item.iImage = index;
}
}
wh::send_message(
handle,
TVM_SETITEMW,
0,
&mut tree_item as *mut TVITEMW as LPARAM,
);
}
#[cfg(feature = "image-list")]
pub fn item_image(&self, item: &TreeItem, on_select: bool) -> i32 {
use winapi::um::commctrl::{TVIF_IMAGE, TVIF_SELECTEDIMAGE, TVM_GETITEMW};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut tree_item = blank_item();
tree_item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tree_item.hItem = item.handle;
match wh::send_message(
handle,
TVM_GETITEMW,
0,
&mut tree_item as *mut TVITEMW as LPARAM,
) {
0 => 0,
_ => match on_select {
true => tree_item.iSelectedImage,
false => tree_item.iImage,
},
}
}
pub fn set_text_color(&self, r: u8, g: u8, b: u8) {
use winapi::um::commctrl::TVM_SETTEXTCOLOR;
use winapi::um::wingdi::RGB;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let color = RGB(r, g, b);
wh::send_message(handle, TVM_SETTEXTCOLOR, 0, color as _);
self.invalidate();
}
pub fn text_color(&self) -> [u8; 3] {
use winapi::um::commctrl::TVM_GETTEXTCOLOR;
use winapi::um::wingdi::{GetBValue, GetGValue, GetRValue};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let col = wh::send_message(handle, TVM_GETTEXTCOLOR, 0, 0) as u32;
[GetRValue(col), GetGValue(col), GetBValue(col)]
}
pub fn indent(&self) -> u32 {
use winapi::um::commctrl::TVM_GETINDENT;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, TVM_GETINDENT, 0, 0) as u32
}
pub fn set_indent(&self, indent: u32) {
use winapi::um::commctrl::TVM_SETINDENT;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, TVM_SETINDENT, indent as _, 0);
}
pub fn root(&self) -> Option<TreeItem> {
use winapi::um::commctrl::TVGN_ROOT;
next_treeview_item(&self.handle, TVGN_ROOT, ptr::null_mut())
}
pub fn first_child(&self, item: &TreeItem) -> Option<TreeItem> {
use winapi::um::commctrl::TVGN_CHILD;
next_treeview_item(&self.handle, TVGN_CHILD, item.handle)
}
pub fn next_sibling(&self, item: &TreeItem) -> Option<TreeItem> {
use winapi::um::commctrl::TVGN_NEXT;
next_treeview_item(&self.handle, TVGN_NEXT, item.handle)
}
pub fn previous_sibling(&self, item: &TreeItem) -> Option<TreeItem> {
use winapi::um::commctrl::TVGN_PREVIOUS;
next_treeview_item(&self.handle, TVGN_PREVIOUS, item.handle)
}
pub fn parent(&self, item: &TreeItem) -> Option<TreeItem> {
use winapi::um::commctrl::TVGN_PARENT;
next_treeview_item(&self.handle, TVGN_PARENT, item.handle)
}
pub fn selected_item(&self) -> Option<TreeItem> {
use winapi::um::commctrl::{TVGN_NEXTSELECTED, TVM_GETNEXTITEM};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let tree_handle =
wh::send_message(handle, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0) as HTREEITEM;
if tree_handle.is_null() {
None
} else {
Some(TreeItem {
handle: tree_handle,
})
}
}
pub fn selected_items(&self) -> Vec<TreeItem> {
use winapi::um::commctrl::{TVGN_NEXTSELECTED, TVM_GETNEXTITEM};
let mut items = Vec::new();
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut last_handle = wh::send_message(handle, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0);
while last_handle != 0 {
items.push(TreeItem {
handle: last_handle as _,
});
last_handle =
wh::send_message(handle, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, last_handle as _);
}
items
}
pub fn selected_item_count(&self) -> usize {
use winapi::um::commctrl::{TVGN_NEXTSELECTED, TVM_GETNEXTITEM};
let mut count = 0;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut last_handle = wh::send_message(handle, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0);
while last_handle != 0 {
count += 1;
last_handle =
wh::send_message(handle, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, last_handle as _);
}
count
}
pub fn insert_item<'a>(
&self,
new: &'a str,
parent: Option<&TreeItem>,
position: TreeInsert,
) -> TreeItem {
use winapi::um::commctrl::TVINSERTSTRUCTW_u;
use winapi::um::commctrl::{
TVI_FIRST, TVI_LAST, TVI_ROOT, TVI_SORT, TVIF_TEXT, TVINSERTSTRUCTW, TVM_INSERTITEMW,
};
use winapi::um::winnt::LPWSTR;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let insert = match position {
TreeInsert::First => TVI_FIRST,
TreeInsert::Last => TVI_LAST,
TreeInsert::Root => TVI_ROOT,
TreeInsert::Sort => TVI_SORT,
TreeInsert::After(i) => i,
};
let text = to_utf16(new);
let item = {
let mut item: TVINSERTSTRUCTW_u = unsafe { mem::zeroed() };
let i = unsafe { item.item_mut() };
i.mask = TVIF_TEXT;
i.pszText = text.as_ptr() as LPWSTR;
item
};
let new_item = TVINSERTSTRUCTW {
hParent: parent.map(|p| p.handle).unwrap_or(ptr::null_mut()),
hInsertAfter: insert,
u: item,
};
let ptr = &new_item as *const TVINSERTSTRUCTW;
let handle = wh::send_message(handle, TVM_INSERTITEMW, 0, ptr as LPARAM) as HTREEITEM;
self.invalidate();
TreeItem { handle }
}
pub fn insert_item_with_param<'a>(
&self,
new: &'a str,
parent: Option<&TreeItem>,
position: TreeInsert,
data: isize,
) -> TreeItem {
use winapi::um::commctrl::TVINSERTSTRUCTW_u;
use winapi::um::commctrl::{
TVI_FIRST, TVI_LAST, TVI_ROOT, TVI_SORT, TVIF_PARAM, TVIF_TEXT, TVINSERTSTRUCTW,
TVM_INSERTITEMW,
};
use winapi::um::winnt::LPWSTR;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let insert = match position {
TreeInsert::First => TVI_FIRST,
TreeInsert::Last => TVI_LAST,
TreeInsert::Root => TVI_ROOT,
TreeInsert::Sort => TVI_SORT,
TreeInsert::After(i) => i,
};
let text = to_utf16(new);
let item = {
let mut item: TVINSERTSTRUCTW_u = unsafe { mem::zeroed() };
let i = unsafe { item.item_mut() };
i.mask = TVIF_TEXT | TVIF_PARAM;
i.pszText = text.as_ptr() as LPWSTR;
i.lParam = data;
item
};
let new_item = TVINSERTSTRUCTW {
hParent: parent.map(|p| p.handle).unwrap_or(ptr::null_mut()),
hInsertAfter: insert,
u: item,
};
let ptr = &new_item as *const TVINSERTSTRUCTW;
let handle = wh::send_message(handle, TVM_INSERTITEMW, 0, ptr as LPARAM) as HTREEITEM;
self.invalidate();
TreeItem { handle }
}
pub fn remove_item(&self, item: &TreeItem) {
use winapi::um::commctrl::TVM_DELETEITEM;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, TVM_DELETEITEM, 0, item.handle as LPARAM);
}
pub fn select_item(&self, item: &TreeItem) {
use winapi::um::commctrl::{TVIF_STATE, TVM_SETITEMW};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut tree_item = blank_item();
tree_item.mask = TVIF_STATE;
tree_item.hItem = item.handle;
tree_item.state = TVIS_SELECTED;
tree_item.stateMask = TVIS_SELECTED;
wh::send_message(
handle,
TVM_SETITEMW,
0,
&mut tree_item as *mut TVITEMW as LPARAM,
);
}
pub fn unselect_item(&self, item: &TreeItem) {
use winapi::um::commctrl::{TVIF_STATE, TVM_SETITEMW};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut tree_item = blank_item();
tree_item.mask = TVIF_STATE;
tree_item.hItem = item.handle;
tree_item.state = 0;
tree_item.stateMask = TVIS_SELECTED;
wh::send_message(
handle,
TVM_SETITEMW,
0,
&mut tree_item as *mut TVITEMW as LPARAM,
);
}
#[cfg(feature = "tree-view-iterator")]
pub fn iter<'a>(&'a self) -> crate::TreeViewIterator<'a> {
check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
crate::TreeViewIterator::new(self, ptr::null_mut())
}
#[cfg(feature = "tree-view-iterator")]
pub fn iter_item<'a>(&'a self, item: &TreeItem) -> crate::TreeViewIterator<'a> {
check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
crate::TreeViewIterator::new(self, item.handle)
}
pub fn item_text(&self, tree_item: &TreeItem) -> Option<String> {
use winapi::um::commctrl::{TVIF_HANDLE, TVIF_TEXT, TVM_GETITEMW};
const BUFFER_MAX: usize = 260;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut text_buffer = Vec::with_capacity(BUFFER_MAX);
unsafe {
text_buffer.set_len(BUFFER_MAX);
}
let mut item: TVITEMW = blank_item();
item.mask = TVIF_TEXT | TVIF_HANDLE;
item.hItem = tree_item.handle;
item.pszText = text_buffer.as_mut_ptr();
item.cchTextMax = BUFFER_MAX as _;
let result = wh::send_message(handle, TVM_GETITEMW, 0, &mut item as *mut TVITEMW as LPARAM);
if result == 0 {
return None;
}
Some(from_utf16(&text_buffer))
}
pub fn set_item_text(&self, tree_item: &TreeItem, new_text: &str) {
use winapi::um::commctrl::{TVIF_TEXT, TVM_SETITEMW};
use winapi::um::winnt::LPWSTR;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let text = to_utf16(new_text);
let mut item: TVITEMW = blank_item();
item.mask = TVIF_TEXT;
item.hItem = tree_item.handle;
item.pszText = text.as_ptr() as LPWSTR;
wh::send_message(handle, TVM_SETITEMW, 0, &mut item as *mut TVITEMW as LPARAM);
}
pub fn item_param(&self, tree_item: &TreeItem) -> Option<isize> {
use winapi::um::commctrl::{TVIF_HANDLE, TVIF_PARAM, TVM_GETITEMW};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut item: TVITEMW = blank_item();
item.mask = TVIF_HANDLE | TVIF_PARAM;
item.hItem = tree_item.handle;
let result = wh::send_message(handle, TVM_GETITEMW, 0, &mut item as *mut TVITEMW as LPARAM);
if result == 0 {
return None;
}
Some(item.lParam)
}
pub fn item_has_children(&self, tree_item: &TreeItem) -> Option<bool> {
use winapi::um::commctrl::{TVIF_CHILDREN, TVIF_HANDLE, TVM_GETITEMW};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut item: TVITEMW = blank_item();
item.hItem = tree_item.handle;
item.mask = TVIF_CHILDREN | TVIF_HANDLE;
let result = wh::send_message(handle, TVM_GETITEMW, 0, &mut item as *mut TVITEMW as LPARAM);
if result == 0 {
return None;
}
Some(item.cChildren != 0)
}
pub fn item_state(&self, tree_item: &TreeItem) -> Option<TreeItemState> {
use winapi::um::commctrl::{TVIF_HANDLE, TVIF_STATE, TVM_GETITEMW};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut item: TVITEMW = unsafe { mem::zeroed() };
item.hItem = tree_item.handle;
item.mask = TVIF_STATE | TVIF_HANDLE;
item.stateMask = 0xFF;
let result = wh::send_message(handle, TVM_GETITEMW, 0, &mut item as *mut TVITEMW as LPARAM);
if result == 0 {
return None;
}
Some(TreeItemState::from_bits_truncate(item.state))
}
pub fn set_expand_state(&self, item: &TreeItem, state: ExpandState) {
use winapi::um::commctrl::{
TVE_COLLAPSE, TVE_COLLAPSERESET, TVE_EXPAND, TVE_EXPANDPARTIAL, TVE_TOGGLE, TVM_EXPAND,
};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let state = match state {
ExpandState::Collapse => TVE_COLLAPSE,
ExpandState::CollapseReset => TVE_COLLAPSE | TVE_COLLAPSERESET,
ExpandState::Expand => TVE_EXPAND,
ExpandState::ExpandPartial => TVE_EXPANDPARTIAL,
ExpandState::Toggle => TVE_TOGGLE,
};
wh::send_message(handle, TVM_EXPAND, state as WPARAM, item.handle as LPARAM);
}
pub fn ensure_visible(&self, item: &TreeItem) {
use winapi::um::commctrl::TVM_ENSUREVISIBLE;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, TVM_ENSUREVISIBLE, 0, item.handle as LPARAM);
}
pub fn clear(&self) {
use winapi::um::commctrl::{TVI_ROOT, TVM_DELETEITEM};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, TVM_DELETEITEM, 0, TVI_ROOT as LPARAM);
}
pub fn len(&self) -> usize {
use winapi::um::commctrl::TVM_GETCOUNT;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, TVM_GETCOUNT, 0, 0) as usize
}
pub fn visible_len(&self) -> usize {
use winapi::um::commctrl::TVM_GETVISIBLECOUNT;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, TVM_GETVISIBLECOUNT, 0, 0) as usize
}
pub fn invalidate(&self) {
use winapi::um::winuser::InvalidateRect;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe {
InvalidateRect(handle, ptr::null(), 1);
}
}
pub fn font(&self) -> Option<Font> {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let font_handle = wh::get_window_font(handle);
if font_handle.is_null() {
None
} else {
Some(Font {
handle: font_handle,
})
}
}
pub fn set_font(&self, font: Option<&Font>) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_font(handle, font.map(|f| f.handle), true);
}
pub fn focus(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_focus(handle)
}
pub fn set_focus(&self) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_focus(handle);
}
pub fn enabled(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_window_enabled(handle)
}
pub fn set_enabled(&self, v: bool) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_enabled(handle, v)
}
pub fn visible(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_window_visibility(handle)
}
pub fn set_visible(&self, v: bool) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_visibility(handle, v)
}
pub fn size(&self) -> (u32, u32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_window_size(handle)
}
pub fn set_size(&self, x: u32, y: u32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_size(handle, x, y, false)
}
pub fn position(&self) -> (i32, i32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_window_position(handle)
}
pub fn set_position(&self, x: i32, y: i32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_position(handle, x, y)
}
pub fn class_name(&self) -> &'static str {
winapi::um::commctrl::WC_TREEVIEW
}
pub fn flags(&self) -> u32 {
use winapi::um::commctrl::{TVS_EDITLABELS, TVS_HASBUTTONS, TVS_HASLINES, TVS_LINESATROOT};
WS_VISIBLE
| TVS_HASBUTTONS
| TVS_LINESATROOT
| TVS_HASLINES
| WS_TABSTOP
| TVS_SHOWSELALWAYS
| TVS_EDITLABELS
}
pub fn forced_flags(&self) -> u32 {
use winapi::um::commctrl::TVS_NOTOOLTIPS;
use winapi::um::winuser::{WS_BORDER, WS_CHILD};
WS_CHILD | WS_BORDER | TVS_NOTOOLTIPS
}
pub fn edit_label(&self, item: &TreeItem) -> Option<ControlHandle> {
use winapi::shared::windef::HWND;
use winapi::um::commctrl::TVM_EDITLABELW;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let result = wh::send_message(
handle,
TVM_EDITLABELW,
0,
item.handle as HTREEITEM as LPARAM,
);
if result == 0 {
return None;
}
Some(ControlHandle::Hwnd(result as HWND))
}
pub fn end_edit_label_now(&self, f_cancel: bool) -> bool {
use winapi::um::commctrl::TVM_ENDEDITLABELNOW;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, TVM_ENDEDITLABELNOW, f_cancel as WPARAM, 0) != 0
}
}
impl Drop for TreeView {
fn drop(&mut self) {
self.handle.destroy();
}
}
pub struct TreeViewBuilder<'a> {
size: (i32, i32),
position: (i32, i32),
enabled: bool,
focus: bool,
flags: Option<TreeViewFlags>,
ex_flags: u32,
font: Option<&'a Font>,
parent: Option<ControlHandle>,
#[cfg(feature = "image-list")]
image_list: Option<&'a ImageList>,
}
impl<'a> TreeViewBuilder<'a> {
pub fn flags(mut self, flags: TreeViewFlags) -> TreeViewBuilder<'a> {
self.flags = Some(flags);
self
}
pub fn ex_flags(mut self, flags: u32) -> TreeViewBuilder<'a> {
self.ex_flags = flags;
self
}
pub fn size(mut self, size: (i32, i32)) -> TreeViewBuilder<'a> {
self.size = size;
self
}
pub fn position(mut self, pos: (i32, i32)) -> TreeViewBuilder<'a> {
self.position = pos;
self
}
pub fn enabled(mut self, e: bool) -> TreeViewBuilder<'a> {
self.enabled = e;
self
}
pub fn focus(mut self, focus: bool) -> TreeViewBuilder<'a> {
self.focus = focus;
self
}
pub fn font(mut self, font: Option<&'a Font>) -> TreeViewBuilder<'a> {
self.font = font;
self
}
pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> TreeViewBuilder<'a> {
self.parent = Some(p.into());
self
}
#[cfg(feature = "image-list")]
pub fn image_list(mut self, list: Option<&'a ImageList>) -> TreeViewBuilder<'a> {
self.image_list = list;
self
}
pub fn build(self, out: &mut TreeView) -> Result<(), NwgError> {
let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
let parent = match self.parent {
Some(p) => Ok(p),
None => Err(NwgError::no_parent("TreeView")),
}?;
*out = Default::default();
out.handle = ControlBase::build_hwnd()
.class_name(out.class_name())
.forced_flags(out.forced_flags())
.flags(flags)
.ex_flags(self.ex_flags)
.size(self.size)
.position(self.position)
.parent(Some(parent))
.build()?;
if self.font.is_some() {
out.set_font(self.font);
} else {
out.set_font(Font::global_default().as_ref());
}
builder_set_image_list(&self, out);
if self.focus {
out.set_focus();
}
out.set_enabled(self.enabled);
Ok(())
}
}
impl PartialEq for TreeItem {
fn eq(&self, other: &Self) -> bool {
self.handle == other.handle
}
}
impl Eq for TreeItem {}
fn next_treeview_item(handle: &ControlHandle, action: usize, item: HTREEITEM) -> Option<TreeItem> {
use winapi::um::commctrl::TVM_GETNEXTITEM;
if handle.blank() {
panic!("{}", NOT_BOUND);
}
let handle = handle.hwnd().expect(BAD_HANDLE);
let handle = wh::send_message(handle, TVM_GETNEXTITEM, action as _, item as _) as HTREEITEM;
if handle.is_null() {
None
} else {
Some(TreeItem { handle })
}
}
#[cfg(feature = "image-list")]
fn builder_set_image_list(builder: &TreeViewBuilder, out: &TreeView) {
if builder.image_list.is_some() {
out.set_image_list(builder.image_list);
}
}
#[cfg(not(feature = "image-list"))]
fn builder_set_image_list(_builder: &TreeViewBuilder, _out: &TreeView) {}
fn blank_item() -> TVITEMW {
TVITEMW {
mask: 0,
hItem: ptr::null_mut(),
state: 0,
stateMask: 0,
pszText: ptr::null_mut(),
cchTextMax: 0,
iImage: 0,
iSelectedImage: 0,
cChildren: 0,
lParam: 0,
}
}