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