]> git.saurik.com Git - wxWidgets.git/blame - wxPython/contrib/gizmos/wxCode/src/treelistctrl.cpp
KeyCode --> GetKeyCode
[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
80752b57
RD
1197 wxRendererNative::Get().DrawHeaderButton(this, dc, rect, flags,
1198 wxHDR_SORT_ICON_NONE, &params);
5c86a7fa
RD
1199 }
1200
1201 if (x < w) {
1202 wxRect rect(x, 0, w-x, h);
1203 wxRendererNative::Get().DrawHeaderButton(this, dc, rect);
1204 }
1205
1206#else // not 2.7.0.1+
1207
1208 dc.SetFont( GetFont() );
1209
1fded56b
RD
1210 // do *not* use the listctrl colour for headers - one day we will have a
1211 // function to set it separately
1212 //dc.SetTextForeground( *wxBLACK );
33328cd8
RD
1213#if !wxCHECK_VERSION(2, 5, 0)
1214 dc.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
1215#else
1216 dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ));
1217#endif
1fded56b 1218
1fded56b
RD
1219 int numColumns = GetColumnCount();
1220 for ( int i = 0; i < numColumns && x < w; i++ )
1221 {
5c86a7fa 1222 if (!IsColumnShown (i)) continue; // do next column if not shown
28eab81f 1223
1fded56b
RD
1224 wxTreeListColumnInfo& column = GetColumn(i);
1225 int wCol = column.GetWidth();
1226
1227 // the width of the rect to draw: make it smaller to fit entirely
1228 // inside the column rect
1229 int cw = wCol - 2;
1230
33328cd8 1231#if !wxCHECK_VERSION(2, 7, 0)
1fded56b 1232 dc.SetPen( *wxWHITE_PEN );
33328cd8
RD
1233 DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
1234#else
1235 wxRect rect(x, HEADER_OFFSET_Y, cw, h-2);
1236 wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
1237#endif
1fded56b
RD
1238
1239 // if we have an image, draw it on the right of the label
1240 int image = column.GetImage(); //item.m_image;
1241 int ix = -2, iy = 0;
1242 wxImageList* imageList = m_owner->GetImageList();
33328cd8
RD
1243 if ((image != -1) && imageList) {
1244 imageList->GetSize (image, ix, iy);
1fded56b
RD
1245 }
1246
33328cd8 1247 // extra margins around the text label
1fded56b
RD
1248 int text_width = 0;
1249 int text_x = x;
1250 int image_offset = cw - ix - 1;
1251
1252 switch(column.GetAlignment()) {
33328cd8 1253 case wxALIGN_LEFT:
1fded56b
RD
1254 text_x += EXTRA_WIDTH;
1255 cw -= ix + 2;
1256 break;
33328cd8
RD
1257 case wxALIGN_RIGHT:
1258 dc.GetTextExtent (column.GetText(), &text_width, NULL);
1259 text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
1fded56b
RD
1260 image_offset = 0;
1261 break;
33328cd8 1262 case wxALIGN_CENTER:
1fded56b
RD
1263 dc.GetTextExtent(column.GetText(), &text_width, NULL);
1264 text_x += (cw - text_width)/2 + ix + 2;
33328cd8 1265 image_offset = (cw - text_width - ix - 2)/2 - MARGIN;
1fded56b
RD
1266 break;
1267 }
1268
1269 // draw the image
33328cd8
RD
1270 if ((image != -1) && imageList) {
1271 imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/,
1272 HEADER_OFFSET_Y + (h - 4 - iy)/2,
1273 wxIMAGELIST_DRAW_TRANSPARENT);
1fded56b
RD
1274 }
1275
33328cd8 1276 // draw the text clipping it so that it doesn't overwrite the column boundary
1fded56b 1277 wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
33328cd8 1278 dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT );
1fded56b 1279
33328cd8 1280 // next column
1fded56b
RD
1281 x += wCol;
1282 }
1283
33328cd8
RD
1284 int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
1285 if (more_w > 0) {
1286#if !wxCHECK_VERSION(2, 7, 0)
1287 DoDrawRect (&dc, x, HEADER_OFFSET_Y, more_w, h-2 );
1288#else
1289 wxRect rect (x, HEADER_OFFSET_Y, more_w, h-2);
1290 wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
1291#endif
28eab81f 1292 }
5c86a7fa 1293#endif // 2.7.0.1
1fded56b
RD
1294}
1295
1296void wxTreeListHeaderWindow::DrawCurrent()
1297{
1298 int x1 = m_currentX;
1299 int y1 = 0;
33328cd8 1300 ClientToScreen (&x1, &y1);
1fded56b
RD
1301
1302 int x2 = m_currentX-1;
1303#ifdef __WXMSW__
33328cd8 1304 ++x2; // but why ????
1fded56b
RD
1305#endif
1306 int y2 = 0;
1307 m_owner->GetClientSize( NULL, &y2 );
1308 m_owner->ClientToScreen( &x2, &y2 );
1309
1310 wxScreenDC dc;
33328cd8
RD
1311 dc.SetLogicalFunction (wxINVERT);
1312 dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID));
1313 dc.SetBrush (*wxTRANSPARENT_BRUSH);
1fded56b
RD
1314
1315 AdjustDC(dc);
33328cd8
RD
1316 dc.DrawLine (x1, y1, x2, y2);
1317 dc.SetLogicalFunction (wxCOPY);
1318 dc.SetPen (wxNullPen);
1319 dc.SetBrush (wxNullBrush);
1fded56b
RD
1320}
1321
5c86a7fa
RD
1322#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1323int wxTreeListHeaderWindow::XToCol(int x)
1324{
1325 int colLeft = 0;
1326 int numColumns = GetColumnCount();
1327 for ( int col = 0; col < numColumns; col++ )
1328 {
1329 if (!IsColumnShown(col)) continue;
1330 wxTreeListColumnInfo& column = GetColumn(col);
1331
1332 if ( x < (colLeft + column.GetWidth()) )
1333 return col;
1334
1335 colLeft += column.GetWidth();
1336 }
1337 return -1;
1338}
1339
1340
1341void wxTreeListHeaderWindow::RefreshColLabel(int col)
1342{
1343 if ( col > GetColumnCount() )
1344 return;
1345
1346 int x = 0;
1347 int width = 0;
1348 int idx = 0;
1349 do {
1350 if (!IsColumnShown(idx)) continue;
1351 wxTreeListColumnInfo& column = GetColumn(idx);
1352 x += width;
1353 width = column.GetWidth();
1354 } while (++idx <= col);
1355
1356 m_owner->CalcScrolledPosition(x, 0, &x, NULL);
1357 RefreshRect(wxRect(x, 0, width, GetSize().GetHeight()));
1358}
1359#endif
1360
1361
33328cd8
RD
1362void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
1363
1fded56b
RD
1364 // we want to work with logical coords
1365 int x;
1366 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1367 int y = event.GetY();
1368
5c86a7fa
RD
1369#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1370 if ( event.Moving() )
1371 {
1372 int col = XToCol(x);
1373 if ( col != m_hotTrackCol )
1374 {
1375 // Refresh the col header so it will be painted with hot tracking
1376 // (if supported by the native renderer.)
1377 RefreshColLabel(col);
1378
1379 // Also refresh the old hot header
1380 if ( m_hotTrackCol >= 0 )
1381 RefreshColLabel(m_hotTrackCol);
1382
1383 m_hotTrackCol = col;
1384 }
1385 }
1386
1387 if ( event.Leaving() && m_hotTrackCol >= 0 )
1388 {
1389 // Leaving the window so clear any hot tracking indicator that may be present
1390 RefreshColLabel(m_hotTrackCol);
1391 m_hotTrackCol = -1;
1392 }
1393#endif
1394
33328cd8
RD
1395 if (m_isDragging) {
1396
1397 SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
1fded56b
RD
1398
1399 // we don't draw the line beyond our window, but we allow dragging it
1400 // there
1401 int w = 0;
1402 GetClientSize( &w, NULL );
1403 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1404 w -= 6;
1405
1406 // erase the line if it was drawn
33328cd8 1407 if (m_currentX < w) DrawCurrent();
1fded56b 1408
33328cd8
RD
1409 if (event.ButtonUp()) {
1410 m_isDragging = false;
1411 if (HasCapture()) ReleaseMouse();
1412 m_dirty = true;
1413 SetColumnWidth (m_column, m_currentX - m_minX);
1fded56b 1414 Refresh();
33328cd8
RD
1415 SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
1416 }else{
1417 m_currentX = wxMax (m_minX + 7, x);
1fded56b
RD
1418
1419 // draw in the new location
33328cd8 1420 if (m_currentX < w) DrawCurrent();
1fded56b 1421 }
33328cd8
RD
1422
1423 }else{ // not dragging
1424
1fded56b 1425 m_minX = 0;
33328cd8 1426 bool hit_border = false;
1fded56b
RD
1427
1428 // end of the current column
1429 int xpos = 0;
1430
33328cd8 1431 // find the column where this event occured
1fded56b 1432 int countCol = GetColumnCount();
33328cd8
RD
1433 for (int column = 0; column < countCol; column++) {
1434 if (!IsColumnShown (column)) continue; // do next if not shown
1fded56b 1435
33328cd8
RD
1436 xpos += GetColumnWidth (column);
1437 m_column = column;
1438 if ((abs (x-xpos) < 3) && (y < 22)) {
1fded56b 1439 // near the column border
33328cd8 1440 hit_border = true;
1fded56b
RD
1441 break;
1442 }
1443
33328cd8 1444 if (x < xpos) {
1fded56b
RD
1445 // inside the column
1446 break;
1447 }
1448
1449 m_minX = xpos;
1450 }
1451
33328cd8
RD
1452 if (event.LeftDown() || event.RightUp()) {
1453 if (hit_border && event.LeftDown()) {
1454 m_isDragging = true;
1455 CaptureMouse();
1fded56b
RD
1456 m_currentX = x;
1457 DrawCurrent();
33328cd8
RD
1458 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
1459 }else{ // click on a column
1460 wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
1461 wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
1462 SendListEvent (evt, event.GetPosition());
1fded56b 1463 }
33328cd8
RD
1464 }else if (event.LeftDClick() && hit_border) {
1465 SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
1466 Refresh();
1467
1468 }else if (event.Moving()) {
1fded56b 1469 bool setCursor;
33328cd8 1470 if (hit_border) {
1fded56b
RD
1471 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1472 m_currentCursor = m_resizeCursor;
33328cd8 1473 }else{
1fded56b
RD
1474 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1475 m_currentCursor = wxSTANDARD_CURSOR;
1476 }
33328cd8 1477 if (setCursor) SetCursor (*m_currentCursor);
1fded56b 1478 }
33328cd8 1479
1fded56b
RD
1480 }
1481}
1482
33328cd8 1483void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
1fded56b
RD
1484 m_owner->SetFocus();
1485}
1486
33328cd8 1487void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
1fded56b 1488 wxWindow *parent = GetParent();
33328cd8
RD
1489 wxListEvent le (type, parent->GetId());
1490 le.SetEventObject (parent);
1fded56b
RD
1491 le.m_pointDrag = pos;
1492
1493 // the position should be relative to the parent window, not
1494 // this one for compatibility with MSW and common sense: the
1495 // user code doesn't know anything at all about this header
1496 // window, so why should it get positions relative to it?
1497 le.m_pointDrag.y -= GetSize().y;
1fded56b 1498 le.m_col = m_column;
33328cd8 1499 parent->GetEventHandler()->ProcessEvent (le);
1fded56b
RD
1500}
1501
33328cd8
RD
1502void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
1503 m_columns.Add (colInfo);
1504 m_total_col_width += colInfo.GetWidth();
1fded56b 1505 m_owner->AdjustMyScrollbars();
33328cd8 1506 m_owner->m_dirty = true;
1fded56b
RD
1507}
1508
33328cd8
RD
1509void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
1510 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1511 m_total_col_width -= m_columns[column].GetWidth();
1512 m_columns[column].SetWidth(width);
1513 m_total_col_width += width;
1514 m_owner->AdjustMyScrollbars();
1515 m_owner->m_dirty = true;
1fded56b
RD
1516}
1517
33328cd8
RD
1518void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
1519 wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
1520 m_columns.Insert (colInfo, before);
1521 m_total_col_width += colInfo.GetWidth();
1fded56b 1522 m_owner->AdjustMyScrollbars();
33328cd8 1523 m_owner->m_dirty = true;
1fded56b
RD
1524}
1525
33328cd8
RD
1526void wxTreeListHeaderWindow::RemoveColumn (int column) {
1527 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1fded56b 1528 m_total_col_width -= m_columns[column].GetWidth();
33328cd8 1529 m_columns.RemoveAt (column);
1fded56b 1530 m_owner->AdjustMyScrollbars();
33328cd8 1531 m_owner->m_dirty = true;
1fded56b
RD
1532}
1533
33328cd8
RD
1534void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
1535 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1536 int w = m_columns[column].GetWidth();
1fded56b 1537 m_columns[column] = info;
33328cd8 1538 if (w != info.GetWidth()) {
1fded56b
RD
1539 m_total_col_width += info.GetWidth() - w;
1540 m_owner->AdjustMyScrollbars();
1fded56b 1541 }
33328cd8 1542 m_owner->m_dirty = true;
1fded56b
RD
1543}
1544
1545// ---------------------------------------------------------------------------
1546// wxTreeListItem
1547// ---------------------------------------------------------------------------
1548
33328cd8
RD
1549wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
1550 wxTreeListItem *parent,
1551 const wxArrayString& text,
1552 int image, int selImage,
1553 wxTreeItemData *data)
1554 : m_text (text) {
1555
1fded56b
RD
1556 m_images[wxTreeItemIcon_Normal] = image;
1557 m_images[wxTreeItemIcon_Selected] = selImage;
1558 m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
1559 m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
1560
1561 m_data = data;
33328cd8
RD
1562 m_x = 0;
1563 m_y = 0;
1564 m_text_x = 0;
1fded56b 1565
33328cd8
RD
1566 m_isCollapsed = true;
1567 m_hasHilight = false;
1568 m_hasPlus = false;
1569 m_isBold = false;
1fded56b
RD
1570
1571 m_owner = owner;
1fded56b
RD
1572 m_parent = parent;
1573
1574 m_attr = (wxTreeItemAttr *)NULL;
33328cd8 1575 m_ownsAttr = false;
1fded56b
RD
1576
1577 // We don't know the height here yet.
1578 m_width = 0;
1579 m_height = 0;
1580}
1581
33328cd8 1582wxTreeListItem::~wxTreeListItem() {
1fded56b 1583 delete m_data;
1fded56b
RD
1584 if (m_ownsAttr) delete m_attr;
1585
33328cd8 1586 wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1fded56b
RD
1587}
1588
33328cd8 1589void wxTreeListItem::DeleteChildren (wxTreeListMainWindow *tree) {
1fded56b 1590 size_t count = m_children.Count();
33328cd8 1591 for (size_t n = 0; n < count; n++) {
1fded56b 1592 wxTreeListItem *child = m_children[n];
33328cd8
RD
1593 if (tree) {
1594 tree->SendDeleteEvent (child);
1595 if (tree->m_selectItem == child) tree->m_selectItem = (wxTreeListItem*)NULL;
1596 }
1597 child->DeleteChildren (tree);
1fded56b
RD
1598 delete child;
1599 }
1fded56b
RD
1600 m_children.Empty();
1601}
1602
33328cd8
RD
1603void wxTreeListItem::SetText (const wxString &text) {
1604 if (m_text.GetCount() > 0) {
1605 m_text[0] = text;
1606 }else{
1607 m_text.Add (text);
1fded56b
RD
1608 }
1609}
1610
33328cd8 1611size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
1fded56b 1612 size_t count = m_children.Count();
33328cd8 1613 if (!recursively) return count;
1fded56b
RD
1614
1615 size_t total = count;
33328cd8 1616 for (size_t n = 0; n < count; ++n) {
1fded56b
RD
1617 total += m_children[n]->GetChildrenCount();
1618 }
1fded56b
RD
1619 return total;
1620}
1621
33328cd8
RD
1622void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
1623 int bottomY = m_y + theButton->GetLineHeight (this);
1624 if (y < bottomY) y = bottomY;
1fded56b
RD
1625 int width = m_x + m_width;
1626 if ( x < width ) x = width;
1627
33328cd8 1628 if (IsExpanded()) {
1fded56b 1629 size_t count = m_children.Count();
33328cd8
RD
1630 for (size_t n = 0; n < count; ++n ) {
1631 m_children[n]->GetSize (x, y, theButton);
1fded56b
RD
1632 }
1633 }
1634}
1635
33328cd8
RD
1636wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
1637 const wxTreeListMainWindow *theCtrl,
1638 int &flags, int& column, int level) {
1639
1fded56b 1640 // for a hidden root node, don't evaluate it, but do evaluate children
33328cd8
RD
1641 if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
1642
1643 // reset any previous hit infos
1644 flags = 0;
1645 column = -1;
1646 wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
1647
1648 // check for right of all columns (outside)
1649 if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
1650
1651 // evaluate if y-pos is okay
1652 int h = theCtrl->GetLineHeight (this);
1653 if ((point.y >= m_y) && (point.y <= m_y + h)) {
1654
1655 int maincol = theCtrl->GetMainColumn();
1656
28eab81f 1657 // check for above/below middle
1fded56b 1658 int y_mid = m_y + h/2;
33328cd8 1659 if (point.y < y_mid) {
1fded56b 1660 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
33328cd8 1661 }else{
1fded56b 1662 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
33328cd8 1663 }
1fded56b 1664
28eab81f 1665 // check for button hit
33328cd8
RD
1666 if (HasPlus() && theCtrl->HasButtons()) {
1667 int bntX = m_x - theCtrl->m_btnWidth2;
1668 int bntY = y_mid - theCtrl->m_btnHeight2;
1669 if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
1670 (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
1671 flags |= wxTREE_HITTEST_ONITEMBUTTON;
1672 column = maincol;
1673 return this;
1674 }
1fded56b
RD
1675 }
1676
28eab81f 1677 // check for image hit
33328cd8
RD
1678 if (theCtrl->m_imgWidth > 0) {
1679 int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
28eab81f
RD
1680 int imgY = y_mid - theCtrl->m_imgHeight2;
1681 if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
1682 (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
1fded56b 1683 flags |= wxTREE_HITTEST_ONITEMICON;
33328cd8 1684 column = maincol;
28eab81f
RD
1685 return this;
1686 }
1687 }
1fded56b 1688
28eab81f 1689 // check for label hit
33328cd8 1690 if ((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) {
28eab81f 1691 flags |= wxTREE_HITTEST_ONITEMLABEL;
33328cd8 1692 column = maincol;
1fded56b
RD
1693 return this;
1694 }
1695
33328cd8 1696 // check for indent hit after button and image hit
28eab81f 1697 if (point.x < m_x) {
1fded56b 1698 flags |= wxTREE_HITTEST_ONITEMINDENT;
33328cd8 1699 column = -1; // considered not belonging to main column
28eab81f
RD
1700 return this;
1701 }
1702
33328cd8
RD
1703 // check for right of label
1704 int end = 0;
1705 for (int i = 0; i <= maincol; ++i) end += header_win->GetColumnWidth (i);
1706 if ((point.x > (m_text_x + m_width)) && (point.x <= end)) {
1fded56b 1707 flags |= wxTREE_HITTEST_ONITEMRIGHT;
33328cd8 1708 column = -1; // considered not belonging to main column
28eab81f
RD
1709 return this;
1710 }
1fded56b 1711
33328cd8
RD
1712 // else check for each column except main
1713 int x = 0;
1714 for (int j = 0; j < theCtrl->GetColumnCount(); ++j) {
1715 if (!header_win->IsColumnShown(j)) continue;
1716 int w = header_win->GetColumnWidth (j);
1717 if ((j != maincol) && (point.x >= x && point.x < x+w)) {
1718 flags |= wxTREE_HITTEST_ONITEMCOLUMN;
1719 column = j;
1720 return this;
1721 }
1722 x += w;
1723 }
1724
1725 // no special flag or column found
1726 return this;
1727
1fded56b
RD
1728 }
1729
33328cd8
RD
1730 // if children not expanded, return no item
1731 if (!IsExpanded()) return (wxTreeListItem*) NULL;
1fded56b
RD
1732 }
1733
33328cd8
RD
1734 // in any case evaluate children
1735 wxTreeListItem *child;
1fded56b 1736 size_t count = m_children.Count();
33328cd8
RD
1737 for (size_t n = 0; n < count; n++) {
1738 child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
1739 if (child) return child;
1fded56b
RD
1740 }
1741
33328cd8 1742 // not found
1fded56b
RD
1743 return (wxTreeListItem*) NULL;
1744}
1745
33328cd8 1746int wxTreeListItem::GetCurrentImage() const {
1fded56b 1747 int image = NO_IMAGE;
33328cd8
RD
1748 if (IsExpanded()) {
1749 if (IsSelected()) {
1750 image = GetImage (wxTreeItemIcon_SelectedExpanded);
1751 }else{
1752 image = GetImage (wxTreeItemIcon_Expanded);
1fded56b 1753 }
33328cd8
RD
1754 }else{ // not expanded
1755 if (IsSelected()) {
1756 image = GetImage (wxTreeItemIcon_Selected);
1757 }else{
1758 image = GetImage (wxTreeItemIcon_Normal);
1fded56b
RD
1759 }
1760 }
1fded56b 1761
33328cd8
RD
1762 // maybe it doesn't have the specific image, try the default one instead
1763 if (image == NO_IMAGE) image = GetImage();
1fded56b
RD
1764
1765 return image;
1766}
1767
1768// ---------------------------------------------------------------------------
1769// wxTreeListMainWindow implementation
1770// ---------------------------------------------------------------------------
1771
1772IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
1773
1774BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
1775 EVT_PAINT (wxTreeListMainWindow::OnPaint)
1776 EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse)
1777 EVT_CHAR (wxTreeListMainWindow::OnChar)
1778 EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus)
1779 EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus)
1780 EVT_IDLE (wxTreeListMainWindow::OnIdle)
1fded56b
RD
1781 EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll)
1782END_EVENT_TABLE()
1783
1784
1785// ---------------------------------------------------------------------------
1786// construction/destruction
1787// ---------------------------------------------------------------------------
1788
33328cd8
RD
1789void wxTreeListMainWindow::Init() {
1790
1791 m_rootItem = (wxTreeListItem*)NULL;
1792 m_curItem = (wxTreeListItem*)NULL;
1793 m_shiftItem = (wxTreeListItem*)NULL;
1794 m_editItem = (wxTreeListItem*)NULL;
1795 m_selectItem = (wxTreeListItem*)NULL;
1796
1797 m_curColumn = -1; // no current column
1798
1799 m_hasFocus = false;
1800 m_dirty = false;
1fded56b 1801
28eab81f
RD
1802 m_lineHeight = LINEHEIGHT;
1803 m_indent = MININDENT; // min. indent
1fded56b
RD
1804 m_linespacing = 4;
1805
33328cd8
RD
1806#if !wxCHECK_VERSION(2, 5, 0)
1807 m_hilightBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1808 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1809#else
1810 m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1811 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1812#endif
1813
1814 m_imageListNormal = (wxImageList *) NULL;
1815 m_imageListButtons = (wxImageList *) NULL;
1fded56b
RD
1816 m_imageListState = (wxImageList *) NULL;
1817 m_ownsImageListNormal = m_ownsImageListButtons =
33328cd8
RD
1818 m_ownsImageListState = false;
1819
1820 m_imgWidth = 0, m_imgWidth2 = 0;
1821 m_imgHeight = 0, m_imgHeight2 = 0;
1822 m_btnWidth = 0, m_btnWidth2 = 0;
1823 m_btnHeight = 0, m_btnHeight2 = 0;
1fded56b
RD
1824
1825 m_dragCount = 0;
33328cd8
RD
1826 m_isDragging = false;
1827 m_dragTimer = new wxTimer (this, -1);
1828 m_dragItem = (wxTreeListItem*)NULL;
1fded56b 1829
33328cd8
RD
1830 m_renameTimer = new wxTreeListRenameTimer (this);
1831 m_lastOnSame = false;
1832 m_left_down_selection = false;
1fded56b 1833
28eab81f
RD
1834 m_findTimer = new wxTimer (this, -1);
1835
33328cd8
RD
1836#if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1837 m_normalFont.MacCreateThemeFont (kThemeViewsFont);
8e3ca43b 1838#else
33328cd8 1839 m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
8e3ca43b 1840#endif
1fded56b
RD
1841 m_boldFont = wxFont( m_normalFont.GetPointSize(),
1842 m_normalFont.GetFamily(),
1843 m_normalFont.GetStyle(),
1844 wxBOLD,
8e3ca43b
RD
1845 m_normalFont.GetUnderlined(),
1846 m_normalFont.GetFaceName(),
1847 m_normalFont.GetEncoding());
1fded56b
RD
1848}
1849
33328cd8
RD
1850bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
1851 wxWindowID id,
1852 const wxPoint& pos,
1853 const wxSize& size,
1854 long style,
1855 const wxValidator &validator,
1856 const wxString& name) {
1fded56b 1857
1fded56b 1858#ifdef __WXMAC__
33328cd8
RD
1859 style &= ~wxTR_LINES_AT_ROOT;
1860 style |= wxTR_NO_LINES;
1861
1862 int major,minor;
1863 wxGetOsVersion( &major, &minor );
1864 if (major < 10) style |= wxTR_ROW_LINES;
1fded56b 1865#endif
33328cd8
RD
1866
1867 wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1fded56b 1868
1fded56b 1869#if wxUSE_VALIDATORS
33328cd8
RD
1870 SetValidator(validator);
1871#endif
1872
1873#if !wxCHECK_VERSION(2, 5, 0)
1874 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX));
1875#else
1876 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
1fded56b
RD
1877#endif
1878
28eab81f
RD
1879#ifdef __WXMSW__
1880 {
1881 int i, j;
1882 wxBitmap bmp(8, 8);
1883 wxMemoryDC bdc;
1884 bdc.SelectObject(bmp);
1885 bdc.SetPen(*wxGREY_PEN);
1886 bdc.DrawRectangle(-1, -1, 10, 10);
1887 for (i = 0; i < 8; i++) {
1888 for (j = 0; j < 8; j++) {
1889 if (!((i + j) & 1)) {
1890 bdc.DrawPoint(i, j);
1891 }
1892 }
1893 }
1894
1895 m_dottedPen = wxPen(bmp, 1);
1896 }
1897#else
33328cd8
RD
1898//? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1899 m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
28eab81f 1900#endif
1fded56b 1901
1fded56b
RD
1902 m_owner = parent;
1903 m_main_column = 0;
1904
33328cd8 1905 return true;
1fded56b
RD
1906}
1907
33328cd8 1908wxTreeListMainWindow::~wxTreeListMainWindow() {
1fded56b
RD
1909 delete m_hilightBrush;
1910 delete m_hilightUnfocusedBrush;
1911
33328cd8 1912 delete m_dragTimer;
1fded56b 1913 delete m_renameTimer;
28eab81f 1914 delete m_findTimer;
1fded56b
RD
1915 if (m_ownsImageListNormal) delete m_imageListNormal;
1916 if (m_ownsImageListState) delete m_imageListState;
1917 if (m_ownsImageListButtons) delete m_imageListButtons;
1fded56b 1918
33328cd8
RD
1919 DeleteRoot();
1920}
1fded56b
RD
1921
1922
1923//-----------------------------------------------------------------------------
1924// accessors
1925//-----------------------------------------------------------------------------
1926
33328cd8
RD
1927size_t wxTreeListMainWindow::GetCount() const {
1928 return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
1fded56b
RD
1929}
1930
33328cd8
RD
1931void wxTreeListMainWindow::SetIndent (unsigned int indent) {
1932 m_indent = wxMax ((unsigned)MININDENT, indent);
1933 m_dirty = true;
1fded56b
RD
1934}
1935
33328cd8 1936void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
1fded56b 1937 m_linespacing = spacing;
33328cd8 1938 m_dirty = true;
1fded56b
RD
1939 CalculateLineHeight();
1940}
1941
33328cd8
RD
1942size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
1943 bool recursively) {
1944 wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
1945 return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
1fded56b
RD
1946}
1947
33328cd8 1948void wxTreeListMainWindow::SetWindowStyle (const long styles) {
28eab81f
RD
1949 // right now, just sets the styles. Eventually, we may
1950 // want to update the inherited styles, but right now
1951 // none of the parents has updatable styles
1fded56b 1952 m_windowStyle = styles;
33328cd8 1953 m_dirty = true;
1fded56b
RD
1954}
1955
1956//-----------------------------------------------------------------------------
1957// functions to work with tree items
1958//-----------------------------------------------------------------------------
1959
33328cd8
RD
1960int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column,
1961 wxTreeItemIcon which) const {
1962 wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
1963 return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
1fded56b
RD
1964}
1965
33328cd8
RD
1966wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
1967 wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
1fded56b
RD
1968 return ((wxTreeListItem*) item.m_pItem)->GetData();
1969}
1970
33328cd8
RD
1971bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
1972 wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
1973 return ((wxTreeListItem *)item.m_pItem)->IsBold();
1974}
1975
33328cd8
RD
1976wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
1977 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1fded56b
RD
1978 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1979 return pItem->Attr().GetTextColour();
1980}
1981
33328cd8
RD
1982wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
1983 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1fded56b
RD
1984 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1985 return pItem->Attr().GetBackgroundColour();
1986}
1987
33328cd8
RD
1988wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
1989 wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
1fded56b
RD
1990 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1991 return pItem->Attr().GetFont();
1992}
1993
33328cd8
RD
1994void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column,
1995 int image, wxTreeItemIcon which) {
1996 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 1997 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
1998 pItem->SetImage (column, image, which);
1999 wxClientDC dc (this);
2000 CalculateSize (pItem, dc);
2001 RefreshLine (pItem);
1fded56b
RD
2002}
2003
33328cd8
RD
2004void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,
2005 wxTreeItemData *data) {
2006 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b
RD
2007 ((wxTreeListItem*) item.m_pItem)->SetData(data);
2008}
2009
33328cd8
RD
2010void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item,
2011 bool has) {
2012 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2013 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2014 pItem->SetHasPlus (has);
2015 RefreshLine (pItem);
1fded56b
RD
2016}
2017
33328cd8
RD
2018void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, bool bold) {
2019 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2020 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2021 if (pItem->IsBold() != bold) { // avoid redrawing if no real change
2022 pItem->SetBold (bold);
2023 RefreshLine (pItem);
1fded56b
RD
2024 }
2025}
2026
33328cd8
RD
2027void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,
2028 const wxColour& colour) {
2029 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2030 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2031 pItem->Attr().SetTextColour (colour);
2032 RefreshLine (pItem);
1fded56b
RD
2033}
2034
33328cd8
RD
2035void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,
2036 const wxColour& colour) {
2037 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2038 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2039 pItem->Attr().SetBackgroundColour (colour);
2040 RefreshLine (pItem);
1fded56b
RD
2041}
2042
33328cd8
RD
2043void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,
2044 const wxFont& font) {
2045 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1fded56b 2046 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
33328cd8
RD
2047 pItem->Attr().SetFont (font);
2048 RefreshLine (pItem);
1fded56b
RD
2049}
2050
33328cd8
RD
2051bool wxTreeListMainWindow::SetFont (const wxFont &font) {
2052 wxScrolledWindow::SetFont (font);
2053 m_normalFont = font;
2054 m_boldFont = wxFont (m_normalFont.GetPointSize(),
2055 m_normalFont.GetFamily(),
2056 m_normalFont.GetStyle(),
2057 wxBOLD,
2058 m_normalFont.GetUnderlined(),
2059 m_normalFont.GetFaceName());
2060 CalculateLineHeight();
2061 return true;
1fded56b
RD
2062}
2063
2064
2065// ----------------------------------------------------------------------------
2066// item status inquiries
2067// ----------------------------------------------------------------------------
2068
33328cd8
RD
2069bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow) const {
2070 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2071
2072 // An item is only visible if it's not a descendant of a collapsed item
2073 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
28eab81f 2074 wxTreeListItem* parent = pItem->GetItemParent();
33328cd8
RD
2075 while (parent) {
2076 if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
2077 if (!parent->IsExpanded()) return false;
28eab81f 2078 parent = parent->GetItemParent();
1fded56b
RD
2079 }
2080
1fded56b 2081 wxSize clientSize = GetClientSize();
1fded56b 2082 wxRect rect;
33328cd8
RD
2083 if ((!GetBoundingRect (item, rect)) ||
2084 ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
2085 (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) ||
2086 (!fullRow && (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x))) return false;
1fded56b 2087
33328cd8 2088 return true;
1fded56b
RD
2089}
2090
33328cd8
RD
2091bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
2092 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2093
2094 // consider that the item does have children if it has the "+" button: it
2095 // might not have them (if it had never been expanded yet) but then it
2096 // could have them as well and it's better to err on this side rather than
2097 // disabling some operations which are restricted to the items with
2098 // children for an item which does have them
2099 return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2100}
2101
33328cd8
RD
2102bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2103 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2104 return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2105}
2106
33328cd8
RD
2107bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2108 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2109 return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2110}
2111
33328cd8
RD
2112bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item) const {
2113 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1fded56b
RD
2114 return ((wxTreeListItem*) item.m_pItem)->IsBold();
2115}
2116
2117// ----------------------------------------------------------------------------
2118// navigation
2119// ----------------------------------------------------------------------------
2120
33328cd8
RD
2121wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2122 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
28eab81f 2123 return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
1fded56b
RD
2124}
2125
28eab81f 2126#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
2127wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2128 long& cookie) const {
28eab81f 2129#else
33328cd8
RD
2130wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2131 wxTreeItemIdValue& cookie) const {
28eab81f 2132#endif
33328cd8
RD
2133 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2134 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
1fded56b 2135 cookie = 0;
33328cd8 2136 return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
1fded56b
RD
2137}
2138
28eab81f 2139#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
2140wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2141 long& cookie) const {
28eab81f 2142#else
33328cd8
RD
2143wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2144 wxTreeItemIdValue& cookie) const {
28eab81f 2145#endif
33328cd8 2146 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
28eab81f 2147 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
33328cd8
RD
2148 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2149 long *pIndex = ((long*)&cookie);
2150 return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
28eab81f
RD
2151}
2152
2153#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
2154wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2155 long& cookie) const {
28eab81f 2156#else
33328cd8
RD
2157wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2158 wxTreeItemIdValue& cookie) const {
28eab81f 2159#endif
33328cd8 2160 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
28eab81f 2161 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
33328cd8
RD
2162 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2163 long *pIndex = (long*)&cookie;
2164 return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
1fded56b
RD
2165}
2166
33328cd8
RD
2167#if !wxCHECK_VERSION(2, 5, 0)
2168wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2169 long& cookie) const {
2170#else
2171wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2172 wxTreeItemIdValue& cookie) const {
2173#endif
2174 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
1fded56b 2175 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
33328cd8
RD
2176 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2177 long *pIndex = ((long*)&cookie);
2178 (*pIndex) = children.Count();
2179 return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
1fded56b
RD
2180}
2181
33328cd8
RD
2182wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2183 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
1fded56b 2184
33328cd8 2185 // get parent
1fded56b 2186 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
28eab81f 2187 wxTreeListItem *parent = i->GetItemParent();
33328cd8 2188 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
1fded56b 2189
33328cd8 2190 // get index
1fded56b 2191 wxArrayTreeListItems& siblings = parent->GetChildren();
33328cd8
RD
2192 size_t index = siblings.Index (i);
2193 wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2194 return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
1fded56b
RD
2195}
2196
33328cd8
RD
2197wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2198 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
1fded56b 2199
33328cd8 2200 // get parent
1fded56b 2201 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
28eab81f 2202 wxTreeListItem *parent = i->GetItemParent();
33328cd8 2203 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
1fded56b 2204
33328cd8 2205 // get index
1fded56b 2206 wxArrayTreeListItems& siblings = parent->GetChildren();
33328cd8
RD
2207 size_t index = siblings.Index(i);
2208 wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2209 return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
1fded56b
RD
2210}
2211
2212// Only for internal use right now, but should probably be public
33328cd8
RD
2213wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2214 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
1fded56b 2215
33328cd8
RD
2216 // if there are any children, return first child
2217 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2218 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2219 if (children.GetCount() > 0) return children.Item (0);
1fded56b 2220 }
33328cd8
RD
2221
2222 // get sibling of this item or of the ancestors instead
2223 wxTreeItemId next;
2224 wxTreeItemId parent = item;
2225 do {
2226 next = GetNextSibling (parent);
2227 parent = GetItemParent (parent);
2228 } while (!next.IsOk() && parent.IsOk());
2229 return next;
2230}
2231
2232// Only for internal use right now, but should probably be public
2233wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2234 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2235
2236 // if there are any children, return last child
2237 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2238 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2239 if (children.GetCount() > 0) return children.Item (children.GetCount()-1);
1fded56b 2240 }
33328cd8
RD
2241
2242 // get sibling of this item or of the ancestors instead
2243 wxTreeItemId next;
2244 wxTreeItemId parent = item;
2245 do {
2246 next = GetPrevSibling (parent);
2247 parent = GetItemParent (parent);
2248 } while (!next.IsOk() && parent.IsOk());
2249 return next;
1fded56b
RD
2250}
2251
33328cd8
RD
2252wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2253 return GetNextExpanded (GetRootItem());
2254}
1fded56b 2255
33328cd8
RD
2256wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2257 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2258 return GetNext (item, false);
2259}
1fded56b 2260
33328cd8
RD
2261wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2262 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2263 return GetPrev (item, false);
1fded56b
RD
2264}
2265
33328cd8
RD
2266wxTreeItemId wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow) const {
2267 return GetNextVisible (GetRootItem(), fullRow);
2268}
1fded56b 2269
33328cd8
RD
2270wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow) const {
2271 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2272 wxTreeItemId id = GetNext (item, false);
2273 while (id.IsOk()) {
2274 if (IsVisible (id, fullRow)) return id;
2275 id = GetNext (id, false);
1fded56b
RD
2276 }
2277 return wxTreeItemId();
2278}
2279
33328cd8
RD
2280wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow) const {
2281 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2282 wxTreeItemId id = GetPrev (item, true);
2283 while (id.IsOk()) {
2284 if (IsVisible (id, fullRow)) return id;
2285 id = GetPrev(id, true);
2286 }
1fded56b
RD
2287 return wxTreeItemId();
2288}
2289
2290// ----------------------------------------------------------------------------
2291// operations
2292// ----------------------------------------------------------------------------
2293
33328cd8
RD
2294wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2295 size_t previous,
2296 const wxString& text,
2297 int image, int selImage,
2298 wxTreeItemData *data) {
2299 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2300 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2301 m_dirty = true; // do this first so stuff below doesn't cause flicker
1fded56b 2302
1fded56b 2303 wxArrayString arr;
33328cd8
RD
2304 arr.Alloc (GetColumnCount());
2305 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
1fded56b 2306 arr[m_main_column] = text;
33328cd8
RD
2307 wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2308 if (data != NULL) {
2309#if !wxCHECK_VERSION(2, 5, 0)
2310 data->SetId ((long)item);
2311#else
2312 data->SetId (item);
2313#endif
1fded56b 2314 }
33328cd8 2315 parent->Insert (item, previous);
1fded56b
RD
2316
2317 return item;
2318}
2319
33328cd8
RD
2320wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2321 int image, int selImage,
2322 wxTreeItemData *data) {
2323 wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2324 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2325 m_dirty = true; // do this first so stuff below doesn't cause flicker
1fded56b 2326
1fded56b 2327 wxArrayString arr;
33328cd8
RD
2328 arr.Alloc (GetColumnCount());
2329 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
1fded56b 2330 arr[m_main_column] = text;
33328cd8
RD
2331 m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2332 if (data != NULL) {
2333#if !wxCHECK_VERSION(2, 5, 0)
2334 data->SetId((long)m_rootItem);
2335#else
2336 data->SetId(m_rootItem);
28eab81f 2337#endif
1fded56b 2338 }
33328cd8
RD
2339 if (HasFlag(wxTR_HIDE_ROOT)) {
2340 // if we will hide the root, make sure children are visible
2341 m_rootItem->SetHasPlus();
2342 m_rootItem->Expand();
2343#if !wxCHECK_VERSION(2, 5, 0)
2344 long cookie = 0;
2345#else
2346 wxTreeItemIdValue cookie = 0;
2347#endif
2348 m_curItem = (wxTreeListItem*)GetFirstChild (m_rootItem, cookie).m_pItem;
1fded56b 2349 }
33328cd8 2350 return m_rootItem;
1fded56b
RD
2351}
2352
33328cd8
RD
2353wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2354 const wxString& text,
2355 int image, int selImage,
2356 wxTreeItemData *data) {
2357 return DoInsertItem (parent, 0u, text, image, selImage, data);
1fded56b
RD
2358}
2359
33328cd8
RD
2360wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2361 const wxTreeItemId& idPrevious,
2362 const wxString& text,
2363 int image, int selImage,
2364 wxTreeItemData *data) {
2365 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2366 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
1fded56b
RD
2367
2368 int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2369 wxASSERT_MSG( index != wxNOT_FOUND,
33328cd8 2370 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
1fded56b 2371
33328cd8 2372 return DoInsertItem (parentId, ++index, text, image, selImage, data);
1fded56b
RD
2373}
2374
33328cd8
RD
2375wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2376 size_t before,
2377 const wxString& text,
2378 int image, int selImage,
2379 wxTreeItemData *data) {
2380 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2381 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
1fded56b 2382
33328cd8 2383 return DoInsertItem (parentId, before, text, image, selImage, data);
1fded56b
RD
2384}
2385
33328cd8
RD
2386wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2387 const wxString& text,
2388 int image, int selImage,
2389 wxTreeItemData *data) {
1fded56b 2390 wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
33328cd8 2391 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
1fded56b 2392
33328cd8 2393 return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
1fded56b
RD
2394}
2395
33328cd8
RD
2396void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem *item) {
2397 // send event to user code
2398 wxTreeEvent event (wxEVT_COMMAND_TREE_DELETE_ITEM, m_owner->GetId());
2399#if !wxCHECK_VERSION(2, 5, 0)
2400 event.SetItem ((long)item);
2401#else
2402 event.SetItem (item);
2403#endif
2404 event.SetEventObject (m_owner);
2405 m_owner->ProcessEvent (event);
28eab81f
RD
2406}
2407
33328cd8 2408void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
1fded56b 2409 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
33328cd8
RD
2410 wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2411 m_dirty = true; // do this first so stuff below doesn't cause flicker
2412
2413 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2414 bool changeKeyCurrent = false;
2415 wxTreeListItem *itemKey = m_shiftItem;
2416 while (itemKey) {
2417 if (itemKey == item) { // m_shiftItem is a descendant of the item being deleted
2418 changeKeyCurrent = true;
1fded56b
RD
2419 break;
2420 }
28eab81f 2421 itemKey = itemKey->GetItemParent();
1fded56b
RD
2422 }
2423
28eab81f 2424 wxTreeListItem *parent = item->GetItemParent();
33328cd8
RD
2425 if (parent) {
2426 parent->GetChildren().Remove (item); // remove by value
28eab81f 2427 }
33328cd8 2428 if (changeKeyCurrent) m_shiftItem = parent;
1fded56b 2429
33328cd8
RD
2430 SendDeleteEvent (item);
2431 if (m_selectItem == item) m_selectItem = (wxTreeListItem*)NULL;
2432 item->DeleteChildren (this);
1fded56b
RD
2433 delete item;
2434}
2435
33328cd8
RD
2436void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2437 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2438 m_dirty = true; // do this first so stuff below doesn't cause flicker
1fded56b 2439
33328cd8
RD
2440 item->DeleteChildren (this);
2441}
1fded56b 2442
33328cd8
RD
2443void wxTreeListMainWindow::DeleteRoot() {
2444 if (m_rootItem) {
2445 m_dirty = true;
2446 SendDeleteEvent (m_rootItem);
2447 m_curItem = (wxTreeListItem*)NULL;
2448 m_selectItem= (wxTreeListItem*)NULL;
2449 m_rootItem->DeleteChildren (this);
2450 delete m_rootItem;
2451 m_rootItem = NULL;
1fded56b
RD
2452 }
2453}
2454
33328cd8 2455void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
1fded56b 2456 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
33328cd8 2457 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
1fded56b 2458
33328cd8 2459 if (!item->HasPlus() || item->IsExpanded()) return;
1fded56b 2460
33328cd8
RD
2461 // send event to user code
2462 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_EXPANDING, m_owner->GetId());
2463#if !wxCHECK_VERSION(2, 5, 0)
2464 event.SetItem ((long)item);
2465#else
2466 event.SetItem (item);
2467#endif
2468 event.SetEventObject (m_owner);
2469 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // expand canceled
1fded56b
RD
2470
2471 item->Expand();
33328cd8 2472 m_dirty = true;
1fded56b 2473
33328cd8
RD
2474 // send event to user code
2475 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2476 m_owner->ProcessEvent (event);
1fded56b
RD
2477}
2478
33328cd8
RD
2479void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2480 Expand (itemId);
2481 if (!IsExpanded (itemId)) return;
28eab81f 2482#if !wxCHECK_VERSION(2, 5, 0)
33328cd8 2483 long cookie;
28eab81f 2484#else
33328cd8 2485 wxTreeItemIdValue cookie;
28eab81f 2486#endif
33328cd8
RD
2487 wxTreeItemId child = GetFirstChild (itemId, cookie);
2488 while (child.IsOk()) {
2489 ExpandAll (child);
2490 child = GetNextChild (itemId, cookie);
1fded56b
RD
2491 }
2492}
2493
33328cd8 2494void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
1fded56b 2495 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
33328cd8 2496 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
1fded56b 2497
33328cd8 2498 if (!item->HasPlus() || !item->IsExpanded()) return;
1fded56b 2499
33328cd8
RD
2500 // send event to user code
2501 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, m_owner->GetId() );
2502#if !wxCHECK_VERSION(2, 5, 0)
2503 event.SetItem ((long)item);
2504#else
2505 event.SetItem (item);
1fded56b 2506#endif
33328cd8
RD
2507 event.SetEventObject (m_owner);
2508 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // collapse canceled
1fded56b 2509
33328cd8
RD
2510 item->Collapse();
2511 m_dirty = true;
1fded56b 2512
33328cd8
RD
2513 // send event to user code
2514 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2515 ProcessEvent (event);
1fded56b
RD
2516}
2517
33328cd8
RD
2518void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2519 Collapse (item);
2520 DeleteChildren (item);
1fded56b
RD
2521}
2522
33328cd8
RD
2523void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2524 if (IsExpanded (itemId)) {
2525 Collapse (itemId);
2526 }else{
2527 Expand (itemId);
2528 }
1fded56b
RD
2529}
2530
33328cd8
RD
2531void wxTreeListMainWindow::Unselect() {
2532 if (m_selectItem) {
2533 m_selectItem->SetHilight (false);
2534 RefreshLine (m_selectItem);
2535 m_selectItem = (wxTreeListItem*)NULL;
1fded56b
RD
2536 }
2537}
2538
33328cd8
RD
2539void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2540 if (item->IsSelected()) {
2541 item->SetHilight (false);
2542 RefreshLine (item);
2543 if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
1fded56b 2544 }
33328cd8 2545 if (item->HasChildren()) {
1fded56b
RD
2546 wxArrayTreeListItems& children = item->GetChildren();
2547 size_t count = children.Count();
33328cd8
RD
2548 for (size_t n = 0; n < count; ++n) {
2549 UnselectAllChildren (children[n]);
1fded56b
RD
2550 }
2551 }
2552}
2553
33328cd8
RD
2554void wxTreeListMainWindow::UnselectAll() {
2555 UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
1fded56b
RD
2556}
2557
2558// Recursive function !
2559// To stop we must have crt_item<last_item
2560// Algorithm :
2561// Tag all next children, when no more children,
2562// Move to parent (not to tag)
2563// Keep going... if we found last_item, we stop.
33328cd8
RD
2564bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem *crt_item,
2565 wxTreeListItem *last_item) {
28eab81f 2566 wxTreeListItem *parent = crt_item->GetItemParent();
1fded56b 2567
33328cd8
RD
2568 if (!parent) {// This is root item
2569 return TagAllChildrenUntilLast (crt_item, last_item);
2570 }
1fded56b
RD
2571
2572 wxArrayTreeListItems& children = parent->GetChildren();
2573 int index = children.Index(crt_item);
33328cd8 2574 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
1fded56b 2575
33328cd8
RD
2576 if ((parent->HasChildren() && parent->IsExpanded()) ||
2577 ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2578 size_t count = children.Count();
2579 for (size_t n = (index+1); n < count; ++n) {
2580 if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2581 }
1fded56b
RD
2582 }
2583
33328cd8 2584 return TagNextChildren (parent, last_item);
1fded56b
RD
2585}
2586
33328cd8
RD
2587bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item,
2588 wxTreeListItem *last_item) {
2589 crt_item->SetHilight (true);
1fded56b
RD
2590 RefreshLine(crt_item);
2591
33328cd8 2592 if (crt_item==last_item) return true;
1fded56b 2593
33328cd8 2594 if (crt_item->HasChildren() && crt_item->IsExpanded()) {
1fded56b
RD
2595 wxArrayTreeListItems& children = crt_item->GetChildren();
2596 size_t count = children.Count();
33328cd8
RD
2597 for (size_t n = 0; n < count; ++n) {
2598 if (TagAllChildrenUntilLast (children[n], last_item)) return true;
1fded56b
RD
2599 }
2600 }
2601
33328cd8 2602 return false;
1fded56b
RD
2603}
2604
33328cd8
RD
2605void wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2606 const wxTreeItemId& lastId,
2607 bool unselect_others) {
2608 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item") );
1fded56b 2609
33328cd8
RD
2610 bool is_single = !HasFlag(wxTR_MULTIPLE);
2611 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
1fded56b 2612
33328cd8
RD
2613 // single selection requires unselect others
2614 if (is_single) unselect_others = true;
1fded56b 2615
33328cd8 2616 // send event to the user code
1fded56b 2617 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
33328cd8
RD
2618#if !wxCHECK_VERSION(2, 5, 0)
2619 event.SetItem ((long)item);
2620 event.SetOldItem ((long)m_curItem);
2621#else
2622 event.SetItem (item);
2623 event.SetOldItem (m_curItem);
2624#endif
2625 event.SetEventObject (m_owner);
2626 if (m_owner->GetEventHandler()->ProcessEvent (event) && !event.IsAllowed()) return;
2627
2628 // unselect all if unselect other items
2629 bool unselected = false; // see that UnselectAll is done only once
2630 if (unselect_others) {
2631 if (is_single) {
2632 Unselect(); // to speed up thing
2633 }else{
2634 UnselectAll();
2635 unselected = true;
2636 }
1fded56b
RD
2637 }
2638
33328cd8
RD
2639 // select item or item range
2640 if (lastId.IsOk() && (itemId != lastId)) {
1fded56b 2641
33328cd8
RD
2642 if (!unselected) UnselectAll();
2643 wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
1fded56b 2644
33328cd8
RD
2645 // ensure that the position of the item it calculated in any case
2646 if (m_dirty) CalculatePositions();
2647
2648 // select item range according Y-position
2649 if (last->GetY() < item->GetY()) {
2650 if (!TagAllChildrenUntilLast (last, item)) {
2651 TagNextChildren (last, item);
2652 }
2653 }else{
2654 if (!TagAllChildrenUntilLast (item, last)) {
2655 TagNextChildren (item, last);
2656 }
1fded56b
RD
2657 }
2658
33328cd8 2659 }else{
1fded56b 2660
33328cd8
RD
2661 // select item according its old selection
2662 item->SetHilight (!item->IsSelected());
2663 RefreshLine (item);
2664 if (unselect_others) {
2665 m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL;
2666 }
1fded56b 2667
1fded56b
RD
2668 }
2669
33328cd8 2670 // send event to user code
1fded56b 2671 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
33328cd8 2672 m_owner->GetEventHandler()->ProcessEvent (event);
1fded56b
RD
2673}
2674
33328cd8
RD
2675void wxTreeListMainWindow::SelectAll() {
2676 wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
28eab81f 2677
33328cd8
RD
2678 // send event to user code
2679 wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId());
2680 event.SetItem (GetRootItem());
2681#if !wxCHECK_VERSION(2, 5, 0)
2682 event.SetOldItem ((long)m_curItem);
2683#else
2684 event.SetOldItem (m_curItem);
2685#endif
2686 event.SetEventObject (m_owner);
2687 if (m_owner->GetEventHandler()->ProcessEvent (event) && !event.IsAllowed()) return;
28eab81f 2688
28eab81f
RD
2689#if !wxCHECK_VERSION(2, 5, 0)
2690 long cookie = 0;
2691#else
2692 wxTreeItemIdValue cookie = 0;
2693#endif
2694 wxTreeItemId root = GetRootItem();
2695 wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
33328cd8
RD
2696 wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
2697 if (!TagAllChildrenUntilLast (first, last)) {
2698 TagNextChildren (first, last);
2699 }
28eab81f 2700
33328cd8
RD
2701 // send event to user code
2702 event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED);
2703 m_owner->GetEventHandler()->ProcessEvent (event);
28eab81f
RD
2704}
2705
33328cd8
RD
2706void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
2707 wxArrayTreeItemIds &array) const {
2708 if (item->IsSelected()) array.Add (wxTreeItemId(item));
1fded56b 2709
33328cd8 2710 if (item->HasChildren()) {
1fded56b
RD
2711 wxArrayTreeListItems& children = item->GetChildren();
2712 size_t count = children.GetCount();
33328cd8 2713 for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
1fded56b
RD
2714 }
2715}
2716
33328cd8 2717size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
1fded56b
RD
2718 array.Empty();
2719 wxTreeItemId idRoot = GetRootItem();
33328cd8 2720 if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
1fded56b
RD
2721 return array.Count();
2722}
2723
33328cd8
RD
2724void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
2725 if (!item.IsOk()) return; // do nothing if no item
1fded56b
RD
2726
2727 // first expand all parent branches
33328cd8 2728 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
28eab81f 2729 wxTreeListItem *parent = gitem->GetItemParent();
33328cd8
RD
2730 while (parent) {
2731 Expand (parent);
28eab81f 2732 parent = parent->GetItemParent();
1fded56b
RD
2733 }
2734
33328cd8
RD
2735 ScrollTo (item);
2736 RefreshLine (gitem);
1fded56b
RD
2737}
2738
33328cd8
RD
2739void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
2740 if (!item.IsOk()) return; // do nothing if no item
1fded56b 2741
33328cd8
RD
2742 // ensure that the position of the item it calculated in any case
2743 if (m_dirty) CalculatePositions();
1fded56b
RD
2744
2745 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2746
2747 // now scroll to the item
2748 int item_y = gitem->GetY();
2749
33328cd8
RD
2750 int xUnit, yUnit;
2751 GetScrollPixelsPerUnit (&xUnit, &yUnit);
1fded56b
RD
2752 int start_x = 0;
2753 int start_y = 0;
33328cd8
RD
2754 GetViewStart (&start_x, &start_y);
2755 start_y *= yUnit;
1fded56b
RD
2756
2757 int client_h = 0;
2758 int client_w = 0;
33328cd8 2759 GetClientSize (&client_w, &client_h);
1fded56b 2760
33328cd8
RD
2761 int x = 0;
2762 int y = 0;
2763 m_rootItem->GetSize (x, y, this);
2764 x = m_owner->GetHeaderWindow()->GetWidth();
2765 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2766 int x_pos = GetScrollPos( wxHORIZONTAL );
2767
2768 if (item_y < start_y+3) {
2769 // going down, item should appear at top
2770 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
2771 }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
2772 // going up, item should appear at bottom
2773 item_y += yUnit + 2;
2774 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
1fded56b
RD
2775 }
2776}
2777
2778// FIXME: tree sorting functions are not reentrant and not MT-safe!
2779static wxTreeListMainWindow *s_treeBeingSorted = NULL;
2780
2781static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1,
2782 wxTreeListItem **item2)
2783{
33328cd8 2784 wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
1fded56b
RD
2785
2786 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
2787}
2788
2789int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1,
2790 const wxTreeItemId& item2)
2791{
33328cd8 2792 return m_owner->OnCompareItems (item1, item2);
1fded56b
RD
2793}
2794
33328cd8
RD
2795void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId) {
2796 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
1fded56b
RD
2797
2798 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2799
33328cd8
RD
2800 wxCHECK_RET (!s_treeBeingSorted,
2801 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
1fded56b
RD
2802
2803 wxArrayTreeListItems& children = item->GetChildren();
33328cd8
RD
2804 if ( children.Count() > 1 ) {
2805 m_dirty = true;
1fded56b
RD
2806 s_treeBeingSorted = this;
2807 children.Sort(tree_ctrl_compare_func);
2808 s_treeBeingSorted = NULL;
2809 }
1fded56b
RD
2810}
2811
33328cd8
RD
2812wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, const wxString& str, int mode) {
2813 wxString itemText;
2814 // determine start item
2815 wxTreeItemId next = item;
2816 if (next.IsOk()) {
2817 if (mode & wxTL_MODE_NAV_LEVEL) {
2818 next = GetNextSibling (next);
2819 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2820 next = GetNextVisible (next, false);
2821 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2822 next = GetNextExpanded (next);
2823 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2824 next = GetNext (next, true);
2825 }
2826 }
2827
28eab81f
RD
2828#if !wxCHECK_VERSION(2, 5, 0)
2829 long cookie = 0;
2830#else
2831 wxTreeItemIdValue cookie = 0;
2832#endif
28eab81f 2833 if (!next.IsOk()) {
33328cd8 2834 next = (wxTreeListItem*)GetRootItem().m_pItem;
28eab81f
RD
2835 if (HasFlag(wxTR_HIDE_ROOT)) {
2836 next = (wxTreeListItem*)GetFirstChild (GetRootItem().m_pItem, cookie).m_pItem;
28eab81f
RD
2837 }
2838 }
33328cd8 2839 if (!next.IsOk()) return (wxTreeItemId*)NULL;
28eab81f
RD
2840
2841 // start checking the next items
33328cd8
RD
2842 while (next.IsOk() && (next != item)) {
2843 if (mode & wxTL_MODE_FIND_PARTIAL) {
28eab81f
RD
2844 itemText = GetItemText (next).Mid (0, str.Length());
2845 }else{
2846 itemText = GetItemText (next);
2847 }
33328cd8 2848 if (mode & wxTL_MODE_FIND_NOCASE) {
28eab81f
RD
2849 if (itemText.CmpNoCase (str) == 0) return next;
2850 }else{
2851 if (itemText.Cmp (str) == 0) return next;
2852 }
33328cd8
RD
2853 if (mode & wxTL_MODE_NAV_LEVEL) {
2854 next = GetNextSibling (next);
2855 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2856 next = GetNextVisible (next, false);
2857 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2858 next = GetNextExpanded (next);
2859 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2860 next = GetNext (next, true);
2861 }
2862 if (!next.IsOk() && item.IsOk()) {
2863 next = (wxTreeListItem*)GetRootItem().m_pItem;
2864 if (HasFlag(wxTR_HIDE_ROOT)) {
2865 next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem;
2866 }
2867 }
28eab81f 2868 }
33328cd8 2869 return (wxTreeItemId*)NULL;
1fded56b
RD
2870}
2871
33328cd8
RD
2872void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
2873 wxTreeListItem *prevItem = m_dragItem;
2874 m_dragItem = (wxTreeListItem*) item.m_pItem;
2875 if (prevItem) RefreshLine (prevItem);
2876 if (m_dragItem) RefreshLine (m_dragItem);
1fded56b
RD
2877}
2878
33328cd8
RD
2879void wxTreeListMainWindow::CalculateLineHeight() {
2880 wxClientDC dc (this);
2881 dc.SetFont (m_normalFont);
28eab81f 2882 m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
1fded56b 2883
33328cd8 2884 if (m_imageListNormal) {
1fded56b
RD
2885 // Calculate a m_lineHeight value from the normal Image sizes.
2886 // May be toggle off. Then wxTreeListMainWindow will spread when
2887 // necessary (which might look ugly).
2888 int n = m_imageListNormal->GetImageCount();
33328cd8 2889 for (int i = 0; i < n ; i++) {
1fded56b
RD
2890 int width = 0, height = 0;
2891 m_imageListNormal->GetSize(i, width, height);
28eab81f 2892 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
1fded56b
RD
2893 }
2894 }
2895
33328cd8 2896 if (m_imageListButtons) {
1fded56b
RD
2897 // Calculate a m_lineHeight value from the Button image sizes.
2898 // May be toggle off. Then wxTreeListMainWindow will spread when
2899 // necessary (which might look ugly).
2900 int n = m_imageListButtons->GetImageCount();
33328cd8 2901 for (int i = 0; i < n ; i++) {
1fded56b
RD
2902 int width = 0, height = 0;
2903 m_imageListButtons->GetSize(i, width, height);
28eab81f 2904 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
1fded56b
RD
2905 }
2906 }
2907
33328cd8
RD
2908 if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
2909 m_lineHeight += 2; // minimal 2 pixel space
2910 }else{
2911 m_lineHeight += m_lineHeight / 10; // otherwise 10% space
2912 }
1fded56b
RD
2913}
2914
33328cd8 2915void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
1fded56b
RD
2916 if (m_ownsImageListNormal) delete m_imageListNormal;
2917 m_imageListNormal = imageList;
33328cd8
RD
2918 m_ownsImageListNormal = false;
2919 m_dirty = true;
1fded56b
RD
2920 CalculateLineHeight();
2921}
2922
33328cd8 2923void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
1fded56b
RD
2924 if (m_ownsImageListState) delete m_imageListState;
2925 m_imageListState = imageList;
33328cd8 2926 m_ownsImageListState = false;
1fded56b
RD
2927}
2928
33328cd8 2929void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
1fded56b
RD
2930 if (m_ownsImageListButtons) delete m_imageListButtons;
2931 m_imageListButtons = imageList;
33328cd8
RD
2932 m_ownsImageListButtons = false;
2933 m_dirty = true;
1fded56b
RD
2934 CalculateLineHeight();
2935}
2936
33328cd8 2937void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
1fded56b 2938 SetImageList(imageList);
33328cd8 2939 m_ownsImageListNormal = true;
1fded56b
RD
2940}
2941
33328cd8 2942void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
1fded56b 2943 SetStateImageList(imageList);
33328cd8 2944 m_ownsImageListState = true;
1fded56b
RD
2945}
2946
33328cd8 2947void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
1fded56b 2948 SetButtonsImageList(imageList);
33328cd8 2949 m_ownsImageListButtons = true;
1fded56b
RD
2950}
2951
2952// ----------------------------------------------------------------------------
2953// helpers
2954// ----------------------------------------------------------------------------
2955
33328cd8
RD
2956void wxTreeListMainWindow::AdjustMyScrollbars() {
2957 if (m_rootItem) {
2958 int xUnit, yUnit;
2959 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2960 if (xUnit == 0) xUnit = GetCharWidth();
2961 if (yUnit == 0) yUnit = m_lineHeight;
1fded56b 2962 int x = 0, y = 0;
33328cd8
RD
2963 m_rootItem->GetSize (x, y, this);
2964 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2965 int x_pos = GetScrollPos (wxHORIZONTAL);
2966 int y_pos = GetScrollPos (wxVERTICAL);
1fded56b 2967 x = m_owner->GetHeaderWindow()->GetWidth() + 2;
33328cd8
RD
2968 if (x < GetClientSize().GetWidth()) x_pos = 0;
2969 SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
2970 }else{
2971 SetScrollbars (0, 0, 0, 0);
1fded56b
RD
2972 }
2973}
2974
33328cd8
RD
2975int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
2976 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
1fded56b 2977 return item->GetHeight();
33328cd8 2978 }else{
1fded56b 2979 return m_lineHeight;
33328cd8 2980 }
1fded56b
RD
2981}
2982
33328cd8
RD
2983void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
2984
1fded56b 2985 wxTreeItemAttr *attr = item->GetAttributes();
33328cd8
RD
2986
2987 dc.SetFont (GetItemFont (item));
2988
28eab81f
RD
2989 wxColour colText;
2990 if (attr && attr->HasTextColour()) {
2991 colText = attr->GetTextColour();
2992 }else{
2993 colText = GetForegroundColour();
2994 }
33328cd8
RD
2995#if !wxCHECK_VERSION(2, 5, 0)
2996 wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2997#else
2998 wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2999#endif
28eab81f 3000
33328cd8
RD
3001 int total_w = m_owner->GetHeaderWindow()->GetWidth();
3002 int total_h = GetLineHeight(item);
3003 int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
3004 int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
3005 wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
1fded56b 3006
33328cd8 3007 int text_w = 0, text_h = 0;
1fded56b
RD
3008 dc.GetTextExtent( item->GetText(GetMainColumn()), &text_w, &text_h );
3009
33328cd8
RD
3010 // determine background and show it
3011 wxColour colBg;
3012 if (attr && attr->HasBackgroundColour()) {
3013 colBg = attr->GetBackgroundColour();
3014 }else{
3015 colBg = m_backgroundColour;
3016 }
3017 dc.SetBrush (wxBrush (colBg, wxSOLID));
3018 dc.SetPen (*wxTRANSPARENT_PEN);
3019 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3020 if (item == m_dragItem) {
3021 dc.SetBrush (*m_hilightBrush);
3022#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3023 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3024#endif // !__WXMAC__
3025 dc.SetTextForeground (colTextHilight);
3026 }else if (item->IsSelected()) {
3027 if (!m_isDragging && m_hasFocus) {
3028 dc.SetBrush (*m_hilightBrush);
3029#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3030 dc.SetPen (*wxBLACK_PEN);
3031#endif // !__WXMAC__
3032 }else{
3033 dc.SetBrush (*m_hilightUnfocusedBrush);
3034#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3035 dc.SetPen (*wxTRANSPARENT_PEN);
3036#endif // !__WXMAC__
3037 }
3038 dc.SetTextForeground (colTextHilight);
3039 }else if (item == m_curItem) {
3040 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3041 }else{
3042 dc.SetTextForeground (colText);
28eab81f 3043 }
33328cd8
RD
3044 dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
3045 }else{
3046 dc.SetTextForeground (colText);
1fded56b
RD
3047 }
3048
28eab81f
RD
3049 int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3050 int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3051 int x_colstart = 0;
33328cd8
RD
3052 for (int i = 0; i < GetColumnCount(); ++i ) {
3053 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3054
3055 int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3056 wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3057
3058 int x = 0;
3059 int image = NO_IMAGE;
28eab81f 3060 int image_w = 0;
33328cd8
RD
3061 if(i == GetMainColumn()) {
3062 x = item->GetX() + MARGIN;
3063 if (HasButtons()) {
3064 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
28eab81f 3065 }else{
33328cd8 3066 x -= m_indent/2;
28eab81f 3067 }
33328cd8
RD
3068 if (m_imageListNormal) image = item->GetCurrentImage();
3069 }else{
3070 x = x_colstart + MARGIN;
1fded56b
RD
3071 image = item->GetImage(i);
3072 }
28eab81f 3073 if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
1fded56b
RD
3074
3075 // honor text alignment
3076 wxString text = item->GetText(i);
33328cd8 3077 int w = 0;
28eab81f 3078 switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
33328cd8
RD
3079 case wxALIGN_LEFT:
3080 // nothing to do, already left aligned
1fded56b 3081 break;
33328cd8
RD
3082 case wxALIGN_RIGHT:
3083 dc.GetTextExtent (text, &text_w, NULL);
3084 w = col_w - (image_w + text_w + off_w + MARGIN);
3085 x += (w > 0)? w: 0;
1fded56b 3086 break;
33328cd8 3087 case wxALIGN_CENTER:
1fded56b 3088 dc.GetTextExtent(text, &text_w, NULL);
33328cd8
RD
3089 w = (col_w - (image_w + text_w + off_w + MARGIN))/2;
3090 x += (w > 0)? w: 0;
28eab81f
RD
3091 break;
3092 }
33328cd8
RD
3093 int text_x = x + image_w;
3094 if (i == GetMainColumn()) item->SetTextX (text_x);
3095
3096 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3097 if (i == GetMainColumn()) {
3098 if (item == m_dragItem) {
3099 dc.SetBrush (*m_hilightBrush);
3100#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3101 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3102#endif // !__WXMAC__
3103 dc.SetTextForeground (colTextHilight);
3104 }else if (item->IsSelected()) {
3105 if (!m_isDragging && m_hasFocus) {
3106 dc.SetBrush (*m_hilightBrush);
3107#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3108 dc.SetPen (*wxBLACK_PEN);
3109#endif // !__WXMAC__
3110 }else{
3111 dc.SetBrush (*m_hilightUnfocusedBrush);
3112#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3113 dc.SetPen (*wxTRANSPARENT_PEN);
3114#endif // !__WXMAC__
3115 }
3116 dc.SetTextForeground (colTextHilight);
3117 }else if (item == m_curItem) {
3118 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3119 }else{
3120 dc.SetTextForeground (colText);
3121 }
3122 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3123 }else{
3124 dc.SetTextForeground (colText);
3125 }
3126 }
28eab81f 3127
33328cd8
RD
3128 if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns
3129#if !wxCHECK_VERSION(2, 5, 0)
3130 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3131#else
3132 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3133#endif
3134 dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3135 dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h);
1fded56b
RD
3136 }
3137
33328cd8
RD
3138 dc.SetBackgroundMode (wxTRANSPARENT);
3139
3140 if (image != NO_IMAGE) {
3141 int y = item->GetY() + img_extraH;
3142 m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
1fded56b 3143 }
28eab81f 3144 int text_y = item->GetY() + text_extraH;
33328cd8 3145 dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
1fded56b 3146
33328cd8 3147 x_colstart += col_w;
1fded56b
RD
3148 }
3149
3150 // restore normal font
3151 dc.SetFont( m_normalFont );
3152}
3153
3154// Now y stands for the top of the item, whereas it used to stand for middle !
28eab81f 3155void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
33328cd8
RD
3156 int level, int &y, int x_maincol) {
3157
28eab81f
RD
3158 // Handle hide root (only level 0)
3159 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
1fded56b 3160 wxArrayTreeListItems& children = item->GetChildren();
33328cd8
RD
3161 for (size_t n = 0; n < children.Count(); n++) {
3162 PaintLevel (children[n], dc, 1, y, x_maincol);
1fded56b 3163 }
28eab81f 3164 // end after expanding root
1fded56b
RD
3165 return;
3166 }
3167
28eab81f 3168 // calculate position of vertical lines
33328cd8
RD
3169 int x = x_maincol + MARGIN; // start of column
3170 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
28eab81f 3171 if (HasButtons()) {
33328cd8 3172 x += (m_btnWidth-m_btnWidth2); // half button space
28eab81f 3173 }else{
33328cd8 3174 x += (m_indent-m_indent/2);
28eab81f 3175 }
33328cd8
RD
3176 if (HasFlag(wxTR_HIDE_ROOT)) {
3177 x += m_indent * (level-1); // indent but not level 1
28eab81f 3178 }else{
33328cd8 3179 x += m_indent * level; // indent according to level
28eab81f
RD
3180 }
3181
33328cd8 3182 // set position of vertical line
28eab81f
RD
3183 item->SetX (x);
3184 item->SetY (y);
1fded56b 3185
33328cd8 3186 int h = GetLineHeight (item);
1fded56b 3187 int y_top = y;
28eab81f 3188 int y_mid = y_top + (h/2);
1fded56b
RD
3189 y += h;
3190
3191 int exposed_x = dc.LogicalToDeviceX(0);
3192 int exposed_y = dc.LogicalToDeviceY(y_top);
3193
33328cd8 3194 if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
f84fa75a 3195
33328cd8 3196 if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
28eab81f 3197 //dc.DestroyClippingRegion();
1fded56b
RD
3198 int total_width = m_owner->GetHeaderWindow()->GetWidth();
3199 // if the background colour is white, choose a
3200 // contrasting color for the lines
33328cd8
RD
3201#if !wxCHECK_VERSION(2, 5, 0)
3202 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3203#else
3204 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3205#endif
3206 dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3207 dc.DrawLine (0, y_top, total_width, y_top);
3208 dc.DrawLine (0, y_top+h, total_width, y_top+h);
1fded56b
RD
3209 }
3210
33328cd8
RD
3211 // draw item
3212 PaintItem (item, dc);
3213
1fded56b
RD
3214 // restore DC objects
3215 dc.SetBrush(*wxWHITE_BRUSH);
3216 dc.SetPen(m_dottedPen);
1fded56b 3217
33328cd8
RD
3218 // clip to the column width
3219 int clip_width = m_owner->GetHeaderWindow()->
28eab81f 3220 GetColumn(m_main_column).GetWidth();
33328cd8 3221 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
28eab81f 3222
33328cd8
RD
3223 if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3224
3225 // draw the horizontal line here
3226 dc.SetPen(m_dottedPen);
3227 int x2 = x - m_indent;
3228 if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3229 int x3 = x + (m_btnWidth-m_btnWidth2);
3230 if (HasButtons()) {
3231 if (item->HasPlus()) {
3232 dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3233 dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3234 }else{
3235 dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3236 }
3237 }else{
3238 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
f84fa75a 3239 }
33328cd8
RD
3240 }
3241
3242 if (item->HasPlus() && HasButtons()) { // should the item show a button?
3243
3244 if (m_imageListButtons) {
3245
1fded56b 3246 // draw the image button here
28eab81f 3247 int image = wxTreeItemIcon_Normal;
1fded56b 3248 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
33328cd8
RD
3249 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3250 int xx = x - m_btnWidth2 + MARGIN;
28eab81f
RD
3251 int yy = y_mid - m_btnHeight2;
3252 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
33328cd8 3253 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
1fded56b 3254 dc.DestroyClippingRegion();
28eab81f 3255
33328cd8
RD
3256 }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3257
3258 // draw the twisty button here
3259 dc.SetPen(*wxBLACK_PEN);
3260 dc.SetBrush(*m_hilightBrush);
3261 wxPoint button[3];
3262 if (item->IsExpanded()) {
3263 button[0].x = x - (m_btnWidth2+1);
3264 button[0].y = y_mid - (m_btnHeight/3);
3265 button[1].x = x + (m_btnWidth2+1);
3266 button[1].y = button[0].y;
3267 button[2].x = x;
3268 button[2].y = button[0].y + (m_btnHeight2+1);
28eab81f 3269 }else{
33328cd8
RD
3270 button[0].x = x - (m_btnWidth/3);
3271 button[0].y = y_mid - (m_btnHeight2+1);
3272 button[1].x = button[0].x;
3273 button[1].y = y_mid + (m_btnHeight2+1);
3274 button[2].x = button[0].x + (m_btnWidth2+1);
3275 button[2].y = y_mid;
3276 }
3277 dc.DrawPolygon(3, button);
3278
3279 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3280
3281 // draw the plus sign here
3282#if !wxCHECK_VERSION(2, 7, 0)
3283 dc.SetPen(*wxGREY_PEN);
3284 dc.SetBrush(*wxWHITE_BRUSH);
3285 dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3286 dc.SetPen(*wxBLACK_PEN);
3287 dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
3288 if (!item->IsExpanded()) { // change "-" to "+"
3289 dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
28eab81f 3290 }
33328cd8
RD
3291#else
3292 wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3293 int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0;
3294 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag);
3295#endif
3296
28eab81f 3297 }
33328cd8 3298
1fded56b 3299 }
33328cd8 3300
1fded56b
RD
3301 }
3302
28eab81f
RD
3303 // restore DC objects
3304 dc.SetBrush(*wxWHITE_BRUSH);
3305 dc.SetPen(m_dottedPen);
3306 dc.SetTextForeground(*wxBLACK);
3307
1fded56b
RD
3308 if (item->IsExpanded())
3309 {
3310 wxArrayTreeListItems& children = item->GetChildren();
28eab81f 3311
33328cd8
RD
3312 // clip to the column width
3313 int clip_width = m_owner->GetHeaderWindow()->
3314 GetColumn(m_main_column).GetWidth();
1fded56b 3315
33328cd8
RD
3316 // process lower levels
3317 int oldY;
3318 if (m_imgWidth > 0) {
3319 oldY = y_mid + m_imgHeight2;
3320 }else{
3321 oldY = y_mid + h/2;
1fded56b 3322 }
33328cd8
RD
3323 int y2;
3324 for (size_t n = 0; n < children.Count(); ++n) {
3325
3326 y2 = y + h/2;
3327 PaintLevel (children[n], dc, level+1, y, x_maincol);
3328
3329 // draw vertical line
3330 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3331 if (!HasFlag (wxTR_NO_LINES)) {
3332 x = item->GetX();
3333 dc.DrawLine (x, oldY, x, y2);
3334 oldY = y2;
3335 }
1fded56b 3336 }
1fded56b
RD
3337 }
3338}
3339
1fded56b
RD
3340
3341// ----------------------------------------------------------------------------
3342// wxWindows callbacks
3343// ----------------------------------------------------------------------------
3344
33328cd8 3345void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
1fded56b 3346
33328cd8
RD
3347 wxPaintDC dc (this);
3348 PrepareDC (dc);
1fded56b 3349
33328cd8 3350 if (!m_rootItem || (GetColumnCount() <= 0)) return;
1fded56b 3351
28eab81f 3352 // calculate button size
28eab81f
RD
3353 if (m_imageListButtons) {
3354 m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3355 }else if (HasButtons()) {
3356 m_btnWidth = BTNWIDTH;
3357 m_btnHeight = BTNHEIGHT;
3358 }
3359 m_btnWidth2 = m_btnWidth/2;
3360 m_btnHeight2 = m_btnHeight/2;
3361
3362 // calculate image size
28eab81f
RD
3363 if (m_imageListNormal) {
3364 m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
28eab81f
RD
3365 }
3366 m_imgWidth2 = m_imgWidth/2;
3367 m_imgHeight2 = m_imgHeight/2;
3368
3369 // calculate indent size
33328cd8
RD
3370 if (m_imageListButtons) {
3371 m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3372 }else if (HasButtons()) {
3373 m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3374 }
28eab81f
RD
3375
3376 // set default values
1fded56b
RD
3377 dc.SetFont( m_normalFont );
3378 dc.SetPen( m_dottedPen );
3379
28eab81f 3380 // calculate column start and paint
33328cd8 3381 int x_maincol = 0;
28eab81f
RD
3382 int i = 0;
3383 for (i = 0; i < (int)GetMainColumn(); ++i) {
33328cd8
RD
3384 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3385 x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
1fded56b 3386 }
28eab81f 3387 int y = 0;
33328cd8 3388 PaintLevel (m_rootItem, dc, 0, y, x_maincol);
1fded56b
RD
3389}
3390
33328cd8 3391void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
1fded56b 3392
33328cd8 3393 m_hasFocus = true;
1fded56b 3394 RefreshSelected();
33328cd8 3395 if (m_curItem) RefreshLine (m_curItem);
1fded56b
RD
3396 event.Skip();
3397}
3398
3399void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3400{
33328cd8 3401 m_hasFocus = false;
1fded56b 3402 RefreshSelected();
33328cd8 3403 if (m_curItem) RefreshLine (m_curItem);
1fded56b
RD
3404 event.Skip();
3405}
3406
33328cd8
RD
3407void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3408 // send event to user code
3409 wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, m_owner->GetId());
3410 nevent.SetKeyEvent (event);
3411 nevent.SetEventObject (m_owner);
3412 if (m_owner->GetEventHandler()->ProcessEvent (nevent)) return; // handled in user code
1fded56b 3413
33328cd8
RD
3414 // determine first current if none
3415 bool curItemSet = false;
3416 if (!m_curItem) {
3417 m_curItem = (wxTreeListItem*)GetRootItem().m_pItem;
28eab81f
RD
3418 if (HasFlag(wxTR_HIDE_ROOT)) {
3419#if !wxCHECK_VERSION(2, 5, 0)
3420 long cookie = 0;
3421#else
3422 wxTreeItemIdValue cookie = 0;
3423#endif
33328cd8 3424 m_curItem = (wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem;
28eab81f 3425 }
33328cd8 3426 curItemSet = true;
1fded56b 3427 }
33328cd8 3428 if (!m_curItem) return; // do nothing if empty tree
1fded56b 3429
33328cd8
RD
3430 // remember item at shift down
3431 if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3432 if (!m_shiftItem) m_shiftItem = m_curItem;
3433 }else{
3434 m_shiftItem = (wxTreeListItem*)NULL;
3435 }
1fded56b 3436
33328cd8
RD
3437 // process all cases
3438 wxTreeItemId newItem = (wxTreeItemId*)NULL;
3439 switch (event.GetKeyCode()) {
3440
3441 // '+': Expand subtree
3442 case '+':
3443 case WXK_ADD: {
3444 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3445 }break;
1fded56b 3446
33328cd8 3447 // '-': collapse subtree
1fded56b 3448 case '-':
33328cd8
RD
3449 case WXK_SUBTRACT: {
3450 if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3451 }break;
1fded56b 3452
33328cd8
RD
3453 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3454 case '*':
3455 case WXK_MULTIPLY: {
3456 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3457 ExpandAll (m_curItem);
3458 }else if (m_curItem->HasPlus()) {
3459 Collapse (m_curItem); // TODO: CollapseAll
28eab81f 3460 }
33328cd8 3461 }break;
28eab81f 3462
33328cd8
RD
3463 // ' ': toggle current item
3464 case ' ': {
3465 SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3466 }break;
3467
3468 // <RETURN>: activate current item
3469 case WXK_RETURN: {
3470 wxTreeEvent aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
28eab81f 3471#if !wxCHECK_VERSION(2, 5, 0)
33328cd8 3472 aevent.SetItem ((long)m_curItem);
28eab81f 3473#else
33328cd8 3474 aevent.SetItem (m_curItem);
28eab81f 3475#endif
33328cd8
RD
3476 aevent.SetEventObject (m_owner);
3477 m_owner->GetEventHandler()->ProcessEvent (aevent);
3478 }break;
3479
3480 // <BKSP>: go to the parent without collapsing
3481 case WXK_BACK: {
3482 newItem = GetItemParent (m_curItem);
3483 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3484 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
1fded56b 3485 }
33328cd8 3486 }break;
1fded56b 3487
33328cd8
RD
3488 // <UP>: go to the previous sibling or to the last of its children, to the parent
3489 case WXK_UP: {
3490 newItem = GetPrevSibling (m_curItem);
3491 if (newItem) {
28eab81f 3492#if !wxCHECK_VERSION(2, 5, 0)
33328cd8 3493 long cookie = 0;
28eab81f 3494#else
33328cd8 3495 wxTreeItemIdValue cookie = 0;
28eab81f 3496#endif
33328cd8
RD
3497 while (IsExpanded (newItem) && HasChildren (newItem)) {
3498 newItem = GetLastChild (newItem, cookie);
1fded56b 3499 }
33328cd8
RD
3500 }else {
3501 newItem = GetItemParent (m_curItem);
3502 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3503 newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
28eab81f 3504 }
1fded56b 3505 }
33328cd8 3506 }break;
1fded56b 3507
33328cd8
RD
3508 // <LEFT>: if expanded collapse subtree, else go to the parent
3509 case WXK_LEFT: {
3510 if (IsExpanded (m_curItem)) {
3511 Collapse (m_curItem);
3512 }else{
3513 newItem = GetItemParent (m_curItem);
3514 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3515 newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
1fded56b 3516 }
33328cd8
RD
3517 }
3518 }break;
1fded56b 3519
33328cd8
RD
3520 // <RIGHT>: if possible expand subtree, else go go to the first child
3521 case WXK_RIGHT: {
3522 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3523 Expand (m_curItem);
3524 }else{
3525 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3526#if !wxCHECK_VERSION(2, 5, 0)
3527 long cookie = 0;
3528#else
3529 wxTreeItemIdValue cookie = 0;
3530#endif
3531 newItem = GetFirstChild (m_curItem, cookie);
1fded56b
RD
3532 }
3533 }
33328cd8 3534 }break;
1fded56b 3535
33328cd8
RD
3536 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3537 case WXK_DOWN: {
3538 if (curItemSet) {
3539 newItem = m_curItem;
3540 }else{
3541 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
28eab81f
RD
3542#if !wxCHECK_VERSION(2, 5, 0)
3543 long cookie = 0;
3544#else
3545 wxTreeItemIdValue cookie = 0;
3546#endif
33328cd8
RD
3547 newItem = GetFirstChild( m_curItem, cookie );
3548 }
3549 if (!newItem) {
3550 wxTreeItemId parent = m_curItem;
3551 do {
3552 newItem = GetNextSibling (parent);
3553 parent = GetItemParent (parent);
3554 } while (!newItem && parent);
1fded56b 3555 }
1fded56b 3556 }
33328cd8
RD
3557 }break;
3558
3559 // <END>: go to last item of the root
3560 case WXK_END: {
3561#if !wxCHECK_VERSION(2, 5, 0)
3562 long cookie = 0;
3563#else
3564 wxTreeItemIdValue cookie = 0;
3565#endif
3566 newItem = GetLastChild (GetRootItem(), cookie);
3567 }break;
3568
3569 // <HOME>: go to root
3570 case WXK_HOME: {
3571 newItem = GetRootItem();
3572 if (HasFlag(wxTR_HIDE_ROOT)) {
3573#if !wxCHECK_VERSION(2, 5, 0)
3574 long cookie = 0;
3575#else
3576 wxTreeItemIdValue cookie = 0;
3577#endif
3578 newItem = GetFirstChild (newItem, cookie);
3579 }
3580 }break;
1fded56b 3581
33328cd8 3582 // any char: go to the next matching string
1fded56b 3583 default:
33328cd8 3584 if (event.GetKeyCode() >= (int)' ') {
28eab81f 3585 if (!m_findTimer->IsRunning()) m_findStr.Clear();
33328cd8
RD
3586 m_findStr.Append (event.GetKeyCode());
3587 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3588 wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL;
3589 while (true) {
3590 newItem = FindItem (prev, m_findStr, wxTL_MODE_NAV_EXPANDED |
3591 wxTL_MODE_FIND_PARTIAL |
3592 wxTL_MODE_FIND_NOCASE);
3593 if (newItem || (m_findStr.Length() <= 1)) break;
3594 m_findStr.RemoveLast();
3595 };
28eab81f 3596 }
1fded56b 3597 event.Skip();
33328cd8 3598
1fded56b 3599 }
33328cd8
RD
3600
3601 // select and show the new item
3602 if (newItem) {
3603 if (!event.ControlDown()) {
3604 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3605 HasFlag(wxTR_MULTIPLE));
3606 SelectItem (newItem, m_shiftItem, unselect_others);
3607 }
3608 EnsureVisible (newItem);
3609 wxTreeListItem *oldItem = m_curItem;
3610 m_curItem = (wxTreeListItem*)newItem.m_pItem; // make the new item the current item
3611 RefreshLine (oldItem);
3612 }
3613
1fded56b
RD
3614}
3615
33328cd8 3616wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
1fded56b
RD
3617
3618 int w, h;
3619 GetSize(&w, &h);
3620 flags=0;
04443bbf 3621 column = -1;
1fded56b
RD
3622 if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
3623 if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
3624 if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
3625 if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
3626 if (flags) return wxTreeItemId();
3627
33328cd8 3628 if (!m_rootItem) {
1fded56b 3629 flags = wxTREE_HITTEST_NOWHERE;
33328cd8 3630 column = -1;
1fded56b
RD
3631 return wxTreeItemId();
3632 }
3633
33328cd8
RD
3634 wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
3635 this, flags, column, 0);
3636 if (!hit) {
1fded56b 3637 flags = wxTREE_HITTEST_NOWHERE;
33328cd8 3638 column = -1;
1fded56b
RD
3639 return wxTreeItemId();
3640 }
3641 return hit;
3642}
3643
3644// get the bounding rectangle of the item (or of its label only)
33328cd8
RD
3645bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
3646 bool WXUNUSED(textOnly)) const {
3647 wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
1fded56b 3648
33328cd8 3649 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
1fded56b 3650
33328cd8
RD
3651 int xUnit, yUnit;
3652 GetScrollPixelsPerUnit (&xUnit, &yUnit);
1fded56b
RD
3653 int startX, startY;
3654 GetViewStart(& startX, & startY);
3655
33328cd8
RD
3656 rect.x = item->GetX() - startX * xUnit;
3657 rect.y = item->GetY() - startY * yUnit;
3658 rect.width = item->GetWidth();
3659 rect.height = GetLineHeight (item);
1fded56b 3660
33328cd8 3661 return true;
1fded56b
RD
3662}
3663
3664/* **** */
3665
33328cd8 3666void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
1fded56b 3667 if (!item.IsOk()) return;
33328cd8 3668 if (!((column >= 0) && (column < GetColumnCount()))) return;
1fded56b 3669
33328cd8 3670 m_editItem = (wxTreeListItem*) item.m_pItem;
1fded56b
RD
3671
3672 wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, m_owner->GetId() );
33328cd8
RD
3673#if !wxCHECK_VERSION(2, 5, 0)
3674 te.SetItem ((long)m_editItem);
3675#else
3676 te.SetItem (m_editItem);
3677#endif
3678 te.SetInt (column);
3679 te.SetEventObject (m_owner );
3680 m_owner->GetEventHandler()->ProcessEvent (te);
1fded56b
RD
3681
3682 if (!te.IsAllowed()) return;
3683
33328cd8
RD
3684 // ensure that the position of the item it calculated in any case
3685 if (m_dirty) CalculatePositions();
3686
3687 wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
3688 int x = 0;
3689 int y = m_editItem->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3690 int w = 0;
3691 int h = m_editItem->GetHeight();
3692 long style = 0;
3693 if (column == GetMainColumn()) {
3694 x += m_editItem->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3695 w = wxMin (m_editItem->GetWidth(), m_owner->GetHeaderWindow()->GetWidth() - x);
3696 }else{
3697 for (int i = 0; i < column; ++i) x += header_win->GetColumnWidth (i); // start of column
3698 switch (header_win->GetColumnAlignment (column)) {
3699 case wxALIGN_LEFT: {style = wxTE_LEFT; break;}
3700 case wxALIGN_RIGHT: {style = wxTE_RIGHT; break;}
3701 case wxALIGN_CENTER: {style = wxTE_CENTER; break;}
3702 }
3703 w = header_win->GetColumnWidth (column); // width of column
3704 }
3705
3706 wxClientDC dc (this);
3707 PrepareDC (dc);
3708 x = dc.LogicalToDeviceX (x);
3709 y = dc.LogicalToDeviceY (y);
3710
3711 wxEditTextCtrl *text = new wxEditTextCtrl (this, -1, &m_renameAccept, &m_renameRes,
3712 this, m_editItem->GetText (column),
3713 wxPoint (x, y), wxSize (w, h), style);
1fded56b
RD
3714 text->SetFocus();
3715}
3716
33328cd8
RD
3717void wxTreeListMainWindow::OnRenameTimer() {
3718 EditLabel (m_curItem, m_curColumn);
1fded56b
RD
3719}
3720
33328cd8
RD
3721void wxTreeListMainWindow::OnRenameAccept() {
3722
1fded56b
RD
3723 // TODO if the validator fails this causes a crash
3724 wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, m_owner->GetId() );
33328cd8
RD
3725#if !wxCHECK_VERSION(2, 5, 0)
3726 le.SetItem((long)m_editItem);
3727#else
3728 le.SetItem(m_editItem);
3729#endif
1fded56b
RD
3730 le.SetEventObject( /*this*/m_owner );
3731 le.SetLabel( m_renameRes );
3732 m_owner->GetEventHandler()->ProcessEvent( le );
3733
3734 if (!le.IsAllowed()) return;
3735
33328cd8 3736 SetItemText (m_editItem, m_curColumn, m_renameRes);
1fded56b
RD
3737}
3738
33328cd8
RD
3739void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
3740 if (!m_rootItem) return;
4f73709d 3741
1fded56b
RD
3742 // we process left mouse up event (enables in-place edit), right down
3743 // (pass to the user code), left dbl click (activate item) and
3744 // dragging/moving events for items drag-and-drop
33328cd8
RD
3745 if (!(event.LeftDown() ||
3746 event.LeftUp() ||
3747 event.RightDown() ||
3748 event.RightUp() ||
3749 event.LeftDClick() ||
3750 event.Dragging() ||
3751 (event.GetWheelRotation() != 0 )/*? TODO ||
3752 event.Moving()?*/)) {
3753 m_owner->GetEventHandler()->ProcessEvent (event);
1fded56b
RD
3754 return;
3755 }
3756
33328cd8
RD
3757 // set focus if window clicked
3758 if (event.LeftDown() || event.RightDown()) SetFocus();
1fded56b 3759
33328cd8
RD
3760 // determine event
3761 wxPoint p = wxPoint (event.GetX(), event.GetY());
3762 int flags = 0;
3763 wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
3764 this, flags, m_curColumn, 0);
1fded56b 3765
33328cd8
RD
3766 // we only process dragging here
3767 if (event.Dragging()){
3768 if (m_isDragging) return; // nothing to do, already done
3769 if (item == NULL) return; // we need an item to dragging
1fded56b 3770
33328cd8
RD
3771 // determine drag start
3772 if (m_dragCount == 0) {
3773 m_dragTimer->Start (DRAG_TIMER_TICKS, wxTIMER_ONE_SHOT);
1fded56b 3774 }
33328cd8
RD
3775 m_dragCount++;
3776 if (m_dragCount < 3) return; // minimum drag 3 pixel
3777 if (m_dragTimer->IsRunning()) return;
1fded56b 3778
33328cd8
RD
3779 // we're going to drag
3780 m_dragCount = 0;
3781 m_isDragging = true;
3782 CaptureMouse();
3783 RefreshSelected();
3784
3785 // send drag start event
3786 wxEventType command = event.LeftIsDown()
3787 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3788 : wxEVT_COMMAND_TREE_BEGIN_RDRAG;
3789 wxTreeEvent nevent (command, m_owner->GetId());
3790 nevent.SetEventObject (m_owner);
3791#if !wxCHECK_VERSION(2, 5, 0)
3792 nevent.SetItem ((long)item); // the item the drag is ended
3793#else
3794 nevent.SetItem (item); // the item the drag is ended
3795#endif
3796 nevent.Veto(); // dragging must be explicit allowed!
3797 m_owner->GetEventHandler()->ProcessEvent (nevent);
1fded56b 3798
33328cd8 3799 }else if (m_isDragging) { // any other event but not event.Dragging()
1fded56b 3800
33328cd8
RD
3801 // end dragging
3802 m_dragCount = 0;
3803 m_isDragging = false;
3804 if (HasCapture()) ReleaseMouse();
3805 RefreshSelected();
1fded56b 3806
33328cd8
RD
3807 // send drag end event event
3808 wxTreeEvent nevent (wxEVT_COMMAND_TREE_END_DRAG, m_owner->GetId());
3809 nevent.SetEventObject (m_owner);
3810#if !wxCHECK_VERSION(2, 5, 0)
3811 nevent.SetItem ((long)item); // the item the drag is started
3812#else
3813 nevent.SetItem (item); // the item the drag is started
3814#endif
3815 nevent.SetPoint (p);
3816 m_owner->GetEventHandler()->ProcessEvent (nevent);
1fded56b 3817
33328cd8 3818 }else if (m_dragCount > 0) { // just in case dragging is initiated
1fded56b 3819
33328cd8
RD
3820 // end dragging
3821 m_dragCount = 0;
1fded56b 3822
33328cd8 3823 }
1fded56b 3824
33328cd8
RD
3825 // we process only the messages which happen on tree items
3826 if (item == NULL) {
3827 m_owner->GetEventHandler()->ProcessEvent (event);
3828 return;
1fded56b 3829 }
1fded56b 3830
33328cd8
RD
3831 // remember item at shift down
3832 if (event.ShiftDown()) {
3833 if (!m_shiftItem) m_shiftItem = m_curItem;
3834 }else{
3835 m_shiftItem = (wxTreeListItem*)NULL;
3836 }
1fded56b 3837
33328cd8 3838 if (event.RightUp()) {
1fded56b 3839
33328cd8
RD
3840 SetFocus();
3841 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, m_owner->GetId());
3842 nevent.SetEventObject (m_owner);
3843#if !wxCHECK_VERSION(2, 5, 0)
3844 nevent.SetItem ((long)item); // the item clicked
3845#else
3846 nevent.SetItem (item); // the item clicked
3847#endif
3848 nevent.SetInt (m_curColumn); // the colum clicked
3849 nevent.SetPoint (p);
3850 m_owner->GetEventHandler()->ProcessEvent (nevent);
1fded56b 3851
33328cd8 3852 }else if (event.LeftUp()) {
1fded56b 3853
33328cd8
RD
3854 if (m_lastOnSame) {
3855 if ((item == m_curItem) && (m_curColumn != -1) &&
3856 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
3857 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))){
3858 m_renameTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
3859 }
3860 m_lastOnSame = false;
3861 }
1fded56b 3862
33328cd8
RD
3863 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3864 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3865 HasButtons() && item->HasPlus()) {
1fded56b 3866
33328cd8
RD
3867 // only toggle the item for a single click, double click on
3868 // the button doesn't do anything (it toggles the item twice)
3869 if (event.LeftDown()) Toggle (item);
1fded56b 3870
33328cd8
RD
3871 // don't select the item if the button was clicked
3872 return;
3873 }
1fded56b 3874
33328cd8
RD
3875 // determine the selection if not done by left down
3876 if (!m_left_down_selection) {
3877 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3878 HasFlag(wxTR_MULTIPLE));
3879 SelectItem (item, m_shiftItem, unselect_others);
3880 EnsureVisible (item);
3881 m_curItem = item; // make the new item the current item
3882 }else{
3883 m_left_down_selection = false;
3884 }
1fded56b 3885
33328cd8 3886 }else if (event.LeftDown() || event.RightDown() || event.LeftDClick()) {
1fded56b 3887
33328cd8 3888 if (event.LeftDown() || event.RightDown()) {
1fded56b 3889 SetFocus();
33328cd8 3890 m_lastOnSame = item == m_curItem;
1fded56b 3891 }
1fded56b 3892
33328cd8
RD
3893 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3894 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3895 item->HasPlus()) {
3896
3897 // only toggle the item for a single click, double click on
3898 // the button doesn't do anything (it toggles the item twice)
3899 if (event.LeftDown()) Toggle (item);
3900
3901 // don't select the item if the button was clicked
3902 return;
1fded56b 3903 }
1fded56b 3904
33328cd8
RD
3905 // determine the selection if the current item is not selected
3906 if (!item->IsSelected()) {
3907 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3908 HasFlag(wxTR_MULTIPLE));
3909 SelectItem (item, m_shiftItem, unselect_others);
3910 EnsureVisible (item);
3911 m_curItem = item; // make the new item the current item
3912 m_left_down_selection = true;
3913 }
1fded56b 3914
33328cd8
RD
3915 // For some reason, Windows isn't recognizing a left double-click,
3916 // so we need to simulate it here. Allow 200 milliseconds for now.
3917 if (event.LeftDClick()) {
1fded56b 3918
33328cd8
RD
3919 // double clicking should not start editing the item label
3920 m_renameTimer->Stop();
3921 m_lastOnSame = false;
3922
3923 // send activate event first
3924 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3925 nevent.SetEventObject (m_owner);
3926#if !wxCHECK_VERSION(2, 5, 0)
3927 nevent.SetItem ((long)item); // the item clicked
3928#else
3929 nevent.SetItem (item); // the item clicked
3930#endif
3931 nevent.SetInt (m_curColumn); // the colum clicked
3932 nevent.SetPoint (p);
3933 if (!m_owner->GetEventHandler()->ProcessEvent (nevent)) {
3934
3935 // if the user code didn't process the activate event,
3936 // handle it ourselves by toggling the item when it is
3937 // double clicked
3938 if (item->HasPlus()) Toggle(item);
1fded56b
RD
3939 }
3940 }
1fded56b 3941
33328cd8
RD
3942 }else{ // any other event skip just in case
3943
3944 event.Skip();
3945
3946 }
01fdd955
RD
3947}
3948
33328cd8 3949void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
1fded56b
RD
3950 /* after all changes have been done to the tree control,
3951 * we actually redraw the tree when everything is over */
3952
3953 if (!m_dirty) return;
3954
33328cd8 3955 m_dirty = false;
1fded56b
RD
3956
3957 CalculatePositions();
3958 Refresh();
3959 AdjustMyScrollbars();
3960}
3961
33328cd8 3962void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
1fded56b
RD
3963 // FIXME
3964#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
3965 wxScrolledWindow::OnScroll(event);
3966#else
3967 HandleOnScroll( event );
3968#endif
3969
33328cd8 3970 if(event.GetOrientation() == wxHORIZONTAL) {
1fded56b 3971 m_owner->GetHeaderWindow()->Refresh();
425de63d 3972 m_owner->GetHeaderWindow()->Update();
1fded56b
RD
3973 }
3974}
3975
33328cd8 3976void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
1fded56b
RD
3977 wxCoord text_w = 0;
3978 wxCoord text_h = 0;
3979
33328cd8 3980 dc.SetFont (GetItemFont (item));
1fded56b 3981
33328cd8 3982 dc.GetTextExtent (item->GetText (m_main_column), &text_w, &text_h);
1fded56b
RD
3983
3984 // restore normal font
33328cd8 3985 dc.SetFont (m_normalFont);
1fded56b 3986
28eab81f 3987 int total_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
33328cd8
RD
3988 if (total_h < 30) { // add 10% space if greater than 30 pixels
3989 total_h += 2; // minimal 2 pixel space
3990 }else{
3991 total_h += total_h / 10; // otherwise 10% space
3992 }
1fded56b 3993
33328cd8
RD
3994 item->SetHeight (total_h);
3995 if (total_h > m_lineHeight) m_lineHeight = total_h;
28eab81f 3996 item->SetWidth(m_imgWidth + text_w+2);
1fded56b
RD
3997}
3998
3999// -----------------------------------------------------------------------------
33328cd8
RD
4000void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
4001 int level, int &y, int x_colstart) {
4002
28eab81f
RD
4003 // calculate position of vertical lines
4004 int x = x_colstart + MARGIN; // start of column
4005 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
33328cd8
RD
4006 if (HasButtons()) {
4007 x += (m_btnWidth-m_btnWidth2); // half button space
4008 }else{
4009 x += (m_indent-m_indent/2);
4010 }
4011 if (HasFlag(wxTR_HIDE_ROOT)) {
4012 x += m_indent * (level-1); // indent but not level 1
4013 }else{
4014 x += m_indent * level; // indent according to level
4015 }
28eab81f
RD
4016
4017 // a hidden root is not evaluated, but its children are always
4018 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
1fded56b
RD
4019
4020 CalculateSize( item, dc );
4021
4022 // set its position
28eab81f
RD
4023 item->SetX (x);
4024 item->SetY (y);
1fded56b
RD
4025 y += GetLineHeight(item);
4026
28eab81f
RD
4027 // we don't need to calculate collapsed branches
4028 if ( !item->IsExpanded() ) return;
1fded56b 4029
28eab81f 4030Recurse:
1fded56b 4031 wxArrayTreeListItems& children = item->GetChildren();
33328cd8 4032 long n, count = (long)children.Count();
1fded56b 4033 ++level;
33328cd8 4034 for (n = 0; n < count; ++n) {
28eab81f 4035 CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse
33328cd8 4036 }
1fded56b
RD
4037}
4038
33328cd8
RD
4039void wxTreeListMainWindow::CalculatePositions() {
4040 if ( !m_rootItem ) return;
1fded56b
RD
4041
4042 wxClientDC dc(this);
4043 PrepareDC( dc );
4044
4045 dc.SetFont( m_normalFont );
4046
4047 dc.SetPen( m_dottedPen );
4048 //if(GetImageList() == NULL)
4049 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4050
4051 int y = 2;
28eab81f 4052 int x_colstart = 0;
33328cd8
RD
4053 for (int i = 0; i < (int)GetMainColumn(); ++i) {
4054 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
28eab81f 4055 x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
1fded56b 4056 }
33328cd8 4057 CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
1fded56b
RD
4058}
4059
33328cd8 4060void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
1fded56b
RD
4061 if (m_dirty) return;
4062
4063 wxClientDC dc(this);
4064 PrepareDC(dc);
4065
4066 int cw = 0;
4067 int ch = 0;
33328cd8 4068 GetVirtualSize( &cw, &ch );
1fded56b
RD
4069
4070 wxRect rect;
4071 rect.x = dc.LogicalToDeviceX( 0 );
4072 rect.width = cw;
4073 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4074 rect.height = ch;
4075
33328cd8 4076 Refresh (true, &rect );
1fded56b
RD
4077 AdjustMyScrollbars();
4078}
4079
33328cd8 4080void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
1fded56b
RD
4081 if (m_dirty) return;
4082
4083 wxClientDC dc(this);
4084 PrepareDC( dc );
4085
4086 int cw = 0;
4087 int ch = 0;
33328cd8 4088 GetVirtualSize( &cw, &ch );
1fded56b
RD
4089
4090 wxRect rect;
4091 rect.x = dc.LogicalToDeviceX( 0 );
4092 rect.y = dc.LogicalToDeviceY( item->GetY() );
4093 rect.width = cw;
4094 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4095
33328cd8 4096 Refresh (true, &rect);
1fded56b
RD
4097}
4098
33328cd8 4099void wxTreeListMainWindow::RefreshSelected() {
1fded56b
RD
4100 // TODO: this is awfully inefficient, we should keep the list of all
4101 // selected items internally, should be much faster
33328cd8
RD
4102 if (m_rootItem) {
4103 RefreshSelectedUnder (m_rootItem);
4104 }
1fded56b
RD
4105}
4106
33328cd8
RD
4107void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4108 if (item->IsSelected()) {
4109 RefreshLine (item);
4110 }
1fded56b
RD
4111
4112 const wxArrayTreeListItems& children = item->GetChildren();
33328cd8
RD
4113 long count = children.GetCount();
4114 for (long n = 0; n < count; n++ ) {
4115 RefreshSelectedUnder (children[n]);
1fded56b
RD
4116 }
4117}
4118
4119// ----------------------------------------------------------------------------
4120// changing colours: we need to refresh the tree control
4121// ----------------------------------------------------------------------------
4122
33328cd8
RD
4123bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4124 if (!wxWindow::SetBackgroundColour(colour)) return false;
1fded56b
RD
4125
4126 Refresh();
33328cd8 4127 return true;
1fded56b
RD
4128}
4129
33328cd8
RD
4130bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4131 if (!wxWindow::SetForegroundColour(colour)) return false;
1fded56b
RD
4132
4133 Refresh();
33328cd8 4134 return true;
1fded56b
RD
4135}
4136
33328cd8
RD
4137void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column,
4138 const wxString& text) {
4139 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
1fded56b 4140
33328cd8
RD
4141 wxClientDC dc (this);
4142 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4143 item->SetText (column, text);
4144 CalculateSize (item, dc);
4145 RefreshLine (item);
1fded56b
RD
4146}
4147
33328cd8
RD
4148wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId,
4149 int column) const {
4150 wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
1fded56b 4151
33328cd8
RD
4152 if( IsVirtual() ) return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4153 else return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
1fded56b
RD
4154}
4155
33328cd8
RD
4156wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item,
4157int column) const {
4158 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4159 return m_owner->OnGetItemText(item,column);
4160}
4161
4162void wxTreeListMainWindow::SetFocus() {
28eab81f
RD
4163 wxWindow::SetFocus();
4164}
4165
33328cd8
RD
4166wxFont wxTreeListMainWindow::GetItemFont (wxTreeListItem *item) {
4167 wxTreeItemAttr *attr = item->GetAttributes();
4168
4169 if (attr && attr->HasFont()) {
4170 return attr->GetFont();
4171 }else if (item->IsBold()) {
4172 return m_boldFont;
4173 }else{
4174 return m_normalFont;
4175 }
4176}
4177
4178int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4179 if (!item) return 0;
4180
4181 // determine item width
4182 int w = 0, h = 0;
4183 wxFont font = GetItemFont (item);
4184 GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4185 w += 2*MARGIN;
4186
4187 // calculate width
4188 int width = w + 2*MARGIN;
4189 if (column == GetMainColumn()) {
4190 width += MARGIN;
4191 if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4192 if (HasButtons()) width += m_btnWidth + LINEATROOT;
4193 if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4194
4195 // count indent level
4196 int level = 0;
4197 wxTreeListItem *parent = item->GetItemParent();
4198 wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4199 while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4200 level++;
4201 parent = parent->GetItemParent();
4202 }
4203 if (level) width += level * GetIndent();
4204 }
4205
4206 return width;
4207}
4208
4209int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4210 int maxWidth, h;
4211 GetClientSize (&maxWidth, &h);
4212 int width = 0;
4213
4214 // get root if on item
4215 if (!parent.IsOk()) parent = GetRootItem();
4216
4217 // add root width
4218 if (!HasFlag(wxTR_HIDE_ROOT)) {
4219 int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4220 if (width < w) width = w;
4221 if (width > maxWidth) return maxWidth;
4222 }
4223
4224 wxTreeItemIdValue cookie = 0;
4225 wxTreeItemId item = GetFirstChild (parent, cookie);
4226 while (item.IsOk()) {
4227 int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4228 if (width < w) width = w;
4229 if (width > maxWidth) return maxWidth;
4230
4231 // check the children of this item
4232 if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4233 int w = GetBestColumnWidth (column, item);
4234 if (width < w) width = w;
4235 if (width > maxWidth) return maxWidth;
4236 }
4237
4238 // next sibling
4239 item = GetNextChild (parent, cookie);
4240 }
4241
4242 return width;
4243}
4244
1fded56b
RD
4245
4246//-----------------------------------------------------------------------------
4247// wxTreeListCtrl
4248//-----------------------------------------------------------------------------
4249
33328cd8 4250IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
1fded56b
RD
4251
4252BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4253 EVT_SIZE(wxTreeListCtrl::OnSize)
4254END_EVENT_TABLE();
4255
4256bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4257 const wxPoint& pos,
4258 const wxSize& size,
4259 long style, const wxValidator &validator,
4260 const wxString& name)
4261{
33328cd8
RD
4262 long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER|
4263 wxRAISED_BORDER|wxSTATIC_BORDER);
28eab81f 4264 long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
1fded56b 4265
28eab81f
RD
4266 if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4267 return false;
4268 }
33328cd8
RD
4269 m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4270 main_style, validator);
4271 m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4272 wxPoint(0, 0), wxDefaultSize,
4273 wxTAB_TRAVERSAL);
8e3ca43b 4274 CalculateAndSetHeaderHeight();
33328cd8 4275 return true;
1fded56b
RD
4276}
4277
8e3ca43b
RD
4278void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4279{
33328cd8 4280 if (m_header_win) {
5c86a7fa
RD
4281 int h;
4282#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
4283 h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
4284#else
8e3ca43b 4285 // we use 'g' to get the descent, too
5c86a7fa 4286 int w, d;
33328cd8 4287 m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
8e3ca43b 4288 h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
5c86a7fa 4289#endif
8e3ca43b 4290 // only update if changed
33328cd8
RD
4291 if (h != m_headerHeight) {
4292 m_headerHeight = h;
4293 DoHeaderLayout();
8e3ca43b
RD
4294 }
4295 }
4296}
4297
136518e5 4298void wxTreeListCtrl::DoHeaderLayout()
1fded56b
RD
4299{
4300 int w, h;
4301 GetClientSize(&w, &h);
33328cd8
RD
4302 if (m_header_win) {
4303 m_header_win->SetSize (0, 0, w, m_headerHeight);
4304 m_header_win->Refresh();
4305 }
4306 if (m_main_win) {
4307 m_main_win->SetSize (0, m_headerHeight + 1, w, h - m_headerHeight - 1);
e778b8f0 4308 }
33328cd8 4309}
136518e5
RD
4310
4311void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4312{
4313 DoHeaderLayout();
1fded56b
RD
4314}
4315
4316size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4317
4318unsigned int wxTreeListCtrl::GetIndent() const
4319{ return m_main_win->GetIndent(); }
4320
4321void wxTreeListCtrl::SetIndent(unsigned int indent)
4322{ m_main_win->SetIndent(indent); }
4323
1fded56b
RD
4324unsigned int wxTreeListCtrl::GetLineSpacing() const
4325{ return m_main_win->GetLineSpacing(); }
4326
4327void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4328{ m_main_win->SetLineSpacing(spacing); }
4329
4330wxImageList* wxTreeListCtrl::GetImageList() const
4331{ return m_main_win->GetImageList(); }
4332
4333wxImageList* wxTreeListCtrl::GetStateImageList() const
4334{ return m_main_win->GetStateImageList(); }
4335
4336wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4337{ return m_main_win->GetButtonsImageList(); }
4338
4339void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4340{ m_main_win->SetImageList(imageList); }
4341
4342void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4343{ m_main_win->SetStateImageList(imageList); }
4344
4345void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4346{ m_main_win->SetButtonsImageList(imageList); }
4347
4348void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4349{ m_main_win->AssignImageList(imageList); }
4350
4351void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4352{ m_main_win->AssignStateImageList(imageList); }
4353
4354void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4355{ m_main_win->AssignButtonsImageList(imageList); }
4356
33328cd8
RD
4357wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4358{ return m_main_win->GetItemText (item, column); }
1fded56b 4359
33328cd8 4360int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column,
1fded56b
RD
4361 wxTreeItemIcon which) const
4362{ return m_main_win->GetItemImage(item, column, which); }
4363
4364wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4365{ return m_main_win->GetItemData(item); }
4366
4367bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4368{ return m_main_win->GetItemBold(item); }
4369
4370wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4371{ return m_main_win->GetItemTextColour(item); }
4372
4373wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item)
4374 const
4375{ return m_main_win->GetItemBackgroundColour(item); }
4376
4377wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4378{ return m_main_win->GetItemFont(item); }
4379
4380
33328cd8 4381void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column,
1fded56b 4382 const wxString& text)
33328cd8 4383{ m_main_win->SetItemText (item, column, text); }
1fded56b
RD
4384
4385void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item,
33328cd8 4386 int column,
1fded56b
RD
4387 int image,
4388 wxTreeItemIcon which)
4389{ m_main_win->SetItemImage(item, column, image, which); }
4390
4391void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,
4392 wxTreeItemData* data)
4393{ m_main_win->SetItemData(item, data); }
4394
4395void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4396{ m_main_win->SetItemHasChildren(item, has); }
4397
4398void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
4399{ m_main_win->SetItemBold(item, bold); }
4400
4401void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,
33328cd8
RD
4402 const wxColour& colour)
4403{ m_main_win->SetItemTextColour(item, colour); }
1fded56b
RD
4404
4405void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
33328cd8
RD
4406 const wxColour& colour)
4407{ m_main_win->SetItemBackgroundColour(item, colour); }
1fded56b
RD
4408
4409void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,
4410 const wxFont& font)
4411{ m_main_win->SetItemFont(item, font); }
4412
4413bool wxTreeListCtrl::SetFont(const wxFont& font)
4414{
33328cd8 4415 if (m_header_win) {
8e3ca43b
RD
4416 m_header_win->SetFont(font);
4417 CalculateAndSetHeaderHeight();
33328cd8 4418 m_header_win->Refresh();
8e3ca43b 4419 }
33328cd8 4420 if (m_main_win) {
1fded56b 4421 return m_main_win->SetFont(font);
33328cd8
RD
4422 }else{
4423 return false;
4424 }
1fded56b
RD
4425}
4426
4427void wxTreeListCtrl::SetWindowStyle(const long style)
4428{
4429 if(m_main_win)
4430 m_main_win->SetWindowStyle(style);
33328cd8 4431 m_windowStyle = style;
1fded56b
RD
4432 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4433}
4434
4435long wxTreeListCtrl::GetWindowStyle() const
4436{
4437 long style = m_windowStyle;
4438 if(m_main_win)
4439 style |= m_main_win->GetWindowStyle();
4440 return style;
4441}
4442
33328cd8
RD
4443bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow) const
4444{ return m_main_win->IsVisible(item, fullRow); }
1fded56b 4445
33328cd8
RD
4446bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4447{ return m_main_win->HasChildren(item); }
1fded56b
RD
4448
4449bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4450{ return m_main_win->IsExpanded(item); }
4451
4452bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4453{ return m_main_win->IsSelected(item); }
4454
4455bool wxTreeListCtrl::IsBold(const wxTreeItemId& item) const
4456{ return m_main_win->IsBold(item); }
4457
4458size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4459{ return m_main_win->GetChildrenCount(item, rec); }
4460
4461wxTreeItemId wxTreeListCtrl::GetRootItem() const
4462{ return m_main_win->GetRootItem(); }
4463
4464wxTreeItemId wxTreeListCtrl::GetSelection() const
4465{ return m_main_win->GetSelection(); }
4466
4467size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4468{ return m_main_win->GetSelections(arr); }
4469
28eab81f
RD
4470wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4471{ return m_main_win->GetItemParent(item); }
1fded56b 4472
28eab81f 4473#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
4474wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4475 long& cookie) const
28eab81f 4476#else
33328cd8
RD
4477wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4478 wxTreeItemIdValue& cookie) const
28eab81f 4479#endif
1fded56b
RD
4480{ return m_main_win->GetFirstChild(item, cookie); }
4481
28eab81f 4482#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
4483wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4484 long& cookie) const
28eab81f 4485#else
33328cd8
RD
4486wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4487 wxTreeItemIdValue& cookie) const
28eab81f 4488#endif
1fded56b
RD
4489{ return m_main_win->GetNextChild(item, cookie); }
4490
28eab81f 4491#if !wxCHECK_VERSION(2, 5, 0)
33328cd8
RD
4492wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4493 long& cookie) const
28eab81f 4494#else
33328cd8
RD
4495wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4496 wxTreeItemIdValue& cookie) const
28eab81f
RD
4497#endif
4498{ return m_main_win->GetPrevChild(item, cookie); }
4499
33328cd8
RD
4500#if !wxCHECK_VERSION(2, 5, 0)
4501wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4502 long& cookie) const
4503#else
4504wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4505 wxTreeItemIdValue& cookie) const
4506#endif
4507{ return m_main_win->GetLastChild(item, cookie); }
4508
1fded56b
RD
4509
4510wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
4511{ return m_main_win->GetNextSibling(item); }
4512
4513wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
4514{ return m_main_win->GetPrevSibling(item); }
4515
33328cd8
RD
4516wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
4517{ return m_main_win->GetNext(item, true); }
1fded56b 4518
33328cd8
RD
4519wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
4520{ return m_main_win->GetPrev(item, true); }
1fded56b 4521
33328cd8
RD
4522wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
4523{ return m_main_win->GetFirstExpandedItem(); }
1fded56b 4524
33328cd8
RD
4525wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
4526{ return m_main_win->GetNextExpanded(item); }
4527
4528wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
4529{ return m_main_win->GetPrevExpanded(item); }
4530
4531wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
4532{ return m_main_win->GetFirstVisibleItem(fullRow); }
1fded56b 4533
33328cd8
RD
4534wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow) const
4535{ return m_main_win->GetNextVisible(item, fullRow); }
4536
4537wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow) const
4538{ return m_main_win->GetPrevVisible(item, fullRow); }
4539
4540wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
4541 int selectedImage, wxTreeItemData* data)
4542{ return m_main_win->AddRoot (text, image, selectedImage, data); }
1fded56b
RD
4543
4544wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
4545 const wxString& text, int image,
4546 int selectedImage,
4547 wxTreeItemData* data)
4548{ return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
4549
4550wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4551 const wxTreeItemId& previous,
4552 const wxString& text, int image,
4553 int selectedImage,
4554 wxTreeItemData* data)
4555{
4556 return m_main_win->InsertItem(parent, previous, text, image,
4557 selectedImage, data);
4558}
4559
4560wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4561 size_t index,
4562 const wxString& text, int image,
4563 int selectedImage,
4564 wxTreeItemData* data)
4565{
4566 return m_main_win->InsertItem(parent, index, text, image,
4567 selectedImage, data);
4568}
4569
4570wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
4571 const wxString& text, int image,
4572 int selectedImage,
4573 wxTreeItemData* data)
4574{ return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
4575
4576void wxTreeListCtrl::Delete(const wxTreeItemId& item)
4577{ m_main_win->Delete(item); }
4578
4579void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
4580{ m_main_win->DeleteChildren(item); }
4581
33328cd8
RD
4582void wxTreeListCtrl::DeleteRoot()
4583{ m_main_win->DeleteRoot(); }
1fded56b
RD
4584
4585void wxTreeListCtrl::Expand(const wxTreeItemId& item)
4586{ m_main_win->Expand(item); }
4587
4588void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
4589{ m_main_win->ExpandAll(item); }
4590
4591void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
4592{ m_main_win->Collapse(item); }
4593
4594void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
4595{ m_main_win->CollapseAndReset(item); }
4596
4597void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
4598{ m_main_win->Toggle(item); }
4599
4600void wxTreeListCtrl::Unselect()
4601{ m_main_win->Unselect(); }
4602
4603void wxTreeListCtrl::UnselectAll()
4604{ m_main_win->UnselectAll(); }
4605
33328cd8
RD
4606void wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
4607 bool unselect_others)
4608{ m_main_win->SelectItem (item, last, unselect_others); }
1fded56b 4609
33328cd8
RD
4610void wxTreeListCtrl::SelectAll()
4611{ m_main_win->SelectAll(); }
28eab81f 4612
1fded56b
RD
4613void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
4614{ m_main_win->EnsureVisible(item); }
4615
4616void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
4617{ m_main_win->ScrollTo(item); }
4618
33328cd8 4619wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
1fded56b 4620{
33328cd8
RD
4621 wxPoint p = m_main_win->ScreenToClient (ClientToScreen (pos));
4622 return m_main_win->HitTest (p, flags, column);
1fded56b
RD
4623}
4624
4625bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
4626 bool textOnly) const
4627{ return m_main_win->GetBoundingRect(item, rect, textOnly); }
4628
33328cd8
RD
4629void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
4630{ m_main_win->EditLabel (item, column); }
1fded56b
RD
4631
4632int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1,
4633 const wxTreeItemId& item2)
4634{
33328cd8 4635 // do the comparison here, and not delegate to m_main_win, in order
1fded56b
RD
4636 // to let the user override it
4637 //return m_main_win->OnCompareItems(item1, item2);
4638 return wxStrcmp(GetItemText(item1), GetItemText(item2));
4639}
4640
4641void wxTreeListCtrl::SortChildren(const wxTreeItemId& item)
4642{ m_main_win->SortChildren(item); }
4643
33328cd8
RD
4644wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, const wxString& str, int mode)
4645{ return m_main_win->FindItem (item, str, mode); }
4646
4647void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
4648{ m_main_win->SetDragItem (item); }
28eab81f 4649
1fded56b 4650bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
33328cd8 4651{
da9b4153 4652 if (!m_main_win) return false;
33328cd8 4653 return m_main_win->SetBackgroundColour(colour);
da9b4153 4654}
1fded56b
RD
4655
4656bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
33328cd8 4657{
da9b4153 4658 if (!m_main_win) return false;
33328cd8 4659 return m_main_win->SetForegroundColour(colour);
da9b4153 4660}
1fded56b 4661
33328cd8 4662int wxTreeListCtrl::GetColumnCount() const
1fded56b
RD
4663{ return m_main_win->GetColumnCount(); }
4664
33328cd8
RD
4665void wxTreeListCtrl::SetColumnWidth(int column, int width)
4666{
4667 m_header_win->SetColumnWidth (column, width);
4668 m_header_win->Refresh();
4669}
1fded56b 4670
33328cd8 4671int wxTreeListCtrl::GetColumnWidth(int column) const
1fded56b
RD
4672{ return m_header_win->GetColumnWidth(column); }
4673
33328cd8 4674void wxTreeListCtrl::SetMainColumn(int column)
1fded56b
RD
4675{ m_main_win->SetMainColumn(column); }
4676
33328cd8 4677int wxTreeListCtrl::GetMainColumn() const
1fded56b
RD
4678{ return m_main_win->GetMainColumn(); }
4679
33328cd8 4680void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
1fded56b 4681{
33328cd8 4682 m_header_win->SetColumnText (column, text);
1fded56b
RD
4683 m_header_win->Refresh();
4684}
4685
33328cd8 4686wxString wxTreeListCtrl::GetColumnText(int column) const
1fded56b
RD
4687{ return m_header_win->GetColumnText(column); }
4688
33328cd8 4689void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
136518e5 4690{
33328cd8 4691 m_header_win->AddColumn (colInfo);
136518e5
RD
4692 DoHeaderLayout();
4693}
1fded56b 4694
33328cd8
RD
4695void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
4696{
4697 m_header_win->InsertColumn (before, colInfo);
4698 m_header_win->Refresh();
4699}
1fded56b 4700
33328cd8
RD
4701void wxTreeListCtrl::RemoveColumn(int column)
4702{
4703 m_header_win->RemoveColumn (column);
4704 m_header_win->Refresh();
4705}
1fded56b 4706
33328cd8
RD
4707void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
4708{
4709 m_header_win->SetColumn (column, colInfo);
4710 m_header_win->Refresh();
4711}
1fded56b 4712
33328cd8 4713const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
1fded56b
RD
4714{ return m_header_win->GetColumn(column); }
4715
33328cd8 4716wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column)
1fded56b
RD
4717{ return m_header_win->GetColumn(column); }
4718
33328cd8 4719void wxTreeListCtrl::SetColumnImage(int column, int image)
1fded56b 4720{
33328cd8
RD
4721 m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
4722 m_header_win->Refresh();
1fded56b
RD
4723}
4724
33328cd8 4725int wxTreeListCtrl::GetColumnImage(int column) const
1fded56b
RD
4726{
4727 return m_header_win->GetColumn(column).GetImage();
4728}
4729
33328cd8
RD
4730void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
4731{
4732 m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
4733}
4734
4735void wxTreeListCtrl::SetColumnShown(int column, bool shown)
4736{
4737 wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
4738 m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
4739 m_header_win->Refresh();
4740}
4741
4742bool wxTreeListCtrl::IsColumnEditable(int column) const
28eab81f 4743{
33328cd8 4744 return m_header_win->GetColumn(column).IsEditable();
28eab81f
RD
4745}
4746
33328cd8 4747bool wxTreeListCtrl::IsColumnShown(int column) const
28eab81f 4748{
33328cd8 4749 return m_header_win->GetColumn(column).IsShown();
28eab81f
RD
4750}
4751
33328cd8 4752void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
1fded56b 4753{
33328cd8
RD
4754 m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
4755 m_header_win->Refresh();
1fded56b
RD
4756}
4757
33328cd8 4758int wxTreeListCtrl::GetColumnAlignment(int column) const
1fded56b
RD
4759{
4760 return m_header_win->GetColumn(column).GetAlignment();
4761}
4762
4763void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
4764{
33328cd8
RD
4765 m_main_win->Refresh (erase, rect);
4766 m_header_win->Refresh (erase, rect);
1fded56b
RD
4767}
4768
4769void wxTreeListCtrl::SetFocus()
4770{ m_main_win->SetFocus(); }
28eab81f 4771
3872d96d
RD
4772wxSize wxTreeListCtrl::DoGetBestSize() const
4773{
4774 // something is better than nothing...
33328cd8 4775 return wxSize (200,200); // but it should be specified values! FIXME
3872d96d 4776}
4f73709d 4777
33328cd8 4778wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
4f73709d 4779{
33328cd8 4780 return wxEmptyString;
4f73709d 4781}