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