]> git.saurik.com Git - wxWidgets.git/blame - src/msw/treectrl.cpp
Added dcbase.cpp
[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
30#ifndef WX_PRECOMP
ad5c34f3 31 #include "wx/wx.h"
2bda0e17
KB
32#endif
33
2bda0e17
KB
34#if defined(__WIN95__)
35
08b7c251 36#include "wx/log.h"
ce3ed50d 37#include "wx/dynarray.h"
08b7c251 38#include "wx/imaglist.h"
ce3ed50d 39#include "wx/msw/treectrl.h"
08b7c251 40
2bda0e17
KB
41#include "wx/msw/private.h"
42
9a05fd8d
JS
43#ifdef __GNUWIN32__
44#include "wx/msw/gnuwin32/extra.h"
45#endif
46
57c208c5 47#if (defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__)
08b7c251 48 #include <commctrl.h>
2bda0e17
KB
49#endif
50
51// Bug in headers, sometimes
52#ifndef TVIS_FOCUSED
08b7c251 53 #define TVIS_FOCUSED 0x0001
2bda0e17
KB
54#endif
55
08b7c251
VZ
56// ----------------------------------------------------------------------------
57// private classes
58// ----------------------------------------------------------------------------
2bda0e17 59
08b7c251
VZ
60// a convenient wrapper around TV_ITEM struct which adds a ctor
61struct wxTreeViewItem : public TV_ITEM
62{
63 wxTreeViewItem(const wxTreeItemId& item,
64 UINT mask_, UINT stateMask_ = 0)
65 {
66 mask = mask_;
67 stateMask = stateMask_;
06e38c8e 68 hItem = (HTREEITEM) (WXHTREEITEM) item;
08b7c251
VZ
69 }
70};
2bda0e17 71
08b7c251
VZ
72// ----------------------------------------------------------------------------
73// macros
74// ----------------------------------------------------------------------------
75
76#if !USE_SHARED_LIBRARY
77 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
2bda0e17
KB
78#endif
79
08b7c251 80// hide the ugly cast (of course, the macro is _quite_ ugly too...)
06e38c8e 81#define wxhWnd ((HWND)m_hWnd)
08b7c251
VZ
82
83// ----------------------------------------------------------------------------
84// variables
85// ----------------------------------------------------------------------------
86
87// handy table for sending events
88static const wxEventType g_events[2][2] =
2bda0e17 89{
08b7c251
VZ
90 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
91 { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING }
92};
93
94// ============================================================================
95// implementation
96// ============================================================================
97
98// ----------------------------------------------------------------------------
99// construction and destruction
100// ----------------------------------------------------------------------------
101
102void wxTreeCtrl::Init()
103{
104 m_imageListNormal = NULL;
105 m_imageListState = NULL;
106 m_textCtrl = NULL;
2bda0e17
KB
107}
108
08b7c251
VZ
109bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
110 const wxPoint& pos, const wxSize& size,
111 long style, const wxValidator& validator,
112 const wxString& name)
2bda0e17 113{
08b7c251 114 Init();
2bda0e17 115
08b7c251 116 wxSystemSettings settings;
2bda0e17 117
08b7c251
VZ
118 SetName(name);
119 SetValidator(validator);
2bda0e17 120
08b7c251 121 m_windowStyle = style;
2bda0e17 122
08b7c251 123 SetParent(parent);
2bda0e17 124
08b7c251 125 m_windowId = (id == -1) ? NewControlId() : id;
2bda0e17 126
f5ee2e5f
JS
127 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | TVS_HASLINES | TVS_SHOWSELALWAYS ;
128
2bda0e17 129
08b7c251
VZ
130 bool want3D;
131 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ;
2bda0e17 132
08b7c251
VZ
133 // Even with extended styles, need to combine with WS_BORDER
134 // for them to look right.
135 if ( want3D || wxStyleHasBorder(m_windowStyle) )
136 {
137 wstyle |= WS_BORDER;
138 }
2bda0e17 139
08b7c251
VZ
140 if ( m_windowStyle & wxTR_HAS_BUTTONS )
141 wstyle |= TVS_HASBUTTONS;
2bda0e17 142
08b7c251
VZ
143 if ( m_windowStyle & wxTR_EDIT_LABELS )
144 wstyle |= TVS_EDITLABELS;
2bda0e17 145
08b7c251
VZ
146 if ( m_windowStyle & wxTR_LINES_AT_ROOT )
147 wstyle |= TVS_LINESATROOT;
2bda0e17 148
08b7c251
VZ
149 // Create the tree control.
150 m_hWnd = (WXHWND)::CreateWindowEx
151 (
152 exStyle,
153 WC_TREEVIEW,
154 "",
155 wstyle,
156 pos.x, pos.y, size.x, size.y,
157 (HWND)parent->GetHWND(),
158 (HMENU)m_windowId,
159 wxGetInstance(),
160 NULL
161 );
7798a18e 162
08b7c251 163 wxCHECK_MSG( m_hWnd, FALSE, "Failed to create tree ctrl" );
2bda0e17 164
08b7c251
VZ
165 if ( parent )
166 parent->AddChild(this);
2bda0e17 167
08b7c251 168 SubclassWin(m_hWnd);
2bda0e17 169
08b7c251 170 return TRUE;
2bda0e17
KB
171}
172
08b7c251 173wxTreeCtrl::~wxTreeCtrl()
2bda0e17 174{
08b7c251 175 DeleteTextCtrl();
2bda0e17 176
08b7c251
VZ
177 // delete user data to prevent memory leaks
178 DeleteAllItems();
2bda0e17
KB
179}
180
08b7c251
VZ
181// ----------------------------------------------------------------------------
182// accessors
183// ----------------------------------------------------------------------------
2bda0e17 184
08b7c251 185// simple wrappers which add error checking in debug mode
2bda0e17 186
08b7c251 187bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const
2bda0e17 188{
06e38c8e 189 if ( !TreeView_GetItem(wxhWnd, tvItem) )
2bda0e17 190 {
08b7c251
VZ
191 wxLogLastError("TreeView_GetItem");
192
193 return FALSE;
194 }
195
196 return TRUE;
2bda0e17
KB
197}
198
08b7c251 199void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem)
2bda0e17 200{
06e38c8e 201 if ( TreeView_SetItem(wxhWnd, tvItem) == -1 )
2bda0e17 202 {
08b7c251
VZ
203 wxLogLastError("TreeView_SetItem");
204 }
2bda0e17
KB
205}
206
08b7c251 207size_t wxTreeCtrl::GetCount() const
2bda0e17 208{
06e38c8e 209 return (size_t)TreeView_GetCount(wxhWnd);
2bda0e17
KB
210}
211
08b7c251 212unsigned int wxTreeCtrl::GetIndent() const
2bda0e17 213{
06e38c8e 214 return TreeView_GetIndent(wxhWnd);
2bda0e17
KB
215}
216
08b7c251 217void wxTreeCtrl::SetIndent(unsigned int indent)
2bda0e17 218{
06e38c8e 219 TreeView_SetIndent(wxhWnd, indent);
2bda0e17
KB
220}
221
08b7c251 222wxImageList *wxTreeCtrl::GetImageList() const
2bda0e17 223{
08b7c251 224 return m_imageListNormal;
2bda0e17
KB
225}
226
08b7c251 227wxImageList *wxTreeCtrl::GetStateImageList() const
2bda0e17 228{
08b7c251 229 return m_imageListNormal;
2bda0e17
KB
230}
231
08b7c251 232void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which)
2bda0e17 233{
08b7c251 234 // no error return
06e38c8e 235 TreeView_SetImageList(wxhWnd,
08b7c251
VZ
236 imageList ? imageList->GetHIMAGELIST() : 0,
237 which);
2bda0e17
KB
238}
239
08b7c251 240void wxTreeCtrl::SetImageList(wxImageList *imageList)
2bda0e17 241{
08b7c251 242 SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
2bda0e17
KB
243}
244
08b7c251 245void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
2bda0e17 246{
08b7c251 247 SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
2bda0e17
KB
248}
249
23fd5130
VZ
250size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
251{
252 long cookie;
253
254 size_t result = 0;
255
256 wxArrayLong children;
257 wxTreeItemId child = GetFirstChild(item, cookie);
258 while ( child.IsOk() )
259 {
260 if ( recursively )
261 {
262 // recursive call
263 result += GetChildrenCount(child, TRUE);
264 }
265
266 // add the child to the result in any case
267 result++;
268
269 child = GetNextChild(item, cookie);
270 }
271
272 return result;
273}
274
08b7c251
VZ
275// ----------------------------------------------------------------------------
276// Item access
277// ----------------------------------------------------------------------------
278
279wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
2bda0e17 280{
08b7c251 281 char buf[512]; // the size is arbitrary...
02ce7b72 282
08b7c251
VZ
283 wxTreeViewItem tvItem(item, TVIF_TEXT);
284 tvItem.pszText = buf;
285 tvItem.cchTextMax = WXSIZEOF(buf);
286 if ( !DoGetItem(&tvItem) )
287 {
288 // don't return some garbage which was on stack, but an empty string
289 buf[0] = '\0';
290 }
2bda0e17 291
08b7c251
VZ
292 return wxString(buf);
293}
2bda0e17 294
08b7c251
VZ
295void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
296{
297 wxTreeViewItem tvItem(item, TVIF_TEXT);
298 tvItem.pszText = (char *)text.c_str(); // conversion is ok
299 DoSetItem(&tvItem);
300}
2bda0e17 301
08b7c251
VZ
302int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
303{
304 wxTreeViewItem tvItem(item, TVIF_IMAGE);
305 DoGetItem(&tvItem);
2bda0e17 306
08b7c251
VZ
307 return tvItem.iImage;
308}
2bda0e17 309
08b7c251
VZ
310void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
311{
312 wxTreeViewItem tvItem(item, TVIF_IMAGE);
313 tvItem.iImage = image;
314 DoSetItem(&tvItem);
315}
2bda0e17 316
08b7c251
VZ
317int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
318{
319 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
320 DoGetItem(&tvItem);
2bda0e17 321
08b7c251 322 return tvItem.iSelectedImage;
2bda0e17
KB
323}
324
08b7c251 325void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
2bda0e17 326{
08b7c251
VZ
327 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
328 tvItem.iSelectedImage = image;
329 DoSetItem(&tvItem);
2bda0e17
KB
330}
331
08b7c251 332wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
2bda0e17 333{
08b7c251
VZ
334 wxTreeViewItem tvItem(item, TVIF_PARAM);
335 if ( !DoGetItem(&tvItem) )
336 {
337 return NULL;
338 }
2bda0e17 339
3a5a2f56 340 return (wxTreeItemData *)tvItem.lParam;
2bda0e17
KB
341}
342
08b7c251 343void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
2bda0e17 344{
08b7c251
VZ
345 wxTreeViewItem tvItem(item, TVIF_PARAM);
346 tvItem.lParam = (LPARAM)data;
347 DoSetItem(&tvItem);
348}
2bda0e17 349
3a5a2f56
VZ
350void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
351{
352 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
353 tvItem.cChildren = (int)has;
354 DoSetItem(&tvItem);
355}
356
add28c55
VZ
357void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
358{
359 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
360 tvItem.state = bold ? TVIS_BOLD : 0;
361 DoSetItem(&tvItem);
362}
363
58a8ab88
JS
364void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight)
365{
366 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_DROPHILITED);
367 tvItem.state = highlight ? TVIS_DROPHILITED : 0;
368 DoSetItem(&tvItem);
369}
370
08b7c251
VZ
371// ----------------------------------------------------------------------------
372// Item status
373// ----------------------------------------------------------------------------
2bda0e17 374
08b7c251
VZ
375bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
376{
add28c55 377 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
08b7c251 378 RECT rect;
add28c55 379 return SendMessage(wxhWnd, TVM_GETITEMRECT, FALSE, (LPARAM)&rect) != 0;
06e38c8e 380
2bda0e17
KB
381}
382
08b7c251 383bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
2bda0e17 384{
08b7c251
VZ
385 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
386 DoGetItem(&tvItem);
2bda0e17 387
08b7c251 388 return tvItem.cChildren != 0;
2bda0e17
KB
389}
390
08b7c251 391bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
2bda0e17 392{
08b7c251
VZ
393 // probably not a good idea to put it here
394 //wxASSERT( ItemHasChildren(item) );
2bda0e17 395
08b7c251
VZ
396 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDED);
397 DoGetItem(&tvItem);
2bda0e17 398
08b7c251 399 return (tvItem.state & TVIS_EXPANDED) != 0;
2bda0e17
KB
400}
401
08b7c251 402bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
2bda0e17 403{
08b7c251
VZ
404 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_SELECTED);
405 DoGetItem(&tvItem);
2bda0e17 406
08b7c251 407 return (tvItem.state & TVIS_SELECTED) != 0;
2bda0e17
KB
408}
409
add28c55
VZ
410bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
411{
412 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
413 DoGetItem(&tvItem);
414
415 return (tvItem.state & TVIS_BOLD) != 0;
416}
417
08b7c251
VZ
418// ----------------------------------------------------------------------------
419// navigation
420// ----------------------------------------------------------------------------
2bda0e17 421
08b7c251
VZ
422wxTreeItemId wxTreeCtrl::GetRootItem() const
423{
a3168196 424 return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(wxhWnd));
08b7c251 425}
2bda0e17 426
08b7c251
VZ
427wxTreeItemId wxTreeCtrl::GetSelection() const
428{
a3168196 429 return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(wxhWnd));
2bda0e17
KB
430}
431
08b7c251 432wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
2bda0e17 433{
06e38c8e 434 return wxTreeItemId((WXHTREEITEM) TreeView_GetParent(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
08b7c251 435}
2bda0e17 436
08b7c251 437wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
06e38c8e 438 long& _cookie) const
08b7c251
VZ
439{
440 // remember the last child returned in 'cookie'
06e38c8e 441 _cookie = (long)TreeView_GetChild(wxhWnd, (HTREEITEM) (WXHTREEITEM)item);
2bda0e17 442
06e38c8e 443 return wxTreeItemId((WXHTREEITEM)_cookie);
2bda0e17
KB
444}
445
08b7c251 446wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& WXUNUSED(item),
06e38c8e 447 long& _cookie) const
2bda0e17 448{
23fd5130
VZ
449 wxTreeItemId l = wxTreeItemId((WXHTREEITEM)TreeView_GetNextSibling(wxhWnd,
450 (HTREEITEM)(WXHTREEITEM)_cookie));
451 _cookie = (long)l;
452
2e5dddb0 453 return l;
08b7c251 454}
2bda0e17 455
978f38c2
VZ
456wxTreeItemId wxTreeCtrl::GetLastChild(const wxTreeItemId& item) const
457{
458 // can this be done more efficiently?
459 long cookie;
460
461 wxTreeItemId childLast,
2165ad93 462 child = GetFirstChild(item, cookie);
978f38c2
VZ
463 while ( child.IsOk() )
464 {
465 childLast = child;
2165ad93 466 child = GetNextChild(item, cookie);
978f38c2
VZ
467 }
468
469 return childLast;
470}
471
08b7c251
VZ
472wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
473{
a3168196 474 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextSibling(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
2bda0e17
KB
475}
476
08b7c251 477wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
2bda0e17 478{
a3168196 479 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevSibling(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
2bda0e17
KB
480}
481
08b7c251 482wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
2bda0e17 483{
a3168196 484 return wxTreeItemId((WXHTREEITEM) TreeView_GetFirstVisible(wxhWnd));
2bda0e17
KB
485}
486
08b7c251 487wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
2bda0e17 488{
08b7c251
VZ
489 wxASSERT_MSG( IsVisible(item), "The item you call GetNextVisible() "
490 "for must be visible itself!");
02ce7b72 491
a3168196 492 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
08b7c251 493}
02ce7b72 494
08b7c251
VZ
495wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
496{
497 wxASSERT_MSG( IsVisible(item), "The item you call GetPrevVisible() "
498 "for must be visible itself!");
02ce7b72 499
a3168196 500 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
08b7c251 501}
02ce7b72 502
08b7c251
VZ
503// ----------------------------------------------------------------------------
504// Usual operations
505// ----------------------------------------------------------------------------
02ce7b72 506
08b7c251
VZ
507wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent,
508 wxTreeItemId hInsertAfter,
509 const wxString& text,
510 int image, int selectedImage,
511 wxTreeItemData *data)
512{
513 TV_INSERTSTRUCT tvIns;
06e38c8e
JS
514 tvIns.hParent = (HTREEITEM) (WXHTREEITEM)parent;
515 tvIns.hInsertAfter = (HTREEITEM) (WXHTREEITEM) hInsertAfter;
58a8ab88
JS
516
517 // This is how we insert the item as the first child: supply a NULL hInsertAfter
518 if (tvIns.hInsertAfter == (HTREEITEM) 0)
519 {
520 tvIns.hInsertAfter = TVI_FIRST;
521 }
522
08b7c251
VZ
523 UINT mask = 0;
524 if ( !text.IsEmpty() )
525 {
526 mask |= TVIF_TEXT;
527 tvIns.item.pszText = (char *)text.c_str(); // cast is ok
528 }
02ce7b72 529
08b7c251
VZ
530 if ( image != -1 )
531 {
532 mask |= TVIF_IMAGE;
533 tvIns.item.iImage = image;
3a5a2f56 534
6b037754 535 if ( selectedImage == -1 )
3a5a2f56
VZ
536 {
537 // take the same image for selected icon if not specified
538 selectedImage = image;
539 }
08b7c251 540 }
02ce7b72 541
08b7c251
VZ
542 if ( selectedImage != -1 )
543 {
544 mask |= TVIF_SELECTEDIMAGE;
545 tvIns.item.iSelectedImage = selectedImage;
546 }
02ce7b72 547
08b7c251
VZ
548 if ( data != NULL )
549 {
550 mask |= TVIF_PARAM;
551 tvIns.item.lParam = (LPARAM)data;
552 }
02ce7b72 553
08b7c251 554 tvIns.item.mask = mask;
02ce7b72 555
4fabb575 556 HTREEITEM id = (HTREEITEM) TreeView_InsertItem(wxhWnd, &tvIns);
08b7c251
VZ
557 if ( id == 0 )
558 {
559 wxLogLastError("TreeView_InsertItem");
560 }
02ce7b72 561
fd3f686c
VZ
562 if ( data != NULL )
563 {
564 // associate the application tree item with Win32 tree item handle
565 data->SetId((WXHTREEITEM)id);
566 }
567
06e38c8e 568 return wxTreeItemId((WXHTREEITEM)id);
2bda0e17
KB
569}
570
08b7c251
VZ
571// for compatibility only
572wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
573 const wxString& text,
574 int image, int selImage,
575 long insertAfter)
2bda0e17 576{
06e38c8e 577 return DoInsertItem(parent, (WXHTREEITEM)insertAfter, text,
08b7c251 578 image, selImage, NULL);
2bda0e17
KB
579}
580
08b7c251
VZ
581wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
582 int image, int selectedImage,
583 wxTreeItemData *data)
2bda0e17 584{
06e38c8e 585 return DoInsertItem(wxTreeItemId((WXHTREEITEM) 0), (WXHTREEITEM) 0,
08b7c251 586 text, image, selectedImage, data);
2bda0e17
KB
587}
588
08b7c251
VZ
589wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
590 const wxString& text,
591 int image, int selectedImage,
592 wxTreeItemData *data)
2bda0e17 593{
06e38c8e 594 return DoInsertItem(parent, (WXHTREEITEM) TVI_FIRST,
08b7c251 595 text, image, selectedImage, data);
2bda0e17
KB
596}
597
08b7c251
VZ
598wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
599 const wxTreeItemId& idPrevious,
600 const wxString& text,
601 int image, int selectedImage,
602 wxTreeItemData *data)
2bda0e17 603{
08b7c251 604 return DoInsertItem(parent, idPrevious, text, image, selectedImage, data);
2bda0e17
KB
605}
606
08b7c251
VZ
607wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parent,
608 const wxString& text,
609 int image, int selectedImage,
610 wxTreeItemData *data)
2bda0e17 611{
06e38c8e 612 return DoInsertItem(parent, (WXHTREEITEM) TVI_LAST,
08b7c251 613 text, image, selectedImage, data);
2bda0e17
KB
614}
615
08b7c251 616void wxTreeCtrl::Delete(const wxTreeItemId& item)
2bda0e17 617{
06e38c8e 618 if ( !TreeView_DeleteItem(wxhWnd, (HTREEITEM)(WXHTREEITEM)item) )
bbcdf8bc 619 {
08b7c251 620 wxLogLastError("TreeView_DeleteItem");
bbcdf8bc 621 }
bbcdf8bc
JS
622}
623
23fd5130
VZ
624// delete all children (but don't delete the item itself)
625void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item)
626{
627 long cookie;
628
629 wxArrayLong children;
630 wxTreeItemId child = GetFirstChild(item, cookie);
631 while ( child.IsOk() )
632 {
633 children.Add((long)(WXHTREEITEM)child);
634
635 child = GetNextChild(item, cookie);
636 }
637
638 size_t nCount = children.Count();
639 for ( size_t n = 0; n < nCount; n++ )
640 {
641 if ( !TreeView_DeleteItem(wxhWnd, (HTREEITEM)children[n]) )
642 {
643 wxLogLastError("TreeView_DeleteItem");
644 }
645 }
646}
647
08b7c251 648void wxTreeCtrl::DeleteAllItems()
bbcdf8bc 649{
06e38c8e 650 if ( !TreeView_DeleteAllItems(wxhWnd) )
bbcdf8bc 651 {
08b7c251 652 wxLogLastError("TreeView_DeleteAllItems");
bbcdf8bc 653 }
2bda0e17
KB
654}
655
08b7c251 656void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
2bda0e17 657{
dd3646fd
VZ
658 wxASSERT_MSG( flag == TVE_COLLAPSE ||
659 flag == (TVE_COLLAPSE | TVE_COLLAPSERESET) ||
660 flag == TVE_EXPAND ||
661 flag == TVE_TOGGLE,
08b7c251
VZ
662 "Unknown flag in wxTreeCtrl::DoExpand" );
663
664 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
665 // emulate them
06e38c8e 666 if ( TreeView_Expand(wxhWnd, (HTREEITEM) (WXHTREEITEM) item, flag) != 0 )
08b7c251
VZ
667 {
668 wxTreeEvent event(wxEVT_NULL, m_windowId);
669 event.m_item = item;
670
671 bool isExpanded = IsExpanded(item);
2bda0e17 672
08b7c251 673 event.SetEventObject(this);
2bda0e17 674
08b7c251
VZ
675 // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded
676 event.SetEventType(g_events[isExpanded][TRUE]);
677 GetEventHandler()->ProcessEvent(event);
2bda0e17 678
08b7c251
VZ
679 event.SetEventType(g_events[isExpanded][FALSE]);
680 GetEventHandler()->ProcessEvent(event);
681 }
682 else
683 {
684 // I wonder if it really ever happens...
685 wxLogDebug("TreeView_Expand: change didn't took place.");
686 }
2bda0e17
KB
687}
688
08b7c251 689void wxTreeCtrl::Expand(const wxTreeItemId& item)
2bda0e17 690{
08b7c251 691 DoExpand(item, TVE_EXPAND);
2bda0e17 692}
2bda0e17 693
08b7c251 694void wxTreeCtrl::Collapse(const wxTreeItemId& item)
2bda0e17 695{
08b7c251 696 DoExpand(item, TVE_COLLAPSE);
2bda0e17
KB
697}
698
08b7c251 699void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
2bda0e17 700{
dd3646fd 701 DoExpand(item, TVE_COLLAPSE | TVE_COLLAPSERESET);
2bda0e17
KB
702}
703
08b7c251 704void wxTreeCtrl::Toggle(const wxTreeItemId& item)
2bda0e17 705{
08b7c251 706 DoExpand(item, TVE_TOGGLE);
2bda0e17
KB
707}
708
42c5812d
UU
709void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
710{
711 DoExpand(item, action);
712}
713
08b7c251 714void wxTreeCtrl::Unselect()
2bda0e17 715{
06e38c8e 716 SelectItem(wxTreeItemId((WXHTREEITEM) 0));
08b7c251 717}
02ce7b72 718
08b7c251
VZ
719void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
720{
06e38c8e 721 if ( !TreeView_SelectItem(wxhWnd, (HTREEITEM) (WXHTREEITEM) item) )
2bda0e17 722 {
08b7c251 723 wxLogLastError("TreeView_SelectItem");
2bda0e17 724 }
08b7c251 725}
2bda0e17 726
08b7c251
VZ
727void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
728{
729 // no error return
06e38c8e 730 TreeView_EnsureVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item);
08b7c251
VZ
731}
732
733void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
734{
06e38c8e 735 if ( !TreeView_SelectSetFirstVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item) )
2bda0e17 736 {
08b7c251 737 wxLogLastError("TreeView_SelectSetFirstVisible");
2bda0e17 738 }
08b7c251
VZ
739}
740
741wxTextCtrl* wxTreeCtrl::GetEditControl() const
742{
743 return m_textCtrl;
744}
745
746void wxTreeCtrl::DeleteTextCtrl()
747{
748 if ( m_textCtrl )
2bda0e17 749 {
08b7c251
VZ
750 m_textCtrl->UnsubclassWin();
751 m_textCtrl->SetHWND(0);
752 delete m_textCtrl;
753 m_textCtrl = NULL;
2bda0e17 754 }
08b7c251 755}
2bda0e17 756
08b7c251
VZ
757wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
758 wxClassInfo* textControlClass)
759{
760 wxASSERT( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)) );
761
06e38c8e 762 HWND hWnd = (HWND) TreeView_EditLabel(wxhWnd, (HTREEITEM) (WXHTREEITEM) item);
2bda0e17 763
08b7c251 764 wxCHECK_MSG( hWnd, NULL, "Can't edit tree ctrl label" );
2bda0e17 765
08b7c251 766 DeleteTextCtrl();
2bda0e17 767
08b7c251
VZ
768 m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
769 m_textCtrl->SetHWND((WXHWND)hWnd);
770 m_textCtrl->SubclassWin((WXHWND)hWnd);
2bda0e17 771
08b7c251 772 return m_textCtrl;
2bda0e17
KB
773}
774
08b7c251
VZ
775// End label editing, optionally cancelling the edit
776void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
2bda0e17 777{
06e38c8e 778 TreeView_EndEditLabelNow(wxhWnd, discardChanges);
08b7c251
VZ
779
780 DeleteTextCtrl();
2bda0e17
KB
781}
782
08b7c251 783wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
2bda0e17 784{
08b7c251
VZ
785 TV_HITTESTINFO hitTestInfo;
786 hitTestInfo.pt.x = (int)point.x;
787 hitTestInfo.pt.y = (int)point.y;
2bda0e17 788
06e38c8e 789 TreeView_HitTest(wxhWnd, &hitTestInfo);
2bda0e17 790
08b7c251
VZ
791 flags = 0;
792
793 // avoid repetition
794 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
795 flags |= wxTREE_HITTEST_##flag
796
797 TRANSLATE_FLAG(ABOVE);
798 TRANSLATE_FLAG(BELOW);
799 TRANSLATE_FLAG(NOWHERE);
800 TRANSLATE_FLAG(ONITEMBUTTON);
801 TRANSLATE_FLAG(ONITEMICON);
802 TRANSLATE_FLAG(ONITEMINDENT);
803 TRANSLATE_FLAG(ONITEMLABEL);
804 TRANSLATE_FLAG(ONITEMRIGHT);
805 TRANSLATE_FLAG(ONITEMSTATEICON);
806 TRANSLATE_FLAG(TOLEFT);
807 TRANSLATE_FLAG(TORIGHT);
2bda0e17 808
08b7c251
VZ
809 #undef TRANSLATE_FLAG
810
06e38c8e 811 return wxTreeItemId((WXHTREEITEM) hitTestInfo.hItem);
08b7c251
VZ
812}
813
f7c832a7
VZ
814bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
815 wxRect& rect,
816 bool textOnly) const
817{
818 RECT rc;
819 if ( TreeView_GetItemRect(wxhWnd, (HTREEITEM)(WXHTREEITEM)item,
820 &rc, textOnly) )
821 {
822 rect = wxRect(wxPoint(rc.left, rc.top), wxPoint(rc.right, rc.bottom));
823
824 return TRUE;
825 }
826 else
827 {
828 // couldn't retrieve rect: for example, item isn't visible
829 return FALSE;
830 }
831}
832
23fd5130
VZ
833// ----------------------------------------------------------------------------
834// sorting stuff
835// ----------------------------------------------------------------------------
f7c832a7 836
23fd5130
VZ
837static int CALLBACK TreeView_CompareCallback(wxTreeItemData *pItem1,
838 wxTreeItemData *pItem2,
839 wxTreeCtrl *tree)
840{
096c9f9b
VZ
841 wxCHECK_MSG( pItem1 && pItem2, 0,
842 _T("sorting tree without data doesn't make sense") );
843
23fd5130
VZ
844 return tree->OnCompareItems(pItem1->GetId(), pItem2->GetId());
845}
846
95aabccc
VZ
847int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
848 const wxTreeItemId& item2)
08b7c251 849{
95aabccc
VZ
850 return strcmp(GetItemText(item1), GetItemText(item2));
851}
852
853void wxTreeCtrl::SortChildren(const wxTreeItemId& item)
854{
855 // rely on the fact that TreeView_SortChildren does the same thing as our
23fd5130
VZ
856 // default behaviour, i.e. sorts items alphabetically and so call it
857 // directly if we're not in derived class (much more efficient!)
858 if ( GetClassInfo() == CLASSINFO(wxTreeCtrl) )
2bda0e17 859 {
23fd5130 860 TreeView_SortChildren(wxhWnd, (HTREEITEM)(WXHTREEITEM)item, 0);
2bda0e17 861 }
08b7c251 862 else
2bda0e17 863 {
62448488 864 TV_SORTCB tvSort;
23fd5130
VZ
865 tvSort.hParent = (HTREEITEM)(WXHTREEITEM)item;
866 tvSort.lpfnCompare = (PFNTVCOMPARE)TreeView_CompareCallback;
867 tvSort.lParam = (LPARAM)this;
868 TreeView_SortChildrenCB(wxhWnd, &tvSort, 0 /* reserved */);
2bda0e17 869 }
08b7c251 870}
2bda0e17 871
08b7c251
VZ
872// ----------------------------------------------------------------------------
873// implementation
874// ----------------------------------------------------------------------------
2bda0e17 875
08b7c251
VZ
876bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id)
877{
878 if ( cmd == EN_UPDATE )
2bda0e17 879 {
08b7c251
VZ
880 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
881 event.SetEventObject( this );
882 ProcessCommand(event);
2bda0e17 883 }
08b7c251 884 else if ( cmd == EN_KILLFOCUS )
2bda0e17 885 {
08b7c251
VZ
886 wxCommandEvent event(wxEVT_KILL_FOCUS, id);
887 event.SetEventObject( this );
888 ProcessCommand(event);
2bda0e17 889 }
08b7c251 890 else
2bda0e17 891 {
08b7c251
VZ
892 // nothing done
893 return FALSE;
2bda0e17 894 }
08b7c251
VZ
895
896 // command processed
897 return TRUE;
898}
899
900// process WM_NOTIFY Windows message
a23fd0e1 901bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
08b7c251
VZ
902{
903 wxTreeEvent event(wxEVT_NULL, m_windowId);
904 wxEventType eventType = wxEVT_NULL;
905 NMHDR *hdr = (NMHDR *)lParam;
906
907 switch ( hdr->code )
2bda0e17 908 {
08b7c251
VZ
909 case TVN_BEGINDRAG:
910 eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
911 // fall through
912
913 case TVN_BEGINRDRAG:
914 {
915 if ( eventType == wxEVT_NULL )
916 eventType = wxEVT_COMMAND_TREE_BEGIN_RDRAG;
917 //else: left drag, already set above
918
919 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
920
06e38c8e 921 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
08b7c251
VZ
922 event.m_pointDrag = wxPoint(tv->ptDrag.x, tv->ptDrag.y);
923 break;
924 }
925
926 case TVN_BEGINLABELEDIT:
927 {
928 eventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
929 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
930
06e38c8e 931 event.m_item = (WXHTREEITEM) info->item.hItem;
08b7c251
VZ
932 break;
933 }
934
935 case TVN_DELETEITEM:
936 {
937 eventType = wxEVT_COMMAND_TREE_DELETE_ITEM;
938 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
939
06e38c8e 940 event.m_item = (WXHTREEITEM) tv->itemOld.hItem;
08b7c251
VZ
941 break;
942 }
943
944 case TVN_ENDLABELEDIT:
945 {
946 eventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
947 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
948
06e38c8e 949 event.m_item = (WXHTREEITEM) info->item.hItem;
08b7c251
VZ
950 break;
951 }
952
953 case TVN_GETDISPINFO:
954 eventType = wxEVT_COMMAND_TREE_GET_INFO;
955 // fall through
956
957 case TVN_SETDISPINFO:
958 {
959 if ( eventType == wxEVT_NULL )
960 eventType = wxEVT_COMMAND_TREE_SET_INFO;
961 //else: get, already set above
962
963 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
964
06e38c8e 965 event.m_item = (WXHTREEITEM) info->item.hItem;
08b7c251
VZ
966 break;
967 }
968
969 case TVN_ITEMEXPANDING:
970 event.m_code = FALSE;
971 // fall through
972
973 case TVN_ITEMEXPANDED:
974 {
975 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
976
977 bool expand = FALSE;
978 switch ( tv->action )
979 {
980 case TVE_EXPAND:
981 expand = TRUE;
982 break;
983
984 case TVE_COLLAPSE:
985 expand = FALSE;
986 break;
987
988 default:
989 wxLogDebug("unexpected code %d in TVN_ITEMEXPAND "
990 "message", tv->action);
991 }
992
06e38c8e 993 bool ing = (hdr->code == TVN_ITEMEXPANDING);
08b7c251
VZ
994 eventType = g_events[expand][ing];
995
06e38c8e 996 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
08b7c251
VZ
997 break;
998 }
999
1000 case TVN_KEYDOWN:
1001 {
1002 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
1003 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
1004
1005 event.m_code = wxCharCodeMSWToWX(info->wVKey);
23fd5130
VZ
1006
1007 // a separate event for this case
1008 if ( info->wVKey == VK_SPACE || info->wVKey == VK_RETURN )
1009 {
1010 wxTreeEvent event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
1011 m_windowId);
1012 event2.SetEventObject(this);
1013
1014 GetEventHandler()->ProcessEvent(event2);
1015 }
08b7c251
VZ
1016 break;
1017 }
1018
1019 case TVN_SELCHANGED:
1020 eventType = wxEVT_COMMAND_TREE_SEL_CHANGED;
1021 // fall through
1022
1023 case TVN_SELCHANGING:
1024 {
1025 if ( eventType == wxEVT_NULL )
1026 eventType = wxEVT_COMMAND_TREE_SEL_CHANGING;
1027 //else: already set above
1028
1029 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
1030
06e38c8e
JS
1031 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
1032 event.m_itemOld = (WXHTREEITEM) tv->itemOld.hItem;
08b7c251
VZ
1033 break;
1034 }
1035
1036 default:
a23fd0e1 1037 return wxControl::MSWOnNotify(idCtrl, lParam, result);
2bda0e17 1038 }
08b7c251
VZ
1039
1040 event.SetEventObject(this);
1041 event.SetEventType(eventType);
1042
fd3f686c 1043 bool processed = GetEventHandler()->ProcessEvent(event);
08b7c251
VZ
1044
1045 // post processing
fd3f686c 1046 if ( hdr->code == TVN_DELETEITEM )
2bda0e17 1047 {
08b7c251
VZ
1048 // NB: we might process this message using wxWindows event tables, but
1049 // due to overhead of wxWin event system we prefer to do it here
1050 // (otherwise deleting a tree with many items is just too slow)
fd3f686c
VZ
1051 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
1052 wxTreeItemData *data = (wxTreeItemData *)tv->itemOld.lParam;
1053 delete data; // may be NULL, ok
8162b848 1054 processed = TRUE; // Make sure we don't get called twice
2bda0e17 1055 }
08b7c251 1056
fd3f686c
VZ
1057 *result = !event.IsAllowed();
1058
1059 return processed;
2bda0e17
KB
1060}
1061
08b7c251 1062// ----------------------------------------------------------------------------
2bda0e17 1063// Tree event
08b7c251
VZ
1064// ----------------------------------------------------------------------------
1065
92976ab6 1066IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
2bda0e17 1067
08b7c251 1068wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
fd3f686c 1069 : wxNotifyEvent(commandType, id)
2bda0e17 1070{
08b7c251
VZ
1071 m_code = 0;
1072 m_itemOld = 0;
2bda0e17
KB
1073}
1074
08b7c251 1075#endif // __WIN95__
2bda0e17 1076