]> git.saurik.com Git - wxWidgets.git/blame - wxPython/contrib/gizmos/wxCode/src/treelistctrl.cpp
Another package name fix
[wxWidgets.git] / wxPython / contrib / gizmos / wxCode / src / treelistctrl.cpp
CommitLineData
1fded56b 1/////////////////////////////////////////////////////////////////////////////
28eab81f 2// Name: treelistctrl.cpp
1fded56b
RD
3// Purpose: multi column tree control implementation
4// Author: Robert Roebling
33328cd8 5// Maintainer: Otto Wyss
1fded56b 6// Created: 01/02/97
33328cd8
RD
7// RCS-ID: $Id$
8// Copyright: (c) 2004 Robert Roebling, Julian Smart, Alberto Griggio,
28eab81f 9// Vadim Zeitlin, Otto Wyss
33328cd8 10// Licence: wxWindows
1fded56b
RD
11/////////////////////////////////////////////////////////////////////////////
12
13// ===========================================================================
14// declarations
15// ===========================================================================
16
17// ---------------------------------------------------------------------------
18// headers
19// ---------------------------------------------------------------------------
20
1fded56b
RD
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25 #pragma hdrstop
26#endif
27
28
29#include <wx/treebase.h>
30#include <wx/timer.h>
31#include <wx/textctrl.h>
32#include <wx/imaglist.h>
33#include <wx/settings.h>
34#include <wx/dcclient.h>
35#include <wx/dcscreen.h>
36#include <wx/scrolwin.h>
33328cd8 37#if wxCHECK_VERSION(2, 7, 0)
8e3ca43b 38#include <wx/renderer.h>
1fded56b
RD
39#endif
40
8e3ca43b 41#ifdef __WXMAC__
33328cd8 42#include "wx/mac/private.h"
8e3ca43b
RD
43#endif
44
33328cd8
RD
45#include "wx/treelistctrl.h"
46
8e3ca43b 47
1fded56b
RD
48// ---------------------------------------------------------------------------
49// array types
50// ---------------------------------------------------------------------------
51
52class wxTreeListItem;
53
28eab81f 54#if !wxCHECK_VERSION(2, 5, 0)
1fded56b 55WX_DEFINE_ARRAY(wxTreeListItem *, wxArrayTreeListItems);
28eab81f
RD
56#else
57WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems);
58#endif
1fded56b
RD
59
60#include <wx/dynarray.h>
61WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo);
62#include <wx/arrimpl.cpp>
63WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo);
64
1fded56b
RD
65
66// --------------------------------------------------------------------------
67// constants
68// --------------------------------------------------------------------------
69
70static const int NO_IMAGE = -1;
71
33328cd8
RD
72static const int LINEHEIGHT = 10;
73static const int LINEATROOT = 5;
74static const int MARGIN = 2;
75static const int MININDENT = 16;
76static const int BTNWIDTH = 9;
77static const int BTNHEIGHT = 9;
8e3ca43b
RD
78static const int EXTRA_WIDTH = 4;
79static const int EXTRA_HEIGHT = 4;
8e3ca43b
RD
80static const int HEADER_OFFSET_X = 1;
81static const int HEADER_OFFSET_Y = 1;
82
33328cd8
RD
83static const int DRAG_TIMER_TICKS = 250; // minimum drag wait time in ms
84static const int FIND_TIMER_TICKS = 500; // minimum find wait time in ms
85static const int RENAME_TIMER_TICKS = 250; // minimum rename wait time in ms
8e3ca43b 86
33328cd8 87const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl");
1fded56b
RD
88
89static wxTreeListColumnInfo wxInvalidTreeListColumnInfo;
90
91
92// ---------------------------------------------------------------------------
93// private classes
94// ---------------------------------------------------------------------------
95//-----------------------------------------------------------------------------
96// wxTreeListHeaderWindow (internal)
97//-----------------------------------------------------------------------------
98
99class wxTreeListHeaderWindow : public wxWindow
100{
101protected:
28eab81f 102 wxTreeListMainWindow *m_owner;
33328cd8
RD
103 const wxCursor *m_currentCursor;
104 const wxCursor *m_resizeCursor;
105 bool m_isDragging;
1fded56b
RD
106
107 // column being resized
108 int m_column;
109
110 // divider line position in logical (unscrolled) coords
111 int m_currentX;
112
113 // minimal position beyond which the divider line can't be dragged in
114 // logical coords
115 int m_minX;
116
117 wxArrayTreeListColumnInfo m_columns;
118
119 // total width of the columns
120 int m_total_col_width;
121
5c86a7fa
RD
122#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
123 // which col header is currently highlighted with mouse-over
124 int m_hotTrackCol;
1fded56b 125
5c86a7fa
RD
126 int XToCol(int x);
127 void RefreshColLabel(int col);
128#endif
129
1fded56b
RD
130public:
131 wxTreeListHeaderWindow();
132
133 wxTreeListHeaderWindow( wxWindow *win,
28eab81f
RD
134 wxWindowID id,
135 wxTreeListMainWindow *owner,
136 const wxPoint &pos = wxDefaultPosition,
137 const wxSize &size = wxDefaultSize,
138 long style = 0,
33328cd8 139 const wxString &name = _T("wxtreelistctrlcolumntitles") );
1fded56b
RD
140
141 virtual ~wxTreeListHeaderWindow();
142
143 void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
144 void DrawCurrent();
145 void AdjustDC(wxDC& dc);
146
147 void OnPaint( wxPaintEvent &event );
148 void OnMouse( wxMouseEvent &event );
149 void OnSetFocus( wxFocusEvent &event );
150
33328cd8
RD
151 // total width of all columns
152 int GetWidth() const { return m_total_col_width; }
1fded56b 153
33328cd8
RD
154 // column manipulation
155 int GetColumnCount() const { return m_columns.GetCount(); }
1fded56b 156
33328cd8 157 void AddColumn (const wxTreeListColumnInfo& colInfo);
1fded56b 158
33328cd8 159 void InsertColumn (int before, const wxTreeListColumnInfo& colInfo);
1fded56b 160
33328cd8 161 void RemoveColumn (int column);
1fded56b 162
33328cd8
RD
163 // column information manipulation
164 const wxTreeListColumnInfo& GetColumn (int column) const{
165 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
166 wxInvalidTreeListColumnInfo, _T("Invalid column"));
1fded56b
RD
167 return m_columns[column];
168 }
33328cd8
RD
169 wxTreeListColumnInfo& GetColumn (int column) {
170 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
171 wxInvalidTreeListColumnInfo, _T("Invalid column"));
1fded56b
RD
172 return m_columns[column];
173 }
33328cd8 174 void SetColumn (int column, const wxTreeListColumnInfo& info);
1fded56b 175
33328cd8
RD
176 wxString GetColumnText (int column) const {
177 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
178 wxEmptyString, _T("Invalid column"));
179 return m_columns[column].GetText();
1fded56b 180 }
33328cd8
RD
181 void SetColumnText (int column, const wxString& text) {
182 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
183 _T("Invalid column"));
184 m_columns[column].SetText (text);
28eab81f
RD
185 }
186
33328cd8
RD
187 int GetColumnAlignment (int column) const {
188 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
189 wxALIGN_LEFT, _T("Invalid column"));
190 return m_columns[column].GetAlignment();
191 }
192 void SetColumnAlignment (int column, int flag) {
193 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
194 _T("Invalid column"));
195 m_columns[column].SetAlignment (flag);
1fded56b
RD
196 }
197
33328cd8
RD
198 int GetColumnWidth (int column) const {
199 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
200 -1, _T("Invalid column"));
1fded56b
RD
201 return m_columns[column].GetWidth();
202 }
33328cd8 203 void SetColumnWidth (int column, int width);
1fded56b 204
33328cd8
RD
205 bool IsColumnEditable (int column) const {
206 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
207 false, _T("Invalid column"));
208 return m_columns[column].IsEditable();
209 }
1fded56b 210
33328cd8
RD
211 bool IsColumnShown (int column) const {
212 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
213 true, _T("Invalid column"));
214 return m_columns[column].IsShown();
28eab81f
RD
215 }
216
1fded56b
RD
217 // needs refresh
218 bool m_dirty;
219
220private:
221 // common part of all ctors
222 void Init();
223
224 void SendListEvent(wxEventType type, wxPoint pos);
225
226 DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow)
227 DECLARE_EVENT_TABLE()
228};
229
230
231// this is the "true" control
232class wxTreeListMainWindow: public wxScrolledWindow
233{
234public:
235 // creation
236 // --------
237 wxTreeListMainWindow() { Init(); }
238
33328cd8 239 wxTreeListMainWindow (wxTreeListCtrl *parent, wxWindowID id = -1,
1fded56b
RD
240 const wxPoint& pos = wxDefaultPosition,
241 const wxSize& size = wxDefaultSize,
242 long style = wxTR_DEFAULT_STYLE,
243 const wxValidator &validator = wxDefaultValidator,
33328cd8 244 const wxString& name = _T("wxtreelistmainwindow"))
1fded56b
RD
245 {
246 Init();
33328cd8 247 Create (parent, id, pos, size, style, validator, name);
1fded56b
RD
248 }
249
250 virtual ~wxTreeListMainWindow();
251
252 bool Create(wxTreeListCtrl *parent, wxWindowID id = -1,
253 const wxPoint& pos = wxDefaultPosition,
254 const wxSize& size = wxDefaultSize,
255 long style = wxTR_DEFAULT_STYLE,
256 const wxValidator &validator = wxDefaultValidator,
33328cd8 257 const wxString& name = _T("wxtreelistctrl"));
1fded56b
RD
258
259 // accessors
260 // ---------
261
33328cd8
RD
262 // return true if this is a virtual list control
263 bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); }
264
28eab81f 265 // get the total number of items in the control
1fded56b
RD
266 size_t GetCount() const;
267
28eab81f
RD
268 // indent is the number of pixels the children are indented relative to
269 // the parents position. SetIndent() also redraws the control
270 // immediately.
1fded56b
RD
271 unsigned int GetIndent() const { return m_indent; }
272 void SetIndent(unsigned int indent);
273
1fded56b
RD
274 // see wxTreeListCtrl for the meaning
275 unsigned int GetLineSpacing() const { return m_linespacing; }
276 void SetLineSpacing(unsigned int spacing);
277
28eab81f
RD
278 // image list: these functions allow to associate an image list with
279 // the control and retrieve it. Note that when assigned with
280 // SetImageList, the control does _not_ delete
281 // the associated image list when it's deleted in order to allow image
282 // lists to be shared between different controls. If you use
283 // AssignImageList, the control _does_ delete the image list.
284
285 // The normal image list is for the icons which correspond to the
286 // normal tree item state (whether it is selected or not).
287 // Additionally, the application might choose to show a state icon
288 // which corresponds to an app-defined item state (for example,
289 // checked/unchecked) which are taken from the state image list.
33328cd8
RD
290 wxImageList *GetImageList() const { return m_imageListNormal; }
291 wxImageList *GetStateImageList() const { return m_imageListState; }
292 wxImageList *GetButtonsImageList() const { return m_imageListButtons; }
1fded56b
RD
293
294 void SetImageList(wxImageList *imageList);
295 void SetStateImageList(wxImageList *imageList);
296 void SetButtonsImageList(wxImageList *imageList);
297 void AssignImageList(wxImageList *imageList);
298 void AssignStateImageList(wxImageList *imageList);
299 void AssignButtonsImageList(wxImageList *imageList);
300
301 // Functions to work with tree ctrl items.
302
303 // accessors
304 // ---------
305
28eab81f 306 // retrieve item's label
33328cd8
RD
307 wxString GetItemText (const wxTreeItemId& item) const
308 { return GetItemText (item, GetMainColumn()); }
309 wxString GetItemText (const wxTreeItemId& item, int column) const;
310 wxString GetItemText (wxTreeItemData* item, int column) const;
311
28eab81f 312 // get one of the images associated with the item (normal by default)
33328cd8
RD
313 int GetItemImage (const wxTreeItemId& item,
314 wxTreeItemIcon which = wxTreeItemIcon_Normal) const
315 { return GetItemImage (item, GetMainColumn(), which); }
316 int GetItemImage (const wxTreeItemId& item, int column,
317 wxTreeItemIcon which = wxTreeItemIcon_Normal) const;
1fded56b 318
28eab81f 319 // get the data associated with the item
1fded56b
RD
320 wxTreeItemData *GetItemData(const wxTreeItemId& item) const;
321
322 bool GetItemBold(const wxTreeItemId& item) const;
323 wxColour GetItemTextColour(const wxTreeItemId& item) const;
324 wxColour GetItemBackgroundColour(const wxTreeItemId& item) const;
325 wxFont GetItemFont(const wxTreeItemId& item) const;
326
327 // modifiers
328 // ---------
329
28eab81f 330 // set item's label
33328cd8
RD
331 void SetItemText (const wxTreeItemId& item, const wxString& text)
332 { SetItemText (item, GetMainColumn(), text); }
333 void SetItemText (const wxTreeItemId& item, int column, const wxString& text);
1fded56b 334
28eab81f 335 // get one of the images associated with the item (normal by default)
33328cd8
RD
336 void SetItemImage (const wxTreeItemId& item, int image,
337 wxTreeItemIcon which = wxTreeItemIcon_Normal)
338 { SetItemImage (item, GetMainColumn(), image, which); }
339 void SetItemImage (const wxTreeItemId& item, int column, int image,
340 wxTreeItemIcon which = wxTreeItemIcon_Normal);
1fded56b 341
28eab81f 342 // associate some data with the item
1fded56b
RD
343 void SetItemData(const wxTreeItemId& item, wxTreeItemData *data);
344
28eab81f
RD
345 // force appearance of [+] button near the item. This is useful to
346 // allow the user to expand the items which don't have any children now
347 // - but instead add them only when needed, thus minimizing memory
348 // usage and loading time.
33328cd8 349 void SetItemHasChildren(const wxTreeItemId& item, bool has = true);
1fded56b 350
28eab81f 351 // the item will be shown in bold
33328cd8 352 void SetItemBold(const wxTreeItemId& item, bool bold = true);
1fded56b 353
28eab81f
RD
354 // set the item's text colour
355 void SetItemTextColour(const wxTreeItemId& item, const wxColour& colour);
1fded56b 356
28eab81f
RD
357 // set the item's background colour
358 void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& colour);
1fded56b 359
28eab81f 360 // set the item's font (should be of the same height for all items)
1fded56b
RD
361 void SetItemFont(const wxTreeItemId& item, const wxFont& font);
362
28eab81f 363 // set the window font
1fded56b
RD
364 virtual bool SetFont( const wxFont &font );
365
28eab81f
RD
366 // set the styles. No need to specify a GetWindowStyle here since
367 // the base wxWindow member function will do it for us
1fded56b
RD
368 void SetWindowStyle(const long styles);
369
370 // item status inquiries
371 // ---------------------
372
28eab81f 373 // is the item visible (it might be outside the view or not expanded)?
33328cd8 374 bool IsVisible(const wxTreeItemId& item, bool fullRow) const;
28eab81f 375 // does the item has any children?
33328cd8 376 bool HasChildren(const wxTreeItemId& item) const;
28eab81f 377 // is the item expanded (only makes sense if HasChildren())?
1fded56b 378 bool IsExpanded(const wxTreeItemId& item) const;
28eab81f 379 // is this item currently selected (the same as has focus)?
1fded56b 380 bool IsSelected(const wxTreeItemId& item) const;
28eab81f 381 // is item text in bold font?
1fded56b
RD
382 bool IsBold(const wxTreeItemId& item) const;
383 // does the layout include space for a button?
384
385 // number of children
386 // ------------------
387
33328cd8 388 // if 'recursively' is false, only immediate children count, otherwise
28eab81f 389 // the returned number is the number of all items in this branch
33328cd8 390 size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true);
1fded56b
RD
391
392 // navigation
393 // ----------
394
33328cd8 395 // wxTreeItemId.IsOk() will return false if there is no such item
1fded56b 396
28eab81f 397 // get the root tree item
33328cd8 398 wxTreeItemId GetRootItem() const { return m_rootItem; }
1fded56b 399
33328cd8
RD
400 // get the item currently selected, only if a single item is selected
401 wxTreeItemId GetSelection() const { return m_selectItem; }
1fded56b 402
33328cd8 403 // get all the items currently selected, return count of items
1fded56b
RD
404 size_t GetSelections(wxArrayTreeItemIds&) const;
405
28eab81f
RD
406 // get the parent of this item (may return NULL if root)
407 wxTreeItemId GetItemParent(const wxTreeItemId& item) const;
1fded56b 408
28eab81f
RD
409 // for this enumeration function you must pass in a "cookie" parameter
410 // which is opaque for the application but is necessary for the library
411 // to make these functions reentrant (i.e. allow more than one
412 // enumeration on one and the same object simultaneously). Of course,
413 // the "cookie" passed to GetFirstChild() and GetNextChild() should be
414 // the same!
1fded56b 415
33328cd8 416 // get child of this item
28eab81f 417#if !wxCHECK_VERSION(2, 5, 0)
1fded56b 418 wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const;
1fded56b 419 wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const;
28eab81f 420 wxTreeItemId GetPrevChild(const wxTreeItemId& item, long& cookie) const;
33328cd8 421 wxTreeItemId GetLastChild(const wxTreeItemId& item, long& cookie) const;
28eab81f 422#else
33328cd8
RD
423 wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
424 wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
28eab81f 425 wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
33328cd8 426 wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
28eab81f 427#endif
1fded56b 428
33328cd8 429 // get sibling of this item
1fded56b 430 wxTreeItemId GetNextSibling(const wxTreeItemId& item) const;
1fded56b
RD
431 wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const;
432
33328cd8
RD
433 // get item in the full tree (currently only for internal use)
434 wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const;
435 wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const;
436
437 // get expanded item, see IsExpanded()
438 wxTreeItemId GetFirstExpandedItem() const;
439 wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const;
440 wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const;
1fded56b 441
33328cd8
RD
442 // get visible item, see IsVisible()
443 wxTreeItemId GetFirstVisibleItem(bool fullRow) const;
444 wxTreeItemId GetNextVisible(const wxTreeItemId& item, bool fullRow) const;
445 wxTreeItemId GetPrevVisible(const wxTreeItemId& item, bool fullRow) const;
1fded56b
RD
446
447 // operations
448 // ----------
449
28eab81f 450 // add the root node to the tree
33328cd8
RD
451 wxTreeItemId AddRoot (const wxString& text,
452 int image = -1, int selectedImage = -1,
453 wxTreeItemData *data = NULL);
1fded56b 454
28eab81f 455 // insert a new item in as the first child of the parent
1fded56b
RD
456 wxTreeItemId PrependItem(const wxTreeItemId& parent,
457 const wxString& text,
458 int image = -1, int selectedImage = -1,
459 wxTreeItemData *data = NULL);
460
28eab81f 461 // insert a new item after a given one
1fded56b
RD
462 wxTreeItemId InsertItem(const wxTreeItemId& parent,
463 const wxTreeItemId& idPrevious,
464 const wxString& text,
465 int image = -1, int selectedImage = -1,
466 wxTreeItemData *data = NULL);
467
28eab81f 468 // insert a new item before the one with the given index
1fded56b
RD
469 wxTreeItemId InsertItem(const wxTreeItemId& parent,
470 size_t index,
471 const wxString& text,
472 int image = -1, int selectedImage = -1,
473 wxTreeItemData *data = NULL);
474
28eab81f 475 // insert a new item in as the last child of the parent
1fded56b
RD
476 wxTreeItemId AppendItem(const wxTreeItemId& parent,
477 const wxString& text,
478 int image = -1, int selectedImage = -1,
479 wxTreeItemData *data = NULL);
480
28eab81f 481 // delete this item and associated data if any
1fded56b 482 void Delete(const wxTreeItemId& item);
28eab81f
RD
483 // delete all children (but don't delete the item itself)
484 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
1fded56b 485 void DeleteChildren(const wxTreeItemId& item);
33328cd8 486 // delete the root and all its children from the tree
28eab81f 487 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
33328cd8 488 void DeleteRoot();
1fded56b 489
28eab81f 490 // expand this item
1fded56b 491 void Expand(const wxTreeItemId& item);
28eab81f 492 // expand this item and all subitems recursively
1fded56b 493 void ExpandAll(const wxTreeItemId& item);
28eab81f 494 // collapse the item without removing its children
1fded56b 495 void Collapse(const wxTreeItemId& item);
28eab81f 496 // collapse the item and remove all children
1fded56b 497 void CollapseAndReset(const wxTreeItemId& item);
28eab81f 498 // toggles the current state
1fded56b
RD
499 void Toggle(const wxTreeItemId& item);
500
28eab81f 501 // remove the selection from currently selected item (if any)
1fded56b
RD
502 void Unselect();
503 void UnselectAll();
28eab81f 504 // select this item
33328cd8
RD
505 void SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL,
506 bool unselect_others = true);
507 void SelectAll();
28eab81f
RD
508 // make sure this item is visible (expanding the parent item and/or
509 // scrolling to this item if necessary)
1fded56b 510 void EnsureVisible(const wxTreeItemId& item);
28eab81f 511 // scroll to this item (but don't expand its parent)
1fded56b
RD
512 void ScrollTo(const wxTreeItemId& item);
513 void AdjustMyScrollbars();
514
28eab81f
RD
515 // The first function is more portable (because easier to implement
516 // on other platforms), but the second one returns some extra info.
33328cd8
RD
517 wxTreeItemId HitTest (const wxPoint& point)
518 { int flags; int column; return HitTest (point, flags, column); }
519 wxTreeItemId HitTest (const wxPoint& point, int& flags)
520 { int column; return HitTest (point, flags, column); }
521 wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column);
1fded56b
RD
522
523
28eab81f 524 // get the bounding rectangle of the item (or of its label only)
1fded56b
RD
525 bool GetBoundingRect(const wxTreeItemId& item,
526 wxRect& rect,
33328cd8 527 bool textOnly = false) const;
1fded56b 528
28eab81f
RD
529 // Start editing the item label: this (temporarily) replaces the item
530 // with a one line edit control. The item will be selected if it hadn't
531 // been before.
33328cd8 532 void EditLabel (const wxTreeItemId& item, int column);
1fded56b
RD
533
534 // sorting
28eab81f
RD
535 // this function is called to compare 2 items and should return -1, 0
536 // or +1 if the first item is less than, equal to or greater than the
537 // second one. The base class version performs alphabetic comparaison
538 // of item labels (GetText)
1fded56b
RD
539 virtual int OnCompareItems(const wxTreeItemId& item1,
540 const wxTreeItemId& item2);
28eab81f
RD
541 // sort the children of this item using OnCompareItems
542 //
543 // NB: this function is not reentrant and not MT-safe (FIXME)!
1fded56b
RD
544 void SortChildren(const wxTreeItemId& item);
545
28eab81f 546 // searching
33328cd8 547 wxTreeItemId FindItem (const wxTreeItemId& item, const wxString& str, int mode = 0);
1fded56b
RD
548
549 // implementation only from now on
550
551 // overridden base class virtuals
552 virtual bool SetBackgroundColour(const wxColour& colour);
553 virtual bool SetForegroundColour(const wxColour& colour);
554
33328cd8
RD
555 // drop over item
556 void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL);
557
1fded56b
RD
558 // callbacks
559 void OnPaint( wxPaintEvent &event );
560 void OnSetFocus( wxFocusEvent &event );
561 void OnKillFocus( wxFocusEvent &event );
562 void OnChar( wxKeyEvent &event );
563 void OnMouse( wxMouseEvent &event );
564 void OnIdle( wxIdleEvent &event );
33328cd8 565 void OnScroll(wxScrollWinEvent& event);
1fded56b
RD
566
567 // implementation helpers
568 void SendDeleteEvent(wxTreeListItem *itemBeingDeleted);
569
33328cd8 570 int GetColumnCount() const
1fded56b
RD
571 { return m_owner->GetHeaderWindow()->GetColumnCount(); }
572
33328cd8
RD
573 void SetMainColumn (int column)
574 { if ((column >= 0) && (column < GetColumnCount())) m_main_column = column; }
1fded56b 575
33328cd8 576 int GetMainColumn() const { return m_main_column; }
1fded56b 577
33328cd8
RD
578 int GetBestColumnWidth (int column, wxTreeItemId parent = wxTreeItemId());
579 int GetItemWidth (int column, wxTreeListItem *item);
580 wxFont GetItemFont (wxTreeListItem *item);
28eab81f
RD
581
582 void SetFocus();
583
1fded56b 584protected:
33328cd8 585 wxTreeListCtrl* m_owner;
1fded56b 586
33328cd8 587 int m_main_column;
1fded56b
RD
588
589 friend class wxTreeListItem;
590 friend class wxTreeListRenameTimer;
33328cd8 591 friend class wxEditTextCtrl;
1fded56b
RD
592
593 wxFont m_normalFont;
594 wxFont m_boldFont;
595
33328cd8
RD
596 wxTreeListItem *m_rootItem; // root item
597 wxTreeListItem *m_curItem; // current item, either selected or marked
598 wxTreeListItem *m_shiftItem; // item, where the shift key was pressed
599 wxTreeListItem *m_editItem; // item, which is currently edited
600 wxTreeListItem *m_selectItem; // current selected item, not with wxTR_MULTIPLE
601
602 int m_curColumn;
603
28eab81f
RD
604 int m_btnWidth, m_btnWidth2;
605 int m_btnHeight, m_btnHeight2;
606 int m_imgWidth, m_imgWidth2;
607 int m_imgHeight, m_imgHeight2;
1fded56b 608 unsigned short m_indent;
1fded56b
RD
609 int m_lineHeight;
610 unsigned short m_linespacing;
611 wxPen m_dottedPen;
612 wxBrush *m_hilightBrush,
613 *m_hilightUnfocusedBrush;
614 bool m_hasFocus;
615public:
616 bool m_dirty;
617protected:
618 bool m_ownsImageListNormal,
619 m_ownsImageListState,
620 m_ownsImageListButtons;
621 bool m_isDragging; // true between BEGIN/END drag events
622 bool m_renameAccept;
623 bool m_lastOnSame; // last click on the same item as prev
33328cd8
RD
624 bool m_left_down_selection;
625
1fded56b
RD
626 wxImageList *m_imageListNormal,
627 *m_imageListState,
628 *m_imageListButtons;
629
630 int m_dragCount;
33328cd8
RD
631 wxTimer *m_dragTimer;
632 wxTreeListItem *m_dragItem;
1fded56b
RD
633
634 wxTimer *m_renameTimer;
635 wxString m_renameRes;
636
28eab81f
RD
637 // char navigation
638 wxTimer *m_findTimer;
639 wxString m_findStr;
640
1fded56b
RD
641 // the common part of all ctors
642 void Init();
643
644 // misc helpers
645 wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
646 size_t previous,
647 const wxString& text,
648 int image, int selectedImage,
649 wxTreeItemData *data);
650 bool HasButtons(void) const
33328cd8 651 { return (m_imageListButtons) || HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); }
1fded56b
RD
652
653protected:
654 void CalculateLineHeight();
655 int GetLineHeight(wxTreeListItem *item) const;
656 void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y,
33328cd8 657 int x_maincol);
1fded56b
RD
658 void PaintItem( wxTreeListItem *item, wxDC& dc);
659
660 void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y,
33328cd8 661 int x_maincol);
1fded56b
RD
662 void CalculatePositions();
663 void CalculateSize( wxTreeListItem *item, wxDC &dc );
664
33328cd8
RD
665 void RefreshSubtree (wxTreeListItem *item);
666 void RefreshLine (wxTreeListItem *item);
1fded56b
RD
667
668 // redraw all selected items
669 void RefreshSelected();
670
671 // RefreshSelected() recursive helper
33328cd8 672 void RefreshSelectedUnder (wxTreeListItem *item);
1fded56b
RD
673
674 void OnRenameTimer();
675 void OnRenameAccept();
676
677 void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const;
33328cd8
RD
678 bool TagAllChildrenUntilLast (wxTreeListItem *crt_item, wxTreeListItem *last_item);
679 bool TagNextChildren (wxTreeListItem *crt_item, wxTreeListItem *last_item);
680 void UnselectAllChildren (wxTreeListItem *item );
1fded56b
RD
681
682private:
683 DECLARE_EVENT_TABLE()
684 DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow)
685};
686
687
688// timer used for enabling in-place edit
689class wxTreeListRenameTimer: public wxTimer
690{
691public:
692 wxTreeListRenameTimer( wxTreeListMainWindow *owner );
693
694 void Notify();
695
696private:
697 wxTreeListMainWindow *m_owner;
698};
699
700// control used for in-place edit
33328cd8 701class wxEditTextCtrl: public wxTextCtrl
1fded56b
RD
702{
703public:
33328cd8
RD
704 wxEditTextCtrl (wxWindow *parent,
705 const wxWindowID id,
706 bool *accept,
707 wxString *res,
708 wxTreeListMainWindow *owner,
709 const wxString &value = wxEmptyString,
710 const wxPoint &pos = wxDefaultPosition,
711 const wxSize &size = wxDefaultSize,
712 int style = 0,
713 const wxValidator& validator = wxDefaultValidator,
714 const wxString &name = wxTextCtrlNameStr );
1fded56b
RD
715
716 void OnChar( wxKeyEvent &event );
717 void OnKeyUp( wxKeyEvent &event );
718 void OnKillFocus( wxFocusEvent &event );
719
720private:
721 bool *m_accept;
722 wxString *m_res;
723 wxTreeListMainWindow *m_owner;
724 wxString m_startValue;
725 bool m_finished;
726
727 DECLARE_EVENT_TABLE()
728};
729
730// a tree item
731class wxTreeListItem
732{
733public:
734 // ctors & dtor
735 wxTreeListItem() { m_data = NULL; }
736 wxTreeListItem( wxTreeListMainWindow *owner,
737 wxTreeListItem *parent,
738 const wxArrayString& text,
739 int image,
740 int selImage,
741 wxTreeItemData *data );
742
743 ~wxTreeListItem();
744
745 // trivial accessors
746 wxArrayTreeListItems& GetChildren() { return m_children; }
747
748 const wxString GetText() const
749 {
33328cd8 750 return GetText(0);
1fded56b 751 }
33328cd8 752 const wxString GetText (int column) const
1fded56b 753 {
33328cd8
RD
754 if(m_text.GetCount() > 0)
755 {
756 if( IsVirtual() ) return m_owner->GetItemText( m_data, column );
757 else return m_text[column];
758 }
1fded56b
RD
759 return wxEmptyString;
760 }
33328cd8
RD
761
762 int GetImage (wxTreeItemIcon which = wxTreeItemIcon_Normal) const
1fded56b 763 { return m_images[which]; }
33328cd8 764 int GetImage (int column, wxTreeItemIcon which=wxTreeItemIcon_Normal) const
1fded56b 765 {
33328cd8
RD
766 if(column == m_owner->GetMainColumn()) return m_images[which];
767 if(column < (int)m_col_images.GetCount()) return m_col_images[column];
1fded56b
RD
768 return NO_IMAGE;
769 }
33328cd8 770
1fded56b
RD
771 wxTreeItemData *GetData() const { return m_data; }
772
773 // returns the current image for the item (depending on its
774 // selected/expanded/whatever state)
775 int GetCurrentImage() const;
776
33328cd8
RD
777 void SetText (const wxString &text );
778 void SetText (int column, const wxString& text)
1fded56b 779 {
33328cd8
RD
780 if (column < (int)m_text.GetCount()) {
781 m_text[column] = text;
782 }else if (column < m_owner->GetColumnCount()) {
1fded56b 783 int howmany = m_owner->GetColumnCount();
33328cd8
RD
784 for (int i = m_text.GetCount(); i < howmany; ++i) m_text.Add (wxEmptyString);
785 m_text[column] = text;
1fded56b
RD
786 }
787 }
33328cd8
RD
788 void SetImage (int image, wxTreeItemIcon which) { m_images[which] = image; }
789 void SetImage (int column, int image, wxTreeItemIcon which)
1fded56b 790 {
33328cd8
RD
791 if (column == m_owner->GetMainColumn()) {
792 m_images[which] = image;
793 }else if (column < (int)m_col_images.GetCount()) {
794 m_col_images[column] = image;
795 }else if (column < m_owner->GetColumnCount()) {
1fded56b 796 int howmany = m_owner->GetColumnCount();
33328cd8
RD
797 for (int i = m_col_images.GetCount(); i < howmany; ++i) m_col_images.Add (NO_IMAGE);
798 m_col_images[column] = image;
1fded56b
RD
799 }
800 }
801
802 void SetData(wxTreeItemData *data) { m_data = data; }
803
33328cd8 804 void SetHasPlus(bool has = true) { m_hasPlus = has; }
1fded56b
RD
805
806 void SetBold(bool bold) { m_isBold = bold; }
807
808 int GetX() const { return m_x; }
809 int GetY() const { return m_y; }
810
33328cd8
RD
811 void SetX (int x) { m_x = x; }
812 void SetY (int y) { m_y = y; }
1fded56b
RD
813
814 int GetHeight() const { return m_height; }
815 int GetWidth() const { return m_width; }
816
33328cd8
RD
817 void SetHeight (int height) { m_height = height; }
818 void SetWidth (int width) { m_width = width; }
819
820 int GetTextX() const { return m_text_x; }
821 void SetTextX (int text_x) { m_text_x = text_x; }
1fded56b 822
28eab81f 823 wxTreeListItem *GetItemParent() const { return m_parent; }
1fded56b
RD
824
825 // operations
28eab81f
RD
826 // deletes all children notifying the treectrl about it if !NULL
827 // pointer given
1fded56b
RD
828 void DeleteChildren(wxTreeListMainWindow *tree = NULL);
829
830 // get count of all children (and grand children if 'recursively')
33328cd8 831 size_t GetChildrenCount(bool recursively = true) const;
1fded56b
RD
832
833 void Insert(wxTreeListItem *child, size_t index)
834 { m_children.Insert(child, index); }
835
836 void GetSize( int &x, int &y, const wxTreeListMainWindow* );
837
28eab81f 838 // return the item at given position (or NULL if no item), onButton is
33328cd8 839 // true if the point belongs to the item's button, otherwise it lies
28eab81f 840 // on the button's label
33328cd8 841 wxTreeListItem *HitTest (const wxPoint& point,
1fded56b 842 const wxTreeListMainWindow *,
33328cd8 843 int &flags, int& column, int level);
1fded56b 844
33328cd8
RD
845 void Expand() { m_isCollapsed = false; }
846 void Collapse() { m_isCollapsed = true; }
1fded56b 847
33328cd8 848 void SetHilight( bool set = true ) { m_hasHilight = set; }
1fded56b
RD
849
850 // status inquiries
851 bool HasChildren() const { return !m_children.IsEmpty(); }
852 bool IsSelected() const { return m_hasHilight != 0; }
853 bool IsExpanded() const { return !m_isCollapsed; }
854 bool HasPlus() const { return m_hasPlus || HasChildren(); }
855 bool IsBold() const { return m_isBold != 0; }
33328cd8 856 bool IsVirtual() const { return m_owner->IsVirtual(); }
1fded56b
RD
857
858 // attributes
28eab81f 859 // get them - may be NULL
1fded56b 860 wxTreeItemAttr *GetAttributes() const { return m_attr; }
28eab81f 861 // get them ensuring that the pointer is not NULL
1fded56b
RD
862 wxTreeItemAttr& Attr()
863 {
864 if ( !m_attr )
865 {
866 m_attr = new wxTreeItemAttr;
33328cd8 867 m_ownsAttr = true;
1fded56b
RD
868 }
869 return *m_attr;
870 }
28eab81f 871 // set them
1fded56b
RD
872 void SetAttributes(wxTreeItemAttr *attr)
873 {
874 if ( m_ownsAttr ) delete m_attr;
875 m_attr = attr;
33328cd8 876 m_ownsAttr = false;
1fded56b 877 }
28eab81f 878 // set them and delete when done
1fded56b
RD
879 void AssignAttributes(wxTreeItemAttr *attr)
880 {
881 SetAttributes(attr);
33328cd8 882 m_ownsAttr = true;
1fded56b
RD
883 }
884
885private:
886 wxTreeListMainWindow *m_owner; // control the item belongs to
887
888 // since there can be very many of these, we save size by chosing
889 // the smallest representation for the elements and by ordering
890 // the members to avoid padding.
891 wxArrayString m_text; // labels to be rendered for item
892
893 wxTreeItemData *m_data; // user-provided data
894
895 wxArrayTreeListItems m_children; // list of children
896 wxTreeListItem *m_parent; // parent of this item
897
898 wxTreeItemAttr *m_attr; // attributes???
899
900 // tree ctrl images for the normal, selected, expanded and
901 // expanded+selected states
902 short m_images[wxTreeItemIcon_Max];
903 wxArrayShort m_col_images; // images for the various columns (!= main)
904
33328cd8
RD
905 // main column item positions
906 wxCoord m_x; // (virtual) offset from left (vertical line)
907 wxCoord m_y; // (virtual) offset from top
908 wxCoord m_text_x; // item offset from left
1fded56b
RD
909 short m_width; // width of this item
910 unsigned char m_height; // height of this item
911
912 // use bitfields to save size
913 int m_isCollapsed :1;
914 int m_hasHilight :1; // same as focused
915 int m_hasPlus :1; // used for item which doesn't have
916 // children but has a [+] button
917 int m_isBold :1; // render the label in bold font
918 int m_ownsAttr :1; // delete attribute when done
919};
920
921// ===========================================================================
922// implementation
923// ===========================================================================
924
1fded56b
RD
925// ---------------------------------------------------------------------------
926// wxTreeListRenameTimer (internal)
927// ---------------------------------------------------------------------------
928
929wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner )
930{
931 m_owner = owner;
932}
933
934void wxTreeListRenameTimer::Notify()
935{
936 m_owner->OnRenameTimer();
937}
938
939//-----------------------------------------------------------------------------
33328cd8 940// wxEditTextCtrl (internal)
1fded56b
RD
941//-----------------------------------------------------------------------------
942
33328cd8
RD
943BEGIN_EVENT_TABLE (wxEditTextCtrl,wxTextCtrl)
944 EVT_CHAR (wxEditTextCtrl::OnChar)
945 EVT_KEY_UP (wxEditTextCtrl::OnKeyUp)
946 EVT_KILL_FOCUS (wxEditTextCtrl::OnKillFocus)
1fded56b
RD
947END_EVENT_TABLE()
948
33328cd8
RD
949wxEditTextCtrl::wxEditTextCtrl (wxWindow *parent,
950 const wxWindowID id,
951 bool *accept,
952 wxString *res,
953 wxTreeListMainWindow *owner,
954 const wxString &value,
955 const wxPoint &pos,
956 const wxSize &size,
957 int style,
958 const wxValidator& validator,
959 const wxString &name)
960 : wxTextCtrl (parent, id, value, pos, size, style|wxSIMPLE_BORDER, validator, name)
1fded56b
RD
961{
962 m_res = res;
963 m_accept = accept;
964 m_owner = owner;
33328cd8 965 (*m_accept) = false;
1fded56b
RD
966 (*m_res) = wxEmptyString;
967 m_startValue = value;
33328cd8 968 m_finished = false;
1fded56b
RD
969}
970
33328cd8 971void wxEditTextCtrl::OnChar( wxKeyEvent &event )
1fded56b 972{
33328cd8 973 if (event.GetKeyCode() == WXK_RETURN)
1fded56b 974 {
33328cd8 975 (*m_accept) = true;
1fded56b
RD
976 (*m_res) = GetValue();
977
978 if ((*m_res) != m_startValue)
979 m_owner->OnRenameAccept();
980
981 if (!wxPendingDelete.Member(this))
982 wxPendingDelete.Append(this);
983
33328cd8 984 m_finished = true;
1fded56b
RD
985 m_owner->SetFocus(); // This doesn't work. TODO.
986
987 return;
988 }
33328cd8 989 if (event.GetKeyCode() == WXK_ESCAPE)
1fded56b 990 {
33328cd8 991 (*m_accept) = false;
1fded56b
RD
992 (*m_res) = wxEmptyString;
993
994 if (!wxPendingDelete.Member(this))
995 wxPendingDelete.Append(this);
996
33328cd8 997 m_finished = true;
1fded56b
RD
998 m_owner->SetFocus(); // This doesn't work. TODO.
999
1000 return;
1001 }
1002 event.Skip();
1003}
1004
33328cd8 1005void wxEditTextCtrl::OnKeyUp( wxKeyEvent &event )
1fded56b
RD
1006{
1007 if (m_finished)
1008 {
1009 event.Skip();
1010 return;
1011 }
1012
1013 // auto-grow the textctrl:
1014 wxSize parentSize = m_owner->GetSize();
1015 wxPoint myPos = GetPosition();
1016 wxSize mySize = GetSize();
1017 int sx, sy;
1018 GetTextExtent(GetValue() + _T("M"), &sx, &sy);
1019 if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
1020 if (mySize.x > sx) sx = mySize.x;
1021 SetSize(sx, -1);
1022
1023 event.Skip();
1024}
1025
33328cd8 1026void wxEditTextCtrl::OnKillFocus( wxFocusEvent &event )
1fded56b
RD
1027{
1028 if (m_finished)
1029 {
1030 event.Skip();
1031 return;
1032 }
1033
1034 if (!wxPendingDelete.Member(this))
1035 wxPendingDelete.Append(this);
1036
33328cd8 1037 (*m_accept) = true;
1fded56b
RD
1038 (*m_res) = GetValue();
1039
1040 if ((*m_res) != m_startValue)
1041 m_owner->OnRenameAccept();
1042}
1043
1044//-----------------------------------------------------------------------------
1045// wxTreeListHeaderWindow
1046//-----------------------------------------------------------------------------
1047
33328cd8 1048IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxWindow);
1fded56b
RD
1049
1050BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)
33328cd8
RD
1051 EVT_PAINT (wxTreeListHeaderWindow::OnPaint)
1052 EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse)
1053 EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus)
1fded56b
RD
1054END_EVENT_TABLE()
1055
1056void wxTreeListHeaderWindow::Init()
1057{
1058 m_currentCursor = (wxCursor *) NULL;
33328cd8
RD
1059 m_isDragging = false;
1060 m_dirty = false;
1fded56b 1061 m_total_col_width = 0;
5c86a7fa 1062 m_hotTrackCol = -1;
1fded56b
RD
1063}
1064
1065wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1066{
1067 Init();
1068
1069 m_owner = (wxTreeListMainWindow *) NULL;
1070 m_resizeCursor = (wxCursor *) NULL;
1071}
1072
1073wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win,
1074 wxWindowID id,
1075 wxTreeListMainWindow *owner,
1076 const wxPoint& pos,
1077 const wxSize& size,
1078 long style,
1079 const wxString &name )
1080 : wxWindow( win, id, pos, size, style, name )
1081{
1082 Init();
1083
1084 m_owner = owner;
1085 m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE);
1086
33328cd8
RD
1087#if !wxCHECK_VERSION(2, 5, 0)
1088 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE));
1089#else
1090 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE));
1091#endif
1fded56b
RD
1092}
1093
1094wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1095{
1096 delete m_resizeCursor;
1097}
1098
1099void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
1100{
33328cd8
RD
1101#if !wxCHECK_VERSION(2, 5, 0)
1102 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1103#else
1104 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1105#endif
1fded56b 1106
1fded56b
RD
1107 const int m_corner = 1;
1108
1109 dc->SetBrush( *wxTRANSPARENT_BRUSH );
33328cd8
RD
1110#if defined( __WXMAC__ )
1111 dc->SetPen (pen);
1fded56b 1112#else // !GTK, !Mac
1fded56b 1113 dc->SetPen( *wxBLACK_PEN );
33328cd8 1114#endif
1fded56b
RD
1115 dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
1116 dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
1117
33328cd8 1118#if defined( __WXMAC__ )
47e59154 1119 pen = wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
33328cd8 1120#endif
1fded56b
RD
1121 dc->SetPen( pen );
1122 dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1123 dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
1124
1125 dc->SetPen( *wxWHITE_PEN );
1126 dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1127 dc->DrawRectangle( x, y, 1, h ); // left (outer)
1128 dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1129 dc->DrawLine( x+w-1, y, x+w-1, y+1 );
1fded56b
RD
1130}
1131
1132// shift the DC origin to match the position of the main window horz
1133// scrollbar: this allows us to always use logical coords
1134void wxTreeListHeaderWindow::AdjustDC(wxDC& dc)
1135{
1136 int xpix;
1137 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1fded56b
RD
1138 int x;
1139 m_owner->GetViewStart( &x, NULL );
1140
1141 // account for the horz scrollbar offset
1142 dc.SetDeviceOrigin( -x * xpix, 0 );
1143}
1144
1145void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1146{
1fded56b 1147#ifdef __WXGTK__
01fdd955 1148 wxClientDC dc( this );
1fded56b 1149#else
01fdd955 1150 wxPaintDC dc( this );
1fded56b
RD
1151#endif
1152
33328cd8 1153 PrepareDC( dc );
01fdd955 1154 AdjustDC( dc );
5c86a7fa
RD
1155
1156 int x = HEADER_OFFSET_X;
1fded56b
RD
1157
1158 // width and height of the entire header window
1159 int w, h;
1160 GetClientSize( &w, &h );
1161 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1fded56b
RD
1162 dc.SetBackgroundMode(wxTRANSPARENT);
1163
5c86a7fa
RD
1164#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1165 int numColumns = GetColumnCount();
1166 for ( int i = 0; i < numColumns && x < w; i++ )
1167 {
1168 if (!IsColumnShown (i)) continue; // do next column if not shown
1169
1170 wxHeaderButtonParams params;
1171
1172 // TODO: columnInfo should have label colours...
1173 params.m_labelColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
1174 params.m_labelFont = GetFont();
1175
1176 wxTreeListColumnInfo& column = GetColumn(i);
1177 int wCol = column.GetWidth();
1178 int flags = 0;
1179 wxRect rect(x, 0, wCol, h);
1180 x += wCol;
1181
1182 if ( i == m_hotTrackCol)
1183 flags |= wxCONTROL_CURRENT;
1184
1185 params.m_labelText = column.GetText();
1186 params.m_labelAlignment = column.GetAlignment();
1187
1188 int image = column.GetImage();
1189 wxImageList* imageList = m_owner->GetImageList();
1190 if ((image != -1) && imageList)
1191 params.m_labelBitmap = imageList->GetBitmap(image);
1192
80752b57
RD
1193 wxRendererNative::Get().DrawHeaderButton(this, dc, rect, flags,
1194 wxHDR_SORT_ICON_NONE, &params);
5c86a7fa
RD
1195 }
1196
1197 if (x < w) {
1198 wxRect rect(x, 0, w-x, h);
1199 wxRendererNative::Get().DrawHeaderButton(this, dc, rect);
1200 }
1201
1202#else // not 2.7.0.1+
1203
1204 dc.SetFont( GetFont() );
1205
1fded56b
RD
1206 // do *not* use the listctrl colour for headers - one day we will have a
1207 // function to set it separately
1208 //dc.SetTextForeground( *wxBLACK );
33328cd8
RD
1209#if !wxCHECK_VERSION(2, 5, 0)
1210 dc.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
1211#else
1212 dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ));
1213#endif
1fded56b 1214
1fded56b
RD
1215 int numColumns = GetColumnCount();
1216 for ( int i = 0; i < numColumns && x < w; i++ )
1217 {
5c86a7fa 1218 if (!IsColumnShown (i)) continue; // do next column if not shown
28eab81f 1219
1fded56b
RD
1220 wxTreeListColumnInfo& column = GetColumn(i);
1221 int wCol = column.GetWidth();
1222
1223 // the width of the rect to draw: make it smaller to fit entirely
1224 // inside the column rect
1225 int cw = wCol - 2;
1226
33328cd8 1227#if !wxCHECK_VERSION(2, 7, 0)
1fded56b 1228 dc.SetPen( *wxWHITE_PEN );
33328cd8
RD
1229 DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
1230#else
1231 wxRect rect(x, HEADER_OFFSET_Y, cw, h-2);
1232 wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
1233#endif
1fded56b
RD
1234
1235 // if we have an image, draw it on the right of the label
1236 int image = column.GetImage(); //item.m_image;
1237 int ix = -2, iy = 0;
1238 wxImageList* imageList = m_owner->GetImageList();
33328cd8
RD
1239 if ((image != -1) && imageList) {
1240 imageList->GetSize (image, ix, iy);
1fded56b
RD
1241 }
1242
33328cd8 1243 // extra margins around the text label
1fded56b
RD
1244 int text_width = 0;
1245 int text_x = x;
1246 int image_offset = cw - ix - 1;
1247
1248 switch(column.GetAlignment()) {
33328cd8 1249 case wxALIGN_LEFT:
1fded56b
RD
1250 text_x += EXTRA_WIDTH;
1251 cw -= ix + 2;
1252 break;
33328cd8
RD
1253 case wxALIGN_RIGHT:
1254 dc.GetTextExtent (column.GetText(), &text_width, NULL);
1255 text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
1fded56b
RD
1256 image_offset = 0;
1257 break;
33328cd8 1258 case wxALIGN_CENTER:
1fded56b
RD
1259 dc.GetTextExtent(column.GetText(), &text_width, NULL);
1260 text_x += (cw - text_width)/2 + ix + 2;
33328cd8 1261 image_offset = (cw - text_width - ix - 2)/2 - MARGIN;
1fded56b
RD
1262 break;
1263 }
1264
1265 // draw the image
33328cd8
RD
1266 if ((image != -1) && imageList) {
1267 imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/,
1268 HEADER_OFFSET_Y + (h - 4 - iy)/2,
1269 wxIMAGELIST_DRAW_TRANSPARENT);
1fded56b
RD
1270 }
1271
33328cd8 1272 // draw the text clipping it so that it doesn't overwrite the column boundary
1fded56b 1273 wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
33328cd8 1274 dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT );
1fded56b 1275
33328cd8 1276 // next column
1fded56b
RD
1277 x += wCol;
1278 }
1279
33328cd8
RD
1280 int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
1281 if (more_w > 0) {
1282#if !wxCHECK_VERSION(2, 7, 0)
1283 DoDrawRect (&dc, x, HEADER_OFFSET_Y, more_w, h-2 );
1284#else
1285 wxRect rect (x, HEADER_OFFSET_Y, more_w, h-2);
1286 wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
1287#endif
28eab81f 1288 }
5c86a7fa 1289#endif // 2.7.0.1
1fded56b
RD
1290}
1291
1292void wxTreeListHeaderWindow::DrawCurrent()
1293{
1294 int x1 = m_currentX;
1295 int y1 = 0;
33328cd8 1296 ClientToScreen (&x1, &y1);
1fded56b
RD
1297
1298 int x2 = m_currentX-1;
1299#ifdef __WXMSW__
33328cd8 1300 ++x2; // but why ????
1fded56b
RD
1301#endif
1302 int y2 = 0;
1303 m_owner->GetClientSize( NULL, &y2 );
1304 m_owner->ClientToScreen( &x2, &y2 );
1305
1306 wxScreenDC dc;
33328cd8
RD
1307 dc.SetLogicalFunction (wxINVERT);
1308 dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID));
1309 dc.SetBrush (*wxTRANSPARENT_BRUSH);
1fded56b
RD
1310
1311 AdjustDC(dc);
33328cd8
RD
1312 dc.DrawLine (x1, y1, x2, y2);
1313 dc.SetLogicalFunction (wxCOPY);
1314 dc.SetPen (wxNullPen);
1315 dc.SetBrush (wxNullBrush);
1fded56b
RD
1316}
1317
5c86a7fa
RD
1318#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1319int wxTreeListHeaderWindow::XToCol(int x)
1320{
1321 int colLeft = 0;
1322 int numColumns = GetColumnCount();
1323 for ( int col = 0; col < numColumns; col++ )
1324 {
1325 if (!IsColumnShown(col)) continue;
1326 wxTreeListColumnInfo& column = GetColumn(col);
1327
1328 if ( x < (colLeft + column.GetWidth()) )
1329 return col;
1330
1331 colLeft += column.GetWidth();
1332 }
1333 return -1;
1334}
1335
1336
1337void wxTreeListHeaderWindow::RefreshColLabel(int col)
1338{
1339 if ( col > GetColumnCount() )
1340 return;
1341
1342 int x = 0;
1343 int width = 0;
1344 int idx = 0;
1345 do {
1346 if (!IsColumnShown(idx)) continue;
1347 wxTreeListColumnInfo& column = GetColumn(idx);
1348 x += width;
1349 width = column.GetWidth();
1350 } while (++idx <= col);
1351
1352 m_owner->CalcScrolledPosition(x, 0, &x, NULL);
1353 RefreshRect(wxRect(x, 0, width, GetSize().GetHeight()));
1354}
1355#endif
1356
1357
33328cd8
RD
1358void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
1359
1fded56b
RD
1360 // we want to work with logical coords
1361 int x;
1362 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1363 int y = event.GetY();
1364
5c86a7fa
RD
1365#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1366 if ( event.Moving() )
1367 {
1368 int col = XToCol(x);
1369 if ( col != m_hotTrackCol )
1370 {
1371 // Refresh the col header so it will be painted with hot tracking
1372 // (if supported by the native renderer.)
1373 RefreshColLabel(col);
1374
1375 // Also refresh the old hot header
1376 if ( m_hotTrackCol >= 0 )
1377 RefreshColLabel(m_hotTrackCol);
1378
1379 m_hotTrackCol = col;
1380 }
1381 }
1382
1383 if ( event.Leaving() && m_hotTrackCol >= 0 )
1384 {
1385 // Leaving the window so clear any hot tracking indicator that may be present
1386 RefreshColLabel(m_hotTrackCol);
1387 m_hotTrackCol = -1;
1388 }
1389#endif
1390
33328cd8
RD
1391 if (m_isDragging) {
1392
1393 SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
1fded56b
RD
1394
1395 // we don't draw the line beyond our window, but we allow dragging it
1396 // there
1397 int w = 0;
1398 GetClientSize( &w, NULL );
1399 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1400 w -= 6;
1401
1402 // erase the line if it was drawn
33328cd8 1403 if (m_currentX < w) DrawCurrent();
1fded56b 1404
33328cd8
RD
1405 if (event.ButtonUp()) {
1406 m_isDragging = false;
1407 if (HasCapture()) ReleaseMouse();
1408 m_dirty = true;
1409 SetColumnWidth (m_column, m_currentX - m_minX);
1fded56b 1410 Refresh();
33328cd8
RD
1411 SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
1412 }else{
1413 m_currentX = wxMax (m_minX + 7, x);
1fded56b
RD
1414
1415 // draw in the new location
33328cd8 1416 if (m_currentX < w) DrawCurrent();
1fded56b 1417 }
33328cd8
RD
1418
1419 }else{ // not dragging
1420
1fded56b 1421 m_minX = 0;
33328cd8 1422 bool hit_border = false;
1fded56b
RD
1423
1424 // end of the current column
1425 int xpos = 0;
1426
33328cd8 1427 // find the column where this event occured
1fded56b 1428 int countCol = GetColumnCount();
33328cd8
RD
1429 for (int column = 0; column < countCol; column++) {
1430 if (!IsColumnShown (column)) continue; // do next if not shown
1fded56b 1431
33328cd8
RD
1432 xpos += GetColumnWidth (column);
1433 m_column = column;
1434 if ((abs (x-xpos) < 3) && (y < 22)) {
1fded56b 1435 // near the column border
33328cd8 1436 hit_border = true;
1fded56b
RD
1437 break;
1438 }
1439
33328cd8 1440 if (x < xpos) {
1fded56b
RD
1441 // inside the column
1442 break;
1443 }
1444
1445 m_minX = xpos;
1446 }
1447
33328cd8
RD
1448 if (event.LeftDown() || event.RightUp()) {
1449 if (hit_border && event.LeftDown()) {
1450 m_isDragging = true;
1451 CaptureMouse();
1fded56b
RD
1452 m_currentX = x;
1453 DrawCurrent();
33328cd8
RD
1454 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
1455 }else{ // click on a column
1456 wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
1457 wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
1458 SendListEvent (evt, event.GetPosition());
1fded56b 1459 }
33328cd8
RD
1460 }else if (event.LeftDClick() && hit_border) {
1461 SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
1462 Refresh();
1463
1464 }else if (event.Moving()) {
1fded56b 1465 bool setCursor;
33328cd8 1466 if (hit_border) {
1fded56b
RD
1467 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1468 m_currentCursor = m_resizeCursor;
33328cd8 1469 }else{
1fded56b
RD
1470 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1471 m_currentCursor = wxSTANDARD_CURSOR;
1472 }
33328cd8 1473 if (setCursor) SetCursor (*m_currentCursor);
1fded56b 1474 }
33328cd8 1475
1fded56b
RD
1476 }
1477}
1478
33328cd8 1479void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
1fded56b
RD
1480 m_owner->SetFocus();
1481}
1482
33328cd8 1483void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
1fded56b 1484 wxWindow *parent = GetParent();
33328cd8
RD
1485 wxListEvent le (type, parent->GetId());
1486 le.SetEventObject (parent);
1fded56b
RD
1487 le.m_pointDrag = pos;
1488
1489 // the position should be relative to the parent window, not
1490 // this one for compatibility with MSW and common sense: the
1491 // user code doesn't know anything at all about this header
1492 // window, so why should it get positions relative to it?
1493 le.m_pointDrag.y -= GetSize().y;
1fded56b 1494 le.m_col = m_column;
33328cd8 1495 parent->GetEventHandler()->ProcessEvent (le);
1fded56b
RD
1496}
1497
33328cd8
RD
1498void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
1499 m_columns.Add (colInfo);
1500 m_total_col_width += colInfo.GetWidth();
1fded56b 1501 m_owner->AdjustMyScrollbars();
33328cd8 1502 m_owner->m_dirty = true;
1fded56b
RD
1503}
1504
33328cd8
RD
1505void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
1506 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1507 m_total_col_width -= m_columns[column].GetWidth();
1508 m_columns[column].SetWidth(width);
1509 m_total_col_width += width;
1510 m_owner->AdjustMyScrollbars();
1511 m_owner->m_dirty = true;
1fded56b
RD
1512}
1513
33328cd8
RD
1514void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
1515 wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
1516 m_columns.Insert (colInfo, before);
1517 m_total_col_width += colInfo.GetWidth();
1fded56b 1518 m_owner->AdjustMyScrollbars();
33328cd8 1519 m_owner->m_dirty = true;
1fded56b
RD
1520}
1521
33328cd8
RD
1522void wxTreeListHeaderWindow::RemoveColumn (int column) {
1523 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1fded56b 1524 m_total_col_width -= m_columns[column].GetWidth();
33328cd8 1525 m_columns.RemoveAt (column);
1fded56b 1526 m_owner->AdjustMyScrollbars();
33328cd8 1527 m_owner->m_dirty = true;
1fded56b
RD
1528}
1529
33328cd8
RD
1530void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
1531 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1532 int w = m_columns[column].GetWidth();
1fded56b 1533 m_columns[column] = info;
33328cd8 1534 if (w != info.GetWidth()) {
1fded56b
RD
1535 m_total_col_width += info.GetWidth() - w;
1536 m_owner->AdjustMyScrollbars();
1fded56b 1537 }
33328cd8 1538 m_owner->m_dirty = true;
1fded56b
RD
1539}
1540
1541// ---------------------------------------------------------------------------
1542// wxTreeListItem
1543// ---------------------------------------------------------------------------
1544
33328cd8
RD
1545wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
1546 wxTreeListItem *parent,
1547 const wxArrayString& text,
1548 int image, int selImage,
1549 wxTreeItemData *data)
1550 : m_text (text) {
1551
1fded56b
RD
1552 m_images[wxTreeItemIcon_Normal] = image;
1553 m_images[wxTreeItemIcon_Selected] = selImage;
1554 m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
1555 m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
1556
1557 m_data = data;
33328cd8
RD
1558 m_x = 0;
1559 m_y = 0;
1560 m_text_x = 0;
1fded56b 1561
33328cd8
RD
1562 m_isCollapsed = true;
1563 m_hasHilight = false;
1564 m_hasPlus = false;
1565 m_isBold = false;
1fded56b
RD
1566
1567 m_owner = owner;
1fded56b
RD
1568 m_parent = parent;
1569
1570 m_attr = (wxTreeItemAttr *)NULL;
33328cd8 1571 m_ownsAttr = false;
1fded56b
RD
1572
1573 // We don't know the height here yet.
1574 m_width = 0;
1575 m_height = 0;
1576}
1577
33328cd8 1578wxTreeListItem::~wxTreeListItem() {
1fded56b 1579 delete m_data;
1fded56b
RD
1580 if (m_ownsAttr) delete m_attr;
1581
33328cd8 1582 wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1fded56b
RD
1583}
1584
33328cd8 1585void wxTreeListItem::DeleteChildren (wxTreeListMainWindow *tree) {
1fded56b 1586 size_t count = m_children.Count();
33328cd8 1587 for (size_t n = 0; n < count; n++) {
1fded56b 1588 wxTreeListItem *child = m_children[n];
33328cd8
RD
1589 if (tree) {
1590 tree->SendDeleteEvent (child);
1591 if (tree->m_selectItem == child) tree->m_selectItem = (wxTreeListItem*)NULL;
1592 }
1593 child->DeleteChildren (tree);
1fded56b
RD
1594 delete child;
1595 }
1fded56b
RD
1596 m_children.Empty();
1597}
1598
33328cd8
RD
1599void wxTreeListItem::SetText (const wxString &text) {
1600 if (m_text.GetCount() > 0) {
1601 m_text[0] = text;
1602 }else{
1603 m_text.Add (text);
1fded56b
RD
1604 }
1605}
1606
33328cd8 1607size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
1fded56b 1608 size_t count = m_children.Count();
33328cd8 1609 if (!recursively) return count;
1fded56b
RD
1610
1611 size_t total = count;
33328cd8 1612 for (size_t n = 0; n < count; ++n) {
1fded56b
RD
1613 total += m_children[n]->GetChildrenCount();
1614 }
1fded56b
RD
1615 return total;
1616}
1617
33328cd8
RD
1618void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
1619 int bottomY = m_y + theButton->GetLineHeight (this);
1620 if (y < bottomY) y = bottomY;
1fded56b
RD
1621 int width = m_x + m_width;
1622 if ( x < width ) x = width;
1623
33328cd8 1624 if (IsExpanded()) {
1fded56b 1625 size_t count = m_children.Count();
33328cd8
RD
1626 for (size_t n = 0; n < count; ++n ) {
1627 m_children[n]->GetSize (x, y, theButton);
1fded56b
RD
1628 }
1629 }
1630}
1631
33328cd8
RD
1632wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
1633 const wxTreeListMainWindow *theCtrl,
1634 int &flags, int& column, int level) {
1635
1fded56b 1636 // for a hidden root node, don't evaluate it, but do evaluate children
33328cd8
RD
1637 if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
1638
1639 // reset any previous hit infos
1640 flags = 0;
1641 column = -1;
1642 wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
1643
1644 // check for right of all columns (outside)
1645 if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
1646
1647 // evaluate if y-pos is okay
1648 int h = theCtrl->GetLineHeight (this);
1649 if ((point.y >= m_y) && (point.y <= m_y + h)) {
1650
1651 int maincol = theCtrl->GetMainColumn();
1652
28eab81f 1653 // check for above/below middle
1fded56b 1654 int y_mid = m_y + h/2;
33328cd8 1655 if (point.y < y_mid) {
1fded56b 1656 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
33328cd8 1657 }else{
1fded56b 1658 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
33328cd8 1659 }
1fded56b 1660
28eab81f 1661 // check for button hit
33328cd8
RD
1662 if (HasPlus() && theCtrl->HasButtons()) {
1663 int bntX = m_x - theCtrl->m_btnWidth2;
1664 int bntY = y_mid - theCtrl->m_btnHeight2;
1665 if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
1666 (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
1667 flags |= wxTREE_HITTEST_ONITEMBUTTON;
1668 column = maincol;
1669 return this;
1670 }
1fded56b
RD
1671 }
1672
28eab81f 1673 // check for image hit
33328cd8
RD
1674 if (theCtrl->m_imgWidth > 0) {
1675 int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
28eab81f
RD
1676 int imgY = y_mid - theCtrl->m_imgHeight2;
1677 if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
1678 (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
1fded56b 1679 flags |= wxTREE_HITTEST_ONITEMICON;
33328cd8 1680 column = maincol;
28eab81f
RD
1681 return this;
1682 }
1683 }
1fded56b 1684
28eab81f 1685 // check for label hit
33328cd8 1686 if ((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) {
28eab81f 1687 flags |= wxTREE_HITTEST_ONITEMLABEL;
33328cd8 1688 column = maincol;
1fded56b
RD
1689 return this;
1690 }
1691
33328cd8 1692 // check for indent hit after button and image hit
28eab81f 1693 if (point.x < m_x) {
1fded56b 1694 flags |= wxTREE_HITTEST_ONITEMINDENT;
33328cd8 1695 column = -1; // considered not belonging to main column
28eab81f
RD
1696 return this;
1697 }
1698
33328cd8
RD
1699 // check for right of label
1700 int end = 0;
1701 for (int i = 0; i <= maincol; ++i) end += header_win->GetColumnWidth (i);
1702 if ((point.x > (m_text_x + m_width)) && (point.x <= end)) {
1fded56b 1703 flags |= wxTREE_HITTEST_ONITEMRIGHT;
33328cd8 1704 column = -1; // considered not belonging to main column
28eab81f
RD
1705 return this;
1706 }
1fded56b 1707
33328cd8
RD
1708 // else check for each column except main
1709 int x = 0;
1710 for (int j = 0; j < theCtrl->GetColumnCount(); ++j) {
1711 if (!header_win->IsColumnShown(j)) continue;
1712 int w = header_win->GetColumnWidth (j);
1713 if ((j != maincol) && (point.x >= x && point.x < x+w)) {
1714 flags |= wxTREE_HITTEST_ONITEMCOLUMN;
1715 column = j;
1716 return this;
1717 }
1718 x += w;
1719 }
1720
1721 // no special flag or column found
1722 return this;
1723
1fded56b
RD
1724 }
1725
33328cd8
RD
1726 // if children not expanded, return no item
1727 if (!IsExpanded()) return (wxTreeListItem*) NULL;
1fded56b
RD
1728 }
1729
33328cd8
RD
1730 // in any case evaluate children
1731 wxTreeListItem *child;
1fded56b 1732 size_t count = m_children.Count();
33328cd8
RD
1733 for (size_t n = 0; n < count; n++) {
1734 child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
1735 if (child) return child;
1fded56b
RD
1736 }
1737
33328cd8 1738 // not found
1fded56b
RD
1739 return (wxTreeListItem*) NULL;
1740}
1741
33328cd8 1742int wxTreeListItem::GetCurrentImage() const {
1fded56b 1743 int image = NO_IMAGE;
33328cd8
RD
1744 if (IsExpanded()) {
1745 if (IsSelected()) {
1746 image = GetImage (wxTreeItemIcon_SelectedExpanded);
1747 }else{
1748 image = GetImage (wxTreeItemIcon_Expanded);
1fded56b 1749 }
33328cd8
RD
1750 }else{ // not expanded
1751 if (IsSelected()) {
1752 image = GetImage (wxTreeItemIcon_Selected);
1753 }else{
1754 image = GetImage (wxTreeItemIcon_Normal);
1fded56b
RD
1755 }
1756 }
1fded56b 1757
33328cd8
RD
1758 // maybe it doesn't have the specific image, try the default one instead
1759 if (image == NO_IMAGE) image = GetImage();
1fded56b
RD
1760
1761 return image;
1762}
1763
1764// ---------------------------------------------------------------------------
1765// wxTreeListMainWindow implementation
1766// ---------------------------------------------------------------------------
1767
1768IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
1769
1770BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
1771 EVT_PAINT (wxTreeListMainWindow::OnPaint)
1772 EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse)
1773 EVT_CHAR (wxTreeListMainWindow::OnChar)
1774 EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus)
1775 EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus)
1776 EVT_IDLE (wxTreeListMainWindow::OnIdle)
1fded56b
RD
1777 EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll)
1778END_EVENT_TABLE()
1779
1780
1781// ---------------------------------------------------------------------------
1782// construction/destruction
1783// ---------------------------------------------------------------------------
1784
33328cd8
RD
1785void wxTreeListMainWindow::Init() {
1786
1787 m_rootItem = (wxTreeListItem*)NULL;
1788 m_curItem = (wxTreeListItem*)NULL;
1789 m_shiftItem = (wxTreeListItem*)NULL;
1790 m_editItem = (wxTreeListItem*)NULL;
1791 m_selectItem = (wxTreeListItem*)NULL;
1792
1793 m_curColumn = -1; // no current column
1794
1795 m_hasFocus = false;
1796 m_dirty = false;
1fded56b 1797
28eab81f
RD
1798 m_lineHeight = LINEHEIGHT;
1799 m_indent = MININDENT; // min. indent
1fded56b
RD
1800 m_linespacing = 4;
1801
33328cd8
RD
1802#if !wxCHECK_VERSION(2, 5, 0)
1803 m_hilightBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1804 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1805#else
1806 m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1807 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1808#endif
1809
1810 m_imageListNormal = (wxImageList *) NULL;
1811 m_imageListButtons = (wxImageList *) NULL;
1fded56b
RD
1812 m_imageListState = (wxImageList *) NULL;
1813 m_ownsImageListNormal = m_ownsImageListButtons =
33328cd8
RD
1814 m_ownsImageListState = false;
1815
1816 m_imgWidth = 0, m_imgWidth2 = 0;
1817 m_imgHeight = 0, m_imgHeight2 = 0;
1818 m_btnWidth = 0, m_btnWidth2 = 0;
1819 m_btnHeight = 0, m_btnHeight2 = 0;
1fded56b
RD
1820
1821 m_dragCount = 0;
33328cd8
RD
1822 m_isDragging = false;
1823 m_dragTimer = new wxTimer (this, -1);
1824 m_dragItem = (wxTreeListItem*)NULL;
1fded56b 1825
33328cd8
RD
1826 m_renameTimer = new wxTreeListRenameTimer (this);
1827 m_lastOnSame = false;
1828 m_left_down_selection = false;
1fded56b 1829
28eab81f
RD
1830 m_findTimer = new wxTimer (this, -1);
1831
33328cd8
RD
1832#if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1833 m_normalFont.MacCreateThemeFont (kThemeViewsFont);
8e3ca43b 1834#else
33328cd8 1835 m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
8e3ca43b 1836#endif
1fded56b
RD
1837 m_boldFont = wxFont( m_normalFont.GetPointSize(),
1838 m_normalFont.GetFamily(),
1839 m_normalFont.GetStyle(),
1840 wxBOLD,
8e3ca43b
RD
1841 m_normalFont.GetUnderlined(),
1842 m_normalFont.GetFaceName(),
1843 m_normalFont.GetEncoding());
1fded56b
RD
1844}
1845
33328cd8
RD
1846bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
1847 wxWindowID id,
1848 const wxPoint& pos,
1849 const wxSize& size,
1850 long style,
1851 const wxValidator &validator,
1852 const wxString& name) {
1fded56b 1853
1fded56b 1854#ifdef __WXMAC__
33328cd8
RD
1855 style &= ~wxTR_LINES_AT_ROOT;
1856 style |= wxTR_NO_LINES;
1857
1858 int major,minor;
1859 wxGetOsVersion( &major, &minor );
1860 if (major < 10) style |= wxTR_ROW_LINES;
1fded56b 1861#endif
33328cd8
RD
1862
1863 wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1fded56b 1864
1fded56b 1865#if wxUSE_VALIDATORS
33328cd8
RD
1866 SetValidator(validator);
1867#endif
1868
1869#if !wxCHECK_VERSION(2, 5, 0)
1870 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX));
1871#else
1872 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
1fded56b
RD
1873#endif
1874
28eab81f
RD
1875#ifdef __WXMSW__
1876 {
1877 int i, j;
1878 wxBitmap bmp(8, 8);
1879 wxMemoryDC bdc;
1880 bdc.SelectObject(bmp);
1881 bdc.SetPen(*wxGREY_PEN);
1882 bdc.DrawRectangle(-1, -1, 10, 10);
1883 for (i = 0; i < 8; i++) {
1884 for (j = 0; j < 8; j++) {
1885 if (!((i + j) & 1)) {
1886 bdc.DrawPoint(i, j);
1887 }
1888 }
1889 }
1890
1891 m_dottedPen = wxPen(bmp, 1);
1892 }
1893#else
33328cd8
RD
1894//? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1895 m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
28eab81f 1896#endif
1fded56b 1897
1fded56b
RD
1898 m_owner = parent;
1899 m_main_column = 0;
1900
33328cd8 1901 return true;
1fded56b
RD
1902}
1903
33328cd8 1904wxTreeListMainWindow::~wxTreeListMainWindow() {
1fded56b
RD
1905 delete m_hilightBrush;
1906 delete m_hilightUnfocusedBrush;
1907
33328cd8 1908 delete m_dragTimer;
1fded56b 1909 delete m_renameTimer;
28eab81f 1910 delete m_findTimer;
1fded56b
RD
1911 if (m_ownsImageListNormal) delete m_imageListNormal;
1912 if (m_ownsImageListState) delete m_imageListState;
1913 if (m_ownsImageListButtons) delete m_imageListButtons;
1fded56b 1914
33328cd8
RD
1915 DeleteRoot();
1916}
1fded56b
RD
1917
1918
1919//-----------------------------------------------------------------------------
1920// accessors
1921//-----------------------------------------------------------------------------
1922
33328cd8
RD
1923size_t wxTreeListMainWindow::GetCount() const {
1924 return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
1fded56b
RD
1925}
1926
33328cd8
RD
1927void wxTreeListMainWindow::SetIndent (unsigned int indent) {
1928 m_indent = wxMax ((unsigned)MININDENT, indent);
1929 m_dirty = true;
1fded56b
RD
1930}
1931
33328cd8 1932void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
1fded56b 1933 m_linespacing = spacing;
33328cd8 1934 m_dirty = true;
1fded56b
RD
1935 CalculateLineHeight();
1936}
1937
33328cd8
RD
1938size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
1939 bool recursively) {
1940 wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
1941 return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
1fded56b
RD
1942}
1943
33328cd8 1944void wxTreeListMainWindow::SetWindowStyle (const long styles) {
28eab81f
RD
1945 // right now, just sets the styles. Eventually, we may
1946 // want to update the inherited styles, but right now
1947 // none of the parents has updatable styles
1fded56b 1948 m_windowStyle = styles;
33328cd8 1949 m_dirty = true;
1fded56b
RD
1950}
1951
1952//-----------------------------------------------------------------------------
1953// functions to work with tree items
1954//-----------------------------------------------------------------------------
1955
33328cd8
RD
1956int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column,
1957 wxTreeItemIcon which) const {
1958 wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
1959 return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
1fded56b
RD
1960}
1961
33328cd8
RD
1962wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
1963 wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
1fded56b
RD
1964 return ((wxTreeListItem*) item.m_pItem)->GetData();
1965}
1966
33328cd8
RD
1967bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
1968 wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
1969 return ((wxTreeListItem *)item.m_pItem)->IsBold();
1970}
1971
33328cd8
RD
1972wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
1973 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1fded56b
RD
1974 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1975 return pItem->Attr().GetTextColour();
1976}
1977
33328cd8
RD
1978wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
1979 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1fded56b
RD
1980 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1981 return pItem->Attr().GetBackgroundColour();
1982}
1983
33328cd8
RD
1984wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
1985 wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
1fded56b
RD
1986 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1987 return pItem->Attr().GetFont();
1988}
1989
33328cd8
RD
1990void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column,
1991 int image, wxTreeItemIcon which) {
1992 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 1993 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
1994 pItem->SetImage (column, image, which);
1995 wxClientDC dc (this);
1996 CalculateSize (pItem, dc);
1997 RefreshLine (pItem);
1fded56b
RD
1998}
1999
33328cd8
RD
2000void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,
2001 wxTreeItemData *data) {
2002 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b
RD
2003 ((wxTreeListItem*) item.m_pItem)->SetData(data);
2004}
2005
33328cd8
RD
2006void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item,
2007 bool has) {
2008 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2009 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2010 pItem->SetHasPlus (has);
2011 RefreshLine (pItem);
1fded56b
RD
2012}
2013
33328cd8
RD
2014void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, bool bold) {
2015 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2016 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2017 if (pItem->IsBold() != bold) { // avoid redrawing if no real change
2018 pItem->SetBold (bold);
2019 RefreshLine (pItem);
1fded56b
RD
2020 }
2021}
2022
33328cd8
RD
2023void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,
2024 const wxColour& colour) {
2025 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2026 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2027 pItem->Attr().SetTextColour (colour);
2028 RefreshLine (pItem);
1fded56b
RD
2029}
2030
33328cd8
RD
2031void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,
2032 const wxColour& colour) {
2033 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2034 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2035 pItem->Attr().SetBackgroundColour (colour);
2036 RefreshLine (pItem);
1fded56b
RD
2037}
2038
33328cd8
RD
2039void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,
2040 const wxFont& font) {
2041 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2042 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2043 pItem->Attr().SetFont (font);
2044 RefreshLine (pItem);
1fded56b
RD
2045}
2046
33328cd8
RD
2047bool wxTreeListMainWindow::SetFont (const wxFont &font) {
2048 wxScrolledWindow::SetFont (font);
2049 m_normalFont = font;
2050 m_boldFont = wxFont (m_normalFont.GetPointSize(),
2051 m_normalFont.GetFamily(),
2052 m_normalFont.GetStyle(),
2053 wxBOLD,
2054 m_normalFont.GetUnderlined(),
2055 m_normalFont.GetFaceName());
2056 CalculateLineHeight();
2057 return true;
1fded56b
RD
2058}
2059
2060
2061// ----------------------------------------------------------------------------
2062// item status inquiries
2063// ----------------------------------------------------------------------------
2064
33328cd8
RD
2065bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow) const {
2066 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2067
2068 // An item is only visible if it's not a descendant of a collapsed item
2069 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
28eab81f 2070 wxTreeListItem* parent = pItem->GetItemParent();
33328cd8
RD
2071 while (parent) {
2072 if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
2073 if (!parent->IsExpanded()) return false;
28eab81f 2074 parent = parent->GetItemParent();
1fded56b
RD
2075 }
2076
1fded56b 2077 wxSize clientSize = GetClientSize();
1fded56b 2078 wxRect rect;
33328cd8
RD
2079 if ((!GetBoundingRect (item, rect)) ||
2080 ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
2081 (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) ||
2082 (!fullRow && (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x))) return false;
1fded56b 2083
33328cd8 2084 return true;
1fded56b
RD
2085}
2086
33328cd8
RD
2087bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
2088 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2089
2090 // consider that the item does have children if it has the "+" button: it
2091 // might not have them (if it had never been expanded yet) but then it
2092 // could have them as well and it's better to err on this side rather than
2093 // disabling some operations which are restricted to the items with
2094 // children for an item which does have them
2095 return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2096}
2097
33328cd8
RD
2098bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2099 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2100 return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2101}
2102
33328cd8
RD
2103bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2104 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2105 return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2106}
2107
33328cd8
RD
2108bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item) const {
2109 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2110 return ((wxTreeListItem*) item.m_pItem)->IsBold();
2111}
2112
2113// ----------------------------------------------------------------------------
2114// navigation
2115// ----------------------------------------------------------------------------
2116
33328cd8
RD
2117wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2118 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
28eab81f 2119 return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
1fded56b
RD
2120}
2121
28eab81f 2122#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
2123wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2124 long& cookie) const {
28eab81f 2125#else
33328cd8
RD
2126wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2127 wxTreeItemIdValue& cookie) const {
28eab81f 2128#endif
33328cd8
RD
2129 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2130 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
1fded56b 2131 cookie = 0;
33328cd8 2132 return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
1fded56b
RD
2133}
2134
28eab81f 2135#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
2136wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2137 long& cookie) const {
28eab81f 2138#else
33328cd8
RD
2139wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2140 wxTreeItemIdValue& cookie) const {
28eab81f 2141#endif
33328cd8 2142 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
28eab81f 2143 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
33328cd8
RD
2144 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2145 long *pIndex = ((long*)&cookie);
2146 return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
28eab81f
RD
2147}
2148
2149#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
2150wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2151 long& cookie) const {
28eab81f 2152#else
33328cd8
RD
2153wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2154 wxTreeItemIdValue& cookie) const {
28eab81f 2155#endif
33328cd8 2156 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
28eab81f 2157 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
33328cd8
RD
2158 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2159 long *pIndex = (long*)&cookie;
2160 return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
1fded56b
RD
2161}
2162
33328cd8
RD
2163#if !wxCHECK_VERSION(2, 5, 0)
2164wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2165 long& cookie) const {
2166#else
2167wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2168 wxTreeItemIdValue& cookie) const {
2169#endif
2170 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
1fded56b 2171 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
33328cd8
RD
2172 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2173 long *pIndex = ((long*)&cookie);
2174 (*pIndex) = children.Count();
2175 return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
1fded56b
RD
2176}
2177
33328cd8
RD
2178wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2179 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
1fded56b 2180
33328cd8 2181 // get parent
1fded56b 2182 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
28eab81f 2183 wxTreeListItem *parent = i->GetItemParent();
33328cd8 2184 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
1fded56b 2185
33328cd8 2186 // get index
1fded56b 2187 wxArrayTreeListItems& siblings = parent->GetChildren();
33328cd8
RD
2188 size_t index = siblings.Index (i);
2189 wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2190 return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
1fded56b
RD
2191}
2192
33328cd8
RD
2193wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2194 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
1fded56b 2195
33328cd8 2196 // get parent
1fded56b 2197 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
28eab81f 2198 wxTreeListItem *parent = i->GetItemParent();
33328cd8 2199 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
1fded56b 2200
33328cd8 2201 // get index
1fded56b 2202 wxArrayTreeListItems& siblings = parent->GetChildren();
33328cd8
RD
2203 size_t index = siblings.Index(i);
2204 wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2205 return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
1fded56b
RD
2206}
2207
2208// Only for internal use right now, but should probably be public
33328cd8
RD
2209wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2210 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
1fded56b 2211
33328cd8
RD
2212 // if there are any children, return first child
2213 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2214 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2215 if (children.GetCount() > 0) return children.Item (0);
1fded56b 2216 }
33328cd8
RD
2217
2218 // get sibling of this item or of the ancestors instead
2219 wxTreeItemId next;
2220 wxTreeItemId parent = item;
2221 do {
2222 next = GetNextSibling (parent);
2223 parent = GetItemParent (parent);
2224 } while (!next.IsOk() && parent.IsOk());
2225 return next;
2226}
2227
2228// Only for internal use right now, but should probably be public
2229wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2230 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2231
2232 // if there are any children, return last child
2233 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2234 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2235 if (children.GetCount() > 0) return children.Item (children.GetCount()-1);
1fded56b 2236 }
33328cd8
RD
2237
2238 // get sibling of this item or of the ancestors instead
2239 wxTreeItemId next;
2240 wxTreeItemId parent = item;
2241 do {
2242 next = GetPrevSibling (parent);
2243 parent = GetItemParent (parent);
2244 } while (!next.IsOk() && parent.IsOk());
2245 return next;
1fded56b
RD
2246}
2247
33328cd8
RD
2248wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2249 return GetNextExpanded (GetRootItem());
2250}
1fded56b 2251
33328cd8
RD
2252wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2253 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2254 return GetNext (item, false);
2255}
1fded56b 2256
33328cd8
RD
2257wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2258 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2259 return GetPrev (item, false);
1fded56b
RD
2260}
2261
33328cd8
RD
2262wxTreeItemId wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow) const {
2263 return GetNextVisible (GetRootItem(), fullRow);
2264}
1fded56b 2265
33328cd8
RD
2266wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow) const {
2267 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2268 wxTreeItemId id = GetNext (item, false);
2269 while (id.IsOk()) {
2270 if (IsVisible (id, fullRow)) return id;
2271 id = GetNext (id, false);
1fded56b
RD
2272 }
2273 return wxTreeItemId();
2274}
2275
33328cd8
RD
2276wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow) const {
2277 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2278 wxTreeItemId id = GetPrev (item, true);
2279 while (id.IsOk()) {
2280 if (IsVisible (id, fullRow)) return id;
2281 id = GetPrev(id, true);
2282 }
1fded56b
RD
2283 return wxTreeItemId();
2284}
2285
2286// ----------------------------------------------------------------------------
2287// operations
2288// ----------------------------------------------------------------------------
2289
33328cd8
RD
2290wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2291 size_t previous,
2292 const wxString& text,
2293 int image, int selImage,
2294 wxTreeItemData *data) {
2295 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2296 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2297 m_dirty = true; // do this first so stuff below doesn't cause flicker
1fded56b 2298
1fded56b 2299 wxArrayString arr;
33328cd8
RD
2300 arr.Alloc (GetColumnCount());
2301 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
1fded56b 2302 arr[m_main_column] = text;
33328cd8
RD
2303 wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2304 if (data != NULL) {
2305#if !wxCHECK_VERSION(2, 5, 0)
2306 data->SetId ((long)item);
2307#else
2308 data->SetId (item);
2309#endif
1fded56b 2310 }
33328cd8 2311 parent->Insert (item, previous);
1fded56b
RD
2312
2313 return item;
2314}
2315
33328cd8
RD
2316wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2317 int image, int selImage,
2318 wxTreeItemData *data) {
2319 wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2320 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2321 m_dirty = true; // do this first so stuff below doesn't cause flicker
1fded56b 2322
1fded56b 2323 wxArrayString arr;
33328cd8
RD
2324 arr.Alloc (GetColumnCount());
2325 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
1fded56b 2326 arr[m_main_column] = text;
33328cd8
RD
2327 m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2328 if (data != NULL) {
2329#if !wxCHECK_VERSION(2, 5, 0)
2330 data->SetId((long)m_rootItem);
2331#else
2332 data->SetId(m_rootItem);
28eab81f 2333#endif
1fded56b 2334 }
33328cd8
RD
2335 if (HasFlag(wxTR_HIDE_ROOT)) {
2336 // if we will hide the root, make sure children are visible
2337 m_rootItem->SetHasPlus();
2338 m_rootItem->Expand();
2339#if !wxCHECK_VERSION(2, 5, 0)
2340 long cookie = 0;
2341#else
2342 wxTreeItemIdValue cookie = 0;
2343#endif
2344 m_curItem = (wxTreeListItem*)GetFirstChild (m_rootItem, cookie).m_pItem;
1fded56b 2345 }
33328cd8 2346 return m_rootItem;
1fded56b
RD
2347}
2348
33328cd8
RD
2349wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2350 const wxString& text,
2351 int image, int selImage,
2352 wxTreeItemData *data) {
2353 return DoInsertItem (parent, 0u, text, image, selImage, data);
1fded56b
RD
2354}
2355
33328cd8
RD
2356wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2357 const wxTreeItemId& idPrevious,
2358 const wxString& text,
2359 int image, int selImage,
2360 wxTreeItemData *data) {
2361 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2362 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
1fded56b
RD
2363
2364 int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2365 wxASSERT_MSG( index != wxNOT_FOUND,
33328cd8 2366 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
1fded56b 2367
33328cd8 2368 return DoInsertItem (parentId, ++index, text, image, selImage, data);
1fded56b
RD
2369}
2370
33328cd8
RD
2371wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2372 size_t before,
2373 const wxString& text,
2374 int image, int selImage,
2375 wxTreeItemData *data) {
2376 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2377 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
1fded56b 2378
33328cd8 2379 return DoInsertItem (parentId, before, text, image, selImage, data);
1fded56b
RD
2380}
2381
33328cd8
RD
2382wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2383 const wxString& text,
2384 int image, int selImage,
2385 wxTreeItemData *data) {
1fded56b 2386 wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
33328cd8 2387 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
1fded56b 2388
33328cd8 2389 return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
1fded56b
RD
2390}
2391
33328cd8
RD
2392void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem *item) {
2393 // send event to user code
2394 wxTreeEvent event (wxEVT_COMMAND_TREE_DELETE_ITEM, m_owner->GetId());
2395#if !wxCHECK_VERSION(2, 5, 0)
2396 event.SetItem ((long)item);
2397#else
2398 event.SetItem (item);
2399#endif
2400 event.SetEventObject (m_owner);
2401 m_owner->ProcessEvent (event);
28eab81f
RD
2402}
2403
33328cd8 2404void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
1fded56b 2405 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
33328cd8
RD
2406 wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2407 m_dirty = true; // do this first so stuff below doesn't cause flicker
2408
2409 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2410 bool changeKeyCurrent = false;
2411 wxTreeListItem *itemKey = m_shiftItem;
2412 while (itemKey) {
2413 if (itemKey == item) { // m_shiftItem is a descendant of the item being deleted
2414 changeKeyCurrent = true;
1fded56b
RD
2415 break;
2416 }
28eab81f 2417 itemKey = itemKey->GetItemParent();
1fded56b
RD
2418 }
2419
28eab81f 2420 wxTreeListItem *parent = item->GetItemParent();
33328cd8
RD
2421 if (parent) {
2422 parent->GetChildren().Remove (item); // remove by value
28eab81f 2423 }
33328cd8 2424 if (changeKeyCurrent) m_shiftItem = parent;
1fded56b 2425
33328cd8
RD
2426 SendDeleteEvent (item);
2427 if (m_selectItem == item) m_selectItem = (wxTreeListItem*)NULL;
2428 item->DeleteChildren (this);
1fded56b
RD
2429 delete item;
2430}
2431
33328cd8
RD
2432void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2433 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2434 m_dirty = true; // do this first so stuff below doesn't cause flicker
1fded56b 2435
33328cd8
RD
2436 item->DeleteChildren (this);
2437}
1fded56b 2438
33328cd8
RD
2439void wxTreeListMainWindow::DeleteRoot() {
2440 if (m_rootItem) {
2441 m_dirty = true;
2442 SendDeleteEvent (m_rootItem);
2443 m_curItem = (wxTreeListItem*)NULL;
2444 m_selectItem= (wxTreeListItem*)NULL;
2445 m_rootItem->DeleteChildren (this);
2446 delete m_rootItem;
2447 m_rootItem = NULL;
1fded56b
RD
2448 }
2449}
2450
33328cd8 2451void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
1fded56b 2452 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
33328cd8 2453 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
1fded56b 2454
33328cd8 2455 if (!item->HasPlus() || item->IsExpanded()) return;
1fded56b 2456
33328cd8
RD
2457 // send event to user code
2458 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_EXPANDING, m_owner->GetId());
2459#if !wxCHECK_VERSION(2, 5, 0)
2460 event.SetItem ((long)item);
2461#else
2462 event.SetItem (item);
2463#endif
2464 event.SetEventObject (m_owner);
2465 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // expand canceled
1fded56b
RD
2466
2467 item->Expand();
33328cd8 2468 m_dirty = true;
1fded56b 2469
33328cd8
RD
2470 // send event to user code
2471 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2472 m_owner->ProcessEvent (event);
1fded56b
RD
2473}
2474
33328cd8
RD
2475void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2476 Expand (itemId);
2477 if (!IsExpanded (itemId)) return;
28eab81f 2478#if !wxCHECK_VERSION(2, 5, 0)
33328cd8 2479 long cookie;
28eab81f 2480#else
33328cd8 2481 wxTreeItemIdValue cookie;
28eab81f 2482#endif
33328cd8
RD
2483 wxTreeItemId child = GetFirstChild (itemId, cookie);
2484 while (child.IsOk()) {
2485 ExpandAll (child);
2486 child = GetNextChild (itemId, cookie);
1fded56b
RD
2487 }
2488}
2489
33328cd8 2490void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
1fded56b 2491 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
33328cd8 2492 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
1fded56b 2493
33328cd8 2494 if (!item->HasPlus() || !item->IsExpanded()) return;
1fded56b 2495
33328cd8
RD
2496 // send event to user code
2497 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, m_owner->GetId() );
2498#if !wxCHECK_VERSION(2, 5, 0)
2499 event.SetItem ((long)item);
2500#else
2501 event.SetItem (item);
1fded56b 2502#endif
33328cd8
RD
2503 event.SetEventObject (m_owner);
2504 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // collapse canceled
1fded56b 2505
33328cd8
RD
2506 item->Collapse();
2507 m_dirty = true;
1fded56b 2508
33328cd8
RD
2509 // send event to user code
2510 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2511 ProcessEvent (event);
1fded56b
RD
2512}
2513
33328cd8
RD
2514void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2515 Collapse (item);
2516 DeleteChildren (item);
1fded56b
RD
2517}
2518
33328cd8
RD
2519void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2520 if (IsExpanded (itemId)) {
2521 Collapse (itemId);
2522 }else{
2523 Expand (itemId);
2524 }
1fded56b
RD
2525}
2526
33328cd8
RD
2527void wxTreeListMainWindow::Unselect() {
2528 if (m_selectItem) {
2529 m_selectItem->SetHilight (false);
2530 RefreshLine (m_selectItem);
2531 m_selectItem = (wxTreeListItem*)NULL;
1fded56b
RD
2532 }
2533}
2534
33328cd8
RD
2535void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2536 if (item->IsSelected()) {
2537 item->SetHilight (false);
2538 RefreshLine (item);
2539 if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
1fded56b 2540 }
33328cd8 2541 if (item->HasChildren()) {
1fded56b
RD
2542 wxArrayTreeListItems& children = item->GetChildren();
2543 size_t count = children.Count();
33328cd8
RD
2544 for (size_t n = 0; n < count; ++n) {
2545 UnselectAllChildren (children[n]);
1fded56b
RD
2546 }
2547 }
2548}
2549
33328cd8
RD
2550void wxTreeListMainWindow::UnselectAll() {
2551 UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
1fded56b
RD
2552}
2553
2554// Recursive function !
2555// To stop we must have crt_item<last_item
2556// Algorithm :
2557// Tag all next children, when no more children,
2558// Move to parent (not to tag)
2559// Keep going... if we found last_item, we stop.
33328cd8
RD
2560bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem *crt_item,
2561 wxTreeListItem *last_item) {
28eab81f 2562 wxTreeListItem *parent = crt_item->GetItemParent();
1fded56b 2563
33328cd8
RD
2564 if (!parent) {// This is root item
2565 return TagAllChildrenUntilLast (crt_item, last_item);
2566 }
1fded56b
RD
2567
2568 wxArrayTreeListItems& children = parent->GetChildren();
2569 int index = children.Index(crt_item);
33328cd8 2570 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
1fded56b 2571
33328cd8
RD
2572 if ((parent->HasChildren() && parent->IsExpanded()) ||
2573 ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2574 size_t count = children.Count();
2575 for (size_t n = (index+1); n < count; ++n) {
2576 if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2577 }
1fded56b
RD
2578 }
2579
33328cd8 2580 return TagNextChildren (parent, last_item);
1fded56b
RD
2581}
2582
33328cd8
RD
2583bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item,
2584 wxTreeListItem *last_item) {
2585 crt_item->SetHilight (true);
1fded56b
RD
2586 RefreshLine(crt_item);
2587
33328cd8 2588 if (crt_item==last_item) return true;
1fded56b 2589
33328cd8 2590 if (crt_item->HasChildren() && crt_item->IsExpanded()) {
1fded56b
RD
2591 wxArrayTreeListItems& children = crt_item->GetChildren();
2592 size_t count = children.Count();
33328cd8
RD
2593 for (size_t n = 0; n < count; ++n) {
2594 if (TagAllChildrenUntilLast (children[n], last_item)) return true;
1fded56b
RD
2595 }
2596 }
2597
33328cd8 2598 return false;
1fded56b
RD
2599}
2600
33328cd8
RD
2601void wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2602 const wxTreeItemId& lastId,
2603 bool unselect_others) {
2604 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item") );
1fded56b 2605
33328cd8
RD
2606 bool is_single = !HasFlag(wxTR_MULTIPLE);
2607 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
1fded56b 2608
33328cd8
RD
2609 // single selection requires unselect others
2610 if (is_single) unselect_others = true;
1fded56b 2611
33328cd8 2612 // send event to the user code
1fded56b 2613 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
33328cd8
RD
2614#if !wxCHECK_VERSION(2, 5, 0)
2615 event.SetItem ((long)item);
2616 event.SetOldItem ((long)m_curItem);
2617#else
2618 event.SetItem (item);
2619 event.SetOldItem (m_curItem);
2620#endif
2621 event.SetEventObject (m_owner);
2622 if (m_owner->GetEventHandler()->ProcessEvent (event) && !event.IsAllowed()) return;
2623
2624 // unselect all if unselect other items
2625 bool unselected = false; // see that UnselectAll is done only once
2626 if (unselect_others) {
2627 if (is_single) {
2628 Unselect(); // to speed up thing
2629 }else{
2630 UnselectAll();
2631 unselected = true;
2632 }
1fded56b
RD
2633 }
2634
33328cd8
RD
2635 // select item or item range
2636 if (lastId.IsOk() && (itemId != lastId)) {
1fded56b 2637
33328cd8
RD
2638 if (!unselected) UnselectAll();
2639 wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
1fded56b 2640
33328cd8
RD
2641 // ensure that the position of the item it calculated in any case
2642 if (m_dirty) CalculatePositions();
2643
2644 // select item range according Y-position
2645 if (last->GetY() < item->GetY()) {
2646 if (!TagAllChildrenUntilLast (last, item)) {
2647 TagNextChildren (last, item);
2648 }
2649 }else{
2650 if (!TagAllChildrenUntilLast (item, last)) {
2651 TagNextChildren (item, last);
2652 }
1fded56b
RD
2653 }
2654
33328cd8 2655 }else{
1fded56b 2656
33328cd8
RD
2657 // select item according its old selection
2658 item->SetHilight (!item->IsSelected());
2659 RefreshLine (item);
2660 if (unselect_others) {
2661 m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL;
2662 }
1fded56b 2663
1fded56b
RD
2664 }
2665
33328cd8 2666 // send event to user code
1fded56b 2667 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
33328cd8 2668 m_owner->GetEventHandler()->ProcessEvent (event);
1fded56b
RD
2669}
2670
33328cd8 2671void wxTreeListMainWindow::SelectAll() {
48ac3cf8 2672 wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style, must have wxTR_MULTIPLE style to select all items"));
28eab81f 2673
33328cd8
RD
2674 // send event to user code
2675 wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId());
2676 event.SetItem (GetRootItem());
2677#if !wxCHECK_VERSION(2, 5, 0)
2678 event.SetOldItem ((long)m_curItem);
2679#else
2680 event.SetOldItem (m_curItem);
2681#endif
2682 event.SetEventObject (m_owner);
2683 if (m_owner->GetEventHandler()->ProcessEvent (event) && !event.IsAllowed()) return;
28eab81f 2684
28eab81f
RD
2685#if !wxCHECK_VERSION(2, 5, 0)
2686 long cookie = 0;
2687#else
2688 wxTreeItemIdValue cookie = 0;
2689#endif
2690 wxTreeItemId root = GetRootItem();
2691 wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
33328cd8 2692 wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
48ac3cf8 2693 if (!first || !last) return;
33328cd8
RD
2694 if (!TagAllChildrenUntilLast (first, last)) {
2695 TagNextChildren (first, last);
2696 }
28eab81f 2697
33328cd8
RD
2698 // send event to user code
2699 event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED);
2700 m_owner->GetEventHandler()->ProcessEvent (event);
28eab81f
RD
2701}
2702
33328cd8
RD
2703void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
2704 wxArrayTreeItemIds &array) const {
2705 if (item->IsSelected()) array.Add (wxTreeItemId(item));
1fded56b 2706
33328cd8 2707 if (item->HasChildren()) {
1fded56b
RD
2708 wxArrayTreeListItems& children = item->GetChildren();
2709 size_t count = children.GetCount();
33328cd8 2710 for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
1fded56b
RD
2711 }
2712}
2713
33328cd8 2714size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
1fded56b
RD
2715 array.Empty();
2716 wxTreeItemId idRoot = GetRootItem();
33328cd8 2717 if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
1fded56b
RD
2718 return array.Count();
2719}
2720
33328cd8
RD
2721void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
2722 if (!item.IsOk()) return; // do nothing if no item
1fded56b
RD
2723
2724 // first expand all parent branches
33328cd8 2725 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
28eab81f 2726 wxTreeListItem *parent = gitem->GetItemParent();
33328cd8
RD
2727 while (parent) {
2728 Expand (parent);
28eab81f 2729 parent = parent->GetItemParent();
1fded56b
RD
2730 }
2731
33328cd8
RD
2732 ScrollTo (item);
2733 RefreshLine (gitem);
1fded56b
RD
2734}
2735
33328cd8
RD
2736void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
2737 if (!item.IsOk()) return; // do nothing if no item
1fded56b 2738
33328cd8
RD
2739 // ensure that the position of the item it calculated in any case
2740 if (m_dirty) CalculatePositions();
1fded56b
RD
2741
2742 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2743
2744 // now scroll to the item
2745 int item_y = gitem->GetY();
2746
33328cd8
RD
2747 int xUnit, yUnit;
2748 GetScrollPixelsPerUnit (&xUnit, &yUnit);
1fded56b
RD
2749 int start_x = 0;
2750 int start_y = 0;
33328cd8
RD
2751 GetViewStart (&start_x, &start_y);
2752 start_y *= yUnit;
1fded56b
RD
2753
2754 int client_h = 0;
2755 int client_w = 0;
33328cd8 2756 GetClientSize (&client_w, &client_h);
1fded56b 2757
33328cd8
RD
2758 int x = 0;
2759 int y = 0;
2760 m_rootItem->GetSize (x, y, this);
2761 x = m_owner->GetHeaderWindow()->GetWidth();
2762 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2763 int x_pos = GetScrollPos( wxHORIZONTAL );
2764
2765 if (item_y < start_y+3) {
2766 // going down, item should appear at top
2767 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
2768 }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
2769 // going up, item should appear at bottom
2770 item_y += yUnit + 2;
2771 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
1fded56b
RD
2772 }
2773}
2774
2775// FIXME: tree sorting functions are not reentrant and not MT-safe!
2776static wxTreeListMainWindow *s_treeBeingSorted = NULL;
2777
2778static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1,
2779 wxTreeListItem **item2)
2780{
33328cd8 2781 wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
1fded56b
RD
2782
2783 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
2784}
2785
2786int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1,
2787 const wxTreeItemId& item2)
2788{
33328cd8 2789 return m_owner->OnCompareItems (item1, item2);
1fded56b
RD
2790}
2791
33328cd8
RD
2792void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId) {
2793 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
1fded56b
RD
2794
2795 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2796
33328cd8
RD
2797 wxCHECK_RET (!s_treeBeingSorted,
2798 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
1fded56b
RD
2799
2800 wxArrayTreeListItems& children = item->GetChildren();
33328cd8
RD
2801 if ( children.Count() > 1 ) {
2802 m_dirty = true;
1fded56b
RD
2803 s_treeBeingSorted = this;
2804 children.Sort(tree_ctrl_compare_func);
2805 s_treeBeingSorted = NULL;
2806 }
1fded56b
RD
2807}
2808
33328cd8
RD
2809wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, const wxString& str, int mode) {
2810 wxString itemText;
2811 // determine start item
2812 wxTreeItemId next = item;
2813 if (next.IsOk()) {
2814 if (mode & wxTL_MODE_NAV_LEVEL) {
2815 next = GetNextSibling (next);
2816 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2817 next = GetNextVisible (next, false);
2818 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2819 next = GetNextExpanded (next);
2820 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2821 next = GetNext (next, true);
2822 }
2823 }
2824
28eab81f
RD
2825#if !wxCHECK_VERSION(2, 5, 0)
2826 long cookie = 0;
2827#else
2828 wxTreeItemIdValue cookie = 0;
2829#endif
28eab81f 2830 if (!next.IsOk()) {
33328cd8 2831 next = (wxTreeListItem*)GetRootItem().m_pItem;
28eab81f
RD
2832 if (HasFlag(wxTR_HIDE_ROOT)) {
2833 next = (wxTreeListItem*)GetFirstChild (GetRootItem().m_pItem, cookie).m_pItem;
28eab81f
RD
2834 }
2835 }
33328cd8 2836 if (!next.IsOk()) return (wxTreeItemId*)NULL;
28eab81f
RD
2837
2838 // start checking the next items
33328cd8
RD
2839 while (next.IsOk() && (next != item)) {
2840 if (mode & wxTL_MODE_FIND_PARTIAL) {
28eab81f
RD
2841 itemText = GetItemText (next).Mid (0, str.Length());
2842 }else{
2843 itemText = GetItemText (next);
2844 }
33328cd8 2845 if (mode & wxTL_MODE_FIND_NOCASE) {
28eab81f
RD
2846 if (itemText.CmpNoCase (str) == 0) return next;
2847 }else{
2848 if (itemText.Cmp (str) == 0) return next;
2849 }
33328cd8
RD
2850 if (mode & wxTL_MODE_NAV_LEVEL) {
2851 next = GetNextSibling (next);
2852 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2853 next = GetNextVisible (next, false);
2854 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2855 next = GetNextExpanded (next);
2856 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2857 next = GetNext (next, true);
2858 }
2859 if (!next.IsOk() && item.IsOk()) {
2860 next = (wxTreeListItem*)GetRootItem().m_pItem;
2861 if (HasFlag(wxTR_HIDE_ROOT)) {
2862 next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem;
2863 }
2864 }
28eab81f 2865 }
33328cd8 2866 return (wxTreeItemId*)NULL;
1fded56b
RD
2867}
2868
33328cd8
RD
2869void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
2870 wxTreeListItem *prevItem = m_dragItem;
2871 m_dragItem = (wxTreeListItem*) item.m_pItem;
2872 if (prevItem) RefreshLine (prevItem);
2873 if (m_dragItem) RefreshLine (m_dragItem);
1fded56b
RD
2874}
2875
33328cd8
RD
2876void wxTreeListMainWindow::CalculateLineHeight() {
2877 wxClientDC dc (this);
2878 dc.SetFont (m_normalFont);
28eab81f 2879 m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
1fded56b 2880
33328cd8 2881 if (m_imageListNormal) {
1fded56b
RD
2882 // Calculate a m_lineHeight value from the normal Image sizes.
2883 // May be toggle off. Then wxTreeListMainWindow will spread when
2884 // necessary (which might look ugly).
2885 int n = m_imageListNormal->GetImageCount();
33328cd8 2886 for (int i = 0; i < n ; i++) {
1fded56b
RD
2887 int width = 0, height = 0;
2888 m_imageListNormal->GetSize(i, width, height);
28eab81f 2889 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
1fded56b
RD
2890 }
2891 }
2892
33328cd8 2893 if (m_imageListButtons) {
1fded56b
RD
2894 // Calculate a m_lineHeight value from the Button image sizes.
2895 // May be toggle off. Then wxTreeListMainWindow will spread when
2896 // necessary (which might look ugly).
2897 int n = m_imageListButtons->GetImageCount();
33328cd8 2898 for (int i = 0; i < n ; i++) {
1fded56b
RD
2899 int width = 0, height = 0;
2900 m_imageListButtons->GetSize(i, width, height);
28eab81f 2901 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
1fded56b
RD
2902 }
2903 }
2904
33328cd8
RD
2905 if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
2906 m_lineHeight += 2; // minimal 2 pixel space
2907 }else{
2908 m_lineHeight += m_lineHeight / 10; // otherwise 10% space
2909 }
1fded56b
RD
2910}
2911
33328cd8 2912void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
1fded56b
RD
2913 if (m_ownsImageListNormal) delete m_imageListNormal;
2914 m_imageListNormal = imageList;
33328cd8
RD
2915 m_ownsImageListNormal = false;
2916 m_dirty = true;
1fded56b
RD
2917 CalculateLineHeight();
2918}
2919
33328cd8 2920void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
1fded56b
RD
2921 if (m_ownsImageListState) delete m_imageListState;
2922 m_imageListState = imageList;
33328cd8 2923 m_ownsImageListState = false;
1fded56b
RD
2924}
2925
33328cd8 2926void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
1fded56b
RD
2927 if (m_ownsImageListButtons) delete m_imageListButtons;
2928 m_imageListButtons = imageList;
33328cd8
RD
2929 m_ownsImageListButtons = false;
2930 m_dirty = true;
1fded56b
RD
2931 CalculateLineHeight();
2932}
2933
33328cd8 2934void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
1fded56b 2935 SetImageList(imageList);
33328cd8 2936 m_ownsImageListNormal = true;
1fded56b
RD
2937}
2938
33328cd8 2939void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
1fded56b 2940 SetStateImageList(imageList);
33328cd8 2941 m_ownsImageListState = true;
1fded56b
RD
2942}
2943
33328cd8 2944void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
1fded56b 2945 SetButtonsImageList(imageList);
33328cd8 2946 m_ownsImageListButtons = true;
1fded56b
RD
2947}
2948
2949// ----------------------------------------------------------------------------
2950// helpers
2951// ----------------------------------------------------------------------------
2952
33328cd8
RD
2953void wxTreeListMainWindow::AdjustMyScrollbars() {
2954 if (m_rootItem) {
2955 int xUnit, yUnit;
2956 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2957 if (xUnit == 0) xUnit = GetCharWidth();
2958 if (yUnit == 0) yUnit = m_lineHeight;
1fded56b 2959 int x = 0, y = 0;
33328cd8
RD
2960 m_rootItem->GetSize (x, y, this);
2961 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2962 int x_pos = GetScrollPos (wxHORIZONTAL);
2963 int y_pos = GetScrollPos (wxVERTICAL);
1fded56b 2964 x = m_owner->GetHeaderWindow()->GetWidth() + 2;
33328cd8
RD
2965 if (x < GetClientSize().GetWidth()) x_pos = 0;
2966 SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
2967 }else{
2968 SetScrollbars (0, 0, 0, 0);
1fded56b
RD
2969 }
2970}
2971
33328cd8
RD
2972int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
2973 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
1fded56b 2974 return item->GetHeight();
33328cd8 2975 }else{
1fded56b 2976 return m_lineHeight;
33328cd8 2977 }
1fded56b
RD
2978}
2979
33328cd8
RD
2980void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
2981
1fded56b 2982 wxTreeItemAttr *attr = item->GetAttributes();
33328cd8
RD
2983
2984 dc.SetFont (GetItemFont (item));
2985
28eab81f
RD
2986 wxColour colText;
2987 if (attr && attr->HasTextColour()) {
2988 colText = attr->GetTextColour();
2989 }else{
2990 colText = GetForegroundColour();
2991 }
33328cd8
RD
2992#if !wxCHECK_VERSION(2, 5, 0)
2993 wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2994#else
2995 wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2996#endif
28eab81f 2997
33328cd8
RD
2998 int total_w = m_owner->GetHeaderWindow()->GetWidth();
2999 int total_h = GetLineHeight(item);
3000 int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
3001 int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
3002 wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
1fded56b 3003
33328cd8 3004 int text_w = 0, text_h = 0;
1fded56b
RD
3005 dc.GetTextExtent( item->GetText(GetMainColumn()), &text_w, &text_h );
3006
33328cd8
RD
3007 // determine background and show it
3008 wxColour colBg;
3009 if (attr && attr->HasBackgroundColour()) {
3010 colBg = attr->GetBackgroundColour();
3011 }else{
3012 colBg = m_backgroundColour;
3013 }
3014 dc.SetBrush (wxBrush (colBg, wxSOLID));
3015 dc.SetPen (*wxTRANSPARENT_PEN);
3016 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3017 if (item == m_dragItem) {
3018 dc.SetBrush (*m_hilightBrush);
3019#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3020 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3021#endif // !__WXMAC__
3022 dc.SetTextForeground (colTextHilight);
3023 }else if (item->IsSelected()) {
dbace455
KO
3024#if defined(__WXGTK2__) || defined(__WXMAC__)
3025 int flags = wxCONTROL_SELECTED;
3026 if (m_hasFocus)
3027 {
3028 flags |= wxCONTROL_FOCUSED;
3029#ifdef __WXMAC__
3030 dc.SetTextForeground( *wxWHITE );
3031#endif
3032 }
3033 wxRendererNative::GetDefault().DrawItemSelectionRect( m_owner, dc, wxRect( 0, item->GetY() + off_h, total_w, total_h - off_h ), flags);
3034#else
33328cd8
RD
3035 if (!m_isDragging && m_hasFocus) {
3036 dc.SetBrush (*m_hilightBrush);
33328cd8 3037 dc.SetPen (*wxBLACK_PEN);
33328cd8
RD
3038 }else{
3039 dc.SetBrush (*m_hilightUnfocusedBrush);
33328cd8 3040 dc.SetPen (*wxTRANSPARENT_PEN);
33328cd8
RD
3041 }
3042 dc.SetTextForeground (colTextHilight);
dbace455 3043#endif // defined(__WXGTK2__) || defined(__WXMAC__)
33328cd8
RD
3044 }else if (item == m_curItem) {
3045 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3046 }else{
3047 dc.SetTextForeground (colText);
28eab81f 3048 }
dbace455 3049#if !defined(__WXGTK2__) && !defined(__WXMAC__)
33328cd8 3050 dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
dbace455 3051#endif
33328cd8
RD
3052 }else{
3053 dc.SetTextForeground (colText);
1fded56b
RD
3054 }
3055
28eab81f
RD
3056 int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3057 int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3058 int x_colstart = 0;
33328cd8
RD
3059 for (int i = 0; i < GetColumnCount(); ++i ) {
3060 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3061
3062 int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3063 wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3064
3065 int x = 0;
3066 int image = NO_IMAGE;
28eab81f 3067 int image_w = 0;
33328cd8
RD
3068 if(i == GetMainColumn()) {
3069 x = item->GetX() + MARGIN;
3070 if (HasButtons()) {
3071 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
28eab81f 3072 }else{
33328cd8 3073 x -= m_indent/2;
28eab81f 3074 }
33328cd8
RD
3075 if (m_imageListNormal) image = item->GetCurrentImage();
3076 }else{
3077 x = x_colstart + MARGIN;
1fded56b
RD
3078 image = item->GetImage(i);
3079 }
28eab81f 3080 if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
1fded56b
RD
3081
3082 // honor text alignment
3083 wxString text = item->GetText(i);
33328cd8 3084 int w = 0;
28eab81f 3085 switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
33328cd8
RD
3086 case wxALIGN_LEFT:
3087 // nothing to do, already left aligned
1fded56b 3088 break;
33328cd8
RD
3089 case wxALIGN_RIGHT:
3090 dc.GetTextExtent (text, &text_w, NULL);
3091 w = col_w - (image_w + text_w + off_w + MARGIN);
3092 x += (w > 0)? w: 0;
1fded56b 3093 break;
33328cd8 3094 case wxALIGN_CENTER:
1fded56b 3095 dc.GetTextExtent(text, &text_w, NULL);
33328cd8
RD
3096 w = (col_w - (image_w + text_w + off_w + MARGIN))/2;
3097 x += (w > 0)? w: 0;
28eab81f
RD
3098 break;
3099 }
33328cd8
RD
3100 int text_x = x + image_w;
3101 if (i == GetMainColumn()) item->SetTextX (text_x);
3102
3103 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3104 if (i == GetMainColumn()) {
3105 if (item == m_dragItem) {
3106 dc.SetBrush (*m_hilightBrush);
3107#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3108 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3109#endif // !__WXMAC__
3110 dc.SetTextForeground (colTextHilight);
3111 }else if (item->IsSelected()) {
dbace455
KO
3112#if defined(__WXGTK2__) || defined(__WXMAC__)
3113 int flags = wxCONTROL_SELECTED;
3114 if (m_hasFocus)
3115 {
3116 flags |= wxCONTROL_FOCUSED;
3117#ifdef __WXMAC__
3118 dc.SetTextForeground( *wxWHITE );
3119#endif
3120 }
3121 wxRendererNative::GetDefault().DrawItemSelectionRect( m_owner, dc, wxRect( 0, item->GetY() + off_h, total_w, total_h - off_h ), flags);
3122#else
33328cd8
RD
3123 if (!m_isDragging && m_hasFocus) {
3124 dc.SetBrush (*m_hilightBrush);
33328cd8 3125 dc.SetPen (*wxBLACK_PEN);
33328cd8
RD
3126 }else{
3127 dc.SetBrush (*m_hilightUnfocusedBrush);
dbace455 3128 dc.SetPen (*wxTRANSPARENT_PEN);
33328cd8
RD
3129 }
3130 dc.SetTextForeground (colTextHilight);
dbace455 3131#endif // defined(__WXGTK2__) || defined(__WXMAC__)
33328cd8
RD
3132 }else if (item == m_curItem) {
3133 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3134 }else{
3135 dc.SetTextForeground (colText);
3136 }
dbace455 3137#if !defined(__WXGTK2__) && !defined(__WXMAC__)
33328cd8 3138 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
dbace455 3139#endif
33328cd8
RD
3140 }else{
3141 dc.SetTextForeground (colText);
3142 }
3143 }
28eab81f 3144
33328cd8
RD
3145 if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns
3146#if !wxCHECK_VERSION(2, 5, 0)
3147 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3148#else
3149 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3150#endif
3151 dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3152 dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h);
1fded56b
RD
3153 }
3154
33328cd8
RD
3155 dc.SetBackgroundMode (wxTRANSPARENT);
3156
3157 if (image != NO_IMAGE) {
3158 int y = item->GetY() + img_extraH;
3159 m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
1fded56b 3160 }
28eab81f 3161 int text_y = item->GetY() + text_extraH;
33328cd8 3162 dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
1fded56b 3163
33328cd8 3164 x_colstart += col_w;
1fded56b
RD
3165 }
3166
3167 // restore normal font
3168 dc.SetFont( m_normalFont );
3169}
3170
3171// Now y stands for the top of the item, whereas it used to stand for middle !
28eab81f 3172void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
33328cd8
RD
3173 int level, int &y, int x_maincol) {
3174
28eab81f
RD
3175 // Handle hide root (only level 0)
3176 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
1fded56b 3177 wxArrayTreeListItems& children = item->GetChildren();
33328cd8
RD
3178 for (size_t n = 0; n < children.Count(); n++) {
3179 PaintLevel (children[n], dc, 1, y, x_maincol);
1fded56b 3180 }
28eab81f 3181 // end after expanding root
1fded56b
RD
3182 return;
3183 }
3184
28eab81f 3185 // calculate position of vertical lines
33328cd8
RD
3186 int x = x_maincol + MARGIN; // start of column
3187 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
28eab81f 3188 if (HasButtons()) {
33328cd8 3189 x += (m_btnWidth-m_btnWidth2); // half button space
28eab81f 3190 }else{
33328cd8 3191 x += (m_indent-m_indent/2);
28eab81f 3192 }
33328cd8
RD
3193 if (HasFlag(wxTR_HIDE_ROOT)) {
3194 x += m_indent * (level-1); // indent but not level 1
28eab81f 3195 }else{
33328cd8 3196 x += m_indent * level; // indent according to level
28eab81f
RD
3197 }
3198
33328cd8 3199 // set position of vertical line
28eab81f
RD
3200 item->SetX (x);
3201 item->SetY (y);
1fded56b 3202
33328cd8 3203 int h = GetLineHeight (item);
1fded56b 3204 int y_top = y;
28eab81f 3205 int y_mid = y_top + (h/2);
1fded56b
RD
3206 y += h;
3207
3208 int exposed_x = dc.LogicalToDeviceX(0);
3209 int exposed_y = dc.LogicalToDeviceY(y_top);
3210
33328cd8 3211 if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
f84fa75a 3212
33328cd8 3213 if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
28eab81f 3214 //dc.DestroyClippingRegion();
1fded56b
RD
3215 int total_width = m_owner->GetHeaderWindow()->GetWidth();
3216 // if the background colour is white, choose a
3217 // contrasting color for the lines
33328cd8
RD
3218#if !wxCHECK_VERSION(2, 5, 0)
3219 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3220#else
3221 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3222#endif
3223 dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3224 dc.DrawLine (0, y_top, total_width, y_top);
3225 dc.DrawLine (0, y_top+h, total_width, y_top+h);
1fded56b
RD
3226 }
3227
33328cd8
RD
3228 // draw item
3229 PaintItem (item, dc);
3230
1fded56b
RD
3231 // restore DC objects
3232 dc.SetBrush(*wxWHITE_BRUSH);
3233 dc.SetPen(m_dottedPen);
1fded56b 3234
33328cd8
RD
3235 // clip to the column width
3236 int clip_width = m_owner->GetHeaderWindow()->
28eab81f 3237 GetColumn(m_main_column).GetWidth();
33328cd8 3238 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
28eab81f 3239
33328cd8
RD
3240 if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3241
3242 // draw the horizontal line here
3243 dc.SetPen(m_dottedPen);
3244 int x2 = x - m_indent;
3245 if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3246 int x3 = x + (m_btnWidth-m_btnWidth2);
3247 if (HasButtons()) {
3248 if (item->HasPlus()) {
3249 dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3250 dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3251 }else{
3252 dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3253 }
3254 }else{
3255 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
f84fa75a 3256 }
33328cd8
RD
3257 }
3258
3259 if (item->HasPlus() && HasButtons()) { // should the item show a button?
3260
3261 if (m_imageListButtons) {
3262
1fded56b 3263 // draw the image button here
28eab81f 3264 int image = wxTreeItemIcon_Normal;
1fded56b 3265 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
33328cd8
RD
3266 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3267 int xx = x - m_btnWidth2 + MARGIN;
28eab81f
RD
3268 int yy = y_mid - m_btnHeight2;
3269 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
33328cd8 3270 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
1fded56b 3271 dc.DestroyClippingRegion();
28eab81f 3272
33328cd8
RD
3273 }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3274
3275 // draw the twisty button here
3276 dc.SetPen(*wxBLACK_PEN);
3277 dc.SetBrush(*m_hilightBrush);
3278 wxPoint button[3];
3279 if (item->IsExpanded()) {
3280 button[0].x = x - (m_btnWidth2+1);
3281 button[0].y = y_mid - (m_btnHeight/3);
3282 button[1].x = x + (m_btnWidth2+1);
3283 button[1].y = button[0].y;
3284 button[2].x = x;
3285 button[2].y = button[0].y + (m_btnHeight2+1);
28eab81f 3286 }else{
33328cd8
RD
3287 button[0].x = x - (m_btnWidth/3);
3288 button[0].y = y_mid - (m_btnHeight2+1);
3289 button[1].x = button[0].x;
3290 button[1].y = y_mid + (m_btnHeight2+1);
3291 button[2].x = button[0].x + (m_btnWidth2+1);
3292 button[2].y = y_mid;
3293 }
3294 dc.DrawPolygon(3, button);
3295
3296 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3297
3298 // draw the plus sign here
3299#if !wxCHECK_VERSION(2, 7, 0)
3300 dc.SetPen(*wxGREY_PEN);
3301 dc.SetBrush(*wxWHITE_BRUSH);
3302 dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3303 dc.SetPen(*wxBLACK_PEN);
3304 dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
3305 if (!item->IsExpanded()) { // change "-" to "+"
3306 dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
28eab81f 3307 }
33328cd8
RD
3308#else
3309 wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3310 int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0;
3311 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag);
3312#endif
3313
28eab81f 3314 }
33328cd8 3315
1fded56b 3316 }
33328cd8 3317
1fded56b
RD
3318 }
3319
28eab81f
RD
3320 // restore DC objects
3321 dc.SetBrush(*wxWHITE_BRUSH);
3322 dc.SetPen(m_dottedPen);
3323 dc.SetTextForeground(*wxBLACK);
3324
1fded56b
RD
3325 if (item->IsExpanded())
3326 {
3327 wxArrayTreeListItems& children = item->GetChildren();
28eab81f 3328
33328cd8
RD
3329 // clip to the column width
3330 int clip_width = m_owner->GetHeaderWindow()->
3331 GetColumn(m_main_column).GetWidth();
1fded56b 3332
33328cd8
RD
3333 // process lower levels
3334 int oldY;
3335 if (m_imgWidth > 0) {
3336 oldY = y_mid + m_imgHeight2;
3337 }else{
3338 oldY = y_mid + h/2;
1fded56b 3339 }
33328cd8
RD
3340 int y2;
3341 for (size_t n = 0; n < children.Count(); ++n) {
3342
3343 y2 = y + h/2;
3344 PaintLevel (children[n], dc, level+1, y, x_maincol);
3345
3346 // draw vertical line
3347 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3348 if (!HasFlag (wxTR_NO_LINES)) {
3349 x = item->GetX();
3350 dc.DrawLine (x, oldY, x, y2);
3351 oldY = y2;
3352 }
1fded56b 3353 }
1fded56b
RD
3354 }
3355}
3356
1fded56b
RD
3357
3358// ----------------------------------------------------------------------------
3359// wxWindows callbacks
3360// ----------------------------------------------------------------------------
3361
33328cd8 3362void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
1fded56b 3363
33328cd8
RD
3364 wxPaintDC dc (this);
3365 PrepareDC (dc);
1fded56b 3366
33328cd8 3367 if (!m_rootItem || (GetColumnCount() <= 0)) return;
1fded56b 3368
28eab81f 3369 // calculate button size
28eab81f
RD
3370 if (m_imageListButtons) {
3371 m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3372 }else if (HasButtons()) {
3373 m_btnWidth = BTNWIDTH;
3374 m_btnHeight = BTNHEIGHT;
3375 }
3376 m_btnWidth2 = m_btnWidth/2;
3377 m_btnHeight2 = m_btnHeight/2;
3378
3379 // calculate image size
28eab81f
RD
3380 if (m_imageListNormal) {
3381 m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
28eab81f
RD
3382 }
3383 m_imgWidth2 = m_imgWidth/2;
3384 m_imgHeight2 = m_imgHeight/2;
3385
3386 // calculate indent size
33328cd8
RD
3387 if (m_imageListButtons) {
3388 m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3389 }else if (HasButtons()) {
3390 m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3391 }
28eab81f
RD
3392
3393 // set default values
1fded56b
RD
3394 dc.SetFont( m_normalFont );
3395 dc.SetPen( m_dottedPen );
3396
28eab81f 3397 // calculate column start and paint
33328cd8 3398 int x_maincol = 0;
28eab81f
RD
3399 int i = 0;
3400 for (i = 0; i < (int)GetMainColumn(); ++i) {
33328cd8
RD
3401 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3402 x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
1fded56b 3403 }
28eab81f 3404 int y = 0;
33328cd8 3405 PaintLevel (m_rootItem, dc, 0, y, x_maincol);
1fded56b
RD
3406}
3407
33328cd8 3408void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
1fded56b 3409
33328cd8 3410 m_hasFocus = true;
1fded56b 3411 RefreshSelected();
33328cd8 3412 if (m_curItem) RefreshLine (m_curItem);
1fded56b
RD
3413 event.Skip();
3414}
3415
3416void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3417{
33328cd8 3418 m_hasFocus = false;
1fded56b 3419 RefreshSelected();
33328cd8 3420 if (m_curItem) RefreshLine (m_curItem);
1fded56b
RD
3421 event.Skip();
3422}
3423
33328cd8
RD
3424void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3425 // send event to user code
3426 wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, m_owner->GetId());
3427 nevent.SetKeyEvent (event);
3428 nevent.SetEventObject (m_owner);
3429 if (m_owner->GetEventHandler()->ProcessEvent (nevent)) return; // handled in user code
1fded56b 3430
33328cd8
RD
3431 // determine first current if none
3432 bool curItemSet = false;
3433 if (!m_curItem) {
3434 m_curItem = (wxTreeListItem*)GetRootItem().m_pItem;
28eab81f
RD
3435 if (HasFlag(wxTR_HIDE_ROOT)) {
3436#if !wxCHECK_VERSION(2, 5, 0)
3437 long cookie = 0;
3438#else
3439 wxTreeItemIdValue cookie = 0;
3440#endif
33328cd8 3441 m_curItem = (wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem;
28eab81f 3442 }
33328cd8 3443 curItemSet = true;
1fded56b 3444 }
33328cd8 3445 if (!m_curItem) return; // do nothing if empty tree
1fded56b 3446
33328cd8
RD
3447 // remember item at shift down
3448 if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3449 if (!m_shiftItem) m_shiftItem = m_curItem;
3450 }else{
3451 m_shiftItem = (wxTreeListItem*)NULL;
3452 }
1fded56b 3453
33328cd8
RD
3454 // process all cases
3455 wxTreeItemId newItem = (wxTreeItemId*)NULL;
3456 switch (event.GetKeyCode()) {
3457
3458 // '+': Expand subtree
3459 case '+':
3460 case WXK_ADD: {
3461 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3462 }break;
1fded56b 3463
33328cd8 3464 // '-': collapse subtree
1fded56b 3465 case '-':
33328cd8
RD
3466 case WXK_SUBTRACT: {
3467 if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3468 }break;
1fded56b 3469
33328cd8
RD
3470 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3471 case '*':
3472 case WXK_MULTIPLY: {
3473 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3474 ExpandAll (m_curItem);
3475 }else if (m_curItem->HasPlus()) {
3476 Collapse (m_curItem); // TODO: CollapseAll
28eab81f 3477 }
33328cd8 3478 }break;
28eab81f 3479
33328cd8
RD
3480 // ' ': toggle current item
3481 case ' ': {
3482 SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3483 }break;
3484
3485 // <RETURN>: activate current item
3486 case WXK_RETURN: {
3487 wxTreeEvent aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
28eab81f 3488#if !wxCHECK_VERSION(2, 5, 0)
33328cd8 3489 aevent.SetItem ((long)m_curItem);
28eab81f 3490#else
33328cd8 3491 aevent.SetItem (m_curItem);
28eab81f 3492#endif
33328cd8
RD
3493 aevent.SetEventObject (m_owner);
3494 m_owner->GetEventHandler()->ProcessEvent (aevent);
3495 }break;
3496
3497 // <BKSP>: go to the parent without collapsing
3498 case WXK_BACK: {
3499 newItem = GetItemParent (m_curItem);
3500 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3501 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
1fded56b 3502 }
33328cd8 3503 }break;
1fded56b 3504
33328cd8
RD
3505 // <UP>: go to the previous sibling or to the last of its children, to the parent
3506 case WXK_UP: {
3507 newItem = GetPrevSibling (m_curItem);
3508 if (newItem) {
28eab81f 3509#if !wxCHECK_VERSION(2, 5, 0)
33328cd8 3510 long cookie = 0;
28eab81f 3511#else
33328cd8 3512 wxTreeItemIdValue cookie = 0;
28eab81f 3513#endif
33328cd8
RD
3514 while (IsExpanded (newItem) && HasChildren (newItem)) {
3515 newItem = GetLastChild (newItem, cookie);
1fded56b 3516 }
33328cd8
RD
3517 }else {
3518 newItem = GetItemParent (m_curItem);
3519 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3520 newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
28eab81f 3521 }
1fded56b 3522 }
33328cd8 3523 }break;
1fded56b 3524
33328cd8
RD
3525 // <LEFT>: if expanded collapse subtree, else go to the parent
3526 case WXK_LEFT: {
3527 if (IsExpanded (m_curItem)) {
3528 Collapse (m_curItem);
3529 }else{
3530 newItem = GetItemParent (m_curItem);
3531 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3532 newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
1fded56b 3533 }
33328cd8
RD
3534 }
3535 }break;
1fded56b 3536
33328cd8
RD
3537 // <RIGHT>: if possible expand subtree, else go go to the first child
3538 case WXK_RIGHT: {
3539 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3540 Expand (m_curItem);
3541 }else{
3542 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3543#if !wxCHECK_VERSION(2, 5, 0)
3544 long cookie = 0;
3545#else
3546 wxTreeItemIdValue cookie = 0;
3547#endif
3548 newItem = GetFirstChild (m_curItem, cookie);
1fded56b
RD
3549 }
3550 }
33328cd8 3551 }break;
1fded56b 3552
33328cd8
RD
3553 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3554 case WXK_DOWN: {
3555 if (curItemSet) {
3556 newItem = m_curItem;
3557 }else{
3558 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
28eab81f
RD
3559#if !wxCHECK_VERSION(2, 5, 0)
3560 long cookie = 0;
3561#else
3562 wxTreeItemIdValue cookie = 0;
3563#endif
33328cd8
RD
3564 newItem = GetFirstChild( m_curItem, cookie );
3565 }
3566 if (!newItem) {
3567 wxTreeItemId parent = m_curItem;
3568 do {
3569 newItem = GetNextSibling (parent);
3570 parent = GetItemParent (parent);
3571 } while (!newItem && parent);
1fded56b 3572 }
1fded56b 3573 }
33328cd8
RD
3574 }break;
3575
3576 // <END>: go to last item of the root
3577 case WXK_END: {
3578#if !wxCHECK_VERSION(2, 5, 0)
3579 long cookie = 0;
3580#else
3581 wxTreeItemIdValue cookie = 0;
3582#endif
3583 newItem = GetLastChild (GetRootItem(), cookie);
3584 }break;
3585
3586 // <HOME>: go to root
3587 case WXK_HOME: {
3588 newItem = GetRootItem();
3589 if (HasFlag(wxTR_HIDE_ROOT)) {
3590#if !wxCHECK_VERSION(2, 5, 0)
3591 long cookie = 0;
3592#else
3593 wxTreeItemIdValue cookie = 0;
3594#endif
3595 newItem = GetFirstChild (newItem, cookie);
3596 }
3597 }break;
1fded56b 3598
33328cd8 3599 // any char: go to the next matching string
1fded56b 3600 default:
33328cd8 3601 if (event.GetKeyCode() >= (int)' ') {
28eab81f 3602 if (!m_findTimer->IsRunning()) m_findStr.Clear();
33328cd8
RD
3603 m_findStr.Append (event.GetKeyCode());
3604 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3605 wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL;
3606 while (true) {
3607 newItem = FindItem (prev, m_findStr, wxTL_MODE_NAV_EXPANDED |
3608 wxTL_MODE_FIND_PARTIAL |
3609 wxTL_MODE_FIND_NOCASE);
3610 if (newItem || (m_findStr.Length() <= 1)) break;
3611 m_findStr.RemoveLast();
3612 };
28eab81f 3613 }
1fded56b 3614 event.Skip();
33328cd8 3615
1fded56b 3616 }
33328cd8
RD
3617
3618 // select and show the new item
3619 if (newItem) {
3620 if (!event.ControlDown()) {
3621 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3622 HasFlag(wxTR_MULTIPLE));
3623 SelectItem (newItem, m_shiftItem, unselect_others);
3624 }
3625 EnsureVisible (newItem);
3626 wxTreeListItem *oldItem = m_curItem;
3627 m_curItem = (wxTreeListItem*)newItem.m_pItem; // make the new item the current item
3628 RefreshLine (oldItem);
3629 }
3630
1fded56b
RD
3631}
3632
33328cd8 3633wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
1fded56b
RD
3634
3635 int w, h;
3636 GetSize(&w, &h);
3637 flags=0;
04443bbf 3638 column = -1;
1fded56b
RD
3639 if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
3640 if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
3641 if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
3642 if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
3643 if (flags) return wxTreeItemId();
3644
33328cd8 3645 if (!m_rootItem) {
1fded56b 3646 flags = wxTREE_HITTEST_NOWHERE;
33328cd8 3647 column = -1;
1fded56b
RD
3648 return wxTreeItemId();
3649 }
3650
33328cd8
RD
3651 wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
3652 this, flags, column, 0);
3653 if (!hit) {
1fded56b 3654 flags = wxTREE_HITTEST_NOWHERE;
33328cd8 3655 column = -1;
1fded56b
RD
3656 return wxTreeItemId();
3657 }
3658 return hit;
3659}
3660
3661// get the bounding rectangle of the item (or of its label only)
33328cd8
RD
3662bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
3663 bool WXUNUSED(textOnly)) const {
3664 wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
1fded56b 3665
33328cd8 3666 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
1fded56b 3667
33328cd8
RD
3668 int xUnit, yUnit;
3669 GetScrollPixelsPerUnit (&xUnit, &yUnit);
1fded56b
RD
3670 int startX, startY;
3671 GetViewStart(& startX, & startY);
3672
33328cd8
RD
3673 rect.x = item->GetX() - startX * xUnit;
3674 rect.y = item->GetY() - startY * yUnit;
3675 rect.width = item->GetWidth();
3676 rect.height = GetLineHeight (item);
1fded56b 3677
33328cd8 3678 return true;
1fded56b
RD
3679}
3680
3681/* **** */
3682
33328cd8 3683void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
1fded56b 3684 if (!item.IsOk()) return;
33328cd8 3685 if (!((column >= 0) && (column < GetColumnCount()))) return;
1fded56b 3686
33328cd8 3687 m_editItem = (wxTreeListItem*) item.m_pItem;
1fded56b
RD
3688
3689 wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, m_owner->GetId() );
33328cd8
RD
3690#if !wxCHECK_VERSION(2, 5, 0)
3691 te.SetItem ((long)m_editItem);
3692#else
3693 te.SetItem (m_editItem);
3694#endif
3695 te.SetInt (column);
3696 te.SetEventObject (m_owner );
3697 m_owner->GetEventHandler()->ProcessEvent (te);
1fded56b
RD
3698
3699 if (!te.IsAllowed()) return;
3700
33328cd8
RD
3701 // ensure that the position of the item it calculated in any case
3702 if (m_dirty) CalculatePositions();
3703
3704 wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
3705 int x = 0;
3706 int y = m_editItem->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3707 int w = 0;
3708 int h = m_editItem->GetHeight();
3709 long style = 0;
3710 if (column == GetMainColumn()) {
3711 x += m_editItem->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3712 w = wxMin (m_editItem->GetWidth(), m_owner->GetHeaderWindow()->GetWidth() - x);
3713 }else{
3714 for (int i = 0; i < column; ++i) x += header_win->GetColumnWidth (i); // start of column
3715 switch (header_win->GetColumnAlignment (column)) {
3716 case wxALIGN_LEFT: {style = wxTE_LEFT; break;}
3717 case wxALIGN_RIGHT: {style = wxTE_RIGHT; break;}
3718 case wxALIGN_CENTER: {style = wxTE_CENTER; break;}
3719 }
3720 w = header_win->GetColumnWidth (column); // width of column
3721 }
3722
3723 wxClientDC dc (this);
3724 PrepareDC (dc);
3725 x = dc.LogicalToDeviceX (x);
3726 y = dc.LogicalToDeviceY (y);
3727
3728 wxEditTextCtrl *text = new wxEditTextCtrl (this, -1, &m_renameAccept, &m_renameRes,
3729 this, m_editItem->GetText (column),
3730 wxPoint (x, y), wxSize (w, h), style);
1fded56b
RD
3731 text->SetFocus();
3732}
3733
33328cd8
RD
3734void wxTreeListMainWindow::OnRenameTimer() {
3735 EditLabel (m_curItem, m_curColumn);
1fded56b
RD
3736}
3737
33328cd8
RD
3738void wxTreeListMainWindow::OnRenameAccept() {
3739
1fded56b
RD
3740 // TODO if the validator fails this causes a crash
3741 wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, m_owner->GetId() );
33328cd8
RD
3742#if !wxCHECK_VERSION(2, 5, 0)
3743 le.SetItem((long)m_editItem);
3744#else
3745 le.SetItem(m_editItem);
3746#endif
1fded56b
RD
3747 le.SetEventObject( /*this*/m_owner );
3748 le.SetLabel( m_renameRes );
3749 m_owner->GetEventHandler()->ProcessEvent( le );
3750
3751 if (!le.IsAllowed()) return;
3752
33328cd8 3753 SetItemText (m_editItem, m_curColumn, m_renameRes);
1fded56b
RD
3754}
3755
33328cd8
RD
3756void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
3757 if (!m_rootItem) return;
4f73709d 3758
1fded56b
RD
3759 // we process left mouse up event (enables in-place edit), right down
3760 // (pass to the user code), left dbl click (activate item) and
3761 // dragging/moving events for items drag-and-drop
33328cd8
RD
3762 if (!(event.LeftDown() ||
3763 event.LeftUp() ||
3764 event.RightDown() ||
3765 event.RightUp() ||
3766 event.LeftDClick() ||
3767 event.Dragging() ||
3768 (event.GetWheelRotation() != 0 )/*? TODO ||
3769 event.Moving()?*/)) {
3770 m_owner->GetEventHandler()->ProcessEvent (event);
1fded56b
RD
3771 return;
3772 }
3773
33328cd8
RD
3774 // set focus if window clicked
3775 if (event.LeftDown() || event.RightDown()) SetFocus();
1fded56b 3776
33328cd8
RD
3777 // determine event
3778 wxPoint p = wxPoint (event.GetX(), event.GetY());
3779 int flags = 0;
3780 wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
3781 this, flags, m_curColumn, 0);
1fded56b 3782
33328cd8
RD
3783 // we only process dragging here
3784 if (event.Dragging()){
3785 if (m_isDragging) return; // nothing to do, already done
3786 if (item == NULL) return; // we need an item to dragging
1fded56b 3787
33328cd8
RD
3788 // determine drag start
3789 if (m_dragCount == 0) {
3790 m_dragTimer->Start (DRAG_TIMER_TICKS, wxTIMER_ONE_SHOT);
1fded56b 3791 }
33328cd8
RD
3792 m_dragCount++;
3793 if (m_dragCount < 3) return; // minimum drag 3 pixel
3794 if (m_dragTimer->IsRunning()) return;
1fded56b 3795
33328cd8
RD
3796 // we're going to drag
3797 m_dragCount = 0;
3798 m_isDragging = true;
3799 CaptureMouse();
3800 RefreshSelected();
3801
3802 // send drag start event
3803 wxEventType command = event.LeftIsDown()
3804 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3805 : wxEVT_COMMAND_TREE_BEGIN_RDRAG;
3806 wxTreeEvent nevent (command, m_owner->GetId());
3807 nevent.SetEventObject (m_owner);
3808#if !wxCHECK_VERSION(2, 5, 0)
3809 nevent.SetItem ((long)item); // the item the drag is ended
3810#else
3811 nevent.SetItem (item); // the item the drag is ended
3812#endif
48ac3cf8 3813 nevent.SetPoint (p);
33328cd8
RD
3814 nevent.Veto(); // dragging must be explicit allowed!
3815 m_owner->GetEventHandler()->ProcessEvent (nevent);
1fded56b 3816
33328cd8 3817 }else if (m_isDragging) { // any other event but not event.Dragging()
1fded56b 3818
33328cd8
RD
3819 // end dragging
3820 m_dragCount = 0;
3821 m_isDragging = false;
3822 if (HasCapture()) ReleaseMouse();
3823 RefreshSelected();
1fded56b 3824
33328cd8
RD
3825 // send drag end event event
3826 wxTreeEvent nevent (wxEVT_COMMAND_TREE_END_DRAG, m_owner->GetId());
3827 nevent.SetEventObject (m_owner);
3828#if !wxCHECK_VERSION(2, 5, 0)
3829 nevent.SetItem ((long)item); // the item the drag is started
3830#else
3831 nevent.SetItem (item); // the item the drag is started
3832#endif
3833 nevent.SetPoint (p);
3834 m_owner->GetEventHandler()->ProcessEvent (nevent);
1fded56b 3835
33328cd8 3836 }else if (m_dragCount > 0) { // just in case dragging is initiated
1fded56b 3837
33328cd8
RD
3838 // end dragging
3839 m_dragCount = 0;
1fded56b 3840
33328cd8 3841 }
1fded56b 3842
33328cd8
RD
3843 // we process only the messages which happen on tree items
3844 if (item == NULL) {
3845 m_owner->GetEventHandler()->ProcessEvent (event);
3846 return;
1fded56b 3847 }
1fded56b 3848
33328cd8
RD
3849 // remember item at shift down
3850 if (event.ShiftDown()) {
3851 if (!m_shiftItem) m_shiftItem = m_curItem;
3852 }else{
3853 m_shiftItem = (wxTreeListItem*)NULL;
3854 }
1fded56b 3855
33328cd8 3856 if (event.RightUp()) {
1fded56b 3857
33328cd8
RD
3858 SetFocus();
3859 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, m_owner->GetId());
3860 nevent.SetEventObject (m_owner);
3861#if !wxCHECK_VERSION(2, 5, 0)
3862 nevent.SetItem ((long)item); // the item clicked
3863#else
3864 nevent.SetItem (item); // the item clicked
3865#endif
3866 nevent.SetInt (m_curColumn); // the colum clicked
3867 nevent.SetPoint (p);
3868 m_owner->GetEventHandler()->ProcessEvent (nevent);
1fded56b 3869
33328cd8 3870 }else if (event.LeftUp()) {
1fded56b 3871
33328cd8
RD
3872 if (m_lastOnSame) {
3873 if ((item == m_curItem) && (m_curColumn != -1) &&
3874 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
3875 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))){
3876 m_renameTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
3877 }
3878 m_lastOnSame = false;
3879 }
1fded56b 3880
33328cd8
RD
3881 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3882 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3883 HasButtons() && item->HasPlus()) {
1fded56b 3884
33328cd8
RD
3885 // only toggle the item for a single click, double click on
3886 // the button doesn't do anything (it toggles the item twice)
3887 if (event.LeftDown()) Toggle (item);
1fded56b 3888
33328cd8
RD
3889 // don't select the item if the button was clicked
3890 return;
3891 }
1fded56b 3892
33328cd8
RD
3893 // determine the selection if not done by left down
3894 if (!m_left_down_selection) {
3895 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3896 HasFlag(wxTR_MULTIPLE));
3897 SelectItem (item, m_shiftItem, unselect_others);
3898 EnsureVisible (item);
3899 m_curItem = item; // make the new item the current item
3900 }else{
3901 m_left_down_selection = false;
3902 }
1fded56b 3903
33328cd8 3904 }else if (event.LeftDown() || event.RightDown() || event.LeftDClick()) {
1fded56b 3905
33328cd8 3906 if (event.LeftDown() || event.RightDown()) {
1fded56b 3907 SetFocus();
33328cd8 3908 m_lastOnSame = item == m_curItem;
1fded56b 3909 }
1fded56b 3910
33328cd8
RD
3911 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3912 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3913 item->HasPlus()) {
3914
3915 // only toggle the item for a single click, double click on
3916 // the button doesn't do anything (it toggles the item twice)
3917 if (event.LeftDown()) Toggle (item);
3918
3919 // don't select the item if the button was clicked
3920 return;
1fded56b 3921 }
1fded56b 3922
33328cd8
RD
3923 // determine the selection if the current item is not selected
3924 if (!item->IsSelected()) {
3925 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3926 HasFlag(wxTR_MULTIPLE));
3927 SelectItem (item, m_shiftItem, unselect_others);
3928 EnsureVisible (item);
3929 m_curItem = item; // make the new item the current item
3930 m_left_down_selection = true;
3931 }
1fded56b 3932
33328cd8
RD
3933 // For some reason, Windows isn't recognizing a left double-click,
3934 // so we need to simulate it here. Allow 200 milliseconds for now.
3935 if (event.LeftDClick()) {
1fded56b 3936
33328cd8
RD
3937 // double clicking should not start editing the item label
3938 m_renameTimer->Stop();
3939 m_lastOnSame = false;
3940
3941 // send activate event first
3942 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3943 nevent.SetEventObject (m_owner);
3944#if !wxCHECK_VERSION(2, 5, 0)
3945 nevent.SetItem ((long)item); // the item clicked
3946#else
3947 nevent.SetItem (item); // the item clicked
3948#endif
3949 nevent.SetInt (m_curColumn); // the colum clicked
3950 nevent.SetPoint (p);
3951 if (!m_owner->GetEventHandler()->ProcessEvent (nevent)) {
3952
3953 // if the user code didn't process the activate event,
3954 // handle it ourselves by toggling the item when it is
3955 // double clicked
3956 if (item->HasPlus()) Toggle(item);
1fded56b
RD
3957 }
3958 }
1fded56b 3959
33328cd8
RD
3960 }else{ // any other event skip just in case
3961
3962 event.Skip();
3963
3964 }
01fdd955
RD
3965}
3966
33328cd8 3967void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
1fded56b
RD
3968 /* after all changes have been done to the tree control,
3969 * we actually redraw the tree when everything is over */
3970
3971 if (!m_dirty) return;
3972
33328cd8 3973 m_dirty = false;
1fded56b
RD
3974
3975 CalculatePositions();
3976 Refresh();
3977 AdjustMyScrollbars();
3978}
3979
33328cd8 3980void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
1fded56b
RD
3981 // FIXME
3982#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
3983 wxScrolledWindow::OnScroll(event);
3984#else
3985 HandleOnScroll( event );
3986#endif
3987
33328cd8 3988 if(event.GetOrientation() == wxHORIZONTAL) {
1fded56b 3989 m_owner->GetHeaderWindow()->Refresh();
425de63d 3990 m_owner->GetHeaderWindow()->Update();
1fded56b
RD
3991 }
3992}
3993
33328cd8 3994void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
1fded56b
RD
3995 wxCoord text_w = 0;
3996 wxCoord text_h = 0;
3997
33328cd8 3998 dc.SetFont (GetItemFont (item));
1fded56b 3999
33328cd8 4000 dc.GetTextExtent (item->GetText (m_main_column), &text_w, &text_h);
1fded56b
RD
4001
4002 // restore normal font
33328cd8 4003 dc.SetFont (m_normalFont);
1fded56b 4004
28eab81f 4005 int total_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
33328cd8
RD
4006 if (total_h < 30) { // add 10% space if greater than 30 pixels
4007 total_h += 2; // minimal 2 pixel space
4008 }else{
4009 total_h += total_h / 10; // otherwise 10% space
4010 }
1fded56b 4011
33328cd8
RD
4012 item->SetHeight (total_h);
4013 if (total_h > m_lineHeight) m_lineHeight = total_h;
28eab81f 4014 item->SetWidth(m_imgWidth + text_w+2);
1fded56b
RD
4015}
4016
4017// -----------------------------------------------------------------------------
33328cd8
RD
4018void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
4019 int level, int &y, int x_colstart) {
4020
28eab81f
RD
4021 // calculate position of vertical lines
4022 int x = x_colstart + MARGIN; // start of column
4023 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
33328cd8
RD
4024 if (HasButtons()) {
4025 x += (m_btnWidth-m_btnWidth2); // half button space
4026 }else{
4027 x += (m_indent-m_indent/2);
4028 }
4029 if (HasFlag(wxTR_HIDE_ROOT)) {
4030 x += m_indent * (level-1); // indent but not level 1
4031 }else{
4032 x += m_indent * level; // indent according to level
4033 }
28eab81f
RD
4034
4035 // a hidden root is not evaluated, but its children are always
4036 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
1fded56b
RD
4037
4038 CalculateSize( item, dc );
4039
4040 // set its position
28eab81f
RD
4041 item->SetX (x);
4042 item->SetY (y);
1fded56b
RD
4043 y += GetLineHeight(item);
4044
28eab81f
RD
4045 // we don't need to calculate collapsed branches
4046 if ( !item->IsExpanded() ) return;
1fded56b 4047
28eab81f 4048Recurse:
1fded56b 4049 wxArrayTreeListItems& children = item->GetChildren();
33328cd8 4050 long n, count = (long)children.Count();
1fded56b 4051 ++level;
33328cd8 4052 for (n = 0; n < count; ++n) {
28eab81f 4053 CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse
33328cd8 4054 }
1fded56b
RD
4055}
4056
33328cd8
RD
4057void wxTreeListMainWindow::CalculatePositions() {
4058 if ( !m_rootItem ) return;
1fded56b
RD
4059
4060 wxClientDC dc(this);
4061 PrepareDC( dc );
4062
4063 dc.SetFont( m_normalFont );
4064
4065 dc.SetPen( m_dottedPen );
4066 //if(GetImageList() == NULL)
4067 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4068
4069 int y = 2;
28eab81f 4070 int x_colstart = 0;
33328cd8
RD
4071 for (int i = 0; i < (int)GetMainColumn(); ++i) {
4072 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
28eab81f 4073 x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
1fded56b 4074 }
33328cd8 4075 CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
1fded56b
RD
4076}
4077
33328cd8 4078void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
1fded56b
RD
4079 if (m_dirty) return;
4080
4081 wxClientDC dc(this);
4082 PrepareDC(dc);
4083
4084 int cw = 0;
4085 int ch = 0;
33328cd8 4086 GetVirtualSize( &cw, &ch );
1fded56b
RD
4087
4088 wxRect rect;
4089 rect.x = dc.LogicalToDeviceX( 0 );
4090 rect.width = cw;
4091 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4092 rect.height = ch;
4093
33328cd8 4094 Refresh (true, &rect );
1fded56b
RD
4095 AdjustMyScrollbars();
4096}
4097
33328cd8 4098void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
1fded56b
RD
4099 if (m_dirty) return;
4100
4101 wxClientDC dc(this);
4102 PrepareDC( dc );
4103
4104 int cw = 0;
4105 int ch = 0;
33328cd8 4106 GetVirtualSize( &cw, &ch );
1fded56b
RD
4107
4108 wxRect rect;
4109 rect.x = dc.LogicalToDeviceX( 0 );
4110 rect.y = dc.LogicalToDeviceY( item->GetY() );
4111 rect.width = cw;
4112 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4113
33328cd8 4114 Refresh (true, &rect);
1fded56b
RD
4115}
4116
33328cd8 4117void wxTreeListMainWindow::RefreshSelected() {
1fded56b
RD
4118 // TODO: this is awfully inefficient, we should keep the list of all
4119 // selected items internally, should be much faster
33328cd8
RD
4120 if (m_rootItem) {
4121 RefreshSelectedUnder (m_rootItem);
4122 }
1fded56b
RD
4123}
4124
33328cd8
RD
4125void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4126 if (item->IsSelected()) {
4127 RefreshLine (item);
4128 }
1fded56b
RD
4129
4130 const wxArrayTreeListItems& children = item->GetChildren();
33328cd8
RD
4131 long count = children.GetCount();
4132 for (long n = 0; n < count; n++ ) {
4133 RefreshSelectedUnder (children[n]);
1fded56b
RD
4134 }
4135}
4136
4137// ----------------------------------------------------------------------------
4138// changing colours: we need to refresh the tree control
4139// ----------------------------------------------------------------------------
4140
33328cd8
RD
4141bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4142 if (!wxWindow::SetBackgroundColour(colour)) return false;
1fded56b
RD
4143
4144 Refresh();
33328cd8 4145 return true;
1fded56b
RD
4146}
4147
33328cd8
RD
4148bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4149 if (!wxWindow::SetForegroundColour(colour)) return false;
1fded56b
RD
4150
4151 Refresh();
33328cd8 4152 return true;
1fded56b
RD
4153}
4154
33328cd8
RD
4155void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column,
4156 const wxString& text) {
4157 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
1fded56b 4158
33328cd8
RD
4159 wxClientDC dc (this);
4160 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4161 item->SetText (column, text);
4162 CalculateSize (item, dc);
4163 RefreshLine (item);
1fded56b
RD
4164}
4165
33328cd8
RD
4166wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId,
4167 int column) const {
4168 wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
1fded56b 4169
33328cd8
RD
4170 if( IsVirtual() ) return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4171 else return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
1fded56b
RD
4172}
4173
33328cd8
RD
4174wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item,
4175int column) const {
4176 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4177 return m_owner->OnGetItemText(item,column);
4178}
4179
4180void wxTreeListMainWindow::SetFocus() {
28eab81f
RD
4181 wxWindow::SetFocus();
4182}
4183
33328cd8
RD
4184wxFont wxTreeListMainWindow::GetItemFont (wxTreeListItem *item) {
4185 wxTreeItemAttr *attr = item->GetAttributes();
4186
4187 if (attr && attr->HasFont()) {
4188 return attr->GetFont();
4189 }else if (item->IsBold()) {
4190 return m_boldFont;
4191 }else{
4192 return m_normalFont;
4193 }
4194}
4195
4196int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4197 if (!item) return 0;
4198
4199 // determine item width
4200 int w = 0, h = 0;
4201 wxFont font = GetItemFont (item);
4202 GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4203 w += 2*MARGIN;
4204
4205 // calculate width
4206 int width = w + 2*MARGIN;
4207 if (column == GetMainColumn()) {
4208 width += MARGIN;
4209 if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4210 if (HasButtons()) width += m_btnWidth + LINEATROOT;
4211 if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4212
4213 // count indent level
4214 int level = 0;
4215 wxTreeListItem *parent = item->GetItemParent();
4216 wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4217 while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4218 level++;
4219 parent = parent->GetItemParent();
4220 }
4221 if (level) width += level * GetIndent();
4222 }
4223
4224 return width;
4225}
4226
4227int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4228 int maxWidth, h;
4229 GetClientSize (&maxWidth, &h);
4230 int width = 0;
4231
4232 // get root if on item
4233 if (!parent.IsOk()) parent = GetRootItem();
4234
4235 // add root width
4236 if (!HasFlag(wxTR_HIDE_ROOT)) {
4237 int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4238 if (width < w) width = w;
4239 if (width > maxWidth) return maxWidth;
4240 }
4241
4242 wxTreeItemIdValue cookie = 0;
4243 wxTreeItemId item = GetFirstChild (parent, cookie);
4244 while (item.IsOk()) {
4245 int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4246 if (width < w) width = w;
4247 if (width > maxWidth) return maxWidth;
4248
4249 // check the children of this item
4250 if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4251 int w = GetBestColumnWidth (column, item);
4252 if (width < w) width = w;
4253 if (width > maxWidth) return maxWidth;
4254 }
4255
4256 // next sibling
4257 item = GetNextChild (parent, cookie);
4258 }
4259
4260 return width;
4261}
4262
1fded56b
RD
4263
4264//-----------------------------------------------------------------------------
4265// wxTreeListCtrl
4266//-----------------------------------------------------------------------------
4267
33328cd8 4268IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
1fded56b
RD
4269
4270BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4271 EVT_SIZE(wxTreeListCtrl::OnSize)
4272END_EVENT_TABLE();
4273
4274bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4275 const wxPoint& pos,
4276 const wxSize& size,
4277 long style, const wxValidator &validator,
4278 const wxString& name)
4279{
33328cd8
RD
4280 long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER|
4281 wxRAISED_BORDER|wxSTATIC_BORDER);
28eab81f 4282 long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
1fded56b 4283
28eab81f
RD
4284 if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4285 return false;
4286 }
33328cd8
RD
4287 m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4288 main_style, validator);
4289 m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4290 wxPoint(0, 0), wxDefaultSize,
4291 wxTAB_TRAVERSAL);
8e3ca43b 4292 CalculateAndSetHeaderHeight();
33328cd8 4293 return true;
1fded56b
RD
4294}
4295
8e3ca43b
RD
4296void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4297{
33328cd8 4298 if (m_header_win) {
5c86a7fa
RD
4299 int h;
4300#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
4301 h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
4302#else
8e3ca43b 4303 // we use 'g' to get the descent, too
5c86a7fa 4304 int w, d;
33328cd8 4305 m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
8e3ca43b 4306 h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
5c86a7fa 4307#endif
8e3ca43b 4308 // only update if changed
33328cd8
RD
4309 if (h != m_headerHeight) {
4310 m_headerHeight = h;
4311 DoHeaderLayout();
8e3ca43b
RD
4312 }
4313 }
4314}
4315
136518e5 4316void wxTreeListCtrl::DoHeaderLayout()
1fded56b
RD
4317{
4318 int w, h;
4319 GetClientSize(&w, &h);
33328cd8
RD
4320 if (m_header_win) {
4321 m_header_win->SetSize (0, 0, w, m_headerHeight);
4322 m_header_win->Refresh();
4323 }
4324 if (m_main_win) {
4325 m_main_win->SetSize (0, m_headerHeight + 1, w, h - m_headerHeight - 1);
e778b8f0 4326 }
33328cd8 4327}
136518e5
RD
4328
4329void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4330{
4331 DoHeaderLayout();
1fded56b
RD
4332}
4333
4334size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4335
4336unsigned int wxTreeListCtrl::GetIndent() const
4337{ return m_main_win->GetIndent(); }
4338
4339void wxTreeListCtrl::SetIndent(unsigned int indent)
4340{ m_main_win->SetIndent(indent); }
4341
1fded56b
RD
4342unsigned int wxTreeListCtrl::GetLineSpacing() const
4343{ return m_main_win->GetLineSpacing(); }
4344
4345void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4346{ m_main_win->SetLineSpacing(spacing); }
4347
4348wxImageList* wxTreeListCtrl::GetImageList() const
4349{ return m_main_win->GetImageList(); }
4350
4351wxImageList* wxTreeListCtrl::GetStateImageList() const
4352{ return m_main_win->GetStateImageList(); }
4353
4354wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4355{ return m_main_win->GetButtonsImageList(); }
4356
4357void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4358{ m_main_win->SetImageList(imageList); }
4359
4360void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4361{ m_main_win->SetStateImageList(imageList); }
4362
4363void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4364{ m_main_win->SetButtonsImageList(imageList); }
4365
4366void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4367{ m_main_win->AssignImageList(imageList); }
4368
4369void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4370{ m_main_win->AssignStateImageList(imageList); }
4371
4372void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4373{ m_main_win->AssignButtonsImageList(imageList); }
4374
33328cd8
RD
4375wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4376{ return m_main_win->GetItemText (item, column); }
1fded56b 4377
33328cd8 4378int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column,
1fded56b
RD
4379 wxTreeItemIcon which) const
4380{ return m_main_win->GetItemImage(item, column, which); }
4381
4382wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4383{ return m_main_win->GetItemData(item); }
4384
4385bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4386{ return m_main_win->GetItemBold(item); }
4387
4388wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4389{ return m_main_win->GetItemTextColour(item); }
4390
4391wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item)
4392 const
4393{ return m_main_win->GetItemBackgroundColour(item); }
4394
4395wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4396{ return m_main_win->GetItemFont(item); }
4397
4398
33328cd8 4399void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column,
1fded56b 4400 const wxString& text)
33328cd8 4401{ m_main_win->SetItemText (item, column, text); }
1fded56b
RD
4402
4403void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item,
33328cd8 4404 int column,
1fded56b
RD
4405 int image,
4406 wxTreeItemIcon which)
4407{ m_main_win->SetItemImage(item, column, image, which); }
4408
4409void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,
4410 wxTreeItemData* data)
4411{ m_main_win->SetItemData(item, data); }
4412
4413void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4414{ m_main_win->SetItemHasChildren(item, has); }
4415
4416void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
4417{ m_main_win->SetItemBold(item, bold); }
4418
4419void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,
33328cd8
RD
4420 const wxColour& colour)
4421{ m_main_win->SetItemTextColour(item, colour); }
1fded56b
RD
4422
4423void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
33328cd8
RD
4424 const wxColour& colour)
4425{ m_main_win->SetItemBackgroundColour(item, colour); }
1fded56b
RD
4426
4427void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,
4428 const wxFont& font)
4429{ m_main_win->SetItemFont(item, font); }
4430
4431bool wxTreeListCtrl::SetFont(const wxFont& font)
4432{
33328cd8 4433 if (m_header_win) {
8e3ca43b
RD
4434 m_header_win->SetFont(font);
4435 CalculateAndSetHeaderHeight();
33328cd8 4436 m_header_win->Refresh();
8e3ca43b 4437 }
33328cd8 4438 if (m_main_win) {
1fded56b 4439 return m_main_win->SetFont(font);
33328cd8
RD
4440 }else{
4441 return false;
4442 }
1fded56b
RD
4443}
4444
4445void wxTreeListCtrl::SetWindowStyle(const long style)
4446{
4447 if(m_main_win)
4448 m_main_win->SetWindowStyle(style);
33328cd8 4449 m_windowStyle = style;
1fded56b
RD
4450 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4451}
4452
4453long wxTreeListCtrl::GetWindowStyle() const
4454{
4455 long style = m_windowStyle;
4456 if(m_main_win)
4457 style |= m_main_win->GetWindowStyle();
4458 return style;
4459}
4460
33328cd8
RD
4461bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow) const
4462{ return m_main_win->IsVisible(item, fullRow); }
1fded56b 4463
33328cd8
RD
4464bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4465{ return m_main_win->HasChildren(item); }
1fded56b
RD
4466
4467bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4468{ return m_main_win->IsExpanded(item); }
4469
4470bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4471{ return m_main_win->IsSelected(item); }
4472
4473bool wxTreeListCtrl::IsBold(const wxTreeItemId& item) const
4474{ return m_main_win->IsBold(item); }
4475
4476size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4477{ return m_main_win->GetChildrenCount(item, rec); }
4478
4479wxTreeItemId wxTreeListCtrl::GetRootItem() const
4480{ return m_main_win->GetRootItem(); }
4481
4482wxTreeItemId wxTreeListCtrl::GetSelection() const
4483{ return m_main_win->GetSelection(); }
4484
4485size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4486{ return m_main_win->GetSelections(arr); }
4487
28eab81f
RD
4488wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4489{ return m_main_win->GetItemParent(item); }
1fded56b 4490
28eab81f 4491#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
4492wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4493 long& cookie) const
28eab81f 4494#else
33328cd8
RD
4495wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4496 wxTreeItemIdValue& cookie) const
28eab81f 4497#endif
1fded56b
RD
4498{ return m_main_win->GetFirstChild(item, cookie); }
4499
28eab81f 4500#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
4501wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4502 long& cookie) const
28eab81f 4503#else
33328cd8
RD
4504wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4505 wxTreeItemIdValue& cookie) const
28eab81f 4506#endif
1fded56b
RD
4507{ return m_main_win->GetNextChild(item, cookie); }
4508
28eab81f 4509#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
4510wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4511 long& cookie) const
28eab81f 4512#else
33328cd8
RD
4513wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4514 wxTreeItemIdValue& cookie) const
28eab81f
RD
4515#endif
4516{ return m_main_win->GetPrevChild(item, cookie); }
4517
33328cd8
RD
4518#if !wxCHECK_VERSION(2, 5, 0)
4519wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4520 long& cookie) const
4521#else
4522wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4523 wxTreeItemIdValue& cookie) const
4524#endif
4525{ return m_main_win->GetLastChild(item, cookie); }
4526
1fded56b
RD
4527
4528wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
4529{ return m_main_win->GetNextSibling(item); }
4530
4531wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
4532{ return m_main_win->GetPrevSibling(item); }
4533
33328cd8
RD
4534wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
4535{ return m_main_win->GetNext(item, true); }
1fded56b 4536
33328cd8
RD
4537wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
4538{ return m_main_win->GetPrev(item, true); }
1fded56b 4539
33328cd8
RD
4540wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
4541{ return m_main_win->GetFirstExpandedItem(); }
1fded56b 4542
33328cd8
RD
4543wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
4544{ return m_main_win->GetNextExpanded(item); }
4545
4546wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
4547{ return m_main_win->GetPrevExpanded(item); }
4548
4549wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
4550{ return m_main_win->GetFirstVisibleItem(fullRow); }
1fded56b 4551
33328cd8
RD
4552wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow) const
4553{ return m_main_win->GetNextVisible(item, fullRow); }
4554
4555wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow) const
4556{ return m_main_win->GetPrevVisible(item, fullRow); }
4557
4558wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
4559 int selectedImage, wxTreeItemData* data)
4560{ return m_main_win->AddRoot (text, image, selectedImage, data); }
1fded56b
RD
4561
4562wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
4563 const wxString& text, int image,
4564 int selectedImage,
4565 wxTreeItemData* data)
4566{ return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
4567
4568wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4569 const wxTreeItemId& previous,
4570 const wxString& text, int image,
4571 int selectedImage,
4572 wxTreeItemData* data)
4573{
4574 return m_main_win->InsertItem(parent, previous, text, image,
4575 selectedImage, data);
4576}
4577
4578wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4579 size_t index,
4580 const wxString& text, int image,
4581 int selectedImage,
4582 wxTreeItemData* data)
4583{
4584 return m_main_win->InsertItem(parent, index, text, image,
4585 selectedImage, data);
4586}
4587
4588wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
4589 const wxString& text, int image,
4590 int selectedImage,
4591 wxTreeItemData* data)
4592{ return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
4593
4594void wxTreeListCtrl::Delete(const wxTreeItemId& item)
4595{ m_main_win->Delete(item); }
4596
4597void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
4598{ m_main_win->DeleteChildren(item); }
4599
33328cd8
RD
4600void wxTreeListCtrl::DeleteRoot()
4601{ m_main_win->DeleteRoot(); }
1fded56b
RD
4602
4603void wxTreeListCtrl::Expand(const wxTreeItemId& item)
4604{ m_main_win->Expand(item); }
4605
4606void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
4607{ m_main_win->ExpandAll(item); }
4608
4609void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
4610{ m_main_win->Collapse(item); }
4611
4612void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
4613{ m_main_win->CollapseAndReset(item); }
4614
4615void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
4616{ m_main_win->Toggle(item); }
4617
4618void wxTreeListCtrl::Unselect()
4619{ m_main_win->Unselect(); }
4620
4621void wxTreeListCtrl::UnselectAll()
4622{ m_main_win->UnselectAll(); }
4623
33328cd8
RD
4624void wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
4625 bool unselect_others)
4626{ m_main_win->SelectItem (item, last, unselect_others); }
1fded56b 4627
33328cd8
RD
4628void wxTreeListCtrl::SelectAll()
4629{ m_main_win->SelectAll(); }
28eab81f 4630
1fded56b
RD
4631void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
4632{ m_main_win->EnsureVisible(item); }
4633
4634void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
4635{ m_main_win->ScrollTo(item); }
4636
33328cd8 4637wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
1fded56b 4638{
48ac3cf8 4639 return m_main_win->HitTest (pos, flags, column);
1fded56b
RD
4640}
4641
4642bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
4643 bool textOnly) const
4644{ return m_main_win->GetBoundingRect(item, rect, textOnly); }
4645
33328cd8
RD
4646void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
4647{ m_main_win->EditLabel (item, column); }
1fded56b
RD
4648
4649int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1,
4650 const wxTreeItemId& item2)
4651{
33328cd8 4652 // do the comparison here, and not delegate to m_main_win, in order
1fded56b
RD
4653 // to let the user override it
4654 //return m_main_win->OnCompareItems(item1, item2);
4655 return wxStrcmp(GetItemText(item1), GetItemText(item2));
4656}
4657
4658void wxTreeListCtrl::SortChildren(const wxTreeItemId& item)
4659{ m_main_win->SortChildren(item); }
4660
33328cd8
RD
4661wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, const wxString& str, int mode)
4662{ return m_main_win->FindItem (item, str, mode); }
4663
4664void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
4665{ m_main_win->SetDragItem (item); }
28eab81f 4666
1fded56b 4667bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
33328cd8 4668{
da9b4153 4669 if (!m_main_win) return false;
33328cd8 4670 return m_main_win->SetBackgroundColour(colour);
da9b4153 4671}
1fded56b
RD
4672
4673bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
33328cd8 4674{
da9b4153 4675 if (!m_main_win) return false;
33328cd8 4676 return m_main_win->SetForegroundColour(colour);
da9b4153 4677}
1fded56b 4678
33328cd8 4679int wxTreeListCtrl::GetColumnCount() const
1fded56b
RD
4680{ return m_main_win->GetColumnCount(); }
4681
33328cd8
RD
4682void wxTreeListCtrl::SetColumnWidth(int column, int width)
4683{
4684 m_header_win->SetColumnWidth (column, width);
4685 m_header_win->Refresh();
4686}
1fded56b 4687
33328cd8 4688int wxTreeListCtrl::GetColumnWidth(int column) const
1fded56b
RD
4689{ return m_header_win->GetColumnWidth(column); }
4690
33328cd8 4691void wxTreeListCtrl::SetMainColumn(int column)
1fded56b
RD
4692{ m_main_win->SetMainColumn(column); }
4693
33328cd8 4694int wxTreeListCtrl::GetMainColumn() const
1fded56b
RD
4695{ return m_main_win->GetMainColumn(); }
4696
33328cd8 4697void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
1fded56b 4698{
33328cd8 4699 m_header_win->SetColumnText (column, text);
1fded56b
RD
4700 m_header_win->Refresh();
4701}
4702
33328cd8 4703wxString wxTreeListCtrl::GetColumnText(int column) const
1fded56b
RD
4704{ return m_header_win->GetColumnText(column); }
4705
33328cd8 4706void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
136518e5 4707{
33328cd8 4708 m_header_win->AddColumn (colInfo);
136518e5
RD
4709 DoHeaderLayout();
4710}
1fded56b 4711
33328cd8
RD
4712void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
4713{
4714 m_header_win->InsertColumn (before, colInfo);
4715 m_header_win->Refresh();
4716}
1fded56b 4717
33328cd8
RD
4718void wxTreeListCtrl::RemoveColumn(int column)
4719{
4720 m_header_win->RemoveColumn (column);
4721 m_header_win->Refresh();
4722}
1fded56b 4723
33328cd8
RD
4724void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
4725{
4726 m_header_win->SetColumn (column, colInfo);
4727 m_header_win->Refresh();
4728}
1fded56b 4729
33328cd8 4730const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
1fded56b
RD
4731{ return m_header_win->GetColumn(column); }
4732
33328cd8 4733wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column)
1fded56b
RD
4734{ return m_header_win->GetColumn(column); }
4735
33328cd8 4736void wxTreeListCtrl::SetColumnImage(int column, int image)
1fded56b 4737{
33328cd8
RD
4738 m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
4739 m_header_win->Refresh();
1fded56b
RD
4740}
4741
33328cd8 4742int wxTreeListCtrl::GetColumnImage(int column) const
1fded56b
RD
4743{
4744 return m_header_win->GetColumn(column).GetImage();
4745}
4746
33328cd8
RD
4747void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
4748{
4749 m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
4750}
4751
4752void wxTreeListCtrl::SetColumnShown(int column, bool shown)
4753{
4754 wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
4755 m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
4756 m_header_win->Refresh();
4757}
4758
4759bool wxTreeListCtrl::IsColumnEditable(int column) const
28eab81f 4760{
33328cd8 4761 return m_header_win->GetColumn(column).IsEditable();
28eab81f
RD
4762}
4763
33328cd8 4764bool wxTreeListCtrl::IsColumnShown(int column) const
28eab81f 4765{
33328cd8 4766 return m_header_win->GetColumn(column).IsShown();
28eab81f
RD
4767}
4768
33328cd8 4769void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
1fded56b 4770{
33328cd8
RD
4771 m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
4772 m_header_win->Refresh();
1fded56b
RD
4773}
4774
33328cd8 4775int wxTreeListCtrl::GetColumnAlignment(int column) const
1fded56b
RD
4776{
4777 return m_header_win->GetColumn(column).GetAlignment();
4778}
4779
4780void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
4781{
33328cd8
RD
4782 m_main_win->Refresh (erase, rect);
4783 m_header_win->Refresh (erase, rect);
1fded56b
RD
4784}
4785
4786void wxTreeListCtrl::SetFocus()
4787{ m_main_win->SetFocus(); }
28eab81f 4788
3872d96d
RD
4789wxSize wxTreeListCtrl::DoGetBestSize() const
4790{
4791 // something is better than nothing...
33328cd8 4792 return wxSize (200,200); // but it should be specified values! FIXME
3872d96d 4793}
4f73709d 4794
33328cd8 4795wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
4f73709d 4796{
33328cd8 4797 return wxEmptyString;
4f73709d 4798}