]> git.saurik.com Git - wxWidgets.git/blame - src/generic/treectrl.cpp
OnExit() is called for modules which were initialized even if the init of
[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;
bbe0af5b
RR
362
363 m_dragCount = 0;
edaa81ae 364}
c801d85f 365
f135ff73
VZ
366bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
367 const wxPoint& pos, const wxSize& size,
4f22cf8d
RR
368 long style,
369 const wxValidator &validator,
370 const wxString& name )
c801d85f 371{
f135ff73
VZ
372 Init();
373
a367b9b3 374 wxScrolledWindow::Create( parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name );
4f22cf8d
RR
375
376 SetValidator( validator );
f135ff73
VZ
377
378 SetBackgroundColour( *wxWHITE );
379 m_dottedPen = wxPen( *wxBLACK, 0, 0 );
380
381 return TRUE;
edaa81ae 382}
c801d85f 383
f135ff73 384wxTreeCtrl::~wxTreeCtrl()
c801d85f 385{
f135ff73 386 wxDELETE( m_hilightBrush );
a43a4f9d
VZ
387
388 DeleteAllItems();
edaa81ae 389}
c801d85f 390
f135ff73
VZ
391// -----------------------------------------------------------------------------
392// accessors
393// -----------------------------------------------------------------------------
394
395size_t wxTreeCtrl::GetCount() const
c801d85f 396{
4832f7c0 397 return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount();
edaa81ae 398}
c801d85f 399
f135ff73 400void wxTreeCtrl::SetIndent(unsigned int indent)
c801d85f 401{
f135ff73
VZ
402 m_indent = indent;
403 Refresh();
404}
74bedbeb 405
4832f7c0
VZ
406size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
407{
408 wxCHECK_MSG( item.IsOk(), 0u, "invalid tree item" );
409
410 return item.m_pItem->GetChildrenCount(recursively);
411}
412
f135ff73
VZ
413// -----------------------------------------------------------------------------
414// functions to work with tree items
415// -----------------------------------------------------------------------------
74bedbeb 416
f135ff73
VZ
417wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
418{
4832f7c0
VZ
419 wxCHECK_MSG( item.IsOk(), "", "invalid tree item" );
420
f135ff73 421 return item.m_pItem->GetText();
edaa81ae 422}
74bedbeb 423
f135ff73 424int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
74bedbeb 425{
4832f7c0
VZ
426 wxCHECK_MSG( item.IsOk(), -1, "invalid tree item" );
427
f135ff73 428 return item.m_pItem->GetImage();
edaa81ae 429}
c801d85f 430
f135ff73 431int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
c801d85f 432{
4832f7c0
VZ
433 wxCHECK_MSG( item.IsOk(), -1, "invalid tree item" );
434
f135ff73 435 return item.m_pItem->GetSelectedImage();
edaa81ae 436}
c801d85f 437
f135ff73 438wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
c801d85f 439{
4832f7c0
VZ
440 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
441
f135ff73 442 return item.m_pItem->GetData();
edaa81ae 443}
c801d85f 444
f135ff73
VZ
445void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
446{
4832f7c0
VZ
447 wxCHECK_RET( item.IsOk(), "invalid tree item" );
448
f135ff73 449 wxClientDC dc(this);
de646ed1 450 item.m_pItem->SetText(text, dc);
f135ff73 451}
c801d85f 452
f135ff73
VZ
453void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
454{
4832f7c0
VZ
455 wxCHECK_RET( item.IsOk(), "invalid tree item" );
456
de646ed1 457 item.m_pItem->SetImage(image);
f135ff73 458}
c801d85f 459
f135ff73 460void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
c801d85f 461{
4832f7c0
VZ
462 wxCHECK_RET( item.IsOk(), "invalid tree item" );
463
de646ed1 464 item.m_pItem->SetSelectedImage(image);
edaa81ae 465}
c801d85f 466
f135ff73 467void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
c801d85f 468{
4832f7c0
VZ
469 wxCHECK_RET( item.IsOk(), "invalid tree item" );
470
de646ed1 471 item.m_pItem->SetData(data);
edaa81ae 472}
c801d85f 473
f135ff73 474void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
c801d85f 475{
4832f7c0
VZ
476 wxCHECK_RET( item.IsOk(), "invalid tree item" );
477
f135ff73 478 item.m_pItem->SetHasPlus(has);
edaa81ae 479}
c801d85f 480
ef44a621
VZ
481void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
482{
483 wxCHECK_RET( item.IsOk(), "invalid tree item" );
484
485 // avoid redrawing the tree if no real change
486 wxGenericTreeItem *pItem = item.m_pItem;
487 if ( pItem->IsBold() != bold )
488 {
489 pItem->SetBold(bold);
490 RefreshLine(pItem);
491 }
492}
493
f135ff73
VZ
494// -----------------------------------------------------------------------------
495// item status inquiries
496// -----------------------------------------------------------------------------
497
df875e59 498bool wxTreeCtrl::IsVisible(const wxTreeItemId& WXUNUSED(item)) const
c801d85f 499{
f135ff73
VZ
500 wxFAIL_MSG("not implemented");
501
c801d85f 502 return TRUE;
edaa81ae 503}
c801d85f 504
f135ff73 505bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
c801d85f 506{
4832f7c0
VZ
507 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
508
f135ff73 509 return !item.m_pItem->GetChildren().IsEmpty();
edaa81ae 510}
c801d85f 511
f135ff73 512bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
c801d85f 513{
4832f7c0
VZ
514 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
515
f135ff73
VZ
516 return item.m_pItem->IsExpanded();
517}
29d87bba 518
f135ff73
VZ
519bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
520{
4832f7c0
VZ
521 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
522
f135ff73
VZ
523 return item.m_pItem->HasHilight();
524}
29d87bba 525
ef44a621
VZ
526bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
527{
528 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
529
530 return item.m_pItem->IsBold();
531}
532
f135ff73
VZ
533// -----------------------------------------------------------------------------
534// navigation
535// -----------------------------------------------------------------------------
29d87bba 536
f135ff73
VZ
537wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
538{
1e6d9499 539 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
389cdc7a 540
f135ff73
VZ
541 return item.m_pItem->GetParent();
542}
29d87bba 543
f135ff73
VZ
544wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
545{
1e6d9499 546 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
29d87bba 547
f135ff73
VZ
548 cookie = 0;
549 return GetNextChild(item, cookie);
550}
29d87bba 551
f135ff73
VZ
552wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
553{
1e6d9499 554 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
29d87bba 555
4832f7c0
VZ
556 wxArrayTreeItems& children = item.m_pItem->GetChildren();
557 if ( (size_t)cookie < children.Count() )
558 {
559 return item.m_pItem->GetChildren().Item(cookie++);
560 }
561 else
562 {
563 // there are no more of them
1e6d9499 564 return wxTreeItemId();
4832f7c0 565 }
f135ff73 566}
29d87bba 567
f135ff73
VZ
568wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
569{
1e6d9499 570 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
f135ff73
VZ
571
572 wxGenericTreeItem *i = item.m_pItem;
573 wxGenericTreeItem *parent = i->GetParent();
574 if ( parent == NULL )
575 {
576 // root item doesn't have any siblings
1e6d9499 577 return wxTreeItemId();
edaa81ae 578 }
4832f7c0 579
f135ff73
VZ
580 wxArrayTreeItems& siblings = parent->GetChildren();
581 int index = siblings.Index(i);
3c67202d 582 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
29d87bba 583
f135ff73 584 size_t n = (size_t)(index + 1);
fdd8d7b5 585 return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
edaa81ae 586}
c801d85f 587
f135ff73 588wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
c801d85f 589{
1e6d9499 590 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
f135ff73
VZ
591
592 wxGenericTreeItem *i = item.m_pItem;
593 wxGenericTreeItem *parent = i->GetParent();
594 if ( parent == NULL )
c801d85f 595 {
f135ff73 596 // root item doesn't have any siblings
1e6d9499 597 return wxTreeItemId();
edaa81ae 598 }
4832f7c0 599
f135ff73
VZ
600 wxArrayTreeItems& siblings = parent->GetChildren();
601 int index = siblings.Index(i);
3c67202d 602 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
29d87bba 603
fdd8d7b5
VZ
604 return index == 0 ? wxTreeItemId()
605 : wxTreeItemId(siblings[(size_t)(index - 1)]);
f135ff73 606}
389cdc7a 607
f135ff73
VZ
608wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
609{
610 wxFAIL_MSG("not implemented");
29d87bba 611
1e6d9499 612 return wxTreeItemId();
f135ff73 613}
29d87bba 614
f135ff73
VZ
615wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
616{
1e6d9499 617 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
29d87bba 618
f135ff73 619 wxFAIL_MSG("not implemented");
29d87bba 620
1e6d9499 621 return wxTreeItemId();
f135ff73 622}
29d87bba 623
f135ff73
VZ
624wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
625{
1e6d9499 626 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
29d87bba 627
f135ff73 628 wxFAIL_MSG("not implemented");
29d87bba 629
1e6d9499 630 return wxTreeItemId();
edaa81ae 631}
c801d85f 632
f135ff73
VZ
633// -----------------------------------------------------------------------------
634// operations
635// -----------------------------------------------------------------------------
636
637wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
638 size_t previous,
639 const wxString& text,
640 int image, int selImage,
641 wxTreeItemData *data)
c801d85f 642{
f135ff73
VZ
643 wxGenericTreeItem *parent = parentId.m_pItem;
644 if ( !parent )
645 {
646 // should we give a warning here?
647 return AddRoot(text, image, selImage, data);
648 }
4832f7c0 649
f135ff73
VZ
650 wxClientDC dc(this);
651 wxGenericTreeItem *item = new wxGenericTreeItem(parent,
652 text, dc,
653 image, selImage,
654 data);
74bedbeb 655
f135ff73 656 if ( data != NULL )
c801d85f 657 {
f135ff73
VZ
658 data->m_pItem = item;
659 }
74bedbeb 660
f135ff73 661 parent->Insert( item, previous );
ef44a621 662
3db7be80 663 m_dirty = TRUE;
389cdc7a 664
f135ff73 665 return item;
4c681997
RR
666}
667
f135ff73
VZ
668wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
669 int image, int selImage,
670 wxTreeItemData *data)
4c681997 671{
1e6d9499 672 wxCHECK_MSG( !m_anchor, wxTreeItemId(), "tree can have only one root" );
389cdc7a 673
f135ff73
VZ
674 wxClientDC dc(this);
675 m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
676 image, selImage, data);
677 if ( data != NULL )
678 {
679 data->m_pItem = m_anchor;
680 }
389cdc7a 681
f135ff73 682 AdjustMyScrollbars();
a32dd690 683 Refresh();
a32dd690 684
f135ff73 685 return m_anchor;
edaa81ae 686}
c801d85f 687
f135ff73
VZ
688wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
689 const wxString& text,
690 int image, int selImage,
691 wxTreeItemData *data)
c801d85f 692{
f135ff73 693 return DoInsertItem(parent, 0u, text, image, selImage, data);
edaa81ae 694}
c801d85f 695
f135ff73
VZ
696wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId,
697 const wxTreeItemId& idPrevious,
698 const wxString& text,
699 int image, int selImage,
700 wxTreeItemData *data)
c801d85f 701{
f135ff73
VZ
702 wxGenericTreeItem *parent = parentId.m_pItem;
703 if ( !parent )
704 {
705 // should we give a warning here?
706 return AddRoot(text, image, selImage, data);
707 }
c801d85f 708
f135ff73 709 int index = parent->GetChildren().Index(idPrevious.m_pItem);
3c67202d 710 wxASSERT_MSG( index != wxNOT_FOUND,
f135ff73
VZ
711 "previous item in wxTreeCtrl::InsertItem() is not a sibling" );
712 return DoInsertItem(parentId, (size_t)index, text, image, selImage, data);
edaa81ae 713}
c801d85f 714
f135ff73
VZ
715wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId,
716 const wxString& text,
717 int image, int selImage,
718 wxTreeItemData *data)
74bedbeb 719{
f135ff73
VZ
720 wxGenericTreeItem *parent = parentId.m_pItem;
721 if ( !parent )
722 {
723 // should we give a warning here?
724 return AddRoot(text, image, selImage, data);
725 }
726
727 return DoInsertItem(parent, parent->GetChildren().Count(), text,
728 image, selImage, data);
74bedbeb
VZ
729}
730
a43a4f9d
VZ
731void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
732{
733 wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
734 event.m_item = item;
735 event.SetEventObject( this );
736 ProcessEvent( event );
737}
738
372edb9d
VZ
739void wxTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
740{
741 wxGenericTreeItem *item = itemId.m_pItem;
a43a4f9d 742 item->DeleteChildren(this);
372edb9d
VZ
743
744 m_dirty = TRUE;
745}
746
f135ff73 747void wxTreeCtrl::Delete(const wxTreeItemId& itemId)
c801d85f 748{
f135ff73 749 wxGenericTreeItem *item = itemId.m_pItem;
ff5bf259
VZ
750 wxGenericTreeItem *parent = item->GetParent();
751
752 if ( parent )
753 {
754 parent->GetChildren().Remove(item);
755 }
f135ff73 756
a43a4f9d
VZ
757 item->DeleteChildren(this);
758 SendDeleteEvent(item);
f135ff73
VZ
759 delete item;
760
4bb19cfb 761 m_dirty = TRUE;
edaa81ae 762}
c801d85f 763
f135ff73 764void wxTreeCtrl::DeleteAllItems()
c801d85f 765{
f135ff73
VZ
766 if ( m_anchor )
767 {
a43a4f9d 768 m_anchor->DeleteChildren(this);
f135ff73 769 delete m_anchor;
a43a4f9d 770
f135ff73
VZ
771 m_anchor = NULL;
772
4bb19cfb 773 m_dirty = TRUE;
f135ff73 774 }
edaa81ae
RR
775}
776
f135ff73 777void wxTreeCtrl::Expand(const wxTreeItemId& itemId)
edaa81ae 778{
f135ff73
VZ
779 wxGenericTreeItem *item = itemId.m_pItem;
780
4bb19cfb
RR
781 if ( !item->HasPlus() )
782 return;
783
f135ff73
VZ
784 if ( item->IsExpanded() )
785 return;
786
787 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
788 event.m_item = item;
789 event.SetEventObject( this );
790 if ( ProcessEvent( event ) && event.m_code )
791 {
792 // cancelled by program
793 return;
794 }
4832f7c0 795
f135ff73 796 item->Expand();
28ab302b 797 CalculatePositions();
f135ff73
VZ
798
799 RefreshSubtree(item);
800
801 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
802 ProcessEvent( event );
edaa81ae
RR
803}
804
f135ff73 805void wxTreeCtrl::Collapse(const wxTreeItemId& itemId)
edaa81ae 806{
f135ff73
VZ
807 wxGenericTreeItem *item = itemId.m_pItem;
808
809 if ( !item->IsExpanded() )
810 return;
811
812 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
813 event.m_item = item;
814 event.SetEventObject( this );
815 if ( ProcessEvent( event ) && event.m_code )
edaa81ae 816 {
f135ff73
VZ
817 // cancelled by program
818 return;
819 }
4832f7c0 820
f135ff73
VZ
821 item->Collapse();
822
823 wxArrayTreeItems& children = item->GetChildren();
824 size_t count = children.Count();
825 for ( size_t n = 0; n < count; n++ )
826 {
827 Collapse(children[n]);
edaa81ae 828 }
f135ff73
VZ
829
830 CalculatePositions();
831
832 RefreshSubtree(item);
833
834 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
835 ProcessEvent( event );
edaa81ae 836}
c801d85f 837
f135ff73 838void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
c801d85f 839{
f135ff73 840 Collapse(item);
372edb9d 841 DeleteChildren(item);
edaa81ae 842}
c801d85f 843
f135ff73 844void wxTreeCtrl::Toggle(const wxTreeItemId& itemId)
c801d85f 845{
f135ff73 846 wxGenericTreeItem *item = itemId.m_pItem;
389cdc7a 847
f135ff73
VZ
848 if ( item->IsExpanded() )
849 Collapse(itemId);
850 else
851 Expand(itemId);
852}
389cdc7a 853
f135ff73
VZ
854void wxTreeCtrl::Unselect()
855{
856 if ( m_current )
857 {
858 m_current->SetHilight( FALSE );
859 RefreshLine( m_current );
860 }
edaa81ae 861}
c801d85f 862
f135ff73 863void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId)
389cdc7a 864{
f135ff73
VZ
865 wxGenericTreeItem *item = itemId.m_pItem;
866
867 if ( m_current != item )
389cdc7a 868 {
f135ff73
VZ
869 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
870 event.m_item = item;
871 event.m_itemOld = m_current;
872 event.SetEventObject( this );
6daa0637 873 if ( GetEventHandler()->ProcessEvent( event ) && event.WasVetoed() )
f135ff73
VZ
874 return;
875
876 if ( m_current )
389cdc7a
VZ
877 {
878 m_current->SetHilight( FALSE );
879 RefreshLine( m_current );
edaa81ae 880 }
f135ff73 881
389cdc7a
VZ
882 m_current = item;
883 m_current->SetHilight( TRUE );
884 RefreshLine( m_current );
885
f135ff73 886 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
6daa0637 887 GetEventHandler()->ProcessEvent( event );
389cdc7a
VZ
888 }
889}
890
6daa0637 891void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
c801d85f 892{
0659e7ee 893 wxGenericTreeItem *gitem = item.m_pItem;
ef44a621 894
0659e7ee 895 int item_y = gitem->GetY();
ef44a621 896
0659e7ee
RR
897 int start_x = 0;
898 int start_y = 0;
899 ViewStart( &start_x, &start_y );
900 start_y *= 10;
a93109d5
RR
901
902 int client_h = 0;
903 int client_w = 0;
904 GetClientSize( &client_w, &client_h );
ef44a621 905
0659e7ee
RR
906 if (item_y < start_y+3)
907 {
908 int x = 0;
909 int y = 0;
910 m_anchor->GetSize( x, y );
911 y += 2*m_lineHeight;
912 int x_pos = GetScrollPos( wxHORIZONTAL );
a93109d5 913 SetScrollbars( 10, 10, x/10, y/10, x_pos, (item_y-client_h/2)/10 );
0659e7ee
RR
914 return;
915 }
ef44a621 916
a93109d5 917 if (item_y > start_y+client_h-16)
0659e7ee
RR
918 {
919 int x = 0;
920 int y = 0;
921 m_anchor->GetSize( x, y );
922 y += 2*m_lineHeight;
923 int x_pos = GetScrollPos( wxHORIZONTAL );
a93109d5 924 SetScrollbars( 10, 10, x/10, y/10, x_pos, (item_y-client_h/2)/10 );
0659e7ee
RR
925 return;
926 }
edaa81ae 927}
c801d85f 928
df875e59 929void wxTreeCtrl::ScrollTo(const wxTreeItemId& WXUNUSED(item))
c801d85f 930{
bbe0af5b 931 wxFAIL_MSG("not implemented");
edaa81ae 932}
c801d85f 933
df875e59
RR
934wxTextCtrl *wxTreeCtrl::EditLabel( const wxTreeItemId& WXUNUSED(item),
935 wxClassInfo* WXUNUSED(textCtrlClass) )
c801d85f 936{
bbe0af5b 937 wxFAIL_MSG("not implemented");
c801d85f 938
bbe0af5b 939 return (wxTextCtrl*)NULL;
edaa81ae 940}
c801d85f 941
f135ff73 942wxTextCtrl *wxTreeCtrl::GetEditControl() const
c801d85f 943{
0659e7ee 944 wxFAIL_MSG("not implemented");
c801d85f 945
0659e7ee 946 return (wxTextCtrl*)NULL;
edaa81ae 947}
c801d85f 948
df875e59 949void wxTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool WXUNUSED(discardChanges))
74bedbeb 950{
0659e7ee 951 wxFAIL_MSG("not implemented");
74bedbeb
VZ
952}
953
e1ee62bd
VZ
954// FIXME: tree sorting functions are not reentrant and not MT-safe!
955static wxTreeCtrl *s_treeBeingSorted = NULL;
0659e7ee 956
e1ee62bd
VZ
957static int tree_ctrl_compare_func(wxGenericTreeItem **item1,
958 wxGenericTreeItem **item2)
edaa81ae 959{
e1ee62bd
VZ
960 wxCHECK_MSG( s_treeBeingSorted, 0, "bug in wxTreeCtrl::SortChildren()" );
961
962 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
0659e7ee
RR
963}
964
e1ee62bd
VZ
965int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
966 const wxTreeItemId& item2)
0659e7ee 967{
e1ee62bd
VZ
968 return strcmp(GetItemText(item1), GetItemText(item2));
969}
970
971void wxTreeCtrl::SortChildren(const wxTreeItemId& itemId)
972{
973 wxCHECK_RET( itemId.IsOk(), "invalid tree item" );
974
975 wxGenericTreeItem *item = itemId.m_pItem;
0659e7ee 976
e1ee62bd
VZ
977 wxCHECK_RET( !s_treeBeingSorted,
978 "wxTreeCtrl::SortChildren is not reentrant" );
979
980 wxArrayTreeItems& children = item->GetChildren();
981 if ( children.Count() > 1 )
982 {
983 s_treeBeingSorted = this;
984 children.Sort(tree_ctrl_compare_func);
985 s_treeBeingSorted = NULL;
0659e7ee 986
e1ee62bd
VZ
987 m_dirty = TRUE;
988 }
989 //else: don't make the tree dirty as nothing changed
edaa81ae
RR
990}
991
f135ff73 992wxImageList *wxTreeCtrl::GetImageList() const
edaa81ae 993{
f135ff73 994 return m_imageListNormal;
edaa81ae
RR
995}
996
f135ff73 997wxImageList *wxTreeCtrl::GetStateImageList() const
c801d85f 998{
f135ff73 999 return m_imageListState;
edaa81ae 1000}
c801d85f 1001
f135ff73 1002void wxTreeCtrl::SetImageList(wxImageList *imageList)
e2414cbe 1003{
f135ff73 1004 m_imageListNormal = imageList;
edaa81ae 1005}
e2414cbe 1006
f135ff73 1007void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
e2414cbe 1008{
f135ff73 1009 m_imageListState = imageList;
edaa81ae 1010}
e2414cbe 1011
f135ff73
VZ
1012// -----------------------------------------------------------------------------
1013// helpers
1014// -----------------------------------------------------------------------------
0659e7ee 1015
74bedbeb 1016void wxTreeCtrl::AdjustMyScrollbars()
c801d85f 1017{
0659e7ee
RR
1018 if (m_anchor)
1019 {
1020 int x = 0;
1021 int y = 0;
1022 m_anchor->GetSize( x, y );
1023 y += 2*m_lineHeight;
1024 int x_pos = GetScrollPos( wxHORIZONTAL );
1025 int y_pos = GetScrollPos( wxVERTICAL );
1026 SetScrollbars( 10, 10, x/10, y/10, x_pos, y_pos );
1027 }
1028 else
1029 {
1030 SetScrollbars( 0, 0, 0, 0 );
1031 }
edaa81ae 1032}
c801d85f 1033
ef44a621
VZ
1034void wxTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
1035{
bbe0af5b
RR
1036 /* render bold items in bold */
1037 wxFont fontOld;
1038 wxFont fontNew;
c59e2a82 1039
bbe0af5b
RR
1040 if (item->IsBold())
1041 {
1042 fontOld = dc.GetFont();
1043 if (fontOld.Ok())
1044 {
1045 /* @@ is there any better way to make a bold variant of old font? */
1046 fontNew = wxFont( fontOld.GetPointSize(),
1047 fontOld.GetFamily(),
1048 fontOld.GetStyle(),
1049 wxBOLD,
1050 fontOld.GetUnderlined());
1051 dc.SetFont(fontNew);
1052 }
1053 else
1054 {
1055 wxFAIL_MSG("wxDC::GetFont() failed!");
1056 }
1057 }
ef44a621 1058
bbe0af5b
RR
1059 long text_w = 0;
1060 long text_h = 0;
1061 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
ef44a621 1062
bbe0af5b
RR
1063 int image_h = 0;
1064 int image_w = 0;
1065 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1066 {
1067 m_imageListNormal->GetSize( item->GetSelectedImage(), image_w, image_h );
1068 image_w += 4;
1069 }
1070 else if (item->GetImage() != -1)
1071 {
1072 m_imageListNormal->GetSize( item->GetImage(), image_w, image_h );
1073 image_w += 4;
1074 }
ef44a621 1075
bbe0af5b 1076 dc.DrawRectangle( item->GetX()-2, item->GetY()-2, image_w+text_w+4, text_h+4 );
ef44a621 1077
bbe0af5b
RR
1078 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1079 {
1080 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h );
1081 m_imageListNormal->Draw( item->GetSelectedImage(), dc,
1082 item->GetX(), item->GetY()-1,
1083 wxIMAGELIST_DRAW_TRANSPARENT );
1084 dc.DestroyClippingRegion();
1085 }
1086 else if (item->GetImage() != -1)
1087 {
1088 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h );
1089 m_imageListNormal->Draw( item->GetImage(), dc,
1090 item->GetX(), item->GetY()-1,
1091 wxIMAGELIST_DRAW_TRANSPARENT );
1092 dc.DestroyClippingRegion();
1093 }
ef44a621 1094
bbe0af5b
RR
1095 dc.SetBackgroundMode(wxTRANSPARENT);
1096 dc.DrawText( item->GetText(), image_w + item->GetX(), item->GetY() );
ef44a621 1097
bbe0af5b
RR
1098 /* restore normal font for bold items */
1099 if (fontOld.Ok())
1100 {
1101 dc.SetFont( fontOld);
1102 }
ef44a621
VZ
1103}
1104
16c1f7f3 1105void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 1106{
bbe0af5b 1107 int horizX = level*m_indent;
389cdc7a 1108
bbe0af5b
RR
1109 item->SetX( horizX+33 );
1110 item->SetY( y-m_lineHeight/3 );
1111 item->SetHeight( m_lineHeight );
389cdc7a 1112
bbe0af5b 1113 item->SetCross( horizX+15, y );
4c681997 1114
bbe0af5b 1115 int oldY = y;
389cdc7a 1116
bbe0af5b
RR
1117 int exposed_x = dc.LogicalToDeviceX( 0 );
1118 int exposed_y = dc.LogicalToDeviceY( item->GetY()-2 );
4832f7c0 1119
bbe0af5b
RR
1120 if (IsExposed( exposed_x, exposed_y, 10000, m_lineHeight+4 )) // 10000 = very much
1121 {
1122 int startX = horizX;
1123 int endX = horizX + 10;
29d87bba 1124
bbe0af5b 1125 if (!item->HasChildren()) endX += 20;
4832f7c0 1126
bbe0af5b 1127 dc.DrawLine( startX, y, endX, y );
29d87bba 1128
bbe0af5b
RR
1129 if (item->HasPlus())
1130 {
1131 dc.DrawLine( horizX+20, y, horizX+30, y );
1132 dc.SetPen( *wxGREY_PEN );
1133 dc.SetBrush( *wxWHITE_BRUSH );
1134 dc.DrawRectangle( horizX+10, y-4, 11, 9 );
1135 dc.SetPen( *wxBLACK_PEN );
1136 dc.DrawLine( horizX+13, y, horizX+18, y );
1137
1138 if (!item->IsExpanded())
1139 {
1140 dc.DrawLine( horizX+15, y-2, horizX+15, y+3 );
1141 }
1142 }
c801d85f 1143
bbe0af5b
RR
1144 if (item->HasHilight())
1145 {
1146 dc.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
a367b9b3 1147
bbe0af5b 1148 dc.SetBrush( *m_hilightBrush );
4832f7c0 1149
bbe0af5b
RR
1150 if (m_hasFocus)
1151 dc.SetPen( *wxBLACK_PEN );
1152 else
1153 dc.SetPen( *wxTRANSPARENT_PEN );
4832f7c0 1154
bbe0af5b 1155 PaintItem(item, dc);
f135ff73 1156
bbe0af5b
RR
1157 dc.SetPen( *wxBLACK_PEN );
1158 dc.SetTextForeground( *wxBLACK );
1159 dc.SetBrush( *wxWHITE_BRUSH );
1160 }
1161 else
1162 {
1163 dc.SetBrush( *wxWHITE_BRUSH );
1164 dc.SetPen( *wxTRANSPARENT_PEN );
4832f7c0 1165
bbe0af5b 1166 PaintItem(item, dc);
4832f7c0 1167
bbe0af5b
RR
1168 dc.SetPen( *wxBLACK_PEN );
1169 }
f135ff73 1170 }
e2414cbe 1171
bbe0af5b
RR
1172 if (item->IsExpanded())
1173 {
1174 int semiOldY = y;
389cdc7a 1175
bbe0af5b
RR
1176 wxArrayTreeItems& children = item->GetChildren();
1177 size_t count = children.Count();
1178 for ( size_t n = 0; n < count; n++ )
1179 {
1180 y += m_lineHeight;
1181 semiOldY = y;
1182 PaintLevel( children[n], dc, level+1, y );
1183 }
389cdc7a 1184
bbe0af5b
RR
1185 /* it may happen that the item is expanded but has no items (when you
1186 * delete all its children for example) - don't draw the vertical line
1187 * in this case */
1188 if (count > 0) dc.DrawLine( horizX+15, oldY+5, horizX+15, semiOldY );
1189 }
4c681997 1190}
c801d85f 1191
f135ff73
VZ
1192// -----------------------------------------------------------------------------
1193// wxWindows callbacks
1194// -----------------------------------------------------------------------------
1195
3db7be80 1196void wxTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
c801d85f 1197{
0659e7ee
RR
1198 if ( !m_anchor )
1199 return;
c801d85f 1200
0659e7ee
RR
1201 wxPaintDC dc(this);
1202 PrepareDC( dc );
29d87bba 1203
f60d0f94 1204 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) );
29d87bba 1205
0659e7ee
RR
1206 dc.SetPen( m_dottedPen );
1207 m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1208
0659e7ee
RR
1209 int y = m_lineHeight / 2 + 2;
1210 PaintLevel( m_anchor, dc, 0, y );
edaa81ae 1211}
c801d85f 1212
3db7be80 1213void wxTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1214{
0659e7ee 1215 m_hasFocus = TRUE;
bbe0af5b
RR
1216
1217 if (m_current) RefreshLine( m_current );
edaa81ae 1218}
c801d85f 1219
3db7be80 1220void wxTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1221{
0659e7ee 1222 m_hasFocus = FALSE;
bbe0af5b
RR
1223
1224 if (m_current) RefreshLine( m_current );
edaa81ae 1225}
c801d85f
KB
1226
1227void wxTreeCtrl::OnChar( wxKeyEvent &event )
1228{
435fe83e
RR
1229 wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
1230 te.m_code = event.KeyCode();
1231 te.SetEventObject( this );
1232 GetEventHandler()->ProcessEvent( te );
1233
6daa0637 1234 if (m_current == 0)
ef44a621 1235 {
6daa0637
RR
1236 event.Skip();
1237 return;
1238 }
ef44a621 1239
6daa0637
RR
1240 switch (event.KeyCode())
1241 {
1242 case '+':
1243 case WXK_ADD:
4bb19cfb 1244 if (m_current->HasPlus() && !IsExpanded(m_current))
6daa0637
RR
1245 {
1246 Expand(m_current);
1247 }
ef44a621
VZ
1248 break;
1249
6daa0637
RR
1250 case '-':
1251 case WXK_SUBTRACT:
6daa0637
RR
1252 if (IsExpanded(m_current))
1253 {
1254 Collapse(m_current);
1255 }
ef44a621
VZ
1256 break;
1257
1258 case '*':
1259 case WXK_MULTIPLY:
1260 Toggle(m_current);
1261 break;
1262
6daa0637
RR
1263 case ' ':
1264 case WXK_RETURN:
ef44a621 1265 {
435fe83e 1266 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
ef44a621
VZ
1267 event.m_item = m_current;
1268 event.m_code = 0;
1269 event.SetEventObject( this );
1270 GetEventHandler()->ProcessEvent( event );
1271 }
1272 break;
1273
6daa0637 1274 case WXK_UP:
a93109d5
RR
1275 {
1276 wxTreeItemId prev = GetPrevSibling( m_current );
1277 if (!prev)
1278 {
1279 prev = GetParent( m_current );
1280 long cockie = 0;
1281 wxTreeItemId current = m_current;
1282 if (current == GetFirstChild( prev, cockie ))
1283 {
1284 // otherwise we return to where we came from
1285 SelectItem( prev );
1286 EnsureVisible( prev );
1287 break;
1288 }
1289 }
1290 if (prev)
1291 {
1292 while (IsExpanded(prev))
1293 {
1294 int c = (int)GetChildrenCount( prev, FALSE );
1295 long cockie = 0;
1296 prev = GetFirstChild( prev, cockie );
1297 for (int i = 0; i < c-1; i++)
1298 prev = GetNextSibling( prev );
1299 }
1300 SelectItem( prev );
1301 EnsureVisible( prev );
1302 }
1303 }
1304 break;
1305 case WXK_LEFT:
6daa0637 1306 {
ef44a621
VZ
1307 wxTreeItemId prev = GetPrevSibling( m_current );
1308 if (prev != 0)
1309 {
1310 SelectItem( prev );
1311 EnsureVisible( prev );
1312 }
1313 else
1314 {
1315 prev = GetParent( m_current );
1316 if (prev)
1317 {
1318 EnsureVisible( prev );
1319 SelectItem( prev );
1320 }
1321 }
6daa0637 1322 }
ef44a621
VZ
1323 break;
1324
1325 case WXK_RIGHT:
1326 // this works the same as the down arrow except that we also expand the
1327 // item if it wasn't expanded yet
1328 Expand(m_current);
1329 // fall through
1330
1331 case WXK_DOWN:
6daa0637 1332 {
ef44a621
VZ
1333 if (IsExpanded(m_current))
1334 {
1335 long cookie = 0;
1336 wxTreeItemId child = GetFirstChild( m_current, cookie );
1337 SelectItem( child );
1338 EnsureVisible( child );
1339 }
1340 else
1341 {
1342 wxTreeItemId next = GetNextSibling( m_current );
1343 if (next == 0)
1344 {
1345 wxTreeItemId current = m_current;
1346 while (current && !next)
1347 {
1348 current = GetParent( current );
1349 if (current) next = GetNextSibling( current );
1350 }
1351 }
1352 if (next != 0)
1353 {
1354 SelectItem( next );
1355 EnsureVisible( next );
1356 }
1357 }
6daa0637 1358 }
ef44a621
VZ
1359 break;
1360
1361 default:
1362 event.Skip();
6daa0637 1363 }
edaa81ae 1364}
c801d85f 1365
4f22cf8d
RR
1366wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& WXUNUSED(flags))
1367{
bbe0af5b
RR
1368 bool onButton = FALSE;
1369 return m_anchor->HitTest( point, onButton );
4f22cf8d
RR
1370}
1371
3db7be80 1372void wxTreeCtrl::OnMouse( wxMouseEvent &event )
c801d85f 1373{
bbe0af5b 1374 if (!event.LeftIsDown()) m_dragCount = 0;
f135ff73 1375
bbe0af5b 1376 if ( !(event.LeftDown() || event.LeftDClick() || event.Dragging()) ) return;
29d87bba 1377
bbe0af5b
RR
1378 if ( !m_anchor ) return;
1379
1380 wxClientDC dc(this);
1381 PrepareDC(dc);
1382 long x = dc.DeviceToLogicalX( (long)event.GetX() );
1383 long y = dc.DeviceToLogicalY( (long)event.GetY() );
29d87bba 1384
bbe0af5b
RR
1385 bool onButton = FALSE;
1386 wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), onButton );
1387
1388 if (item == NULL) return; /* we hit the blank area */
29d87bba 1389
bbe0af5b
RR
1390 if (event.Dragging())
1391 {
1392 if (m_dragCount == 2) /* small drag latency (3?) */
1393 {
1394 m_dragCount = 0;
1395
1396 wxTreeEvent nevent(wxEVT_COMMAND_TREE_BEGIN_DRAG, GetId());
1397 nevent.m_item = m_current;
1398 nevent.SetEventObject(this);
1399 GetEventHandler()->ProcessEvent(nevent);
1400 }
1401 else
1402 {
1403 m_dragCount++;
1404 }
1405 return;
1406 }
1407
1408 if (!IsSelected(item)) SelectItem(item); /* we dont support multiple selections, BTW */
29d87bba 1409
bbe0af5b
RR
1410 if (event.LeftDClick())
1411 {
1412 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
1413 event.m_item = item;
1414 event.m_code = 0;
1415 event.SetEventObject( this );
1416 GetEventHandler()->ProcessEvent( event );
1417 }
29d87bba 1418
bbe0af5b
RR
1419 if (onButton)
1420 {
1421 Toggle( item );
1422 }
edaa81ae 1423}
c801d85f 1424
3db7be80
RR
1425void wxTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
1426{
bbe0af5b
RR
1427 /* after all changes have been done to the tree control,
1428 * we actually redraw the tree when everything is over */
ef44a621 1429
bbe0af5b 1430 if (!m_dirty) return;
ef44a621 1431
bbe0af5b 1432 m_dirty = FALSE;
3db7be80 1433
bbe0af5b
RR
1434 CalculatePositions();
1435
1436 AdjustMyScrollbars();
3db7be80
RR
1437}
1438
f135ff73 1439// -----------------------------------------------------------------------------
bbe0af5b
RR
1440
1441void wxTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 1442{
bbe0af5b 1443 int horizX = level*m_indent;
389cdc7a 1444
bbe0af5b
RR
1445 item->SetX( horizX+33 );
1446 item->SetY( y-m_lineHeight/3-2 );
1447 item->SetHeight( m_lineHeight );
4c681997 1448
bbe0af5b
RR
1449 if ( !item->IsExpanded() )
1450 {
1451 /* we dont need to calculate collapsed branches */
1452 return;
1453 }
389cdc7a 1454
bbe0af5b
RR
1455 wxArrayTreeItems& children = item->GetChildren();
1456 size_t count = children.Count();
1457 for ( size_t n = 0; n < count; n++ )
1458 {
1459 y += m_lineHeight;
1460 CalculateLevel( children[n], dc, level+1, y ); /* recurse */
1461 }
edaa81ae 1462}
c801d85f 1463
74bedbeb 1464void wxTreeCtrl::CalculatePositions()
c801d85f 1465{
bbe0af5b 1466 if ( !m_anchor ) return;
29d87bba 1467
bbe0af5b
RR
1468 wxClientDC dc(this);
1469 PrepareDC( dc );
29d87bba 1470
bbe0af5b 1471 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) );
29d87bba 1472
bbe0af5b
RR
1473 dc.SetPen( m_dottedPen );
1474 m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1475
bbe0af5b
RR
1476 int y = m_lineHeight / 2 + 2;
1477 CalculateLevel( m_anchor, dc, 0, y ); /* start recursion */
edaa81ae 1478}
c801d85f 1479
f135ff73 1480void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
c801d85f 1481{
bbe0af5b
RR
1482 wxClientDC dc(this);
1483 PrepareDC(dc);
4832f7c0 1484
bbe0af5b
RR
1485 int cw = 0;
1486 int ch = 0;
1487 GetClientSize( &cw, &ch );
4832f7c0 1488
bbe0af5b
RR
1489 wxRect rect;
1490 rect.x = dc.LogicalToDeviceX( 0 );
1491 rect.width = cw;
1492 rect.y = dc.LogicalToDeviceY( item->GetY() );
1493 rect.height = ch;
f135ff73 1494
bbe0af5b 1495 Refresh( TRUE, &rect );
f135ff73 1496
bbe0af5b 1497 AdjustMyScrollbars();
edaa81ae 1498}
c801d85f
KB
1499
1500void wxTreeCtrl::RefreshLine( wxGenericTreeItem *item )
1501{
bbe0af5b
RR
1502 wxClientDC dc(this);
1503 PrepareDC( dc );
1504
1505 wxRect rect;
1506 rect.x = dc.LogicalToDeviceX( item->GetX() - 2 );
1507 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
1508 rect.width = 1000;
1509 rect.height = dc.GetCharHeight() + 6;
1510
1511 Refresh( TRUE, &rect );
edaa81ae 1512}
c801d85f 1513