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