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