]> git.saurik.com Git - wxWidgets.git/blame - src/generic/treectlg.cpp
Added chapter on collection and container classes to contents
[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(); }
181 bool IsSelected() const { return m_hasHilight; }
182 bool IsExpanded() const { return !m_isCollapsed; }
183 bool HasPlus() const { return m_hasPlus || HasChildren(); }
184 bool IsBold() const { return m_isBold; }
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;
978f38c2 618
00e12320 619 m_dragCount = 0;
3dbeaa52 620 m_isDragging = FALSE;
b3a7510d
VZ
621 m_dropTarget =
622 m_oldSelection = (wxGenericTreeItem *)NULL;
9dfbf520 623
00e12320 624 m_renameTimer = new wxTreeRenameTimer( this );
f6bcfd97 625 m_lastOnSame = FALSE;
f38374d0 626
00e12320
RR
627 m_normalFont = wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT );
628 m_boldFont = wxFont( m_normalFont.GetPointSize(),
eff869aa
RR
629 m_normalFont.GetFamily(),
630 m_normalFont.GetStyle(),
631 wxBOLD,
632 m_normalFont.GetUnderlined());
edaa81ae 633}
c801d85f 634
941830cb 635bool wxGenericTreeCtrl::Create(wxWindow *parent, wxWindowID id,
f135ff73 636 const wxPoint& pos, const wxSize& size,
978f38c2 637 long style,
674ac8b9
VZ
638 const wxValidator &validator,
639 const wxString& name )
c801d85f 640{
00e12320 641 Init();
f135ff73 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;
edaa81ae 663}
c801d85f 664
f135ff73
VZ
665// -----------------------------------------------------------------------------
666// accessors
667// -----------------------------------------------------------------------------
668
941830cb 669size_t wxGenericTreeCtrl::GetCount() const
c801d85f 670{
f2593d0d 671 return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount();
edaa81ae 672}
c801d85f 673
941830cb 674void wxGenericTreeCtrl::SetIndent(unsigned int indent)
c801d85f 675{
f2593d0d
RR
676 m_indent = indent;
677 m_dirty = TRUE;
cf724bce
RR
678}
679
941830cb 680void wxGenericTreeCtrl::SetSpacing(unsigned int spacing)
cf724bce 681{
f2593d0d
RR
682 m_spacing = spacing;
683 m_dirty = TRUE;
f135ff73 684}
74bedbeb 685
941830cb 686size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
4832f7c0 687{
f2593d0d 688 wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") );
4832f7c0 689
941830cb 690 return ((wxGenericTreeItem*) item.m_pItem)->GetChildrenCount(recursively);
4832f7c0
VZ
691}
692
f135ff73
VZ
693// -----------------------------------------------------------------------------
694// functions to work with tree items
695// -----------------------------------------------------------------------------
74bedbeb 696
941830cb 697wxString wxGenericTreeCtrl::GetItemText(const wxTreeItemId& item) const
f135ff73 698{
f2593d0d 699 wxCHECK_MSG( item.IsOk(), wxT(""), wxT("invalid tree item") );
4832f7c0 700
941830cb 701 return ((wxGenericTreeItem*) item.m_pItem)->GetText();
edaa81ae 702}
74bedbeb 703
941830cb 704int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId& item,
8dc99046 705 wxTreeItemIcon which) const
74bedbeb 706{
f2593d0d 707 wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") );
4832f7c0 708
941830cb 709 return ((wxGenericTreeItem*) item.m_pItem)->GetImage(which);
edaa81ae 710}
c801d85f 711
941830cb 712wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const
c801d85f 713{
f2593d0d 714 wxCHECK_MSG( item.IsOk(), NULL, wxT("invalid tree item") );
4832f7c0 715
941830cb 716 return ((wxGenericTreeItem*) item.m_pItem)->GetData();
edaa81ae 717}
c801d85f 718
941830cb 719void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
f135ff73 720{
f2593d0d 721 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
4832f7c0 722
f2593d0d 723 wxClientDC dc(this);
941830cb 724 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
f2593d0d
RR
725 pItem->SetText(text);
726 CalculateSize(pItem, dc);
727 RefreshLine(pItem);
f135ff73 728}
c801d85f 729
941830cb 730void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId& item,
8dc99046
VZ
731 int image,
732 wxTreeItemIcon which)
f135ff73 733{
223d09f6 734 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
4832f7c0 735
941830cb 736 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
8dc99046 737 pItem->SetImage(image, which);
4832f7c0 738
8dc99046
VZ
739 wxClientDC dc(this);
740 CalculateSize(pItem, dc);
741 RefreshLine(pItem);
edaa81ae 742}
c801d85f 743
941830cb 744void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
c801d85f 745{
f2593d0d 746 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
4832f7c0 747
941830cb 748 ((wxGenericTreeItem*) item.m_pItem)->SetData(data);
edaa81ae 749}
c801d85f 750
941830cb 751void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
c801d85f 752{
f2593d0d 753 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
4832f7c0 754
941830cb 755 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
f2593d0d
RR
756 pItem->SetHasPlus(has);
757 RefreshLine(pItem);
edaa81ae 758}
c801d85f 759
941830cb 760void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
ef44a621 761{
9ec64fa7 762 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
ef44a621 763
9ec64fa7 764 // avoid redrawing the tree if no real change
941830cb 765 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
9ec64fa7
VZ
766 if ( pItem->IsBold() != bold )
767 {
768 pItem->SetBold(bold);
769 RefreshLine(pItem);
770 }
771}
772
941830cb 773void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId& item,
9ec64fa7
VZ
774 const wxColour& col)
775{
776 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
777
941830cb 778 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
9ec64fa7
VZ
779 pItem->Attr().SetTextColour(col);
780 RefreshLine(pItem);
781}
782
941830cb 783void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
9ec64fa7
VZ
784 const wxColour& col)
785{
786 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
787
941830cb 788 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
9ec64fa7
VZ
789 pItem->Attr().SetBackgroundColour(col);
790 RefreshLine(pItem);
791}
792
941830cb 793void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font)
9ec64fa7
VZ
794{
795 wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
796
941830cb 797 wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
9ec64fa7 798 pItem->Attr().SetFont(font);
ef44a621 799 RefreshLine(pItem);
ef44a621
VZ
800}
801
f135ff73
VZ
802// -----------------------------------------------------------------------------
803// item status inquiries
804// -----------------------------------------------------------------------------
805
941830cb 806bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& WXUNUSED(item)) const
c801d85f 807{
f2593d0d 808 wxFAIL_MSG(wxT("not implemented"));
f135ff73 809
f2593d0d 810 return TRUE;
edaa81ae 811}
c801d85f 812
941830cb 813bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
c801d85f 814{
f2593d0d 815 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
4832f7c0 816
941830cb 817 return !((wxGenericTreeItem*) item.m_pItem)->GetChildren().IsEmpty();
edaa81ae 818}
c801d85f 819
941830cb 820bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId& item) const
c801d85f 821{
f2593d0d 822 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
4832f7c0 823
941830cb 824 return ((wxGenericTreeItem*) item.m_pItem)->IsExpanded();
f135ff73 825}
29d87bba 826
941830cb 827bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId& item) const
f135ff73 828{
f2593d0d 829 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
4832f7c0 830
941830cb 831 return ((wxGenericTreeItem*) item.m_pItem)->IsSelected();
f135ff73 832}
29d87bba 833
941830cb 834bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const
ef44a621 835{
f2593d0d 836 wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
ef44a621 837
941830cb 838 return ((wxGenericTreeItem*) item.m_pItem)->IsBold();
ef44a621
VZ
839}
840
f135ff73
VZ
841// -----------------------------------------------------------------------------
842// navigation
843// -----------------------------------------------------------------------------
29d87bba 844
941830cb 845wxTreeItemId wxGenericTreeCtrl::GetParent(const wxTreeItemId& item) const
f135ff73 846{
223d09f6 847 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
389cdc7a 848
941830cb 849 return ((wxGenericTreeItem*) item.m_pItem)->GetParent();
f135ff73 850}
29d87bba 851
941830cb 852wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
f135ff73 853{
223d09f6 854 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
29d87bba 855
f135ff73
VZ
856 cookie = 0;
857 return GetNextChild(item, cookie);
858}
29d87bba 859
941830cb 860wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
f135ff73 861{
223d09f6 862 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
29d87bba 863
941830cb 864 wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
4832f7c0
VZ
865 if ( (size_t)cookie < children.Count() )
866 {
06b466c7 867 return children.Item((size_t)cookie++);
4832f7c0
VZ
868 }
869 else
870 {
871 // there are no more of them
1e6d9499 872 return wxTreeItemId();
4832f7c0 873 }
f135ff73 874}
29d87bba 875
941830cb 876wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const
978f38c2 877{
223d09f6 878 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
978f38c2 879
941830cb 880 wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
0a240683 881 return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last()));
978f38c2
VZ
882}
883
941830cb 884wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
f135ff73 885{
223d09f6 886 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
f135ff73 887
941830cb 888 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
f135ff73
VZ
889 wxGenericTreeItem *parent = i->GetParent();
890 if ( parent == NULL )
891 {
892 // root item doesn't have any siblings
1e6d9499 893 return wxTreeItemId();
edaa81ae 894 }
4832f7c0 895
91b8de8d 896 wxArrayGenericTreeItems& siblings = parent->GetChildren();
f135ff73 897 int index = siblings.Index(i);
3c67202d 898 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
29d87bba 899
f135ff73 900 size_t n = (size_t)(index + 1);
fdd8d7b5 901 return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
edaa81ae 902}
c801d85f 903
941830cb 904wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
c801d85f 905{
223d09f6 906 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
f135ff73 907
941830cb 908 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
f135ff73
VZ
909 wxGenericTreeItem *parent = i->GetParent();
910 if ( parent == NULL )
c801d85f 911 {
f135ff73 912 // root item doesn't have any siblings
1e6d9499 913 return wxTreeItemId();
edaa81ae 914 }
4832f7c0 915
91b8de8d 916 wxArrayGenericTreeItems& siblings = parent->GetChildren();
f135ff73 917 int index = siblings.Index(i);
3c67202d 918 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
29d87bba 919
fdd8d7b5
VZ
920 return index == 0 ? wxTreeItemId()
921 : wxTreeItemId(siblings[(size_t)(index - 1)]);
f135ff73 922}
389cdc7a 923
941830cb 924wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
f135ff73 925{
223d09f6 926 wxFAIL_MSG(wxT("not implemented"));
29d87bba 927
1e6d9499 928 return wxTreeItemId();
f135ff73 929}
29d87bba 930
941830cb 931wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
f135ff73 932{
223d09f6 933 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
29d87bba 934
223d09f6 935 wxFAIL_MSG(wxT("not implemented"));
29d87bba 936
1e6d9499 937 return wxTreeItemId();
f135ff73 938}
29d87bba 939
941830cb 940wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
f135ff73 941{
223d09f6 942 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
29d87bba 943
223d09f6 944 wxFAIL_MSG(wxT("not implemented"));
29d87bba 945
1e6d9499 946 return wxTreeItemId();
edaa81ae 947}
c801d85f 948
f135ff73
VZ
949// -----------------------------------------------------------------------------
950// operations
951// -----------------------------------------------------------------------------
952
941830cb 953wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
f135ff73
VZ
954 size_t previous,
955 const wxString& text,
956 int image, int selImage,
957 wxTreeItemData *data)
c801d85f 958{
941830cb 959 wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
f49f2b0c
RR
960 if ( !parent )
961 {
962 // should we give a warning here?
963 return AddRoot(text, image, selImage, data);
964 }
4832f7c0 965
f49f2b0c 966 wxClientDC dc(this);
f38374d0 967 wxGenericTreeItem *item =
f49f2b0c 968 new wxGenericTreeItem( parent, text, dc, image, selImage, data );
74bedbeb 969
f49f2b0c
RR
970 if ( data != NULL )
971 {
972 data->m_pItem = item;
973 }
74bedbeb 974
f49f2b0c 975 parent->Insert( item, previous );
ef44a621 976
f49f2b0c 977 m_dirty = TRUE;
389cdc7a 978
f49f2b0c 979 return item;
4c681997
RR
980}
981
941830cb 982wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
f135ff73
VZ
983 int image, int selImage,
984 wxTreeItemData *data)
4c681997 985{
f49f2b0c 986 wxCHECK_MSG( !m_anchor, wxTreeItemId(), wxT("tree can have only one root") );
389cdc7a 987
f49f2b0c
RR
988 wxClientDC dc(this);
989 m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
f135ff73 990 image, selImage, data);
f49f2b0c
RR
991 if ( data != NULL )
992 {
993 data->m_pItem = m_anchor;
994 }
f38374d0 995
f49f2b0c
RR
996 if (!HasFlag(wxTR_MULTIPLE))
997 {
998 m_current = m_key_current = m_anchor;
06b466c7 999 m_current->SetHilight( TRUE );
f49f2b0c 1000 }
389cdc7a 1001
f6bcfd97 1002 m_dirty = TRUE;
a32dd690 1003
f49f2b0c 1004 return m_anchor;
edaa81ae 1005}
c801d85f 1006
941830cb 1007wxTreeItemId wxGenericTreeCtrl::PrependItem(const wxTreeItemId& parent,
f135ff73
VZ
1008 const wxString& text,
1009 int image, int selImage,
1010 wxTreeItemData *data)
c801d85f 1011{
f2593d0d 1012 return DoInsertItem(parent, 0u, text, image, selImage, data);
edaa81ae 1013}
c801d85f 1014
941830cb 1015wxTreeItemId wxGenericTreeCtrl::InsertItem(const wxTreeItemId& parentId,
f135ff73
VZ
1016 const wxTreeItemId& idPrevious,
1017 const wxString& text,
1018 int image, int selImage,
1019 wxTreeItemData *data)
c801d85f 1020{
941830cb 1021 wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
f2593d0d
RR
1022 if ( !parent )
1023 {
1024 // should we give a warning here?
1025 return AddRoot(text, image, selImage, data);
1026 }
c801d85f 1027
941830cb 1028 int index = parent->GetChildren().Index((wxGenericTreeItem*) idPrevious.m_pItem);
f2593d0d 1029 wxASSERT_MSG( index != wxNOT_FOUND,
941830cb 1030 wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") );
06b466c7 1031
f2593d0d
RR
1032 return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data);
1033}
1034
941830cb 1035wxTreeItemId wxGenericTreeCtrl::InsertItem(const wxTreeItemId& parentId,
f2593d0d
RR
1036 size_t before,
1037 const wxString& text,
1038 int image, int selImage,
1039 wxTreeItemData *data)
1040{
941830cb 1041 wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
f2593d0d
RR
1042 if ( !parent )
1043 {
1044 // should we give a warning here?
1045 return AddRoot(text, image, selImage, data);
1046 }
1047
1048 return DoInsertItem(parentId, before, text, image, selImage, data);
edaa81ae 1049}
c801d85f 1050
941830cb 1051wxTreeItemId wxGenericTreeCtrl::AppendItem(const wxTreeItemId& parentId,
f135ff73
VZ
1052 const wxString& text,
1053 int image, int selImage,
1054 wxTreeItemData *data)
74bedbeb 1055{
941830cb 1056 wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
f2593d0d
RR
1057 if ( !parent )
1058 {
1059 // should we give a warning here?
1060 return AddRoot(text, image, selImage, data);
1061 }
f135ff73 1062
f2593d0d
RR
1063 return DoInsertItem( parent, parent->GetChildren().Count(), text,
1064 image, selImage, data);
74bedbeb
VZ
1065}
1066
941830cb 1067void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
a43a4f9d 1068{
f2593d0d
RR
1069 wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
1070 event.m_item = item;
1071 event.SetEventObject( this );
1072 ProcessEvent( event );
a43a4f9d
VZ
1073}
1074
941830cb 1075void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
372edb9d 1076{
941830cb 1077 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
a43a4f9d 1078 item->DeleteChildren(this);
372edb9d
VZ
1079
1080 m_dirty = TRUE;
1081}
1082
941830cb 1083void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
c801d85f 1084{
941830cb 1085 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
ff5bf259 1086
aaa2f297
VZ
1087 // don't stay with invalid m_key_current or we will crash in the next call
1088 // to OnChar()
1089 bool changeKeyCurrent = FALSE;
1090 wxGenericTreeItem *itemKey = m_key_current;
1091 while ( itemKey && !changeKeyCurrent )
1092 {
1093 if ( itemKey == item )
1094 {
1095 // m_key_current is a descendant of the item being deleted
1096 changeKeyCurrent = TRUE;
1097 }
1098 else
1099 {
1100 itemKey = itemKey->GetParent();
1101 }
1102 }
1103
1104 wxGenericTreeItem *parent = item->GetParent();
97d7bfb8
RR
1105 if ( parent )
1106 {
1107 parent->GetChildren().Remove( item ); // remove by value
1108 }
f135ff73 1109
aaa2f297
VZ
1110 if ( changeKeyCurrent )
1111 {
1112 // may be NULL or not
1113 m_key_current = parent;
1114 }
1115
97d7bfb8
RR
1116 item->DeleteChildren(this);
1117 SendDeleteEvent(item);
1118 delete item;
f135ff73 1119
97d7bfb8 1120 m_dirty = TRUE;
edaa81ae 1121}
c801d85f 1122
941830cb 1123void wxGenericTreeCtrl::DeleteAllItems()
c801d85f 1124{
97d7bfb8
RR
1125 if ( m_anchor )
1126 {
1127 m_anchor->DeleteChildren(this);
1128 delete m_anchor;
a43a4f9d 1129
97d7bfb8 1130 m_anchor = NULL;
f135ff73 1131
97d7bfb8
RR
1132 m_dirty = TRUE;
1133 }
edaa81ae
RR
1134}
1135
941830cb 1136void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
edaa81ae 1137{
941830cb 1138 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
f135ff73 1139
941830cb 1140 wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") );
f6bcfd97 1141
f2593d0d
RR
1142 if ( !item->HasPlus() )
1143 return;
978f38c2 1144
f2593d0d
RR
1145 if ( item->IsExpanded() )
1146 return;
f135ff73 1147
f2593d0d
RR
1148 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
1149 event.m_item = item;
1150 event.SetEventObject( this );
004fd0c8 1151
f2593d0d
RR
1152 if ( ProcessEvent( event ) && !event.IsAllowed() )
1153 {
1154 // cancelled by program
1155 return;
1156 }
4832f7c0 1157
f2593d0d
RR
1158 item->Expand();
1159 CalculatePositions();
f135ff73 1160
f2593d0d 1161 RefreshSubtree(item);
f135ff73 1162
f2593d0d
RR
1163 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
1164 ProcessEvent( event );
edaa81ae
RR
1165}
1166
941830cb 1167void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId& item)
f6bcfd97
BP
1168{
1169 Expand(item);
1170 if ( IsExpanded(item) )
1171 {
1172 long cookie;
1173 wxTreeItemId child = GetFirstChild(item, cookie);
1174 while ( child.IsOk() )
1175 {
1176 ExpandAll(child);
1177
1178 child = GetNextChild(item, cookie);
1179 }
1180 }
1181}
1182
941830cb 1183void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
edaa81ae 1184{
941830cb 1185 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
f135ff73 1186
f2593d0d
RR
1187 if ( !item->IsExpanded() )
1188 return;
f135ff73 1189
f2593d0d
RR
1190 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
1191 event.m_item = item;
1192 event.SetEventObject( this );
1193 if ( ProcessEvent( event ) && !event.IsAllowed() )
1194 {
1195 // cancelled by program
1196 return;
1197 }
4832f7c0 1198
f2593d0d 1199 item->Collapse();
f135ff73 1200
f2593d0d
RR
1201 wxArrayGenericTreeItems& children = item->GetChildren();
1202 size_t count = children.Count();
1203 for ( size_t n = 0; n < count; n++ )
1204 {
1205 Collapse(children[n]);
1206 }
f135ff73 1207
f2593d0d 1208 CalculatePositions();
f135ff73 1209
f2593d0d 1210 RefreshSubtree(item);
f135ff73 1211
f2593d0d
RR
1212 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
1213 ProcessEvent( event );
edaa81ae 1214}
c801d85f 1215
941830cb 1216void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
c801d85f 1217{
00e12320
RR
1218 Collapse(item);
1219 DeleteChildren(item);
edaa81ae 1220}
c801d85f 1221
941830cb 1222void wxGenericTreeCtrl::Toggle(const wxTreeItemId& itemId)
c801d85f 1223{
941830cb 1224 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
389cdc7a 1225
00e12320
RR
1226 if (item->IsExpanded())
1227 Collapse(itemId);
1228 else
1229 Expand(itemId);
f135ff73 1230}
389cdc7a 1231
941830cb 1232void wxGenericTreeCtrl::Unselect()
f135ff73 1233{
00e12320
RR
1234 if (m_current)
1235 {
1236 m_current->SetHilight( FALSE );
1237 RefreshLine( m_current );
1238 }
edaa81ae 1239}
c801d85f 1240
941830cb 1241void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
389cdc7a 1242{
00e12320
RR
1243 if (item->IsSelected())
1244 {
1245 item->SetHilight(FALSE);
1246 RefreshLine(item);
1247 }
d3a9f4af 1248
00e12320 1249 if (item->HasChildren())
88ac883a 1250 {
00e12320
RR
1251 wxArrayGenericTreeItems& children = item->GetChildren();
1252 size_t count = children.Count();
1253 for ( size_t n = 0; n < count; ++n )
1254 {
1255 UnselectAllChildren(children[n]);
1256 }
88ac883a
VZ
1257 }
1258}
f135ff73 1259
941830cb 1260void wxGenericTreeCtrl::UnselectAll()
88ac883a 1261{
941830cb 1262 UnselectAllChildren((wxGenericTreeItem*) GetRootItem().m_pItem);
88ac883a
VZ
1263}
1264
1265// Recursive function !
1266// To stop we must have crt_item<last_item
91b8de8d 1267// Algorithm :
88ac883a 1268// Tag all next children, when no more children,
d3a9f4af 1269// Move to parent (not to tag)
91b8de8d 1270// Keep going... if we found last_item, we stop.
941830cb 1271bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select)
88ac883a
VZ
1272{
1273 wxGenericTreeItem *parent = crt_item->GetParent();
1274
00e12320
RR
1275 if (parent == NULL) // This is root item
1276 return TagAllChildrenUntilLast(crt_item, last_item, select);
88ac883a 1277
91b8de8d 1278 wxArrayGenericTreeItems& children = parent->GetChildren();
88ac883a
VZ
1279 int index = children.Index(crt_item);
1280 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
1281
1282 size_t count = children.Count();
1283 for (size_t n=(size_t)(index+1); n<count; ++n)
00e12320
RR
1284 {
1285 if (TagAllChildrenUntilLast(children[n], last_item, select)) return TRUE;
1286 }
88ac883a
VZ
1287
1288 return TagNextChildren(parent, last_item, select);
1289}
1290
941830cb 1291bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select)
88ac883a 1292{
00e12320
RR
1293 crt_item->SetHilight(select);
1294 RefreshLine(crt_item);
d3a9f4af 1295
06b466c7 1296 if (crt_item==last_item)
00e12320 1297 return TRUE;
88ac883a 1298
00e12320 1299 if (crt_item->HasChildren())
88ac883a 1300 {
00e12320
RR
1301 wxArrayGenericTreeItems& children = crt_item->GetChildren();
1302 size_t count = children.Count();
1303 for ( size_t n = 0; n < count; ++n )
1304 {
06b466c7 1305 if (TagAllChildrenUntilLast(children[n], last_item, select))
00e12320 1306 return TRUE;
06b466c7 1307 }
88ac883a 1308 }
d3a9f4af 1309
c0de7af4 1310 return FALSE;
88ac883a
VZ
1311}
1312
941830cb 1313void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2)
88ac883a 1314{
f2593d0d
RR
1315 // item2 is not necessary after item1
1316 wxGenericTreeItem *first=NULL, *last=NULL;
88ac883a 1317
f2593d0d
RR
1318 // choice first' and 'last' between item1 and item2
1319 if (item1->GetY()<item2->GetY())
06b466c7 1320 {
f2593d0d
RR
1321 first=item1;
1322 last=item2;
1323 }
1324 else
1325 {
1326 first=item2;
1327 last=item1;
1328 }
88ac883a 1329
f2593d0d 1330 bool select = m_current->IsSelected();
d3a9f4af 1331
f2593d0d
RR
1332 if ( TagAllChildrenUntilLast(first,last,select) )
1333 return;
88ac883a 1334
f2593d0d 1335 TagNextChildren(first,last,select);
88ac883a
VZ
1336}
1337
941830cb 1338void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
c193b707
VZ
1339 bool unselect_others,
1340 bool extended_select)
d3a9f4af 1341{
223d09f6 1342 wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
8b04a037 1343
88ac883a 1344 bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE);
941830cb 1345 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
88ac883a
VZ
1346
1347 //wxCHECK_RET( ( (!unselect_others) && is_single),
223d09f6 1348 // wxT("this is a single selection tree") );
88ac883a
VZ
1349
1350 // to keep going anyhow !!!
d3a9f4af 1351 if (is_single)
8dc99046
VZ
1352 {
1353 if (item->IsSelected())
1354 return; // nothing to do
1355 unselect_others = TRUE;
1356 extended_select = FALSE;
1357 }
1358 else if ( unselect_others && item->IsSelected() )
1359 {
1360 // selection change if there is more than one item currently selected
1361 wxArrayTreeItemIds selected_items;
1362 if ( GetSelections(selected_items) == 1 )
1363 return;
1364 }
d3a9f4af 1365
f135ff73
VZ
1366 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
1367 event.m_item = item;
1368 event.m_itemOld = m_current;
1369 event.SetEventObject( this );
91b8de8d 1370 // TODO : Here we don't send any selection mode yet !
d3a9f4af 1371
f98e2558 1372 if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
f135ff73
VZ
1373 return;
1374
88ac883a
VZ
1375 // ctrl press
1376 if (unselect_others)
389cdc7a 1377 {
88ac883a 1378 if (is_single) Unselect(); // to speed up thing
c193b707 1379 else UnselectAll();
edaa81ae 1380 }
f135ff73 1381
88ac883a 1382 // shift press
d3a9f4af 1383 if (extended_select)
88ac883a 1384 {
aaa2f297
VZ
1385 if ( !m_current )
1386 {
1387 m_current =
941830cb 1388 m_key_current = (wxGenericTreeItem*) GetRootItem().m_pItem;
aaa2f297
VZ
1389 }
1390
88ac883a
VZ
1391 // don't change the mark (m_current)
1392 SelectItemRange(m_current, item);
1393 }
1394 else
1395 {
c0de7af4 1396 bool select=TRUE; // the default
88ac883a 1397
c193b707
VZ
1398 // Check if we need to toggle hilight (ctrl mode)
1399 if (!unselect_others)
8dc99046 1400 select=!item->IsSelected();
88ac883a 1401
91b8de8d 1402 m_current = m_key_current = item;
c193b707
VZ
1403 m_current->SetHilight(select);
1404 RefreshLine( m_current );
88ac883a 1405 }
389cdc7a 1406
f135ff73 1407 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
6daa0637 1408 GetEventHandler()->ProcessEvent( event );
389cdc7a
VZ
1409}
1410
941830cb 1411void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item,
9dfbf520 1412 wxArrayTreeItemIds &array) const
c801d85f 1413{
8dc99046 1414 if ( item->IsSelected() )
9dfbf520 1415 array.Add(wxTreeItemId(item));
91b8de8d 1416
9dfbf520 1417 if ( item->HasChildren() )
91b8de8d 1418 {
9dfbf520
VZ
1419 wxArrayGenericTreeItems& children = item->GetChildren();
1420 size_t count = children.GetCount();
1421 for ( size_t n = 0; n < count; ++n )
f6bcfd97 1422 FillArray(children[n], array);
91b8de8d
RR
1423 }
1424}
1425
941830cb 1426size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const
91b8de8d
RR
1427{
1428 array.Empty();
f6bcfd97
BP
1429 wxTreeItemId idRoot = GetRootItem();
1430 if ( idRoot.IsOk() )
1431 {
941830cb 1432 FillArray((wxGenericTreeItem*) idRoot.m_pItem, array);
f6bcfd97
BP
1433 }
1434 //else: the tree is empty, so no selections
91b8de8d
RR
1435
1436 return array.Count();
1437}
1438
941830cb 1439void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
d3a9f4af 1440{
91b8de8d
RR
1441 if (!item.IsOk()) return;
1442
941830cb 1443 wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
ef44a621 1444
f65635b5
VZ
1445 // first expand all parent branches
1446 wxGenericTreeItem *parent = gitem->GetParent();
5391f772 1447 while ( parent )
f65635b5 1448 {
8dc99046 1449 Expand(parent);
f65635b5
VZ
1450 parent = parent->GetParent();
1451 }
1452
5391f772 1453 //if (parent) CalculatePositions();
91b8de8d
RR
1454
1455 ScrollTo(item);
1456}
1457
941830cb 1458void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
91b8de8d
RR
1459{
1460 if (!item.IsOk()) return;
1461
dc6c62a9
RR
1462 // We have to call this here because the label in
1463 // question might just have been added and no screen
1464 // update taken place.
1465 if (m_dirty) wxYield();
1466
941830cb 1467 wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
91b8de8d 1468
f65635b5 1469 // now scroll to the item
0659e7ee 1470 int item_y = gitem->GetY();
8dc99046 1471
0659e7ee
RR
1472 int start_x = 0;
1473 int start_y = 0;
1474 ViewStart( &start_x, &start_y );
91b8de8d 1475 start_y *= PIXELS_PER_UNIT;
978f38c2 1476
a93109d5
RR
1477 int client_h = 0;
1478 int client_w = 0;
1479 GetClientSize( &client_w, &client_h );
ef44a621 1480
0659e7ee
RR
1481 if (item_y < start_y+3)
1482 {
91b8de8d 1483 // going down
0659e7ee
RR
1484 int x = 0;
1485 int y = 0;
91b8de8d
RR
1486 m_anchor->GetSize( x, y, this );
1487 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
c7a9fa36 1488 x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
0659e7ee 1489 int x_pos = GetScrollPos( wxHORIZONTAL );
c193b707 1490 // Item should appear at top
91b8de8d 1491 SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT );
0659e7ee 1492 }
91b8de8d 1493 else if (item_y+GetLineHeight(gitem) > start_y+client_h)
0659e7ee 1494 {
c7a9fa36
RR
1495 // going up
1496 int x = 0;
1497 int y = 0;
1498 m_anchor->GetSize( x, y, this );
1499 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
1500 x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
1501 item_y += PIXELS_PER_UNIT+2;
1502 int x_pos = GetScrollPos( wxHORIZONTAL );
c193b707 1503 // Item should appear at bottom
c7a9fa36 1504 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 1505 }
edaa81ae 1506}
c801d85f 1507
e1ee62bd 1508// FIXME: tree sorting functions are not reentrant and not MT-safe!
941830cb 1509static wxGenericTreeCtrl *s_treeBeingSorted = NULL;
0659e7ee 1510
004fd0c8 1511static int LINKAGEMODE tree_ctrl_compare_func(wxGenericTreeItem **item1,
e1ee62bd 1512 wxGenericTreeItem **item2)
edaa81ae 1513{
941830cb 1514 wxCHECK_MSG( s_treeBeingSorted, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") );
e1ee62bd
VZ
1515
1516 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
0659e7ee
RR
1517}
1518
941830cb 1519int wxGenericTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
e1ee62bd 1520 const wxTreeItemId& item2)
0659e7ee 1521{
87138c52 1522 return wxStrcmp(GetItemText(item1), GetItemText(item2));
e1ee62bd
VZ
1523}
1524
941830cb 1525void wxGenericTreeCtrl::SortChildren(const wxTreeItemId& itemId)
e1ee62bd 1526{
223d09f6 1527 wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
e1ee62bd 1528
941830cb 1529 wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
978f38c2 1530
e1ee62bd 1531 wxCHECK_RET( !s_treeBeingSorted,
941830cb 1532 wxT("wxGenericTreeCtrl::SortChildren is not reentrant") );
e1ee62bd 1533
91b8de8d 1534 wxArrayGenericTreeItems& children = item->GetChildren();
e1ee62bd
VZ
1535 if ( children.Count() > 1 )
1536 {
1537 s_treeBeingSorted = this;
1538 children.Sort(tree_ctrl_compare_func);
1539 s_treeBeingSorted = NULL;
978f38c2 1540
e1ee62bd
VZ
1541 m_dirty = TRUE;
1542 }
1543 //else: don't make the tree dirty as nothing changed
edaa81ae
RR
1544}
1545
941830cb 1546wxImageList *wxGenericTreeCtrl::GetImageList() const
edaa81ae 1547{
f135ff73 1548 return m_imageListNormal;
edaa81ae
RR
1549}
1550
941830cb 1551wxImageList *wxGenericTreeCtrl::GetStateImageList() const
c801d85f 1552{
f135ff73 1553 return m_imageListState;
edaa81ae 1554}
c801d85f 1555
941830cb 1556void wxGenericTreeCtrl::SetImageList(wxImageList *imageList)
e2414cbe 1557{
f2593d0d 1558 m_imageListNormal = imageList;
91b8de8d 1559
2c8e4738
VZ
1560 if ( !m_imageListNormal )
1561 return;
1562
f2593d0d 1563 // Calculate a m_lineHeight value from the image sizes.
941830cb 1564 // May be toggle off. Then wxGenericTreeCtrl will spread when
f2593d0d 1565 // necessary (which might look ugly).
f2593d0d
RR
1566 wxClientDC dc(this);
1567 m_lineHeight = (int)(dc.GetCharHeight() + 4);
1568 int width = 0, height = 0,
1569 n = m_imageListNormal->GetImageCount();
06b466c7 1570
f2593d0d
RR
1571 for (int i = 0; i < n ; i++)
1572 {
1573 m_imageListNormal->GetSize(i, width, height);
1574 if (height > m_lineHeight) m_lineHeight = height;
1575 }
91b8de8d 1576
06b466c7 1577 if (m_lineHeight < 40)
f2593d0d 1578 m_lineHeight += 2; // at least 2 pixels
06b466c7 1579 else
f2593d0d 1580 m_lineHeight += m_lineHeight/10; // otherwise 10% extra spacing
edaa81ae 1581}
e2414cbe 1582
941830cb 1583void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList)
e2414cbe 1584{
f135ff73 1585 m_imageListState = imageList;
edaa81ae 1586}
e2414cbe 1587
f135ff73
VZ
1588// -----------------------------------------------------------------------------
1589// helpers
1590// -----------------------------------------------------------------------------
0659e7ee 1591
941830cb 1592void wxGenericTreeCtrl::AdjustMyScrollbars()
c801d85f 1593{
0659e7ee
RR
1594 if (m_anchor)
1595 {
1596 int x = 0;
1597 int y = 0;
91b8de8d 1598 m_anchor->GetSize( x, y, this );
c193b707 1599 y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
c7a9fa36 1600 x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
0659e7ee
RR
1601 int x_pos = GetScrollPos( wxHORIZONTAL );
1602 int y_pos = GetScrollPos( wxVERTICAL );
91b8de8d 1603 SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, y_pos );
0659e7ee
RR
1604 }
1605 else
1606 {
1607 SetScrollbars( 0, 0, 0, 0 );
1608 }
edaa81ae 1609}
c801d85f 1610
941830cb 1611int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem *item) const
91b8de8d 1612{
dc6c62a9
RR
1613 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT)
1614 return item->GetHeight();
1615 else
1616 return m_lineHeight;
91b8de8d
RR
1617}
1618
941830cb 1619void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
ef44a621 1620{
9ec64fa7
VZ
1621 wxTreeItemAttr *attr = item->GetAttributes();
1622 if ( attr && attr->HasFont() )
1623 dc.SetFont(attr->GetFont());
1624 else if (item->IsBold())
eff869aa 1625 dc.SetFont(m_boldFont);
ef44a621 1626
bbe0af5b
RR
1627 long text_w = 0;
1628 long text_h = 0;
1629 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
ef44a621 1630
bbe0af5b
RR
1631 int image_h = 0;
1632 int image_w = 0;
8dc99046
VZ
1633 int image = item->GetCurrentImage();
1634 if ( image != NO_IMAGE )
bbe0af5b 1635 {
2c8e4738
VZ
1636 if ( m_imageListNormal )
1637 {
1638 m_imageListNormal->GetSize( image, image_w, image_h );
1639 image_w += 4;
1640 }
1641 else
1642 {
1643 image = NO_IMAGE;
1644 }
bbe0af5b 1645 }
ef44a621 1646
91b8de8d
RR
1647 int total_h = GetLineHeight(item);
1648
c0fba4d1
VS
1649 if (item->IsSelected())
1650 dc.SetBrush(*m_hilightBrush);
afa6a1a1 1651 else
c0fba4d1
VS
1652 {
1653 wxColour colBg;
1654 if ( attr && attr->HasBackgroundColour() )
1655 colBg = attr->GetBackgroundColour();
1656 else
1657 colBg = m_backgroundColour;
1658 dc.SetBrush(wxBrush(colBg, wxSOLID));
1659 }
afa6a1a1 1660
91b8de8d 1661 dc.DrawRectangle( item->GetX()-2, item->GetY(), item->GetWidth()+2, total_h );
ef44a621 1662
8dc99046 1663 if ( image != NO_IMAGE )
bbe0af5b 1664 {
d30b4d20 1665 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, total_h );
8dc99046 1666 m_imageListNormal->Draw( image, dc,
49cd56ef 1667 item->GetX(),
d701d432 1668 item->GetY() +((total_h > image_h)?((total_h-image_h)/2):0),
bbe0af5b
RR
1669 wxIMAGELIST_DRAW_TRANSPARENT );
1670 dc.DestroyClippingRegion();
1671 }
ef44a621 1672
afa6a1a1 1673 dc.SetBackgroundMode(wxTRANSPARENT);
f6bcfd97
BP
1674 int extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
1675 dc.DrawText( item->GetText(),
1676 (wxCoord)(image_w + item->GetX()),
1677 (wxCoord)(item->GetY() + extraH));
ef44a621 1678
eff869aa
RR
1679 // restore normal font
1680 dc.SetFont( m_normalFont );
ef44a621
VZ
1681}
1682
91b8de8d 1683// Now y stands for the top of the item, whereas it used to stand for middle !
941830cb 1684void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 1685{
bbe0af5b 1686 int horizX = level*m_indent;
389cdc7a 1687
cf724bce 1688 item->SetX( horizX+m_indent+m_spacing );
91b8de8d 1689 item->SetY( y );
4c681997 1690
bbe0af5b 1691 int oldY = y;
91b8de8d
RR
1692 y+=GetLineHeight(item)/2;
1693
1694 item->SetCross( horizX+m_indent, y );
389cdc7a 1695
bbe0af5b 1696 int exposed_x = dc.LogicalToDeviceX( 0 );
5391f772 1697 int exposed_y = dc.LogicalToDeviceY( item->GetY() );
4832f7c0 1698
233058c7
JS
1699 bool drawLines = ((GetWindowStyle() & wxTR_NO_LINES) == 0);
1700
5391f772 1701 if (IsExposed( exposed_x, exposed_y, 10000, GetLineHeight(item) )) // 10000 = very much
bbe0af5b
RR
1702 {
1703 int startX = horizX;
cf724bce 1704 int endX = horizX + (m_indent-5);
29d87bba 1705
cf724bce 1706// if (!item->HasChildren()) endX += (m_indent+5);
bbe0af5b 1707 if (!item->HasChildren()) endX += 20;
4832f7c0 1708
233058c7
JS
1709 if (drawLines)
1710 dc.DrawLine( startX, y, endX, y );
29d87bba 1711
bbe0af5b
RR
1712 if (item->HasPlus())
1713 {
233058c7
JS
1714 if (drawLines)
1715 dc.DrawLine( horizX+(m_indent+5), y, horizX+(m_indent+15), y );
bbe0af5b
RR
1716 dc.SetPen( *wxGREY_PEN );
1717 dc.SetBrush( *wxWHITE_BRUSH );
cf724bce 1718 dc.DrawRectangle( horizX+(m_indent-5), y-4, 11, 9 );
9dfbf520 1719
bbe0af5b 1720 dc.SetPen( *wxBLACK_PEN );
cf724bce 1721 dc.DrawLine( horizX+(m_indent-2), y, horizX+(m_indent+3), y );
bbe0af5b 1722 if (!item->IsExpanded())
cf724bce 1723 dc.DrawLine( horizX+m_indent, y-2, horizX+m_indent, y+3 );
9dfbf520 1724
112c5086 1725 dc.SetPen( m_dottedPen );
bbe0af5b 1726 }
c801d85f 1727
9ec64fa7 1728 wxPen *pen = wxTRANSPARENT_PEN;
9ec64fa7 1729 wxColour colText;
a367b9b3 1730
9ec64fa7
VZ
1731 if ( item->IsSelected() )
1732 {
1733 colText = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
4832f7c0 1734
9ec64fa7
VZ
1735 if ( m_hasFocus )
1736 pen = wxBLACK_PEN;
f135ff73 1737
bbe0af5b
RR
1738 }
1739 else
1740 {
9ec64fa7
VZ
1741 wxTreeItemAttr *attr = item->GetAttributes();
1742 if ( attr && attr->HasTextColour() )
1743 colText = attr->GetTextColour();
1744 else
1745 colText = *wxBLACK;
bbe0af5b 1746 }
9ec64fa7
VZ
1747
1748 // prepare to draw
1749 dc.SetTextForeground(colText);
1750 dc.SetPen(*pen);
9ec64fa7
VZ
1751
1752 // draw
1753 PaintItem(item, dc);
1754
1755 // restore DC objects
1756 dc.SetBrush( *wxWHITE_BRUSH );
1757 dc.SetPen( m_dottedPen );
1758 dc.SetTextForeground( *wxBLACK );
f135ff73 1759 }
d3a9f4af 1760
91b8de8d 1761 y = oldY+GetLineHeight(item);
e2414cbe 1762
bbe0af5b
RR
1763 if (item->IsExpanded())
1764 {
91b8de8d 1765 oldY+=GetLineHeight(item)/2;
9ec64fa7 1766 int semiOldY=0;
389cdc7a 1767
91b8de8d
RR
1768 wxArrayGenericTreeItems& children = item->GetChildren();
1769 size_t n, count = children.Count();
1770 for ( n = 0; n < count; ++n )
c193b707
VZ
1771 {
1772 semiOldY=y;
1773 PaintLevel( children[n], dc, level+1, y );
1774 }
389cdc7a 1775
f65635b5
VZ
1776 // it may happen that the item is expanded but has no items (when you
1777 // delete all its children for example) - don't draw the vertical line
1778 // in this case
1779 if (count > 0)
9ec64fa7 1780 {
c193b707 1781 semiOldY+=GetLineHeight(children[--n])/2;
233058c7
JS
1782 if (drawLines)
1783 dc.DrawLine( horizX+m_indent, oldY+5, horizX+m_indent, semiOldY );
9ec64fa7 1784 }
bbe0af5b 1785 }
4c681997 1786}
c801d85f 1787
941830cb 1788void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item)
3dbeaa52
VZ
1789{
1790 if ( item )
1791 {
1792 if ( item->HasPlus() )
1793 {
1794 // it's a folder, indicate it by a border
1795 DrawBorder(item);
1796 }
1797 else
1798 {
1799 // draw a line under the drop target because the item will be
1800 // dropped there
1801 DrawLine(item, TRUE /* below */);
1802 }
1803
1804 SetCursor(wxCURSOR_BULLSEYE);
1805 }
1806 else
1807 {
1808 // can't drop here
1809 SetCursor(wxCURSOR_NO_ENTRY);
1810 }
1811}
1812
941830cb 1813void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId &item)
91b8de8d 1814{
941830cb 1815 wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") );
91b8de8d 1816
941830cb 1817 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
91b8de8d 1818
1044a386 1819 wxClientDC dc(this);
91b8de8d
RR
1820 PrepareDC( dc );
1821 dc.SetLogicalFunction(wxINVERT);
3dbeaa52 1822 dc.SetBrush(*wxTRANSPARENT_BRUSH);
91b8de8d 1823
3dbeaa52
VZ
1824 int w = i->GetWidth() + 2;
1825 int h = GetLineHeight(i) + 2;
91b8de8d 1826
3dbeaa52 1827 dc.DrawRectangle( i->GetX() - 1, i->GetY() - 1, w, h);
91b8de8d
RR
1828}
1829
941830cb 1830void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below)
91b8de8d 1831{
941830cb 1832 wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") );
91b8de8d 1833
941830cb 1834 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
91b8de8d 1835
1044a386 1836 wxClientDC dc(this);
91b8de8d
RR
1837 PrepareDC( dc );
1838 dc.SetLogicalFunction(wxINVERT);
d3a9f4af 1839
3dbeaa52
VZ
1840 int x = i->GetX(),
1841 y = i->GetY();
1842 if ( below )
1843 {
1844 y += GetLineHeight(i) - 1;
1845 }
91b8de8d 1846
3dbeaa52 1847 dc.DrawLine( x, y, x + i->GetWidth(), y);
91b8de8d
RR
1848}
1849
f135ff73
VZ
1850// -----------------------------------------------------------------------------
1851// wxWindows callbacks
1852// -----------------------------------------------------------------------------
1853
941830cb 1854void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
c801d85f 1855{
0659e7ee
RR
1856 wxPaintDC dc(this);
1857 PrepareDC( dc );
29d87bba 1858
941830cb
JS
1859 if ( !m_anchor)
1860 return;
1861
eff869aa 1862 dc.SetFont( m_normalFont );
0659e7ee 1863 dc.SetPen( m_dottedPen );
f38374d0 1864
eff869aa 1865 // this is now done dynamically
91b8de8d
RR
1866 //if(GetImageList() == NULL)
1867 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1868
91b8de8d 1869 int y = 2;
0659e7ee 1870 PaintLevel( m_anchor, dc, 0, y );
edaa81ae 1871}
c801d85f 1872
941830cb 1873void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1874{
0659e7ee 1875 m_hasFocus = TRUE;
978f38c2 1876
bbe0af5b 1877 if (m_current) RefreshLine( m_current );
edaa81ae 1878}
c801d85f 1879
941830cb 1880void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f 1881{
0659e7ee 1882 m_hasFocus = FALSE;
978f38c2 1883
bbe0af5b 1884 if (m_current) RefreshLine( m_current );
edaa81ae 1885}
c801d85f 1886
941830cb 1887void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
c801d85f 1888{
978f38c2 1889 wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
06b466c7 1890 te.m_code = (int)event.KeyCode();
978f38c2
VZ
1891 te.SetEventObject( this );
1892 GetEventHandler()->ProcessEvent( te );
435fe83e 1893
91b8de8d 1894 if ( (m_current == 0) || (m_key_current == 0) )
978f38c2
VZ
1895 {
1896 event.Skip();
1897 return;
1898 }
ef44a621 1899
06b466c7
VZ
1900 // how should the selection work for this event?
1901 bool is_multiple, extended_select, unselect_others;
1902 EventFlagsToSelType(GetWindowStyleFlag(),
1903 event.ShiftDown(),
1904 event.ControlDown(),
dfc6cd93
SB
1905 is_multiple, extended_select, unselect_others);
1906
1907 // + : Expand
1908 // - : Collaspe
f6bcfd97 1909 // * : Expand all/Collapse all
dfc6cd93
SB
1910 // ' ' | return : activate
1911 // up : go up (not last children!)
1912 // down : go down
1913 // left : go to parent
1914 // right : open if parent and go next
1915 // home : go to root
1916 // end : go to last item without opening parents
978f38c2
VZ
1917 switch (event.KeyCode())
1918 {
1919 case '+':
1920 case WXK_ADD:
1921 if (m_current->HasPlus() && !IsExpanded(m_current))
1922 {
1923 Expand(m_current);
1924 }
1925 break;
ef44a621 1926
f6bcfd97
BP
1927 case '*':
1928 case WXK_MULTIPLY:
1929 if ( !IsExpanded(m_current) )
1930 {
1931 // expand all
1932 ExpandAll(m_current);
1933 break;
1934 }
1935 //else: fall through to Collapse() it
1936
978f38c2
VZ
1937 case '-':
1938 case WXK_SUBTRACT:
1939 if (IsExpanded(m_current))
1940 {
1941 Collapse(m_current);
1942 }
1943 break;
ef44a621 1944
978f38c2
VZ
1945 case ' ':
1946 case WXK_RETURN:
1947 {
1948 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
1949 event.m_item = m_current;
1950 event.m_code = 0;
1951 event.SetEventObject( this );
1952 GetEventHandler()->ProcessEvent( event );
1953 }
1954 break;
ef44a621 1955
978f38c2
VZ
1956 // up goes to the previous sibling or to the last of its children if
1957 // it's expanded
1958 case WXK_UP:
1959 {
91b8de8d 1960 wxTreeItemId prev = GetPrevSibling( m_key_current );
978f38c2
VZ
1961 if (!prev)
1962 {
91b8de8d 1963 prev = GetParent( m_key_current );
c193b707
VZ
1964 if (prev)
1965 {
90e58684 1966 long cockie = 0;
91b8de8d 1967 wxTreeItemId current = m_key_current;
90e58684
RR
1968 if (current == GetFirstChild( prev, cockie ))
1969 {
1970 // otherwise we return to where we came from
88ac883a 1971 SelectItem( prev, unselect_others, extended_select );
941830cb 1972 m_key_current= (wxGenericTreeItem*) prev.m_pItem;
c193b707 1973 EnsureVisible( prev );
90e58684 1974 break;
c193b707 1975 }
978f38c2
VZ
1976 }
1977 }
1978 if (prev)
1979 {
69a282d4 1980 while ( IsExpanded(prev) && HasChildren(prev) )
978f38c2 1981 {
69a282d4
VZ
1982 wxTreeItemId child = GetLastChild(prev);
1983 if ( child )
1984 {
1985 prev = child;
1986 }
978f38c2 1987 }
69a282d4 1988
88ac883a 1989 SelectItem( prev, unselect_others, extended_select );
941830cb 1990 m_key_current=(wxGenericTreeItem*) prev.m_pItem;
978f38c2
VZ
1991 EnsureVisible( prev );
1992 }
1993 }
1994 break;
ef44a621 1995
978f38c2
VZ
1996 // left arrow goes to the parent
1997 case WXK_LEFT:
1998 {
1999 wxTreeItemId prev = GetParent( m_current );
2000 if (prev)
2001 {
2002 EnsureVisible( prev );
88ac883a 2003 SelectItem( prev, unselect_others, extended_select );
978f38c2
VZ
2004 }
2005 }
2006 break;
ef44a621 2007
978f38c2
VZ
2008 case WXK_RIGHT:
2009 // this works the same as the down arrow except that we also expand the
2010 // item if it wasn't expanded yet
2011 Expand(m_current);
2012 // fall through
2013
2014 case WXK_DOWN:
ef44a621 2015 {
91b8de8d 2016 if (IsExpanded(m_key_current) && HasChildren(m_key_current))
978f38c2
VZ
2017 {
2018 long cookie = 0;
91b8de8d 2019 wxTreeItemId child = GetFirstChild( m_key_current, cookie );
88ac883a 2020 SelectItem( child, unselect_others, extended_select );
941830cb 2021 m_key_current=(wxGenericTreeItem*) child.m_pItem;
978f38c2
VZ
2022 EnsureVisible( child );
2023 }
2024 else
2025 {
91b8de8d 2026 wxTreeItemId next = GetNextSibling( m_key_current );
b62c3631 2027 if (!next)
978f38c2 2028 {
91b8de8d 2029 wxTreeItemId current = m_key_current;
978f38c2
VZ
2030 while (current && !next)
2031 {
2032 current = GetParent( current );
2033 if (current) next = GetNextSibling( current );
2034 }
2035 }
b62c3631 2036 if (next)
978f38c2 2037 {
88ac883a 2038 SelectItem( next, unselect_others, extended_select );
941830cb 2039 m_key_current=(wxGenericTreeItem*) next.m_pItem;
978f38c2
VZ
2040 EnsureVisible( next );
2041 }
2042 }
ef44a621 2043 }
978f38c2 2044 break;
ef44a621 2045
978f38c2
VZ
2046 // <End> selects the last visible tree item
2047 case WXK_END:
2048 {
2049 wxTreeItemId last = GetRootItem();
2050
2051 while ( last.IsOk() && IsExpanded(last) )
2052 {
2053 wxTreeItemId lastChild = GetLastChild(last);
2054
2055 // it may happen if the item was expanded but then all of
2056 // its children have been deleted - so IsExpanded() returned
2057 // TRUE, but GetLastChild() returned invalid item
2058 if ( !lastChild )
2059 break;
2060
2061 last = lastChild;
2062 }
2063
2064 if ( last.IsOk() )
2065 {
2066 EnsureVisible( last );
88ac883a 2067 SelectItem( last, unselect_others, extended_select );
978f38c2
VZ
2068 }
2069 }
2070 break;
2071
2072 // <Home> selects the root item
2073 case WXK_HOME:
2074 {
2075 wxTreeItemId prev = GetRootItem();
2076 if (prev)
2077 {
2078 EnsureVisible( prev );
88ac883a 2079 SelectItem( prev, unselect_others, extended_select );
978f38c2
VZ
2080 }
2081 }
2082 break;
2083
2084 default:
2085 event.Skip();
2086 }
edaa81ae 2087}
c801d85f 2088
941830cb 2089wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
4f22cf8d 2090{
dc6c62a9
RR
2091 // We have to call this here because the label in
2092 // question might just have been added and no screen
2093 // update taken place.
2094 if (m_dirty) wxYield();
2095
67a7abf7
VZ
2096 wxClientDC dc(this);
2097 PrepareDC(dc);
06b466c7
VZ
2098 wxCoord x = dc.DeviceToLogicalX( point.x );
2099 wxCoord y = dc.DeviceToLogicalY( point.y );
91b8de8d
RR
2100 int w, h;
2101 GetSize(&w, &h);
2102
2103 flags=0;
2104 if (point.x<0) flags|=wxTREE_HITTEST_TOLEFT;
2105 if (point.x>w) flags|=wxTREE_HITTEST_TORIGHT;
2106 if (point.y<0) flags|=wxTREE_HITTEST_ABOVE;
2107 if (point.y>h) flags|=wxTREE_HITTEST_BELOW;
d3a9f4af 2108
91b8de8d 2109 return m_anchor->HitTest( wxPoint(x, y), this, flags);
4f22cf8d
RR
2110}
2111
8fb3bfe2
JS
2112// get the bounding rectangle of the item (or of its label only)
2113bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
2114 wxRect& rect,
2115 bool textOnly) const
2116{
2117 wxCHECK2_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
2118
2119 wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
2120
2121 int startX, startY;
2122 GetViewStart(& startX, & startY);
2123
2124 rect.x = i->GetX() - startX*PIXELS_PER_UNIT; rect.y = i->GetY()*PIXELS_PER_UNIT;
2125 rect.width = i->GetWidth(); rect.height = i->GetHeight();
2126
2127 return TRUE;
2128
2129 // wxFAIL_MSG(wxT("GetBoundingRect unimplemented"));
2130 // return FALSE;
2131}
2132
e179bd65
RR
2133/* **** */
2134
941830cb 2135void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
e179bd65
RR
2136{
2137 if (!item.IsOk()) return;
2138
941830cb 2139 m_currentEdit = (wxGenericTreeItem*) item.m_pItem;
9dfbf520 2140
e179bd65
RR
2141 wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
2142 te.m_item = m_currentEdit;
2143 te.SetEventObject( this );
2144 GetEventHandler()->ProcessEvent( te );
2145
2146 if (!te.IsAllowed()) return;
8dc99046 2147
dc6c62a9
RR
2148 // We have to call this here because the label in
2149 // question might just have been added and no screen
2150 // update taken place.
2151 if (m_dirty) wxYield();
9dfbf520 2152
e179bd65
RR
2153 wxString s = m_currentEdit->GetText();
2154 int x = m_currentEdit->GetX();
2155 int y = m_currentEdit->GetY();
2156 int w = m_currentEdit->GetWidth();
2157 int h = m_currentEdit->GetHeight();
9dfbf520 2158
5f1ea0ee
RR
2159 int image_h = 0;
2160 int image_w = 0;
8dc99046
VZ
2161
2162 int image = m_currentEdit->GetCurrentImage();
2163 if ( image != NO_IMAGE )
5f1ea0ee 2164 {
2c8e4738
VZ
2165 if ( m_imageListNormal )
2166 {
2167 m_imageListNormal->GetSize( image, image_w, image_h );
2168 image_w += 4;
2169 }
2170 else
2171 {
2172 wxFAIL_MSG(_T("you must create an image list to use images!"));
2173 }
5f1ea0ee
RR
2174 }
2175 x += image_w;
2176 w -= image_w + 4; // I don't know why +4 is needed
e179bd65
RR
2177
2178 wxClientDC dc(this);
2179 PrepareDC( dc );
2180 x = dc.LogicalToDeviceX( x );
2181 y = dc.LogicalToDeviceY( y );
2182
2183 wxTreeTextCtrl *text = new wxTreeTextCtrl(
2184 this, -1, &m_renameAccept, &m_renameRes, this, s, wxPoint(x-4,y-4), wxSize(w+11,h+8) );
2185 text->SetFocus();
2186}
2187
941830cb 2188void wxGenericTreeCtrl::OnRenameTimer()
e179bd65
RR
2189{
2190 Edit( m_current );
2191}
2192
941830cb 2193void wxGenericTreeCtrl::OnRenameAccept()
e179bd65
RR
2194{
2195 wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
2196 le.m_item = m_currentEdit;
2197 le.SetEventObject( this );
2198 le.m_label = m_renameRes;
2199 GetEventHandler()->ProcessEvent( le );
9dfbf520 2200
e179bd65 2201 if (!le.IsAllowed()) return;
9dfbf520 2202
5f1ea0ee 2203 SetItemText( m_currentEdit, m_renameRes );
e179bd65 2204}
9dfbf520 2205
941830cb 2206void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
c801d85f 2207{
bbe0af5b 2208 if ( !m_anchor ) return;
978f38c2 2209
3dbeaa52
VZ
2210 // we process left mouse up event (enables in-place edit), right down
2211 // (pass to the user code), left dbl click (activate item) and
2212 // dragging/moving events for items drag-and-drop
f6bcfd97
BP
2213 if ( !(event.LeftDown() ||
2214 event.LeftUp() ||
3dbeaa52
VZ
2215 event.RightDown() ||
2216 event.LeftDClick() ||
2217 event.Dragging() ||
2218 ((event.Moving() || event.RightUp()) && m_isDragging)) )
2219 {
2220 event.Skip();
2221
2222 return;
2223 }
2224
bbe0af5b
RR
2225 wxClientDC dc(this);
2226 PrepareDC(dc);
06b466c7
VZ
2227 wxCoord x = dc.DeviceToLogicalX( event.GetX() );
2228 wxCoord y = dc.DeviceToLogicalY( event.GetY() );
29d87bba 2229
3dbeaa52 2230 int flags = 0;
91b8de8d 2231 wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), this, flags);
3dbeaa52 2232
3dbeaa52 2233 if ( event.Dragging() && !m_isDragging )
bbe0af5b 2234 {
fd9811b1 2235 if (m_dragCount == 0)
8dc99046
VZ
2236 m_dragStart = wxPoint(x,y);
2237
fd9811b1 2238 m_dragCount++;
8dc99046 2239
3dbeaa52
VZ
2240 if (m_dragCount != 3)
2241 {
2242 // wait until user drags a bit further...
2243 return;
2244 }
8dc99046 2245
3dbeaa52
VZ
2246 wxEventType command = event.RightIsDown()
2247 ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
2248 : wxEVT_COMMAND_TREE_BEGIN_DRAG;
8dc99046 2249
fd9811b1
RR
2250 wxTreeEvent nevent( command, GetId() );
2251 nevent.m_item = m_current;
2252 nevent.SetEventObject(this);
3dbeaa52
VZ
2253
2254 // by default the dragging is not supported, the user code must
2255 // explicitly allow the event for it to take place
2256 nevent.Veto();
2257
2258 if ( GetEventHandler()->ProcessEvent(nevent) && nevent.IsAllowed() )
2259 {
2260 // we're going to drag this item
2261 m_isDragging = TRUE;
2262
b3a7510d
VZ
2263 // remember the old cursor because we will change it while
2264 // dragging
2265 m_oldCursor = m_cursor;
2266
2267 // in a single selection control, hide the selection temporarily
2268 if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE) )
2269 {
941830cb 2270 m_oldSelection = (wxGenericTreeItem*) GetSelection().m_pItem;
b3a7510d
VZ
2271
2272 if ( m_oldSelection )
2273 {
2274 m_oldSelection->SetHilight(FALSE);
2275 RefreshLine(m_oldSelection);
2276 }
2277 }
2278
3dbeaa52
VZ
2279 CaptureMouse();
2280 }
bbe0af5b 2281 }
3dbeaa52 2282 else if ( event.Moving() )
fd9811b1 2283 {
3dbeaa52
VZ
2284 if ( item != m_dropTarget )
2285 {
2286 // unhighlight the previous drop target
2287 DrawDropEffect(m_dropTarget);
fd9811b1 2288
3dbeaa52 2289 m_dropTarget = item;
978f38c2 2290
3dbeaa52
VZ
2291 // highlight the current drop target if any
2292 DrawDropEffect(m_dropTarget);
fb882e1c 2293
3dbeaa52
VZ
2294 wxYield();
2295 }
e179bd65 2296 }
3dbeaa52
VZ
2297 else if ( (event.LeftUp() || event.RightUp()) && m_isDragging )
2298 {
2299 // erase the highlighting
2300 DrawDropEffect(m_dropTarget);
9dfbf520 2301
3dbeaa52
VZ
2302 // generate the drag end event
2303 wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId());
88ac883a 2304
3dbeaa52
VZ
2305 event.m_item = item;
2306 event.m_pointDrag = wxPoint(x, y);
2307 event.SetEventObject(this);
91b8de8d 2308
3dbeaa52 2309 (void)GetEventHandler()->ProcessEvent(event);
29d87bba 2310
3dbeaa52
VZ
2311 m_isDragging = FALSE;
2312 m_dropTarget = (wxGenericTreeItem *)NULL;
2313
b3a7510d
VZ
2314 if ( m_oldSelection )
2315 {
2316 m_oldSelection->SetHilight(TRUE);
2317 RefreshLine(m_oldSelection);
2318 m_oldSelection = (wxGenericTreeItem *)NULL;
2319 }
2320
3dbeaa52
VZ
2321 ReleaseMouse();
2322
b3a7510d 2323 SetCursor(m_oldCursor);
3dbeaa52
VZ
2324
2325 wxYield();
2326 }
2327 else
bbe0af5b 2328 {
3dbeaa52
VZ
2329 // here we process only the messages which happen on tree items
2330
2331 m_dragCount = 0;
2332
2333 if (item == NULL) return; /* we hit the blank area */
2334
2335 if ( event.RightDown() )
2336 {
2337 wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
2338 nevent.m_item = item;
2339 nevent.m_code = 0;
2340 nevent.SetEventObject(this);
2341 GetEventHandler()->ProcessEvent(nevent);
2342 }
f6bcfd97
BP
2343 else if ( event.LeftUp() && m_lastOnSame )
2344 {
2345 if ( (item == m_current) &&
3dbeaa52
VZ
2346 (flags & wxTREE_HITTEST_ONITEMLABEL) &&
2347 HasFlag(wxTR_EDIT_LABELS) )
f6bcfd97
BP
2348 {
2349 m_renameTimer->Start( 100, TRUE );
2350 }
2351
2352 m_lastOnSame = FALSE;
3dbeaa52
VZ
2353 }
2354 else
2355 {
f6bcfd97
BP
2356 if ( event.LeftDown() )
2357 {
2358 m_lastOnSame = item == m_current;
2359 }
2360
3dbeaa52
VZ
2361 // how should the selection work for this event?
2362 bool is_multiple, extended_select, unselect_others;
2363 EventFlagsToSelType(GetWindowStyleFlag(),
2364 event.ShiftDown(),
2365 event.ControlDown(),
dfc6cd93 2366 is_multiple, extended_select, unselect_others);
3dbeaa52 2367
f6bcfd97 2368 if ( (flags & wxTREE_HITTEST_ONITEMBUTTON) && event.LeftDown() )
3dbeaa52
VZ
2369 {
2370 Toggle( item );
2371 if ( is_multiple )
2372 return;
2373 }
2374
2375 SelectItem(item, unselect_others, extended_select);
2376
2377 if ( event.LeftDClick() )
2378 {
f6bcfd97
BP
2379 // double clicking should not start editing the item label
2380 m_renameTimer->Stop();
2381 m_lastOnSame = FALSE;
2382
3dbeaa52
VZ
2383 wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
2384 nevent.m_item = item;
2385 nevent.m_code = 0;
2386 nevent.SetEventObject( this );
2387 GetEventHandler()->ProcessEvent( nevent );
2388 }
2389 }
bbe0af5b 2390 }
edaa81ae 2391}
c801d85f 2392
941830cb 2393void wxGenericTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
3db7be80 2394{
bbe0af5b
RR
2395 /* after all changes have been done to the tree control,
2396 * we actually redraw the tree when everything is over */
ef44a621 2397
f65635b5
VZ
2398 if (!m_dirty)
2399 return;
ef44a621 2400
bbe0af5b 2401 m_dirty = FALSE;
3db7be80 2402
bbe0af5b 2403 CalculatePositions();
91b8de8d 2404 Refresh();
bbe0af5b 2405 AdjustMyScrollbars();
3db7be80
RR
2406}
2407
941830cb 2408void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
d3a9f4af 2409{
e06b9569
JS
2410 wxCoord text_w = 0;
2411 wxCoord text_h = 0;
9dfbf520 2412
a62867a5 2413 if (item->IsBold())
eff869aa 2414 dc.SetFont(m_boldFont);
9dfbf520 2415
91b8de8d 2416 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
a62867a5 2417 text_h+=2;
91b8de8d 2418
eff869aa
RR
2419 // restore normal font
2420 dc.SetFont( m_normalFont );
9dfbf520 2421
91b8de8d
RR
2422 int image_h = 0;
2423 int image_w = 0;
8dc99046
VZ
2424 int image = item->GetCurrentImage();
2425 if ( image != NO_IMAGE )
91b8de8d 2426 {
2c8e4738
VZ
2427 if ( m_imageListNormal )
2428 {
2429 m_imageListNormal->GetSize( image, image_w, image_h );
2430 image_w += 4;
2431 }
91b8de8d
RR
2432 }
2433
2434 int total_h = (image_h > text_h) ? image_h : text_h;
2435
06b466c7 2436 if (total_h < 40)
f2593d0d 2437 total_h += 2; // at least 2 pixels
06b466c7 2438 else
f2593d0d 2439 total_h += total_h/10; // otherwise 10% extra spacing
91b8de8d
RR
2440
2441 item->SetHeight(total_h);
6cedba09
VZ
2442 if (total_h>m_lineHeight)
2443 m_lineHeight=total_h;
bbe0af5b 2444
91b8de8d
RR
2445 item->SetWidth(image_w+text_w+2);
2446}
2447
2448// -----------------------------------------------------------------------------
2449// for developper : y is now the top of the level
2450// not the middle of it !
941830cb 2451void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 2452{
bbe0af5b 2453 int horizX = level*m_indent;
389cdc7a 2454
91b8de8d 2455 CalculateSize( item, dc );
d3a9f4af 2456
91b8de8d 2457 // set its position
cf724bce 2458 item->SetX( horizX+m_indent+m_spacing );
91b8de8d
RR
2459 item->SetY( y );
2460 y+=GetLineHeight(item);
4c681997 2461
bbe0af5b
RR
2462 if ( !item->IsExpanded() )
2463 {
f65635b5 2464 // we dont need to calculate collapsed branches
bbe0af5b
RR
2465 return;
2466 }
389cdc7a 2467
91b8de8d
RR
2468 wxArrayGenericTreeItems& children = item->GetChildren();
2469 size_t n, count = children.Count();
2470 for (n = 0; n < count; ++n )
f2593d0d 2471 CalculateLevel( children[n], dc, level+1, y ); // recurse
edaa81ae 2472}
c801d85f 2473
941830cb 2474void wxGenericTreeCtrl::CalculatePositions()
c801d85f 2475{
bbe0af5b 2476 if ( !m_anchor ) return;
29d87bba 2477
bbe0af5b
RR
2478 wxClientDC dc(this);
2479 PrepareDC( dc );
29d87bba 2480
eff869aa 2481 dc.SetFont( m_normalFont );
29d87bba 2482
bbe0af5b 2483 dc.SetPen( m_dottedPen );
91b8de8d
RR
2484 //if(GetImageList() == NULL)
2485 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 2486
8dc99046 2487 int y = 2;
f65635b5 2488 CalculateLevel( m_anchor, dc, 0, y ); // start recursion
edaa81ae 2489}
c801d85f 2490
941830cb 2491void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
c801d85f 2492{
e6527f9d
RR
2493 if (m_dirty) return;
2494
bbe0af5b
RR
2495 wxClientDC dc(this);
2496 PrepareDC(dc);
4832f7c0 2497
bbe0af5b
RR
2498 int cw = 0;
2499 int ch = 0;
2500 GetClientSize( &cw, &ch );
4832f7c0 2501
bbe0af5b
RR
2502 wxRect rect;
2503 rect.x = dc.LogicalToDeviceX( 0 );
2504 rect.width = cw;
2505 rect.y = dc.LogicalToDeviceY( item->GetY() );
2506 rect.height = ch;
f135ff73 2507
bbe0af5b 2508 Refresh( TRUE, &rect );
f135ff73 2509
bbe0af5b 2510 AdjustMyScrollbars();
edaa81ae 2511}
c801d85f 2512
941830cb 2513void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
c801d85f 2514{
e6527f9d
RR
2515 if (m_dirty) return;
2516
bbe0af5b
RR
2517 wxClientDC dc(this);
2518 PrepareDC( dc );
2519
5391f772
SB
2520 int cw = 0;
2521 int ch = 0;
2522 GetClientSize( &cw, &ch );
2523
bbe0af5b 2524 wxRect rect;
5391f772
SB
2525 rect.x = dc.LogicalToDeviceX( 0 );
2526 rect.y = dc.LogicalToDeviceY( item->GetY() );
2527 rect.width = cw;
91b8de8d 2528 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
978f38c2 2529
bbe0af5b 2530 Refresh( TRUE, &rect );
edaa81ae 2531}
c801d85f 2532