]> git.saurik.com Git - wxWidgets.git/blame - src/generic/treectrl.cpp
Added Property List classes to main library; added proplist sample; merged
[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"
37#include "wx/dcclient.h"
0659e7ee 38#include "wx/msgdlg.h"
c801d85f 39
f135ff73
VZ
40// -----------------------------------------------------------------------------
41// array types
42// -----------------------------------------------------------------------------
c801d85f 43
1e6d9499
JS
44class WXDLLEXPORT wxGenericTreeItem;
45
f135ff73 46WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayTreeItems);
c801d85f 47
f135ff73
VZ
48// -----------------------------------------------------------------------------
49// private classes
50// -----------------------------------------------------------------------------
51
52// a tree item
53class WXDLLEXPORT wxGenericTreeItem
c801d85f 54{
f135ff73
VZ
55public:
56 // ctors & dtor
57 wxGenericTreeItem() { m_data = NULL; }
58 wxGenericTreeItem( wxGenericTreeItem *parent,
59 const wxString& text,
60 wxDC& dc,
61 int image, int selImage,
62 wxTreeItemData *data );
63
ff5bf259 64 ~wxGenericTreeItem();
f135ff73
VZ
65
66 // trivial accessors
67 wxArrayTreeItems& GetChildren() { return m_children; }
68
69 const wxString& GetText() const { return m_text; }
70 int GetImage() const { return m_image; }
71 int GetSelectedImage() const { return m_selImage; }
72 wxTreeItemData *GetData() const { return m_data; }
73
74 void SetText( const wxString &text, wxDC& dc );
75 void SetImage(int image) { m_image = image; }
76 void SetSelectedImage(int image) { m_selImage = image; }
77 void SetData(wxTreeItemData *data) { m_data = data; }
78
79 void SetHasPlus(bool has = TRUE) { m_hasPlus = has; }
80
ef44a621
VZ
81 void SetBold(bool bold) { m_isBold = bold; }
82
f135ff73
VZ
83 int GetX() const { return m_x; }
84 int GetY() const { return m_y; }
85
86 void SetHeight(int h) { m_height = h; }
87
88 void SetX(int x) { m_x = x; }
89 void SetY(int y) { m_y = y; }
90
91 wxGenericTreeItem *GetParent() const { return m_parent; }
c801d85f 92
f135ff73 93 // operations
a43a4f9d
VZ
94 // deletes all children notifying the treectrl about it if !NULL pointer
95 // given
96 void DeleteChildren(wxTreeCtrl *tree = NULL);
97 // FIXME don't know what is it for
f135ff73
VZ
98 void Reset();
99
4832f7c0
VZ
100 // get count of all children (and grand children if 'recursively')
101 size_t GetChildrenCount(bool recursively = TRUE) const;
f135ff73
VZ
102
103 void Insert(wxGenericTreeItem *child, size_t index)
104 { m_children.Insert(child, index); }
105
106 void SetCross( int x, int y );
107 void GetSize( int &x, int &y );
108
109 // return the item at given position (or NULL if no item), onButton is TRUE
110 // if the point belongs to the item's button, otherwise it lies on the
111 // button's label
112 wxGenericTreeItem *HitTest( const wxPoint& point, bool &onButton );
113
114 void Expand() { m_isCollapsed = FALSE; }
115 void Collapse() { m_isCollapsed = TRUE; }
116
117 void SetHilight( bool set = TRUE ) { m_hasHilight = set; }
118
119 // status inquiries
120 bool HasChildren() const { return !m_children.IsEmpty(); }
121 bool HasHilight() const { return m_hasHilight; }
122 bool IsExpanded() const { return !m_isCollapsed; }
123 bool HasPlus() const { return m_hasPlus || HasChildren(); }
ef44a621 124 bool IsBold() const { return m_isBold; }
f135ff73
VZ
125
126private:
127 wxString m_text;
128
129 int m_image,
130 m_selImage;
131
132 wxTreeItemData *m_data;
4832f7c0 133
ef44a621
VZ
134 // use bitfields to save size
135 int m_isCollapsed :1;
136 int m_hasHilight :1; // same as focused
137 int m_hasPlus :1; // used for item which doesn't have
138 // children but still has a [+] button
139 int m_isBold :1; // render the label in bold font
f135ff73
VZ
140
141 int m_x, m_y;
142 long m_height, m_width;
143 int m_xCross, m_yCross;
144 int m_level;
145 wxArrayTreeItems m_children;
146 wxGenericTreeItem *m_parent;
147};
148
149// =============================================================================
150// implementation
151// =============================================================================
152
153// -----------------------------------------------------------------------------
c801d85f 154// wxTreeEvent
f135ff73 155// -----------------------------------------------------------------------------
c801d85f 156
92976ab6 157IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
c801d85f 158
f135ff73 159wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
92976ab6 160 : wxNotifyEvent( commandType, id )
c801d85f
KB
161{
162 m_code = 0;
f135ff73 163 m_itemOld = (wxGenericTreeItem *)NULL;
edaa81ae 164}
c801d85f 165
f135ff73 166// -----------------------------------------------------------------------------
c801d85f 167// wxGenericTreeItem
f135ff73 168// -----------------------------------------------------------------------------
c801d85f 169
f135ff73
VZ
170wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
171 const wxString& text,
172 wxDC& dc,
173 int image, int selImage,
174 wxTreeItemData *data)
175 : m_text(text)
c801d85f 176{
f135ff73
VZ
177 m_image = image;
178 m_selImage = selImage;
179 m_data = data;
180 m_x = m_y = 0;
181 m_xCross = m_yCross = 0;
182
183 m_level = 0;
184
185 m_isCollapsed = TRUE;
c801d85f 186 m_hasHilight = FALSE;
df875e59 187 m_hasPlus = FALSE;
ef44a621 188 m_isBold = FALSE;
c801d85f 189
c801d85f 190 m_parent = parent;
f135ff73
VZ
191
192 dc.GetTextExtent( m_text, &m_width, &m_height );
edaa81ae 193}
c801d85f 194
f135ff73 195wxGenericTreeItem::~wxGenericTreeItem()
c801d85f 196{
f135ff73 197 delete m_data;
4832f7c0 198
a43a4f9d
VZ
199 wxASSERT_MSG( m_children.IsEmpty(),
200 "please call DeleteChildren() before deleting the item" );
372edb9d
VZ
201}
202
a43a4f9d 203void wxGenericTreeItem::DeleteChildren(wxTreeCtrl *tree)
372edb9d 204{
f135ff73
VZ
205 size_t count = m_children.Count();
206 for ( size_t n = 0; n < count; n++ )
a43a4f9d
VZ
207 {
208 wxGenericTreeItem *child = m_children[n];
209 if ( tree )
210 {
211 tree->SendDeleteEvent(child);
212 }
213
214 child->DeleteChildren(tree);
215 delete child;
216 }
372edb9d
VZ
217
218 m_children.Empty();
edaa81ae 219}
c801d85f 220
f135ff73 221void wxGenericTreeItem::SetText( const wxString &text, wxDC& dc )
c801d85f
KB
222{
223 m_text = text;
f135ff73
VZ
224
225 dc.GetTextExtent( m_text, &m_width, &m_height );
edaa81ae 226}
c801d85f 227
74bedbeb 228void wxGenericTreeItem::Reset()
c801d85f 229{
f135ff73
VZ
230 m_text.Empty();
231 m_image =
232 m_selImage = -1;
233 m_data = NULL;
234 m_x = m_y =
235 m_height = m_width = 0;
236 m_xCross =
c801d85f 237 m_yCross = 0;
74bedbeb 238
f135ff73 239 m_level = 0;
c801d85f 240
372edb9d 241 DeleteChildren();
f135ff73 242 m_isCollapsed = TRUE;
c801d85f 243
f135ff73 244 m_parent = (wxGenericTreeItem *)NULL;
edaa81ae 245}
c801d85f 246
4832f7c0 247size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
c801d85f 248{
f135ff73 249 size_t count = m_children.Count();
4832f7c0
VZ
250 if ( !recursively )
251 return count;
252
f135ff73
VZ
253 size_t total = count;
254 for ( size_t n = 0; n < count; n++ )
c801d85f 255 {
4832f7c0 256 total += m_children[n]->GetChildrenCount();
edaa81ae 257 }
c801d85f 258
f135ff73 259 return total;
edaa81ae 260}
c801d85f
KB
261
262void wxGenericTreeItem::SetCross( int x, int y )
263{
264 m_xCross = x;
265 m_yCross = y;
edaa81ae 266}
c801d85f
KB
267
268void wxGenericTreeItem::GetSize( int &x, int &y )
269{
df875e59 270 if ( y < m_y ) y = m_y;
c801d85f
KB
271 int width = m_x + m_width;
272 if (width > x) x = width;
f135ff73 273
df875e59 274 if (IsExpanded())
c801d85f 275 {
df875e59
RR
276 size_t count = m_children.Count();
277 for ( size_t n = 0; n < count; n++ )
4832f7c0 278 {
df875e59
RR
279 m_children[n]->GetSize( x, y );
280 }
edaa81ae
RR
281 }
282}
c801d85f 283
f135ff73
VZ
284wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point,
285 bool &onButton )
c801d85f 286{
f135ff73 287 if ((point.y > m_y) && (point.y < m_y + m_height))
c801d85f 288 {
f135ff73
VZ
289 // FIXME why +5?
290 if ((point.x > m_xCross-5) && (point.x < m_xCross+5) &&
291 (point.y > m_yCross-5) && (point.y < m_yCross+5) &&
f9f950fc 292 (IsExpanded() || HasPlus()))
c801d85f 293 {
f135ff73
VZ
294 onButton = TRUE;
295 return this;
edaa81ae 296 }
a93109d5
RR
297
298 int w = m_width;
299 if (m_image != -1) w += 20;
f135ff73 300
a93109d5 301 if ((point.x > m_x) && (point.x < m_x+w))
c801d85f 302 {
f135ff73
VZ
303 onButton = FALSE;
304 return this;
edaa81ae 305 }
c801d85f
KB
306 }
307 else
308 {
e2414cbe 309 if (!m_isCollapsed)
c801d85f 310 {
f135ff73
VZ
311 size_t count = m_children.Count();
312 for ( size_t n = 0; n < count; n++ )
e2414cbe 313 {
f135ff73
VZ
314 wxGenericTreeItem *res = m_children[n]->HitTest( point, onButton );
315 if ( res != NULL )
316 return res;
edaa81ae
RR
317 }
318 }
319 }
f135ff73
VZ
320
321 return NULL;
edaa81ae 322}
c801d85f 323
f135ff73
VZ
324// -----------------------------------------------------------------------------
325// wxTreeCtrl implementation
326// -----------------------------------------------------------------------------
327
328IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxScrolledWindow)
329
330BEGIN_EVENT_TABLE(wxTreeCtrl,wxScrolledWindow)
331 EVT_PAINT (wxTreeCtrl::OnPaint)
332 EVT_MOUSE_EVENTS (wxTreeCtrl::OnMouse)
333 EVT_CHAR (wxTreeCtrl::OnChar)
334 EVT_SET_FOCUS (wxTreeCtrl::OnSetFocus)
335 EVT_KILL_FOCUS (wxTreeCtrl::OnKillFocus)
3db7be80 336 EVT_IDLE (wxTreeCtrl::OnIdle)
f135ff73
VZ
337END_EVENT_TABLE()
338
339// -----------------------------------------------------------------------------
340// construction/destruction
341// -----------------------------------------------------------------------------
342void wxTreeCtrl::Init()
c801d85f 343{
f135ff73
VZ
344 m_current =
345 m_anchor = (wxGenericTreeItem *) NULL;
346 m_hasFocus = FALSE;
3db7be80 347 m_dirty = FALSE;
f135ff73
VZ
348
349 m_xScroll = 0;
350 m_yScroll = 0;
351 m_lineHeight = 10;
352 m_indent = 15;
353
354 m_hilightBrush = new wxBrush
355 (
356 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT),
357 wxSOLID
358 );
359
360 m_imageListNormal =
361 m_imageListState = (wxImageList *) NULL;
edaa81ae 362}
c801d85f 363
f135ff73
VZ
364bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
365 const wxPoint& pos, const wxSize& size,
4f22cf8d
RR
366 long style,
367 const wxValidator &validator,
368 const wxString& name )
c801d85f 369{
f135ff73
VZ
370 Init();
371
a367b9b3 372 wxScrolledWindow::Create( parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name );
4f22cf8d
RR
373
374 SetValidator( validator );
f135ff73
VZ
375
376 SetBackgroundColour( *wxWHITE );
377 m_dottedPen = wxPen( *wxBLACK, 0, 0 );
378
379 return TRUE;
edaa81ae 380}
c801d85f 381
f135ff73 382wxTreeCtrl::~wxTreeCtrl()
c801d85f 383{
f135ff73 384 wxDELETE( m_hilightBrush );
a43a4f9d
VZ
385
386 DeleteAllItems();
edaa81ae 387}
c801d85f 388
f135ff73
VZ
389// -----------------------------------------------------------------------------
390// accessors
391// -----------------------------------------------------------------------------
392
393size_t wxTreeCtrl::GetCount() const
c801d85f 394{
4832f7c0 395 return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount();
edaa81ae 396}
c801d85f 397
f135ff73 398void wxTreeCtrl::SetIndent(unsigned int indent)
c801d85f 399{
f135ff73
VZ
400 m_indent = indent;
401 Refresh();
402}
74bedbeb 403
4832f7c0
VZ
404size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
405{
406 wxCHECK_MSG( item.IsOk(), 0u, "invalid tree item" );
407
408 return item.m_pItem->GetChildrenCount(recursively);
409}
410
f135ff73
VZ
411// -----------------------------------------------------------------------------
412// functions to work with tree items
413// -----------------------------------------------------------------------------
74bedbeb 414
f135ff73
VZ
415wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
416{
4832f7c0
VZ
417 wxCHECK_MSG( item.IsOk(), "", "invalid tree item" );
418
f135ff73 419 return item.m_pItem->GetText();
edaa81ae 420}
74bedbeb 421
f135ff73 422int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
74bedbeb 423{
4832f7c0
VZ
424 wxCHECK_MSG( item.IsOk(), -1, "invalid tree item" );
425
f135ff73 426 return item.m_pItem->GetImage();
edaa81ae 427}
c801d85f 428
f135ff73 429int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
c801d85f 430{
4832f7c0
VZ
431 wxCHECK_MSG( item.IsOk(), -1, "invalid tree item" );
432
f135ff73 433 return item.m_pItem->GetSelectedImage();
edaa81ae 434}
c801d85f 435
f135ff73 436wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
c801d85f 437{
4832f7c0
VZ
438 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
439
f135ff73 440 return item.m_pItem->GetData();
edaa81ae 441}
c801d85f 442
f135ff73
VZ
443void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
444{
4832f7c0
VZ
445 wxCHECK_RET( item.IsOk(), "invalid tree item" );
446
f135ff73 447 wxClientDC dc(this);
de646ed1 448 item.m_pItem->SetText(text, dc);
f135ff73 449}
c801d85f 450
f135ff73
VZ
451void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
452{
4832f7c0
VZ
453 wxCHECK_RET( item.IsOk(), "invalid tree item" );
454
de646ed1 455 item.m_pItem->SetImage(image);
f135ff73 456}
c801d85f 457
f135ff73 458void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
c801d85f 459{
4832f7c0
VZ
460 wxCHECK_RET( item.IsOk(), "invalid tree item" );
461
de646ed1 462 item.m_pItem->SetSelectedImage(image);
edaa81ae 463}
c801d85f 464
f135ff73 465void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
c801d85f 466{
4832f7c0
VZ
467 wxCHECK_RET( item.IsOk(), "invalid tree item" );
468
de646ed1 469 item.m_pItem->SetData(data);
edaa81ae 470}
c801d85f 471
f135ff73 472void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
c801d85f 473{
4832f7c0
VZ
474 wxCHECK_RET( item.IsOk(), "invalid tree item" );
475
f135ff73 476 item.m_pItem->SetHasPlus(has);
edaa81ae 477}
c801d85f 478
ef44a621
VZ
479void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
480{
481 wxCHECK_RET( item.IsOk(), "invalid tree item" );
482
483 // avoid redrawing the tree if no real change
484 wxGenericTreeItem *pItem = item.m_pItem;
485 if ( pItem->IsBold() != bold )
486 {
487 pItem->SetBold(bold);
488 RefreshLine(pItem);
489 }
490}
491
f135ff73
VZ
492// -----------------------------------------------------------------------------
493// item status inquiries
494// -----------------------------------------------------------------------------
495
df875e59 496bool wxTreeCtrl::IsVisible(const wxTreeItemId& WXUNUSED(item)) const
c801d85f 497{
f135ff73
VZ
498 wxFAIL_MSG("not implemented");
499
c801d85f 500 return TRUE;
edaa81ae 501}
c801d85f 502
f135ff73 503bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
c801d85f 504{
4832f7c0
VZ
505 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
506
f135ff73 507 return !item.m_pItem->GetChildren().IsEmpty();
edaa81ae 508}
c801d85f 509
f135ff73 510bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
c801d85f 511{
4832f7c0
VZ
512 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
513
f135ff73
VZ
514 return item.m_pItem->IsExpanded();
515}
29d87bba 516
f135ff73
VZ
517bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
518{
4832f7c0
VZ
519 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
520
f135ff73
VZ
521 return item.m_pItem->HasHilight();
522}
29d87bba 523
ef44a621
VZ
524bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
525{
526 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
527
528 return item.m_pItem->IsBold();
529}
530
f135ff73
VZ
531// -----------------------------------------------------------------------------
532// navigation
533// -----------------------------------------------------------------------------
29d87bba 534
f135ff73
VZ
535wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
536{
1e6d9499 537 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
389cdc7a 538
f135ff73
VZ
539 return item.m_pItem->GetParent();
540}
29d87bba 541
f135ff73
VZ
542wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
543{
1e6d9499 544 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
29d87bba 545
f135ff73
VZ
546 cookie = 0;
547 return GetNextChild(item, cookie);
548}
29d87bba 549
f135ff73
VZ
550wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
551{
1e6d9499 552 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
29d87bba 553
4832f7c0
VZ
554 wxArrayTreeItems& children = item.m_pItem->GetChildren();
555 if ( (size_t)cookie < children.Count() )
556 {
557 return item.m_pItem->GetChildren().Item(cookie++);
558 }
559 else
560 {
561 // there are no more of them
1e6d9499 562 return wxTreeItemId();
4832f7c0 563 }
f135ff73 564}
29d87bba 565
f135ff73
VZ
566wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
567{
1e6d9499 568 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
f135ff73
VZ
569
570 wxGenericTreeItem *i = item.m_pItem;
571 wxGenericTreeItem *parent = i->GetParent();
572 if ( parent == NULL )
573 {
574 // root item doesn't have any siblings
1e6d9499 575 return wxTreeItemId();
edaa81ae 576 }
4832f7c0 577
f135ff73
VZ
578 wxArrayTreeItems& siblings = parent->GetChildren();
579 int index = siblings.Index(i);
580 wxASSERT( index != NOT_FOUND ); // I'm not a child of my parent?
29d87bba 581
f135ff73 582 size_t n = (size_t)(index + 1);
fdd8d7b5 583 return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
edaa81ae 584}
c801d85f 585
f135ff73 586wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
c801d85f 587{
1e6d9499 588 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
f135ff73
VZ
589
590 wxGenericTreeItem *i = item.m_pItem;
591 wxGenericTreeItem *parent = i->GetParent();
592 if ( parent == NULL )
c801d85f 593 {
f135ff73 594 // root item doesn't have any siblings
1e6d9499 595 return wxTreeItemId();
edaa81ae 596 }
4832f7c0 597
f135ff73
VZ
598 wxArrayTreeItems& siblings = parent->GetChildren();
599 int index = siblings.Index(i);
600 wxASSERT( index != NOT_FOUND ); // I'm not a child of my parent?
29d87bba 601
fdd8d7b5
VZ
602 return index == 0 ? wxTreeItemId()
603 : wxTreeItemId(siblings[(size_t)(index - 1)]);
f135ff73 604}
389cdc7a 605
f135ff73
VZ
606wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
607{
608 wxFAIL_MSG("not implemented");
29d87bba 609
1e6d9499 610 return wxTreeItemId();
f135ff73 611}
29d87bba 612
f135ff73
VZ
613wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
614{
1e6d9499 615 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
29d87bba 616
f135ff73 617 wxFAIL_MSG("not implemented");
29d87bba 618
1e6d9499 619 return wxTreeItemId();
f135ff73 620}
29d87bba 621
f135ff73
VZ
622wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
623{
1e6d9499 624 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
29d87bba 625
f135ff73 626 wxFAIL_MSG("not implemented");
29d87bba 627
1e6d9499 628 return wxTreeItemId();
edaa81ae 629}
c801d85f 630
f135ff73
VZ
631// -----------------------------------------------------------------------------
632// operations
633// -----------------------------------------------------------------------------
634
635wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
636 size_t previous,
637 const wxString& text,
638 int image, int selImage,
639 wxTreeItemData *data)
c801d85f 640{
f135ff73
VZ
641 wxGenericTreeItem *parent = parentId.m_pItem;
642 if ( !parent )
643 {
644 // should we give a warning here?
645 return AddRoot(text, image, selImage, data);
646 }
4832f7c0 647
f135ff73
VZ
648 wxClientDC dc(this);
649 wxGenericTreeItem *item = new wxGenericTreeItem(parent,
650 text, dc,
651 image, selImage,
652 data);
74bedbeb 653
f135ff73 654 if ( data != NULL )
c801d85f 655 {
f135ff73
VZ
656 data->m_pItem = item;
657 }
74bedbeb 658
f135ff73 659 parent->Insert( item, previous );
ef44a621 660
3db7be80 661 m_dirty = TRUE;
389cdc7a 662
f135ff73 663 return item;
4c681997
RR
664}
665
f135ff73
VZ
666wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
667 int image, int selImage,
668 wxTreeItemData *data)
4c681997 669{
1e6d9499 670 wxCHECK_MSG( !m_anchor, wxTreeItemId(), "tree can have only one root" );
389cdc7a 671
f135ff73
VZ
672 wxClientDC dc(this);
673 m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
674 image, selImage, data);
675 if ( data != NULL )
676 {
677 data->m_pItem = m_anchor;
678 }
389cdc7a 679
f135ff73 680 AdjustMyScrollbars();
a32dd690 681 Refresh();
a32dd690 682
f135ff73 683 return m_anchor;
edaa81ae 684}
c801d85f 685
f135ff73
VZ
686wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
687 const wxString& text,
688 int image, int selImage,
689 wxTreeItemData *data)
c801d85f 690{
f135ff73 691 return DoInsertItem(parent, 0u, text, image, selImage, data);
edaa81ae 692}
c801d85f 693
f135ff73
VZ
694wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId,
695 const wxTreeItemId& idPrevious,
696 const wxString& text,
697 int image, int selImage,
698 wxTreeItemData *data)
c801d85f 699{
f135ff73
VZ
700 wxGenericTreeItem *parent = parentId.m_pItem;
701 if ( !parent )
702 {
703 // should we give a warning here?
704 return AddRoot(text, image, selImage, data);
705 }
c801d85f 706
f135ff73
VZ
707 int index = parent->GetChildren().Index(idPrevious.m_pItem);
708 wxASSERT_MSG( index != NOT_FOUND,
709 "previous item in wxTreeCtrl::InsertItem() is not a sibling" );
710 return DoInsertItem(parentId, (size_t)index, text, image, selImage, data);
edaa81ae 711}
c801d85f 712
f135ff73
VZ
713wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId,
714 const wxString& text,
715 int image, int selImage,
716 wxTreeItemData *data)
74bedbeb 717{
f135ff73
VZ
718 wxGenericTreeItem *parent = parentId.m_pItem;
719 if ( !parent )
720 {
721 // should we give a warning here?
722 return AddRoot(text, image, selImage, data);
723 }
724
725 return DoInsertItem(parent, parent->GetChildren().Count(), text,
726 image, selImage, data);
74bedbeb
VZ
727}
728
a43a4f9d
VZ
729void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
730{
731 wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
732 event.m_item = item;
733 event.SetEventObject( this );
734 ProcessEvent( event );
735}
736
372edb9d
VZ
737void wxTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
738{
739 wxGenericTreeItem *item = itemId.m_pItem;
a43a4f9d 740 item->DeleteChildren(this);
372edb9d
VZ
741
742 m_dirty = TRUE;
743}
744
f135ff73 745void wxTreeCtrl::Delete(const wxTreeItemId& itemId)
c801d85f 746{
f135ff73 747 wxGenericTreeItem *item = itemId.m_pItem;
ff5bf259
VZ
748 wxGenericTreeItem *parent = item->GetParent();
749
750 if ( parent )
751 {
752 parent->GetChildren().Remove(item);
753 }
f135ff73 754
a43a4f9d
VZ
755 item->DeleteChildren(this);
756 SendDeleteEvent(item);
f135ff73
VZ
757 delete item;
758
4bb19cfb 759 m_dirty = TRUE;
edaa81ae 760}
c801d85f 761
f135ff73 762void wxTreeCtrl::DeleteAllItems()
c801d85f 763{
f135ff73
VZ
764 if ( m_anchor )
765 {
a43a4f9d 766 m_anchor->DeleteChildren(this);
f135ff73 767 delete m_anchor;
a43a4f9d 768
f135ff73
VZ
769 m_anchor = NULL;
770
4bb19cfb 771 m_dirty = TRUE;
f135ff73 772 }
edaa81ae
RR
773}
774
f135ff73 775void wxTreeCtrl::Expand(const wxTreeItemId& itemId)
edaa81ae 776{
f135ff73
VZ
777 wxGenericTreeItem *item = itemId.m_pItem;
778
4bb19cfb
RR
779 if ( !item->HasPlus() )
780 return;
781
f135ff73
VZ
782 if ( item->IsExpanded() )
783 return;
784
785 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
786 event.m_item = item;
787 event.SetEventObject( this );
788 if ( ProcessEvent( event ) && event.m_code )
789 {
790 // cancelled by program
791 return;
792 }
4832f7c0 793
f135ff73 794 item->Expand();
28ab302b 795 CalculatePositions();
f135ff73
VZ
796
797 RefreshSubtree(item);
798
799 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
800 ProcessEvent( event );
edaa81ae
RR
801}
802
f135ff73 803void wxTreeCtrl::Collapse(const wxTreeItemId& itemId)
edaa81ae 804{
f135ff73
VZ
805 wxGenericTreeItem *item = itemId.m_pItem;
806
807 if ( !item->IsExpanded() )
808 return;
809
810 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
811 event.m_item = item;
812 event.SetEventObject( this );
813 if ( ProcessEvent( event ) && event.m_code )
edaa81ae 814 {
f135ff73
VZ
815 // cancelled by program
816 return;
817 }
4832f7c0 818
f135ff73
VZ
819 item->Collapse();
820
821 wxArrayTreeItems& children = item->GetChildren();
822 size_t count = children.Count();
823 for ( size_t n = 0; n < count; n++ )
824 {
825 Collapse(children[n]);
edaa81ae 826 }
f135ff73
VZ
827
828 CalculatePositions();
829
830 RefreshSubtree(item);
831
832 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
833 ProcessEvent( event );
edaa81ae 834}
c801d85f 835
f135ff73 836void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
c801d85f 837{
f135ff73 838 Collapse(item);
372edb9d 839 DeleteChildren(item);
edaa81ae 840}
c801d85f 841
f135ff73 842void wxTreeCtrl::Toggle(const wxTreeItemId& itemId)
c801d85f 843{
f135ff73 844 wxGenericTreeItem *item = itemId.m_pItem;
389cdc7a 845
f135ff73
VZ
846 if ( item->IsExpanded() )
847 Collapse(itemId);
848 else
849 Expand(itemId);
850}
389cdc7a 851
f135ff73
VZ
852void wxTreeCtrl::Unselect()
853{
854 if ( m_current )
855 {
856 m_current->SetHilight( FALSE );
857 RefreshLine( m_current );
858 }
edaa81ae 859}
c801d85f 860
f135ff73 861void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId)
389cdc7a 862{
f135ff73
VZ
863 wxGenericTreeItem *item = itemId.m_pItem;
864
865 if ( m_current != item )
389cdc7a 866 {
f135ff73
VZ
867 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
868 event.m_item = item;
869 event.m_itemOld = m_current;
870 event.SetEventObject( this );
6daa0637 871 if ( GetEventHandler()->ProcessEvent( event ) && event.WasVetoed() )
f135ff73
VZ
872 return;
873
874 if ( m_current )
389cdc7a
VZ
875 {
876 m_current->SetHilight( FALSE );
877 RefreshLine( m_current );
edaa81ae 878 }
f135ff73 879
389cdc7a
VZ
880 m_current = item;
881 m_current->SetHilight( TRUE );
882 RefreshLine( m_current );
883
f135ff73 884 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
6daa0637 885 GetEventHandler()->ProcessEvent( event );
389cdc7a
VZ
886 }
887}
888
6daa0637 889void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
c801d85f 890{
0659e7ee 891 wxGenericTreeItem *gitem = item.m_pItem;
ef44a621 892
0659e7ee 893 int item_y = gitem->GetY();
ef44a621 894
0659e7ee
RR
895 int start_x = 0;
896 int start_y = 0;
897 ViewStart( &start_x, &start_y );
898 start_y *= 10;
a93109d5
RR
899
900 int client_h = 0;
901 int client_w = 0;
902 GetClientSize( &client_w, &client_h );
ef44a621 903
0659e7ee
RR
904 if (item_y < start_y+3)
905 {
906 int x = 0;
907 int y = 0;
908 m_anchor->GetSize( x, y );
909 y += 2*m_lineHeight;
910 int x_pos = GetScrollPos( wxHORIZONTAL );
a93109d5 911 SetScrollbars( 10, 10, x/10, y/10, x_pos, (item_y-client_h/2)/10 );
0659e7ee
RR
912 return;
913 }
ef44a621 914
a93109d5 915 if (item_y > start_y+client_h-16)
0659e7ee
RR
916 {
917 int x = 0;
918 int y = 0;
919 m_anchor->GetSize( x, y );
920 y += 2*m_lineHeight;
921 int x_pos = GetScrollPos( wxHORIZONTAL );
a93109d5 922 SetScrollbars( 10, 10, x/10, y/10, x_pos, (item_y-client_h/2)/10 );
0659e7ee
RR
923 return;
924 }
edaa81ae 925}
c801d85f 926
df875e59 927void wxTreeCtrl::ScrollTo(const wxTreeItemId& WXUNUSED(item))
c801d85f 928{
f135ff73 929 wxFAIL_MSG("not implemented");
edaa81ae 930}
c801d85f 931
df875e59
RR
932wxTextCtrl *wxTreeCtrl::EditLabel( const wxTreeItemId& WXUNUSED(item),
933 wxClassInfo* WXUNUSED(textCtrlClass) )
c801d85f 934{
f135ff73 935 wxFAIL_MSG("not implemented");
c801d85f 936
0659e7ee 937 return (wxTextCtrl*)NULL;
edaa81ae 938}
c801d85f 939
f135ff73 940wxTextCtrl *wxTreeCtrl::GetEditControl() const
c801d85f 941{
0659e7ee 942 wxFAIL_MSG("not implemented");
c801d85f 943
0659e7ee 944 return (wxTextCtrl*)NULL;
edaa81ae 945}
c801d85f 946
df875e59 947void wxTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool WXUNUSED(discardChanges))
74bedbeb 948{
0659e7ee 949 wxFAIL_MSG("not implemented");
74bedbeb
VZ
950}
951
e1ee62bd
VZ
952// FIXME: tree sorting functions are not reentrant and not MT-safe!
953static wxTreeCtrl *s_treeBeingSorted = NULL;
0659e7ee 954
e1ee62bd
VZ
955static int tree_ctrl_compare_func(wxGenericTreeItem **item1,
956 wxGenericTreeItem **item2)
edaa81ae 957{
e1ee62bd
VZ
958 wxCHECK_MSG( s_treeBeingSorted, 0, "bug in wxTreeCtrl::SortChildren()" );
959
960 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
0659e7ee
RR
961}
962
e1ee62bd
VZ
963int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
964 const wxTreeItemId& item2)
0659e7ee 965{
e1ee62bd
VZ
966 return strcmp(GetItemText(item1), GetItemText(item2));
967}
968
969void wxTreeCtrl::SortChildren(const wxTreeItemId& itemId)
970{
971 wxCHECK_RET( itemId.IsOk(), "invalid tree item" );
972
973 wxGenericTreeItem *item = itemId.m_pItem;
0659e7ee 974
e1ee62bd
VZ
975 wxCHECK_RET( !s_treeBeingSorted,
976 "wxTreeCtrl::SortChildren is not reentrant" );
977
978 wxArrayTreeItems& children = item->GetChildren();
979 if ( children.Count() > 1 )
980 {
981 s_treeBeingSorted = this;
982 children.Sort(tree_ctrl_compare_func);
983 s_treeBeingSorted = NULL;
0659e7ee 984
e1ee62bd
VZ
985 m_dirty = TRUE;
986 }
987 //else: don't make the tree dirty as nothing changed
edaa81ae
RR
988}
989
f135ff73 990wxImageList *wxTreeCtrl::GetImageList() const
edaa81ae 991{
f135ff73 992 return m_imageListNormal;
edaa81ae
RR
993}
994
f135ff73 995wxImageList *wxTreeCtrl::GetStateImageList() const
c801d85f 996{
f135ff73 997 return m_imageListState;
edaa81ae 998}
c801d85f 999
f135ff73 1000void wxTreeCtrl::SetImageList(wxImageList *imageList)
e2414cbe 1001{
f135ff73 1002 m_imageListNormal = imageList;
edaa81ae 1003}
e2414cbe 1004
f135ff73 1005void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
e2414cbe 1006{
f135ff73 1007 m_imageListState = imageList;
edaa81ae 1008}
e2414cbe 1009
f135ff73
VZ
1010// -----------------------------------------------------------------------------
1011// helpers
1012// -----------------------------------------------------------------------------
0659e7ee 1013
74bedbeb 1014void wxTreeCtrl::AdjustMyScrollbars()
c801d85f 1015{
0659e7ee
RR
1016 if (m_anchor)
1017 {
1018 int x = 0;
1019 int y = 0;
1020 m_anchor->GetSize( x, y );
1021 y += 2*m_lineHeight;
1022 int x_pos = GetScrollPos( wxHORIZONTAL );
1023 int y_pos = GetScrollPos( wxVERTICAL );
1024 SetScrollbars( 10, 10, x/10, y/10, x_pos, y_pos );
1025 }
1026 else
1027 {
1028 SetScrollbars( 0, 0, 0, 0 );
1029 }
edaa81ae 1030}
c801d85f 1031
ef44a621
VZ
1032void wxTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
1033{
1034 // render bold items in bold
c59e2a82
RR
1035 wxFont fontOld;
1036 wxFont fontNew;
1037
ef44a621
VZ
1038 if ( item->IsBold() )
1039 {
1040 fontOld = dc.GetFont();
c59e2a82 1041 if (fontOld.Ok())
ef44a621
VZ
1042 {
1043 // @@ is there any better way to make a bold variant of old font?
c59e2a82
RR
1044 fontNew = wxFont( fontOld.GetPointSize(),
1045 fontOld.GetFamily(),
1046 fontOld.GetStyle(),
1047 wxBOLD,
1048 fontOld.GetUnderlined());
ef44a621
VZ
1049 dc.SetFont(fontNew);
1050 }
1051 else
1052 {
1053 wxFAIL_MSG("wxDC::GetFont() failed!");
1054 }
1055 }
1056
1057 long text_w = 0;
1058 long text_h = 0;
1059 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
1060
1061 int image_h = 0;
1062 int image_w = 0;
0659e7ee
RR
1063 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1064 {
1065 m_imageListNormal->GetSize( item->GetSelectedImage(), image_w, image_h );
1066 image_w += 4;
1067 }
1068 else if (item->GetImage() != -1)
ef44a621
VZ
1069 {
1070 m_imageListNormal->GetSize( item->GetImage(), image_w, image_h );
1071 image_w += 4;
1072 }
1073
1074 dc.DrawRectangle( item->GetX()-2, item->GetY()-2, image_w+text_w+4, text_h+4 );
1075
0659e7ee
RR
1076 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1077 {
1078 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h );
1079 m_imageListNormal->Draw( item->GetSelectedImage(), dc,
1080 item->GetX(), item->GetY()-1,
1081 wxIMAGELIST_DRAW_TRANSPARENT );
1082 dc.DestroyClippingRegion();
1083 }
1084 else if (item->GetImage() != -1)
ef44a621
VZ
1085 {
1086 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h );
1087 m_imageListNormal->Draw( item->GetImage(), dc,
1088 item->GetX(), item->GetY()-1,
1089 wxIMAGELIST_DRAW_TRANSPARENT );
1090 dc.DestroyClippingRegion();
1091 }
1092
f60d0f94 1093 dc.SetBackgroundMode(wxTRANSPARENT);
ef44a621
VZ
1094 dc.DrawText( item->GetText(), image_w + item->GetX(), item->GetY() );
1095
1096 // restore normal font for bold items
c59e2a82 1097 if (fontOld.Ok())
ef44a621 1098 {
c59e2a82 1099 dc.SetFont( fontOld);
ef44a621
VZ
1100 }
1101}
1102
16c1f7f3 1103void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 1104{
4c681997 1105 int horizX = level*m_indent;
389cdc7a 1106
f135ff73
VZ
1107 item->SetX( horizX+33 );
1108 item->SetY( y-m_lineHeight/3 );
1109 item->SetHeight( m_lineHeight );
389cdc7a 1110
4c681997
RR
1111 item->SetCross( horizX+15, y );
1112
c801d85f 1113 int oldY = y;
389cdc7a 1114
d4c99d6f 1115 int exposed_x = dc.LogicalToDeviceX( 0 );
f135ff73 1116 int exposed_y = dc.LogicalToDeviceY( item->GetY()-2 );
4832f7c0 1117
df875e59 1118 if (IsExposed( exposed_x, exposed_y, 10000, m_lineHeight+4 )) // 10000 = very much
c801d85f 1119 {
4c681997
RR
1120 int startX = horizX;
1121 int endX = horizX + 10;
29d87bba 1122
4c681997 1123 if (!item->HasChildren()) endX += 20;
4832f7c0 1124
389cdc7a 1125 dc.DrawLine( startX, y, endX, y );
29d87bba 1126
f135ff73
VZ
1127 if (item->HasPlus())
1128 {
1129 dc.DrawLine( horizX+20, y, horizX+30, y );
1130 dc.SetPen( *wxGREY_PEN );
4bb19cfb 1131 dc.SetBrush( *wxWHITE_BRUSH );
f135ff73
VZ
1132 dc.DrawRectangle( horizX+10, y-4, 11, 9 );
1133 dc.SetPen( *wxBLACK_PEN );
1134 dc.DrawLine( horizX+13, y, horizX+18, y );
1135
1136 if (!item->IsExpanded())
1137 dc.DrawLine( horizX+15, y-2, horizX+15, y+3 );
1138 }
c801d85f 1139
f135ff73
VZ
1140 if (item->HasHilight())
1141 {
1142 dc.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
a367b9b3 1143
f135ff73 1144 dc.SetBrush( *m_hilightBrush );
4832f7c0 1145
df875e59
RR
1146 if (m_hasFocus)
1147 dc.SetPen( *wxBLACK_PEN );
29d87bba 1148 else
389cdc7a 1149 dc.SetPen( *wxTRANSPARENT_PEN );
4832f7c0 1150
ef44a621 1151 PaintItem(item, dc);
f135ff73
VZ
1152
1153 dc.SetPen( *wxBLACK_PEN );
1154 dc.SetTextForeground( *wxBLACK );
1155 dc.SetBrush( *wxWHITE_BRUSH );
1156 }
1157 else
1158 {
1159 dc.SetBrush( *wxWHITE_BRUSH );
1160 dc.SetPen( *wxTRANSPARENT_PEN );
4832f7c0 1161
ef44a621 1162 PaintItem(item, dc);
4832f7c0 1163
f135ff73
VZ
1164 dc.SetPen( *wxBLACK_PEN );
1165 }
edaa81ae 1166 }
4c681997 1167
372edb9d
VZ
1168 if ( item->IsExpanded() )
1169 {
1170 int semiOldY = y;
e2414cbe 1171
372edb9d
VZ
1172 wxArrayTreeItems& children = item->GetChildren();
1173 size_t count = children.Count();
1174 for ( size_t n = 0; n < count; n++ )
1175 {
1176 y += m_lineHeight;
1177 semiOldY = y;
389cdc7a 1178
372edb9d
VZ
1179 PaintLevel( children[n], dc, level+1, y );
1180 }
389cdc7a 1181
372edb9d
VZ
1182 // it may happen that the item is expanded but has no items (when you
1183 // delete all its children for example) - don't draw the vertical line
1184 // in this case
1185 if ( count > 0 )
1186 dc.DrawLine( horizX+15, oldY+5, horizX+15, semiOldY );
edaa81ae 1187 }
4c681997 1188}
c801d85f 1189
f135ff73
VZ
1190// -----------------------------------------------------------------------------
1191// wxWindows callbacks
1192// -----------------------------------------------------------------------------
1193
3db7be80 1194void wxTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
c801d85f 1195{
0659e7ee
RR
1196 if ( !m_anchor )
1197 return;
c801d85f 1198
0659e7ee
RR
1199 wxPaintDC dc(this);
1200 PrepareDC( dc );
29d87bba 1201
f60d0f94 1202 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) );
29d87bba 1203
0659e7ee
RR
1204 dc.SetPen( m_dottedPen );
1205 m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1206
0659e7ee
RR
1207 int y = m_lineHeight / 2 + 2;
1208 PaintLevel( m_anchor, dc, 0, y );
edaa81ae 1209}
c801d85f 1210
3db7be80 1211void wxTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1212{
0659e7ee
RR
1213 m_hasFocus = TRUE;
1214 if ( m_current )
1215 RefreshLine( m_current );
edaa81ae 1216}
c801d85f 1217
3db7be80 1218void wxTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1219{
0659e7ee
RR
1220 m_hasFocus = FALSE;
1221 if ( m_current )
1222 RefreshLine( m_current );
edaa81ae 1223}
c801d85f
KB
1224
1225void wxTreeCtrl::OnChar( wxKeyEvent &event )
1226{
435fe83e
RR
1227 wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
1228 te.m_code = event.KeyCode();
1229 te.SetEventObject( this );
1230 GetEventHandler()->ProcessEvent( te );
1231
6daa0637 1232 if (m_current == 0)
ef44a621 1233 {
6daa0637
RR
1234 event.Skip();
1235 return;
1236 }
ef44a621 1237
6daa0637
RR
1238 switch (event.KeyCode())
1239 {
1240 case '+':
1241 case WXK_ADD:
4bb19cfb 1242 if (m_current->HasPlus() && !IsExpanded(m_current))
6daa0637
RR
1243 {
1244 Expand(m_current);
1245 }
ef44a621
VZ
1246 break;
1247
6daa0637
RR
1248 case '-':
1249 case WXK_SUBTRACT:
6daa0637
RR
1250 if (IsExpanded(m_current))
1251 {
1252 Collapse(m_current);
1253 }
ef44a621
VZ
1254 break;
1255
1256 case '*':
1257 case WXK_MULTIPLY:
1258 Toggle(m_current);
1259 break;
1260
6daa0637
RR
1261 case ' ':
1262 case WXK_RETURN:
ef44a621 1263 {
435fe83e 1264 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
ef44a621
VZ
1265 event.m_item = m_current;
1266 event.m_code = 0;
1267 event.SetEventObject( this );
1268 GetEventHandler()->ProcessEvent( event );
1269 }
1270 break;
1271
6daa0637 1272 case WXK_UP:
a93109d5
RR
1273 {
1274 wxTreeItemId prev = GetPrevSibling( m_current );
1275 if (!prev)
1276 {
1277 prev = GetParent( m_current );
1278 long cockie = 0;
1279 wxTreeItemId current = m_current;
1280 if (current == GetFirstChild( prev, cockie ))
1281 {
1282 // otherwise we return to where we came from
1283 SelectItem( prev );
1284 EnsureVisible( prev );
1285 break;
1286 }
1287 }
1288 if (prev)
1289 {
1290 while (IsExpanded(prev))
1291 {
1292 int c = (int)GetChildrenCount( prev, FALSE );
1293 long cockie = 0;
1294 prev = GetFirstChild( prev, cockie );
1295 for (int i = 0; i < c-1; i++)
1296 prev = GetNextSibling( prev );
1297 }
1298 SelectItem( prev );
1299 EnsureVisible( prev );
1300 }
1301 }
1302 break;
1303 case WXK_LEFT:
6daa0637 1304 {
ef44a621
VZ
1305 wxTreeItemId prev = GetPrevSibling( m_current );
1306 if (prev != 0)
1307 {
1308 SelectItem( prev );
1309 EnsureVisible( prev );
1310 }
1311 else
1312 {
1313 prev = GetParent( m_current );
1314 if (prev)
1315 {
1316 EnsureVisible( prev );
1317 SelectItem( prev );
1318 }
1319 }
6daa0637 1320 }
ef44a621
VZ
1321 break;
1322
1323 case WXK_RIGHT:
1324 // this works the same as the down arrow except that we also expand the
1325 // item if it wasn't expanded yet
1326 Expand(m_current);
1327 // fall through
1328
1329 case WXK_DOWN:
6daa0637 1330 {
ef44a621
VZ
1331 if (IsExpanded(m_current))
1332 {
1333 long cookie = 0;
1334 wxTreeItemId child = GetFirstChild( m_current, cookie );
1335 SelectItem( child );
1336 EnsureVisible( child );
1337 }
1338 else
1339 {
1340 wxTreeItemId next = GetNextSibling( m_current );
1341 if (next == 0)
1342 {
1343 wxTreeItemId current = m_current;
1344 while (current && !next)
1345 {
1346 current = GetParent( current );
1347 if (current) next = GetNextSibling( current );
1348 }
1349 }
1350 if (next != 0)
1351 {
1352 SelectItem( next );
1353 EnsureVisible( next );
1354 }
1355 }
6daa0637 1356 }
ef44a621
VZ
1357 break;
1358
1359 default:
1360 event.Skip();
6daa0637 1361 }
edaa81ae 1362}
c801d85f 1363
4f22cf8d
RR
1364wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& WXUNUSED(flags))
1365{
1366 bool onButton = FALSE;
1367 return m_anchor->HitTest( point, onButton );
1368}
1369
3db7be80 1370void wxTreeCtrl::OnMouse( wxMouseEvent &event )
c801d85f 1371{
f135ff73
VZ
1372 if ( !(event.LeftDown() || event.LeftDClick()) )
1373 return;
1374
1375 if ( !m_anchor )
1376 return;
29d87bba 1377
c801d85f
KB
1378 wxClientDC dc(this);
1379 PrepareDC(dc);
1380 long x = dc.DeviceToLogicalX( (long)event.GetX() );
1381 long y = dc.DeviceToLogicalY( (long)event.GetY() );
29d87bba 1382
f135ff73
VZ
1383 bool onButton = FALSE;
1384 wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), onButton );
1385 if ( item == NULL )
29d87bba 1386 return;
29d87bba 1387
6daa0637 1388 if (!IsSelected(item)) SelectItem(item);
29d87bba 1389
f135ff73
VZ
1390 if ( event.LeftDClick() )
1391 {
435fe83e 1392 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
f135ff73
VZ
1393 event.m_item = item;
1394 event.m_code = 0;
1395 event.SetEventObject( this );
6daa0637 1396 GetEventHandler()->ProcessEvent( event );
f135ff73 1397 }
29d87bba 1398
f135ff73 1399 if ( onButton )
c801d85f 1400 {
f135ff73 1401 Toggle( item );
edaa81ae
RR
1402 }
1403}
c801d85f 1404
3db7be80
RR
1405void wxTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
1406{
1407 if (!m_dirty) return;
ef44a621 1408
3db7be80 1409 m_dirty = FALSE;
ef44a621 1410
3db7be80
RR
1411 CalculatePositions();
1412
1413 AdjustMyScrollbars();
1414}
1415
f135ff73
VZ
1416// -----------------------------------------------------------------------------
1417// -----------------------------------------------------------------------------
1418void wxTreeCtrl::CalculateLevel( wxGenericTreeItem *item,
1419 wxDC &dc,
1420 int level,
1421 int &y )
c801d85f 1422{
4c681997 1423 int horizX = level*m_indent;
389cdc7a 1424
f135ff73
VZ
1425 item->SetX( horizX+33 );
1426 item->SetY( y-m_lineHeight/3-2 );
1427 item->SetHeight( m_lineHeight );
4c681997 1428
28ab302b
JS
1429 // if ( item->IsExpanded() )
1430 // return;
1431 if ( !item->IsExpanded() ) // Surely this is correct? JACS
1432 return;
389cdc7a 1433
f135ff73
VZ
1434 wxArrayTreeItems& children = item->GetChildren();
1435 size_t count = children.Count();
1436 for ( size_t n = 0; n < count; n++ )
c801d85f 1437 {
c801d85f 1438 y += m_lineHeight;
f135ff73 1439 CalculateLevel( children[n], dc, level+1, y );
edaa81ae
RR
1440 }
1441}
c801d85f 1442
74bedbeb 1443void wxTreeCtrl::CalculatePositions()
c801d85f 1444{
f135ff73 1445 if ( !m_anchor )
29d87bba
VZ
1446 return;
1447
c801d85f
KB
1448 wxClientDC dc(this);
1449 PrepareDC( dc );
29d87bba 1450
fdd8d7b5 1451 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) );
29d87bba 1452
c801d85f
KB
1453 dc.SetPen( m_dottedPen );
1454 m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1455
c801d85f
KB
1456 int y = m_lineHeight / 2 + 2;
1457 CalculateLevel( m_anchor, dc, 0, y );
edaa81ae 1458}
c801d85f 1459
f135ff73 1460void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
c801d85f 1461{
f135ff73
VZ
1462 wxClientDC dc(this);
1463 PrepareDC(dc);
4832f7c0 1464
f135ff73
VZ
1465 int cw = 0;
1466 int ch = 0;
1467 GetClientSize( &cw, &ch );
4832f7c0 1468
f135ff73
VZ
1469 wxRect rect;
1470 rect.x = dc.LogicalToDeviceX( 0 );
1471 rect.width = cw;
1472 rect.y = dc.LogicalToDeviceY( item->GetY() );
1473 rect.height = ch;
1474
1475 Refresh( TRUE, &rect );
1476
1477 AdjustMyScrollbars();
edaa81ae 1478}
c801d85f
KB
1479
1480void wxTreeCtrl::RefreshLine( wxGenericTreeItem *item )
1481{
c801d85f
KB
1482 wxClientDC dc(this);
1483 PrepareDC( dc );
f135ff73 1484
c801d85f 1485 wxRect rect;
f135ff73
VZ
1486 rect.x = dc.LogicalToDeviceX( item->GetX() - 2 );
1487 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
c801d85f 1488 rect.width = 1000;
f135ff73 1489 rect.height = dc.GetCharHeight() + 6;
c801d85f 1490 Refresh( TRUE, &rect );
edaa81ae 1491}
c801d85f 1492