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