wxMSW::wxTreeCtrl has multiple selection too (somewhat documented)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3220 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1999-07-30 22:45:55 +00:00
parent 717b9bf234
commit 9dfbf520eb
7 changed files with 433 additions and 151 deletions

View File

@@ -24,6 +24,9 @@ To intercept events from a tree control, use the event table macros described in
left of parent items.}
\twocolitem{\windowstyle{wxTR\_EDIT\_LABELS}}{Use this style if you wish the user to be
able to edit labels in the tree control.}
\twocolitem{\windowstyle{wxTR\_MULTIPLE}}{Use this style to allow the user to
select more than one item in the control - by default, only one item may be
selected.}
\end{twocollist}
See also \helpref{window styles overview}{windowstyles}.
@@ -385,6 +388,18 @@ Gets the selected item image.
\constfunc{wxTreeItemId}{GetSelection}{\void}
Returns the selection, or an invalid item if there is no selection.
This function only works with the controls without wxTR\_MULTIPLE style, use
\helpref{GetSelections}{wxtreectrlgetselections} for the controls which do have
this style.
\membersection{wxTreeCtrl::GetSelections}\label{wxtreectrlgetselections}
\constfunc{size\_t}{GetSelections}{\param{wxArrayTreeItemIds\& }{selection}}
Fills the array of tree items passed in with the currently selected items. This
function can be called only if the control has the wxTR\_MULTIPLE style.
Returns the number of selected items.
\membersection{wxTreeCtrl::HitTest}\label{wxtreectrlhittest}
@@ -572,6 +587,14 @@ Toggles the given item between collapsed and expanded states.
Removes the selection from the currently selected item (if any).
\membersection{wxTreeCtrl::UnselectAll}\label{wxtreectrlunselectall}
\func{void}{UnselectAll}{\void}
This function either behaves the same as \helpref{Unselect}{wxtreectrlunselect}
if the control doesn't have wxTR\_MULTIPLE style, or removes the selection from
all items if it does have this style.
\section{\class{wxTreeItemData}}\label{wxtreeitemdata}
wxTreeItemData is some (arbitrary) user class associated with some item. The

View File

@@ -32,7 +32,7 @@ WXDLLEXPORT_DATA(extern const char*) wxTreeCtrlNameStr;
#include "wx/dynarray.h"
#include "wx/timer.h"
//those defines should only be done in generic/treectrl.h,
//those defines should only be done in generic/treectrl.h,
//because wxMSW doesn't allow mutiple selection
#ifndef wxTR_SINGLE
@@ -177,7 +177,7 @@ class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
public:
wxTreeTextCtrl(void) {};
wxTreeTextCtrl( wxWindow *parent, const wxWindowID id,
wxTreeTextCtrl( wxWindow *parent, const wxWindowID id,
bool *accept, wxString *res, wxTreeCtrl *owner,
const wxString &value = "",
const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize,
@@ -185,7 +185,7 @@ class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
const wxString &name = "wxTreeTextCtrlText" );
void OnChar( wxKeyEvent &event );
void OnKillFocus( wxFocusEvent &event );
DECLARE_EVENT_TABLE()
};
@@ -231,10 +231,10 @@ public:
unsigned int GetIndent() const { return m_indent; }
void SetIndent(unsigned int indent);
// spacing is the number of pixels between the start and the Text
// spacing is the number of pixels between the start and the Text
unsigned int GetSpacing() const { return m_spacing; }
void SetSpacing(unsigned int spacing);
// image list: these functions allow to associate an image list with
// the control and retrieve it. Note that the control does _not_ delete
// the associated image list when it's deleted in order to allow image
@@ -420,7 +420,7 @@ public:
// been before.
void EditLabel( const wxTreeItemId& item ) { Edit( item ); }
void Edit( const wxTreeItemId& item );
// sorting
// this function is called to compare 2 items and should return -1, 0
// or +1 if the first item is less than, equal to or greater than the
@@ -447,7 +447,7 @@ public:
// Draw Special Information
void DrawBorder(wxTreeItemId& item);
void DrawLine(wxTreeItemId& item, bool below);
protected:
friend class wxGenericTreeItem;
friend class wxTreeRenameTimer;
@@ -491,7 +491,7 @@ protected:
void RefreshSubtree( wxGenericTreeItem *item );
void RefreshLine( wxGenericTreeItem *item );
void OnRenameTimer();
void OnRenameAccept();

View File

@@ -121,6 +121,8 @@ protected:
long m_itemId;
};
WX_DEFINE_ARRAY(wxTreeItemId, wxArrayTreeItemIds);
// ----------------------------------------------------------------------------
// wxTreeItemData is some (arbitrary) user class associated with some item. The
// main advantage of having this class (compared to old untyped interface) is
@@ -275,7 +277,8 @@ public:
// if 'recursively' is FALSE, only immediate children count, otherwise
// the returned number is the number of all items in this branch
size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = TRUE);
size_t GetChildrenCount(const wxTreeItemId& item,
bool recursively = TRUE) const;
// navigation
// ----------
@@ -288,6 +291,12 @@ public:
// get the item currently selected (may return NULL if no selection)
wxTreeItemId GetSelection() const;
// get the items currently selected, return the number of such item
//
// NB: this operation is expensive and can take a long time for a
// control with a lot of items (~ O(number of items)).
size_t GetSelections(wxArrayTreeItemIds& selections) const;
// get the parent of this item (may return NULL if root)
wxTreeItemId GetParent(const wxTreeItemId& item) const;
@@ -365,6 +374,8 @@ public:
// remove the selection from currently selected item (if any)
void Unselect();
// unselect all items (only makes sense for multiple selection control)
void UnselectAll();
// select this item
void SelectItem(const wxTreeItemId& item);
// make sure this item is visible (expanding the parent item and/or
@@ -445,6 +456,10 @@ public:
virtual bool MSWCommand(WXUINT param, WXWORD id);
virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
// get/set the check state for the item (only for wxTR_MULTIPLE)
bool IsItemChecked(const wxTreeItemId& item) const;
void SetItemCheck(const wxTreeItemId& item, bool check = TRUE);
protected:
// SetImageList helper
void SetAnyImageList(wxImageList *imageList, int which);
@@ -469,6 +484,8 @@ private:
int image, int selectedImage,
wxTreeItemData *data);
void DoSetItemImages(const wxTreeItemId& item, int image, int imageSel);
void DeleteTextCtrl();
DECLARE_DYNAMIC_CLASS(wxTreeCtrl)

View File

@@ -33,12 +33,13 @@
#include "math.h"
#include "treetest.h"
#ifdef __WXMSW__
#define NO_ADVANCED_FEATURES
//#define NO_MULTIPLE_SELECTION
#define NO_VARIABLE_HEIGHT
#endif
#include "treetest.h"
// under Windows the icons are in the .rc file
#ifndef __WXMSW__
#include "icon1.xpm"
@@ -59,7 +60,11 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(TreeTest_Quit, MyFrame::OnQuit)
EVT_MENU(TreeTest_About, MyFrame::OnAbout)
EVT_MENU(TreeTest_Dump, MyFrame::OnDump)
EVT_MENU(TreeTest_Dump_Selected, MyFrame::OnDumpSelected)
#ifndef NO_MULTIPLE_SELECTION
EVT_MENU(TreeTest_DumpSelected, MyFrame::OnDumpSelected)
EVT_MENU(TreeTest_Select, MyFrame::OnSelect)
EVT_MENU(TreeTest_Unselect, MyFrame::OnUnselect)
#endif // NO_MULTIPLE_SELECTION
EVT_MENU(TreeTest_Rename, MyFrame::OnRename)
EVT_MENU(TreeTest_Sort, MyFrame::OnSort)
EVT_MENU(TreeTest_SortRev, MyFrame::OnSortRev)
@@ -76,6 +81,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(TreeTest_DecIndent, MyFrame::OnDecIndent)
EVT_MENU(TreeTest_IncSpacing, MyFrame::OnIncSpacing)
EVT_MENU(TreeTest_DecSpacing, MyFrame::OnDecSpacing)
EVT_MENU(TreeTest_ToggleIcon, MyFrame::OnToggleIcon)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(MyTreeCtrl, wxTreeCtrl)
@@ -153,14 +159,20 @@ MyFrame::MyFrame(const wxString& title, int x, int y, int w, int h)
tree_menu->Append(TreeTest_DecSpacing, "Reduce spacing by 5 points\tCtrl-R");
item_menu->Append(TreeTest_Dump, "&Dump item children");
#ifndef NO_ADVANCED_FEATURES
item_menu->Append(TreeTest_Dump_Selected, "Dump selected items\tAlt-S");
#endif
item_menu->Append(TreeTest_Rename, "&Rename item...");
item_menu->AppendSeparator();
item_menu->Append(TreeTest_Bold, "Make item &bold");
item_menu->Append(TreeTest_UnBold, "Make item &not bold");
item_menu->AppendSeparator();
item_menu->Append(TreeTest_ToggleIcon, "Toggle the items &icon");
#ifndef NO_MULTIPLE_SELECTION
item_menu->AppendSeparator();
item_menu->Append(TreeTest_DumpSelected, "Dump selected items\tAlt-D");
item_menu->Append(TreeTest_Select, "Select current item\tAlt-S");
item_menu->Append(TreeTest_Unselect, "Unselect everything\tAlt-U");
#endif
wxMenuBar *menu_bar = new wxMenuBar;
menu_bar->Append(file_menu, "&File");
@@ -172,10 +184,8 @@ MyFrame::MyFrame(const wxString& title, int x, int y, int w, int h)
wxDefaultPosition, wxDefaultSize,
wxTR_HAS_BUTTONS |
wxTR_EDIT_LABELS |
#ifndef NO_ADVANCED_FEATURES
wxTR_MULTIPLE |
wxTR_HAS_VARIABLE_ROW_HEIGHT |
#endif
wxSUNKEN_BORDER);
wxTextCtrl *textCtrl = new wxTextCtrl(this, -1, "",
wxDefaultPosition, wxDefaultSize,
@@ -268,20 +278,33 @@ void MyFrame::OnDump(wxCommandEvent& WXUNUSED(event))
m_treeCtrl->GetItemsRecursively(root, -1);
}
#ifndef NO_MULTIPLE_SELECTION
void MyFrame::OnDumpSelected(wxCommandEvent& WXUNUSED(event))
{
#ifndef NO_ADVANCED_FEATURES
wxArrayTreeItemIds array;
wxArrayTreeItemIds array;
m_treeCtrl->GetSelections(array);
size_t nos=array.Count();
wxLogMessage(wxString("items selected : ")<< (int)nos);
size_t count = m_treeCtrl->GetSelections(array);
wxLogMessage(_T("%u items selected"), count);
for (size_t n=0; n<nos; ++n)
wxLogMessage(m_treeCtrl->GetItemText(array.Item(n)));
#endif
for ( size_t n = 0; n < count; n++ )
{
wxLogMessage("\t%s", m_treeCtrl->GetItemText(array.Item(n)).c_str());
}
}
void MyFrame::OnSelect(wxCommandEvent& event)
{
m_treeCtrl->SelectItem(m_treeCtrl->GetSelection());
}
void MyFrame::OnUnselect(wxCommandEvent& event)
{
m_treeCtrl->UnselectAll();
}
#endif // NO_MULTIPLE_SELECTION
void MyFrame::DoSetBold(bool bold)
{
wxTreeItemId item = m_treeCtrl->GetSelection();
@@ -370,6 +393,15 @@ void MyFrame::OnDecSpacing(wxCommandEvent& WXUNUSED(event))
m_treeCtrl->SetSpacing( indent-5 );
}
void MyFrame::OnToggleIcon(wxCommandEvent& WXUNUSED(event))
{
wxTreeItemId item = m_treeCtrl->GetSelection();
CHECK_ITEM( item );
m_treeCtrl->DoToggleIcon(item);
}
// MyTreeCtrl implementation
IMPLEMENT_DYNAMIC_CLASS(MyTreeCtrl, wxTreeCtrl)
@@ -379,7 +411,7 @@ MyTreeCtrl::MyTreeCtrl(wxWindow *parent, const wxWindowID id,
: wxTreeCtrl(parent, id, pos, size, style)
{
#if (USE_TR_HAS_VARIABLE_ROW_HIGHT && wxUSE_LIBJPEG)
wxImage::AddHandler(new wxJPEGHandler);
wxImage::AddHandler(new wxJPEGHandler);
wxImage image;
image.LoadFile(wxString("horse.jpg"), wxBITMAP_TYPE_JPEG );
@@ -450,8 +482,7 @@ void MyTreeCtrl::AddItemsRecursively(const wxTreeItemId& idParent,
else
str.Printf("%s child %d", "Folder", n + 1);
// int image = depth == 1 ? TreeCtrlIcon_File : TreeCtrlIcon_Folder;
int image = depth == 1 ? -1 : TreeCtrlIcon_Folder;
int image = depth == 1 ? TreeCtrlIcon_File : TreeCtrlIcon_Folder;
wxTreeItemId id = AppendItem(idParent, str, image, image,
new MyTreeItemData(str));
@@ -489,7 +520,7 @@ void MyTreeCtrl::GetItemsRecursively(const wxTreeItemId& idParent, long cookie)
if(id <= 0)
return;
wxString text=GetItemText(id);
wxString text = GetItemText(id);
wxLogMessage(text);
if (ItemHasChildren(id))
@@ -498,6 +529,14 @@ void MyTreeCtrl::GetItemsRecursively(const wxTreeItemId& idParent, long cookie)
GetItemsRecursively(idParent, cookie);
}
void MyTreeCtrl::DoToggleIcon(const wxTreeItemId& item)
{
int image = GetItemImage(item) == TreeCtrlIcon_Folder ? TreeCtrlIcon_File
: TreeCtrlIcon_Folder;
SetItemImage(item, image);
}
// avoid repetition
#define TREE_EVENT_HANDLER(name) \

View File

@@ -65,9 +65,11 @@ public:
void AddTestItemsToTree(size_t numChildren, size_t depth);
void DoSortChildren(const wxTreeItemId& item, bool reverse = FALSE)
{ m_reverseSort = reverse; wxTreeCtrl::SortChildren(item); }
{ m_reverseSort = reverse; wxTreeCtrl::SortChildren(item); }
void DoEnsureVisible() { EnsureVisible(m_lastItem); }
void DoToggleIcon(const wxTreeItemId& item);
protected:
virtual int OnCompareItems(const wxTreeItemId& i1, const wxTreeItemId& i2);
@@ -109,7 +111,11 @@ public:
void OnAbout(wxCommandEvent& event);
void OnDump(wxCommandEvent& event);
#ifndef NO_MULTIPLE_SELECTION
void OnDumpSelected(wxCommandEvent& event);
void OnSelect(wxCommandEvent& event);
void OnUnselect(wxCommandEvent& event);
#endif // NO_MULTIPLE_SELECTION
void OnDelete(wxCommandEvent& event);
void OnDeleteChildren(wxCommandEvent& event);
void OnDeleteAll(wxCommandEvent& event);
@@ -126,13 +132,15 @@ public:
void OnSortRev(wxCommandEvent& event) { DoSort(TRUE); }
void OnAddItem(wxCommandEvent& event);
void OnIncIndent(wxCommandEvent& event);
void OnDecIndent(wxCommandEvent& event);
void OnIncSpacing(wxCommandEvent& event);
void OnDecSpacing(wxCommandEvent& event);
void OnToggleIcon(wxCommandEvent& event);
private:
void DoSort(bool reverse = FALSE);
@@ -149,7 +157,7 @@ enum
TreeTest_Quit,
TreeTest_About,
TreeTest_Dump,
TreeTest_Dump_Selected,
TreeTest_DumpSelected,
TreeTest_Sort,
TreeTest_SortRev,
TreeTest_Bold,
@@ -166,5 +174,8 @@ enum
TreeTest_DecIndent,
TreeTest_IncSpacing,
TreeTest_DecSpacing,
TreeTest_Ctrl = 100
TreeTest_ToggleIcon,
TreeTest_Select,
TreeTest_Unselect,
TreeTest_Ctrl = 1000
};

View File

@@ -203,14 +203,14 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
{
(*m_accept) = TRUE;
(*m_res) = GetValue();
m_owner->SetFocus();
m_owner->SetFocus();
return;
}
if (event.m_keyCode == WXK_ESCAPE)
{
(*m_accept) = FALSE;
(*m_res) = "";
m_owner->SetFocus();
m_owner->SetFocus();
return;
}
event.Skip();
@@ -221,7 +221,7 @@ void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
if (wxPendingDelete.Member(this)) return;
wxPendingDelete.Append(this);
if ((*m_accept) && ((*m_res) != m_startValue))
m_owner->OnRenameAccept();
}
@@ -232,7 +232,7 @@ void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
// -----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
: wxNotifyEvent( commandType, id )
{
@@ -463,7 +463,7 @@ void wxTreeCtrl::Init()
m_imageListState = (wxImageList *) NULL;
m_dragCount = 0;
m_renameTimer = new wxTreeRenameTimer( this );
}
@@ -493,7 +493,7 @@ wxTreeCtrl::~wxTreeCtrl()
wxDELETE( m_hilightBrush );
DeleteAllItems();
delete m_renameTimer;
}
@@ -1143,16 +1143,18 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId,
GetEventHandler()->ProcessEvent( event );
}
void wxTreeCtrl::FillArray(wxGenericTreeItem *item, wxArrayTreeItemIds &array) const
void wxTreeCtrl::FillArray(wxGenericTreeItem *item,
wxArrayTreeItemIds &array) const
{
if (item->HasHilight()) array.Add(wxTreeItemId(item));
if ( item->HasHilight() )
array.Add(wxTreeItemId(item));
if (item->HasChildren())
if ( item->HasChildren() )
{
wxArrayGenericTreeItems& children = item->GetChildren();
size_t count = children.Count();
for ( size_t n = 0; n < count; ++n )
FillArray(children[n],array);
wxArrayGenericTreeItems& children = item->GetChildren();
size_t count = children.GetCount();
for ( size_t n = 0; n < count; ++n )
FillArray(children[n],array);
}
}
@@ -1445,12 +1447,12 @@ void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &
dc.SetPen( *wxGREY_PEN );
dc.SetBrush( *wxWHITE_BRUSH );
dc.DrawRectangle( horizX+(m_indent-5), y-4, 11, 9 );
dc.SetPen( *wxBLACK_PEN );
dc.DrawLine( horizX+(m_indent-2), y, horizX+(m_indent+3), y );
if (!item->IsExpanded())
dc.DrawLine( horizX+m_indent, y-2, horizX+m_indent, y+3 );
dc.SetPen( m_dottedPen );
}
@@ -1793,20 +1795,20 @@ void wxTreeCtrl::Edit( const wxTreeItemId& item )
if (!item.IsOk()) return;
m_currentEdit = item.m_pItem;
wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
te.m_item = m_currentEdit;
te.SetEventObject( this );
GetEventHandler()->ProcessEvent( te );
if (!te.IsAllowed()) return;
wxString s = m_currentEdit->GetText();
int x = m_currentEdit->GetX();
int y = m_currentEdit->GetY();
int w = m_currentEdit->GetWidth();
int h = m_currentEdit->GetHeight();
int image_h = 0;
int image_w = 0;
if ((m_currentEdit->IsExpanded()) && (m_currentEdit->GetSelectedImage() != -1))
@@ -1844,12 +1846,12 @@ void wxTreeCtrl::OnRenameAccept()
le.SetEventObject( this );
le.m_label = m_renameRes;
GetEventHandler()->ProcessEvent( le );
if (!le.IsAllowed()) return;
SetItemText( m_currentEdit, m_renameRes );
}
void wxTreeCtrl::OnMouse( wxMouseEvent &event )
{
if (!event.LeftIsDown()) m_dragCount = 0;
@@ -1887,14 +1889,14 @@ void wxTreeCtrl::OnMouse( wxMouseEvent &event )
return;
}
if (event.LeftUp() && (item == m_current) &&
(flags & wxTREE_HITTEST_ONITEMLABEL) &&
HasFlag(wxTR_EDIT_LABELS) )
if (event.LeftUp() && (item == m_current) &&
(flags & wxTREE_HITTEST_ONITEMLABEL) &&
HasFlag(wxTR_EDIT_LABELS) )
{
m_renameTimer->Start( 100, TRUE );
return;
}
bool is_multiple=(GetWindowStyleFlag() & wxTR_MULTIPLE);
bool extended_select=(event.ShiftDown() && is_multiple);
bool unselect_others=!(extended_select || (event.ControlDown() && is_multiple));
@@ -1937,7 +1939,7 @@ void wxTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
{
long text_w = 0;
long text_h = 0;
wxFont fontOld;
wxFont fontNew;
if (item->IsBold())
@@ -1958,14 +1960,14 @@ void wxTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
wxFAIL_MSG(_T("wxDC::GetFont() failed!"));
}
}
dc.GetTextExtent( item->GetText(), &text_w, &text_h );
text_h+=2;
// restore normal font for bold items
if (fontOld.Ok())
dc.SetFont( fontOld);
int image_h = 0;
int image_w = 0;
if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))

View File

@@ -30,10 +30,6 @@
#include "wx/window.h"
#include "wx/msw/private.h"
#ifndef WX_PRECOMP
#include "wx/settings.h"
#endif
// Mingw32 is a bit mental even though this is done in winundef
#ifdef GetFirstChild
#undef GetFirstChild
@@ -70,15 +66,45 @@
// a convenient wrapper around TV_ITEM struct which adds a ctor
struct wxTreeViewItem : public TV_ITEM
{
wxTreeViewItem(const wxTreeItemId& item,
UINT mask_, UINT stateMask_ = 0)
wxTreeViewItem(const wxTreeItemId& item, // the item handle
UINT mask_, // fields which are valid
UINT stateMask_ = 0) // for TVIF_STATE only
{
mask = mask_;
// hItem member is always valid
mask = mask_ | TVIF_HANDLE;
stateMask = stateMask_;
hItem = (HTREEITEM) (WXHTREEITEM) item;
}
};
// a class which encapsulates the tree traversal logic: it vists all (unless
// OnVisit() returns FALSE) items under the given one
class wxTreeTraversal
{
public:
wxTreeTraversal(const wxTreeCtrl *tree)
{
m_tree = tree;
}
// do traverse the tree: visit all items (recursively by default) under the
// given one; return TRUE if all items were traversed or FALSE if the
// traversal was aborted because OnVisit returned FALSE
bool DoTraverse(const wxTreeItemId& root, bool recursively = TRUE);
// override this function to do whatever is needed for each item, return
// FALSE to stop traversing
virtual bool OnVisit(const wxTreeItemId& item) = 0;
protected:
const wxTreeCtrl *GetTree() const { return m_tree; }
private:
bool Traverse(const wxTreeItemId& root, bool recursively);
const wxTreeCtrl *m_tree;
};
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
@@ -102,6 +128,37 @@ static const wxEventType g_events[2][2] =
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// tree traversal
// ----------------------------------------------------------------------------
bool wxTreeTraversal::DoTraverse(const wxTreeItemId& root, bool recursively)
{
if ( !OnVisit(root) )
return FALSE;
return Traverse(root, recursively);
}
bool wxTreeTraversal::Traverse(const wxTreeItemId& root, bool recursively)
{
long cookie;
wxTreeItemId child = m_tree->GetFirstChild(root, cookie);
while ( child.IsOk() )
{
// depth first traversal
if ( recursively && !Traverse(child, TRUE) )
return FALSE;
if ( !OnVisit(child) )
return FALSE;
child = m_tree->GetNextChild(root, cookie);
}
return TRUE;
}
// ----------------------------------------------------------------------------
// construction and destruction
// ----------------------------------------------------------------------------
@@ -113,37 +170,22 @@ void wxTreeCtrl::Init()
m_textCtrl = NULL;
}
bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
const wxPoint& pos, const wxSize& size,
long style, const wxValidator& validator,
bool wxTreeCtrl::Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& validator,
const wxString& name)
{
Init();
wxSystemSettings settings;
SetName(name);
SetValidator(validator);
m_windowStyle = style;
SetParent(parent);
m_windowId = (id == -1) ? NewControlId() : id;
if ( !CreateControl(parent, id, pos, size, style, validator, name) )
return FALSE;
DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
TVS_HASLINES | TVS_SHOWSELALWAYS;
bool want3D;
WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ;
// Even with extended styles, need to combine with WS_BORDER
// for them to look right.
if ( want3D || wxStyleHasBorder(m_windowStyle) )
{
wstyle |= WS_BORDER;
}
if ( m_windowStyle & wxTR_HAS_BUTTONS )
wstyle |= TVS_HASBUTTONS;
@@ -153,26 +195,67 @@ bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
if ( m_windowStyle & wxTR_LINES_AT_ROOT )
wstyle |= TVS_LINESATROOT;
// we emulate the multiple selection tree controls by using checkboxes: set
// up the image list we need for this if we do have multiple selections
if ( m_windowStyle & wxTR_MULTIPLE )
wstyle |= TVS_CHECKBOXES;
// Create the tree control.
m_hWnd = (WXHWND)::CreateWindowEx
(
exStyle,
WC_TREEVIEW,
_T(""),
wstyle,
pos.x, pos.y, size.x, size.y,
(HWND)parent->GetHWND(),
(HMENU)m_windowId,
wxGetInstance(),
NULL
);
if ( !MSWCreateControl(WC_TREEVIEW, wstyle) )
return FALSE;
wxCHECK_MSG( m_hWnd, FALSE, _T("Failed to create tree ctrl") );
// VZ: this is some experimental code which may be used to get the
// TVS_CHECKBOXES style functionality for comctl32.dll < 4.71.
// AFAIK, the standard DLL does about the same thing anyhow.
#if 0
if ( m_windowStyle & wxTR_MULTIPLE )
{
wxBitmap bmp;
if ( parent )
parent->AddChild(this);
// create the DC compatible with the current screen
HDC hdcMem = CreateCompatibleDC(NULL);
SubclassWin(m_hWnd);
// create a mono bitmap of the standard size
int x = GetSystemMetrics(SM_CXMENUCHECK);
int y = GetSystemMetrics(SM_CYMENUCHECK);
wxImageList imagelistCheckboxes(x, y, FALSE, 2);
HBITMAP hbmpCheck = CreateBitmap(x, y, // bitmap size
1, // # of color planes
1, // # bits needed for one pixel
0); // array containing colour data
SelectObject(hdcMem, hbmpCheck);
// then draw a check mark into it
RECT rect = { 0, 0, x, y };
if ( !::DrawFrameControl(hdcMem, &rect,
DFC_BUTTON,
DFCS_BUTTONCHECK | DFCS_CHECKED) )
{
wxLogLastError(_T("DrawFrameControl(check)"));
}
bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
imagelistCheckboxes.Add(bmp);
if ( !::DrawFrameControl(hdcMem, &rect,
DFC_BUTTON,
DFCS_BUTTONCHECK) )
{
wxLogLastError(_T("DrawFrameControl(uncheck)"));
}
bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
imagelistCheckboxes.Add(bmp);
// clean up
::DeleteDC(hdcMem);
// set the imagelist
SetStateImageList(&imagelistCheckboxes);
}
#endif // 0
SetSize(pos.x, pos.y, size.x, size.y);
return TRUE;
}
@@ -254,29 +337,36 @@ void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
}
size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item,
bool recursively) const
{
long cookie;
size_t result = 0;
wxArrayLong children;
wxTreeItemId child = GetFirstChild(item, cookie);
while ( child.IsOk() )
class TraverseCounter : public wxTreeTraversal
{
if ( recursively )
public:
TraverseCounter(const wxTreeCtrl *tree,
const wxTreeItemId& root,
bool recursively)
: wxTreeTraversal(tree)
{
m_count = 0;
DoTraverse(root, recursively);
}
virtual bool OnVisit(const wxTreeItemId& item)
{
// recursive call
result += GetChildrenCount(child, TRUE);
m_count++;
return TRUE;
}
// add the child to the result in any case
result++;
size_t GetCount() const { return m_count; }
child = GetNextChild(item, cookie);
}
private:
size_t m_count;
} counter(this, item, recursively);
return result;
return counter.GetCount();
}
// ----------------------------------------------------------------------------
@@ -306,6 +396,16 @@ void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
DoSetItem(&tvItem);
}
void wxTreeCtrl::DoSetItemImages(const wxTreeItemId& item,
int image,
int imageSel)
{
wxTreeViewItem tvItem(item, TVIF_IMAGE | TVIF_SELECTEDIMAGE);
tvItem.iSelectedImage = imageSel;
tvItem.iImage = image;
DoSetItem(&tvItem);
}
int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
{
wxTreeViewItem tvItem(item, TVIF_IMAGE);
@@ -316,9 +416,10 @@ int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
{
wxTreeViewItem tvItem(item, TVIF_IMAGE);
tvItem.iImage = image;
DoSetItem(&tvItem);
// NB: at least in version 5.00.0518.9 of comctl32.dll we need to always
// change both normal and selected image - otherwise the change simply
// doesn't take place!
DoSetItemImages(item, image, GetItemSelectedImage(item));
}
int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
@@ -331,9 +432,10 @@ int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
{
wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
tvItem.iSelectedImage = image;
DoSetItem(&tvItem);
// NB: at least in version 5.00.0518.9 of comctl32.dll we need to always
// change both normal and selected image - otherwise the change simply
// doesn't take place!
DoSetItemImages(item, GetItemImage(item), image);
}
wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
@@ -433,6 +535,9 @@ wxTreeItemId wxTreeCtrl::GetRootItem() const
wxTreeItemId wxTreeCtrl::GetSelection() const
{
wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (WXHTREEITEM)0,
_T("this only works with single selection controls") );
return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(GetHwnd()));
}
@@ -507,6 +612,62 @@ wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
}
// ----------------------------------------------------------------------------
// multiple selections emulation
// ----------------------------------------------------------------------------
bool wxTreeCtrl::IsItemChecked(const wxTreeItemId& item) const
{
// receive the desired information.
wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
DoGetItem(&tvItem);
// state image indices are 1 based
return ((tvItem.state >> 12) - 1) == 1;
}
void wxTreeCtrl::SetItemCheck(const wxTreeItemId& item, bool check)
{
// receive the desired information.
wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
// state images are one-based
tvItem.state = (check ? 2 : 1) << 12;
DoSetItem(&tvItem);
}
size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds& selections) const
{
class TraverseSelections : public wxTreeTraversal
{
public:
TraverseSelections(const wxTreeCtrl *tree,
wxArrayTreeItemIds& selections)
: wxTreeTraversal(tree), m_selections(selections)
{
m_selections.Empty();
DoTraverse(tree->GetRootItem());
}
virtual bool OnVisit(const wxTreeItemId& item)
{
if ( GetTree()->IsItemChecked(item) )
{
m_selections.Add(item);
}
return TRUE;
}
private:
wxArrayTreeItemIds& m_selections;
} selector(this, selections);
return selections.GetCount();
}
// ----------------------------------------------------------------------------
// Usual operations
// ----------------------------------------------------------------------------
@@ -721,38 +882,67 @@ void wxTreeCtrl::Toggle(const wxTreeItemId& item)
void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
{
DoExpand(item, action);
DoExpand(item, action);
}
void wxTreeCtrl::Unselect()
{
wxASSERT_MSG( !(m_windowStyle & wxTR_MULTIPLE), _T("doesn't make sense") );
// just remove the selection
SelectItem(wxTreeItemId((WXHTREEITEM) 0));
}
void wxTreeCtrl::UnselectAll()
{
if ( m_windowStyle & wxTR_MULTIPLE )
{
wxArrayTreeItemIds selections;
size_t count = GetSelections(selections);
for ( size_t n = 0; n < count; n++ )
{
SetItemCheck(selections[n], FALSE);
}
}
else
{
// just remove the selection
Unselect();
}
}
void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
{
// inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
// the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
// send them ourselves
wxTreeEvent event(wxEVT_NULL, m_windowId);
event.m_item = item;
event.SetEventObject(this);
event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING);
if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
if ( m_windowStyle & wxTR_MULTIPLE )
{
if ( !TreeView_SelectItem(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
{
wxLogLastError("TreeView_SelectItem");
}
else
{
event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
(void)GetEventHandler()->ProcessEvent(event);
}
// selecting the item means checking it
SetItemCheck(item);
}
else
{
// inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
// the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
// send them ourselves
wxTreeEvent event(wxEVT_NULL, m_windowId);
event.m_item = item;
event.SetEventObject(this);
event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING);
if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
{
if ( !TreeView_SelectItem(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
{
wxLogLastError("TreeView_SelectItem");
}
else
{
event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
(void)GetEventHandler()->ProcessEvent(event);
}
}
//else: program vetoed the change
}
//else: program vetoed the change
}
void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)