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