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