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