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