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