]> git.saurik.com Git - wxWidgets.git/blame - src/generic/treectlg.cpp
Doc/distribution script mods
[wxWidgets.git] / src / generic / treectlg.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
941830cb 2// Name: treectlg.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__
941830cb 21 #pragma implementation "treectlg.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
941830cb
JS
31#include "wx/generic/treectlg.h"
32#include "wx/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 47WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
941830cb 48//WX_DEFINE_OBJARRAY(wxArrayTreeItemIds);
c801d85f 49
8dc99046
VZ
50// ----------------------------------------------------------------------------
51// constants
52// ----------------------------------------------------------------------------
53
54static const int NO_IMAGE = -1;
55
3dbeaa52
VZ
56#define PIXELS_PER_UNIT 10
57
f135ff73
VZ
58// -----------------------------------------------------------------------------
59// private classes
60// -----------------------------------------------------------------------------
61
3dbeaa52
VZ
62// timer used for enabling in-place edit
63class WXDLLEXPORT wxTreeRenameTimer: public wxTimer
64{
65public:
941830cb 66 wxTreeRenameTimer( wxGenericTreeCtrl *owner );
3dbeaa52
VZ
67
68 void Notify();
69
70private:
941830cb 71 wxGenericTreeCtrl *m_owner;
3dbeaa52
VZ
72};
73
74// control used for in-place edit
75class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
76{
77public:
78 wxTreeTextCtrl() { }
79 wxTreeTextCtrl( wxWindow *parent,
80 const wxWindowID id,
81 bool *accept,
82 wxString *res,
941830cb 83 wxGenericTreeCtrl *owner,
3dbeaa52
VZ
84 const wxString &value = wxEmptyString,
85 const wxPoint &pos = wxDefaultPosition,
86 const wxSize &size = wxDefaultSize,
27316302 87 int style = wxSIMPLE_BORDER,
3dbeaa52
VZ
88 const wxValidator& validator = wxDefaultValidator,
89 const wxString &name = wxTextCtrlNameStr );
90
91 void OnChar( wxKeyEvent &event );
92 void OnKillFocus( wxFocusEvent &event );
93
94private:
95 bool *m_accept;
96 wxString *m_res;
941830cb 97 wxGenericTreeCtrl *m_owner;
3dbeaa52
VZ
98 wxString m_startValue;
99
100 DECLARE_EVENT_TABLE()
101 DECLARE_DYNAMIC_CLASS(wxTreeTextCtrl);
102};
103
f135ff73
VZ
104// a tree item
105class WXDLLEXPORT wxGenericTreeItem
c801d85f 106{
f135ff73 107public:
9ec64fa7
VZ
108 // ctors & dtor
109 wxGenericTreeItem() { m_data = NULL; }
110 wxGenericTreeItem( wxGenericTreeItem *parent,
111 const wxString& text,
112 wxDC& dc,
113 int image, int selImage,
114 wxTreeItemData *data );
f135ff73 115
9ec64fa7 116 ~wxGenericTreeItem();
f135ff73 117
9ec64fa7
VZ
118 // trivial accessors
119 wxArrayGenericTreeItems& GetChildren() { return m_children; }
f135ff73 120
9ec64fa7
VZ
121 const wxString& GetText() const { return m_text; }
122 int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const
3dbeaa52 123 { return m_images[which]; }
9ec64fa7 124 wxTreeItemData *GetData() const { return m_data; }
f135ff73 125
9ec64fa7
VZ
126 // returns the current image for the item (depending on its
127 // selected/expanded/whatever state)
128 int GetCurrentImage() const;
8dc99046 129
9ec64fa7
VZ
130 void SetText( const wxString &text );
131 void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; }
132 void SetData(wxTreeItemData *data) { m_data = data; }
f135ff73 133
9ec64fa7 134 void SetHasPlus(bool has = TRUE) { m_hasPlus = has; }
f135ff73 135
9ec64fa7 136 void SetBold(bool bold) { m_isBold = bold; }
ef44a621 137
9ec64fa7
VZ
138 int GetX() const { return m_x; }
139 int GetY() const { return m_y; }
f135ff73 140
9ec64fa7
VZ
141 void SetX(int x) { m_x = x; }
142 void SetY(int y) { m_y = y; }
f135ff73 143
9ec64fa7
VZ
144 int GetHeight() const { return m_height; }
145 int GetWidth() const { return m_width; }
91b8de8d 146
9ec64fa7
VZ
147 void SetHeight(int h) { m_height = h; }
148 void SetWidth(int w) { m_width = w; }
91b8de8d
RR
149
150
9ec64fa7 151 wxGenericTreeItem *GetParent() const { return m_parent; }
c801d85f 152
9ec64fa7
VZ
153 // operations
154 // deletes all children notifying the treectrl about it if !NULL
155 // pointer given
941830cb 156 void DeleteChildren(wxGenericTreeCtrl *tree = NULL);
9ec64fa7
VZ
157 // FIXME don't know what is it for
158 void Reset();
f135ff73 159
9ec64fa7
VZ
160 // get count of all children (and grand children if 'recursively')
161 size_t GetChildrenCount(bool recursively = TRUE) const;
f135ff73 162
9ec64fa7 163 void Insert(wxGenericTreeItem *child, size_t index)
f135ff73
VZ
164 { m_children.Insert(child, index); }
165
9ec64fa7 166 void SetCross( int x, int y );
941830cb 167 void GetSize( int &x, int &y, const wxGenericTreeCtrl* );
f135ff73 168
9ec64fa7
VZ
169 // return the item at given position (or NULL if no item), onButton is
170 // TRUE if the point belongs to the item's button, otherwise it lies
171 // on the button's label
941830cb 172 wxGenericTreeItem *HitTest( const wxPoint& point, const wxGenericTreeCtrl *, int &flags);
f135ff73 173
9ec64fa7
VZ
174 void Expand() { m_isCollapsed = FALSE; }
175 void Collapse() { m_isCollapsed = TRUE; }
f135ff73 176
9ec64fa7 177 void SetHilight( bool set = TRUE ) { m_hasHilight = set; }
f135ff73 178
9ec64fa7
VZ
179 // status inquiries
180 bool HasChildren() const { return !m_children.IsEmpty(); }
ef8698d6 181 bool IsSelected() const { return m_hasHilight != 0; }
9ec64fa7
VZ
182 bool IsExpanded() const { return !m_isCollapsed; }
183 bool HasPlus() const { return m_hasPlus || HasChildren(); }
ef8698d6 184 bool IsBold() const { return m_isBold != 0; }
9ec64fa7
VZ
185
186 // attributes
187 // get them - may be NULL
188 wxTreeItemAttr *GetAttributes() const { return m_attr; }
189 // get them ensuring that the pointer is not NULL
190 wxTreeItemAttr& Attr()
191 {
192 if ( !m_attr )
193 m_attr = new wxTreeItemAttr;
194
195 return *m_attr;
196 }
f135ff73
VZ
197
198private:
9ec64fa7
VZ
199 wxString m_text;
200
201 // tree ctrl images for the normal, selected, expanded and
202 // expanded+selected states
203 int m_images[wxTreeItemIcon_Max];
204
205 wxTreeItemData *m_data;
206
207 // use bitfields to save size
208 int m_isCollapsed :1;
209 int m_hasHilight :1; // same as focused
210 int m_hasPlus :1; // used for item which doesn't have
211 // children but has a [+] button
212 int m_isBold :1; // render the label in bold font
213
6f2a55e3
VZ
214 wxCoord m_x, m_y;
215 wxCoord m_height, m_width;
9ec64fa7
VZ
216 int m_xCross, m_yCross;
217 int m_level;
218
219 wxArrayGenericTreeItems m_children;
220 wxGenericTreeItem *m_parent;
221
222 wxTreeItemAttr *m_attr;
f135ff73
VZ
223};
224
225// =============================================================================
226// implementation
227// =============================================================================
228
06b466c7
VZ
229// ----------------------------------------------------------------------------
230// private functions
231// ----------------------------------------------------------------------------
232
233// translate the key or mouse event flags to the type of selection we're
234// dealing with
235static void EventFlagsToSelType(long style,
236 bool shiftDown,
237 bool ctrlDown,
dfc6cd93
SB
238 bool &is_multiple,
239 bool &extended_select,
240 bool &unselect_others)
06b466c7 241{
dfc6cd93
SB
242 is_multiple = (style & wxTR_MULTIPLE) != 0;
243 extended_select = shiftDown && is_multiple;
244 unselect_others = !(extended_select || (ctrlDown && is_multiple));
06b466c7 245}
e179bd65
RR
246
247// -----------------------------------------------------------------------------
248// wxTreeRenameTimer (internal)
249// -----------------------------------------------------------------------------
250
941830cb 251wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl *owner )
e179bd65
RR
252{
253 m_owner = owner;
254}
255
256void wxTreeRenameTimer::Notify()
257{
258 m_owner->OnRenameTimer();
259}
260
261//-----------------------------------------------------------------------------
262// wxTreeTextCtrl (internal)
263//-----------------------------------------------------------------------------
264
265IMPLEMENT_DYNAMIC_CLASS(wxTreeTextCtrl,wxTextCtrl);
266
267BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl)
268 EVT_CHAR (wxTreeTextCtrl::OnChar)
269 EVT_KILL_FOCUS (wxTreeTextCtrl::OnKillFocus)
270END_EVENT_TABLE()
271
674ac8b9
VZ
272wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent,
273 const wxWindowID id,
274 bool *accept,
275 wxString *res,
941830cb 276 wxGenericTreeCtrl *owner,
674ac8b9
VZ
277 const wxString &value,
278 const wxPoint &pos,
279 const wxSize &size,
280 int style,
281 const wxValidator& validator,
282 const wxString &name )
283 : wxTextCtrl( parent, id, value, pos, size, style, validator, name )
e179bd65
RR
284{
285 m_res = res;
286 m_accept = accept;
287 m_owner = owner;
5f1ea0ee 288 (*m_accept) = FALSE;
3dbeaa52 289 (*m_res) = wxEmptyString;
5f1ea0ee 290 m_startValue = value;
e179bd65
RR
291}
292
293void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
294{
295 if (event.m_keyCode == WXK_RETURN)
296 {
297 (*m_accept) = TRUE;
298 (*m_res) = GetValue();
bce1406b
RR
299
300 if (!wxPendingDelete.Member(this))
301 wxPendingDelete.Append(this);
302
303 if ((*m_accept) && ((*m_res) != m_startValue))
304 m_owner->OnRenameAccept();
305
e179bd65
RR
306 return;
307 }
308 if (event.m_keyCode == WXK_ESCAPE)
309 {
310 (*m_accept) = FALSE;
311 (*m_res) = "";
bce1406b
RR
312
313 if (!wxPendingDelete.Member(this))
314 wxPendingDelete.Append(this);
315
e179bd65
RR
316 return;
317 }
318 event.Skip();
319}
320
321void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
322{
bce1406b
RR
323 if (!wxPendingDelete.Member(this))
324 wxPendingDelete.Append(this);
9dfbf520 325
5f1ea0ee
RR
326 if ((*m_accept) && ((*m_res) != m_startValue))
327 m_owner->OnRenameAccept();
e179bd65
RR
328}
329
941830cb 330#if 0
f135ff73 331// -----------------------------------------------------------------------------
c801d85f 332// wxTreeEvent
f135ff73 333// -----------------------------------------------------------------------------
c801d85f 334
e179bd65 335IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
9dfbf520 336
f135ff73 337wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
92976ab6 338 : wxNotifyEvent( commandType, id )
c801d85f 339{
00e12320
RR
340 m_code = 0;
341 m_itemOld = (wxGenericTreeItem *)NULL;
edaa81ae 342}
941830cb 343#endif
c801d85f 344
f135ff73 345// -----------------------------------------------------------------------------
c801d85f 346// wxGenericTreeItem
f135ff73 347// -----------------------------------------------------------------------------
c801d85f 348
f135ff73
VZ
349wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
350 const wxString& text,
406005d2 351 wxDC& WXUNUSED(dc),
f135ff73
VZ
352 int image, int selImage,
353 wxTreeItemData *data)
354 : m_text(text)
c801d85f 355{
00e12320
RR
356 m_images[wxTreeItemIcon_Normal] = image;
357 m_images[wxTreeItemIcon_Selected] = selImage;
358 m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
359 m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
8dc99046 360
00e12320
RR
361 m_data = data;
362 m_x = m_y = 0;
363 m_xCross = m_yCross = 0;
f135ff73 364
00e12320 365 m_level = 0;
f135ff73 366
00e12320
RR
367 m_isCollapsed = TRUE;
368 m_hasHilight = FALSE;
369 m_hasPlus = FALSE;
370 m_isBold = FALSE;
c801d85f 371
00e12320 372 m_parent = parent;
f135ff73 373
00e12320 374 m_attr = (wxTreeItemAttr *)NULL;
06b466c7 375
00e12320
RR
376 // We don't know the height here yet.
377 m_width = 0;
378 m_height = 0;
edaa81ae 379}
c801d85f 380
f135ff73 381wxGenericTreeItem::~wxGenericTreeItem()
c801d85f 382{
00e12320 383 delete m_data;
4832f7c0 384
00e12320 385 delete m_attr;
9ec64fa7 386
00e12320
RR
387 wxASSERT_MSG( m_children.IsEmpty(),
388 wxT("please call DeleteChildren() before deleting the item") );
372edb9d
VZ
389}
390
941830cb 391void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree)
372edb9d 392{
00e12320
RR
393 size_t count = m_children.Count();
394 for ( size_t n = 0; n < count; n++ )
a43a4f9d 395 {
00e12320
RR
396 wxGenericTreeItem *child = m_children[n];
397 if (tree)
398 tree->SendDeleteEvent(child);
a43a4f9d 399
00e12320
RR
400 child->DeleteChildren(tree);
401 delete child;
402 }
372edb9d 403
00e12320 404 m_children.Empty();
edaa81ae 405}
c801d85f 406
91b8de8d 407void wxGenericTreeItem::SetText( const wxString &text )
c801d85f 408{
00e12320 409 m_text = text;
edaa81ae 410}
c801d85f 411
74bedbeb 412void wxGenericTreeItem::Reset()
c801d85f 413{
00e12320
RR
414 m_text.Empty();
415 for ( int i = 0; i < wxTreeItemIcon_Max; i++ )
416 {
417 m_images[i] = NO_IMAGE;
418 }
8dc99046 419
00e12320
RR
420 m_data = NULL;
421 m_x = m_y =
422 m_height = m_width = 0;
423 m_xCross =
424 m_yCross = 0;
74bedbeb 425
00e12320 426 m_level = 0;
c801d85f 427
00e12320
RR
428 DeleteChildren();
429 m_isCollapsed = TRUE;
c801d85f 430
00e12320 431 m_parent = (wxGenericTreeItem *)NULL;
edaa81ae 432}
c801d85f 433
4832f7c0 434size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
c801d85f 435{
00e12320
RR
436 size_t count = m_children.Count();
437 if ( !recursively )
438 return count;
4832f7c0 439
00e12320 440 size_t total = count;
f2593d0d 441 for (size_t n = 0; n < count; ++n)
00e12320
RR
442 {
443 total += m_children[n]->GetChildrenCount();
444 }
c801d85f 445
00e12320 446 return total;
edaa81ae 447}
c801d85f
KB
448
449void wxGenericTreeItem::SetCross( int x, int y )
450{
00e12320
RR
451 m_xCross = x;
452 m_yCross = y;
edaa81ae 453}
c801d85f 454
941830cb 455void wxGenericTreeItem::GetSize( int &x, int &y, const wxGenericTreeCtrl *theTree )
c801d85f 456{
00e12320
RR
457 int bottomY=m_y+theTree->GetLineHeight(this);
458 if ( y < bottomY ) y = bottomY;
459 int width = m_x + m_width;
460 if ( x < width ) x = width;
f135ff73 461
00e12320 462 if (IsExpanded())
4832f7c0 463 {
00e12320
RR
464 size_t count = m_children.Count();
465 for ( size_t n = 0; n < count; ++n )
466 {
467 m_children[n]->GetSize( x, y, theTree );
468 }
df875e59 469 }
edaa81ae 470}
c801d85f 471
f135ff73 472wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point,
941830cb 473 const wxGenericTreeCtrl *theTree,
c193b707 474 int &flags)
c801d85f 475{
f2593d0d 476 if ((point.y > m_y) && (point.y < m_y + theTree->GetLineHeight(this)))
c801d85f 477 {
3dbeaa52 478 if (point.y < m_y+theTree->GetLineHeight(this)/2 )
f2593d0d
RR
479 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
480 else
481 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
978f38c2 482
f2593d0d
RR
483 // 5 is the size of the plus sign
484 if ((point.x > m_xCross-5) && (point.x < m_xCross+5) &&
485 (point.y > m_yCross-5) && (point.y < m_yCross+5) &&
486 (IsExpanded() || HasPlus()))
487 {
488 flags|=wxTREE_HITTEST_ONITEMBUTTON;
489 return this;
490 }
d3a9f4af 491
f2593d0d
RR
492 if ((point.x >= m_x) && (point.x <= m_x+m_width))
493 {
494 int image_w = -1;
495 int image_h;
0ae7f2a2 496
f2593d0d
RR
497 // assuming every image (normal and selected ) has the same size !
498 if ( (GetImage() != NO_IMAGE) && theTree->m_imageListNormal )
499 theTree->m_imageListNormal->GetSize(GetImage(), image_w, image_h);
91b8de8d 500
f2593d0d
RR
501 if ((image_w != -1) && (point.x <= m_x + image_w + 1))
502 flags |= wxTREE_HITTEST_ONITEMICON;
503 else
504 flags |= wxTREE_HITTEST_ONITEMLABEL;
91b8de8d 505
f2593d0d
RR
506 return this;
507 }
91b8de8d 508
f2593d0d
RR
509 if (point.x < m_x)
510 flags |= wxTREE_HITTEST_ONITEMINDENT;
511 if (point.x > m_x+m_width)
512 flags |= wxTREE_HITTEST_ONITEMRIGHT;
513
514 return this;
515 }
516 else
c801d85f 517 {
f2593d0d
RR
518 if (!m_isCollapsed)
519 {
520 size_t count = m_children.Count();
521 for ( size_t n = 0; n < count; n++ )
522 {
523 wxGenericTreeItem *res = m_children[n]->HitTest( point, theTree, flags );
524 if ( res != NULL )
525 return res;
526 }
527 }
edaa81ae 528 }
f135ff73 529
f2593d0d 530 flags|=wxTREE_HITTEST_NOWHERE;
06b466c7 531
f2593d0d 532 return (wxGenericTreeItem*) NULL;
edaa81ae 533}
c801d85f 534
8dc99046
VZ
535int wxGenericTreeItem::GetCurrentImage() const
536{
537 int image = NO_IMAGE;
538 if ( IsExpanded() )
539 {
540 if ( IsSelected() )
541 {
542 image = GetImage(wxTreeItemIcon_SelectedExpanded);
543 }
544
545 if ( image == NO_IMAGE )
546 {
547 // we usually fall back to the normal item, but try just the
548 // expanded one (and not selected) first in this case
549 image = GetImage(wxTreeItemIcon_Expanded);
550 }
551 }
552 else // not expanded
553 {
554 if ( IsSelected() )
555 image = GetImage(wxTreeItemIcon_Selected);
556 }
557
558 // may be it doesn't have the specific image we want, try the default one
559 // instead
560 if ( image == NO_IMAGE )
561 {
562 image = GetImage();
563 }
564
565 return image;
566}
567
f135ff73 568// -----------------------------------------------------------------------------
941830cb 569// wxGenericTreeCtrl implementation
f135ff73
VZ
570// -----------------------------------------------------------------------------
571
941830cb 572IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl, wxScrolledWindow)
f135ff73 573
941830cb
JS
574BEGIN_EVENT_TABLE(wxGenericTreeCtrl,wxScrolledWindow)
575 EVT_PAINT (wxGenericTreeCtrl::OnPaint)
576 EVT_MOUSE_EVENTS (wxGenericTreeCtrl::OnMouse)
577 EVT_CHAR (wxGenericTreeCtrl::OnChar)
578 EVT_SET_FOCUS (wxGenericTreeCtrl::OnSetFocus)
579 EVT_KILL_FOCUS (wxGenericTreeCtrl::OnKillFocus)
580 EVT_IDLE (wxGenericTreeCtrl::OnIdle)
f135ff73
VZ
581END_EVENT_TABLE()
582
233058c7
JS
583#if !defined(__WXMSW__) || defined(__WIN16__)
584/*
585 * wxTreeCtrl has to be a real class or we have problems with
586 * the run-time information.
587 */
588
589IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl)
590#endif
591
f135ff73
VZ
592// -----------------------------------------------------------------------------
593// construction/destruction
594// -----------------------------------------------------------------------------
91b8de8d 595
941830cb 596void wxGenericTreeCtrl::Init()
c801d85f 597{
00e12320
RR
598 m_current =
599 m_key_current =
600 m_anchor = (wxGenericTreeItem *) NULL;
601 m_hasFocus = FALSE;
602 m_dirty = FALSE;
f135ff73 603
00e12320
RR
604 m_xScroll = 0;
605 m_yScroll = 0;
606 m_lineHeight = 10;
607 m_indent = 15;
608 m_spacing = 18;
f135ff73 609
00e12320 610 m_hilightBrush = new wxBrush
f135ff73
VZ
611 (
612 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT),
613 wxSOLID
614 );
615
00e12320
RR
616 m_imageListNormal =
617 m_imageListState = (wxImageList *) NULL;
46cd520d
VS
618 m_ownsImageListNormal =
619 m_ownsImageListState = FALSE;
978f38c2 620
00e12320 621 m_dragCount = 0;
3dbeaa52 622 m_isDragging = FALSE;
b3a7510d
VZ
623 m_dropTarget =
624 m_oldSelection = (wxGenericTreeItem *)NULL;
9dfbf520 625
00e12320 626 m_renameTimer = new wxTreeRenameTimer( this );
f6bcfd97 627 m_lastOnSame = FALSE;
f38374d0 628
00e12320
RR
629 m_normalFont = wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT );
630 m_boldFont = wxFont( m_normalFont.GetPointSize(),
eff869aa
RR
631 m_normalFont.GetFamily(),
632 m_normalFont.GetStyle(),
633 wxBOLD,
634 m_normalFont.GetUnderlined());
edaa81ae 635}
c801d85f 636
941830cb 637bool wxGenericTreeCtrl::Create(wxWindow *parent, wxWindowID id,
f135ff73 638 const wxPoint& pos, const wxSize& size,
978f38c2 639 long style,
674ac8b9
VZ
640 const wxValidator &validator,
641 const wxString& name )
c801d85f 642{
00e12320 643 wxScrolledWindow::Create( parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name );
978f38c2 644
ce4169a4 645#if wxUSE_VALIDATORS
00e12320 646 SetValidator( validator );
ce4169a4 647#endif
f135ff73 648
91fc2bdc 649 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) );
00e12320
RR
650// m_dottedPen = wxPen( "grey", 0, wxDOT ); too slow under XFree86
651 m_dottedPen = wxPen( "grey", 0, 0 );
f135ff73 652
00e12320 653 return TRUE;
edaa81ae 654}
c801d85f 655
941830cb 656wxGenericTreeCtrl::~wxGenericTreeCtrl()
c801d85f 657{
00e12320 658 wxDELETE( m_hilightBrush );
a43a4f9d 659
00e12320 660 DeleteAllItems();
9dfbf520 661
00e12320 662 delete m_renameTimer;
46cd520d
VS
663 if (m_ownsImageListNormal) delete m_imageListNormal;
664 if (m_ownsImageListState) delete m_imageListState;
edaa81ae 665}
c801d85f 666
f135ff73
VZ
667// -----------------------------------------------------------------------------
668// accessors
669// -----------------------------------------------------------------------------
670
941830cb 671size_t wxGenericTreeCtrl::GetCount() const
c801d85f 672{
f2593d0d 673 return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount();
edaa81ae 674}
c801d85f 675
941830cb 676void wxGenericTreeCtrl::SetIndent(unsigned int indent)
c801d85f 677{
f2593d0d
RR
678 m_indent = indent;
679 m_dirty = TRUE;
cf724bce
RR
680}
681
941830cb 682void wxGenericTreeCtrl::SetSpacing(unsigned int spacing)
cf724bce 683{
f2593d0d
RR
684 m_spacing = spacing;
685 m_dirty = TRUE;
f135ff73 686}
74bedbeb 687
941830cb 688size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
4832f7c0 689{
f2593d0d 690 wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") );
4832f7c0 691
941830cb 692 return ((wxGenericTreeItem*) item.m_pItem)->GetChildrenCount(recursively);
4832f7c0
VZ
693}
694
f135ff73
VZ
695// -----------------------------------------------------------------------------
696// functions to work with tree items
697// -----------------------------------------------------------------------------
74bedbeb 698
941830cb 699wxString wxGenericTreeCtrl::GetItemText(const wxTreeItemId& item) const
f135ff73 700{
f2593d0d 701 wxCHECK_MSG( item.IsOk(), wxT(""), wxT("invalid tree item") );
4832f7c0 702
941830cb 703 return ((wxGenericTreeItem*) item.m_pItem)->GetText();
edaa81ae 704}
74bedbeb 705
941830cb 706int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId& item,
8dc99046 707 wxTreeItemIcon which) const
74bedbeb 708{
f2593d0d 709 wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") );
4832f7c0 710
941830cb 711 return ((wxGenericTreeItem*) item.m_pItem)->GetImage(which);
edaa81ae 712}
c801d85f 713
941830cb 714wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const
c801d85f 715{
f2593d0d 716 wxCHECK_MSG( item.IsOk(), NULL, wxT("invalid tree item") );
4832f7c0 717
941830cb 718 return ((wxGenericTreeItem*) item.m_pItem)->GetData();
edaa81ae 719}
c801d85f 720
941830cb 721void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
f135ff73 722{
f2593d0d 723 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
4832f7c0 724
f2593d0d 725 wxClientDC dc(this);
941830cb 726 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
f2593d0d
RR
727 pItem->SetText(text);
728 CalculateSize(pItem, dc);
729 RefreshLine(pItem);
f135ff73 730}
c801d85f 731
941830cb 732void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId& item,
8dc99046
VZ
733 int image,
734 wxTreeItemIcon which)
f135ff73 735{
223d09f6 736 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
4832f7c0 737
941830cb 738 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
8dc99046 739 pItem->SetImage(image, which);
4832f7c0 740
8dc99046
VZ
741 wxClientDC dc(this);
742 CalculateSize(pItem, dc);
743 RefreshLine(pItem);
edaa81ae 744}
c801d85f 745
941830cb 746void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
c801d85f 747{
f2593d0d 748 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
4832f7c0 749
941830cb 750 ((wxGenericTreeItem*) item.m_pItem)->SetData(data);
edaa81ae 751}
c801d85f 752
941830cb 753void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
c801d85f 754{
f2593d0d 755 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
4832f7c0 756
941830cb 757 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
f2593d0d
RR
758 pItem->SetHasPlus(has);
759 RefreshLine(pItem);
edaa81ae 760}
c801d85f 761
941830cb 762void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
ef44a621 763{
9ec64fa7 764 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
ef44a621 765
9ec64fa7 766 // avoid redrawing the tree if no real change
941830cb 767 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
9ec64fa7
VZ
768 if ( pItem->IsBold() != bold )
769 {
770 pItem->SetBold(bold);
771 RefreshLine(pItem);
772 }
773}
774
941830cb 775void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId& item,
9ec64fa7
VZ
776 const wxColour& col)
777{
778 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
779
941830cb 780 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
9ec64fa7
VZ
781 pItem->Attr().SetTextColour(col);
782 RefreshLine(pItem);
783}
784
941830cb 785void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
9ec64fa7
VZ
786 const wxColour& col)
787{
788 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
789
941830cb 790 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
9ec64fa7
VZ
791 pItem->Attr().SetBackgroundColour(col);
792 RefreshLine(pItem);
793}
794
941830cb 795void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font)
9ec64fa7
VZ
796{
797 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
798
941830cb 799 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
9ec64fa7 800 pItem->Attr().SetFont(font);
ef44a621 801 RefreshLine(pItem);
ef44a621
VZ
802}
803
f135ff73
VZ
804// -----------------------------------------------------------------------------
805// item status inquiries
806// -----------------------------------------------------------------------------
807
1ed01484 808bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& item) const
c801d85f 809{
1ed01484
JS
810 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
811
812 // An item is only visible if it's not a descendant of a collapsed item
813 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
814 wxGenericTreeItem* parent = pItem->GetParent();
815 while (parent)
816 {
817 if (!parent->IsExpanded())
818 return FALSE;
819 parent = parent->GetParent();
820 }
821
822 int startX, startY;
823 GetViewStart(& startX, & startY);
824
825 wxSize clientSize = GetClientSize();
826
827 wxRect rect;
828 if (!GetBoundingRect(item, rect))
829 return FALSE;
830 if (rect.GetWidth() == 0 || rect.GetHeight() == 0)
831 return FALSE;
832 if (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y)
833 return FALSE;
834 if (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x)
835 return FALSE;
f135ff73 836
f2593d0d 837 return TRUE;
edaa81ae 838}
c801d85f 839
941830cb 840bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
c801d85f 841{
f2593d0d 842 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
4832f7c0 843
941830cb 844 return !((wxGenericTreeItem*) item.m_pItem)->GetChildren().IsEmpty();
edaa81ae 845}
c801d85f 846
941830cb 847bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId& item) const
c801d85f 848{
f2593d0d 849 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
4832f7c0 850
941830cb 851 return ((wxGenericTreeItem*) item.m_pItem)->IsExpanded();
f135ff73 852}
29d87bba 853
941830cb 854bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId& item) const
f135ff73 855{
f2593d0d 856 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
4832f7c0 857
941830cb 858 return ((wxGenericTreeItem*) item.m_pItem)->IsSelected();
f135ff73 859}
29d87bba 860
941830cb 861bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const
ef44a621 862{
f2593d0d 863 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
ef44a621 864
941830cb 865 return ((wxGenericTreeItem*) item.m_pItem)->IsBold();
ef44a621
VZ
866}
867
f135ff73
VZ
868// -----------------------------------------------------------------------------
869// navigation
870// -----------------------------------------------------------------------------
29d87bba 871
941830cb 872wxTreeItemId wxGenericTreeCtrl::GetParent(const wxTreeItemId& item) const
f135ff73 873{
223d09f6 874 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
389cdc7a 875
941830cb 876 return ((wxGenericTreeItem*) item.m_pItem)->GetParent();
f135ff73 877}
29d87bba 878
941830cb 879wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
f135ff73 880{
223d09f6 881 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
29d87bba 882
f135ff73
VZ
883 cookie = 0;
884 return GetNextChild(item, cookie);
885}
29d87bba 886
941830cb 887wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
f135ff73 888{
223d09f6 889 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
29d87bba 890
941830cb 891 wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
4832f7c0
VZ
892 if ( (size_t)cookie < children.Count() )
893 {
06b466c7 894 return children.Item((size_t)cookie++);
4832f7c0
VZ
895 }
896 else
897 {
898 // there are no more of them
1e6d9499 899 return wxTreeItemId();
4832f7c0 900 }
f135ff73 901}
29d87bba 902
941830cb 903wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const
978f38c2 904{
223d09f6 905 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
978f38c2 906
941830cb 907 wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
0a240683 908 return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last()));
978f38c2
VZ
909}
910
941830cb 911wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
f135ff73 912{
223d09f6 913 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
f135ff73 914
941830cb 915 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
f135ff73
VZ
916 wxGenericTreeItem *parent = i->GetParent();
917 if ( parent == NULL )
918 {
919 // root item doesn't have any siblings
1e6d9499 920 return wxTreeItemId();
edaa81ae 921 }
4832f7c0 922
91b8de8d 923 wxArrayGenericTreeItems& siblings = parent->GetChildren();
f135ff73 924 int index = siblings.Index(i);
3c67202d 925 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
29d87bba 926
f135ff73 927 size_t n = (size_t)(index + 1);
fdd8d7b5 928 return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
edaa81ae 929}
c801d85f 930
941830cb 931wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
c801d85f 932{
223d09f6 933 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
f135ff73 934
941830cb 935 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
f135ff73
VZ
936 wxGenericTreeItem *parent = i->GetParent();
937 if ( parent == NULL )
c801d85f 938 {
f135ff73 939 // root item doesn't have any siblings
1e6d9499 940 return wxTreeItemId();
edaa81ae 941 }
4832f7c0 942
91b8de8d 943 wxArrayGenericTreeItems& siblings = parent->GetChildren();
f135ff73 944 int index = siblings.Index(i);
3c67202d 945 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
29d87bba 946
fdd8d7b5
VZ
947 return index == 0 ? wxTreeItemId()
948 : wxTreeItemId(siblings[(size_t)(index - 1)]);
f135ff73 949}
389cdc7a 950
1ed01484
JS
951// Only for internal use right now, but should probably be public
952wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const
f135ff73 953{
1ed01484
JS
954 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
955
956 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
957
958 // First see if there are any children.
959 wxArrayGenericTreeItems& children = i->GetChildren();
960 if (children.GetCount() > 0)
961 {
962 return children.Item(0);
963 }
964 else
965 {
966 // Try a sibling of this or ancestor instead
967 wxTreeItemId p = item;
968 wxTreeItemId toFind;
969 do
970 {
971 toFind = GetNextSibling(p);
972 p = GetParent(p);
973 } while (p.IsOk() && !toFind.IsOk());
974 return toFind;
975 }
976}
977
978wxTreeItemId wxGenericTreeCtrl::GetPrev(const wxTreeItemId& item) const
979{
980 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
981
223d09f6 982 wxFAIL_MSG(wxT("not implemented"));
29d87bba 983
1e6d9499 984 return wxTreeItemId();
f135ff73 985}
29d87bba 986
1ed01484
JS
987wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
988{
989 wxTreeItemId id = GetRootItem();
990 if (!id.IsOk())
991 return id;
992
993 do
994 {
995 if (IsVisible(id))
996 return id;
997 id = GetNext(id);
998 } while (id.IsOk());
999
1000 return wxTreeItemId();
1001}
1002
941830cb 1003wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
f135ff73 1004{
223d09f6 1005 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
29d87bba 1006
1ed01484
JS
1007 wxTreeItemId id = item;
1008 while (id.IsOk())
1009 {
1010 id = GetNext(id);
29d87bba 1011
1ed01484
JS
1012 if (id.IsOk() && IsVisible(id))
1013 return id;
1014 }
1e6d9499 1015 return wxTreeItemId();
f135ff73 1016}
29d87bba 1017
941830cb 1018wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
f135ff73 1019{
223d09f6 1020 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
29d87bba 1021
223d09f6 1022 wxFAIL_MSG(wxT("not implemented"));
29d87bba 1023
1e6d9499 1024 return wxTreeItemId();
edaa81ae 1025}
c801d85f 1026
f135ff73
VZ
1027// -----------------------------------------------------------------------------
1028// operations
1029// -----------------------------------------------------------------------------
1030
941830cb 1031wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
f135ff73
VZ
1032 size_t previous,
1033 const wxString& text,
1034 int image, int selImage,
1035 wxTreeItemData *data)
c801d85f 1036{
941830cb 1037 wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
f49f2b0c
RR
1038 if ( !parent )
1039 {
1040 // should we give a warning here?
1041 return AddRoot(text, image, selImage, data);
1042 }
4832f7c0 1043
f49f2b0c 1044 wxClientDC dc(this);
f38374d0 1045 wxGenericTreeItem *item =
f49f2b0c 1046 new wxGenericTreeItem( parent, text, dc, image, selImage, data );
74bedbeb 1047
f49f2b0c
RR
1048 if ( data != NULL )
1049 {
40fab78b 1050 data->m_pItem = (long) item;
f49f2b0c 1051 }
74bedbeb 1052
f49f2b0c 1053 parent->Insert( item, previous );
ef44a621 1054
f49f2b0c 1055 m_dirty = TRUE;
389cdc7a 1056
f49f2b0c 1057 return item;
4c681997
RR
1058}
1059
941830cb 1060wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
f135ff73
VZ
1061 int image, int selImage,
1062 wxTreeItemData *data)
4c681997 1063{
f49f2b0c 1064 wxCHECK_MSG( !m_anchor, wxTreeItemId(), wxT("tree can have only one root") );
389cdc7a 1065
f49f2b0c
RR
1066 wxClientDC dc(this);
1067 m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
f135ff73 1068 image, selImage, data);
f49f2b0c
RR
1069 if ( data != NULL )
1070 {
40fab78b 1071 data->m_pItem = (long) m_anchor;
f49f2b0c 1072 }
f38374d0 1073
f49f2b0c
RR
1074 if (!HasFlag(wxTR_MULTIPLE))
1075 {
1076 m_current = m_key_current = m_anchor;
06b466c7 1077 m_current->SetHilight( TRUE );
f49f2b0c 1078 }
389cdc7a 1079
f6bcfd97 1080 m_dirty = TRUE;
a32dd690 1081
f49f2b0c 1082 return m_anchor;
edaa81ae 1083}
c801d85f 1084
941830cb 1085wxTreeItemId wxGenericTreeCtrl::PrependItem(const wxTreeItemId& parent,
f135ff73
VZ
1086 const wxString& text,
1087 int image, int selImage,
1088 wxTreeItemData *data)
c801d85f 1089{
f2593d0d 1090 return DoInsertItem(parent, 0u, text, image, selImage, data);
edaa81ae 1091}
c801d85f 1092
941830cb 1093wxTreeItemId wxGenericTreeCtrl::InsertItem(const wxTreeItemId& parentId,
f135ff73
VZ
1094 const wxTreeItemId& idPrevious,
1095 const wxString& text,
1096 int image, int selImage,
1097 wxTreeItemData *data)
c801d85f 1098{
941830cb 1099 wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
f2593d0d
RR
1100 if ( !parent )
1101 {
1102 // should we give a warning here?
1103 return AddRoot(text, image, selImage, data);
1104 }
c801d85f 1105
941830cb 1106 int index = parent->GetChildren().Index((wxGenericTreeItem*) idPrevious.m_pItem);
f2593d0d 1107 wxASSERT_MSG( index != wxNOT_FOUND,
941830cb 1108 wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") );
06b466c7 1109
f2593d0d
RR
1110 return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data);
1111}
1112
941830cb 1113wxTreeItemId wxGenericTreeCtrl::InsertItem(const wxTreeItemId& parentId,
f2593d0d
RR
1114 size_t before,
1115 const wxString& text,
1116 int image, int selImage,
1117 wxTreeItemData *data)
1118{
941830cb 1119 wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
f2593d0d
RR
1120 if ( !parent )
1121 {
1122 // should we give a warning here?
1123 return AddRoot(text, image, selImage, data);
1124 }
1125
1126 return DoInsertItem(parentId, before, text, image, selImage, data);
edaa81ae 1127}
c801d85f 1128
941830cb 1129wxTreeItemId wxGenericTreeCtrl::AppendItem(const wxTreeItemId& parentId,
f135ff73
VZ
1130 const wxString& text,
1131 int image, int selImage,
1132 wxTreeItemData *data)
74bedbeb 1133{
941830cb 1134 wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
f2593d0d
RR
1135 if ( !parent )
1136 {
1137 // should we give a warning here?
1138 return AddRoot(text, image, selImage, data);
1139 }
f135ff73 1140
f2593d0d
RR
1141 return DoInsertItem( parent, parent->GetChildren().Count(), text,
1142 image, selImage, data);
74bedbeb
VZ
1143}
1144
941830cb 1145void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
a43a4f9d 1146{
f2593d0d 1147 wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
40fab78b 1148 event.m_item = (long) item;
f2593d0d
RR
1149 event.SetEventObject( this );
1150 ProcessEvent( event );
a43a4f9d
VZ
1151}
1152
941830cb 1153void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
372edb9d 1154{
941830cb 1155 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
a43a4f9d 1156 item->DeleteChildren(this);
372edb9d
VZ
1157
1158 m_dirty = TRUE;
1159}
1160
941830cb 1161void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
c801d85f 1162{
941830cb 1163 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
ff5bf259 1164
aaa2f297
VZ
1165 // don't stay with invalid m_key_current or we will crash in the next call
1166 // to OnChar()
1167 bool changeKeyCurrent = FALSE;
1168 wxGenericTreeItem *itemKey = m_key_current;
1169 while ( itemKey && !changeKeyCurrent )
1170 {
1171 if ( itemKey == item )
1172 {
1173 // m_key_current is a descendant of the item being deleted
1174 changeKeyCurrent = TRUE;
1175 }
1176 else
1177 {
1178 itemKey = itemKey->GetParent();
1179 }
1180 }
1181
1182 wxGenericTreeItem *parent = item->GetParent();
97d7bfb8
RR
1183 if ( parent )
1184 {
1185 parent->GetChildren().Remove( item ); // remove by value
1186 }
f135ff73 1187
aaa2f297
VZ
1188 if ( changeKeyCurrent )
1189 {
1190 // may be NULL or not
1191 m_key_current = parent;
1192 }
1193
97d7bfb8
RR
1194 item->DeleteChildren(this);
1195 SendDeleteEvent(item);
1196 delete item;
f135ff73 1197
97d7bfb8 1198 m_dirty = TRUE;
edaa81ae 1199}
c801d85f 1200
941830cb 1201void wxGenericTreeCtrl::DeleteAllItems()
c801d85f 1202{
97d7bfb8
RR
1203 if ( m_anchor )
1204 {
1205 m_anchor->DeleteChildren(this);
1206 delete m_anchor;
a43a4f9d 1207
97d7bfb8 1208 m_anchor = NULL;
f135ff73 1209
97d7bfb8
RR
1210 m_dirty = TRUE;
1211 }
edaa81ae
RR
1212}
1213
941830cb 1214void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
edaa81ae 1215{
941830cb 1216 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
f135ff73 1217
941830cb 1218 wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") );
f6bcfd97 1219
f2593d0d
RR
1220 if ( !item->HasPlus() )
1221 return;
978f38c2 1222
f2593d0d
RR
1223 if ( item->IsExpanded() )
1224 return;
f135ff73 1225
f2593d0d 1226 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
40fab78b 1227 event.m_item = (long) item;
f2593d0d 1228 event.SetEventObject( this );
004fd0c8 1229
f2593d0d
RR
1230 if ( ProcessEvent( event ) && !event.IsAllowed() )
1231 {
1232 // cancelled by program
1233 return;
1234 }
4832f7c0 1235
f2593d0d
RR
1236 item->Expand();
1237 CalculatePositions();
f135ff73 1238
f2593d0d 1239 RefreshSubtree(item);
f135ff73 1240
f2593d0d
RR
1241 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
1242 ProcessEvent( event );
edaa81ae
RR
1243}
1244
941830cb 1245void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId& item)
f6bcfd97
BP
1246{
1247 Expand(item);
1248 if ( IsExpanded(item) )
1249 {
1250 long cookie;
1251 wxTreeItemId child = GetFirstChild(item, cookie);
1252 while ( child.IsOk() )
1253 {
1254 ExpandAll(child);
1255
1256 child = GetNextChild(item, cookie);
1257 }
1258 }
1259}
1260
941830cb 1261void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
edaa81ae 1262{
941830cb 1263 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
f135ff73 1264
f2593d0d
RR
1265 if ( !item->IsExpanded() )
1266 return;
f135ff73 1267
f2593d0d 1268 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
40fab78b 1269 event.m_item = (long) item;
f2593d0d
RR
1270 event.SetEventObject( this );
1271 if ( ProcessEvent( event ) && !event.IsAllowed() )
1272 {
1273 // cancelled by program
1274 return;
1275 }
4832f7c0 1276
f2593d0d 1277 item->Collapse();
f135ff73 1278
f2593d0d
RR
1279 wxArrayGenericTreeItems& children = item->GetChildren();
1280 size_t count = children.Count();
1281 for ( size_t n = 0; n < count; n++ )
1282 {
1283 Collapse(children[n]);
1284 }
f135ff73 1285
f2593d0d 1286 CalculatePositions();
f135ff73 1287
f2593d0d 1288 RefreshSubtree(item);
f135ff73 1289
f2593d0d
RR
1290 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
1291 ProcessEvent( event );
edaa81ae 1292}
c801d85f 1293
941830cb 1294void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
c801d85f 1295{
00e12320
RR
1296 Collapse(item);
1297 DeleteChildren(item);
edaa81ae 1298}
c801d85f 1299
941830cb 1300void wxGenericTreeCtrl::Toggle(const wxTreeItemId& itemId)
c801d85f 1301{
941830cb 1302 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
389cdc7a 1303
00e12320
RR
1304 if (item->IsExpanded())
1305 Collapse(itemId);
1306 else
1307 Expand(itemId);
f135ff73 1308}
389cdc7a 1309
941830cb 1310void wxGenericTreeCtrl::Unselect()
f135ff73 1311{
00e12320
RR
1312 if (m_current)
1313 {
1314 m_current->SetHilight( FALSE );
1315 RefreshLine( m_current );
1316 }
edaa81ae 1317}
c801d85f 1318
941830cb 1319void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
389cdc7a 1320{
00e12320
RR
1321 if (item->IsSelected())
1322 {
1323 item->SetHilight(FALSE);
1324 RefreshLine(item);
1325 }
d3a9f4af 1326
00e12320 1327 if (item->HasChildren())
88ac883a 1328 {
00e12320
RR
1329 wxArrayGenericTreeItems& children = item->GetChildren();
1330 size_t count = children.Count();
1331 for ( size_t n = 0; n < count; ++n )
1332 {
1333 UnselectAllChildren(children[n]);
1334 }
88ac883a
VZ
1335 }
1336}
f135ff73 1337
941830cb 1338void wxGenericTreeCtrl::UnselectAll()
88ac883a 1339{
941830cb 1340 UnselectAllChildren((wxGenericTreeItem*) GetRootItem().m_pItem);
88ac883a
VZ
1341}
1342
1343// Recursive function !
1344// To stop we must have crt_item<last_item
91b8de8d 1345// Algorithm :
88ac883a 1346// Tag all next children, when no more children,
d3a9f4af 1347// Move to parent (not to tag)
91b8de8d 1348// Keep going... if we found last_item, we stop.
941830cb 1349bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select)
88ac883a
VZ
1350{
1351 wxGenericTreeItem *parent = crt_item->GetParent();
1352
00e12320
RR
1353 if (parent == NULL) // This is root item
1354 return TagAllChildrenUntilLast(crt_item, last_item, select);
88ac883a 1355
91b8de8d 1356 wxArrayGenericTreeItems& children = parent->GetChildren();
88ac883a
VZ
1357 int index = children.Index(crt_item);
1358 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
1359
1360 size_t count = children.Count();
1361 for (size_t n=(size_t)(index+1); n<count; ++n)
00e12320
RR
1362 {
1363 if (TagAllChildrenUntilLast(children[n], last_item, select)) return TRUE;
1364 }
88ac883a
VZ
1365
1366 return TagNextChildren(parent, last_item, select);
1367}
1368
941830cb 1369bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select)
88ac883a 1370{
00e12320
RR
1371 crt_item->SetHilight(select);
1372 RefreshLine(crt_item);
d3a9f4af 1373
06b466c7 1374 if (crt_item==last_item)
00e12320 1375 return TRUE;
88ac883a 1376
00e12320 1377 if (crt_item->HasChildren())
88ac883a 1378 {
00e12320
RR
1379 wxArrayGenericTreeItems& children = crt_item->GetChildren();
1380 size_t count = children.Count();
1381 for ( size_t n = 0; n < count; ++n )
1382 {
06b466c7 1383 if (TagAllChildrenUntilLast(children[n], last_item, select))
00e12320 1384 return TRUE;
06b466c7 1385 }
88ac883a 1386 }
d3a9f4af 1387
c0de7af4 1388 return FALSE;
88ac883a
VZ
1389}
1390
941830cb 1391void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2)
88ac883a 1392{
f2593d0d
RR
1393 // item2 is not necessary after item1
1394 wxGenericTreeItem *first=NULL, *last=NULL;
88ac883a 1395
f2593d0d
RR
1396 // choice first' and 'last' between item1 and item2
1397 if (item1->GetY()<item2->GetY())
06b466c7 1398 {
f2593d0d
RR
1399 first=item1;
1400 last=item2;
1401 }
1402 else
1403 {
1404 first=item2;
1405 last=item1;
1406 }
88ac883a 1407
f2593d0d 1408 bool select = m_current->IsSelected();
d3a9f4af 1409
f2593d0d
RR
1410 if ( TagAllChildrenUntilLast(first,last,select) )
1411 return;
88ac883a 1412
f2593d0d 1413 TagNextChildren(first,last,select);
88ac883a
VZ
1414}
1415
941830cb 1416void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
c193b707
VZ
1417 bool unselect_others,
1418 bool extended_select)
d3a9f4af 1419{
223d09f6 1420 wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
8b04a037 1421
88ac883a 1422 bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE);
941830cb 1423 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
88ac883a
VZ
1424
1425 //wxCHECK_RET( ( (!unselect_others) && is_single),
223d09f6 1426 // wxT("this is a single selection tree") );
88ac883a
VZ
1427
1428 // to keep going anyhow !!!
d3a9f4af 1429 if (is_single)
8dc99046
VZ
1430 {
1431 if (item->IsSelected())
1432 return; // nothing to do
1433 unselect_others = TRUE;
1434 extended_select = FALSE;
1435 }
1436 else if ( unselect_others && item->IsSelected() )
1437 {
1438 // selection change if there is more than one item currently selected
1439 wxArrayTreeItemIds selected_items;
1440 if ( GetSelections(selected_items) == 1 )
1441 return;
1442 }
d3a9f4af 1443
f135ff73 1444 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
40fab78b
JS
1445 event.m_item = (long) item;
1446 event.m_itemOld = (long) m_current;
f135ff73 1447 event.SetEventObject( this );
91b8de8d 1448 // TODO : Here we don't send any selection mode yet !
d3a9f4af 1449
f98e2558 1450 if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
f135ff73
VZ
1451 return;
1452
88ac883a
VZ
1453 // ctrl press
1454 if (unselect_others)
389cdc7a 1455 {
88ac883a 1456 if (is_single) Unselect(); // to speed up thing
c193b707 1457 else UnselectAll();
edaa81ae 1458 }
f135ff73 1459
88ac883a 1460 // shift press
d3a9f4af 1461 if (extended_select)
88ac883a 1462 {
aaa2f297
VZ
1463 if ( !m_current )
1464 {
1465 m_current =
941830cb 1466 m_key_current = (wxGenericTreeItem*) GetRootItem().m_pItem;
aaa2f297
VZ
1467 }
1468
88ac883a
VZ
1469 // don't change the mark (m_current)
1470 SelectItemRange(m_current, item);
1471 }
1472 else
1473 {
c0de7af4 1474 bool select=TRUE; // the default
88ac883a 1475
c193b707
VZ
1476 // Check if we need to toggle hilight (ctrl mode)
1477 if (!unselect_others)
8dc99046 1478 select=!item->IsSelected();
88ac883a 1479
91b8de8d 1480 m_current = m_key_current = item;
c193b707
VZ
1481 m_current->SetHilight(select);
1482 RefreshLine( m_current );
88ac883a 1483 }
389cdc7a 1484
f135ff73 1485 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
6daa0637 1486 GetEventHandler()->ProcessEvent( event );
389cdc7a
VZ
1487}
1488
941830cb 1489void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item,
9dfbf520 1490 wxArrayTreeItemIds &array) const
c801d85f 1491{
8dc99046 1492 if ( item->IsSelected() )
9dfbf520 1493 array.Add(wxTreeItemId(item));
91b8de8d 1494
9dfbf520 1495 if ( item->HasChildren() )
91b8de8d 1496 {
9dfbf520
VZ
1497 wxArrayGenericTreeItems& children = item->GetChildren();
1498 size_t count = children.GetCount();
1499 for ( size_t n = 0; n < count; ++n )
f6bcfd97 1500 FillArray(children[n], array);
91b8de8d
RR
1501 }
1502}
1503
941830cb 1504size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const
91b8de8d
RR
1505{
1506 array.Empty();
f6bcfd97
BP
1507 wxTreeItemId idRoot = GetRootItem();
1508 if ( idRoot.IsOk() )
1509 {
941830cb 1510 FillArray((wxGenericTreeItem*) idRoot.m_pItem, array);
f6bcfd97
BP
1511 }
1512 //else: the tree is empty, so no selections
91b8de8d
RR
1513
1514 return array.Count();
1515}
1516
941830cb 1517void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
d3a9f4af 1518{
91b8de8d
RR
1519 if (!item.IsOk()) return;
1520
941830cb 1521 wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
ef44a621 1522
f65635b5
VZ
1523 // first expand all parent branches
1524 wxGenericTreeItem *parent = gitem->GetParent();
5391f772 1525 while ( parent )
f65635b5 1526 {
8dc99046 1527 Expand(parent);
f65635b5
VZ
1528 parent = parent->GetParent();
1529 }
1530
5391f772 1531 //if (parent) CalculatePositions();
91b8de8d
RR
1532
1533 ScrollTo(item);
1534}
1535
941830cb 1536void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
91b8de8d
RR
1537{
1538 if (!item.IsOk()) return;
1539
dc6c62a9
RR
1540 // We have to call this here because the label in
1541 // question might just have been added and no screen
1542 // update taken place.
1543 if (m_dirty) wxYield();
1544
941830cb 1545 wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
91b8de8d 1546
f65635b5 1547 // now scroll to the item
0659e7ee 1548 int item_y = gitem->GetY();
8dc99046 1549
0659e7ee
RR
1550 int start_x = 0;
1551 int start_y = 0;
1552 ViewStart( &start_x, &start_y );
91b8de8d 1553 start_y *= PIXELS_PER_UNIT;
978f38c2 1554
a93109d5
RR
1555 int client_h = 0;
1556 int client_w = 0;
1557 GetClientSize( &client_w, &client_h );
ef44a621 1558
0659e7ee
RR
1559 if (item_y < start_y+3)
1560 {
91b8de8d 1561 // going down
0659e7ee
RR
1562 int x = 0;
1563 int y = 0;
91b8de8d
RR
1564 m_anchor->GetSize( x, y, this );
1565 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
c7a9fa36 1566 x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
0659e7ee 1567 int x_pos = GetScrollPos( wxHORIZONTAL );
c193b707 1568 // Item should appear at top
91b8de8d 1569 SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT );
0659e7ee 1570 }
91b8de8d 1571 else if (item_y+GetLineHeight(gitem) > start_y+client_h)
0659e7ee 1572 {
c7a9fa36
RR
1573 // going up
1574 int x = 0;
1575 int y = 0;
1576 m_anchor->GetSize( x, y, this );
1577 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
1578 x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
1579 item_y += PIXELS_PER_UNIT+2;
1580 int x_pos = GetScrollPos( wxHORIZONTAL );
c193b707 1581 // Item should appear at bottom
c7a9fa36 1582 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 1583 }
edaa81ae 1584}
c801d85f 1585
e1ee62bd 1586// FIXME: tree sorting functions are not reentrant and not MT-safe!
941830cb 1587static wxGenericTreeCtrl *s_treeBeingSorted = NULL;
0659e7ee 1588
004fd0c8 1589static int LINKAGEMODE tree_ctrl_compare_func(wxGenericTreeItem **item1,
e1ee62bd 1590 wxGenericTreeItem **item2)
edaa81ae 1591{
941830cb 1592 wxCHECK_MSG( s_treeBeingSorted, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") );
e1ee62bd
VZ
1593
1594 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
0659e7ee
RR
1595}
1596
941830cb 1597int wxGenericTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
e1ee62bd 1598 const wxTreeItemId& item2)
0659e7ee 1599{
87138c52 1600 return wxStrcmp(GetItemText(item1), GetItemText(item2));
e1ee62bd
VZ
1601}
1602
941830cb 1603void wxGenericTreeCtrl::SortChildren(const wxTreeItemId& itemId)
e1ee62bd 1604{
223d09f6 1605 wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
e1ee62bd 1606
941830cb 1607 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
978f38c2 1608
e1ee62bd 1609 wxCHECK_RET( !s_treeBeingSorted,
941830cb 1610 wxT("wxGenericTreeCtrl::SortChildren is not reentrant") );
e1ee62bd 1611
91b8de8d 1612 wxArrayGenericTreeItems& children = item->GetChildren();
e1ee62bd
VZ
1613 if ( children.Count() > 1 )
1614 {
1615 s_treeBeingSorted = this;
1616 children.Sort(tree_ctrl_compare_func);
1617 s_treeBeingSorted = NULL;
978f38c2 1618
e1ee62bd
VZ
1619 m_dirty = TRUE;
1620 }
1621 //else: don't make the tree dirty as nothing changed
edaa81ae
RR
1622}
1623
941830cb 1624wxImageList *wxGenericTreeCtrl::GetImageList() const
edaa81ae 1625{
f135ff73 1626 return m_imageListNormal;
edaa81ae
RR
1627}
1628
941830cb 1629wxImageList *wxGenericTreeCtrl::GetStateImageList() const
c801d85f 1630{
f135ff73 1631 return m_imageListState;
edaa81ae 1632}
c801d85f 1633
941830cb 1634void wxGenericTreeCtrl::SetImageList(wxImageList *imageList)
e2414cbe 1635{
46cd520d
VS
1636 if (m_ownsImageListNormal) delete m_imageListNormal;
1637
f2593d0d 1638 m_imageListNormal = imageList;
46cd520d 1639 m_ownsImageListNormal = FALSE;
91b8de8d 1640
2c8e4738
VZ
1641 if ( !m_imageListNormal )
1642 return;
1643
f2593d0d 1644 // Calculate a m_lineHeight value from the image sizes.
941830cb 1645 // May be toggle off. Then wxGenericTreeCtrl will spread when
f2593d0d 1646 // necessary (which might look ugly).
f2593d0d
RR
1647 wxClientDC dc(this);
1648 m_lineHeight = (int)(dc.GetCharHeight() + 4);
1649 int width = 0, height = 0,
1650 n = m_imageListNormal->GetImageCount();
06b466c7 1651
f2593d0d
RR
1652 for (int i = 0; i < n ; i++)
1653 {
1654 m_imageListNormal->GetSize(i, width, height);
1655 if (height > m_lineHeight) m_lineHeight = height;
1656 }
91b8de8d 1657
06b466c7 1658 if (m_lineHeight < 40)
f2593d0d 1659 m_lineHeight += 2; // at least 2 pixels
06b466c7 1660 else
f2593d0d 1661 m_lineHeight += m_lineHeight/10; // otherwise 10% extra spacing
edaa81ae 1662}
e2414cbe 1663
941830cb 1664void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList)
e2414cbe 1665{
46cd520d 1666 if (m_ownsImageListState) delete m_imageListState;
f135ff73 1667 m_imageListState = imageList;
46cd520d
VS
1668 m_ownsImageListState = FALSE;
1669}
1670
1671void wxGenericTreeCtrl::AssignImageList(wxImageList *imageList)
1672{
1673 SetImageList(imageList);
1674 m_ownsImageListNormal = TRUE;
1675}
1676
1677void wxGenericTreeCtrl::AssignStateImageList(wxImageList *imageList)
1678{
1679 SetStateImageList(imageList);
1680 m_ownsImageListState = TRUE;
edaa81ae 1681}
e2414cbe 1682
f135ff73
VZ
1683// -----------------------------------------------------------------------------
1684// helpers
1685// -----------------------------------------------------------------------------
0659e7ee 1686
941830cb 1687void wxGenericTreeCtrl::AdjustMyScrollbars()
c801d85f 1688{
0659e7ee
RR
1689 if (m_anchor)
1690 {
1691 int x = 0;
1692 int y = 0;
91b8de8d 1693 m_anchor->GetSize( x, y, this );
c193b707 1694 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
c7a9fa36 1695 x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
0659e7ee
RR
1696 int x_pos = GetScrollPos( wxHORIZONTAL );
1697 int y_pos = GetScrollPos( wxVERTICAL );
91b8de8d 1698 SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, y_pos );
0659e7ee
RR
1699 }
1700 else
1701 {
1702 SetScrollbars( 0, 0, 0, 0 );
1703 }
edaa81ae 1704}
c801d85f 1705
941830cb 1706int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem *item) const
91b8de8d 1707{
dc6c62a9
RR
1708 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT)
1709 return item->GetHeight();
1710 else
1711 return m_lineHeight;
91b8de8d
RR
1712}
1713
941830cb 1714void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
ef44a621 1715{
9ec64fa7
VZ
1716 wxTreeItemAttr *attr = item->GetAttributes();
1717 if ( attr && attr->HasFont() )
1718 dc.SetFont(attr->GetFont());
1719 else if (item->IsBold())
eff869aa 1720 dc.SetFont(m_boldFont);
ef44a621 1721
bbe0af5b
RR
1722 long text_w = 0;
1723 long text_h = 0;
1724 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
ef44a621 1725
bbe0af5b
RR
1726 int image_h = 0;
1727 int image_w = 0;
8dc99046
VZ
1728 int image = item->GetCurrentImage();
1729 if ( image != NO_IMAGE )
bbe0af5b 1730 {
2c8e4738
VZ
1731 if ( m_imageListNormal )
1732 {
1733 m_imageListNormal->GetSize( image, image_w, image_h );
1734 image_w += 4;
1735 }
1736 else
1737 {
1738 image = NO_IMAGE;
1739 }
bbe0af5b 1740 }
ef44a621 1741
91b8de8d
RR
1742 int total_h = GetLineHeight(item);
1743
c0fba4d1
VS
1744 if (item->IsSelected())
1745 dc.SetBrush(*m_hilightBrush);
afa6a1a1 1746 else
c0fba4d1
VS
1747 {
1748 wxColour colBg;
1749 if ( attr && attr->HasBackgroundColour() )
1750 colBg = attr->GetBackgroundColour();
1751 else
1752 colBg = m_backgroundColour;
1753 dc.SetBrush(wxBrush(colBg, wxSOLID));
1754 }
afa6a1a1 1755
91b8de8d 1756 dc.DrawRectangle( item->GetX()-2, item->GetY(), item->GetWidth()+2, total_h );
ef44a621 1757
8dc99046 1758 if ( image != NO_IMAGE )
bbe0af5b 1759 {
d30b4d20 1760 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, total_h );
8dc99046 1761 m_imageListNormal->Draw( image, dc,
49cd56ef 1762 item->GetX(),
d701d432 1763 item->GetY() +((total_h > image_h)?((total_h-image_h)/2):0),
bbe0af5b
RR
1764 wxIMAGELIST_DRAW_TRANSPARENT );
1765 dc.DestroyClippingRegion();
1766 }
ef44a621 1767
afa6a1a1 1768 dc.SetBackgroundMode(wxTRANSPARENT);
f6bcfd97
BP
1769 int extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
1770 dc.DrawText( item->GetText(),
1771 (wxCoord)(image_w + item->GetX()),
1772 (wxCoord)(item->GetY() + extraH));
ef44a621 1773
eff869aa
RR
1774 // restore normal font
1775 dc.SetFont( m_normalFont );
ef44a621
VZ
1776}
1777
91b8de8d 1778// Now y stands for the top of the item, whereas it used to stand for middle !
941830cb 1779void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 1780{
bbe0af5b 1781 int horizX = level*m_indent;
389cdc7a 1782
cf724bce 1783 item->SetX( horizX+m_indent+m_spacing );
91b8de8d 1784 item->SetY( y );
4c681997 1785
bbe0af5b 1786 int oldY = y;
91b8de8d
RR
1787 y+=GetLineHeight(item)/2;
1788
1789 item->SetCross( horizX+m_indent, y );
389cdc7a 1790
bbe0af5b 1791 int exposed_x = dc.LogicalToDeviceX( 0 );
5391f772 1792 int exposed_y = dc.LogicalToDeviceY( item->GetY() );
4832f7c0 1793
233058c7
JS
1794 bool drawLines = ((GetWindowStyle() & wxTR_NO_LINES) == 0);
1795
5391f772 1796 if (IsExposed( exposed_x, exposed_y, 10000, GetLineHeight(item) )) // 10000 = very much
bbe0af5b
RR
1797 {
1798 int startX = horizX;
cf724bce 1799 int endX = horizX + (m_indent-5);
29d87bba 1800
cf724bce 1801// if (!item->HasChildren()) endX += (m_indent+5);
bbe0af5b 1802 if (!item->HasChildren()) endX += 20;
4832f7c0 1803
233058c7
JS
1804 if (drawLines)
1805 dc.DrawLine( startX, y, endX, y );
29d87bba 1806
bbe0af5b
RR
1807 if (item->HasPlus())
1808 {
233058c7
JS
1809 if (drawLines)
1810 dc.DrawLine( horizX+(m_indent+5), y, horizX+(m_indent+15), y );
bbe0af5b
RR
1811 dc.SetPen( *wxGREY_PEN );
1812 dc.SetBrush( *wxWHITE_BRUSH );
cf724bce 1813 dc.DrawRectangle( horizX+(m_indent-5), y-4, 11, 9 );
9dfbf520 1814
bbe0af5b 1815 dc.SetPen( *wxBLACK_PEN );
cf724bce 1816 dc.DrawLine( horizX+(m_indent-2), y, horizX+(m_indent+3), y );
bbe0af5b 1817 if (!item->IsExpanded())
cf724bce 1818 dc.DrawLine( horizX+m_indent, y-2, horizX+m_indent, y+3 );
9dfbf520 1819
112c5086 1820 dc.SetPen( m_dottedPen );
bbe0af5b 1821 }
c801d85f 1822
9ec64fa7 1823 wxPen *pen = wxTRANSPARENT_PEN;
9ec64fa7 1824 wxColour colText;
a367b9b3 1825
9ec64fa7
VZ
1826 if ( item->IsSelected() )
1827 {
1828 colText = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
4832f7c0 1829
9ec64fa7
VZ
1830 if ( m_hasFocus )
1831 pen = wxBLACK_PEN;
f135ff73 1832
bbe0af5b
RR
1833 }
1834 else
1835 {
9ec64fa7
VZ
1836 wxTreeItemAttr *attr = item->GetAttributes();
1837 if ( attr && attr->HasTextColour() )
1838 colText = attr->GetTextColour();
1839 else
37d403aa 1840 colText = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT );
bbe0af5b 1841 }
9ec64fa7
VZ
1842
1843 // prepare to draw
1844 dc.SetTextForeground(colText);
1845 dc.SetPen(*pen);
9ec64fa7
VZ
1846
1847 // draw
1848 PaintItem(item, dc);
1849
1850 // restore DC objects
1851 dc.SetBrush( *wxWHITE_BRUSH );
1852 dc.SetPen( m_dottedPen );
1853 dc.SetTextForeground( *wxBLACK );
f135ff73 1854 }
d3a9f4af 1855
91b8de8d 1856 y = oldY+GetLineHeight(item);
e2414cbe 1857
bbe0af5b
RR
1858 if (item->IsExpanded())
1859 {
91b8de8d 1860 oldY+=GetLineHeight(item)/2;
9ec64fa7 1861 int semiOldY=0;
389cdc7a 1862
91b8de8d
RR
1863 wxArrayGenericTreeItems& children = item->GetChildren();
1864 size_t n, count = children.Count();
1865 for ( n = 0; n < count; ++n )
c193b707
VZ
1866 {
1867 semiOldY=y;
1868 PaintLevel( children[n], dc, level+1, y );
1869 }
389cdc7a 1870
f65635b5
VZ
1871 // it may happen that the item is expanded but has no items (when you
1872 // delete all its children for example) - don't draw the vertical line
1873 // in this case
1874 if (count > 0)
9ec64fa7 1875 {
c193b707 1876 semiOldY+=GetLineHeight(children[--n])/2;
233058c7
JS
1877 if (drawLines)
1878 dc.DrawLine( horizX+m_indent, oldY+5, horizX+m_indent, semiOldY );
9ec64fa7 1879 }
bbe0af5b 1880 }
4c681997 1881}
c801d85f 1882
941830cb 1883void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item)
3dbeaa52
VZ
1884{
1885 if ( item )
1886 {
1887 if ( item->HasPlus() )
1888 {
1889 // it's a folder, indicate it by a border
1890 DrawBorder(item);
1891 }
1892 else
1893 {
1894 // draw a line under the drop target because the item will be
1895 // dropped there
1896 DrawLine(item, TRUE /* below */);
1897 }
1898
1899 SetCursor(wxCURSOR_BULLSEYE);
1900 }
1901 else
1902 {
1903 // can't drop here
1904 SetCursor(wxCURSOR_NO_ENTRY);
1905 }
1906}
1907
941830cb 1908void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId &item)
91b8de8d 1909{
941830cb 1910 wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") );
91b8de8d 1911
941830cb 1912 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
91b8de8d 1913
1044a386 1914 wxClientDC dc(this);
91b8de8d
RR
1915 PrepareDC( dc );
1916 dc.SetLogicalFunction(wxINVERT);
3dbeaa52 1917 dc.SetBrush(*wxTRANSPARENT_BRUSH);
91b8de8d 1918
3dbeaa52
VZ
1919 int w = i->GetWidth() + 2;
1920 int h = GetLineHeight(i) + 2;
91b8de8d 1921
3dbeaa52 1922 dc.DrawRectangle( i->GetX() - 1, i->GetY() - 1, w, h);
91b8de8d
RR
1923}
1924
941830cb 1925void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below)
91b8de8d 1926{
941830cb 1927 wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") );
91b8de8d 1928
941830cb 1929 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
91b8de8d 1930
1044a386 1931 wxClientDC dc(this);
91b8de8d
RR
1932 PrepareDC( dc );
1933 dc.SetLogicalFunction(wxINVERT);
d3a9f4af 1934
3dbeaa52
VZ
1935 int x = i->GetX(),
1936 y = i->GetY();
1937 if ( below )
1938 {
1939 y += GetLineHeight(i) - 1;
1940 }
91b8de8d 1941
3dbeaa52 1942 dc.DrawLine( x, y, x + i->GetWidth(), y);
91b8de8d
RR
1943}
1944
f135ff73
VZ
1945// -----------------------------------------------------------------------------
1946// wxWindows callbacks
1947// -----------------------------------------------------------------------------
1948
941830cb 1949void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
c801d85f 1950{
0659e7ee
RR
1951 wxPaintDC dc(this);
1952 PrepareDC( dc );
29d87bba 1953
941830cb
JS
1954 if ( !m_anchor)
1955 return;
1956
eff869aa 1957 dc.SetFont( m_normalFont );
0659e7ee 1958 dc.SetPen( m_dottedPen );
f38374d0 1959
eff869aa 1960 // this is now done dynamically
91b8de8d
RR
1961 //if(GetImageList() == NULL)
1962 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1963
91b8de8d 1964 int y = 2;
0659e7ee 1965 PaintLevel( m_anchor, dc, 0, y );
edaa81ae 1966}
c801d85f 1967
941830cb 1968void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1969{
0659e7ee 1970 m_hasFocus = TRUE;
978f38c2 1971
bbe0af5b 1972 if (m_current) RefreshLine( m_current );
edaa81ae 1973}
c801d85f 1974
941830cb 1975void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1976{
0659e7ee 1977 m_hasFocus = FALSE;
978f38c2 1978
bbe0af5b 1979 if (m_current) RefreshLine( m_current );
edaa81ae 1980}
c801d85f 1981
941830cb 1982void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
c801d85f 1983{
978f38c2 1984 wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
06b466c7 1985 te.m_code = (int)event.KeyCode();
978f38c2
VZ
1986 te.SetEventObject( this );
1987 GetEventHandler()->ProcessEvent( te );
435fe83e 1988
91b8de8d 1989 if ( (m_current == 0) || (m_key_current == 0) )
978f38c2
VZ
1990 {
1991 event.Skip();
1992 return;
1993 }
ef44a621 1994
06b466c7
VZ
1995 // how should the selection work for this event?
1996 bool is_multiple, extended_select, unselect_others;
1997 EventFlagsToSelType(GetWindowStyleFlag(),
1998 event.ShiftDown(),
1999 event.ControlDown(),
dfc6cd93
SB
2000 is_multiple, extended_select, unselect_others);
2001
2002 // + : Expand
2003 // - : Collaspe
f6bcfd97 2004 // * : Expand all/Collapse all
dfc6cd93
SB
2005 // ' ' | return : activate
2006 // up : go up (not last children!)
2007 // down : go down
2008 // left : go to parent
2009 // right : open if parent and go next
2010 // home : go to root
2011 // end : go to last item without opening parents
978f38c2
VZ
2012 switch (event.KeyCode())
2013 {
2014 case '+':
2015 case WXK_ADD:
2016 if (m_current->HasPlus() && !IsExpanded(m_current))
2017 {
2018 Expand(m_current);
2019 }
2020 break;
ef44a621 2021
f6bcfd97
BP
2022 case '*':
2023 case WXK_MULTIPLY:
2024 if ( !IsExpanded(m_current) )
2025 {
2026 // expand all
2027 ExpandAll(m_current);
2028 break;
2029 }
2030 //else: fall through to Collapse() it
2031
978f38c2
VZ
2032 case '-':
2033 case WXK_SUBTRACT:
2034 if (IsExpanded(m_current))
2035 {
2036 Collapse(m_current);
2037 }
2038 break;
ef44a621 2039
978f38c2
VZ
2040 case ' ':
2041 case WXK_RETURN:
2042 {
2043 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
40fab78b 2044 event.m_item = (long) m_current;
978f38c2
VZ
2045 event.m_code = 0;
2046 event.SetEventObject( this );
2047 GetEventHandler()->ProcessEvent( event );
2048 }
2049 break;
ef44a621 2050
978f38c2
VZ
2051 // up goes to the previous sibling or to the last of its children if
2052 // it's expanded
2053 case WXK_UP:
2054 {
91b8de8d 2055 wxTreeItemId prev = GetPrevSibling( m_key_current );
978f38c2
VZ
2056 if (!prev)
2057 {
91b8de8d 2058 prev = GetParent( m_key_current );
c193b707
VZ
2059 if (prev)
2060 {
90e58684 2061 long cockie = 0;
91b8de8d 2062 wxTreeItemId current = m_key_current;
90e58684
RR
2063 if (current == GetFirstChild( prev, cockie ))
2064 {
2065 // otherwise we return to where we came from
88ac883a 2066 SelectItem( prev, unselect_others, extended_select );
941830cb 2067 m_key_current= (wxGenericTreeItem*) prev.m_pItem;
c193b707 2068 EnsureVisible( prev );
90e58684 2069 break;
c193b707 2070 }
978f38c2
VZ
2071 }
2072 }
2073 if (prev)
2074 {
69a282d4 2075 while ( IsExpanded(prev) && HasChildren(prev) )
978f38c2 2076 {
69a282d4
VZ
2077 wxTreeItemId child = GetLastChild(prev);
2078 if ( child )
2079 {
2080 prev = child;
2081 }
978f38c2 2082 }
69a282d4 2083
88ac883a 2084 SelectItem( prev, unselect_others, extended_select );
941830cb 2085 m_key_current=(wxGenericTreeItem*) prev.m_pItem;
978f38c2
VZ
2086 EnsureVisible( prev );
2087 }
2088 }
2089 break;
ef44a621 2090
978f38c2
VZ
2091 // left arrow goes to the parent
2092 case WXK_LEFT:
2093 {
2094 wxTreeItemId prev = GetParent( m_current );
2095 if (prev)
2096 {
2097 EnsureVisible( prev );
88ac883a 2098 SelectItem( prev, unselect_others, extended_select );
978f38c2
VZ
2099 }
2100 }
2101 break;
ef44a621 2102
978f38c2
VZ
2103 case WXK_RIGHT:
2104 // this works the same as the down arrow except that we also expand the
2105 // item if it wasn't expanded yet
2106 Expand(m_current);
2107 // fall through
2108
2109 case WXK_DOWN:
ef44a621 2110 {
91b8de8d 2111 if (IsExpanded(m_key_current) && HasChildren(m_key_current))
978f38c2
VZ
2112 {
2113 long cookie = 0;
91b8de8d 2114 wxTreeItemId child = GetFirstChild( m_key_current, cookie );
88ac883a 2115 SelectItem( child, unselect_others, extended_select );
941830cb 2116 m_key_current=(wxGenericTreeItem*) child.m_pItem;
978f38c2
VZ
2117 EnsureVisible( child );
2118 }
2119 else
2120 {
91b8de8d 2121 wxTreeItemId next = GetNextSibling( m_key_current );
b62c3631 2122 if (!next)
978f38c2 2123 {
91b8de8d 2124 wxTreeItemId current = m_key_current;
978f38c2
VZ
2125 while (current && !next)
2126 {
2127 current = GetParent( current );
2128 if (current) next = GetNextSibling( current );
2129 }
2130 }
b62c3631 2131 if (next)
978f38c2 2132 {
88ac883a 2133 SelectItem( next, unselect_others, extended_select );
941830cb 2134 m_key_current=(wxGenericTreeItem*) next.m_pItem;
978f38c2
VZ
2135 EnsureVisible( next );
2136 }
2137 }
ef44a621 2138 }
978f38c2 2139 break;
ef44a621 2140
978f38c2
VZ
2141 // <End> selects the last visible tree item
2142 case WXK_END:
2143 {
2144 wxTreeItemId last = GetRootItem();
2145
2146 while ( last.IsOk() && IsExpanded(last) )
2147 {
2148 wxTreeItemId lastChild = GetLastChild(last);
2149
2150 // it may happen if the item was expanded but then all of
2151 // its children have been deleted - so IsExpanded() returned
2152 // TRUE, but GetLastChild() returned invalid item
2153 if ( !lastChild )
2154 break;
2155
2156 last = lastChild;
2157 }
2158
2159 if ( last.IsOk() )
2160 {
2161 EnsureVisible( last );
88ac883a 2162 SelectItem( last, unselect_others, extended_select );
978f38c2
VZ
2163 }
2164 }
2165 break;
2166
2167 // <Home> selects the root item
2168 case WXK_HOME:
2169 {
2170 wxTreeItemId prev = GetRootItem();
2171 if (prev)
2172 {
2173 EnsureVisible( prev );
88ac883a 2174 SelectItem( prev, unselect_others, extended_select );
978f38c2
VZ
2175 }
2176 }
2177 break;
2178
2179 default:
2180 event.Skip();
2181 }
edaa81ae 2182}
c801d85f 2183
941830cb 2184wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
4f22cf8d 2185{
dc6c62a9
RR
2186 // We have to call this here because the label in
2187 // question might just have been added and no screen
2188 // update taken place.
2189 if (m_dirty) wxYield();
2190
67a7abf7
VZ
2191 wxClientDC dc(this);
2192 PrepareDC(dc);
06b466c7
VZ
2193 wxCoord x = dc.DeviceToLogicalX( point.x );
2194 wxCoord y = dc.DeviceToLogicalY( point.y );
91b8de8d
RR
2195 int w, h;
2196 GetSize(&w, &h);
2197
2198 flags=0;
2199 if (point.x<0) flags|=wxTREE_HITTEST_TOLEFT;
2200 if (point.x>w) flags|=wxTREE_HITTEST_TORIGHT;
2201 if (point.y<0) flags|=wxTREE_HITTEST_ABOVE;
2202 if (point.y>h) flags|=wxTREE_HITTEST_BELOW;
d3a9f4af 2203
91b8de8d 2204 return m_anchor->HitTest( wxPoint(x, y), this, flags);
4f22cf8d
RR
2205}
2206
8fb3bfe2
JS
2207// get the bounding rectangle of the item (or of its label only)
2208bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
2209 wxRect& rect,
2210 bool textOnly) const
2211{
601c163b 2212 wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
8fb3bfe2
JS
2213
2214 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
2215
2216 int startX, startY;
2217 GetViewStart(& startX, & startY);
2218
1ed01484
JS
2219 rect.x = i->GetX() - startX*PIXELS_PER_UNIT;
2220 rect.y = i->GetY() - startY*PIXELS_PER_UNIT;
2221 rect.width = i->GetWidth();
2222 //rect.height = i->GetHeight();
2223 rect.height = GetLineHeight(i);
8fb3bfe2
JS
2224
2225 return TRUE;
8fb3bfe2
JS
2226}
2227
e179bd65
RR
2228/* **** */
2229
941830cb 2230void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
e179bd65
RR
2231{
2232 if (!item.IsOk()) return;
2233
941830cb 2234 m_currentEdit = (wxGenericTreeItem*) item.m_pItem;
9dfbf520 2235
e179bd65 2236 wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
40fab78b 2237 te.m_item = (long) m_currentEdit;
e179bd65
RR
2238 te.SetEventObject( this );
2239 GetEventHandler()->ProcessEvent( te );
2240
2241 if (!te.IsAllowed()) return;
8dc99046 2242
dc6c62a9
RR
2243 // We have to call this here because the label in
2244 // question might just have been added and no screen
2245 // update taken place.
2246 if (m_dirty) wxYield();
9dfbf520 2247
e179bd65
RR
2248 wxString s = m_currentEdit->GetText();
2249 int x = m_currentEdit->GetX();
2250 int y = m_currentEdit->GetY();
2251 int w = m_currentEdit->GetWidth();
2252 int h = m_currentEdit->GetHeight();
9dfbf520 2253
5f1ea0ee
RR
2254 int image_h = 0;
2255 int image_w = 0;
8dc99046
VZ
2256
2257 int image = m_currentEdit->GetCurrentImage();
2258 if ( image != NO_IMAGE )
5f1ea0ee 2259 {
2c8e4738
VZ
2260 if ( m_imageListNormal )
2261 {
2262 m_imageListNormal->GetSize( image, image_w, image_h );
2263 image_w += 4;
2264 }
2265 else
2266 {
2267 wxFAIL_MSG(_T("you must create an image list to use images!"));
2268 }
5f1ea0ee
RR
2269 }
2270 x += image_w;
2271 w -= image_w + 4; // I don't know why +4 is needed
e179bd65
RR
2272
2273 wxClientDC dc(this);
2274 PrepareDC( dc );
2275 x = dc.LogicalToDeviceX( x );
2276 y = dc.LogicalToDeviceY( y );
2277
2278 wxTreeTextCtrl *text = new wxTreeTextCtrl(
2279 this, -1, &m_renameAccept, &m_renameRes, this, s, wxPoint(x-4,y-4), wxSize(w+11,h+8) );
2280 text->SetFocus();
2281}
2282
941830cb 2283void wxGenericTreeCtrl::OnRenameTimer()
e179bd65
RR
2284{
2285 Edit( m_current );
2286}
2287
941830cb 2288void wxGenericTreeCtrl::OnRenameAccept()
e179bd65
RR
2289{
2290 wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
40fab78b 2291 le.m_item = (long) m_currentEdit;
e179bd65
RR
2292 le.SetEventObject( this );
2293 le.m_label = m_renameRes;
2294 GetEventHandler()->ProcessEvent( le );
9dfbf520 2295
e179bd65 2296 if (!le.IsAllowed()) return;
9dfbf520 2297
5f1ea0ee 2298 SetItemText( m_currentEdit, m_renameRes );
e179bd65 2299}
9dfbf520 2300
941830cb 2301void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
c801d85f 2302{
bbe0af5b 2303 if ( !m_anchor ) return;
978f38c2 2304
3dbeaa52
VZ
2305 // we process left mouse up event (enables in-place edit), right down
2306 // (pass to the user code), left dbl click (activate item) and
2307 // dragging/moving events for items drag-and-drop
f6bcfd97
BP
2308 if ( !(event.LeftDown() ||
2309 event.LeftUp() ||
3dbeaa52
VZ
2310 event.RightDown() ||
2311 event.LeftDClick() ||
2312 event.Dragging() ||
2313 ((event.Moving() || event.RightUp()) && m_isDragging)) )
2314 {
2315 event.Skip();
2316
2317 return;
2318 }
2319
bbe0af5b
RR
2320 wxClientDC dc(this);
2321 PrepareDC(dc);
06b466c7
VZ
2322 wxCoord x = dc.DeviceToLogicalX( event.GetX() );
2323 wxCoord y = dc.DeviceToLogicalY( event.GetY() );
29d87bba 2324
3dbeaa52 2325 int flags = 0;
91b8de8d 2326 wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), this, flags);
3dbeaa52 2327
3dbeaa52 2328 if ( event.Dragging() && !m_isDragging )
bbe0af5b 2329 {
fd9811b1 2330 if (m_dragCount == 0)
8dc99046
VZ
2331 m_dragStart = wxPoint(x,y);
2332
fd9811b1 2333 m_dragCount++;
8dc99046 2334
3dbeaa52
VZ
2335 if (m_dragCount != 3)
2336 {
2337 // wait until user drags a bit further...
2338 return;
2339 }
8dc99046 2340
3dbeaa52
VZ
2341 wxEventType command = event.RightIsDown()
2342 ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
2343 : wxEVT_COMMAND_TREE_BEGIN_DRAG;
8dc99046 2344
fd9811b1 2345 wxTreeEvent nevent( command, GetId() );
40fab78b 2346 nevent.m_item = (long) m_current;
fd9811b1 2347 nevent.SetEventObject(this);
3dbeaa52
VZ
2348
2349 // by default the dragging is not supported, the user code must
2350 // explicitly allow the event for it to take place
2351 nevent.Veto();
2352
2353 if ( GetEventHandler()->ProcessEvent(nevent) && nevent.IsAllowed() )
2354 {
2355 // we're going to drag this item
2356 m_isDragging = TRUE;
2357
b3a7510d
VZ
2358 // remember the old cursor because we will change it while
2359 // dragging
2360 m_oldCursor = m_cursor;
2361
2362 // in a single selection control, hide the selection temporarily
2363 if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE) )
2364 {
941830cb 2365 m_oldSelection = (wxGenericTreeItem*) GetSelection().m_pItem;
b3a7510d
VZ
2366
2367 if ( m_oldSelection )
2368 {
2369 m_oldSelection->SetHilight(FALSE);
2370 RefreshLine(m_oldSelection);
2371 }
2372 }
2373
3dbeaa52
VZ
2374 CaptureMouse();
2375 }
bbe0af5b 2376 }
3dbeaa52 2377 else if ( event.Moving() )
fd9811b1 2378 {
3dbeaa52
VZ
2379 if ( item != m_dropTarget )
2380 {
2381 // unhighlight the previous drop target
2382 DrawDropEffect(m_dropTarget);
fd9811b1 2383
3dbeaa52 2384 m_dropTarget = item;
978f38c2 2385
3dbeaa52
VZ
2386 // highlight the current drop target if any
2387 DrawDropEffect(m_dropTarget);
fb882e1c 2388
3dbeaa52
VZ
2389 wxYield();
2390 }
e179bd65 2391 }
3dbeaa52
VZ
2392 else if ( (event.LeftUp() || event.RightUp()) && m_isDragging )
2393 {
2394 // erase the highlighting
2395 DrawDropEffect(m_dropTarget);
9dfbf520 2396
3dbeaa52
VZ
2397 // generate the drag end event
2398 wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId());
88ac883a 2399
40fab78b 2400 event.m_item = (long) item;
3dbeaa52
VZ
2401 event.m_pointDrag = wxPoint(x, y);
2402 event.SetEventObject(this);
91b8de8d 2403
3dbeaa52 2404 (void)GetEventHandler()->ProcessEvent(event);
29d87bba 2405
3dbeaa52
VZ
2406 m_isDragging = FALSE;
2407 m_dropTarget = (wxGenericTreeItem *)NULL;
2408
b3a7510d
VZ
2409 if ( m_oldSelection )
2410 {
2411 m_oldSelection->SetHilight(TRUE);
2412 RefreshLine(m_oldSelection);
2413 m_oldSelection = (wxGenericTreeItem *)NULL;
2414 }
2415
3dbeaa52
VZ
2416 ReleaseMouse();
2417
b3a7510d 2418 SetCursor(m_oldCursor);
3dbeaa52
VZ
2419
2420 wxYield();
2421 }
2422 else
bbe0af5b 2423 {
3dbeaa52
VZ
2424 // here we process only the messages which happen on tree items
2425
2426 m_dragCount = 0;
2427
2428 if (item == NULL) return; /* we hit the blank area */
2429
2430 if ( event.RightDown() )
2431 {
2432 wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
40fab78b 2433 nevent.m_item = (long) item;
3dbeaa52
VZ
2434 nevent.m_code = 0;
2435 nevent.SetEventObject(this);
2436 GetEventHandler()->ProcessEvent(nevent);
2437 }
80d2803f 2438 else if ( event.LeftUp() )
f6bcfd97 2439 {
80d2803f 2440 if ( m_lastOnSame )
f6bcfd97 2441 {
80d2803f
VZ
2442 if ( (item == m_current) &&
2443 (flags & wxTREE_HITTEST_ONITEMLABEL) &&
2444 HasFlag(wxTR_EDIT_LABELS) )
2445 {
bdb310a7
VZ
2446 if ( m_renameTimer->IsRunning() )
2447 m_renameTimer->Stop();
2448
80d2803f
VZ
2449 m_renameTimer->Start( 100, TRUE );
2450 }
f6bcfd97 2451
80d2803f
VZ
2452 m_lastOnSame = FALSE;
2453 }
3dbeaa52
VZ
2454 }
2455 else
2456 {
f6bcfd97
BP
2457 if ( event.LeftDown() )
2458 {
2459 m_lastOnSame = item == m_current;
2460 }
2461
3dbeaa52
VZ
2462 // how should the selection work for this event?
2463 bool is_multiple, extended_select, unselect_others;
2464 EventFlagsToSelType(GetWindowStyleFlag(),
2465 event.ShiftDown(),
2466 event.ControlDown(),
dfc6cd93 2467 is_multiple, extended_select, unselect_others);
3dbeaa52 2468
f6bcfd97 2469 if ( (flags & wxTREE_HITTEST_ONITEMBUTTON) && event.LeftDown() )
3dbeaa52
VZ
2470 {
2471 Toggle( item );
2472 if ( is_multiple )
2473 return;
2474 }
2475
2476 SelectItem(item, unselect_others, extended_select);
2477
2478 if ( event.LeftDClick() )
2479 {
f6bcfd97
BP
2480 // double clicking should not start editing the item label
2481 m_renameTimer->Stop();
2482 m_lastOnSame = FALSE;
2483
3dbeaa52 2484 wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
40fab78b 2485 nevent.m_item = (long) item;
3dbeaa52
VZ
2486 nevent.m_code = 0;
2487 nevent.SetEventObject( this );
2488 GetEventHandler()->ProcessEvent( nevent );
2489 }
2490 }
bbe0af5b 2491 }
edaa81ae 2492}
c801d85f 2493
941830cb 2494void wxGenericTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
3db7be80 2495{
bbe0af5b
RR
2496 /* after all changes have been done to the tree control,
2497 * we actually redraw the tree when everything is over */
ef44a621 2498
f65635b5
VZ
2499 if (!m_dirty)
2500 return;
ef44a621 2501
bbe0af5b 2502 m_dirty = FALSE;
3db7be80 2503
bbe0af5b 2504 CalculatePositions();
91b8de8d 2505 Refresh();
bbe0af5b 2506 AdjustMyScrollbars();
3db7be80
RR
2507}
2508
941830cb 2509void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
d3a9f4af 2510{
e06b9569
JS
2511 wxCoord text_w = 0;
2512 wxCoord text_h = 0;
9dfbf520 2513
a62867a5 2514 if (item->IsBold())
eff869aa 2515 dc.SetFont(m_boldFont);
9dfbf520 2516
91b8de8d 2517 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
a62867a5 2518 text_h+=2;
91b8de8d 2519
eff869aa
RR
2520 // restore normal font
2521 dc.SetFont( m_normalFont );
9dfbf520 2522
91b8de8d
RR
2523 int image_h = 0;
2524 int image_w = 0;
8dc99046
VZ
2525 int image = item->GetCurrentImage();
2526 if ( image != NO_IMAGE )
91b8de8d 2527 {
2c8e4738
VZ
2528 if ( m_imageListNormal )
2529 {
2530 m_imageListNormal->GetSize( image, image_w, image_h );
2531 image_w += 4;
2532 }
91b8de8d
RR
2533 }
2534
2535 int total_h = (image_h > text_h) ? image_h : text_h;
2536
06b466c7 2537 if (total_h < 40)
f2593d0d 2538 total_h += 2; // at least 2 pixels
06b466c7 2539 else
f2593d0d 2540 total_h += total_h/10; // otherwise 10% extra spacing
91b8de8d
RR
2541
2542 item->SetHeight(total_h);
6cedba09
VZ
2543 if (total_h>m_lineHeight)
2544 m_lineHeight=total_h;
bbe0af5b 2545
91b8de8d
RR
2546 item->SetWidth(image_w+text_w+2);
2547}
2548
2549// -----------------------------------------------------------------------------
2550// for developper : y is now the top of the level
2551// not the middle of it !
941830cb 2552void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 2553{
bbe0af5b 2554 int horizX = level*m_indent;
389cdc7a 2555
91b8de8d 2556 CalculateSize( item, dc );
d3a9f4af 2557
91b8de8d 2558 // set its position
cf724bce 2559 item->SetX( horizX+m_indent+m_spacing );
91b8de8d
RR
2560 item->SetY( y );
2561 y+=GetLineHeight(item);
4c681997 2562
bbe0af5b
RR
2563 if ( !item->IsExpanded() )
2564 {
f65635b5 2565 // we dont need to calculate collapsed branches
bbe0af5b
RR
2566 return;
2567 }
389cdc7a 2568
91b8de8d
RR
2569 wxArrayGenericTreeItems& children = item->GetChildren();
2570 size_t n, count = children.Count();
2571 for (n = 0; n < count; ++n )
f2593d0d 2572 CalculateLevel( children[n], dc, level+1, y ); // recurse
edaa81ae 2573}
c801d85f 2574
941830cb 2575void wxGenericTreeCtrl::CalculatePositions()
c801d85f 2576{
bbe0af5b 2577 if ( !m_anchor ) return;
29d87bba 2578
bbe0af5b
RR
2579 wxClientDC dc(this);
2580 PrepareDC( dc );
29d87bba 2581
eff869aa 2582 dc.SetFont( m_normalFont );
29d87bba 2583
bbe0af5b 2584 dc.SetPen( m_dottedPen );
91b8de8d
RR
2585 //if(GetImageList() == NULL)
2586 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 2587
8dc99046 2588 int y = 2;
f65635b5 2589 CalculateLevel( m_anchor, dc, 0, y ); // start recursion
edaa81ae 2590}
c801d85f 2591
941830cb 2592void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
c801d85f 2593{
e6527f9d
RR
2594 if (m_dirty) return;
2595
bbe0af5b
RR
2596 wxClientDC dc(this);
2597 PrepareDC(dc);
4832f7c0 2598
bbe0af5b
RR
2599 int cw = 0;
2600 int ch = 0;
2601 GetClientSize( &cw, &ch );
4832f7c0 2602
bbe0af5b
RR
2603 wxRect rect;
2604 rect.x = dc.LogicalToDeviceX( 0 );
2605 rect.width = cw;
2606 rect.y = dc.LogicalToDeviceY( item->GetY() );
2607 rect.height = ch;
f135ff73 2608
bbe0af5b 2609 Refresh( TRUE, &rect );
f135ff73 2610
bbe0af5b 2611 AdjustMyScrollbars();
edaa81ae 2612}
c801d85f 2613
941830cb 2614void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
c801d85f 2615{
e6527f9d
RR
2616 if (m_dirty) return;
2617
bbe0af5b
RR
2618 wxClientDC dc(this);
2619 PrepareDC( dc );
2620
5391f772
SB
2621 int cw = 0;
2622 int ch = 0;
2623 GetClientSize( &cw, &ch );
2624
bbe0af5b 2625 wxRect rect;
5391f772
SB
2626 rect.x = dc.LogicalToDeviceX( 0 );
2627 rect.y = dc.LogicalToDeviceY( item->GetY() );
2628 rect.width = cw;
91b8de8d 2629 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
978f38c2 2630
bbe0af5b 2631 Refresh( TRUE, &rect );
edaa81ae 2632}
c801d85f 2633