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