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