]> git.saurik.com Git - wxWidgets.git/blame - src/generic/treectrl.cpp
1. changed spelling error in wxTR_HAS_VARIABLE_HEIGHT (missing 'E')
[wxWidgets.git] / src / generic / treectrl.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: treectrl.cpp
f135ff73 3// Purpose: generic tree control implementation
c801d85f
KB
4// Author: Robert Roebling
5// Created: 01/02/97
f135ff73 6// Modified: 22/10/98 - almost total rewrite, simpler interface (VZ)
389cdc7a 7// Id: $Id$
c801d85f 8// Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
29d87bba 9// Licence: wxWindows licence
c801d85f
KB
10/////////////////////////////////////////////////////////////////////////////
11
f135ff73
VZ
12// =============================================================================
13// declarations
14// =============================================================================
15
16// -----------------------------------------------------------------------------
17// headers
18// -----------------------------------------------------------------------------
19
c801d85f 20#ifdef __GNUG__
f135ff73 21 #pragma implementation "treectrl.h"
c801d85f
KB
22#endif
23
1e6d9499
JS
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28#pragma hdrstop
29#endif
30
31#include "wx/generic/treectrl.h"
f60d0f94 32#include "wx/generic/imaglist.h"
c801d85f 33#include "wx/settings.h"
389cdc7a 34#include "wx/log.h"
f135ff73
VZ
35#include "wx/intl.h"
36#include "wx/dynarray.h"
91b8de8d 37#include "wx/arrimpl.cpp"
f135ff73 38#include "wx/dcclient.h"
0659e7ee 39#include "wx/msgdlg.h"
c801d85f 40
f135ff73
VZ
41// -----------------------------------------------------------------------------
42// array types
43// -----------------------------------------------------------------------------
c801d85f 44
1e6d9499
JS
45class WXDLLEXPORT wxGenericTreeItem;
46
91b8de8d
RR
47WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
48WX_DEFINE_OBJARRAY(wxArrayTreeItemIds);
c801d85f 49
f135ff73
VZ
50// -----------------------------------------------------------------------------
51// private classes
52// -----------------------------------------------------------------------------
53
54// a tree item
55class WXDLLEXPORT wxGenericTreeItem
c801d85f 56{
f135ff73
VZ
57public:
58 // ctors & dtor
59 wxGenericTreeItem() { m_data = NULL; }
60 wxGenericTreeItem( wxGenericTreeItem *parent,
61 const wxString& text,
62 wxDC& dc,
63 int image, int selImage,
64 wxTreeItemData *data );
65
ff5bf259 66 ~wxGenericTreeItem();
f135ff73
VZ
67
68 // trivial accessors
91b8de8d 69 wxArrayGenericTreeItems& GetChildren() { return m_children; }
f135ff73
VZ
70
71 const wxString& GetText() const { return m_text; }
72 int GetImage() const { return m_image; }
73 int GetSelectedImage() const { return m_selImage; }
74 wxTreeItemData *GetData() const { return m_data; }
75
91b8de8d 76 void SetText( const wxString &text );
f135ff73
VZ
77 void SetImage(int image) { m_image = image; }
78 void SetSelectedImage(int image) { m_selImage = image; }
79 void SetData(wxTreeItemData *data) { m_data = data; }
80
81 void SetHasPlus(bool has = TRUE) { m_hasPlus = has; }
82
ef44a621
VZ
83 void SetBold(bool bold) { m_isBold = bold; }
84
f135ff73
VZ
85 int GetX() const { return m_x; }
86 int GetY() const { return m_y; }
87
f135ff73
VZ
88 void SetX(int x) { m_x = x; }
89 void SetY(int y) { m_y = y; }
90
91b8de8d
RR
91 int GetHeight() const { return m_height; }
92 int GetWidth() const { return m_width; }
93
94 void SetHeight(int h) { m_height = h; }
95 void SetWidth(int w) { m_width = w; }
96
97
f135ff73 98 wxGenericTreeItem *GetParent() const { return m_parent; }
c801d85f 99
f135ff73 100 // operations
a43a4f9d
VZ
101 // deletes all children notifying the treectrl about it if !NULL pointer
102 // given
103 void DeleteChildren(wxTreeCtrl *tree = NULL);
104 // FIXME don't know what is it for
f135ff73
VZ
105 void Reset();
106
4832f7c0
VZ
107 // get count of all children (and grand children if 'recursively')
108 size_t GetChildrenCount(bool recursively = TRUE) const;
f135ff73
VZ
109
110 void Insert(wxGenericTreeItem *child, size_t index)
111 { m_children.Insert(child, index); }
112
113 void SetCross( int x, int y );
91b8de8d 114 void GetSize( int &x, int &y, const wxTreeCtrl* );
f135ff73
VZ
115
116 // return the item at given position (or NULL if no item), onButton is TRUE
117 // if the point belongs to the item's button, otherwise it lies on the
118 // button's label
91b8de8d 119 wxGenericTreeItem *HitTest( const wxPoint& point, const wxTreeCtrl *, int &flags);
f135ff73
VZ
120
121 void Expand() { m_isCollapsed = FALSE; }
122 void Collapse() { m_isCollapsed = TRUE; }
123
124 void SetHilight( bool set = TRUE ) { m_hasHilight = set; }
125
126 // status inquiries
127 bool HasChildren() const { return !m_children.IsEmpty(); }
128 bool HasHilight() const { return m_hasHilight; }
129 bool IsExpanded() const { return !m_isCollapsed; }
130 bool HasPlus() const { return m_hasPlus || HasChildren(); }
ef44a621 131 bool IsBold() const { return m_isBold; }
f135ff73
VZ
132
133private:
134 wxString m_text;
135
136 int m_image,
137 m_selImage;
138
139 wxTreeItemData *m_data;
4832f7c0 140
ef44a621
VZ
141 // use bitfields to save size
142 int m_isCollapsed :1;
143 int m_hasHilight :1; // same as focused
144 int m_hasPlus :1; // used for item which doesn't have
145 // children but still has a [+] button
146 int m_isBold :1; // render the label in bold font
f135ff73
VZ
147
148 int m_x, m_y;
91b8de8d 149 long m_height, m_width;
f135ff73
VZ
150 int m_xCross, m_yCross;
151 int m_level;
91b8de8d 152 wxArrayGenericTreeItems m_children;
f135ff73
VZ
153 wxGenericTreeItem *m_parent;
154};
155
156// =============================================================================
157// implementation
158// =============================================================================
159
91b8de8d 160#define PIXELS_PER_UNIT 10
f135ff73 161// -----------------------------------------------------------------------------
c801d85f 162// wxTreeEvent
f135ff73 163// -----------------------------------------------------------------------------
c801d85f 164
92976ab6 165IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
c801d85f 166
f135ff73 167wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
92976ab6 168 : wxNotifyEvent( commandType, id )
c801d85f
KB
169{
170 m_code = 0;
f135ff73 171 m_itemOld = (wxGenericTreeItem *)NULL;
edaa81ae 172}
c801d85f 173
f135ff73 174// -----------------------------------------------------------------------------
c801d85f 175// wxGenericTreeItem
f135ff73 176// -----------------------------------------------------------------------------
c801d85f 177
f135ff73
VZ
178wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
179 const wxString& text,
180 wxDC& dc,
181 int image, int selImage,
182 wxTreeItemData *data)
183 : m_text(text)
c801d85f 184{
f135ff73
VZ
185 m_image = image;
186 m_selImage = selImage;
187 m_data = data;
188 m_x = m_y = 0;
189 m_xCross = m_yCross = 0;
190
191 m_level = 0;
192
193 m_isCollapsed = TRUE;
c801d85f 194 m_hasHilight = FALSE;
df875e59 195 m_hasPlus = FALSE;
ef44a621 196 m_isBold = FALSE;
c801d85f 197
c801d85f 198 m_parent = parent;
f135ff73 199
91b8de8d
RR
200 dc.GetTextExtent( m_text, &m_width, &m_height );
201 // TODO : Add the width of the image
202 // PB : We don't know which image is shown (image, selImage)
203 // We don't even know imageList from the treectrl this item belongs to !!!
204 // At this point m_width doesn't mean much, this can be remove !
edaa81ae 205}
c801d85f 206
f135ff73 207wxGenericTreeItem::~wxGenericTreeItem()
c801d85f 208{
f135ff73 209 delete m_data;
4832f7c0 210
a43a4f9d 211 wxASSERT_MSG( m_children.IsEmpty(),
87138c52 212 _T("please call DeleteChildren() before deleting the item") );
372edb9d
VZ
213}
214
a43a4f9d 215void wxGenericTreeItem::DeleteChildren(wxTreeCtrl *tree)
372edb9d 216{
f135ff73
VZ
217 size_t count = m_children.Count();
218 for ( size_t n = 0; n < count; n++ )
a43a4f9d
VZ
219 {
220 wxGenericTreeItem *child = m_children[n];
221 if ( tree )
222 {
223 tree->SendDeleteEvent(child);
224 }
225
226 child->DeleteChildren(tree);
227 delete child;
228 }
372edb9d
VZ
229
230 m_children.Empty();
edaa81ae 231}
c801d85f 232
91b8de8d 233void wxGenericTreeItem::SetText( const wxString &text )
c801d85f
KB
234{
235 m_text = text;
edaa81ae 236}
c801d85f 237
74bedbeb 238void wxGenericTreeItem::Reset()
c801d85f 239{
f135ff73
VZ
240 m_text.Empty();
241 m_image =
242 m_selImage = -1;
243 m_data = NULL;
244 m_x = m_y =
91b8de8d 245 m_height = m_width = 0;
f135ff73 246 m_xCross =
c801d85f 247 m_yCross = 0;
74bedbeb 248
f135ff73 249 m_level = 0;
c801d85f 250
372edb9d 251 DeleteChildren();
f135ff73 252 m_isCollapsed = TRUE;
c801d85f 253
f135ff73 254 m_parent = (wxGenericTreeItem *)NULL;
edaa81ae 255}
c801d85f 256
4832f7c0 257size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
c801d85f 258{
f135ff73 259 size_t count = m_children.Count();
4832f7c0
VZ
260 if ( !recursively )
261 return count;
262
f135ff73 263 size_t total = count;
91b8de8d 264 for ( size_t n = 0; n < count; ++n )
c801d85f 265 {
4832f7c0 266 total += m_children[n]->GetChildrenCount();
edaa81ae 267 }
c801d85f 268
f135ff73 269 return total;
edaa81ae 270}
c801d85f
KB
271
272void wxGenericTreeItem::SetCross( int x, int y )
273{
274 m_xCross = x;
275 m_yCross = y;
edaa81ae 276}
c801d85f 277
91b8de8d 278void wxGenericTreeItem::GetSize( int &x, int &y, const wxTreeCtrl *theTree )
c801d85f 279{
91b8de8d
RR
280 int bottomY=m_y+theTree->GetLineHeight(this);
281 if ( y < bottomY ) y = bottomY;
282 int width = m_x + m_width;
283 if ( x < width ) x = width;
f135ff73 284
df875e59 285 if (IsExpanded())
c801d85f 286 {
df875e59 287 size_t count = m_children.Count();
91b8de8d 288 for ( size_t n = 0; n < count; ++n )
4832f7c0 289 {
91b8de8d 290 m_children[n]->GetSize( x, y, theTree );
df875e59 291 }
edaa81ae
RR
292 }
293}
c801d85f 294
f135ff73 295wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point,
91b8de8d
RR
296 const wxTreeCtrl *theTree,
297 int &flags)
c801d85f 298{
91b8de8d 299 if ((point.y > m_y) && (point.y < m_y + theTree->GetLineHeight(this)))
c801d85f 300 {
91b8de8d
RR
301 if (point.y<m_y+theTree->GetLineHeight(this)/2) flags|=wxTREE_HITTEST_ONITEMUPPERPART;
302 else flags|=wxTREE_HITTEST_ONITEMLOWERPART;
303
f135ff73 304 // FIXME why +5?
5679f335 305 // Because that is the size of the plus sign, RR
f135ff73
VZ
306 if ((point.x > m_xCross-5) && (point.x < m_xCross+5) &&
307 (point.y > m_yCross-5) && (point.y < m_yCross+5) &&
f9f950fc 308 (IsExpanded() || HasPlus()))
c801d85f 309 {
91b8de8d 310 flags|=wxTREE_HITTEST_ONITEMBUTTON;
f135ff73 311 return this;
edaa81ae 312 }
978f38c2 313
91b8de8d 314 if ((point.x >= m_x) && (point.x <= m_x+m_width))
c801d85f 315 {
d3a9f4af
RD
316 int image_w = -1;
317 int image_h;
318
91b8de8d 319 // assuming every image (normal and selected ) has the same size !
0ae7f2a2 320 if ((m_image!=-1) && theTree->m_imageListNormal)
d3a9f4af 321 theTree->m_imageListNormal->GetSize(m_image, image_w, image_h);
0ae7f2a2 322
d3a9f4af 323 if ((image_w != -1) && (point.x <= m_x + image_w + 1))
91b8de8d 324 flags|=wxTREE_HITTEST_ONITEMICON;
d3a9f4af 325 else
91b8de8d
RR
326 flags|=wxTREE_HITTEST_ONITEMLABEL;
327
f135ff73 328 return this;
edaa81ae 329 }
91b8de8d
RR
330
331 if (point.x < m_x) flags|=wxTREE_HITTEST_ONITEMIDENT;
332 if (point.x > m_x+m_width) flags|=wxTREE_HITTEST_ONITEMRIGHT;
333
334 return this;
c801d85f
KB
335 }
336 else
337 {
e2414cbe 338 if (!m_isCollapsed)
c801d85f 339 {
f135ff73
VZ
340 size_t count = m_children.Count();
341 for ( size_t n = 0; n < count; n++ )
e2414cbe 342 {
91b8de8d 343 wxGenericTreeItem *res = m_children[n]->HitTest( point, theTree, flags );
f135ff73
VZ
344 if ( res != NULL )
345 return res;
edaa81ae
RR
346 }
347 }
348 }
f135ff73 349
91b8de8d 350 flags|=wxTREE_HITTEST_NOWHERE;
f135ff73 351 return NULL;
edaa81ae 352}
c801d85f 353
f135ff73
VZ
354// -----------------------------------------------------------------------------
355// wxTreeCtrl implementation
356// -----------------------------------------------------------------------------
357
358IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxScrolledWindow)
359
360BEGIN_EVENT_TABLE(wxTreeCtrl,wxScrolledWindow)
361 EVT_PAINT (wxTreeCtrl::OnPaint)
362 EVT_MOUSE_EVENTS (wxTreeCtrl::OnMouse)
363 EVT_CHAR (wxTreeCtrl::OnChar)
364 EVT_SET_FOCUS (wxTreeCtrl::OnSetFocus)
365 EVT_KILL_FOCUS (wxTreeCtrl::OnKillFocus)
3db7be80 366 EVT_IDLE (wxTreeCtrl::OnIdle)
f135ff73
VZ
367END_EVENT_TABLE()
368
369// -----------------------------------------------------------------------------
370// construction/destruction
371// -----------------------------------------------------------------------------
91b8de8d 372
f135ff73 373void wxTreeCtrl::Init()
c801d85f 374{
d3a9f4af 375 m_current =
91b8de8d 376 m_key_current =
f135ff73
VZ
377 m_anchor = (wxGenericTreeItem *) NULL;
378 m_hasFocus = FALSE;
3db7be80 379 m_dirty = FALSE;
f135ff73
VZ
380
381 m_xScroll = 0;
382 m_yScroll = 0;
383 m_lineHeight = 10;
384 m_indent = 15;
cf724bce 385 m_spacing = 18;
f135ff73
VZ
386
387 m_hilightBrush = new wxBrush
388 (
389 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT),
390 wxSOLID
391 );
392
393 m_imageListNormal =
394 m_imageListState = (wxImageList *) NULL;
978f38c2 395
bbe0af5b 396 m_dragCount = 0;
edaa81ae 397}
c801d85f 398
f135ff73
VZ
399bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
400 const wxPoint& pos, const wxSize& size,
978f38c2
VZ
401 long style,
402 const wxValidator &validator,
403 const wxString& name )
c801d85f 404{
f135ff73
VZ
405 Init();
406
a367b9b3 407 wxScrolledWindow::Create( parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name );
978f38c2 408
ce4169a4 409#if wxUSE_VALIDATORS
4f22cf8d 410 SetValidator( validator );
ce4169a4 411#endif
f135ff73
VZ
412
413 SetBackgroundColour( *wxWHITE );
b62c3631
RR
414// m_dottedPen = wxPen( "grey", 0, wxDOT );
415 m_dottedPen = wxPen( "grey", 0, 0 );
f135ff73
VZ
416
417 return TRUE;
edaa81ae 418}
c801d85f 419
f135ff73 420wxTreeCtrl::~wxTreeCtrl()
c801d85f 421{
f135ff73 422 wxDELETE( m_hilightBrush );
a43a4f9d
VZ
423
424 DeleteAllItems();
edaa81ae 425}
c801d85f 426
f135ff73
VZ
427// -----------------------------------------------------------------------------
428// accessors
429// -----------------------------------------------------------------------------
430
431size_t wxTreeCtrl::GetCount() const
c801d85f 432{
4832f7c0 433 return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount();
edaa81ae 434}
c801d85f 435
f135ff73 436void wxTreeCtrl::SetIndent(unsigned int indent)
c801d85f 437{
f135ff73 438 m_indent = indent;
cf724bce
RR
439 m_dirty = TRUE;
440 Refresh();
441}
442
443void wxTreeCtrl::SetSpacing(unsigned int spacing)
444{
445 m_spacing = spacing;
446 m_dirty = TRUE;
f135ff73
VZ
447 Refresh();
448}
74bedbeb 449
4832f7c0
VZ
450size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
451{
87138c52 452 wxCHECK_MSG( item.IsOk(), 0u, _T("invalid tree item") );
4832f7c0
VZ
453
454 return item.m_pItem->GetChildrenCount(recursively);
455}
456
f135ff73
VZ
457// -----------------------------------------------------------------------------
458// functions to work with tree items
459// -----------------------------------------------------------------------------
74bedbeb 460
f135ff73
VZ
461wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
462{
87138c52 463 wxCHECK_MSG( item.IsOk(), _T(""), _T("invalid tree item") );
4832f7c0 464
f135ff73 465 return item.m_pItem->GetText();
edaa81ae 466}
74bedbeb 467
f135ff73 468int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
74bedbeb 469{
87138c52 470 wxCHECK_MSG( item.IsOk(), -1, _T("invalid tree item") );
4832f7c0 471
f135ff73 472 return item.m_pItem->GetImage();
edaa81ae 473}
c801d85f 474
f135ff73 475int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
c801d85f 476{
87138c52 477 wxCHECK_MSG( item.IsOk(), -1, _T("invalid tree item") );
4832f7c0 478
f135ff73 479 return item.m_pItem->GetSelectedImage();
edaa81ae 480}
c801d85f 481
f135ff73 482wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
c801d85f 483{
87138c52 484 wxCHECK_MSG( item.IsOk(), NULL, _T("invalid tree item") );
4832f7c0 485
f135ff73 486 return item.m_pItem->GetData();
edaa81ae 487}
c801d85f 488
f135ff73
VZ
489void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
490{
87138c52 491 wxCHECK_RET( item.IsOk(), _T("invalid tree item") );
4832f7c0 492
f135ff73 493 wxClientDC dc(this);
f992adf9 494 wxGenericTreeItem *pItem = item.m_pItem;
91b8de8d
RR
495 pItem->SetText(text);
496 CalculateSize(pItem, dc);
f992adf9 497 RefreshLine(pItem);
f135ff73 498}
c801d85f 499
f135ff73
VZ
500void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
501{
87138c52 502 wxCHECK_RET( item.IsOk(), _T("invalid tree item") );
4832f7c0 503
91b8de8d 504 wxClientDC dc(this);
f992adf9
VZ
505 wxGenericTreeItem *pItem = item.m_pItem;
506 pItem->SetImage(image);
91b8de8d 507 CalculateSize(pItem, dc);
f992adf9 508 RefreshLine(pItem);
f135ff73 509}
c801d85f 510
f135ff73 511void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
c801d85f 512{
87138c52 513 wxCHECK_RET( item.IsOk(), _T("invalid tree item") );
4832f7c0 514
91b8de8d 515 wxClientDC dc(this);
f992adf9
VZ
516 wxGenericTreeItem *pItem = item.m_pItem;
517 pItem->SetSelectedImage(image);
91b8de8d 518 CalculateSize(pItem, dc);
f992adf9 519 RefreshLine(pItem);
edaa81ae 520}
c801d85f 521
f135ff73 522void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
c801d85f 523{
87138c52 524 wxCHECK_RET( item.IsOk(), _T("invalid tree item") );
4832f7c0 525
de646ed1 526 item.m_pItem->SetData(data);
edaa81ae 527}
c801d85f 528
f135ff73 529void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
c801d85f 530{
87138c52 531 wxCHECK_RET( item.IsOk(), _T("invalid tree item") );
4832f7c0 532
f992adf9
VZ
533 wxGenericTreeItem *pItem = item.m_pItem;
534 pItem->SetHasPlus(has);
535 RefreshLine(pItem);
edaa81ae 536}
c801d85f 537
ef44a621
VZ
538void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
539{
87138c52 540 wxCHECK_RET( item.IsOk(), _T("invalid tree item") );
ef44a621
VZ
541
542 // avoid redrawing the tree if no real change
543 wxGenericTreeItem *pItem = item.m_pItem;
544 if ( pItem->IsBold() != bold )
545 {
546 pItem->SetBold(bold);
547 RefreshLine(pItem);
548 }
549}
550
f135ff73
VZ
551// -----------------------------------------------------------------------------
552// item status inquiries
553// -----------------------------------------------------------------------------
554
df875e59 555bool wxTreeCtrl::IsVisible(const wxTreeItemId& WXUNUSED(item)) const
c801d85f 556{
87138c52 557 wxFAIL_MSG(_T("not implemented"));
f135ff73 558
c801d85f 559 return TRUE;
edaa81ae 560}
c801d85f 561
f135ff73 562bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
c801d85f 563{
87138c52 564 wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid tree item") );
4832f7c0 565
f135ff73 566 return !item.m_pItem->GetChildren().IsEmpty();
edaa81ae 567}
c801d85f 568
f135ff73 569bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
c801d85f 570{
87138c52 571 wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid tree item") );
4832f7c0 572
f135ff73
VZ
573 return item.m_pItem->IsExpanded();
574}
29d87bba 575
f135ff73
VZ
576bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
577{
87138c52 578 wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid tree item") );
4832f7c0 579
f135ff73
VZ
580 return item.m_pItem->HasHilight();
581}
29d87bba 582
ef44a621
VZ
583bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
584{
87138c52 585 wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid tree item") );
ef44a621
VZ
586
587 return item.m_pItem->IsBold();
588}
589
f135ff73
VZ
590// -----------------------------------------------------------------------------
591// navigation
592// -----------------------------------------------------------------------------
29d87bba 593
f135ff73
VZ
594wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
595{
87138c52 596 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), _T("invalid tree item") );
389cdc7a 597
f135ff73
VZ
598 return item.m_pItem->GetParent();
599}
29d87bba 600
f135ff73
VZ
601wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
602{
87138c52 603 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), _T("invalid tree item") );
29d87bba 604
f135ff73
VZ
605 cookie = 0;
606 return GetNextChild(item, cookie);
607}
29d87bba 608
f135ff73
VZ
609wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
610{
87138c52 611 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), _T("invalid tree item") );
29d87bba 612
91b8de8d 613 wxArrayGenericTreeItems& children = item.m_pItem->GetChildren();
4832f7c0
VZ
614 if ( (size_t)cookie < children.Count() )
615 {
978f38c2 616 return children.Item(cookie++);
4832f7c0
VZ
617 }
618 else
619 {
620 // there are no more of them
1e6d9499 621 return wxTreeItemId();
4832f7c0 622 }
f135ff73 623}
29d87bba 624
978f38c2
VZ
625wxTreeItemId wxTreeCtrl::GetLastChild(const wxTreeItemId& item) const
626{
87138c52 627 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), _T("invalid tree item") );
978f38c2 628
91b8de8d 629 wxArrayGenericTreeItems& children = item.m_pItem->GetChildren();
0a240683 630 return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last()));
978f38c2
VZ
631}
632
f135ff73
VZ
633wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
634{
87138c52 635 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), _T("invalid tree item") );
f135ff73
VZ
636
637 wxGenericTreeItem *i = item.m_pItem;
638 wxGenericTreeItem *parent = i->GetParent();
639 if ( parent == NULL )
640 {
641 // root item doesn't have any siblings
1e6d9499 642 return wxTreeItemId();
edaa81ae 643 }
4832f7c0 644
91b8de8d 645 wxArrayGenericTreeItems& siblings = parent->GetChildren();
f135ff73 646 int index = siblings.Index(i);
3c67202d 647 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
29d87bba 648
f135ff73 649 size_t n = (size_t)(index + 1);
fdd8d7b5 650 return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
edaa81ae 651}
c801d85f 652
f135ff73 653wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
c801d85f 654{
87138c52 655 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), _T("invalid tree item") );
f135ff73
VZ
656
657 wxGenericTreeItem *i = item.m_pItem;
658 wxGenericTreeItem *parent = i->GetParent();
659 if ( parent == NULL )
c801d85f 660 {
f135ff73 661 // root item doesn't have any siblings
1e6d9499 662 return wxTreeItemId();
edaa81ae 663 }
4832f7c0 664
91b8de8d 665 wxArrayGenericTreeItems& siblings = parent->GetChildren();
f135ff73 666 int index = siblings.Index(i);
3c67202d 667 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
29d87bba 668
fdd8d7b5
VZ
669 return index == 0 ? wxTreeItemId()
670 : wxTreeItemId(siblings[(size_t)(index - 1)]);
f135ff73 671}
389cdc7a 672
f135ff73
VZ
673wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
674{
87138c52 675 wxFAIL_MSG(_T("not implemented"));
29d87bba 676
1e6d9499 677 return wxTreeItemId();
f135ff73 678}
29d87bba 679
f135ff73
VZ
680wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
681{
87138c52 682 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), _T("invalid tree item") );
29d87bba 683
87138c52 684 wxFAIL_MSG(_T("not implemented"));
29d87bba 685
1e6d9499 686 return wxTreeItemId();
f135ff73 687}
29d87bba 688
f135ff73
VZ
689wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
690{
87138c52 691 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), _T("invalid tree item") );
29d87bba 692
87138c52 693 wxFAIL_MSG(_T("not implemented"));
29d87bba 694
1e6d9499 695 return wxTreeItemId();
edaa81ae 696}
c801d85f 697
f135ff73
VZ
698// -----------------------------------------------------------------------------
699// operations
700// -----------------------------------------------------------------------------
701
702wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
703 size_t previous,
704 const wxString& text,
705 int image, int selImage,
706 wxTreeItemData *data)
c801d85f 707{
f135ff73
VZ
708 wxGenericTreeItem *parent = parentId.m_pItem;
709 if ( !parent )
710 {
711 // should we give a warning here?
712 return AddRoot(text, image, selImage, data);
713 }
4832f7c0 714
f135ff73
VZ
715 wxClientDC dc(this);
716 wxGenericTreeItem *item = new wxGenericTreeItem(parent,
717 text, dc,
718 image, selImage,
719 data);
74bedbeb 720
f135ff73 721 if ( data != NULL )
c801d85f 722 {
f135ff73
VZ
723 data->m_pItem = item;
724 }
74bedbeb 725
f135ff73 726 parent->Insert( item, previous );
ef44a621 727
3db7be80 728 m_dirty = TRUE;
389cdc7a 729
f135ff73 730 return item;
4c681997
RR
731}
732
f135ff73
VZ
733wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
734 int image, int selImage,
735 wxTreeItemData *data)
4c681997 736{
87138c52 737 wxCHECK_MSG( !m_anchor, wxTreeItemId(), _T("tree can have only one root") );
389cdc7a 738
f135ff73
VZ
739 wxClientDC dc(this);
740 m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
741 image, selImage, data);
742 if ( data != NULL )
743 {
744 data->m_pItem = m_anchor;
745 }
389cdc7a 746
a32dd690 747 Refresh();
91b8de8d 748 AdjustMyScrollbars();
a32dd690 749
f135ff73 750 return m_anchor;
edaa81ae 751}
c801d85f 752
f135ff73
VZ
753wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
754 const wxString& text,
755 int image, int selImage,
756 wxTreeItemData *data)
c801d85f 757{
f135ff73 758 return DoInsertItem(parent, 0u, text, image, selImage, data);
edaa81ae 759}
c801d85f 760
f135ff73
VZ
761wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId,
762 const wxTreeItemId& idPrevious,
763 const wxString& text,
764 int image, int selImage,
765 wxTreeItemData *data)
c801d85f 766{
f135ff73
VZ
767 wxGenericTreeItem *parent = parentId.m_pItem;
768 if ( !parent )
769 {
770 // should we give a warning here?
771 return AddRoot(text, image, selImage, data);
772 }
c801d85f 773
f135ff73 774 int index = parent->GetChildren().Index(idPrevious.m_pItem);
3c67202d 775 wxASSERT_MSG( index != wxNOT_FOUND,
87138c52 776 _T("previous item in wxTreeCtrl::InsertItem() is not a sibling") );
91b8de8d 777 return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data);
edaa81ae 778}
c801d85f 779
f135ff73
VZ
780wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId,
781 const wxString& text,
782 int image, int selImage,
783 wxTreeItemData *data)
74bedbeb 784{
f135ff73
VZ
785 wxGenericTreeItem *parent = parentId.m_pItem;
786 if ( !parent )
787 {
788 // should we give a warning here?
789 return AddRoot(text, image, selImage, data);
790 }
791
792 return DoInsertItem(parent, parent->GetChildren().Count(), text,
793 image, selImage, data);
74bedbeb
VZ
794}
795
a43a4f9d
VZ
796void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
797{
798 wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
799 event.m_item = item;
800 event.SetEventObject( this );
801 ProcessEvent( event );
802}
803
372edb9d
VZ
804void wxTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
805{
806 wxGenericTreeItem *item = itemId.m_pItem;
a43a4f9d 807 item->DeleteChildren(this);
372edb9d
VZ
808
809 m_dirty = TRUE;
810}
811
f135ff73 812void wxTreeCtrl::Delete(const wxTreeItemId& itemId)
c801d85f 813{
f135ff73 814 wxGenericTreeItem *item = itemId.m_pItem;
ff5bf259
VZ
815 wxGenericTreeItem *parent = item->GetParent();
816
817 if ( parent )
818 {
819 parent->GetChildren().Remove(item);
820 }
f135ff73 821
a43a4f9d
VZ
822 item->DeleteChildren(this);
823 SendDeleteEvent(item);
f135ff73
VZ
824 delete item;
825
4bb19cfb 826 m_dirty = TRUE;
edaa81ae 827}
c801d85f 828
f135ff73 829void wxTreeCtrl::DeleteAllItems()
c801d85f 830{
f135ff73
VZ
831 if ( m_anchor )
832 {
a43a4f9d 833 m_anchor->DeleteChildren(this);
f135ff73 834 delete m_anchor;
a43a4f9d 835
f135ff73
VZ
836 m_anchor = NULL;
837
4bb19cfb 838 m_dirty = TRUE;
f135ff73 839 }
edaa81ae
RR
840}
841
f135ff73 842void wxTreeCtrl::Expand(const wxTreeItemId& itemId)
edaa81ae 843{
f135ff73
VZ
844 wxGenericTreeItem *item = itemId.m_pItem;
845
978f38c2 846 if ( !item->HasPlus() )
4bb19cfb 847 return;
978f38c2 848
f135ff73
VZ
849 if ( item->IsExpanded() )
850 return;
851
852 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
853 event.m_item = item;
854 event.SetEventObject( this );
855 if ( ProcessEvent( event ) && event.m_code )
856 {
857 // cancelled by program
858 return;
859 }
4832f7c0 860
f135ff73 861 item->Expand();
28ab302b 862 CalculatePositions();
f135ff73
VZ
863
864 RefreshSubtree(item);
865
866 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
867 ProcessEvent( event );
edaa81ae
RR
868}
869
f135ff73 870void wxTreeCtrl::Collapse(const wxTreeItemId& itemId)
edaa81ae 871{
f135ff73
VZ
872 wxGenericTreeItem *item = itemId.m_pItem;
873
874 if ( !item->IsExpanded() )
875 return;
876
877 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
878 event.m_item = item;
879 event.SetEventObject( this );
880 if ( ProcessEvent( event ) && event.m_code )
edaa81ae 881 {
f135ff73
VZ
882 // cancelled by program
883 return;
884 }
4832f7c0 885
f135ff73
VZ
886 item->Collapse();
887
91b8de8d 888 wxArrayGenericTreeItems& children = item->GetChildren();
f135ff73
VZ
889 size_t count = children.Count();
890 for ( size_t n = 0; n < count; n++ )
891 {
892 Collapse(children[n]);
edaa81ae 893 }
f135ff73
VZ
894
895 CalculatePositions();
896
897 RefreshSubtree(item);
898
899 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
900 ProcessEvent( event );
edaa81ae 901}
c801d85f 902
f135ff73 903void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
c801d85f 904{
f135ff73 905 Collapse(item);
372edb9d 906 DeleteChildren(item);
edaa81ae 907}
c801d85f 908
f135ff73 909void wxTreeCtrl::Toggle(const wxTreeItemId& itemId)
c801d85f 910{
f135ff73 911 wxGenericTreeItem *item = itemId.m_pItem;
389cdc7a 912
f135ff73
VZ
913 if ( item->IsExpanded() )
914 Collapse(itemId);
915 else
916 Expand(itemId);
917}
389cdc7a 918
f135ff73
VZ
919void wxTreeCtrl::Unselect()
920{
921 if ( m_current )
922 {
923 m_current->SetHilight( FALSE );
924 RefreshLine( m_current );
925 }
edaa81ae 926}
c801d85f 927
88ac883a 928void wxTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
389cdc7a 929{
88ac883a
VZ
930 item->SetHilight(FALSE);
931 RefreshLine(item);
d3a9f4af 932
88ac883a
VZ
933 if (item->HasChildren())
934 {
91b8de8d 935 wxArrayGenericTreeItems& children = item->GetChildren();
88ac883a
VZ
936 size_t count = children.Count();
937 for ( size_t n = 0; n < count; ++n )
938 UnselectAllChildren(children[n]);
939 }
940}
f135ff73 941
88ac883a
VZ
942void wxTreeCtrl::UnselectAll()
943{
944 UnselectAllChildren(GetRootItem().m_pItem);
945}
946
947// Recursive function !
948// To stop we must have crt_item<last_item
91b8de8d 949// Algorithm :
88ac883a 950// Tag all next children, when no more children,
d3a9f4af 951// Move to parent (not to tag)
91b8de8d 952// Keep going... if we found last_item, we stop.
88ac883a
VZ
953bool wxTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select)
954{
955 wxGenericTreeItem *parent = crt_item->GetParent();
956
957 if ( parent == NULL ) // This is root item
958 return TagAllChildrenUntilLast(crt_item, last_item, select);
959
91b8de8d 960 wxArrayGenericTreeItems& children = parent->GetChildren();
88ac883a
VZ
961 int index = children.Index(crt_item);
962 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
963
964 size_t count = children.Count();
965 for (size_t n=(size_t)(index+1); n<count; ++n)
c0de7af4 966 if (TagAllChildrenUntilLast(children[n], last_item, select)) return TRUE;
88ac883a
VZ
967
968 return TagNextChildren(parent, last_item, select);
969}
970
971bool wxTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select)
972{
973 crt_item->SetHilight(select);
974 RefreshLine(crt_item);
d3a9f4af 975
c0de7af4 976 if (crt_item==last_item) return TRUE;
88ac883a
VZ
977
978 if (crt_item->HasChildren())
979 {
91b8de8d 980 wxArrayGenericTreeItems& children = crt_item->GetChildren();
88ac883a
VZ
981 size_t count = children.Count();
982 for ( size_t n = 0; n < count; ++n )
c0de7af4 983 if (TagAllChildrenUntilLast(children[n], last_item, select)) return TRUE;
88ac883a 984 }
d3a9f4af 985
c0de7af4 986 return FALSE;
88ac883a
VZ
987}
988
989void wxTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2)
990{
991 // item2 is not necessary after item1
992 wxGenericTreeItem *first=NULL, *last=NULL;
993
994 // choice first' and 'last' between item1 and item2
d3a9f4af 995 if (item1->GetY()<item2->GetY())
88ac883a
VZ
996 {
997 first=item1;
998 last=item2;
999 }
d3a9f4af 1000 else
88ac883a
VZ
1001 {
1002 first=item2;
1003 last=item1;
1004 }
1005
1006 bool select=m_current->HasHilight();
d3a9f4af 1007
88ac883a
VZ
1008 if (TagAllChildrenUntilLast(first,last,select)) return;
1009
d3a9f4af 1010 TagNextChildren(first,last,select);
88ac883a
VZ
1011}
1012
d3a9f4af
RD
1013void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId,
1014 bool unselect_others,
88ac883a 1015 bool extended_select)
d3a9f4af 1016{
8b04a037
SB
1017 wxCHECK_RET( itemId.IsOk(), _T("invalid tree item") );
1018
88ac883a
VZ
1019 bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE);
1020
1021 //wxCHECK_RET( ( (!unselect_others) && is_single),
1022 // _T("this is a single selection tree") );
1023
1024 // to keep going anyhow !!!
d3a9f4af 1025 if (is_single)
88ac883a 1026 {
c0de7af4
PA
1027 unselect_others=TRUE;
1028 extended_select=FALSE;
88ac883a
VZ
1029 }
1030
1031 wxGenericTreeItem *item = itemId.m_pItem;
d3a9f4af 1032
f135ff73
VZ
1033 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
1034 event.m_item = item;
1035 event.m_itemOld = m_current;
1036 event.SetEventObject( this );
91b8de8d 1037 // TODO : Here we don't send any selection mode yet !
d3a9f4af 1038
6daa0637 1039 if ( GetEventHandler()->ProcessEvent( event ) && event.WasVetoed() )
f135ff73
VZ
1040 return;
1041
88ac883a
VZ
1042 // ctrl press
1043 if (unselect_others)
389cdc7a 1044 {
88ac883a
VZ
1045 if (is_single) Unselect(); // to speed up thing
1046 else UnselectAll();
edaa81ae 1047 }
f135ff73 1048
88ac883a 1049 // shift press
d3a9f4af 1050 if (extended_select)
88ac883a 1051 {
91b8de8d 1052 if (m_current == NULL) m_current=m_key_current=GetRootItem().m_pItem;
88ac883a
VZ
1053 // don't change the mark (m_current)
1054 SelectItemRange(m_current, item);
1055 }
1056 else
1057 {
c0de7af4 1058 bool select=TRUE; // the default
88ac883a
VZ
1059
1060 // Check if we need to toggle hilight (ctrl mode)
1061 if (!unselect_others)
1062 select=!item->HasHilight();
1063
91b8de8d 1064 m_current = m_key_current = item;
88ac883a
VZ
1065 m_current->SetHilight(select);
1066 RefreshLine( m_current );
1067 }
389cdc7a 1068
f135ff73 1069 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
6daa0637 1070 GetEventHandler()->ProcessEvent( event );
389cdc7a
VZ
1071}
1072
91b8de8d 1073void wxTreeCtrl::FillArray(wxGenericTreeItem *item, wxArrayTreeItemIds &array) const
c801d85f 1074{
91b8de8d
RR
1075 if (item->HasHilight()) array.Add(wxTreeItemId(item));
1076
1077 if (item->HasChildren())
1078 {
1079 wxArrayGenericTreeItems& children = item->GetChildren();
1080 size_t count = children.Count();
1081 for ( size_t n = 0; n < count; ++n )
1082 FillArray(children[n],array);
1083 }
1084}
1085
1086size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const
1087{
1088 array.Empty();
1089 FillArray(GetRootItem().m_pItem, array);
1090
1091 return array.Count();
1092}
1093
1094void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
d3a9f4af 1095{
91b8de8d
RR
1096 if (!item.IsOk()) return;
1097
0659e7ee 1098 wxGenericTreeItem *gitem = item.m_pItem;
ef44a621 1099
f65635b5
VZ
1100 // first expand all parent branches
1101 wxGenericTreeItem *parent = gitem->GetParent();
1102 while ( parent && !parent->IsExpanded() )
1103 {
1104 Expand(parent);
1105
1106 parent = parent->GetParent();
1107 }
1108
91b8de8d
RR
1109 if (parent) CalculatePositions();
1110
1111 ScrollTo(item);
1112}
1113
1114void wxTreeCtrl::ScrollTo(const wxTreeItemId &item)
1115{
1116 if (!item.IsOk()) return;
1117
1118 wxGenericTreeItem *gitem = item.m_pItem;
1119
f65635b5 1120 // now scroll to the item
0659e7ee 1121 int item_y = gitem->GetY();
ef44a621 1122
0659e7ee
RR
1123 int start_x = 0;
1124 int start_y = 0;
1125 ViewStart( &start_x, &start_y );
91b8de8d 1126 start_y *= PIXELS_PER_UNIT;
978f38c2 1127
a93109d5
RR
1128 int client_h = 0;
1129 int client_w = 0;
1130 GetClientSize( &client_w, &client_h );
ef44a621 1131
0659e7ee
RR
1132 if (item_y < start_y+3)
1133 {
91b8de8d 1134 // going down
0659e7ee
RR
1135 int x = 0;
1136 int y = 0;
91b8de8d
RR
1137 m_anchor->GetSize( x, y, this );
1138 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
0659e7ee 1139 int x_pos = GetScrollPos( wxHORIZONTAL );
91b8de8d
RR
1140 // Item should appear at top
1141 SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT );
0659e7ee 1142 }
91b8de8d 1143 else if (item_y+GetLineHeight(gitem) > start_y+client_h)
0659e7ee 1144 {
91b8de8d 1145 // going up
0659e7ee
RR
1146 int x = 0;
1147 int y = 0;
91b8de8d
RR
1148 m_anchor->GetSize( x, y, this );
1149 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
1150 item_y += PIXELS_PER_UNIT+2;
0659e7ee 1151 int x_pos = GetScrollPos( wxHORIZONTAL );
91b8de8d
RR
1152 // Item should appear at bottom
1153 SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT );
0659e7ee 1154 }
edaa81ae 1155}
c801d85f 1156
df875e59
RR
1157wxTextCtrl *wxTreeCtrl::EditLabel( const wxTreeItemId& WXUNUSED(item),
1158 wxClassInfo* WXUNUSED(textCtrlClass) )
c801d85f 1159{
87138c52 1160 wxFAIL_MSG(_T("not implemented"));
c801d85f 1161
bbe0af5b 1162 return (wxTextCtrl*)NULL;
edaa81ae 1163}
c801d85f 1164
f135ff73 1165wxTextCtrl *wxTreeCtrl::GetEditControl() const
c801d85f 1166{
87138c52 1167 wxFAIL_MSG(_T("not implemented"));
c801d85f 1168
0659e7ee 1169 return (wxTextCtrl*)NULL;
edaa81ae 1170}
c801d85f 1171
df875e59 1172void wxTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool WXUNUSED(discardChanges))
74bedbeb 1173{
87138c52 1174 wxFAIL_MSG(_T("not implemented"));
74bedbeb
VZ
1175}
1176
e1ee62bd
VZ
1177// FIXME: tree sorting functions are not reentrant and not MT-safe!
1178static wxTreeCtrl *s_treeBeingSorted = NULL;
0659e7ee 1179
e1ee62bd
VZ
1180static int tree_ctrl_compare_func(wxGenericTreeItem **item1,
1181 wxGenericTreeItem **item2)
edaa81ae 1182{
87138c52 1183 wxCHECK_MSG( s_treeBeingSorted, 0, _T("bug in wxTreeCtrl::SortChildren()") );
e1ee62bd
VZ
1184
1185 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
0659e7ee
RR
1186}
1187
e1ee62bd
VZ
1188int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
1189 const wxTreeItemId& item2)
0659e7ee 1190{
87138c52 1191 return wxStrcmp(GetItemText(item1), GetItemText(item2));
e1ee62bd
VZ
1192}
1193
1194void wxTreeCtrl::SortChildren(const wxTreeItemId& itemId)
1195{
87138c52 1196 wxCHECK_RET( itemId.IsOk(), _T("invalid tree item") );
e1ee62bd
VZ
1197
1198 wxGenericTreeItem *item = itemId.m_pItem;
978f38c2 1199
e1ee62bd 1200 wxCHECK_RET( !s_treeBeingSorted,
87138c52 1201 _T("wxTreeCtrl::SortChildren is not reentrant") );
e1ee62bd 1202
91b8de8d 1203 wxArrayGenericTreeItems& children = item->GetChildren();
e1ee62bd
VZ
1204 if ( children.Count() > 1 )
1205 {
1206 s_treeBeingSorted = this;
1207 children.Sort(tree_ctrl_compare_func);
1208 s_treeBeingSorted = NULL;
978f38c2 1209
e1ee62bd
VZ
1210 m_dirty = TRUE;
1211 }
1212 //else: don't make the tree dirty as nothing changed
edaa81ae
RR
1213}
1214
f135ff73 1215wxImageList *wxTreeCtrl::GetImageList() const
edaa81ae 1216{
f135ff73 1217 return m_imageListNormal;
edaa81ae
RR
1218}
1219
f135ff73 1220wxImageList *wxTreeCtrl::GetStateImageList() const
c801d85f 1221{
f135ff73 1222 return m_imageListState;
edaa81ae 1223}
c801d85f 1224
f135ff73 1225void wxTreeCtrl::SetImageList(wxImageList *imageList)
e2414cbe 1226{
d30b4d20 1227 m_imageListNormal = imageList;
91b8de8d
RR
1228
1229 // Calculate a m_lineHeight value from the image sizes.
1230 // May be toggle off. Then wxTreeCtrl will spread when
1231 // necessary (which might look ugly).
1232#if 1
d30b4d20 1233 wxPaintDC dc(this);
d30b4d20
KB
1234 m_lineHeight = (int)(dc.GetCharHeight() + 4);
1235 int
1236 width = 0,
1237 height = 0,
1238 n = m_imageListNormal->GetImageCount();
1239 for(int i = 0; i < n ; i++)
1240 {
1241 m_imageListNormal->GetSize(i, width, height);
1242 if(height > m_lineHeight) m_lineHeight = height;
d3a9f4af 1243 }
91b8de8d
RR
1244
1245 if (m_lineHeight<40) m_lineHeight+=4; // at least 4 pixels (odd such that a line can be drawn in between)
1246 else m_lineHeight+=m_lineHeight/10; // otherwise 10% extra spacing
1247
1248#endif
edaa81ae 1249}
e2414cbe 1250
f135ff73 1251void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
e2414cbe 1252{
f135ff73 1253 m_imageListState = imageList;
edaa81ae 1254}
e2414cbe 1255
f135ff73
VZ
1256// -----------------------------------------------------------------------------
1257// helpers
1258// -----------------------------------------------------------------------------
0659e7ee 1259
74bedbeb 1260void wxTreeCtrl::AdjustMyScrollbars()
c801d85f 1261{
0659e7ee
RR
1262 if (m_anchor)
1263 {
1264 int x = 0;
1265 int y = 0;
91b8de8d
RR
1266 m_anchor->GetSize( x, y, this );
1267 //y += GetLineHeight(m_anchor);
1268 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
0659e7ee
RR
1269 int x_pos = GetScrollPos( wxHORIZONTAL );
1270 int y_pos = GetScrollPos( wxVERTICAL );
91b8de8d 1271 SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, y_pos );
0659e7ee
RR
1272 }
1273 else
1274 {
1275 SetScrollbars( 0, 0, 0, 0 );
1276 }
edaa81ae 1277}
c801d85f 1278
91b8de8d
RR
1279int wxTreeCtrl::GetLineHeight(wxGenericTreeItem *item) const
1280{
1281 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HIGHT)
1282 return item->GetHeight();
1283 else
d3a9f4af 1284 return m_lineHeight;
91b8de8d
RR
1285}
1286
ef44a621
VZ
1287void wxTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
1288{
f65635b5 1289 // render bold items in bold
bbe0af5b
RR
1290 wxFont fontOld;
1291 wxFont fontNew;
978f38c2 1292
bbe0af5b
RR
1293 if (item->IsBold())
1294 {
1295 fontOld = dc.GetFont();
1296 if (fontOld.Ok())
1297 {
f65635b5 1298 // VZ: is there any better way to make a bold variant of old font?
bbe0af5b
RR
1299 fontNew = wxFont( fontOld.GetPointSize(),
1300 fontOld.GetFamily(),
1301 fontOld.GetStyle(),
1302 wxBOLD,
1303 fontOld.GetUnderlined());
1304 dc.SetFont(fontNew);
1305 }
1306 else
1307 {
87138c52 1308 wxFAIL_MSG(_T("wxDC::GetFont() failed!"));
bbe0af5b
RR
1309 }
1310 }
ef44a621 1311
bbe0af5b
RR
1312 long text_w = 0;
1313 long text_h = 0;
1314 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
ef44a621 1315
bbe0af5b
RR
1316 int image_h = 0;
1317 int image_w = 0;
1318 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1319 {
1320 m_imageListNormal->GetSize( item->GetSelectedImage(), image_w, image_h );
1321 image_w += 4;
978f38c2 1322 }
bbe0af5b
RR
1323 else if (item->GetImage() != -1)
1324 {
1325 m_imageListNormal->GetSize( item->GetImage(), image_w, image_h );
1326 image_w += 4;
1327 }
ef44a621 1328
91b8de8d
RR
1329 int total_h = GetLineHeight(item);
1330
1331 dc.DrawRectangle( item->GetX()-2, item->GetY(), item->GetWidth()+2, total_h );
ef44a621 1332
bbe0af5b
RR
1333 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1334 {
d30b4d20 1335 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, total_h );
bbe0af5b 1336 m_imageListNormal->Draw( item->GetSelectedImage(), dc,
49cd56ef 1337 item->GetX(),
d701d432 1338 item->GetY() +((total_h > image_h)?((total_h-image_h)/2):0),
bbe0af5b
RR
1339 wxIMAGELIST_DRAW_TRANSPARENT );
1340 dc.DestroyClippingRegion();
1341 }
1342 else if (item->GetImage() != -1)
1343 {
d30b4d20 1344 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, total_h );
bbe0af5b 1345 m_imageListNormal->Draw( item->GetImage(), dc,
49cd56ef 1346 item->GetX(),
d701d432 1347 item->GetY() +((total_h > image_h)?((total_h-image_h)/2):0),
bbe0af5b
RR
1348 wxIMAGELIST_DRAW_TRANSPARENT );
1349 dc.DestroyClippingRegion();
1350 }
ef44a621 1351
bbe0af5b 1352 dc.SetBackgroundMode(wxTRANSPARENT);
d30b4d20 1353 dc.DrawText( item->GetText(), image_w + item->GetX(), item->GetY()
49cd56ef 1354 + ((total_h > text_h) ? (total_h - text_h)/2 : 0));
ef44a621 1355
f65635b5 1356 // restore normal font for bold items
bbe0af5b
RR
1357 if (fontOld.Ok())
1358 {
1359 dc.SetFont( fontOld);
1360 }
ef44a621
VZ
1361}
1362
91b8de8d 1363// Now y stands for the top of the item, whereas it used to stand for middle !
16c1f7f3 1364void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 1365{
bbe0af5b 1366 int horizX = level*m_indent;
389cdc7a 1367
cf724bce 1368 item->SetX( horizX+m_indent+m_spacing );
91b8de8d 1369 item->SetY( y );
4c681997 1370
bbe0af5b 1371 int oldY = y;
91b8de8d
RR
1372 y+=GetLineHeight(item)/2;
1373
1374 item->SetCross( horizX+m_indent, y );
389cdc7a 1375
bbe0af5b
RR
1376 int exposed_x = dc.LogicalToDeviceX( 0 );
1377 int exposed_y = dc.LogicalToDeviceY( item->GetY()-2 );
4832f7c0 1378
91b8de8d 1379 if (IsExposed( exposed_x, exposed_y, 10000, GetLineHeight(item)+4 )) // 10000 = very much
bbe0af5b
RR
1380 {
1381 int startX = horizX;
cf724bce 1382 int endX = horizX + (m_indent-5);
29d87bba 1383
cf724bce 1384// if (!item->HasChildren()) endX += (m_indent+5);
bbe0af5b 1385 if (!item->HasChildren()) endX += 20;
4832f7c0 1386
bbe0af5b 1387 dc.DrawLine( startX, y, endX, y );
29d87bba 1388
bbe0af5b
RR
1389 if (item->HasPlus())
1390 {
cf724bce 1391 dc.DrawLine( horizX+(m_indent+5), y, horizX+(m_indent+15), y );
bbe0af5b
RR
1392 dc.SetPen( *wxGREY_PEN );
1393 dc.SetBrush( *wxWHITE_BRUSH );
cf724bce 1394 dc.DrawRectangle( horizX+(m_indent-5), y-4, 11, 9 );
112c5086 1395
bbe0af5b 1396 dc.SetPen( *wxBLACK_PEN );
cf724bce 1397 dc.DrawLine( horizX+(m_indent-2), y, horizX+(m_indent+3), y );
bbe0af5b 1398 if (!item->IsExpanded())
cf724bce 1399 dc.DrawLine( horizX+m_indent, y-2, horizX+m_indent, y+3 );
112c5086
RR
1400
1401 dc.SetPen( m_dottedPen );
bbe0af5b 1402 }
c801d85f 1403
bbe0af5b
RR
1404 if (item->HasHilight())
1405 {
1406 dc.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
a367b9b3 1407
bbe0af5b 1408 dc.SetBrush( *m_hilightBrush );
4832f7c0 1409
bbe0af5b
RR
1410 if (m_hasFocus)
1411 dc.SetPen( *wxBLACK_PEN );
1412 else
1413 dc.SetPen( *wxTRANSPARENT_PEN );
4832f7c0 1414
bbe0af5b 1415 PaintItem(item, dc);
f135ff73 1416
112c5086 1417 dc.SetPen( m_dottedPen );
bbe0af5b
RR
1418 dc.SetTextForeground( *wxBLACK );
1419 dc.SetBrush( *wxWHITE_BRUSH );
1420 }
1421 else
1422 {
1423 dc.SetBrush( *wxWHITE_BRUSH );
1424 dc.SetPen( *wxTRANSPARENT_PEN );
4832f7c0 1425
bbe0af5b 1426 PaintItem(item, dc);
4832f7c0 1427
112c5086 1428 dc.SetPen( m_dottedPen );
bbe0af5b 1429 }
f135ff73 1430 }
d3a9f4af 1431
91b8de8d 1432 y = oldY+GetLineHeight(item);
e2414cbe 1433
bbe0af5b
RR
1434 if (item->IsExpanded())
1435 {
91b8de8d
RR
1436 oldY+=GetLineHeight(item)/2;
1437 int semiOldY=y; // (=y) for stupid compilator
389cdc7a 1438
91b8de8d
RR
1439 wxArrayGenericTreeItems& children = item->GetChildren();
1440 size_t n, count = children.Count();
1441 for ( n = 0; n < count; ++n )
1442 {
1443 semiOldY=y;
1444 PaintLevel( children[n], dc, level+1, y );
1445 }
389cdc7a 1446
f65635b5
VZ
1447 // it may happen that the item is expanded but has no items (when you
1448 // delete all its children for example) - don't draw the vertical line
1449 // in this case
1450 if (count > 0)
91b8de8d
RR
1451 {
1452 semiOldY+=GetLineHeight(children[--n])/2;
cf724bce 1453 dc.DrawLine( horizX+m_indent, oldY+5, horizX+m_indent, semiOldY );
91b8de8d 1454 }
bbe0af5b 1455 }
4c681997 1456}
c801d85f 1457
91b8de8d
RR
1458void wxTreeCtrl::DrawBorder(wxTreeItemId &item)
1459{
1460 if (!item) return;
1461
1462 wxGenericTreeItem *i=item.m_pItem;
1463
1464 wxPaintDC dc(this);
1465 PrepareDC( dc );
1466 dc.SetLogicalFunction(wxINVERT);
1467
1468 int w,h,x;
1469 ViewStart(&x,&h); // we only need x
1470 GetClientSize(&w,&h); // we only need w
1471
1472 h=GetLineHeight(i)+1;
1473 // 2 white column at border
1474 dc.DrawRectangle( PIXELS_PER_UNIT*x+2, i->GetY()-1, w-6, h);
1475}
1476
1477void wxTreeCtrl::DrawLine(wxTreeItemId &item, bool below)
1478{
1479 if (!item) return;
1480
1481 wxGenericTreeItem *i=item.m_pItem;
1482
1483 wxPaintDC dc(this);
1484 PrepareDC( dc );
1485 dc.SetLogicalFunction(wxINVERT);
d3a9f4af 1486
91b8de8d
RR
1487 int w,h,y;
1488 GetSize(&w,&h);
1489
1490 if (below) y=i->GetY()+GetLineHeight(i)-1;
1491 else y=i->GetY();
1492
1493 dc.DrawLine( 0, y, w, y);
1494}
1495
f135ff73
VZ
1496// -----------------------------------------------------------------------------
1497// wxWindows callbacks
1498// -----------------------------------------------------------------------------
1499
3db7be80 1500void wxTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
c801d85f 1501{
91b8de8d 1502 if ( !m_anchor)
0659e7ee 1503 return;
c801d85f 1504
0659e7ee
RR
1505 wxPaintDC dc(this);
1506 PrepareDC( dc );
29d87bba 1507
f60d0f94 1508 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) );
29d87bba 1509
0659e7ee 1510 dc.SetPen( m_dottedPen );
91b8de8d
RR
1511 //if(GetImageList() == NULL)
1512 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1513
91b8de8d 1514 int y = 2;
0659e7ee 1515 PaintLevel( m_anchor, dc, 0, y );
edaa81ae 1516}
c801d85f 1517
3db7be80 1518void wxTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1519{
0659e7ee 1520 m_hasFocus = TRUE;
978f38c2 1521
bbe0af5b 1522 if (m_current) RefreshLine( m_current );
edaa81ae 1523}
c801d85f 1524
3db7be80 1525void wxTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1526{
0659e7ee 1527 m_hasFocus = FALSE;
978f38c2 1528
bbe0af5b 1529 if (m_current) RefreshLine( m_current );
edaa81ae 1530}
c801d85f
KB
1531
1532void wxTreeCtrl::OnChar( wxKeyEvent &event )
1533{
978f38c2
VZ
1534 wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
1535 te.m_code = event.KeyCode();
1536 te.SetEventObject( this );
1537 GetEventHandler()->ProcessEvent( te );
435fe83e 1538
91b8de8d 1539 if ( (m_current == 0) || (m_key_current == 0) )
978f38c2
VZ
1540 {
1541 event.Skip();
1542 return;
1543 }
ef44a621 1544
88ac883a
VZ
1545 bool is_multiple=(GetWindowStyleFlag() & wxTR_MULTIPLE);
1546 bool extended_select=(event.ShiftDown() && is_multiple);
1547 bool unselect_others=!(extended_select || (event.ControlDown() && is_multiple));
1548
978f38c2
VZ
1549 switch (event.KeyCode())
1550 {
1551 case '+':
1552 case WXK_ADD:
1553 if (m_current->HasPlus() && !IsExpanded(m_current))
1554 {
1555 Expand(m_current);
1556 }
1557 break;
ef44a621 1558
978f38c2
VZ
1559 case '-':
1560 case WXK_SUBTRACT:
1561 if (IsExpanded(m_current))
1562 {
1563 Collapse(m_current);
1564 }
1565 break;
ef44a621 1566
978f38c2
VZ
1567 case '*':
1568 case WXK_MULTIPLY:
1569 Toggle(m_current);
1570 break;
ef44a621 1571
978f38c2
VZ
1572 case ' ':
1573 case WXK_RETURN:
1574 {
1575 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
1576 event.m_item = m_current;
1577 event.m_code = 0;
1578 event.SetEventObject( this );
1579 GetEventHandler()->ProcessEvent( event );
1580 }
1581 break;
ef44a621 1582
978f38c2
VZ
1583 // up goes to the previous sibling or to the last of its children if
1584 // it's expanded
1585 case WXK_UP:
1586 {
91b8de8d 1587 wxTreeItemId prev = GetPrevSibling( m_key_current );
978f38c2
VZ
1588 if (!prev)
1589 {
91b8de8d 1590 prev = GetParent( m_key_current );
90e58684
RR
1591 if (prev)
1592 {
1593 long cockie = 0;
91b8de8d 1594 wxTreeItemId current = m_key_current;
90e58684
RR
1595 if (current == GetFirstChild( prev, cockie ))
1596 {
1597 // otherwise we return to where we came from
88ac883a 1598 SelectItem( prev, unselect_others, extended_select );
91b8de8d
RR
1599 m_key_current=prev.m_pItem;
1600 EnsureVisible( prev );
90e58684
RR
1601 break;
1602 }
978f38c2
VZ
1603 }
1604 }
1605 if (prev)
1606 {
69a282d4 1607 while ( IsExpanded(prev) && HasChildren(prev) )
978f38c2 1608 {
69a282d4
VZ
1609 wxTreeItemId child = GetLastChild(prev);
1610 if ( child )
1611 {
1612 prev = child;
1613 }
978f38c2 1614 }
69a282d4 1615
88ac883a 1616 SelectItem( prev, unselect_others, extended_select );
91b8de8d 1617 m_key_current=prev.m_pItem;
978f38c2
VZ
1618 EnsureVisible( prev );
1619 }
1620 }
1621 break;
ef44a621 1622
978f38c2
VZ
1623 // left arrow goes to the parent
1624 case WXK_LEFT:
1625 {
1626 wxTreeItemId prev = GetParent( m_current );
1627 if (prev)
1628 {
1629 EnsureVisible( prev );
88ac883a 1630 SelectItem( prev, unselect_others, extended_select );
978f38c2
VZ
1631 }
1632 }
1633 break;
ef44a621 1634
978f38c2
VZ
1635 case WXK_RIGHT:
1636 // this works the same as the down arrow except that we also expand the
1637 // item if it wasn't expanded yet
1638 Expand(m_current);
1639 // fall through
1640
1641 case WXK_DOWN:
ef44a621 1642 {
91b8de8d 1643 if (IsExpanded(m_key_current) && HasChildren(m_key_current))
978f38c2
VZ
1644 {
1645 long cookie = 0;
91b8de8d 1646 wxTreeItemId child = GetFirstChild( m_key_current, cookie );
88ac883a 1647 SelectItem( child, unselect_others, extended_select );
91b8de8d 1648 m_key_current=child.m_pItem;
978f38c2
VZ
1649 EnsureVisible( child );
1650 }
1651 else
1652 {
91b8de8d 1653 wxTreeItemId next = GetNextSibling( m_key_current );
b62c3631
RR
1654// if (next == 0)
1655 if (!next)
978f38c2 1656 {
91b8de8d 1657 wxTreeItemId current = m_key_current;
978f38c2
VZ
1658 while (current && !next)
1659 {
1660 current = GetParent( current );
1661 if (current) next = GetNextSibling( current );
1662 }
1663 }
b62c3631
RR
1664// if (next != 0)
1665 if (next)
978f38c2 1666 {
88ac883a 1667 SelectItem( next, unselect_others, extended_select );
91b8de8d 1668 m_key_current=next.m_pItem;
978f38c2
VZ
1669 EnsureVisible( next );
1670 }
1671 }
ef44a621 1672 }
978f38c2 1673 break;
ef44a621 1674
978f38c2
VZ
1675 // <End> selects the last visible tree item
1676 case WXK_END:
1677 {
1678 wxTreeItemId last = GetRootItem();
1679
1680 while ( last.IsOk() && IsExpanded(last) )
1681 {
1682 wxTreeItemId lastChild = GetLastChild(last);
1683
1684 // it may happen if the item was expanded but then all of
1685 // its children have been deleted - so IsExpanded() returned
1686 // TRUE, but GetLastChild() returned invalid item
1687 if ( !lastChild )
1688 break;
1689
1690 last = lastChild;
1691 }
1692
1693 if ( last.IsOk() )
1694 {
1695 EnsureVisible( last );
88ac883a 1696 SelectItem( last, unselect_others, extended_select );
978f38c2
VZ
1697 }
1698 }
1699 break;
1700
1701 // <Home> selects the root item
1702 case WXK_HOME:
1703 {
1704 wxTreeItemId prev = GetRootItem();
1705 if (prev)
1706 {
1707 EnsureVisible( prev );
88ac883a 1708 SelectItem( prev, unselect_others, extended_select );
978f38c2
VZ
1709 }
1710 }
1711 break;
1712
1713 default:
1714 event.Skip();
1715 }
edaa81ae 1716}
c801d85f 1717
91b8de8d 1718wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
4f22cf8d 1719{
67a7abf7
VZ
1720 wxClientDC dc(this);
1721 PrepareDC(dc);
1722 long x = dc.DeviceToLogicalX( (long)point.x );
1723 long y = dc.DeviceToLogicalY( (long)point.y );
91b8de8d
RR
1724 int w, h;
1725 GetSize(&w, &h);
1726
1727 flags=0;
1728 if (point.x<0) flags|=wxTREE_HITTEST_TOLEFT;
1729 if (point.x>w) flags|=wxTREE_HITTEST_TORIGHT;
1730 if (point.y<0) flags|=wxTREE_HITTEST_ABOVE;
1731 if (point.y>h) flags|=wxTREE_HITTEST_BELOW;
d3a9f4af 1732
91b8de8d 1733 return m_anchor->HitTest( wxPoint(x, y), this, flags);
4f22cf8d
RR
1734}
1735
3db7be80 1736void wxTreeCtrl::OnMouse( wxMouseEvent &event )
c801d85f 1737{
bbe0af5b 1738 if (!event.LeftIsDown()) m_dragCount = 0;
f135ff73 1739
91b8de8d 1740 if ( !(event.LeftUp() || event.LeftDClick() || event.Dragging()) ) return;
29d87bba 1741
bbe0af5b 1742 if ( !m_anchor ) return;
978f38c2 1743
bbe0af5b
RR
1744 wxClientDC dc(this);
1745 PrepareDC(dc);
1746 long x = dc.DeviceToLogicalX( (long)event.GetX() );
1747 long y = dc.DeviceToLogicalY( (long)event.GetY() );
29d87bba 1748
91b8de8d
RR
1749 int flags=0;
1750 wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), this, flags);
1751 bool onButton = flags & wxTREE_HITTEST_ONITEMBUTTON;
978f38c2 1752
bbe0af5b 1753 if (item == NULL) return; /* we hit the blank area */
29d87bba 1754
bbe0af5b
RR
1755 if (event.Dragging())
1756 {
1757 if (m_dragCount == 2) /* small drag latency (3?) */
1758 {
1759 m_dragCount = 0;
978f38c2 1760
bbe0af5b
RR
1761 wxTreeEvent nevent(wxEVT_COMMAND_TREE_BEGIN_DRAG, GetId());
1762 nevent.m_item = m_current;
1763 nevent.SetEventObject(this);
1764 GetEventHandler()->ProcessEvent(nevent);
1765 }
1766 else
1767 {
1768 m_dragCount++;
1769 }
1770 return;
1771 }
978f38c2 1772
88ac883a
VZ
1773 bool is_multiple=(GetWindowStyleFlag() & wxTR_MULTIPLE);
1774 bool extended_select=(event.ShiftDown() && is_multiple);
1775 bool unselect_others=!(extended_select || (event.ControlDown() && is_multiple));
1776
91b8de8d
RR
1777 if (onButton)
1778 {
1779 Toggle( item );
1780 if (is_multiple) return;
1781 }
1782
88ac883a 1783 SelectItem(item, unselect_others, extended_select);
29d87bba 1784
bbe0af5b
RR
1785 if (event.LeftDClick())
1786 {
1787 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
1788 event.m_item = item;
1789 event.m_code = 0;
1790 event.SetEventObject( this );
1791 GetEventHandler()->ProcessEvent( event );
1792 }
edaa81ae 1793}
c801d85f 1794
3db7be80
RR
1795void wxTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
1796{
bbe0af5b
RR
1797 /* after all changes have been done to the tree control,
1798 * we actually redraw the tree when everything is over */
ef44a621 1799
f65635b5
VZ
1800 if (!m_dirty)
1801 return;
ef44a621 1802
bbe0af5b 1803 m_dirty = FALSE;
3db7be80 1804
bbe0af5b 1805 CalculatePositions();
91b8de8d 1806 Refresh();
bbe0af5b 1807 AdjustMyScrollbars();
3db7be80
RR
1808}
1809
91b8de8d 1810void wxTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
d3a9f4af 1811{
91b8de8d
RR
1812 long text_w = 0;
1813 long text_h = 0;
1814 // TODO : check for boldness. Here with suppose that font normal and bold
1815 // have the same height !
1816 // TODO : bug here, text_w is sometime not the correct answer !!!
1817 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
1818 text_h+=4;
1819
1820 int image_h = 0;
1821 int image_w = 0;
1822 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1823 {
1824 m_imageListNormal->GetSize( item->GetSelectedImage(), image_w, image_h );
1825 image_w += 4;
1826 }
1827 else if (item->GetImage() != -1)
1828 {
1829 m_imageListNormal->GetSize( item->GetImage(), image_w, image_h );
1830 image_w += 4;
1831 }
1832
1833 int total_h = (image_h > text_h) ? image_h : text_h;
1834
1835 if (total_h<40) total_h+=4; // at least 4 pixels
1836 else total_h+=total_h/10; // otherwise 10% extra spacing
1837
1838 item->SetHeight(total_h);
1839 if (total_h>m_lineHeight) m_lineHeight=total_h;
bbe0af5b 1840
91b8de8d
RR
1841 item->SetWidth(image_w+text_w+2);
1842}
1843
1844// -----------------------------------------------------------------------------
1845// for developper : y is now the top of the level
1846// not the middle of it !
bbe0af5b 1847void wxTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 1848{
bbe0af5b 1849 int horizX = level*m_indent;
389cdc7a 1850
91b8de8d 1851 CalculateSize( item, dc );
d3a9f4af 1852
91b8de8d 1853 // set its position
cf724bce 1854 item->SetX( horizX+m_indent+m_spacing );
91b8de8d
RR
1855 item->SetY( y );
1856 y+=GetLineHeight(item);
4c681997 1857
bbe0af5b
RR
1858 if ( !item->IsExpanded() )
1859 {
f65635b5 1860 // we dont need to calculate collapsed branches
bbe0af5b
RR
1861 return;
1862 }
389cdc7a 1863
91b8de8d
RR
1864 wxArrayGenericTreeItems& children = item->GetChildren();
1865 size_t n, count = children.Count();
1866 for (n = 0; n < count; ++n )
1867 CalculateLevel( children[n], dc, level+1, y ); // recurse
edaa81ae 1868}
c801d85f 1869
74bedbeb 1870void wxTreeCtrl::CalculatePositions()
c801d85f 1871{
bbe0af5b 1872 if ( !m_anchor ) return;
29d87bba 1873
bbe0af5b
RR
1874 wxClientDC dc(this);
1875 PrepareDC( dc );
29d87bba 1876
bbe0af5b 1877 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) );
29d87bba 1878
bbe0af5b 1879 dc.SetPen( m_dottedPen );
91b8de8d
RR
1880 //if(GetImageList() == NULL)
1881 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1882
91b8de8d 1883 int y = 2; //GetLineHeight(m_anchor) / 2 + 2;
f65635b5 1884 CalculateLevel( m_anchor, dc, 0, y ); // start recursion
edaa81ae 1885}
c801d85f 1886
f135ff73 1887void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
c801d85f 1888{
bbe0af5b
RR
1889 wxClientDC dc(this);
1890 PrepareDC(dc);
4832f7c0 1891
bbe0af5b
RR
1892 int cw = 0;
1893 int ch = 0;
1894 GetClientSize( &cw, &ch );
4832f7c0 1895
bbe0af5b
RR
1896 wxRect rect;
1897 rect.x = dc.LogicalToDeviceX( 0 );
1898 rect.width = cw;
1899 rect.y = dc.LogicalToDeviceY( item->GetY() );
1900 rect.height = ch;
f135ff73 1901
bbe0af5b 1902 Refresh( TRUE, &rect );
f135ff73 1903
bbe0af5b 1904 AdjustMyScrollbars();
edaa81ae 1905}
c801d85f
KB
1906
1907void wxTreeCtrl::RefreshLine( wxGenericTreeItem *item )
1908{
bbe0af5b
RR
1909 wxClientDC dc(this);
1910 PrepareDC( dc );
1911
1912 wxRect rect;
1913 rect.x = dc.LogicalToDeviceX( item->GetX() - 2 );
91b8de8d 1914 rect.y = dc.LogicalToDeviceY( item->GetY());
bbe0af5b 1915 rect.width = 1000;
91b8de8d 1916 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
978f38c2 1917
bbe0af5b 1918 Refresh( TRUE, &rect );
edaa81ae 1919}
c801d85f 1920