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