]> git.saurik.com Git - wxWidgets.git/blame - src/msw/treectrl.cpp
Corrected problem related to wxSIZE_ALLOW_MINUS_ONE
[wxWidgets.git] / src / msw / treectrl.cpp
CommitLineData
b823f5a1
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: treectrl.cpp
3// Purpose: wxTreeCtrl
4// Author: Julian Smart
08b7c251 5// Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98
b823f5a1
JS
6// Created: 1997
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
08b7c251 9// Licence: wxWindows licence
b823f5a1 10/////////////////////////////////////////////////////////////////////////////
2bda0e17 11
08b7c251
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
2bda0e17 19#ifdef __GNUG__
08b7c251 20 #pragma implementation "treectrl.h"
2bda0e17
KB
21#endif
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
08b7c251 27 #pragma hdrstop
2bda0e17
KB
28#endif
29
0c589ad0
BM
30#include "wx/window.h"
31#include "wx/msw/private.h"
32
0c589ad0
BM
33// Mingw32 is a bit mental even though this is done in winundef
34#ifdef GetFirstChild
d220ae32 35 #undef GetFirstChild
0c589ad0 36#endif
d220ae32 37
0c589ad0 38#ifdef GetNextSibling
d220ae32 39 #undef GetNextSibling
2bda0e17
KB
40#endif
41
2bda0e17
KB
42#if defined(__WIN95__)
43
08b7c251 44#include "wx/log.h"
ce3ed50d 45#include "wx/dynarray.h"
08b7c251 46#include "wx/imaglist.h"
53f69f7a 47#include "wx/treectrl.h"
77cff606 48#include "wx/settings.h"
08b7c251 49
9a05fd8d 50#ifdef __GNUWIN32__
65fd5cb0 51#ifndef wxUSE_NORLANDER_HEADERS
9a05fd8d
JS
52#include "wx/msw/gnuwin32/extra.h"
53#endif
65fd5cb0 54#endif
9a05fd8d 55
65fd5cb0 56#if (defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__) || defined(wxUSE_NORLANDER_HEADERS)
08b7c251 57 #include <commctrl.h>
2bda0e17
KB
58#endif
59
60// Bug in headers, sometimes
61#ifndef TVIS_FOCUSED
08b7c251 62 #define TVIS_FOCUSED 0x0001
2bda0e17
KB
63#endif
64
bb448552
VZ
65#ifndef TV_FIRST
66 #define TV_FIRST 0x1100
67#endif
68
69// old headers might miss these messages (comctl32.dll 4.71+ only)
70#ifndef TVM_SETBKCOLOR
71 #define TVM_SETBKCOLOR (TV_FIRST + 29)
72 #define TVM_SETTEXTCOLOR (TV_FIRST + 30)
73#endif
74
08b7c251
VZ
75// ----------------------------------------------------------------------------
76// private classes
77// ----------------------------------------------------------------------------
2bda0e17 78
08b7c251 79// a convenient wrapper around TV_ITEM struct which adds a ctor
f3ef286f 80#ifdef __VISUALC__
197dd9af 81#pragma warning( disable : 4097 )
f3ef286f
JS
82#endif
83
08b7c251
VZ
84struct wxTreeViewItem : public TV_ITEM
85{
9dfbf520
VZ
86 wxTreeViewItem(const wxTreeItemId& item, // the item handle
87 UINT mask_, // fields which are valid
88 UINT stateMask_ = 0) // for TVIF_STATE only
08b7c251 89 {
9dfbf520
VZ
90 // hItem member is always valid
91 mask = mask_ | TVIF_HANDLE;
08b7c251 92 stateMask = stateMask_;
06e38c8e 93 hItem = (HTREEITEM) (WXHTREEITEM) item;
08b7c251
VZ
94 }
95};
f3ef286f
JS
96
97#ifdef __VISUALC__
197dd9af 98#pragma warning( default : 4097 )
f3ef286f 99#endif
2bda0e17 100
9dfbf520
VZ
101// a class which encapsulates the tree traversal logic: it vists all (unless
102// OnVisit() returns FALSE) items under the given one
103class wxTreeTraversal
104{
105public:
106 wxTreeTraversal(const wxTreeCtrl *tree)
107 {
108 m_tree = tree;
109 }
110
111 // do traverse the tree: visit all items (recursively by default) under the
112 // given one; return TRUE if all items were traversed or FALSE if the
113 // traversal was aborted because OnVisit returned FALSE
114 bool DoTraverse(const wxTreeItemId& root, bool recursively = TRUE);
115
116 // override this function to do whatever is needed for each item, return
117 // FALSE to stop traversing
118 virtual bool OnVisit(const wxTreeItemId& item) = 0;
119
120protected:
121 const wxTreeCtrl *GetTree() const { return m_tree; }
122
123private:
124 bool Traverse(const wxTreeItemId& root, bool recursively);
125
126 const wxTreeCtrl *m_tree;
127};
128
74b31181
VZ
129// internal class for getting the selected items
130class TraverseSelections : public wxTreeTraversal
131{
132public:
133 TraverseSelections(const wxTreeCtrl *tree,
134 wxArrayTreeItemIds& selections)
135 : wxTreeTraversal(tree), m_selections(selections)
136 {
137 m_selections.Empty();
138
139 DoTraverse(tree->GetRootItem());
140 }
141
142 virtual bool OnVisit(const wxTreeItemId& item)
143 {
144 if ( GetTree()->IsItemChecked(item) )
145 {
146 m_selections.Add(item);
147 }
148
149 return TRUE;
150 }
151
152private:
153 wxArrayTreeItemIds& m_selections;
154};
155
156// internal class for counting tree items
157class TraverseCounter : public wxTreeTraversal
158{
159public:
160 TraverseCounter(const wxTreeCtrl *tree,
161 const wxTreeItemId& root,
162 bool recursively)
163 : wxTreeTraversal(tree)
164 {
165 m_count = 0;
166
167 DoTraverse(root, recursively);
168 }
169
170 virtual bool OnVisit(const wxTreeItemId& item)
171 {
172 m_count++;
173
174 return TRUE;
175 }
176
177 size_t GetCount() const { return m_count; }
178
179private:
180 size_t m_count;
181};
182
183// ----------------------------------------------------------------------------
184// This class is needed for support of different images: the Win32 common
185// control natively supports only 2 images (the normal one and another for the
186// selected state). We wish to provide support for 2 more of them for folder
187// items (i.e. those which have children): for expanded state and for expanded
188// selected state. For this we use this structure to store the additional items
189// images.
190//
191// There is only one problem with this: when we retrieve the item's data, we
192// don't know whether we get a pointer to wxTreeItemData or
193// wxTreeItemIndirectData. So we have to maintain a list of all items which
194// have indirect data inside the listctrl itself.
195// ----------------------------------------------------------------------------
696e1ea0 196
74b31181
VZ
197class wxTreeItemIndirectData
198{
199public:
200 // ctor associates this data with the item and the real item data becomes
201 // available through our GetData() method
202 wxTreeItemIndirectData(wxTreeCtrl *tree, const wxTreeItemId& item)
203 {
204 for ( size_t n = 0; n < WXSIZEOF(m_images); n++ )
205 {
206 m_images[n] = -1;
207 }
208
209 // save the old data
210 m_data = tree->GetItemData(item);
211
212 // and set ourselves as the new one
213 tree->SetIndirectItemData(item, this);
214 }
215
216 // dtor deletes the associated data as well
217 ~wxTreeItemIndirectData() { delete m_data; }
218
219 // accessors
220 // get the real data associated with the item
221 wxTreeItemData *GetData() const { return m_data; }
222 // change it
223 void SetData(wxTreeItemData *data) { m_data = data; }
224
225 // do we have such image?
226 bool HasImage(wxTreeItemIcon which) const { return m_images[which] != -1; }
227 // get image
228 int GetImage(wxTreeItemIcon which) const { return m_images[which]; }
229 // change it
230 void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; }
231
232private:
233 // all the images associated with the item
234 int m_images[wxTreeItemIcon_Max];
235
236 wxTreeItemData *m_data;
237};
238
08b7c251
VZ
239// ----------------------------------------------------------------------------
240// macros
241// ----------------------------------------------------------------------------
242
08b7c251 243 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
2bda0e17 244
08b7c251
VZ
245// ----------------------------------------------------------------------------
246// variables
247// ----------------------------------------------------------------------------
248
249// handy table for sending events
250static const wxEventType g_events[2][2] =
2bda0e17 251{
08b7c251
VZ
252 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
253 { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING }
254};
255
256// ============================================================================
257// implementation
258// ============================================================================
259
9dfbf520
VZ
260// ----------------------------------------------------------------------------
261// tree traversal
262// ----------------------------------------------------------------------------
263
264bool wxTreeTraversal::DoTraverse(const wxTreeItemId& root, bool recursively)
265{
266 if ( !OnVisit(root) )
267 return FALSE;
268
269 return Traverse(root, recursively);
270}
271
272bool wxTreeTraversal::Traverse(const wxTreeItemId& root, bool recursively)
273{
274 long cookie;
275 wxTreeItemId child = m_tree->GetFirstChild(root, cookie);
276 while ( child.IsOk() )
277 {
278 // depth first traversal
279 if ( recursively && !Traverse(child, TRUE) )
280 return FALSE;
281
282 if ( !OnVisit(child) )
283 return FALSE;
284
285 child = m_tree->GetNextChild(root, cookie);
286 }
287
288 return TRUE;
289}
290
08b7c251
VZ
291// ----------------------------------------------------------------------------
292// construction and destruction
293// ----------------------------------------------------------------------------
294
295void wxTreeCtrl::Init()
296{
297 m_imageListNormal = NULL;
298 m_imageListState = NULL;
299 m_textCtrl = NULL;
696e1ea0 300 m_hasAnyAttr = FALSE;
2bda0e17
KB
301}
302
9dfbf520
VZ
303bool wxTreeCtrl::Create(wxWindow *parent,
304 wxWindowID id,
305 const wxPoint& pos,
306 const wxSize& size,
307 long style,
308 const wxValidator& validator,
08b7c251 309 const wxString& name)
2bda0e17 310{
08b7c251 311 Init();
2bda0e17 312
9dfbf520
VZ
313 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
314 return FALSE;
2bda0e17 315
5ea47806
VZ
316 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
317 TVS_HASLINES | TVS_SHOWSELALWAYS;
2bda0e17 318
08b7c251
VZ
319 if ( m_windowStyle & wxTR_HAS_BUTTONS )
320 wstyle |= TVS_HASBUTTONS;
2bda0e17 321
08b7c251
VZ
322 if ( m_windowStyle & wxTR_EDIT_LABELS )
323 wstyle |= TVS_EDITLABELS;
2bda0e17 324
08b7c251
VZ
325 if ( m_windowStyle & wxTR_LINES_AT_ROOT )
326 wstyle |= TVS_LINESATROOT;
2bda0e17 327
a925b006 328#if !defined( __GNUWIN32__ ) && !defined( __BORLANDC__ ) && !defined( __WATCOMC__ ) && !defined(wxUSE_NORLANDER_HEADERS)
9dfbf520
VZ
329 // we emulate the multiple selection tree controls by using checkboxes: set
330 // up the image list we need for this if we do have multiple selections
6474416b 331#if !defined(__VISUALC__) || (__VISUALC__ > 1010)
9dfbf520 332 if ( m_windowStyle & wxTR_MULTIPLE )
10fcf31a 333 wstyle |= TVS_CHECKBOXES;
2996bcde 334#endif
2899e223 335#endif
9dfbf520 336
08b7c251 337 // Create the tree control.
9dfbf520
VZ
338 if ( !MSWCreateControl(WC_TREEVIEW, wstyle) )
339 return FALSE;
340
5aeeab14
RD
341 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
342 SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
343
9dfbf520
VZ
344 // VZ: this is some experimental code which may be used to get the
345 // TVS_CHECKBOXES style functionality for comctl32.dll < 4.71.
346 // AFAIK, the standard DLL does about the same thing anyhow.
347#if 0
348 if ( m_windowStyle & wxTR_MULTIPLE )
349 {
350 wxBitmap bmp;
351
352 // create the DC compatible with the current screen
353 HDC hdcMem = CreateCompatibleDC(NULL);
354
355 // create a mono bitmap of the standard size
356 int x = GetSystemMetrics(SM_CXMENUCHECK);
357 int y = GetSystemMetrics(SM_CYMENUCHECK);
358 wxImageList imagelistCheckboxes(x, y, FALSE, 2);
359 HBITMAP hbmpCheck = CreateBitmap(x, y, // bitmap size
360 1, // # of color planes
361 1, // # bits needed for one pixel
362 0); // array containing colour data
363 SelectObject(hdcMem, hbmpCheck);
364
365 // then draw a check mark into it
366 RECT rect = { 0, 0, x, y };
367 if ( !::DrawFrameControl(hdcMem, &rect,
368 DFC_BUTTON,
369 DFCS_BUTTONCHECK | DFCS_CHECKED) )
370 {
223d09f6 371 wxLogLastError(wxT("DrawFrameControl(check)"));
9dfbf520
VZ
372 }
373
374 bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
375 imagelistCheckboxes.Add(bmp);
376
377 if ( !::DrawFrameControl(hdcMem, &rect,
378 DFC_BUTTON,
379 DFCS_BUTTONCHECK) )
380 {
223d09f6 381 wxLogLastError(wxT("DrawFrameControl(uncheck)"));
9dfbf520
VZ
382 }
383
384 bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
385 imagelistCheckboxes.Add(bmp);
386
387 // clean up
388 ::DeleteDC(hdcMem);
389
390 // set the imagelist
391 SetStateImageList(&imagelistCheckboxes);
392 }
393#endif // 0
394
395 SetSize(pos.x, pos.y, size.x, size.y);
2bda0e17 396
08b7c251 397 return TRUE;
2bda0e17
KB
398}
399
08b7c251 400wxTreeCtrl::~wxTreeCtrl()
2bda0e17 401{
696e1ea0
VZ
402 // delete any attributes
403 if ( m_hasAnyAttr )
404 {
405 for ( wxNode *node = m_attrs.Next(); node; node = m_attrs.Next() )
406 {
407 delete (wxTreeItemAttr *)node->Data();
408 }
409
410 // prevent TVN_DELETEITEM handler from deleting the attributes again!
411 m_hasAnyAttr = FALSE;
412 }
413
08b7c251 414 DeleteTextCtrl();
2bda0e17 415
08b7c251
VZ
416 // delete user data to prevent memory leaks
417 DeleteAllItems();
2bda0e17
KB
418}
419
08b7c251
VZ
420// ----------------------------------------------------------------------------
421// accessors
422// ----------------------------------------------------------------------------
2bda0e17 423
08b7c251 424// simple wrappers which add error checking in debug mode
2bda0e17 425
08b7c251 426bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const
2bda0e17 427{
d220ae32 428 if ( !TreeView_GetItem(GetHwnd(), tvItem) )
2bda0e17 429 {
08b7c251
VZ
430 wxLogLastError("TreeView_GetItem");
431
432 return FALSE;
433 }
434
435 return TRUE;
2bda0e17
KB
436}
437
08b7c251 438void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem)
2bda0e17 439{
d220ae32 440 if ( TreeView_SetItem(GetHwnd(), tvItem) == -1 )
2bda0e17 441 {
08b7c251
VZ
442 wxLogLastError("TreeView_SetItem");
443 }
2bda0e17
KB
444}
445
08b7c251 446size_t wxTreeCtrl::GetCount() const
2bda0e17 447{
d220ae32 448 return (size_t)TreeView_GetCount(GetHwnd());
2bda0e17
KB
449}
450
08b7c251 451unsigned int wxTreeCtrl::GetIndent() const
2bda0e17 452{
d220ae32 453 return TreeView_GetIndent(GetHwnd());
2bda0e17
KB
454}
455
08b7c251 456void wxTreeCtrl::SetIndent(unsigned int indent)
2bda0e17 457{
d220ae32 458 TreeView_SetIndent(GetHwnd(), indent);
2bda0e17
KB
459}
460
08b7c251 461wxImageList *wxTreeCtrl::GetImageList() const
2bda0e17 462{
08b7c251 463 return m_imageListNormal;
2bda0e17
KB
464}
465
08b7c251 466wxImageList *wxTreeCtrl::GetStateImageList() const
2bda0e17 467{
08b7c251 468 return m_imageListNormal;
2bda0e17
KB
469}
470
08b7c251 471void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which)
2bda0e17 472{
08b7c251 473 // no error return
d220ae32 474 TreeView_SetImageList(GetHwnd(),
08b7c251
VZ
475 imageList ? imageList->GetHIMAGELIST() : 0,
476 which);
2bda0e17
KB
477}
478
08b7c251 479void wxTreeCtrl::SetImageList(wxImageList *imageList)
2bda0e17 480{
08b7c251 481 SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
2bda0e17
KB
482}
483
08b7c251 484void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
2bda0e17 485{
08b7c251 486 SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
2bda0e17
KB
487}
488
33961d59
RR
489size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item,
490 bool recursively) const
491{
492 TraverseCounter counter(this, item, recursively);
23fd5130 493
73974df1 494 return counter.GetCount() - 1;
23fd5130
VZ
495}
496
bb448552
VZ
497// ----------------------------------------------------------------------------
498// control colours
499// ----------------------------------------------------------------------------
500
501bool wxTreeCtrl::SetBackgroundColour(const wxColour &colour)
502{
503 if ( !wxWindowBase::SetBackgroundColour(colour) )
504 return FALSE;
505
506 SendMessage(GetHwnd(), TVM_SETBKCOLOR, 0, colour.GetPixel());
507
508 return TRUE;
509}
510
511bool wxTreeCtrl::SetForegroundColour(const wxColour &colour)
512{
513 if ( !wxWindowBase::SetForegroundColour(colour) )
514 return FALSE;
515
516 SendMessage(GetHwnd(), TVM_SETTEXTCOLOR, 0, colour.GetPixel());
517
518 return TRUE;
519}
520
08b7c251
VZ
521// ----------------------------------------------------------------------------
522// Item access
523// ----------------------------------------------------------------------------
524
525wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
2bda0e17 526{
837e5743 527 wxChar buf[512]; // the size is arbitrary...
02ce7b72 528
08b7c251
VZ
529 wxTreeViewItem tvItem(item, TVIF_TEXT);
530 tvItem.pszText = buf;
531 tvItem.cchTextMax = WXSIZEOF(buf);
532 if ( !DoGetItem(&tvItem) )
533 {
534 // don't return some garbage which was on stack, but an empty string
223d09f6 535 buf[0] = wxT('\0');
08b7c251 536 }
2bda0e17 537
08b7c251
VZ
538 return wxString(buf);
539}
2bda0e17 540
08b7c251
VZ
541void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
542{
543 wxTreeViewItem tvItem(item, TVIF_TEXT);
837e5743 544 tvItem.pszText = (wxChar *)text.c_str(); // conversion is ok
08b7c251
VZ
545 DoSetItem(&tvItem);
546}
2bda0e17 547
74b31181
VZ
548int wxTreeCtrl::DoGetItemImageFromData(const wxTreeItemId& item,
549 wxTreeItemIcon which) const
550{
551 wxTreeViewItem tvItem(item, TVIF_PARAM);
552 if ( !DoGetItem(&tvItem) )
553 {
554 return -1;
555 }
556
557 return ((wxTreeItemIndirectData *)tvItem.lParam)->GetImage(which);
558}
559
560void wxTreeCtrl::DoSetItemImageFromData(const wxTreeItemId& item,
561 int image,
562 wxTreeItemIcon which) const
563{
564 wxTreeViewItem tvItem(item, TVIF_PARAM);
565 if ( !DoGetItem(&tvItem) )
566 {
567 return;
568 }
569
570 wxTreeItemIndirectData *data = ((wxTreeItemIndirectData *)tvItem.lParam);
571
572 data->SetImage(image, which);
573
574 // make sure that we have selected images as well
575 if ( which == wxTreeItemIcon_Normal &&
576 !data->HasImage(wxTreeItemIcon_Selected) )
577 {
578 data->SetImage(image, wxTreeItemIcon_Selected);
579 }
580
581 if ( which == wxTreeItemIcon_Expanded &&
582 !data->HasImage(wxTreeItemIcon_SelectedExpanded) )
583 {
584 data->SetImage(image, wxTreeItemIcon_SelectedExpanded);
585 }
586}
587
9dfbf520
VZ
588void wxTreeCtrl::DoSetItemImages(const wxTreeItemId& item,
589 int image,
590 int imageSel)
591{
592 wxTreeViewItem tvItem(item, TVIF_IMAGE | TVIF_SELECTEDIMAGE);
593 tvItem.iSelectedImage = imageSel;
594 tvItem.iImage = image;
595 DoSetItem(&tvItem);
596}
597
74b31181
VZ
598int wxTreeCtrl::GetItemImage(const wxTreeItemId& item,
599 wxTreeItemIcon which) const
08b7c251 600{
74b31181
VZ
601 if ( HasIndirectData(item) )
602 {
603 return DoGetItemImageFromData(item, which);
604 }
2bda0e17 605
74b31181
VZ
606 UINT mask;
607 switch ( which )
608 {
609 default:
223d09f6 610 wxFAIL_MSG( wxT("unknown tree item image type") );
2bda0e17 611
74b31181
VZ
612 case wxTreeItemIcon_Normal:
613 mask = TVIF_IMAGE;
614 break;
2bda0e17 615
74b31181
VZ
616 case wxTreeItemIcon_Selected:
617 mask = TVIF_SELECTEDIMAGE;
618 break;
619
620 case wxTreeItemIcon_Expanded:
621 case wxTreeItemIcon_SelectedExpanded:
622 return -1;
623 }
624
625 wxTreeViewItem tvItem(item, mask);
08b7c251 626 DoGetItem(&tvItem);
2bda0e17 627
74b31181 628 return mask == TVIF_IMAGE ? tvItem.iImage : tvItem.iSelectedImage;
2bda0e17
KB
629}
630
74b31181
VZ
631void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image,
632 wxTreeItemIcon which)
2bda0e17 633{
74b31181
VZ
634 int imageNormal, imageSel;
635 switch ( which )
636 {
637 default:
223d09f6 638 wxFAIL_MSG( wxT("unknown tree item image type") );
74b31181
VZ
639
640 case wxTreeItemIcon_Normal:
641 imageNormal = image;
642 imageSel = GetItemSelectedImage(item);
643 break;
644
645 case wxTreeItemIcon_Selected:
646 imageNormal = GetItemImage(item);
647 imageSel = image;
648 break;
649
650 case wxTreeItemIcon_Expanded:
651 case wxTreeItemIcon_SelectedExpanded:
652 if ( !HasIndirectData(item) )
653 {
654 // we need to get the old images first, because after we create
655 // the wxTreeItemIndirectData GetItemXXXImage() will use it to
656 // get the images
657 imageNormal = GetItemImage(item);
658 imageSel = GetItemSelectedImage(item);
659
660 // if it doesn't have it yet, add it
661 wxTreeItemIndirectData *data = new
662 wxTreeItemIndirectData(this, item);
663
664 // copy the data to the new location
665 data->SetImage(imageNormal, wxTreeItemIcon_Normal);
666 data->SetImage(imageSel, wxTreeItemIcon_Selected);
667 }
668
669 DoSetItemImageFromData(item, image, which);
670
671 // reset the normal/selected images because we won't use them any
672 // more - now they're stored inside the indirect data
673 imageNormal =
674 imageSel = I_IMAGECALLBACK;
675 break;
676 }
677
9dfbf520
VZ
678 // NB: at least in version 5.00.0518.9 of comctl32.dll we need to always
679 // change both normal and selected image - otherwise the change simply
680 // doesn't take place!
74b31181 681 DoSetItemImages(item, imageNormal, imageSel);
2bda0e17
KB
682}
683
08b7c251 684wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
2bda0e17 685{
08b7c251
VZ
686 wxTreeViewItem tvItem(item, TVIF_PARAM);
687 if ( !DoGetItem(&tvItem) )
688 {
689 return NULL;
690 }
2bda0e17 691
74b31181
VZ
692 if ( HasIndirectData(item) )
693 {
694 return ((wxTreeItemIndirectData *)tvItem.lParam)->GetData();
695 }
696 else
697 {
698 return (wxTreeItemData *)tvItem.lParam;
699 }
2bda0e17
KB
700}
701
08b7c251 702void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
2bda0e17 703{
08b7c251 704 wxTreeViewItem tvItem(item, TVIF_PARAM);
74b31181
VZ
705
706 if ( HasIndirectData(item) )
707 {
708 if ( DoGetItem(&tvItem) )
709 {
710 ((wxTreeItemIndirectData *)tvItem.lParam)->SetData(data);
711 }
712 else
713 {
223d09f6 714 wxFAIL_MSG( wxT("failed to change tree items data") );
74b31181
VZ
715 }
716 }
717 else
718 {
719 tvItem.lParam = (LPARAM)data;
720 DoSetItem(&tvItem);
721 }
722}
723
724void wxTreeCtrl::SetIndirectItemData(const wxTreeItemId& item,
725 wxTreeItemIndirectData *data)
726{
727 // this should never happen because it's unnecessary and will probably lead
728 // to crash too because the code elsewhere supposes that the pointer the
729 // wxTreeItemIndirectData has is a real wxItemData and not
730 // wxTreeItemIndirectData as well
223d09f6 731 wxASSERT_MSG( !HasIndirectData(item), wxT("setting indirect data twice?") );
74b31181
VZ
732
733 SetItemData(item, (wxTreeItemData *)data);
734
735 m_itemsWithIndirectData.Add(item);
736}
737
738bool wxTreeCtrl::HasIndirectData(const wxTreeItemId& item) const
739{
740 return m_itemsWithIndirectData.Index(item) != wxNOT_FOUND;
08b7c251 741}
2bda0e17 742
3a5a2f56
VZ
743void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
744{
745 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
746 tvItem.cChildren = (int)has;
747 DoSetItem(&tvItem);
748}
749
add28c55
VZ
750void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
751{
752 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
753 tvItem.state = bold ? TVIS_BOLD : 0;
754 DoSetItem(&tvItem);
755}
756
58a8ab88
JS
757void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight)
758{
759 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_DROPHILITED);
760 tvItem.state = highlight ? TVIS_DROPHILITED : 0;
761 DoSetItem(&tvItem);
762}
763
696e1ea0
VZ
764void wxTreeCtrl::SetItemTextColour(const wxTreeItemId& item,
765 const wxColour& col)
766{
767 m_hasAnyAttr = TRUE;
768
769 long id = (long)(WXHTREEITEM)item;
770 wxTreeItemAttr *attr = (wxTreeItemAttr *)m_attrs.Get(id);
771 if ( !attr )
772 {
773 attr = new wxTreeItemAttr;
774 m_attrs.Put(id, (wxObject *)attr);
775 }
776
777 attr->SetTextColour(col);
778}
779
780void wxTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
781 const wxColour& col)
782{
783 m_hasAnyAttr = TRUE;
784
785 long id = (long)(WXHTREEITEM)item;
786 wxTreeItemAttr *attr = (wxTreeItemAttr *)m_attrs.Get(id);
787 if ( !attr )
788 {
789 attr = new wxTreeItemAttr;
790 m_attrs.Put(id, (wxObject *)attr);
791 }
792
793 attr->SetBackgroundColour(col);
794}
795
796void wxTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font)
797{
798 m_hasAnyAttr = TRUE;
799
800 long id = (long)(WXHTREEITEM)item;
801 wxTreeItemAttr *attr = (wxTreeItemAttr *)m_attrs.Get(id);
802 if ( !attr )
803 {
804 attr = new wxTreeItemAttr;
805 m_attrs.Put(id, (wxObject *)attr);
806 }
807
808 attr->SetFont(font);
809}
810
08b7c251
VZ
811// ----------------------------------------------------------------------------
812// Item status
813// ----------------------------------------------------------------------------
2bda0e17 814
08b7c251
VZ
815bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
816{
add28c55 817 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
08b7c251 818 RECT rect;
955be36c
VZ
819
820 // this ugliness comes directly from MSDN - it *is* the correct way to pass
821 // the HTREEITEM with TVM_GETITEMRECT
822 *(WXHTREEITEM *)&rect = (WXHTREEITEM)item;
823
824 // FALSE means get item rect for the whole item, not only text
1c74a900 825 return SendMessage(GetHwnd(), TVM_GETITEMRECT, FALSE, (LPARAM)&rect) != 0;
06e38c8e 826
2bda0e17
KB
827}
828
08b7c251 829bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
2bda0e17 830{
08b7c251
VZ
831 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
832 DoGetItem(&tvItem);
2bda0e17 833
08b7c251 834 return tvItem.cChildren != 0;
2bda0e17
KB
835}
836
08b7c251 837bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
2bda0e17 838{
08b7c251
VZ
839 // probably not a good idea to put it here
840 //wxASSERT( ItemHasChildren(item) );
2bda0e17 841
08b7c251
VZ
842 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDED);
843 DoGetItem(&tvItem);
2bda0e17 844
08b7c251 845 return (tvItem.state & TVIS_EXPANDED) != 0;
2bda0e17
KB
846}
847
08b7c251 848bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
2bda0e17 849{
08b7c251
VZ
850 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_SELECTED);
851 DoGetItem(&tvItem);
2bda0e17 852
08b7c251 853 return (tvItem.state & TVIS_SELECTED) != 0;
2bda0e17
KB
854}
855
add28c55
VZ
856bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
857{
858 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
859 DoGetItem(&tvItem);
860
861 return (tvItem.state & TVIS_BOLD) != 0;
862}
863
08b7c251
VZ
864// ----------------------------------------------------------------------------
865// navigation
866// ----------------------------------------------------------------------------
2bda0e17 867
08b7c251
VZ
868wxTreeItemId wxTreeCtrl::GetRootItem() const
869{
d220ae32 870 return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(GetHwnd()));
08b7c251 871}
2bda0e17 872
08b7c251
VZ
873wxTreeItemId wxTreeCtrl::GetSelection() const
874{
9dfbf520 875 wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (WXHTREEITEM)0,
223d09f6 876 wxT("this only works with single selection controls") );
9dfbf520 877
d220ae32 878 return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(GetHwnd()));
2bda0e17
KB
879}
880
08b7c251 881wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
2bda0e17 882{
d220ae32 883 return wxTreeItemId((WXHTREEITEM) TreeView_GetParent(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
08b7c251 884}
2bda0e17 885
08b7c251 886wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
06e38c8e 887 long& _cookie) const
08b7c251
VZ
888{
889 // remember the last child returned in 'cookie'
d220ae32 890 _cookie = (long)TreeView_GetChild(GetHwnd(), (HTREEITEM) (WXHTREEITEM)item);
2bda0e17 891
06e38c8e 892 return wxTreeItemId((WXHTREEITEM)_cookie);
2bda0e17
KB
893}
894
08b7c251 895wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& WXUNUSED(item),
06e38c8e 896 long& _cookie) const
2bda0e17 897{
d220ae32 898 wxTreeItemId l = wxTreeItemId((WXHTREEITEM)TreeView_GetNextSibling(GetHwnd(),
23fd5130
VZ
899 (HTREEITEM)(WXHTREEITEM)_cookie));
900 _cookie = (long)l;
901
2e5dddb0 902 return l;
08b7c251 903}
2bda0e17 904
978f38c2
VZ
905wxTreeItemId wxTreeCtrl::GetLastChild(const wxTreeItemId& item) const
906{
907 // can this be done more efficiently?
908 long cookie;
909
910 wxTreeItemId childLast,
2165ad93 911 child = GetFirstChild(item, cookie);
978f38c2
VZ
912 while ( child.IsOk() )
913 {
914 childLast = child;
2165ad93 915 child = GetNextChild(item, cookie);
978f38c2
VZ
916 }
917
918 return childLast;
919}
920
08b7c251
VZ
921wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
922{
d220ae32 923 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextSibling(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
2bda0e17
KB
924}
925
08b7c251 926wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
2bda0e17 927{
d220ae32 928 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevSibling(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
2bda0e17
KB
929}
930
08b7c251 931wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
2bda0e17 932{
d220ae32 933 return wxTreeItemId((WXHTREEITEM) TreeView_GetFirstVisible(GetHwnd()));
2bda0e17
KB
934}
935
08b7c251 936wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
2bda0e17 937{
223d09f6 938 wxASSERT_MSG( IsVisible(item), wxT("The item you call GetNextVisible() "
837e5743 939 "for must be visible itself!"));
02ce7b72 940
d220ae32 941 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
08b7c251 942}
02ce7b72 943
08b7c251
VZ
944wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
945{
223d09f6 946 wxASSERT_MSG( IsVisible(item), wxT("The item you call GetPrevVisible() "
837e5743 947 "for must be visible itself!"));
02ce7b72 948
d220ae32 949 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
08b7c251 950}
02ce7b72 951
9dfbf520
VZ
952// ----------------------------------------------------------------------------
953// multiple selections emulation
954// ----------------------------------------------------------------------------
955
956bool wxTreeCtrl::IsItemChecked(const wxTreeItemId& item) const
957{
958 // receive the desired information.
959 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
960 DoGetItem(&tvItem);
961
962 // state image indices are 1 based
963 return ((tvItem.state >> 12) - 1) == 1;
964}
965
966void wxTreeCtrl::SetItemCheck(const wxTreeItemId& item, bool check)
967{
968 // receive the desired information.
969 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
970
971 // state images are one-based
972 tvItem.state = (check ? 2 : 1) << 12;
973
974 DoSetItem(&tvItem);
975}
976
33961d59
RR
977size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds& selections) const
978{
979 TraverseSelections selector(this, selections);
9dfbf520
VZ
980
981 return selections.GetCount();
982}
983
08b7c251
VZ
984// ----------------------------------------------------------------------------
985// Usual operations
986// ----------------------------------------------------------------------------
02ce7b72 987
08b7c251
VZ
988wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent,
989 wxTreeItemId hInsertAfter,
990 const wxString& text,
991 int image, int selectedImage,
992 wxTreeItemData *data)
993{
994 TV_INSERTSTRUCT tvIns;
06e38c8e
JS
995 tvIns.hParent = (HTREEITEM) (WXHTREEITEM)parent;
996 tvIns.hInsertAfter = (HTREEITEM) (WXHTREEITEM) hInsertAfter;
58a8ab88 997
74b31181
VZ
998 // this is how we insert the item as the first child: supply a NULL
999 // hInsertAfter
1000 if ( !tvIns.hInsertAfter )
58a8ab88
JS
1001 {
1002 tvIns.hInsertAfter = TVI_FIRST;
1003 }
1004
08b7c251
VZ
1005 UINT mask = 0;
1006 if ( !text.IsEmpty() )
1007 {
1008 mask |= TVIF_TEXT;
837e5743 1009 tvIns.item.pszText = (wxChar *)text.c_str(); // cast is ok
08b7c251 1010 }
02ce7b72 1011
08b7c251
VZ
1012 if ( image != -1 )
1013 {
1014 mask |= TVIF_IMAGE;
1015 tvIns.item.iImage = image;
3a5a2f56 1016
6b037754 1017 if ( selectedImage == -1 )
3a5a2f56
VZ
1018 {
1019 // take the same image for selected icon if not specified
1020 selectedImage = image;
1021 }
08b7c251 1022 }
02ce7b72 1023
08b7c251
VZ
1024 if ( selectedImage != -1 )
1025 {
1026 mask |= TVIF_SELECTEDIMAGE;
1027 tvIns.item.iSelectedImage = selectedImage;
1028 }
02ce7b72 1029
08b7c251
VZ
1030 if ( data != NULL )
1031 {
1032 mask |= TVIF_PARAM;
1033 tvIns.item.lParam = (LPARAM)data;
1034 }
02ce7b72 1035
08b7c251 1036 tvIns.item.mask = mask;
02ce7b72 1037
d220ae32 1038 HTREEITEM id = (HTREEITEM) TreeView_InsertItem(GetHwnd(), &tvIns);
08b7c251
VZ
1039 if ( id == 0 )
1040 {
1041 wxLogLastError("TreeView_InsertItem");
1042 }
02ce7b72 1043
fd3f686c
VZ
1044 if ( data != NULL )
1045 {
1046 // associate the application tree item with Win32 tree item handle
1047 data->SetId((WXHTREEITEM)id);
1048 }
1049
06e38c8e 1050 return wxTreeItemId((WXHTREEITEM)id);
2bda0e17
KB
1051}
1052
08b7c251
VZ
1053// for compatibility only
1054wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
1055 const wxString& text,
1056 int image, int selImage,
1057 long insertAfter)
2bda0e17 1058{
06e38c8e 1059 return DoInsertItem(parent, (WXHTREEITEM)insertAfter, text,
08b7c251 1060 image, selImage, NULL);
2bda0e17
KB
1061}
1062
08b7c251
VZ
1063wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
1064 int image, int selectedImage,
1065 wxTreeItemData *data)
2bda0e17 1066{
06e38c8e 1067 return DoInsertItem(wxTreeItemId((WXHTREEITEM) 0), (WXHTREEITEM) 0,
08b7c251 1068 text, image, selectedImage, data);
2bda0e17
KB
1069}
1070
08b7c251
VZ
1071wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
1072 const wxString& text,
1073 int image, int selectedImage,
1074 wxTreeItemData *data)
2bda0e17 1075{
06e38c8e 1076 return DoInsertItem(parent, (WXHTREEITEM) TVI_FIRST,
08b7c251 1077 text, image, selectedImage, data);
2bda0e17
KB
1078}
1079
08b7c251
VZ
1080wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
1081 const wxTreeItemId& idPrevious,
1082 const wxString& text,
1083 int image, int selectedImage,
1084 wxTreeItemData *data)
2bda0e17 1085{
08b7c251 1086 return DoInsertItem(parent, idPrevious, text, image, selectedImage, data);
2bda0e17
KB
1087}
1088
2ef31e80
VZ
1089wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
1090 size_t index,
1091 const wxString& text,
1092 int image, int selectedImage,
1093 wxTreeItemData *data)
1094{
1095 // find the item from index
1096 long cookie;
1097 wxTreeItemId idPrev, idCur = GetFirstChild(parent, cookie);
1098 while ( index != 0 && idCur.IsOk() )
1099 {
1100 index--;
1101
1102 idPrev = idCur;
1103 idCur = GetNextChild(parent, cookie);
1104 }
1105
1106 // assert, not check: if the index is invalid, we will append the item
1107 // to the end
1108 wxASSERT_MSG( index == 0, _T("bad index in wxTreeCtrl::InsertItem") );
1109
1110 return DoInsertItem(parent, idPrev, text, image, selectedImage, data);
1111}
1112
08b7c251
VZ
1113wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parent,
1114 const wxString& text,
1115 int image, int selectedImage,
1116 wxTreeItemData *data)
2bda0e17 1117{
06e38c8e 1118 return DoInsertItem(parent, (WXHTREEITEM) TVI_LAST,
08b7c251 1119 text, image, selectedImage, data);
2bda0e17
KB
1120}
1121
08b7c251 1122void wxTreeCtrl::Delete(const wxTreeItemId& item)
2bda0e17 1123{
d220ae32 1124 if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item) )
bbcdf8bc 1125 {
08b7c251 1126 wxLogLastError("TreeView_DeleteItem");
bbcdf8bc 1127 }
bbcdf8bc
JS
1128}
1129
23fd5130
VZ
1130// delete all children (but don't delete the item itself)
1131void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item)
1132{
1133 long cookie;
1134
1135 wxArrayLong children;
1136 wxTreeItemId child = GetFirstChild(item, cookie);
1137 while ( child.IsOk() )
1138 {
1139 children.Add((long)(WXHTREEITEM)child);
1140
1141 child = GetNextChild(item, cookie);
1142 }
1143
1144 size_t nCount = children.Count();
1145 for ( size_t n = 0; n < nCount; n++ )
1146 {
d220ae32 1147 if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM)children[n]) )
23fd5130
VZ
1148 {
1149 wxLogLastError("TreeView_DeleteItem");
1150 }
1151 }
1152}
1153
08b7c251 1154void wxTreeCtrl::DeleteAllItems()
bbcdf8bc 1155{
d220ae32 1156 if ( !TreeView_DeleteAllItems(GetHwnd()) )
bbcdf8bc 1157 {
08b7c251 1158 wxLogLastError("TreeView_DeleteAllItems");
bbcdf8bc 1159 }
2bda0e17
KB
1160}
1161
08b7c251 1162void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
2bda0e17 1163{
dd3646fd
VZ
1164 wxASSERT_MSG( flag == TVE_COLLAPSE ||
1165 flag == (TVE_COLLAPSE | TVE_COLLAPSERESET) ||
1166 flag == TVE_EXPAND ||
1167 flag == TVE_TOGGLE,
223d09f6 1168 wxT("Unknown flag in wxTreeCtrl::DoExpand") );
08b7c251
VZ
1169
1170 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
d220ae32
VZ
1171 // emulate them. This behaviour has changed slightly with comctl32.dll
1172 // v 4.70 - now it does send them but only the first time. To maintain
1173 // compatible behaviour and also in order to not have surprises with the
1174 // future versions, don't rely on this and still do everything ourselves.
1175 // To avoid that the messages be sent twice when the item is expanded for
1176 // the first time we must clear TVIS_EXPANDEDONCE style manually.
1177
1178 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDEDONCE);
1179 tvItem.state = 0;
1180 DoSetItem(&tvItem);
1181
1182 if ( TreeView_Expand(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item, flag) != 0 )
08b7c251
VZ
1183 {
1184 wxTreeEvent event(wxEVT_NULL, m_windowId);
1185 event.m_item = item;
1186
1187 bool isExpanded = IsExpanded(item);
2bda0e17 1188
08b7c251 1189 event.SetEventObject(this);
2bda0e17 1190
d220ae32 1191 // FIXME return value of {EXPAND|COLLAPS}ING event handler is discarded
08b7c251
VZ
1192 event.SetEventType(g_events[isExpanded][TRUE]);
1193 GetEventHandler()->ProcessEvent(event);
2bda0e17 1194
08b7c251
VZ
1195 event.SetEventType(g_events[isExpanded][FALSE]);
1196 GetEventHandler()->ProcessEvent(event);
1197 }
d220ae32 1198 //else: change didn't took place, so do nothing at all
2bda0e17
KB
1199}
1200
08b7c251 1201void wxTreeCtrl::Expand(const wxTreeItemId& item)
2bda0e17 1202{
08b7c251 1203 DoExpand(item, TVE_EXPAND);
2bda0e17 1204}
2bda0e17 1205
08b7c251 1206void wxTreeCtrl::Collapse(const wxTreeItemId& item)
2bda0e17 1207{
08b7c251 1208 DoExpand(item, TVE_COLLAPSE);
2bda0e17
KB
1209}
1210
08b7c251 1211void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
2bda0e17 1212{
dd3646fd 1213 DoExpand(item, TVE_COLLAPSE | TVE_COLLAPSERESET);
2bda0e17
KB
1214}
1215
08b7c251 1216void wxTreeCtrl::Toggle(const wxTreeItemId& item)
2bda0e17 1217{
08b7c251 1218 DoExpand(item, TVE_TOGGLE);
2bda0e17
KB
1219}
1220
42c5812d
UU
1221void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
1222{
9dfbf520 1223 DoExpand(item, action);
42c5812d
UU
1224}
1225
08b7c251 1226void wxTreeCtrl::Unselect()
2bda0e17 1227{
223d09f6 1228 wxASSERT_MSG( !(m_windowStyle & wxTR_MULTIPLE), wxT("doesn't make sense") );
9dfbf520
VZ
1229
1230 // just remove the selection
06e38c8e 1231 SelectItem(wxTreeItemId((WXHTREEITEM) 0));
08b7c251 1232}
02ce7b72 1233
9dfbf520 1234void wxTreeCtrl::UnselectAll()
08b7c251 1235{
9dfbf520 1236 if ( m_windowStyle & wxTR_MULTIPLE )
2bda0e17 1237 {
9dfbf520
VZ
1238 wxArrayTreeItemIds selections;
1239 size_t count = GetSelections(selections);
1240 for ( size_t n = 0; n < count; n++ )
d220ae32 1241 {
9dfbf520 1242 SetItemCheck(selections[n], FALSE);
d220ae32 1243 }
9dfbf520
VZ
1244 }
1245 else
1246 {
1247 // just remove the selection
1248 Unselect();
1249 }
1250}
1251
1252void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
1253{
1254 if ( m_windowStyle & wxTR_MULTIPLE )
1255 {
1256 // selecting the item means checking it
1257 SetItemCheck(item);
1258 }
1259 else
1260 {
1261 // inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
1262 // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
1263 // send them ourselves
1264
1265 wxTreeEvent event(wxEVT_NULL, m_windowId);
1266 event.m_item = item;
1267 event.SetEventObject(this);
1268
1269 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING);
1270 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
d220ae32 1271 {
9dfbf520
VZ
1272 if ( !TreeView_SelectItem(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
1273 {
1274 wxLogLastError("TreeView_SelectItem");
1275 }
1276 else
1277 {
1278 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
1279 (void)GetEventHandler()->ProcessEvent(event);
1280 }
d220ae32 1281 }
9dfbf520 1282 //else: program vetoed the change
2bda0e17 1283 }
08b7c251 1284}
2bda0e17 1285
08b7c251
VZ
1286void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
1287{
1288 // no error return
d220ae32 1289 TreeView_EnsureVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item);
08b7c251
VZ
1290}
1291
1292void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
1293{
d220ae32 1294 if ( !TreeView_SelectSetFirstVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
2bda0e17 1295 {
08b7c251 1296 wxLogLastError("TreeView_SelectSetFirstVisible");
2bda0e17 1297 }
08b7c251
VZ
1298}
1299
1300wxTextCtrl* wxTreeCtrl::GetEditControl() const
1301{
1302 return m_textCtrl;
1303}
1304
1305void wxTreeCtrl::DeleteTextCtrl()
1306{
1307 if ( m_textCtrl )
2bda0e17 1308 {
08b7c251
VZ
1309 m_textCtrl->UnsubclassWin();
1310 m_textCtrl->SetHWND(0);
1311 delete m_textCtrl;
1312 m_textCtrl = NULL;
2bda0e17 1313 }
08b7c251 1314}
2bda0e17 1315
08b7c251
VZ
1316wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
1317 wxClassInfo* textControlClass)
1318{
1319 wxASSERT( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)) );
1320
d220ae32 1321 HWND hWnd = (HWND) TreeView_EditLabel(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item);
2bda0e17 1322
5ea47806
VZ
1323 // this is not an error - the TVN_BEGINLABELEDIT handler might have
1324 // returned FALSE
1325 if ( !hWnd )
1326 {
1327 return NULL;
1328 }
2bda0e17 1329
08b7c251 1330 DeleteTextCtrl();
2bda0e17 1331
08b7c251
VZ
1332 m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
1333 m_textCtrl->SetHWND((WXHWND)hWnd);
1334 m_textCtrl->SubclassWin((WXHWND)hWnd);
2bda0e17 1335
08b7c251 1336 return m_textCtrl;
2bda0e17
KB
1337}
1338
08b7c251
VZ
1339// End label editing, optionally cancelling the edit
1340void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
2bda0e17 1341{
d220ae32 1342 TreeView_EndEditLabelNow(GetHwnd(), discardChanges);
08b7c251
VZ
1343
1344 DeleteTextCtrl();
2bda0e17
KB
1345}
1346
08b7c251 1347wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
2bda0e17 1348{
08b7c251
VZ
1349 TV_HITTESTINFO hitTestInfo;
1350 hitTestInfo.pt.x = (int)point.x;
1351 hitTestInfo.pt.y = (int)point.y;
2bda0e17 1352
d220ae32 1353 TreeView_HitTest(GetHwnd(), &hitTestInfo);
2bda0e17 1354
08b7c251
VZ
1355 flags = 0;
1356
1357 // avoid repetition
1358 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
1359 flags |= wxTREE_HITTEST_##flag
1360
1361 TRANSLATE_FLAG(ABOVE);
1362 TRANSLATE_FLAG(BELOW);
1363 TRANSLATE_FLAG(NOWHERE);
1364 TRANSLATE_FLAG(ONITEMBUTTON);
1365 TRANSLATE_FLAG(ONITEMICON);
1366 TRANSLATE_FLAG(ONITEMINDENT);
1367 TRANSLATE_FLAG(ONITEMLABEL);
1368 TRANSLATE_FLAG(ONITEMRIGHT);
1369 TRANSLATE_FLAG(ONITEMSTATEICON);
1370 TRANSLATE_FLAG(TOLEFT);
1371 TRANSLATE_FLAG(TORIGHT);
2bda0e17 1372
08b7c251
VZ
1373 #undef TRANSLATE_FLAG
1374
06e38c8e 1375 return wxTreeItemId((WXHTREEITEM) hitTestInfo.hItem);
08b7c251
VZ
1376}
1377
f7c832a7
VZ
1378bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
1379 wxRect& rect,
1380 bool textOnly) const
1381{
1382 RECT rc;
d220ae32 1383 if ( TreeView_GetItemRect(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item,
f7c832a7
VZ
1384 &rc, textOnly) )
1385 {
1386 rect = wxRect(wxPoint(rc.left, rc.top), wxPoint(rc.right, rc.bottom));
1387
1388 return TRUE;
1389 }
1390 else
1391 {
1392 // couldn't retrieve rect: for example, item isn't visible
1393 return FALSE;
1394 }
1395}
1396
23fd5130
VZ
1397// ----------------------------------------------------------------------------
1398// sorting stuff
1399// ----------------------------------------------------------------------------
f7c832a7 1400
23fd5130
VZ
1401static int CALLBACK TreeView_CompareCallback(wxTreeItemData *pItem1,
1402 wxTreeItemData *pItem2,
1403 wxTreeCtrl *tree)
1404{
096c9f9b 1405 wxCHECK_MSG( pItem1 && pItem2, 0,
223d09f6 1406 wxT("sorting tree without data doesn't make sense") );
096c9f9b 1407
23fd5130
VZ
1408 return tree->OnCompareItems(pItem1->GetId(), pItem2->GetId());
1409}
1410
95aabccc
VZ
1411int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
1412 const wxTreeItemId& item2)
08b7c251 1413{
837e5743 1414 return wxStrcmp(GetItemText(item1), GetItemText(item2));
95aabccc
VZ
1415}
1416
1417void wxTreeCtrl::SortChildren(const wxTreeItemId& item)
1418{
1419 // rely on the fact that TreeView_SortChildren does the same thing as our
23fd5130
VZ
1420 // default behaviour, i.e. sorts items alphabetically and so call it
1421 // directly if we're not in derived class (much more efficient!)
1422 if ( GetClassInfo() == CLASSINFO(wxTreeCtrl) )
2bda0e17 1423 {
d220ae32 1424 TreeView_SortChildren(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item, 0);
2bda0e17 1425 }
08b7c251 1426 else
2bda0e17 1427 {
62448488 1428 TV_SORTCB tvSort;
23fd5130
VZ
1429 tvSort.hParent = (HTREEITEM)(WXHTREEITEM)item;
1430 tvSort.lpfnCompare = (PFNTVCOMPARE)TreeView_CompareCallback;
1431 tvSort.lParam = (LPARAM)this;
d220ae32 1432 TreeView_SortChildrenCB(GetHwnd(), &tvSort, 0 /* reserved */);
2bda0e17 1433 }
08b7c251 1434}
2bda0e17 1435
08b7c251
VZ
1436// ----------------------------------------------------------------------------
1437// implementation
1438// ----------------------------------------------------------------------------
2bda0e17 1439
08b7c251
VZ
1440bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id)
1441{
1442 if ( cmd == EN_UPDATE )
2bda0e17 1443 {
08b7c251
VZ
1444 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
1445 event.SetEventObject( this );
1446 ProcessCommand(event);
2bda0e17 1447 }
08b7c251 1448 else if ( cmd == EN_KILLFOCUS )
2bda0e17 1449 {
08b7c251
VZ
1450 wxCommandEvent event(wxEVT_KILL_FOCUS, id);
1451 event.SetEventObject( this );
1452 ProcessCommand(event);
2bda0e17 1453 }
08b7c251 1454 else
2bda0e17 1455 {
08b7c251
VZ
1456 // nothing done
1457 return FALSE;
2bda0e17 1458 }
08b7c251
VZ
1459
1460 // command processed
1461 return TRUE;
1462}
1463
1464// process WM_NOTIFY Windows message
a23fd0e1 1465bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
08b7c251
VZ
1466{
1467 wxTreeEvent event(wxEVT_NULL, m_windowId);
1468 wxEventType eventType = wxEVT_NULL;
1469 NMHDR *hdr = (NMHDR *)lParam;
1470
1471 switch ( hdr->code )
2bda0e17 1472 {
84a6b859 1473 case NM_RCLICK:
52f13e49 1474 {
696e1ea0
VZ
1475 if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
1476 return TRUE;
1477
1478 TV_HITTESTINFO tvhti;
1479 ::GetCursorPos(&(tvhti.pt));
1480 ::ScreenToClient(GetHwnd(),&(tvhti.pt));
1481 if ( TreeView_HitTest(GetHwnd(),&tvhti) )
52f13e49 1482 {
696e1ea0
VZ
1483 if( tvhti.flags & TVHT_ONITEM )
1484 {
1485 event.m_item = (WXHTREEITEM) tvhti.hItem;
1486 eventType = wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK;
1487 }
52f13e49
VZ
1488 }
1489 }
1490 break;
52f13e49 1491
08b7c251
VZ
1492 case TVN_BEGINDRAG:
1493 eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
1494 // fall through
1495
1496 case TVN_BEGINRDRAG:
1497 {
1498 if ( eventType == wxEVT_NULL )
1499 eventType = wxEVT_COMMAND_TREE_BEGIN_RDRAG;
1500 //else: left drag, already set above
1501
1502 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
1503
06e38c8e 1504 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
08b7c251 1505 event.m_pointDrag = wxPoint(tv->ptDrag.x, tv->ptDrag.y);
08b7c251 1506 }
696e1ea0 1507 break;
08b7c251
VZ
1508
1509 case TVN_BEGINLABELEDIT:
1510 {
1511 eventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
1512 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1513
06e38c8e 1514 event.m_item = (WXHTREEITEM) info->item.hItem;
5ea47806 1515 event.m_label = info->item.pszText;
08b7c251 1516 }
696e1ea0 1517 break;
08b7c251
VZ
1518
1519 case TVN_DELETEITEM:
1520 {
1521 eventType = wxEVT_COMMAND_TREE_DELETE_ITEM;
1522 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
1523
696e1ea0
VZ
1524 event.m_item = (WXHTREEITEM)tv->itemOld.hItem;
1525
1526 if ( m_hasAnyAttr )
1527 {
1528 delete (wxTreeItemAttr *)m_attrs.
1529 Delete((long)tv->itemOld.hItem);
1530 }
08b7c251 1531 }
696e1ea0 1532 break;
08b7c251
VZ
1533
1534 case TVN_ENDLABELEDIT:
1535 {
1536 eventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
1537 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1538
5ea47806
VZ
1539 event.m_item = (WXHTREEITEM)info->item.hItem;
1540 event.m_label = info->item.pszText;
1ee4ead5
VZ
1541 if (info->item.pszText == NULL)
1542 return FALSE;
08b7c251
VZ
1543 break;
1544 }
1545
1546 case TVN_GETDISPINFO:
1547 eventType = wxEVT_COMMAND_TREE_GET_INFO;
1548 // fall through
1549
1550 case TVN_SETDISPINFO:
1551 {
1552 if ( eventType == wxEVT_NULL )
1553 eventType = wxEVT_COMMAND_TREE_SET_INFO;
1554 //else: get, already set above
1555
1556 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1557
06e38c8e 1558 event.m_item = (WXHTREEITEM) info->item.hItem;
08b7c251
VZ
1559 break;
1560 }
1561
1562 case TVN_ITEMEXPANDING:
1563 event.m_code = FALSE;
1564 // fall through
1565
1566 case TVN_ITEMEXPANDED:
1567 {
1568 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
1569
1570 bool expand = FALSE;
1571 switch ( tv->action )
1572 {
1573 case TVE_EXPAND:
1574 expand = TRUE;
1575 break;
1576
1577 case TVE_COLLAPSE:
1578 expand = FALSE;
1579 break;
1580
1581 default:
223d09f6 1582 wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND "
837e5743 1583 "message"), tv->action);
08b7c251
VZ
1584 }
1585
a17e237f 1586 bool ing = ((int)hdr->code == TVN_ITEMEXPANDING);
08b7c251
VZ
1587 eventType = g_events[expand][ing];
1588
06e38c8e 1589 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
08b7c251 1590 }
696e1ea0 1591 break;
08b7c251
VZ
1592
1593 case TVN_KEYDOWN:
1594 {
1595 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
1596 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
1597
1598 event.m_code = wxCharCodeMSWToWX(info->wVKey);
23fd5130
VZ
1599
1600 // a separate event for this case
1601 if ( info->wVKey == VK_SPACE || info->wVKey == VK_RETURN )
1602 {
1603 wxTreeEvent event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
1604 m_windowId);
1605 event2.SetEventObject(this);
1606
1607 GetEventHandler()->ProcessEvent(event2);
1608 }
08b7c251 1609 }
696e1ea0 1610 break;
08b7c251
VZ
1611
1612 case TVN_SELCHANGED:
1613 eventType = wxEVT_COMMAND_TREE_SEL_CHANGED;
1614 // fall through
1615
1616 case TVN_SELCHANGING:
1617 {
1618 if ( eventType == wxEVT_NULL )
1619 eventType = wxEVT_COMMAND_TREE_SEL_CHANGING;
1620 //else: already set above
1621
1622 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
1623
06e38c8e
JS
1624 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
1625 event.m_itemOld = (WXHTREEITEM) tv->itemOld.hItem;
08b7c251 1626 }
696e1ea0
VZ
1627 break;
1628
6ecfe2ac 1629#if defined(_WIN32_IE) && _WIN32_IE >= 0x300
696e1ea0
VZ
1630 case NM_CUSTOMDRAW:
1631 {
1632 LPNMTVCUSTOMDRAW lptvcd = (LPNMTVCUSTOMDRAW)lParam;
1633 NMCUSTOMDRAW& nmcd = lptvcd->nmcd;
1634 switch( nmcd.dwDrawStage )
1635 {
1636 case CDDS_PREPAINT:
1637 // if we've got any items with non standard attributes,
1638 // notify us before painting each item
1639 *result = m_hasAnyAttr ? CDRF_NOTIFYITEMDRAW
1640 : CDRF_DODEFAULT;
1641 return TRUE;
1642
1643 case CDDS_ITEMPREPAINT:
1644 {
1645 wxTreeItemAttr *attr =
1646 (wxTreeItemAttr *)m_attrs.Get(nmcd.dwItemSpec);
1647
1648 if ( !attr )
1649 {
1650 // nothing to do for this item
1651 return CDRF_DODEFAULT;
1652 }
1653
1654 HFONT hFont;
1655 wxColour colText, colBack;
1656 if ( attr->HasFont() )
1657 {
1658 wxFont font = attr->GetFont();
1659 hFont = (HFONT)font.GetResourceHandle();
1660 }
1661 else
1662 {
1663 hFont = 0;
1664 }
1665
1666 if ( attr->HasTextColour() )
1667 {
1668 colText = attr->GetTextColour();
1669 }
1670 else
1671 {
1672 colText = GetForegroundColour();
1673 }
1674
1675 // selection colours should override ours
1676 if ( nmcd.uItemState & CDIS_SELECTED )
1677 {
1678 DWORD clrBk = ::GetSysColor(COLOR_HIGHLIGHT);
1679 lptvcd->clrTextBk = clrBk;
1680
1681 // try to make the text visible
1682 lptvcd->clrText = wxColourToRGB(colText);
1683 lptvcd->clrText |= ~clrBk;
1684 lptvcd->clrText &= 0x00ffffff;
1685 }
1686 else
1687 {
1688 if ( attr->HasBackgroundColour() )
1689 {
1690 colBack = attr->GetBackgroundColour();
1691 }
1692 else
1693 {
1694 colBack = GetBackgroundColour();
1695 }
1696
1697 lptvcd->clrText = wxColourToRGB(colText);
1698 lptvcd->clrTextBk = wxColourToRGB(colBack);
1699 }
1700
1701 // note that if we wanted to set colours for
1702 // individual columns (subitems), we would have
1703 // returned CDRF_NOTIFYSUBITEMREDRAW from here
1704 if ( hFont )
1705 {
1706 ::SelectObject(nmcd.hdc, hFont);
1707
1708 *result = CDRF_NEWFONT;
1709 }
1710 else
1711 {
1712 *result = CDRF_DODEFAULT;
1713 }
1714
1715 return TRUE;
1716 }
1717
1718 default:
1719 *result = CDRF_DODEFAULT;
1720 return TRUE;
1721 }
1722 }
1723 break;
6ecfe2ac 1724#endif // _WIN32_IE >= 0x300
08b7c251
VZ
1725
1726 default:
a23fd0e1 1727 return wxControl::MSWOnNotify(idCtrl, lParam, result);
2bda0e17 1728 }
08b7c251
VZ
1729
1730 event.SetEventObject(this);
1731 event.SetEventType(eventType);
1732
fd3f686c 1733 bool processed = GetEventHandler()->ProcessEvent(event);
08b7c251
VZ
1734
1735 // post processing
5ea47806 1736 switch ( hdr->code )
2bda0e17 1737 {
5ea47806
VZ
1738 case TVN_DELETEITEM:
1739 {
1740 // NB: we might process this message using wxWindows event
1741 // tables, but due to overhead of wxWin event system we
1742 // prefer to do it here ourself (otherwise deleting a tree
1743 // with many items is just too slow)
1744 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
74b31181
VZ
1745
1746 wxTreeItemId item = event.m_item;
1747 if ( HasIndirectData(item) )
1748 {
1749 wxTreeItemIndirectData *data = (wxTreeItemIndirectData *)
1750 tv->itemOld.lParam;
1751 delete data; // can't be NULL here
1752
1753 m_itemsWithIndirectData.Remove(item);
1754 }
1755 else
1756 {
1757 wxTreeItemData *data = (wxTreeItemData *)tv->itemOld.lParam;
1758 delete data; // may be NULL, ok
1759 }
08b7c251 1760
5ea47806
VZ
1761 processed = TRUE; // Make sure we don't get called twice
1762 }
1763 break;
1764
1765 case TVN_BEGINLABELEDIT:
1766 // return TRUE to cancel label editing
1767 *result = !event.IsAllowed();
1768 break;
1769
1770 case TVN_ENDLABELEDIT:
1771 // return TRUE to set the label to the new string
1772 *result = event.IsAllowed();
1773
1774 // ensure that we don't have the text ctrl which is going to be
1775 // deleted any more
1776 DeleteTextCtrl();
1777 break;
1778
1779 case TVN_SELCHANGING:
1780 case TVN_ITEMEXPANDING:
1781 // return TRUE to prevent the action from happening
1782 *result = !event.IsAllowed();
1783 break;
1784
74b31181
VZ
1785 case TVN_GETDISPINFO:
1786 // NB: so far the user can't set the image himself anyhow, so do it
1787 // anyway - but this may change later
1788 if ( /* !processed && */ 1 )
1789 {
1790 wxTreeItemId item = event.m_item;
1791 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1792 if ( info->item.mask & TVIF_IMAGE )
1793 {
1794 info->item.iImage =
1795 DoGetItemImageFromData
1796 (
1797 item,
1798 IsExpanded(item) ? wxTreeItemIcon_Expanded
1799 : wxTreeItemIcon_Normal
1800 );
1801 }
1802 if ( info->item.mask & TVIF_SELECTEDIMAGE )
1803 {
1804 info->item.iSelectedImage =
1805 DoGetItemImageFromData
1806 (
1807 item,
1808 IsExpanded(item) ? wxTreeItemIcon_SelectedExpanded
1809 : wxTreeItemIcon_Selected
1810 );
1811 }
1812 }
1813 break;
1814
5ea47806
VZ
1815 //default:
1816 // for the other messages the return value is ignored and there is
1817 // nothing special to do
1818 }
fd3f686c
VZ
1819
1820 return processed;
2bda0e17
KB
1821}
1822
08b7c251 1823// ----------------------------------------------------------------------------
2bda0e17 1824// Tree event
08b7c251
VZ
1825// ----------------------------------------------------------------------------
1826
92976ab6 1827IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
2bda0e17 1828
08b7c251 1829wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
fd3f686c 1830 : wxNotifyEvent(commandType, id)
2bda0e17 1831{
08b7c251
VZ
1832 m_code = 0;
1833 m_itemOld = 0;
2bda0e17
KB
1834}
1835
08b7c251 1836#endif // __WIN95__
2bda0e17 1837