1
/////////////////////////////////////////////////////////////////////////////
2
// Name: treelistctrl.cpp
3
// Purpose: multi column tree control implementation
5
// Author: Robert Roebling
6
// Maintainer: Ronan Chartois (pgriddev)
7
// Version: $Id: treelistctrl.cpp 2693 2011-04-03 19:48:06Z pgriddev $
8
// Copyright: (c) 2004-2011 Robert Roebling, Julian Smart, Alberto Griggio,
9
// Vadim Zeitlin, Otto Wyss, Ronan Chartois
11
/////////////////////////////////////////////////////////////////////////////
13
// ===========================================================================
15
// ===========================================================================
17
// ---------------------------------------------------------------------------
19
// ---------------------------------------------------------------------------
21
#if defined(__GNUG__) && !defined(__APPLE__)
22
#pragma implementation "treelistctrl.h"
25
// For compilers that support precompilation, includes "wx.h".
26
#include "wx/wxprec.h"
34
#include <wx/treebase.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
#include <wx/dcmemory.h>
43
#if wxCHECK_VERSION(2, 7, 0)
44
#include <wx/renderer.h>
46
#include <wx/apptrait.h>
47
#include <wx/dcbuffer.h>
48
#include <wx/tooltip.h>
49
#include <wx/hashmap.h>
52
#include "wx/mac/private.h"
55
#include "treelistctrl.h"
57
#include <wx/log.h> // only required for debugging purpose
58
#include <wx/msgdlg.h> // only required for debugging purpose
60
// ---------------------------------------------------------------------------
62
// ---------------------------------------------------------------------------
65
class wxTreeListItemCellAttr;
67
#if !wxCHECK_VERSION(2, 5, 0)
68
WX_DEFINE_ARRAY(wxTreeListItem *, wxArrayTreeListItems);
70
WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems);
73
#include <wx/dynarray.h>
74
WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo);
75
#include <wx/arrimpl.cpp>
76
WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo);
79
WX_DECLARE_HASH_MAP( int, wxTreeListItemCellAttr *, wxIntegerHash, wxIntegerEqual, wxTreeListItemCellAttrHash );
81
// --------------------------------------------------------------------------
83
// --------------------------------------------------------------------------
85
static const int NO_IMAGE = -1;
87
static const int LINEHEIGHT = 10;
88
static const int LINEATROOT = 5;
89
static const int MARGIN = 2;
90
static const int MININDENT = 16;
91
static const int BTNWIDTH = 9;
92
static const int BTNHEIGHT = 9;
93
static const int EXTRA_WIDTH = 4;
94
static const int EXTRA_HEIGHT = 4;
95
static const int HEADER_OFFSET_X = 0; // changed from 1 to 0 on 2009.03.10 for Windows (other OS untested)
96
static const int HEADER_OFFSET_Y = 1;
98
static const int DRAG_TIMER_TICKS = 250; // minimum drag wait time in ms
99
static const int FIND_TIMER_TICKS = 500; // minimum find wait time in ms
100
static const int RENAME_TIMER_TICKS = 250; // minimum rename wait time in ms
102
const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl");
104
static wxTreeListColumnInfo wxInvalidTreeListColumnInfo;
107
// ---------------------------------------------------------------------------
109
// ---------------------------------------------------------------------------
111
class wxTreeListHeaderWindow : public wxWindow
114
wxTreeListMainWindow *m_owner;
115
const wxCursor *m_currentCursor;
116
const wxCursor *m_resizeCursor;
119
// column being resized
122
// divider line position in logical (unscrolled) coords
125
// minimal position beyond which the divider line can't be dragged in
129
wxArrayTreeListColumnInfo m_columns;
131
// total width of the columns
132
int m_total_col_width;
134
#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
135
// which col header is currently highlighted with mouse-over
138
void RefreshColLabel(int col);
142
wxTreeListHeaderWindow();
144
wxTreeListHeaderWindow( wxWindow *win,
146
wxTreeListMainWindow *owner,
147
const wxPoint &pos = wxDefaultPosition,
148
const wxSize &size = wxDefaultSize,
150
const wxString &name = _T("wxtreelistctrlcolumntitles") );
152
virtual ~wxTreeListHeaderWindow();
154
void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
156
void AdjustDC(wxDC& dc);
158
void OnPaint( wxPaintEvent &event );
159
void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // reduce flicker
160
void OnMouse( wxMouseEvent &event );
161
void OnSetFocus( wxFocusEvent &event );
163
// total width of all columns
164
int GetWidth() const { return m_total_col_width; }
166
// column manipulation
167
int GetColumnCount() const { return (int)m_columns.GetCount(); }
169
void AddColumn (const wxTreeListColumnInfo& colInfo);
171
void InsertColumn (int before, const wxTreeListColumnInfo& colInfo);
173
void RemoveColumn (int column);
175
// column information manipulation
176
const wxTreeListColumnInfo& GetColumn (int column) const{
177
wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
178
wxInvalidTreeListColumnInfo, _T("Invalid column"));
179
return m_columns[column];
181
wxTreeListColumnInfo& GetColumn (int column) {
182
wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
183
wxInvalidTreeListColumnInfo, _T("Invalid column"));
184
return m_columns[column];
186
void SetColumn (int column, const wxTreeListColumnInfo& info);
188
wxString GetColumnText (int column) const {
189
wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
190
wxEmptyString, _T("Invalid column"));
191
return m_columns[column].GetText();
193
void SetColumnText (int column, const wxString& text) {
194
wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
195
_T("Invalid column"));
196
m_columns[column].SetText (text);
199
int GetColumnAlignment (int column) const {
200
wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
201
wxALIGN_LEFT, _T("Invalid column"));
202
return m_columns[column].GetAlignment();
204
void SetColumnAlignment (int column, int flag) {
205
wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
206
_T("Invalid column"));
207
m_columns[column].SetAlignment (flag);
210
int GetColumnWidth (int column) const {
211
wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
212
-1, _T("Invalid column"));
213
return m_columns[column].GetWidth();
215
void SetColumnWidth (int column, int width);
217
bool IsColumnEditable (int column) const {
218
wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
219
false, _T("Invalid column"));
220
return m_columns[column].IsEditable();
223
bool IsColumnShown (int column) const {
224
wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
225
true, _T("Invalid column"));
226
return m_columns[column].IsShown();
233
// common part of all ctors
236
void SendListEvent(wxEventType type, wxPoint pos);
238
DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow)
239
DECLARE_EVENT_TABLE()
243
//-----------------------------------------------------------------------------
245
class wxEditTextCtrl;
248
// this is the "true" control
249
class wxTreeListMainWindow: public wxScrolledWindow
254
wxTreeListMainWindow() { Init(); }
256
wxTreeListMainWindow (wxTreeListCtrl *parent, wxWindowID id = -1,
257
const wxPoint& pos = wxDefaultPosition,
258
const wxSize& size = wxDefaultSize,
259
long style = wxTR_DEFAULT_STYLE,
260
const wxValidator &validator = wxDefaultValidator,
261
const wxString& name = _T("wxtreelistmainwindow"))
264
Create (parent, id, pos, size, style, validator, name);
267
virtual ~wxTreeListMainWindow();
269
bool Create(wxTreeListCtrl *parent, wxWindowID id = -1,
270
const wxPoint& pos = wxDefaultPosition,
271
const wxSize& size = wxDefaultSize,
272
long style = wxTR_DEFAULT_STYLE,
273
const wxValidator &validator = wxDefaultValidator,
274
const wxString& name = _T("wxtreelistctrl"));
279
// return true if this is a virtual list control
280
bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); }
282
// get the total number of items in the control
283
size_t GetCount() const;
285
// indent is the number of pixels the children are indented relative to
286
// the parents position. SetIndent() also redraws the control
288
unsigned int GetIndent() const { return m_indent; }
289
void SetIndent(unsigned int indent);
291
// see wxTreeListCtrl for the meaning
292
unsigned int GetLineSpacing() const { return m_linespacing; }
293
void SetLineSpacing(unsigned int spacing);
295
// image list: these functions allow to associate an image list with
296
// the control and retrieve it. Note that when assigned with
297
// SetImageList, the control does _not_ delete
298
// the associated image list when it's deleted in order to allow image
299
// lists to be shared between different controls. If you use
300
// AssignImageList, the control _does_ delete the image list.
302
// The normal image list is for the icons which correspond to the
303
// normal tree item state (whether it is selected or not).
304
// Additionally, the application might choose to show a state icon
305
// which corresponds to an app-defined item state (for example,
306
// checked/unchecked) which are taken from the state image list.
307
wxImageList *GetImageList() const { return m_imageListNormal; }
308
wxImageList *GetStateImageList() const { return m_imageListState; }
309
wxImageList *GetButtonsImageList() const { return m_imageListButtons; }
311
void SetImageList(wxImageList *imageList);
312
void SetStateImageList(wxImageList *imageList);
313
void SetButtonsImageList(wxImageList *imageList);
314
void AssignImageList(wxImageList *imageList);
315
void AssignStateImageList(wxImageList *imageList);
316
void AssignButtonsImageList(wxImageList *imageList);
318
void SetToolTip(const wxString& tip);
319
void SetToolTip(wxToolTip *tip);
320
void SetItemToolTip(const wxTreeItemId& item, const wxString &tip);
322
// Functions to work with tree ctrl items.
326
// accessors (most props have a default at row/item level *and* a default at cell level)
329
std::list<wxTreeItemId> GetPublicChildren(const wxTreeItemId& item) const;
330
wxString GetItemText (const wxTreeItemId& item, int column) const;
331
wxString GetItemText (wxTreeItemData* item, int column) const;
333
// ItemImage is special: main col has multiple images
334
int GetItemImage (const wxTreeItemId& item, wxTreeItemIcon which = wxTreeItemIcon_Normal) const { return GetItemImage (item, GetMainColumn(), which); }
335
int GetItemImage (const wxTreeItemId& item, int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const;
337
// ItemData is special, there is a separate default at row/item level
338
wxTreeItemData *GetItemData(const wxTreeItemId& item) const;
339
wxTreeItemData *GetItemData(const wxTreeItemId& item, int column) const;
341
bool GetItemBold(const wxTreeItemId& item) const;
342
bool GetItemBold(const wxTreeItemId& item, int column) const;
344
wxColour GetItemTextColour(const wxTreeItemId& item) const;
345
wxColour GetItemTextColour(const wxTreeItemId& item, int column) const;
347
wxColour GetItemBackgroundColour(const wxTreeItemId& item) const;
348
wxColour GetItemBackgroundColour(const wxTreeItemId& item, int column) const;
350
wxFont GetItemFont(const wxTreeItemId& item) const;
351
wxFont GetItemFont(const wxTreeItemId& item, int column) const;
355
// modifiers (most properties have a default at row/item level *and* a default at cell level)
358
// force appearance of [+] button near the item. This is useful to
359
// allow the user to expand the items which don't have any children now
360
// - but instead add them only when needed, thus minimizing memory
361
// usage and loading time.
362
void SetItemHasChildren(const wxTreeItemId& item, bool has = true);
365
void SetItemText (const wxTreeItemId& item, int column, const wxString& text);
367
// get one of the images associated with the item (normal by default)
368
void SetItemImage (const wxTreeItemId& item, int image, wxTreeItemIcon which = wxTreeItemIcon_Normal) { SetItemImage (item, GetMainColumn(), image, which); }
369
void SetItemImage (const wxTreeItemId& item, int column, int image, wxTreeItemIcon which = wxTreeItemIcon_Normal);
371
// associate some data with the item
372
void SetItemData(const wxTreeItemId& item, wxTreeItemData *data);
373
void SetItemData(const wxTreeItemId& item, int column, wxTreeItemData *data);
375
// the item will be shown in bold
376
void SetItemBold(const wxTreeItemId& item, bool bold = true);
377
void SetItemBold(const wxTreeItemId& item, int column, bool bold = true);
379
// set the item's text colour
380
void SetItemTextColour(const wxTreeItemId& item, const wxColour& colour);
381
void SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour);
383
// set the item's background colour
384
void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& colour);
385
void SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour);
387
// set the item's font (should be of the same height for all items)
388
void SetItemFont(const wxTreeItemId& item, const wxFont& font);
389
void SetItemFont(const wxTreeItemId& item, int column, const wxFont& font);
393
// item status inquiries
394
// ---------------------
396
// is the item visible (it might be outside the view or not expanded)?
397
bool IsVisible(const wxTreeItemId& item, bool fullRow, bool within = true) const;
398
// does the item has any children?
399
bool HasChildren(const wxTreeItemId& item) const;
400
// is the item expanded (only makes sense if HasChildren())?
401
bool IsExpanded(const wxTreeItemId& item) const;
402
// is this item currently selected (the same as has focus)?
403
bool IsSelected(const wxTreeItemId& item) const;
404
// is item text in bold font?
405
bool IsBold(const wxTreeItemId& item) const;
406
bool IsBold(const wxTreeItemId& item, int column) const;
410
// set the window font
411
virtual bool SetFont( const wxFont &font );
413
// set the styles. No need to specify a GetWindowStyle here since
414
// the base wxWindow member function will do it for us
415
void SetWindowStyle(const long styles);
417
// number of children
418
// ------------------
420
// if 'recursively' is false, only immediate children count, otherwise
421
// the returned number is the number of all items in this branch
422
size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true);
427
// wxTreeItemId.IsOk() will return false if there is no such item
429
// get the root tree item
430
wxTreeItemId GetRootItem() const { return m_rootItem; } // implict cast from wxTreeListItem *
432
// get the item currently selected, only if a single item is selected
433
wxTreeItemId GetSelection() const { return m_selectItem; }
435
// get all the items currently selected, return count of items
436
size_t GetSelections(wxArrayTreeItemIds&) const;
438
// get the parent of this item (may return NULL if root)
439
wxTreeItemId GetItemParent(const wxTreeItemId& item) const;
441
// for this enumeration function you must pass in a "cookie" parameter
442
// which is opaque for the application but is necessary for the library
443
// to make these functions reentrant (i.e. allow more than one
444
// enumeration on one and the same object simultaneously). Of course,
445
// the "cookie" passed to GetFirstChild() and GetNextChild() should be
448
// get child of this item
449
#if !wxCHECK_VERSION(2, 5, 0)
450
wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const;
451
wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const;
452
wxTreeItemId GetPrevChild(const wxTreeItemId& item, long& cookie) const;
453
wxTreeItemId GetLastChild(const wxTreeItemId& item, long& cookie) const;
455
wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
456
wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
457
wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
458
wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
461
// get sibling of this item
462
wxTreeItemId GetNextSibling(const wxTreeItemId& item) const;
463
wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const;
465
// get item in the full tree (currently only for internal use)
466
wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const;
467
wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const;
469
// get expanded item, see IsExpanded()
470
wxTreeItemId GetFirstExpandedItem() const;
471
wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const;
472
wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const;
474
// get visible item, see IsVisible()
475
wxTreeItemId GetFirstVisible( bool fullRow, bool within) const;
476
wxTreeItemId GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const;
477
wxTreeItemId GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const;
478
wxTreeItemId GetLastVisible ( bool fullRow, bool within) const;
483
// add the root node to the tree
484
wxTreeItemId AddRoot (const wxString& text,
485
int image = -1, int selectedImage = -1,
486
wxTreeItemData *data = NULL);
488
// insert a new item in as the first child of the parent
489
wxTreeItemId PrependItem(const wxTreeItemId& parent,
490
const wxString& text,
491
int image = -1, int selectedImage = -1,
492
wxTreeItemData *data = NULL);
494
// insert a new item after a given one
495
wxTreeItemId InsertItem(const wxTreeItemId& parent,
496
const wxTreeItemId& idPrevious,
497
const wxString& text,
498
int image = -1, int selectedImage = -1,
499
wxTreeItemData *data = NULL);
501
// insert a new item before the one with the given index
502
wxTreeItemId InsertItem(const wxTreeItemId& parent,
504
const wxString& text,
505
int image = -1, int selectedImage = -1,
506
wxTreeItemData *data = NULL);
508
// insert a new item in as the last child of the parent
509
wxTreeItemId AppendItem(const wxTreeItemId& parent,
510
const wxString& text,
511
int image = -1, int selectedImage = -1,
512
wxTreeItemData *data = NULL);
514
// delete this item and associated data if any
515
void Delete(const wxTreeItemId& item);
516
// delete all children (but don't delete the item itself)
517
// NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
518
void DeleteChildren(const wxTreeItemId& item);
519
// delete the root and all its children from the tree
520
// NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
524
void Expand(const wxTreeItemId& item);
525
// expand this item and all subitems recursively
526
void ExpandAll(const wxTreeItemId& item);
527
// collapse the item without removing its children
528
void Collapse(const wxTreeItemId& item);
529
// collapse the item and remove all children
530
void CollapseAndReset(const wxTreeItemId& item);
531
// toggles the current state
532
void Toggle(const wxTreeItemId& item);
534
// set cursor item (indicated by black rectangle)
535
void SetCurrentItem(const wxTreeItemId& item);
537
// remove the selection from currently selected item (if any)
541
bool SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL,
542
bool unselect_others = true);
544
// make sure this item is visible (expanding the parent item and/or
545
// scrolling to this item if necessary)
546
void EnsureVisible(const wxTreeItemId& item);
547
// scroll to this item (but don't expand its parent)
548
void ScrollTo(const wxTreeItemId& item);
549
void AdjustMyScrollbars();
551
// The first function is more portable (because easier to implement
552
// on other platforms), but the second one returns some extra info.
553
wxTreeItemId HitTest (const wxPoint& point)
554
{ int flags; int column; return HitTest (point, flags, column); }
555
wxTreeItemId HitTest (const wxPoint& point, int& flags)
556
{ int column; return HitTest (point, flags, column); }
557
wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column);
560
// get the bounding rectangle of the item (or of its label only)
561
bool GetBoundingRect(const wxTreeItemId& item,
563
bool textOnly = false) const;
565
// Start editing the item label: this (temporarily) replaces the item
566
// with a one line edit control. The item will be selected if it hadn't
568
void EditLabel (const wxTreeItemId& item, int column);
569
void EndEdit(bool isCancelled);
572
// this function is called to compare 2 items and should return -1, 0
573
// or +1 if the first item is less than, equal to or greater than the
574
// second one. The base class version performs alphabetic comparaison
575
// of item labels (GetText)
576
virtual int OnCompareItems(const wxTreeItemId& item1,
577
const wxTreeItemId& item2);
578
// sort the children of this item using OnCompareItems
580
// NB: this function is not reentrant and not MT-safe (TODO)!
581
void SortChildren(const wxTreeItemId& item, int column, bool reverseOrder);
584
wxTreeItemId FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode = 0);
586
// implementation only from now on
588
// overridden base class virtuals
589
virtual bool SetBackgroundColour(const wxColour& colour);
590
virtual bool SetForegroundColour(const wxColour& colour);
593
void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL);
596
void OnPaint( wxPaintEvent &event );
597
void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // to reduce flicker
598
void OnSetFocus( wxFocusEvent &event );
599
void OnKillFocus( wxFocusEvent &event );
600
void OnChar( wxKeyEvent &event );
601
void OnMouse( wxMouseEvent &event );
602
void OnIdle( wxIdleEvent &event );
603
void OnScroll(wxScrollWinEvent& event);
604
void OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event)) { ;; }
606
// implementation helpers
607
int GetColumnCount() const
608
{ return m_owner->GetHeaderWindow()->GetColumnCount(); }
610
void SetMainColumn (int column)
611
{ if ((column >= 0) && (column < GetColumnCount())) m_main_column = column; }
613
int GetMainColumn() const { return m_main_column; }
614
int GetCurrentColumn() const { return m_curColumn >= 0 ? m_curColumn : m_main_column; }
616
int GetBestColumnWidth (int column, wxTreeItemId parent = wxTreeItemId());
617
int GetItemWidth (int column, wxTreeListItem *item);
622
wxTreeListCtrl* m_owner;
626
friend class wxTreeListItem;
627
friend class wxTreeListRenameTimer;
628
friend class wxEditTextCtrl;
633
wxTreeListItem *m_rootItem; // root item
634
wxTreeListItem *m_curItem; // current item, either selected or marked
635
wxTreeListItem *m_shiftItem; // item, where the shift key was pressed
636
wxTreeListItem *m_selectItem; // current selected item, not with wxTR_MULTIPLE
640
bool m_ReverseSortOrder;
642
int m_btnWidth, m_btnWidth2;
643
int m_btnHeight, m_btnHeight2;
644
int m_imgWidth, m_imgWidth2;
645
int m_imgHeight, m_imgHeight2;
646
unsigned short m_indent;
648
unsigned short m_linespacing;
650
wxBrush *m_hilightBrush,
651
*m_hilightUnfocusedBrush;
656
bool m_ownsImageListNormal,
657
m_ownsImageListState,
658
m_ownsImageListButtons;
659
bool m_lastOnSame; // last click on the same item as prev
660
bool m_left_down_selection;
662
wxImageList *m_imageListNormal,
666
bool m_isDragStarted; // set at the very beginning of dragging
667
bool m_isDragging; // set once a drag begin event was fired
668
wxPoint m_dragStartPos; // set whenever m_isDragStarted is set to true
669
wxTreeListItem *m_dragItem;
672
wxTreeListItem *m_editItem; // item, which is currently edited
673
wxTimer *m_editTimer;
674
bool m_editAccept; // currently unused, OnRenameAccept() argument makes it redundant
677
wxEditTextCtrl *m_editControl;
680
wxTimer *m_findTimer;
683
bool m_isItemToolTip; // true if individual item tooltips were set (disable global tooltip)
684
wxString m_toolTip; // global tooltip
685
wxTreeListItem *m_toolTipItem; // item whose tip is currently shown (NULL==global, -1==not displayed)
687
// the common part of all ctors
691
wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
693
const wxString& text,
694
int image, int selectedImage,
695
wxTreeItemData *data);
696
void DoDeleteItem (wxTreeListItem *item);
697
void SetCurrentItem(wxTreeListItem *item);
698
bool HasButtons(void) const
699
{ return (m_imageListButtons) || HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); }
701
void CalculateLineHeight();
702
int GetLineHeight(wxTreeListItem *item) const;
703
void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y,
705
void PaintItem( wxTreeListItem *item, wxDC& dc);
707
void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y,
709
void CalculatePositions();
710
void CalculateSize( wxTreeListItem *item, wxDC &dc );
712
void RefreshSubtree (wxTreeListItem *item);
713
void RefreshLine (wxTreeListItem *item);
714
// redraw all selected items
715
void RefreshSelected();
716
// RefreshSelected() recursive helper
717
void RefreshSelectedUnder (wxTreeListItem *item);
719
void OnRenameTimer();
720
void OnRenameAccept(bool isCancelled);
722
void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const;
723
bool TagAllChildrenUntilLast (wxTreeListItem *crt_item, wxTreeListItem *last_item);
724
bool TagNextChildren (wxTreeListItem *crt_item, wxTreeListItem *last_item);
725
void UnselectAllChildren (wxTreeListItem *item );
726
bool SendEvent(wxEventType event_type, wxTreeListItem *item = NULL, wxTreeEvent *event = NULL); // returns true if processed
729
DECLARE_EVENT_TABLE()
730
DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow)
734
//-----------------------------------------------------------------------------
736
// timer used for enabling in-place edit
737
class wxTreeListRenameTimer: public wxTimer
740
wxTreeListRenameTimer( wxTreeListMainWindow *owner );
745
wxTreeListMainWindow *m_owner;
749
//-----------------------------------------------------------------------------
751
// control used for in-place edit
752
class wxEditTextCtrl: public wxTextCtrl
755
wxEditTextCtrl (wxWindow *parent,
759
wxTreeListMainWindow *owner,
760
const wxString &value = wxEmptyString,
761
const wxPoint &pos = wxDefaultPosition,
762
const wxSize &size = wxDefaultSize,
764
const wxValidator& validator = wxDefaultValidator,
765
const wxString &name = wxTextCtrlNameStr );
768
virtual bool Destroy(); // wxWindow override
769
void EndEdit(bool isCancelled);
770
void SetOwner(wxTreeListMainWindow *owner) { m_owner = owner; }
772
void OnChar( wxKeyEvent &event );
773
void OnKeyUp( wxKeyEvent &event );
774
void OnKillFocus( wxFocusEvent &event );
778
wxTreeListMainWindow *m_owner;
781
wxString m_startValue;
782
bool m_finished; // true==deleting, don't process events anymore
784
DECLARE_EVENT_TABLE()
788
//-----------------------------------------------------------------------------
790
// list of per-column attributes for an item (wxTreeListItem)
791
// since there can be very many of these, we save size by chosing
792
// the smallest representation for the elements and by ordering
793
// the members to avoid padding.
794
class wxTreeListItemCellAttr
797
wxTreeListItemCellAttr() {
805
~wxTreeListItemCellAttr() {
806
if (m_ownsAttr) delete m_attr;
809
// generic attribute from wxWidgets lib
810
wxTreeItemAttr *m_attr;
813
wxTreeItemData *m_data; // user-provided data
814
short m_image; // images for the various columns (!= main)
815
int m_isBold :1; // render the label in bold font
816
int m_isBoldSet :1; // was 'm_isBold' set ?
817
int m_ownsAttr :1; // delete attribute when done
821
//-----------------------------------------------------------------------------
823
// a tree item (NOTE: this class is storage only, does not generate events)
824
class wxTreeListItem : public wxTreeListItemPublic
829
wxTreeListItem() { m_toolTip = NULL; }
830
wxTreeListItem( wxTreeListMainWindow *owner,
831
wxTreeListItem *parent,
832
const wxArrayString& text,
835
wxTreeItemData *data );
840
// accessors (most properties have a default at row/item level)
843
virtual std::list<wxTreeItemId> GetPublicChildren() const
845
std::list<wxTreeItemId> ch;
846
for (unsigned int i = 0; i < m_children.size(); i++) {
847
ch.push_back(m_children[i]);
852
wxArrayTreeListItems& GetChildren() { return m_children; }
855
// const wxString GetText ( ) const { return GetText(m_owner->GetMainColumn()); }
856
const wxString GetText (int column) const
858
if ( IsVirtual() ) return m_owner->GetItemText( m_props_row.m_data, column );
859
if (column < (signed)m_text.GetCount()) return m_text[column];
860
return wxEmptyString;
863
int GetImage ( wxTreeItemIcon which = wxTreeItemIcon_Normal) const { return m_images[which]; };
864
int GetImage (int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const
866
// main column is special, more images available
867
if(column == m_owner->GetMainColumn()) return m_images[which];
869
// other columns ignore the 'which' parameter
870
wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
871
if (entry == m_props_cell.end()) return NO_IMAGE;
872
return entry->second->m_image;
875
// data is special: it has a default value at row/item level
876
wxTreeItemData *GetData() const { return m_props_row.m_data; };
877
wxTreeItemData *GetData(int column) const {
878
wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
879
if (entry == m_props_cell.end()) return NULL;
880
return entry->second->m_data;
883
const wxString * GetToolTip() const { return m_toolTip; };
885
// returns the current image for the item (depending on its
886
// selected/expanded/whatever state)
887
int GetCurrentImage() const;
890
// modifiers (most properties have a default at row/item level)
892
void SetHasPlus(bool has = true) { m_hasPlus = has; };
894
void SetText (int column, const wxString& text)
896
if (column < (int)m_text.GetCount()) {
897
m_text[column] = text;
898
} else if (column < m_owner->GetColumnCount()) {
899
int howmany = m_owner->GetColumnCount();
900
for (int i = (int)m_text.GetCount(); i < howmany; ++i) m_text.Add (wxEmptyString);
901
m_text[column] = text;
904
void SetImage ( int image, wxTreeItemIcon which) { m_images[which] = image; };
905
void SetImage (int column, int image, wxTreeItemIcon which)
907
// main column is special, more images available
908
if (column == m_owner->GetMainColumn()) m_images[which] = image;
909
// other columns ignore the 'which' parameter
911
wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
912
if (entry == m_props_cell.end()) {
913
m_props_cell[column] = new wxTreeListItemCellAttr();
914
m_props_cell[column]->m_image = image;
916
entry->second->m_image = image;
921
// data is special: it has a default value at row/item level
922
void SetData( wxTreeItemData *data) { m_props_row.m_data = data; };
923
void SetData(int column, wxTreeItemData *data)
925
wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
926
if (entry == m_props_cell.end()) {
927
m_props_cell[column] = new wxTreeListItemCellAttr();
928
m_props_cell[column]->m_data = data;
930
entry->second->m_data = data;
934
void SetBold( bool bold) { m_props_row.m_isBold = bold; }
935
void SetBold(int column, bool bold)
937
wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
938
if (entry == m_props_cell.end()) {
939
m_props_cell[column] = new wxTreeListItemCellAttr();
940
m_props_cell[column]->m_isBold = bold;
941
m_props_cell[column]->m_isBoldSet = 1;
943
entry->second->m_isBold = bold;
944
entry->second->m_isBoldSet = 1;
949
void SetToolTip(const wxString &tip) {
950
if (m_toolTip) { delete m_toolTip; m_toolTip = NULL; }
951
if (tip.length() > 0) { m_toolTip = new wxString(tip); }
957
bool HasChildren() const { return !m_children.IsEmpty(); }
958
bool IsSelected() const { return m_hasHilight != 0; }
959
bool IsExpanded() const { return !m_isCollapsed; }
960
bool HasPlus() const { return m_hasPlus || HasChildren(); }
961
bool IsBold() const { return m_props_row.m_isBold; }
962
bool IsBold(int column) const
964
wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
965
if (entry == m_props_cell.end() || ! entry->second->m_isBoldSet) return IsBold();
966
return (entry->second->m_isBold != 0);
968
bool IsVirtual() const { return m_owner->IsVirtual(); }
972
int GetX() const { return m_x; }
973
int GetY() const { return m_y; }
975
void SetX (int x) { m_x = x; }
976
void SetY (int y) { m_y = y; }
978
int GetHeight() const { return m_height; }
979
int GetWidth() const { return m_width; }
981
void SetHeight (int height) { m_height = height; }
982
void SetWidth (int width) { m_width = width; }
984
int GetTextX() const { return m_text_x; }
985
void SetTextX (int text_x) { m_text_x = text_x; }
987
virtual wxTreeListItem *GetItemParent() const { return m_parent; }
989
// get count of all children (and grand children if 'recursively')
990
size_t GetChildrenCount(bool recursively = true) const;
992
void GetSize( int &x, int &y, const wxTreeListMainWindow* );
994
// return the item at given position (or NULL if no item), onButton is
995
// true if the point belongs to the item's button, otherwise it lies
996
// on the button's label
997
wxTreeListItem *HitTest (const wxPoint& point,
998
const wxTreeListMainWindow *,
999
int &flags, int& column, int level);
1004
// deletes all children
1005
void DeleteChildren();
1007
void Insert(wxTreeListItem *child, size_t index)
1008
{ m_children.Insert(child, index); }
1010
void Expand() { m_isCollapsed = false; }
1011
void Collapse() { m_isCollapsed = true; }
1013
void SetHilight( bool set = true ) { m_hasHilight = set; }
1019
// get them - may be NULL (used to read attributes)
1020
// NOTE: fall back on default at row/item level is not defined for cell
1021
wxTreeItemAttr *GetAttributes(int column) const
1023
wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
1024
if (entry == m_props_cell.end()) return GetAttributes();
1025
return entry->second->m_attr;
1027
wxTreeItemAttr *GetAttributes() const { return m_props_row.m_attr; }
1029
// get them ensuring that the pointer is not NULL (used to write attributes)
1030
wxTreeItemAttr& Attr(int column) {
1031
wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
1032
if (entry == m_props_cell.end()) {
1033
m_props_cell[column] = new wxTreeListItemCellAttr();
1034
m_props_cell[column]->m_attr = new wxTreeItemAttr;
1035
m_props_cell[column]->m_ownsAttr = 1;
1036
return *(m_props_cell[column]->m_attr);
1038
return *(entry->second->m_attr);
1041
wxTreeItemAttr& Attr()
1043
if ( !m_props_row.m_attr )
1045
m_props_row.m_attr = new wxTreeItemAttr;
1046
m_props_row.m_ownsAttr = 1;
1048
return *m_props_row.m_attr;
1050
/* ----- unused -----
1052
void SetAttributes(wxTreeItemAttr *attr)
1054
if ( m_props_row.m_ownsAttr ) delete m_props_row.m_attr;
1055
m_props_row.m_attr = attr;
1056
m_props_row.m_ownsAttr = 0;
1058
// set them and delete when done
1059
void AssignAttributes(wxTreeItemAttr *attr)
1061
SetAttributes(attr);
1062
m_props_row.m_ownsAttr = 1;
1067
wxTreeListMainWindow *m_owner; // control the item belongs to
1069
wxArrayTreeListItems m_children; // list of children
1070
wxTreeListItem *m_parent; // parent of this item
1072
// main column item positions
1073
wxCoord m_x; // (virtual) offset from left (vertical line)
1074
wxCoord m_y; // (virtual) offset from top
1075
wxCoord m_text_x; // item offset from left
1076
short m_width; // width of this item
1077
unsigned char m_height; // height of this item
1079
// for the normal, selected, expanded and expanded+selected states
1080
short m_images[wxTreeItemIcon_Max];
1081
// currently there is no tooltip at cell level
1082
wxString *m_toolTip;
1084
// use bitfields to save size
1085
int m_isCollapsed :1;
1086
int m_hasHilight :1; // same as focused
1087
int m_hasPlus :1; // used for item which doesn't have
1088
// children but has a [+] button
1090
// here are all the properties which can be set per column
1091
wxArrayString m_text; // labels to be rendered for item
1092
wxTreeListItemCellAttr m_props_row; // default at row/item level for: data, attr
1093
wxTreeListItemCellAttrHash m_props_cell;
1097
// ===========================================================================
1099
// ===========================================================================
1101
// ---------------------------------------------------------------------------
1102
// wxTreeListRenameTimer (internal)
1103
// ---------------------------------------------------------------------------
1105
wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner )
1110
void wxTreeListRenameTimer::Notify()
1112
m_owner->OnRenameTimer();
1115
//-----------------------------------------------------------------------------
1116
// wxEditTextCtrl (internal)
1117
//-----------------------------------------------------------------------------
1119
BEGIN_EVENT_TABLE (wxEditTextCtrl,wxTextCtrl)
1120
EVT_KEY_DOWN (wxEditTextCtrl::OnChar)
1121
EVT_KEY_UP (wxEditTextCtrl::OnKeyUp)
1122
EVT_KILL_FOCUS (wxEditTextCtrl::OnKillFocus)
1125
wxEditTextCtrl::wxEditTextCtrl (wxWindow *parent,
1126
const wxWindowID id,
1129
wxTreeListMainWindow *owner,
1130
const wxString &value,
1134
const wxValidator& validator,
1135
const wxString &name)
1136
: wxTextCtrl (parent, id, value, pos, size, style | wxSIMPLE_BORDER, validator, name)
1141
(*m_accept) = false;
1142
(*m_res) = wxEmptyString;
1143
m_startValue = value;
1147
wxEditTextCtrl::~wxEditTextCtrl() {
1148
EndEdit(true); // cancelled
1151
void wxEditTextCtrl::EndEdit(bool isCancelled) {
1152
if (m_finished) return;
1156
(*m_accept) = ! isCancelled;
1157
(*m_res) = isCancelled ? m_startValue : GetValue();
1158
m_owner->OnRenameAccept(*m_res == m_startValue);
1159
m_owner->m_editControl = NULL;
1160
m_owner->m_editItem = NULL;
1161
m_owner->SetFocus(); // This doesn't work. TODO.
1168
bool wxEditTextCtrl::Destroy() {
1170
wxTheApp->GetTraits()->ScheduleForDestroy(this);
1174
void wxEditTextCtrl::OnChar( wxKeyEvent &event )
1181
if (event.GetKeyCode() == WXK_RETURN)
1183
EndEdit(false); // not cancelled
1186
if (event.GetKeyCode() == WXK_ESCAPE)
1188
EndEdit(true); // cancelled
1194
void wxEditTextCtrl::OnKeyUp( wxKeyEvent &event )
1202
// auto-grow the textctrl:
1203
wxSize parentSize = m_owner->GetSize();
1204
wxPoint myPos = GetPosition();
1205
wxSize mySize = GetSize();
1207
GetTextExtent(GetValue() + _T("M"), &sx, &sy);
1208
if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
1209
if (mySize.x > sx) sx = mySize.x;
1215
void wxEditTextCtrl::OnKillFocus( wxFocusEvent &event )
1223
EndEdit(false); // not cancelled
1226
//-----------------------------------------------------------------------------
1227
// wxTreeListHeaderWindow
1228
//-----------------------------------------------------------------------------
1230
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxWindow);
1232
BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)
1233
EVT_PAINT (wxTreeListHeaderWindow::OnPaint)
1234
EVT_ERASE_BACKGROUND(wxTreeListHeaderWindow::OnEraseBackground) // reduce flicker
1235
EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse)
1236
EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus)
1240
void wxTreeListHeaderWindow::Init()
1242
m_currentCursor = (wxCursor *) NULL;
1243
m_isDragging = false;
1245
m_total_col_width = 0;
1246
#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1250
// prevent any background repaint in order to reducing flicker
1251
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
1254
wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1258
m_owner = (wxTreeListMainWindow *) NULL;
1259
m_resizeCursor = (wxCursor *) NULL;
1262
wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win,
1264
wxTreeListMainWindow *owner,
1268
const wxString &name )
1269
: wxWindow( win, id, pos, size, style, name )
1274
m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE);
1276
#if !wxCHECK_VERSION(2, 5, 0)
1277
SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE));
1279
SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE));
1283
wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1285
delete m_resizeCursor;
1288
void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
1290
#if !wxCHECK_VERSION(2, 5, 0)
1291
wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1293
wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1296
const int m_corner = 1;
1298
dc->SetBrush( *wxTRANSPARENT_BRUSH );
1299
#if defined( __WXMAC__ )
1302
dc->SetPen( *wxBLACK_PEN );
1304
dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
1305
dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
1307
#if defined( __WXMAC__ )
1308
pen = wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
1311
dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1312
dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
1314
dc->SetPen( *wxWHITE_PEN );
1315
dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1316
dc->DrawRectangle( x, y, 1, h ); // left (outer)
1317
dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1318
dc->DrawLine( x+w-1, y, x+w-1, y+1 );
1321
// shift the DC origin to match the position of the main window horz
1322
// scrollbar: this allows us to always use logical coords
1323
void wxTreeListHeaderWindow::AdjustDC(wxDC& dc)
1326
m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1328
m_owner->GetViewStart( &x, NULL );
1330
// account for the horz scrollbar offset
1331
dc.SetDeviceOrigin( -x * xpix, 0 );
1334
void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1336
wxAutoBufferedPaintDC dc( this );
1339
int x = HEADER_OFFSET_X;
1341
// width and height of the entire header window
1343
GetClientSize( &w, &h );
1344
m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1345
dc.SetBackgroundMode(wxTRANSPARENT);
1347
#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1348
int numColumns = GetColumnCount();
1349
for ( int i = 0; i < numColumns && x < w; i++ )
1351
if (!IsColumnShown (i)) continue; // do next column if not shown
1353
wxHeaderButtonParams params;
1355
// TODO: columnInfo should have label colours...
1356
params.m_labelColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
1357
params.m_labelFont = GetFont();
1359
wxTreeListColumnInfo& column = GetColumn(i);
1360
int wCol = column.GetWidth();
1362
wxRect rect(x, 0, wCol, h);
1365
if ( i == m_hotTrackCol)
1366
flags |= wxCONTROL_CURRENT;
1368
params.m_labelText = column.GetText();
1369
params.m_labelAlignment = column.GetAlignment();
1371
int image = column.GetImage();
1372
wxImageList* imageList = m_owner->GetImageList();
1373
if ((image != -1) && imageList)
1374
params.m_labelBitmap = imageList->GetBitmap(image);
1376
wxRendererNative::Get().DrawHeaderButton(this, dc, rect, flags, wxHDR_SORT_ICON_NONE, ¶ms);
1380
wxRect rect(x, 0, w-x, h);
1381
wxRendererNative::Get().DrawHeaderButton(this, dc, rect);
1384
#else // not 2.7.0.1+
1386
dc.SetFont( GetFont() );
1388
// do *not* use the listctrl colour for headers - one day we will have a
1389
// function to set it separately
1390
//dc.SetTextForeground( *wxBLACK );
1391
#if !wxCHECK_VERSION(2, 5, 0)
1392
dc.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
1394
dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ));
1397
int numColumns = GetColumnCount();
1398
for ( int i = 0; i < numColumns && x < w; i++ )
1400
if (!IsColumnShown (i)) continue; // do next column if not shown
1402
wxTreeListColumnInfo& column = GetColumn(i);
1403
int wCol = column.GetWidth();
1405
// the width of the rect to draw: make it smaller to fit entirely
1406
// inside the column rect
1409
#if !wxCHECK_VERSION(2, 7, 0)
1410
dc.SetPen( *wxWHITE_PEN );
1411
DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
1413
wxRect rect(x, HEADER_OFFSET_Y, cw, h-2);
1414
wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
1417
// if we have an image, draw it on the right of the label
1418
int image = column.GetImage(); //item.m_image;
1419
int ix = -2, iy = 0;
1420
wxImageList* imageList = m_owner->GetImageList();
1421
if ((image != -1) && imageList) {
1422
imageList->GetSize (image, ix, iy);
1425
// extra margins around the text label
1428
int image_offset = cw - ix - 1;
1430
switch(column.GetAlignment()) {
1432
text_x += EXTRA_WIDTH;
1436
dc.GetTextExtent (column.GetText(), &text_width, NULL);
1437
text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
1440
case wxALIGN_CENTER:
1441
dc.GetTextExtent(column.GetText(), &text_width, NULL);
1442
text_x += (cw - text_width)/2 + ix + 2;
1443
image_offset = (cw - text_width - ix - 2)/2 - MARGIN;
1448
if ((image != -1) && imageList) {
1449
imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/,
1450
HEADER_OFFSET_Y + (h - 4 - iy)/2,
1451
wxIMAGELIST_DRAW_TRANSPARENT);
1454
// draw the text clipping it so that it doesn't overwrite the column boundary
1455
wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
1456
dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT );
1462
int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
1464
#if !wxCHECK_VERSION(2, 7, 0)
1465
DoDrawRect (&dc, x, HEADER_OFFSET_Y, more_w, h-2 );
1467
wxRect rect (x, HEADER_OFFSET_Y, more_w, h-2);
1468
wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
1475
void wxTreeListHeaderWindow::DrawCurrent()
1477
int x1 = m_currentX;
1479
ClientToScreen (&x1, &y1);
1481
int x2 = m_currentX-1;
1483
++x2; // but why ????
1486
m_owner->GetClientSize( NULL, &y2 );
1487
m_owner->ClientToScreen( &x2, &y2 );
1490
dc.SetLogicalFunction (wxINVERT);
1491
dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID));
1492
dc.SetBrush (*wxTRANSPARENT_BRUSH);
1495
dc.DrawLine (x1, y1, x2, y2);
1496
dc.SetLogicalFunction (wxCOPY);
1497
dc.SetPen (wxNullPen);
1498
dc.SetBrush (wxNullBrush);
1501
#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1502
int wxTreeListHeaderWindow::XToCol(int x)
1505
int numColumns = GetColumnCount();
1506
for ( int col = 0; col < numColumns; col++ )
1508
if (!IsColumnShown(col)) continue;
1509
wxTreeListColumnInfo& column = GetColumn(col);
1511
if ( x < (colLeft + column.GetWidth()) )
1514
colLeft += column.GetWidth();
1519
void wxTreeListHeaderWindow::RefreshColLabel(int col)
1521
if ( col > GetColumnCount() )
1528
if (!IsColumnShown(idx)) continue;
1529
wxTreeListColumnInfo& column = GetColumn(idx);
1531
width = column.GetWidth();
1532
} while (++idx <= col);
1534
m_owner->CalcScrolledPosition(x, 0, &x, NULL);
1535
RefreshRect(wxRect(x, 0, width, GetSize().GetHeight()));
1539
void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
1541
// we want to work with logical coords
1543
m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1545
#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1546
if ( event.Moving() )
1548
int col = XToCol(x);
1549
if ( col != m_hotTrackCol )
1551
// Refresh the col header so it will be painted with hot tracking
1552
// (if supported by the native renderer.)
1553
RefreshColLabel(col);
1555
// Also refresh the old hot header
1556
if ( m_hotTrackCol >= 0 )
1557
RefreshColLabel(m_hotTrackCol);
1559
m_hotTrackCol = col;
1563
if ( event.Leaving() && m_hotTrackCol >= 0 )
1565
// Leaving the window so clear any hot tracking indicator that may be present
1566
RefreshColLabel(m_hotTrackCol);
1573
SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
1575
// we don't draw the line beyond our window, but we allow dragging it
1578
GetClientSize( &w, NULL );
1579
m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1582
// erase the line if it was drawn
1583
if (m_currentX < w) DrawCurrent();
1585
if (event.ButtonUp()) {
1586
m_isDragging = false;
1587
if (HasCapture()) ReleaseMouse();
1589
SetColumnWidth (m_column, m_currentX - m_minX);
1591
SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
1593
m_currentX = wxMax (m_minX + 7, x);
1595
// draw in the new location
1596
if (m_currentX < w) DrawCurrent();
1599
}else{ // not dragging
1602
bool hit_border = false;
1604
// end of the current column
1607
// find the column where this event occured
1608
int countCol = GetColumnCount();
1609
for (int column = 0; column < countCol; column++) {
1610
if (!IsColumnShown (column)) continue; // do next if not shown
1612
xpos += GetColumnWidth (column);
1614
if (abs (x-xpos) < 3) {
1615
// near the column border
1621
// inside the column
1628
if (event.LeftDown() || event.RightUp()) {
1629
m_owner->EndEdit(true); // cancelled
1631
if (hit_border && event.LeftDown()) {
1632
m_isDragging = true;
1636
SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
1637
}else{ // click on a column
1638
wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
1639
wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
1640
SendListEvent (evt, event.GetPosition());
1642
}else if (event.LeftDClick() && hit_border) {
1643
SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
1646
}else if (event.Moving()) {
1649
setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1650
m_currentCursor = m_resizeCursor;
1652
setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1653
m_currentCursor = wxSTANDARD_CURSOR;
1655
if (setCursor) SetCursor (*m_currentCursor);
1661
void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
1662
m_owner->SetFocus();
1665
void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
1666
wxWindow *parent = GetParent();
1667
wxListEvent le (type, parent->GetId());
1668
le.SetEventObject (parent);
1669
le.m_pointDrag = pos;
1671
// the position should be relative to the parent window, not
1672
// this one for compatibility with MSW and common sense: the
1673
// user code doesn't know anything at all about this header
1674
// window, so why should it get positions relative to it?
1675
le.m_pointDrag.y -= GetSize().y;
1676
le.m_col = m_column;
1677
parent->GetEventHandler()->ProcessEvent (le);
1680
void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
1681
m_columns.Add (colInfo);
1682
m_total_col_width += colInfo.GetWidth();
1683
m_owner->AdjustMyScrollbars();
1684
m_owner->m_dirty = true;
1687
void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
1688
wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1689
m_total_col_width -= m_columns[column].GetWidth();
1690
m_columns[column].SetWidth(width);
1691
m_total_col_width += width;
1692
m_owner->AdjustMyScrollbars();
1693
m_owner->m_dirty = true;
1696
void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
1697
wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
1698
m_columns.Insert (colInfo, before);
1699
m_total_col_width += colInfo.GetWidth();
1700
m_owner->AdjustMyScrollbars();
1701
m_owner->m_dirty = true;
1704
void wxTreeListHeaderWindow::RemoveColumn (int column) {
1705
wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1706
m_total_col_width -= m_columns[column].GetWidth();
1707
m_columns.RemoveAt (column);
1708
m_owner->AdjustMyScrollbars();
1709
m_owner->m_dirty = true;
1712
void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
1713
wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1714
int w = m_columns[column].GetWidth();
1715
m_columns[column] = info;
1716
if (w != info.GetWidth()) {
1717
m_total_col_width += info.GetWidth() - w;
1718
m_owner->AdjustMyScrollbars();
1720
m_owner->m_dirty = true;
1723
// ---------------------------------------------------------------------------
1725
// ---------------------------------------------------------------------------
1727
wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
1728
wxTreeListItem *parent,
1729
const wxArrayString& text,
1730
int image, int selImage,
1731
wxTreeItemData *data)
1734
m_images[wxTreeItemIcon_Normal] = image;
1735
m_images[wxTreeItemIcon_Selected] = selImage;
1736
m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
1737
m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
1739
m_props_row.m_data = data;
1745
m_isCollapsed = true;
1746
m_hasHilight = false;
1752
// We don't know the height here yet.
1757
wxTreeListItem::~wxTreeListItem() {
1758
if (m_toolTip) delete m_toolTip;
1760
wxTreeListItemCellAttrHash::iterator entry = m_props_cell.begin();
1761
while (entry != m_props_cell.end()) {
1762
if (entry->second) delete entry->second;
1766
wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1769
void wxTreeListItem::DeleteChildren () {
1773
size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
1774
size_t count = m_children.Count();
1775
if (!recursively) return count;
1777
size_t total = count;
1778
for (size_t n = 0; n < count; ++n) {
1779
total += m_children[n]->GetChildrenCount();
1784
void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
1785
int bottomY = m_y + theButton->GetLineHeight (this);
1786
if (y < bottomY) y = bottomY;
1787
int width = m_x + m_width;
1788
if ( x < width ) x = width;
1791
size_t count = m_children.Count();
1792
for (size_t n = 0; n < count; ++n ) {
1793
m_children[n]->GetSize (x, y, theButton);
1798
wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
1799
const wxTreeListMainWindow *theCtrl,
1800
int &flags, int& column, int level) {
1802
// reset any previous hit infos
1806
// for a hidden root node, don't evaluate it, but do evaluate children
1807
if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
1809
wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
1811
// check for right of all columns (outside)
1812
if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
1814
for (int x = 0, j = 0; j < theCtrl->GetColumnCount(); ++j) {
1815
if (!header_win->IsColumnShown(j)) continue;
1816
int w = header_win->GetColumnWidth (j);
1817
if (point.x >= x && point.x < x+w) {
1824
// evaluate if y-pos is okay
1825
int h = theCtrl->GetLineHeight (this);
1826
if ((point.y >= m_y) && (point.y <= m_y + h)) {
1828
// check for above/below middle
1829
int y_mid = m_y + h/2;
1830
if (point.y < y_mid) {
1831
flags |= wxTREE_HITTEST_ONITEMUPPERPART;
1833
flags |= wxTREE_HITTEST_ONITEMLOWERPART;
1836
// check for button hit
1837
if (HasPlus() && theCtrl->HasButtons()) {
1838
int bntX = m_x - theCtrl->m_btnWidth2;
1839
int bntY = y_mid - theCtrl->m_btnHeight2;
1840
if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
1841
(point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
1842
flags |= wxTREE_HITTEST_ONITEMBUTTON;
1847
// check for image hit
1848
if (theCtrl->m_imgWidth > 0) {
1849
int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
1850
int imgY = y_mid - theCtrl->m_imgHeight2;
1851
if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
1852
(point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
1853
flags |= wxTREE_HITTEST_ONITEMICON;
1858
// check for label hit
1859
if ((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) {
1860
flags |= wxTREE_HITTEST_ONITEMLABEL;
1864
// check for indent hit after button and image hit
1865
if (point.x < m_x) {
1866
flags |= wxTREE_HITTEST_ONITEMINDENT;
1867
// Ronan, 2008.07.17: removed, not consistent column = -1; // considered not belonging to main column
1871
// check for right of label
1873
for (int i = 0; i <= theCtrl->GetMainColumn(); ++i) end += header_win->GetColumnWidth (i);
1874
if ((point.x > (m_text_x + m_width)) && (point.x <= end)) {
1875
flags |= wxTREE_HITTEST_ONITEMRIGHT;
1876
// Ronan, 2008.07.17: removed, not consistent column = -1; // considered not belonging to main column
1880
// else check for each column except main
1881
if (column >= 0 && column != theCtrl->GetMainColumn()) {
1882
flags |= wxTREE_HITTEST_ONITEMCOLUMN;
1886
// no special flag or column found
1891
// if children not expanded, return no item
1892
if (!IsExpanded()) return (wxTreeListItem*) NULL;
1895
// in any case evaluate children
1896
wxTreeListItem *child;
1897
size_t count = m_children.Count();
1898
for (size_t n = 0; n < count; n++) {
1899
child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
1900
if (child) return child;
1904
return (wxTreeListItem*) NULL;
1907
int wxTreeListItem::GetCurrentImage() const {
1908
int image = NO_IMAGE;
1911
image = GetImage (wxTreeItemIcon_SelectedExpanded);
1913
image = GetImage (wxTreeItemIcon_Expanded);
1915
}else{ // not expanded
1917
image = GetImage (wxTreeItemIcon_Selected);
1919
image = GetImage (wxTreeItemIcon_Normal);
1923
// maybe it doesn't have the specific image, try the default one instead
1924
if (image == NO_IMAGE) image = GetImage();
1929
// ---------------------------------------------------------------------------
1930
// wxTreeListMainWindow implementation
1931
// ---------------------------------------------------------------------------
1933
IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
1935
BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
1936
EVT_PAINT (wxTreeListMainWindow::OnPaint)
1937
EVT_ERASE_BACKGROUND(wxTreeListMainWindow::OnEraseBackground) // to reduce flicker
1938
EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse)
1939
EVT_KEY_DOWN (wxTreeListMainWindow::OnChar)
1940
EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus)
1941
EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus)
1942
EVT_IDLE (wxTreeListMainWindow::OnIdle)
1943
EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll)
1944
EVT_MOUSE_CAPTURE_LOST(wxTreeListMainWindow::OnCaptureLost)
1948
// ---------------------------------------------------------------------------
1949
// construction/destruction
1950
// ---------------------------------------------------------------------------
1953
void wxTreeListMainWindow::Init() {
1955
m_rootItem = (wxTreeListItem*)NULL;
1956
m_curItem = (wxTreeListItem*)NULL;
1957
m_shiftItem = (wxTreeListItem*)NULL;
1958
m_editItem = (wxTreeListItem*)NULL;
1959
m_selectItem = (wxTreeListItem*)NULL;
1961
m_curColumn = -1; // no current column
1966
m_lineHeight = LINEHEIGHT;
1967
m_indent = MININDENT; // min. indent
1970
#if !wxCHECK_VERSION(2, 5, 0)
1971
m_hilightBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1972
m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1974
m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1975
m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1978
m_imageListNormal = (wxImageList *) NULL;
1979
m_imageListButtons = (wxImageList *) NULL;
1980
m_imageListState = (wxImageList *) NULL;
1981
m_ownsImageListNormal = m_ownsImageListButtons =
1982
m_ownsImageListState = false;
1984
m_imgWidth = 0, m_imgWidth2 = 0;
1985
m_imgHeight = 0, m_imgHeight2 = 0;
1986
m_btnWidth = 0, m_btnWidth2 = 0;
1987
m_btnHeight = 0, m_btnHeight2 = 0;
1989
m_isDragStarted = m_isDragging = false;
1993
m_editTimer = new wxTreeListRenameTimer (this);
1994
m_editControl = NULL;
1996
m_lastOnSame = false;
1997
m_left_down_selection = false;
1999
m_findTimer = new wxTimer (this, -1);
2001
#if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
2002
m_normalFont.MacCreateThemeFont (kThemeViewsFont);
2004
m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
2006
m_boldFont = wxFont( m_normalFont.GetPointSize(),
2007
m_normalFont.GetFamily(),
2008
m_normalFont.GetStyle(),
2010
m_normalFont.GetUnderlined(),
2011
m_normalFont.GetFaceName(),
2012
m_normalFont.GetEncoding());
2015
m_toolTipItem = (wxTreeListItem *)-1; // no tooltip displayed
2016
m_isItemToolTip = false; // so far no item-specific tooltip
2019
bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
2024
const wxValidator &validator,
2025
const wxString& name) {
2028
//if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
2029
if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
2030
style &= ~wxTR_LINES_AT_ROOT;
2031
style |= wxTR_NO_LINES;
2034
wxGetOsVersion( &major, &minor );
2035
if (major < 10) style |= wxTR_ROW_LINES;
2038
wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
2040
#if wxUSE_VALIDATORS
2041
SetValidator(validator);
2044
#if !wxCHECK_VERSION(2, 5, 0)
2045
SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX));
2047
SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
2049
// prevent any background repaint in order to reducing flicker
2050
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
2057
bdc.SelectObject(bmp);
2058
bdc.SetPen(*wxGREY_PEN);
2059
bdc.DrawRectangle(-1, -1, 10, 10);
2060
for (i = 0; i < 8; i++) {
2061
for (j = 0; j < 8; j++) {
2062
if (!((i + j) & 1)) {
2063
bdc.DrawPoint(i, j);
2068
m_dottedPen = wxPen(bmp, 1);
2071
//? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
2072
m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
2081
wxTreeListMainWindow::~wxTreeListMainWindow() {
2082
delete m_hilightBrush;
2083
delete m_hilightUnfocusedBrush;
2087
if (m_ownsImageListNormal) delete m_imageListNormal;
2088
if (m_ownsImageListState) delete m_imageListState;
2089
if (m_ownsImageListButtons) delete m_imageListButtons;
2091
if (m_editControl) {
2092
m_editControl->SetOwner(NULL); // prevent control from calling us during delete
2093
delete m_editControl;
2100
//-----------------------------------------------------------------------------
2102
//-----------------------------------------------------------------------------
2104
size_t wxTreeListMainWindow::GetCount() const {
2105
return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
2108
void wxTreeListMainWindow::SetIndent (unsigned int indent) {
2109
m_indent = wxMax ((unsigned)MININDENT, indent);
2113
void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
2114
m_linespacing = spacing;
2116
CalculateLineHeight();
2119
size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
2121
wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
2122
return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
2125
void wxTreeListMainWindow::SetWindowStyle (const long styles) {
2126
// change to selection mode, reset selection
2127
if ((styles ^ m_windowStyle) & wxTR_MULTIPLE) { UnselectAll(); }
2128
// right now, just sets the styles. Eventually, we may
2129
// want to update the inherited styles, but right now
2130
// none of the parents has updatable styles
2131
m_windowStyle = styles;
2135
void wxTreeListMainWindow::SetToolTip(const wxString& tip) {
2136
m_isItemToolTip = false;
2138
m_toolTipItem = (wxTreeListItem *)-1; // no tooltip displayed (force refresh)
2140
void wxTreeListMainWindow::SetToolTip(wxToolTip *tip) {
2141
m_isItemToolTip = false;
2142
m_toolTip = (tip == NULL) ? wxString() : tip->GetTip();
2143
m_toolTipItem = (wxTreeListItem *)-1; // no tooltip displayed (force refresh)
2146
void wxTreeListMainWindow::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
2147
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2148
m_isItemToolTip = true;
2149
((wxTreeListItem*) item.m_pItem)->SetToolTip(tip);
2150
m_toolTipItem = (wxTreeListItem *)-1; // no tooltip displayed (force refresh)
2154
//-----------------------------------------------------------------------------
2155
// functions to work with tree items
2156
//-----------------------------------------------------------------------------
2158
int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column, wxTreeItemIcon which) const {
2159
wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
2160
return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
2163
wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
2164
wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
2165
return ((wxTreeListItem*) item.m_pItem)->GetData();
2167
wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item, int column) const {
2168
wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
2169
return ((wxTreeListItem*) item.m_pItem)->GetData(column);
2172
bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
2173
wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
2174
return ((wxTreeListItem *)item.m_pItem)->IsBold();
2176
bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item, int column) const {
2177
wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
2178
return ((wxTreeListItem *)item.m_pItem)->IsBold(column);
2181
wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
2182
wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2183
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2184
wxTreeItemAttr *attr = pItem->GetAttributes();
2185
if (attr && attr->HasTextColour()) {
2186
return attr->GetTextColour();
2188
return GetForegroundColour();
2191
wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item, int column) const {
2192
wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2193
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2194
wxTreeItemAttr *attr = pItem->GetAttributes(column);
2195
if (attr && attr->HasTextColour()) {
2196
return attr->GetTextColour();
2198
return GetItemTextColour(item);
2202
wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
2203
wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2204
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2205
wxTreeItemAttr *attr = pItem->GetAttributes();
2206
if (attr && attr->HasBackgroundColour()) {
2207
return attr->GetBackgroundColour();
2209
return GetBackgroundColour();
2212
wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item, int column) const {
2213
wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2214
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2215
wxTreeItemAttr *attr = pItem->GetAttributes(column);
2216
if (attr && attr->HasBackgroundColour()) {
2217
return attr->GetBackgroundColour();
2219
return GetItemBackgroundColour(item);
2223
wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
2224
wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
2225
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2226
wxTreeItemAttr *attr = pItem->GetAttributes();
2227
if (attr && attr->HasFont()) {
2228
return attr->GetFont();
2229
}else if (pItem->IsBold()) {
2232
return m_normalFont;
2235
wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item, int column) const {
2236
wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
2237
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2238
wxTreeItemAttr *attr_cell = pItem->GetAttributes(column);
2239
wxTreeItemAttr *attr_row = pItem->GetAttributes();
2240
if (attr_cell && attr_cell->HasFont()) {
2241
return attr_cell->GetFont();
2242
} else if (attr_row && attr_row->HasFont()) {
2243
return attr_row->GetFont();
2244
} else if (pItem->IsBold(column)) {
2247
return m_normalFont;
2251
void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item, bool has) {
2252
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2253
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2254
pItem->SetHasPlus (has);
2255
RefreshLine (pItem);
2258
void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column, int image, wxTreeItemIcon which) {
2259
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2260
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2261
pItem->SetImage (column, image, which);
2262
wxClientDC dc (this);
2263
CalculateSize (pItem, dc);
2264
RefreshLine (pItem);
2267
void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item, wxTreeItemData *data) {
2268
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2269
((wxTreeListItem*) item.m_pItem)->SetData(data);
2271
void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item, int column, wxTreeItemData *data) {
2272
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2273
((wxTreeListItem*) item.m_pItem)->SetData(column, data);
2276
void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, bool bold) {
2277
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2278
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2279
if (pItem->IsBold() != bold) { // avoid redrawing if no real change
2280
pItem->SetBold (bold);
2281
RefreshLine (pItem);
2284
void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, int column, bool bold) {
2285
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2286
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2287
// if (pItem->IsBold(column) != bold) { // avoid redrawing if no real change
2288
pItem->SetBold (column, bold);
2289
RefreshLine (pItem);
2293
void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item, const wxColour& colour) {
2294
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2295
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2296
pItem->Attr().SetTextColour (colour);
2297
RefreshLine (pItem);
2299
void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item, int column, const wxColour& colour) {
2300
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2301
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2302
pItem->Attr(column).SetTextColour (colour);
2303
RefreshLine (pItem);
2306
void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item, const wxColour& colour) {
2307
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2308
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2309
pItem->Attr().SetBackgroundColour (colour);
2310
RefreshLine (pItem);
2312
void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item, int column, const wxColour& colour) {
2313
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2314
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2315
pItem->Attr(column).SetBackgroundColour (colour);
2316
RefreshLine (pItem);
2319
void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item, const wxFont& font) {
2320
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2321
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2322
pItem->Attr().SetFont (font);
2323
RefreshLine (pItem);
2325
void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item, int column, const wxFont& font) {
2326
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2327
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2328
pItem->Attr(column).SetFont (font);
2329
RefreshLine (pItem);
2333
bool wxTreeListMainWindow::SetFont (const wxFont &font) {
2334
wxScrolledWindow::SetFont (font);
2335
m_normalFont = font;
2336
m_boldFont = wxFont (m_normalFont.GetPointSize(),
2337
m_normalFont.GetFamily(),
2338
m_normalFont.GetStyle(),
2340
m_normalFont.GetUnderlined(),
2341
m_normalFont.GetFaceName());
2342
CalculateLineHeight();
2347
// ----------------------------------------------------------------------------
2348
// item status inquiries
2349
// ----------------------------------------------------------------------------
2351
bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2352
wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2354
// An item is only visible if it's not a descendant of a collapsed item
2355
wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2356
wxTreeListItem* parent = pItem->GetItemParent();
2358
if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
2359
if (!parent->IsExpanded()) return false;
2360
parent = parent->GetItemParent();
2363
// and the item is only visible if it is currently (fully) within the view
2365
wxSize clientSize = GetClientSize();
2367
if ((!GetBoundingRect (item, rect)) ||
2368
((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
2369
(rect.GetTop() < 0 || rect.GetBottom() >= clientSize.y) ||
2370
(!fullRow && (rect.GetLeft() < 0 || rect.GetRight() >= clientSize.x))) return false;
2376
bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
2377
wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2379
// consider that the item does have children if it has the "+" button: it
2380
// might not have them (if it had never been expanded yet) but then it
2381
// could have them as well and it's better to err on this side rather than
2382
// disabling some operations which are restricted to the items with
2383
// children for an item which does have them
2384
return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2387
bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2388
wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2389
return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2392
bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2393
wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2394
return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2397
bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item, int column) const {
2398
wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2399
return ((wxTreeListItem*) item.m_pItem)->IsBold(column);
2402
// ----------------------------------------------------------------------------
2404
// ----------------------------------------------------------------------------
2406
wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2407
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2408
return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
2411
#if !wxCHECK_VERSION(2, 5, 0)
2412
wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2413
long& cookie) const {
2415
wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2416
wxTreeItemIdValue& cookie) const {
2418
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2419
wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2421
return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
2424
#if !wxCHECK_VERSION(2, 5, 0)
2425
wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2426
long& cookie) const {
2428
wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2429
wxTreeItemIdValue& cookie) const {
2431
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2432
wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2433
// it's ok to cast cookie to long, we never have indices which overflow "void*"
2434
long *pIndex = ((long*)&cookie);
2435
return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
2438
#if !wxCHECK_VERSION(2, 5, 0)
2439
wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2440
long& cookie) const {
2442
wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2443
wxTreeItemIdValue& cookie) const {
2445
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2446
wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2447
// it's ok to cast cookie to long, we never have indices which overflow "void*"
2448
long *pIndex = (long*)&cookie;
2449
return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
2452
#if !wxCHECK_VERSION(2, 5, 0)
2453
wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2454
long& cookie) const {
2456
wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2457
wxTreeItemIdValue& cookie) const {
2459
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2460
wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2461
// it's ok to cast cookie to long, we never have indices which overflow "void*"
2462
long *pIndex = ((long*)&cookie);
2463
(*pIndex) = (long)children.Count();
2464
return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
2467
wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2468
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2471
wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2472
wxTreeListItem *parent = i->GetItemParent();
2473
if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2476
wxArrayTreeListItems& siblings = parent->GetChildren();
2477
size_t index = siblings.Index (i);
2478
wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2479
return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
2482
wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2483
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2486
wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2487
wxTreeListItem *parent = i->GetItemParent();
2488
if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2491
wxArrayTreeListItems& siblings = parent->GetChildren();
2492
size_t index = siblings.Index(i);
2493
wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2494
return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
2497
// Only for internal use right now, but should probably be public
2498
wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2499
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2501
// if there are any children, return first child
2502
if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2503
wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2504
if (children.GetCount() > 0) return children.Item (0);
2507
// get sibling of this item or of the ancestors instead
2509
wxTreeItemId parent = item;
2511
next = GetNextSibling (parent);
2512
parent = GetItemParent (parent);
2513
} while (!next.IsOk() && parent.IsOk());
2517
// Only for internal use right now, but should probably be public
2518
wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2519
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2521
// if there are no previous sibling get parent
2522
wxTreeItemId prev = GetPrevSibling (item);
2523
if (! prev.IsOk()) return GetItemParent (item);
2525
// while previous sibling has children, return last
2526
while (fulltree || ((wxTreeListItem*)prev.m_pItem)->IsExpanded()) {
2527
wxArrayTreeListItems& children = ((wxTreeListItem*)prev.m_pItem)->GetChildren();
2528
if (children.GetCount() == 0) break;
2529
prev = children.Item (children.GetCount() - 1);
2535
wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2536
return GetNextExpanded (GetRootItem());
2539
wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2540
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2541
return GetNext (item, false);
2544
wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2545
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2546
return GetPrev (item, false);
2549
wxTreeItemId wxTreeListMainWindow::GetFirstVisible(bool fullRow, bool within) const {
2550
if (HasFlag(wxTR_HIDE_ROOT) || ! IsVisible(GetRootItem(), fullRow, within)) {
2551
return GetNextVisible (GetRootItem(), fullRow, within);
2553
return GetRootItem();
2557
wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2558
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2559
wxTreeItemId id = GetNext (item, false);
2561
if (IsVisible (id, fullRow, within)) return id;
2562
id = GetNext (id, false);
2564
return wxTreeItemId();
2567
wxTreeItemId wxTreeListMainWindow::GetLastVisible ( bool fullRow, bool within) const {
2568
wxCHECK_MSG (GetRootItem().IsOk(), wxTreeItemId(), _T("invalid tree item"));
2569
wxTreeItemId id = GetRootItem();
2570
wxTreeItemId res = id;
2571
while ((id = GetNext (id, false)).IsOk()) {
2572
if (IsVisible (id, fullRow, within)) res = id;
2577
wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2578
wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2579
wxTreeItemId id = GetPrev (item, true);
2581
if (IsVisible (id, fullRow, within)) return id;
2582
id = GetPrev(id, true);
2584
return wxTreeItemId();
2587
// ----------------------------------------------------------------------------
2589
// ----------------------------------------------------------------------------
2591
// ---------------------------- ADD OPERATION -------------------------------
2593
wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2595
const wxString& text,
2596
int image, int selImage,
2597
wxTreeItemData *data) {
2598
wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2599
wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2600
m_dirty = true; // do this first so stuff below doesn't cause flicker
2603
arr.Alloc (GetColumnCount());
2604
for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2605
arr[m_main_column] = text;
2606
wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2608
#if !wxCHECK_VERSION(2, 5, 0)
2609
data->SetId ((long)item);
2614
parent->Insert (item, previous);
2619
wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2620
int image, int selImage,
2621
wxTreeItemData *data) {
2622
wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2623
wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2624
m_dirty = true; // do this first so stuff below doesn't cause flicker
2627
arr.Alloc (GetColumnCount());
2628
for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2629
arr[m_main_column] = text;
2630
m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2632
#if !wxCHECK_VERSION(2, 5, 0)
2633
data->SetId((long)m_rootItem);
2635
data->SetId(m_rootItem);
2638
if (HasFlag(wxTR_HIDE_ROOT)) {
2639
// if we will hide the root, make sure children are visible
2640
m_rootItem->SetHasPlus();
2641
m_rootItem->Expand();
2642
#if !wxCHECK_VERSION(2, 5, 0)
2645
wxTreeItemIdValue cookie = 0;
2647
SetCurrentItem(GetFirstChild(m_rootItem, cookie));
2652
wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2653
const wxString& text,
2654
int image, int selImage,
2655
wxTreeItemData *data) {
2656
return DoInsertItem (parent, 0u, text, image, selImage, data);
2659
wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2660
const wxTreeItemId& idPrevious,
2661
const wxString& text,
2662
int image, int selImage,
2663
wxTreeItemData *data) {
2664
wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2665
wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2667
int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2668
wxASSERT_MSG( index != wxNOT_FOUND,
2669
_T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2671
return DoInsertItem (parentId, ++index, text, image, selImage, data);
2674
wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2676
const wxString& text,
2677
int image, int selImage,
2678
wxTreeItemData *data) {
2679
wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2680
wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2682
return DoInsertItem (parentId, before, text, image, selImage, data);
2685
wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2686
const wxString& text,
2687
int image, int selImage,
2688
wxTreeItemData *data) {
2689
wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
2690
wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2692
return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
2696
// -------------------------- DELETE OPERATION ------------------------------
2698
void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
2699
if (! itemId.IsOk()) return;
2700
wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2701
wxTreeListItem *parent = item->GetItemParent();
2702
wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2707
// update parent --CAUTION: must come after delete itself, so that item's
2708
// siblings may be found
2710
parent->GetChildren().Remove (item); // remove by value
2715
void wxTreeListMainWindow::DeleteRoot() {
2716
if (! m_rootItem) return;
2718
SetCurrentItem((wxTreeListItem*)NULL);
2719
m_selectItem = (wxTreeListItem*)NULL;
2720
m_shiftItem = (wxTreeListItem*)NULL;
2722
DeleteChildren (m_rootItem);
2723
SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, m_rootItem);
2724
delete m_rootItem; m_rootItem = NULL;
2728
void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2729
if (! itemId.IsOk()) return;
2730
wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2732
// recursive delete on all children, starting from the right to prevent
2733
// multiple selection changes (see m_curItem handling in DoDeleteItem() )
2734
wxArrayTreeListItems& children = item->GetChildren();
2735
for (size_t n = children.GetCount(); n>0; n--) {
2736
DoDeleteItem(children[n-1]);
2737
// immediately remove child from array, otherwise it might get selected
2738
// as current item (see m_curItem handling in DoDeleteItem() )
2739
children.RemoveAt(n-1);
2744
void wxTreeListMainWindow::DoDeleteItem(wxTreeListItem *item) {
2745
wxCHECK_RET (item, _T("invalid item for delete!"));
2747
m_dirty = true; // do this first so stuff below doesn't cause flicker
2749
// cancel any editing
2751
if (m_editControl) { m_editControl->EndEdit(true); } // cancelled
2753
// cancel any dragging
2754
if (item == m_dragItem) {
2756
m_isDragStarted = m_isDragging = false;
2757
if (HasCapture()) ReleaseMouse();
2760
// don't stay with invalid m_curItem: take next sibling or reset to NULL
2761
// NOTE: this might be slighty inefficient when deleting a whole tree
2762
// but has the advantage that all deletion side-effects are handled here
2763
if (item == m_curItem) {
2764
SetCurrentItem(item->GetItemParent());
2766
wxArrayTreeListItems& siblings = m_curItem->GetChildren();
2767
size_t index = siblings.Index (item);
2768
wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2769
SetCurrentItem(index < siblings.Count()-1 ? siblings[index+1]: (wxTreeListItem*)NULL);
2772
// don't stay with invalid m_shiftItem: reset it to NULL
2773
if (item == m_shiftItem) m_shiftItem = (wxTreeListItem*)NULL;
2774
// don't stay with invalid m_selectItem: default to current item
2775
if (item == m_selectItem) {
2776
m_selectItem = m_curItem;
2777
SelectItem(m_selectItem, (wxTreeItemId*)NULL, true); // unselect others
2780
// recurse children, starting from the right to prevent multiple selection
2781
// changes (see m_curItem handling above)
2782
wxArrayTreeListItems& children = item->GetChildren();
2783
for (size_t n = children.GetCount(); n>0; n--) {
2784
DoDeleteItem(children[n-1]);
2785
// immediately remove child from array, otherwise it might get selected
2786
// as current item (see m_curItem handling above)
2787
children.RemoveAt(n-1);
2790
// delete item itself
2791
SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, item);
2796
// ----------------------------------------------------------------------------
2798
void wxTreeListMainWindow::SetCurrentItem(const wxTreeItemId& itemId) {
2799
SetCurrentItem((wxTreeListItem *)(itemId ? itemId.m_pItem : NULL));
2801
void wxTreeListMainWindow::SetCurrentItem(wxTreeListItem *item) {
2802
wxTreeListItem *old_item;
2804
old_item = m_curItem; m_curItem = item;
2806
// change of item, redraw previous
2807
if (old_item != NULL && old_item != item) {
2808
RefreshLine(old_item);
2813
// ----------------------------------------------------------------------------
2815
void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
2816
wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2817
wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
2819
if (!item->HasPlus() || item->IsExpanded()) return;
2821
// send event to user code
2822
wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, 0);
2823
event.SetInt(m_curColumn);
2824
if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // expand canceled
2829
// send event to user code
2830
event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2831
SendEvent(0, NULL, &event);
2834
void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2835
wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2838
if (!IsExpanded (itemId)) return;
2839
#if !wxCHECK_VERSION(2, 5, 0)
2842
wxTreeItemIdValue cookie;
2844
wxTreeItemId child = GetFirstChild (itemId, cookie);
2845
while (child.IsOk()) {
2847
child = GetNextChild (itemId, cookie);
2851
void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
2852
wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2853
wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
2855
if (!item->HasPlus() || !item->IsExpanded()) return;
2857
// send event to user code
2858
wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 0 );
2859
event.SetInt(m_curColumn);
2860
if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // collapse canceled
2865
// send event to user code
2866
event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2867
SendEvent(0, NULL, &event);
2870
void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2871
wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2874
DeleteChildren (item);
2877
void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2878
wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2880
if (IsExpanded (itemId)) {
2887
void wxTreeListMainWindow::Unselect() {
2889
m_selectItem->SetHilight (false);
2890
RefreshLine (m_selectItem);
2891
m_selectItem = (wxTreeListItem*)NULL;
2895
void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2896
wxCHECK_RET (item, _T("invalid tree item"));
2898
if (item->IsSelected()) {
2899
item->SetHilight (false);
2901
if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2902
if (item != m_curItem) m_lastOnSame = false; // selection change, so reset edit marker
2904
if (item->HasChildren()) {
2905
wxArrayTreeListItems& children = item->GetChildren();
2906
size_t count = children.Count();
2907
for (size_t n = 0; n < count; ++n) {
2908
UnselectAllChildren (children[n]);
2913
void wxTreeListMainWindow::UnselectAll() {
2914
UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
2917
// Recursive function !
2918
// To stop we must have crt_item<last_item
2920
// Tag all next children, when no more children,
2921
// Move to parent (not to tag)
2922
// Keep going... if we found last_item, we stop.
2923
bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem *crt_item,
2924
wxTreeListItem *last_item) {
2925
wxTreeListItem *parent = crt_item->GetItemParent();
2927
if (!parent) {// This is root item
2928
return TagAllChildrenUntilLast (crt_item, last_item);
2931
wxArrayTreeListItems& children = parent->GetChildren();
2932
int index = children.Index(crt_item);
2933
wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2935
if ((parent->HasChildren() && parent->IsExpanded()) ||
2936
((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2937
size_t count = children.Count();
2938
for (size_t n = (index+1); n < count; ++n) {
2939
if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2943
return TagNextChildren (parent, last_item);
2946
bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item,
2947
wxTreeListItem *last_item) {
2948
crt_item->SetHilight (true);
2949
RefreshLine(crt_item);
2951
if (crt_item==last_item) return true;
2953
if (crt_item->HasChildren() && crt_item->IsExpanded()) {
2954
wxArrayTreeListItems& children = crt_item->GetChildren();
2955
size_t count = children.Count();
2956
for (size_t n = 0; n < count; ++n) {
2957
if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2964
bool wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2965
const wxTreeItemId& lastId,
2966
bool unselect_others) {
2968
wxTreeListItem *item = itemId.IsOk() ? (wxTreeListItem*) itemId.m_pItem : NULL;
2970
// send selecting event to the user code
2971
wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
2972
event.SetInt(m_curColumn);
2973
#if !wxCHECK_VERSION(2, 5, 0)
2974
event.SetOldItem ((long)m_curItem);
2976
event.SetOldItem (m_curItem);
2978
if (SendEvent(0, item, &event) && !event.IsAllowed()) return false; // veto on selection change
2980
// unselect all if unselect other items
2981
bool bUnselectedAll = false; // see that UnselectAll is done only once
2982
if (unselect_others) {
2983
if (HasFlag(wxTR_MULTIPLE)) {
2984
UnselectAll(); bUnselectedAll = true;
2986
Unselect(); // to speed up thing
2990
// select item range
2991
if (lastId.IsOk() && itemId.IsOk() && (itemId != lastId)) {
2993
if (! bUnselectedAll) UnselectAll();
2994
wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
2996
// ensure that the position of the item it calculated in any case
2997
if (m_dirty) CalculatePositions();
2999
// select item range according Y-position
3000
if (last->GetY() < item->GetY()) {
3001
if (!TagAllChildrenUntilLast (last, item)) {
3002
TagNextChildren (last, item);
3005
if (!TagAllChildrenUntilLast (item, last)) {
3006
TagNextChildren (item, last);
3010
// or select single item
3011
}else if (itemId.IsOk()) {
3013
// select item according its old selection
3014
item->SetHilight (!item->IsSelected());
3016
if (unselect_others) {
3017
m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL;
3020
// or select nothing
3022
if (! bUnselectedAll) UnselectAll();
3025
// send event to user code
3026
event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
3027
SendEvent(0, NULL, &event);
3032
void wxTreeListMainWindow::SelectAll() {
3033
wxTreeItemId root = GetRootItem();
3034
wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
3035
wxCHECK_RET (root.IsOk(), _T("no tree"));
3037
// send event to user code
3038
wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
3039
#if !wxCHECK_VERSION(2, 5, 0)
3040
event.SetOldItem ((long)m_curItem);
3042
event.SetOldItem (m_curItem);
3044
event.SetInt (-1); // no colum clicked
3045
if (SendEvent(0, m_rootItem, &event) && !event.IsAllowed()) return; // selection change vetoed
3047
#if !wxCHECK_VERSION(2, 5, 0)
3050
wxTreeItemIdValue cookie = 0;
3052
wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
3053
wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
3054
if (!TagAllChildrenUntilLast (first, last)) {
3055
TagNextChildren (first, last);
3058
// send event to user code
3059
event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED);
3060
SendEvent(0, NULL, &event);
3063
void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
3064
wxArrayTreeItemIds &array) const {
3065
if (item->IsSelected()) array.Add (wxTreeItemId(item));
3067
if (item->HasChildren()) {
3068
wxArrayTreeListItems& children = item->GetChildren();
3069
size_t count = children.GetCount();
3070
for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
3074
size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
3076
wxTreeItemId idRoot = GetRootItem();
3077
if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
3078
return array.Count();
3081
void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
3082
if (!item.IsOk()) return; // do nothing if no item
3084
// first expand all parent branches
3085
wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
3086
wxTreeListItem *parent = gitem->GetItemParent();
3089
parent = parent->GetItemParent();
3093
RefreshLine (gitem);
3096
void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
3097
if (!item.IsOk()) return; // do nothing if no item
3099
// ensure that the position of the item it calculated in any case
3100
if (m_dirty) CalculatePositions();
3102
wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
3104
// now scroll to the item
3105
int item_y = gitem->GetY();
3108
GetScrollPixelsPerUnit (&xUnit, &yUnit);
3111
GetViewStart (&start_x, &start_y);
3116
GetClientSize (&client_w, &client_h);
3120
m_rootItem->GetSize (x, y, this);
3121
x = m_owner->GetHeaderWindow()->GetWidth();
3122
y += yUnit + 2; // one more scrollbar unit + 2 pixels
3123
int x_pos = GetScrollPos( wxHORIZONTAL );
3125
if (item_y < start_y+3) {
3126
// going down, item should appear at top
3127
SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
3128
}else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
3129
// going up, item should appear at bottom
3130
item_y += yUnit + 2;
3131
SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
3135
// TODO: tree sorting functions are not reentrant and not MT-safe!
3136
static wxTreeListMainWindow *s_treeBeingSorted = NULL;
3138
static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1, wxTreeListItem **item2)
3140
wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
3141
return s_treeBeingSorted->OnCompareItems(*item1, *item2);
3144
int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
3146
return (m_sortColumn == -1
3147
? m_owner->OnCompareItems (item1, item2)
3148
: (m_ReverseSortOrder
3149
? m_owner->OnCompareItems (item2, item1, m_sortColumn)
3150
: m_owner->OnCompareItems (item1, item2, m_sortColumn)
3155
void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId, int column, bool reverseOrder) {
3156
wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
3158
wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3160
wxCHECK_RET (!s_treeBeingSorted,
3161
_T("wxTreeListMainWindow::SortChildren is not reentrant") );
3163
wxArrayTreeListItems& children = item->GetChildren();
3164
if ( children.Count() > 1 ) {
3166
s_treeBeingSorted = this;
3167
m_sortColumn = column; // -1 indicates legacy mode
3168
m_ReverseSortOrder = reverseOrder;
3169
children.Sort(tree_ctrl_compare_func);
3170
s_treeBeingSorted = NULL;
3174
wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode) {
3176
// determine start item
3177
wxTreeItemId next = item;
3179
if (mode & wxTL_MODE_NAV_LEVEL) {
3180
next = GetNextSibling (next);
3181
}else if (mode & wxTL_MODE_NAV_VISIBLE) { //
3182
next = GetNextVisible (next, false, true);
3183
}else if (mode & wxTL_MODE_NAV_EXPANDED) {
3184
next = GetNextExpanded (next);
3185
}else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
3186
next = GetNext (next, true);
3190
#if !wxCHECK_VERSION(2, 5, 0)
3193
wxTreeItemIdValue cookie = 0;
3196
next = GetRootItem();
3197
if (next.IsOk() && HasFlag(wxTR_HIDE_ROOT)) {
3198
next = GetFirstChild (GetRootItem(), cookie);
3201
if (!next.IsOk()) return (wxTreeItemId*)NULL;
3203
// start checking the next items
3204
while (next.IsOk() && (next != item)) {
3205
if (mode & wxTL_MODE_FIND_PARTIAL) {
3206
itemText = GetItemText (next, column).Mid (0, str.Length());
3208
itemText = GetItemText (next, column);
3210
if (mode & wxTL_MODE_FIND_NOCASE) {
3211
if (itemText.CmpNoCase (str) == 0) return next;
3213
if (itemText.Cmp (str) == 0) return next;
3215
if (mode & wxTL_MODE_NAV_LEVEL) {
3216
next = GetNextSibling (next);
3217
}else if (mode & wxTL_MODE_NAV_VISIBLE) { //
3218
next = GetNextVisible (next, false, true);
3219
}else if (mode & wxTL_MODE_NAV_EXPANDED) {
3220
next = GetNextExpanded (next);
3221
}else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
3222
next = GetNext (next, true);
3224
if (!next.IsOk() && item.IsOk()) {
3225
next = (wxTreeListItem*)GetRootItem().m_pItem;
3226
if (HasFlag(wxTR_HIDE_ROOT)) {
3227
next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem;
3231
return (wxTreeItemId*)NULL;
3234
void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
3235
wxTreeListItem *prevItem = m_dragItem;
3236
m_dragItem = (wxTreeListItem*) item.m_pItem;
3237
if (prevItem) RefreshLine (prevItem);
3238
if (m_dragItem) RefreshLine (m_dragItem);
3241
void wxTreeListMainWindow::CalculateLineHeight() {
3242
wxClientDC dc (this);
3243
dc.SetFont (m_normalFont);
3244
m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
3246
if (m_imageListNormal) {
3247
// Calculate a m_lineHeight value from the normal Image sizes.
3248
// May be toggle off. Then wxTreeListMainWindow will spread when
3249
// necessary (which might look ugly).
3250
int n = m_imageListNormal->GetImageCount();
3251
for (int i = 0; i < n ; i++) {
3252
int width = 0, height = 0;
3253
m_imageListNormal->GetSize(i, width, height);
3254
if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
3258
if (m_imageListButtons) {
3259
// Calculate a m_lineHeight value from the Button image sizes.
3260
// May be toggle off. Then wxTreeListMainWindow will spread when
3261
// necessary (which might look ugly).
3262
int n = m_imageListButtons->GetImageCount();
3263
for (int i = 0; i < n ; i++) {
3264
int width = 0, height = 0;
3265
m_imageListButtons->GetSize(i, width, height);
3266
if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
3270
if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
3271
m_lineHeight += 2; // minimal 2 pixel space
3273
m_lineHeight += m_lineHeight / 10; // otherwise 10% space
3277
void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
3278
if (m_ownsImageListNormal) delete m_imageListNormal;
3279
m_imageListNormal = imageList;
3280
m_ownsImageListNormal = false;
3282
CalculateLineHeight();
3285
void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
3286
if (m_ownsImageListState) delete m_imageListState;
3287
m_imageListState = imageList;
3288
m_ownsImageListState = false;
3291
void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
3292
if (m_ownsImageListButtons) delete m_imageListButtons;
3293
m_imageListButtons = imageList;
3294
m_ownsImageListButtons = false;
3296
CalculateLineHeight();
3299
void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
3300
SetImageList(imageList);
3301
m_ownsImageListNormal = true;
3304
void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
3305
SetStateImageList(imageList);
3306
m_ownsImageListState = true;
3309
void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
3310
SetButtonsImageList(imageList);
3311
m_ownsImageListButtons = true;
3314
// ----------------------------------------------------------------------------
3316
// ----------------------------------------------------------------------------
3318
void wxTreeListMainWindow::AdjustMyScrollbars() {
3321
GetScrollPixelsPerUnit (&xUnit, &yUnit);
3322
if (xUnit == 0) xUnit = GetCharWidth();
3323
if (yUnit == 0) yUnit = m_lineHeight;
3325
m_rootItem->GetSize (x, y, this);
3326
y += yUnit + 2; // one more scrollbar unit + 2 pixels
3327
int x_pos = GetScrollPos (wxHORIZONTAL);
3328
int y_pos = GetScrollPos (wxVERTICAL);
3329
x = m_owner->GetHeaderWindow()->GetWidth() + 2;
3330
if (x < GetClientSize().GetWidth()) x_pos = 0;
3331
SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
3333
SetScrollbars (0, 0, 0, 0);
3337
int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
3338
if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
3339
return item->GetHeight();
3341
return m_lineHeight;
3345
void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
3347
// read attributes constant for all item cells
3348
wxColour colText = GetItemTextColour(item);
3349
wxColour colBg = GetItemBackgroundColour(item);
3350
#if !wxCHECK_VERSION(2, 5, 0)
3351
wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
3353
wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
3355
int total_w = m_owner->GetHeaderWindow()->GetWidth();
3356
int total_h = GetLineHeight(item);
3357
int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
3358
int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
3359
wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
3360
// compute text height based on main col
3362
dc.GetTextExtent( item->GetText(GetMainColumn()).size() > 0
3363
? item->GetText(GetMainColumn())
3364
: _T("M"), // dummy text to avoid zero height and no highlight width
3367
// determine background and show it
3368
// in wxTR_FULL_ROW_HIGHLIGHT mode, some drawing can be done already now
3369
dc.SetBrush (wxBrush ( colBg, wxSOLID));
3370
dc.SetPen (*wxTRANSPARENT_PEN);
3371
if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3372
if (item->IsSelected()) {
3373
if (! m_isDragging && m_hasFocus) {
3374
dc.SetBrush (*m_hilightBrush);
3375
#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3376
dc.SetPen (*wxBLACK_PEN);
3377
#endif // !__WXMAC__
3379
dc.SetBrush (*m_hilightUnfocusedBrush);
3380
#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3381
dc.SetPen (*wxTRANSPARENT_PEN);
3382
#endif // !__WXMAC__
3384
dc.SetTextForeground (colTextHilight);
3386
dc.SetTextForeground (GetItemTextColour(item));
3387
if (item == m_curItem) {
3388
dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3391
dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
3394
// iterate through all cells
3395
int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3396
int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3398
for (int i = 0; i < GetColumnCount(); ++i ) {
3399
if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3400
int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3401
if (col_w <= 0) continue; // workaround for probable GTK2 bug [wxCode-Bugs-#3061215]
3402
wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3404
// read variable attributes
3405
dc.SetFont (GetItemFont (item, i));
3406
colText = GetItemTextColour(item, i);
3407
colBg = GetItemBackgroundColour(item, i);
3411
int image = NO_IMAGE;
3413
if(i == GetMainColumn()) {
3414
x = item->GetX() + MARGIN;
3416
x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
3420
if (m_imageListNormal) image = item->GetCurrentImage();
3422
x = x_colstart + MARGIN;
3423
image = item->GetImage(i);
3425
if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
3427
// honor text alignment
3428
int w = 0, text_w = 0;
3429
wxString text = item->GetText(i);
3430
dc.GetTextExtent (text, &text_w, NULL);
3431
switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
3433
// nothing to do, already left aligned
3436
w = col_w - (image_w + text_w + off_w + MARGIN);
3439
case wxALIGN_CENTER:
3440
w = (col_w - (image_w + text_w + off_w + MARGIN))/2;
3444
int text_x = x + image_w;
3445
if (i == GetMainColumn()) item->SetTextX (text_x);
3447
// draw background (in non wxTR_FULL_ROW_HIGHLIGHT mode)
3448
// cell-specific settings are used --excepted for selection:
3449
if ( ! HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3450
// cursor: indicate current cell
3451
bool drawCursor = false;
3452
#ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3453
drawCursor = (item == m_curItem && i == m_curColumn && !m_isDragging && m_hasFocus);
3454
#endif // !__WXMAC__
3455
// selection: main col only, overrides colors + separate draw
3456
if (item->IsSelected() && i == GetMainColumn()) {
3457
// draw normal background
3458
dc.SetPen (*wxTRANSPARENT_PEN);
3459
dc.SetBrush (wxBrush ( colBg, wxSOLID));
3460
dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
3461
// draw selection & optionally cursor
3462
dc.SetPen (drawCursor ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
3463
dc.SetBrush(!m_isDragging && m_hasFocus ? *m_hilightBrush : *m_hilightUnfocusedBrush);
3464
dc.SetTextForeground (colTextHilight);
3465
dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3466
// normal FG / BG from attributes
3468
// draw normal background & optionally cursor
3469
dc.SetPen (drawCursor && i != GetMainColumn() ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
3470
dc.SetBrush (wxBrush ( colBg, wxSOLID));
3471
dc.SetTextForeground (colText);
3472
dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
3473
// on main col draw a separate cursor
3474
if (drawCursor && i == GetMainColumn()) {
3475
dc.SetPen (*wxBLACK_PEN);
3476
dc.SetBackgroundMode (wxTRANSPARENT);
3477
dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3482
// draw vertical column lines
3483
if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns
3484
#if !wxCHECK_VERSION(2, 5, 0)
3485
wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3487
wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3489
dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3490
dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h);
3493
dc.SetBackgroundMode (wxTRANSPARENT);
3496
if (image != NO_IMAGE && m_imageListNormal && image < m_imageListNormal->GetImageCount()) {
3497
int y = item->GetY() + img_extraH;
3498
m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3502
int text_y = item->GetY() + text_extraH;
3503
dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
3505
x_colstart += col_w;
3508
// restore normal font
3509
dc.SetFont( m_normalFont );
3512
// Now y stands for the top of the item, whereas it used to stand for middle !
3513
void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
3514
int level, int &y, int x_maincol) {
3516
// Handle hide root (only level 0)
3517
if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
3518
wxArrayTreeListItems& children = item->GetChildren();
3519
for (size_t n = 0; n < children.Count(); n++) {
3520
PaintLevel (children[n], dc, 1, y, x_maincol);
3522
// end after expanding root
3526
// calculate position of vertical lines
3527
int x = x_maincol + MARGIN; // start of column
3528
if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3530
x += (m_btnWidth-m_btnWidth2); // half button space
3532
x += (m_indent-m_indent/2);
3534
if (HasFlag(wxTR_HIDE_ROOT)) {
3535
x += m_indent * (level-1); // indent but not level 1
3537
x += m_indent * level; // indent according to level
3540
// set position of vertical line
3544
int h = GetLineHeight (item);
3546
int y_mid = y_top + (h/2);
3549
int exposed_x = dc.LogicalToDeviceX(0);
3550
int exposed_y = dc.LogicalToDeviceY(y_top);
3552
if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
3554
if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
3555
//dc.DestroyClippingRegion();
3556
int total_width = m_owner->GetHeaderWindow()->GetWidth();
3557
// if the background colour is white, choose a
3558
// contrasting color for the lines
3559
#if !wxCHECK_VERSION(2, 5, 0)
3560
wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3562
wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3564
dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3565
dc.DrawLine (0, y_top, total_width, y_top);
3566
dc.DrawLine (0, y_top+h, total_width, y_top+h);
3570
PaintItem (item, dc);
3572
// restore DC objects
3573
dc.SetBrush(*wxWHITE_BRUSH);
3574
dc.SetPen(m_dottedPen);
3576
// clip to the column width
3577
int clip_width = m_owner->GetHeaderWindow()->
3578
GetColumn(m_main_column).GetWidth();
3579
wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3581
if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3583
// draw the horizontal line here
3584
dc.SetPen(m_dottedPen);
3585
int x2 = x - m_indent;
3586
if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3587
int x3 = x + (m_btnWidth-m_btnWidth2);
3589
if (item->HasPlus()) {
3590
dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3591
dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3593
dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3596
dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
3600
if (item->HasPlus() && HasButtons()) { // should the item show a button?
3602
if (m_imageListButtons) {
3604
// draw the image button here
3605
int image = wxTreeItemIcon_Normal;
3606
if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
3607
if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3608
int xx = x - m_btnWidth2 + MARGIN;
3609
int yy = y_mid - m_btnHeight2;
3610
dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
3611
m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
3612
dc.DestroyClippingRegion();
3614
}else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3616
// draw the twisty button here
3617
dc.SetPen(*wxBLACK_PEN);
3618
dc.SetBrush(*m_hilightBrush);
3620
if (item->IsExpanded()) {
3621
button[0].x = x - (m_btnWidth2+1);
3622
button[0].y = y_mid - (m_btnHeight/3);
3623
button[1].x = x + (m_btnWidth2+1);
3624
button[1].y = button[0].y;
3626
button[2].y = button[0].y + (m_btnHeight2+1);
3628
button[0].x = x - (m_btnWidth/3);
3629
button[0].y = y_mid - (m_btnHeight2+1);
3630
button[1].x = button[0].x;
3631
button[1].y = y_mid + (m_btnHeight2+1);
3632
button[2].x = button[0].x + (m_btnWidth2+1);
3633
button[2].y = y_mid;
3635
dc.DrawPolygon(3, button);
3637
}else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3639
// draw the plus sign here
3640
#if !wxCHECK_VERSION(2, 7, 0)
3641
dc.SetPen(*wxGREY_PEN);
3642
dc.SetBrush(*wxWHITE_BRUSH);
3643
dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3644
dc.SetPen(*wxBLACK_PEN);
3645
dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
3646
if (!item->IsExpanded()) { // change "-" to "+"
3647
dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
3650
wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3651
int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0;
3652
wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag);
3661
// restore DC objects
3662
dc.SetBrush(*wxWHITE_BRUSH);
3663
dc.SetPen(m_dottedPen);
3664
dc.SetTextForeground(*wxBLACK);
3666
if (item->IsExpanded())
3668
wxArrayTreeListItems& children = item->GetChildren();
3670
// clip to the column width
3671
int clip_width = m_owner->GetHeaderWindow()->
3672
GetColumn(m_main_column).GetWidth();
3674
// process lower levels
3676
if (m_imgWidth > 0) {
3677
oldY = y_mid + m_imgHeight2;
3682
for (size_t n = 0; n < children.Count(); ++n) {
3685
PaintLevel (children[n], dc, level+1, y, x_maincol);
3687
// draw vertical line
3688
wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3689
if (!HasFlag (wxTR_NO_LINES)) {
3691
dc.DrawLine (x, oldY, x, y2);
3699
// ----------------------------------------------------------------------------
3700
// wxWindows callbacks
3701
// ----------------------------------------------------------------------------
3703
void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
3705
// init device context, clear background (BEFORE changing DC origin...)
3706
wxAutoBufferedPaintDC dc (this);
3707
wxBrush brush(GetBackgroundColour(), wxSOLID);
3708
dc.SetBackground(brush);
3712
if (!m_rootItem || (GetColumnCount() <= 0)) return;
3714
// calculate button size
3715
if (m_imageListButtons) {
3716
m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3717
}else if (HasButtons()) {
3718
m_btnWidth = BTNWIDTH;
3719
m_btnHeight = BTNHEIGHT;
3721
m_btnWidth2 = m_btnWidth/2;
3722
m_btnHeight2 = m_btnHeight/2;
3724
// calculate image size
3725
if (m_imageListNormal) {
3726
m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
3728
m_imgWidth2 = m_imgWidth/2;
3729
m_imgHeight2 = m_imgHeight/2;
3731
// calculate indent size
3732
if (m_imageListButtons) {
3733
m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3734
}else if (HasButtons()) {
3735
m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3738
// set default values
3739
dc.SetFont( m_normalFont );
3740
dc.SetPen( m_dottedPen );
3742
// calculate column start and paint
3745
for (i = 0; i < (int)GetMainColumn(); ++i) {
3746
if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3747
x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
3750
PaintLevel (m_rootItem, dc, 0, y, x_maincol);
3753
void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
3756
if (m_curItem) RefreshLine (m_curItem);
3760
void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3764
if (m_curItem) RefreshLine (m_curItem);
3768
void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3769
// send event to user code
3770
wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, 0 );
3771
nevent.SetInt(m_curColumn);
3772
nevent.SetKeyEvent (event);
3773
if (SendEvent(0, NULL, &nevent)) return; // char event handled in user code
3775
// if no item current, select root
3776
bool curItemSet = false;
3778
if (! GetRootItem().IsOk()) return;
3779
SetCurrentItem((wxTreeListItem*)GetRootItem().m_pItem);
3780
if (HasFlag(wxTR_HIDE_ROOT)) {
3781
#if !wxCHECK_VERSION(2, 5, 0)
3784
wxTreeItemIdValue cookie = 0;
3786
SetCurrentItem((wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem);
3788
SelectItem(m_curItem, (wxTreeItemId*)NULL, true); // unselect others
3792
// remember item at shift down
3793
if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3794
if (!m_shiftItem) m_shiftItem = m_curItem;
3796
m_shiftItem = (wxTreeListItem*)NULL;
3799
if (curItemSet) return; // if no item was current until now, do nothing more
3801
// process all cases
3802
wxTreeItemId newItem = (wxTreeItemId*)NULL;
3803
switch (event.GetKeyCode()) {
3805
// '+': Expand subtree
3808
if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3811
// '-': collapse subtree
3813
case WXK_SUBTRACT: {
3814
if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3817
// '*': expand/collapse all subtrees // TODO: Mak it more useful
3819
case WXK_MULTIPLY: {
3820
if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3821
ExpandAll (m_curItem);
3822
}else if (m_curItem->HasPlus()) {
3823
Collapse (m_curItem); // TODO: CollapseAll
3827
// ' ': toggle current item
3829
SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3832
// <RETURN>: activate current item
3834
if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_curItem)) {
3836
// if the user code didn't process the activate event,
3837
// handle it ourselves by toggling the item when it is
3839
if (m_curItem && m_curItem->HasPlus()) Toggle(m_curItem);
3843
// <BKSP>: go to the parent without collapsing
3845
newItem = GetItemParent (m_curItem);
3846
if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3847
newItem = GetPrevSibling (m_curItem); // get sibling instead of root
3851
// <HOME>: go to first visible
3853
newItem = GetFirstVisible(false, false);
3856
// <PAGE-UP>: go to the top of the page, or if we already are then one page back
3860
wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,1));
3861
// PAGE-UP: first go the the first visible row
3862
newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3863
newItem = GetFirstVisible(false, true);
3864
// if we are already there then scroll back one page
3865
if (newItem == m_curItem) {
3866
abs_p.y -= GetClientSize().GetHeight() - m_curItem->GetHeight();
3867
if (abs_p.y < 0) abs_p.y = 0;
3868
newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3870
// newItem should never be NULL
3873
// <UP>: go to the previous sibling or for the last of its children, to the parent
3875
newItem = GetPrevSibling (m_curItem);
3877
#if !wxCHECK_VERSION(2, 5, 0)
3880
wxTreeItemIdValue cookie = 0;
3882
while (IsExpanded (newItem) && HasChildren (newItem)) {
3883
newItem = GetLastChild (newItem, cookie);
3886
newItem = GetItemParent (m_curItem);
3887
if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3888
newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
3893
// <LEFT>: if expanded collapse subtree, else go to the parent
3895
if (IsExpanded (m_curItem)) {
3896
Collapse (m_curItem);
3898
newItem = GetItemParent (m_curItem);
3899
if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3900
newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
3905
// <RIGHT>: if possible expand subtree, else go go to the first child
3907
if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3910
if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3911
#if !wxCHECK_VERSION(2, 5, 0)
3914
wxTreeItemIdValue cookie = 0;
3916
newItem = GetFirstChild (m_curItem, cookie);
3921
// <DOWN>: if expanded go to the first child, else to the next sibling, ect
3923
if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3924
#if !wxCHECK_VERSION(2, 5, 0)
3927
wxTreeItemIdValue cookie = 0;
3929
newItem = GetFirstChild( m_curItem, cookie );
3932
wxTreeItemId parent = m_curItem;
3934
newItem = GetNextSibling (parent);
3935
parent = GetItemParent (parent);
3936
} while (!newItem && parent);
3940
// <PAGE-DOWN>: go to the bottom of the page, or if we already are then one page further
3941
case WXK_PAGEDOWN: {
3944
wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,GetClientSize().GetHeight() - m_curItem->GetHeight()));
3945
// PAGE-UP: first go the the first visible row
3946
newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3947
newItem = GetLastVisible(false, true);
3948
// if we are already there then scroll down one page
3949
if (newItem == m_curItem) {
3950
abs_p.y += GetClientSize().GetHeight() - m_curItem->GetHeight();
3951
// if (abs_p.y >= GetVirtualSize().GetHeight()) abs_p.y = GetVirtualSize().GetHeight() - 1;
3952
newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3954
// if we reached the empty area below the rows, return last item instead
3955
if (! newItem) newItem = GetLastVisible(false, false);
3958
// <END>: go to last item of the root
3960
newItem = GetLastVisible (false, false);
3963
// any char: go to the next matching string
3965
if (event.GetKeyCode() >= (int)' ') {
3966
if (!m_findTimer->IsRunning()) m_findStr.Clear();
3967
m_findStr.Append (event.GetKeyCode());
3968
m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3969
wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL;
3971
newItem = FindItem (prev, GetCurrentColumn(), m_findStr, wxTL_MODE_NAV_EXPANDED | wxTL_MODE_FIND_PARTIAL | wxTL_MODE_FIND_NOCASE);
3972
if (newItem || (m_findStr.Length() <= 1)) break;
3973
m_findStr.RemoveLast();
3980
// select and show the new item
3982
if (!event.ControlDown()) {
3983
bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3984
HasFlag(wxTR_MULTIPLE));
3985
SelectItem (newItem, m_shiftItem, unselect_others);
3987
EnsureVisible (newItem);
3988
wxTreeListItem *oldItem = m_curItem;
3989
SetCurrentItem((wxTreeListItem*)newItem.m_pItem); // make the new item the current item
3990
RefreshLine (oldItem);
3995
wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
4001
if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
4002
if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
4003
if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
4004
if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
4005
if (flags) return wxTreeItemId();
4008
flags = wxTREE_HITTEST_NOWHERE;
4010
return wxTreeItemId();
4013
wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
4014
this, flags, column, 0);
4016
flags = wxTREE_HITTEST_NOWHERE;
4018
return wxTreeItemId();
4023
// get the bounding rectangle of the item (or of its label only)
4024
bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
4025
bool WXUNUSED(textOnly)) const {
4026
wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
4028
wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4031
GetScrollPixelsPerUnit (&xUnit, &yUnit);
4033
GetViewStart(& startX, & startY);
4035
rect.x = item->GetX() - startX * xUnit;
4036
rect.y = item->GetY() - startY * yUnit;
4037
rect.width = item->GetWidth();
4038
rect.height = GetLineHeight (item);
4045
void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
4048
if (!item.IsOk()) return;
4049
if (!((column >= 0) && (column < GetColumnCount()))) return;
4051
// cancel any editing
4052
if (m_editControl) { m_editControl->EndEdit(true); } // cancelled
4054
// prepare edit (position)
4055
m_editItem = (wxTreeListItem*) item.m_pItem;
4057
wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 0 );
4059
SendEvent(0, m_editItem, &te); if (!te.IsAllowed()) return;
4061
// ensure that the position of the item it calculated in any case
4062
if (m_dirty) CalculatePositions();
4064
wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
4066
// position & size are rather unpredictable (tsssk, tssssk) so were
4067
// set by trial & error (on Win 2003 pre-XP style)
4069
int w = +4; // +4 is necessary, don't know why (simple border erronously counted somewhere ?)
4070
int y = m_editItem->GetY() + 1; // this is cell, not text
4071
int h = m_editItem->GetHeight() - 1; // consequence from above
4073
if (column == GetMainColumn()) {
4074
x += m_editItem->GetTextX() - 2; // wrong by 2, don't know why
4075
w += m_editItem->GetWidth();
4077
for (int i = 0; i < column; ++i) {
4078
if ( header_win->IsColumnShown(i) ) {
4079
x += header_win->GetColumnWidth (i); // start of column
4082
w += header_win->GetColumnWidth (column); // currently non-main column width not pre-computed
4084
switch (header_win->GetColumnAlignment (column)) {
4085
case wxALIGN_LEFT: {style = wxTE_LEFT; x -= 1; break;}
4086
case wxALIGN_CENTER: {style = wxTE_CENTER; x -= 1; break;}
4087
case wxALIGN_RIGHT: {style = wxTE_RIGHT; x += 0; break;} // yes, strange but that's the way it is
4089
// wxTextCtrl simple border style requires 2 extra pixels before and after
4090
// (measured by changing to style wxNO_BORDER in wxEditTextCtrl::wxEditTextCtrl() )
4094
wxClientDC dc (this);
4096
x = dc.LogicalToDeviceX (x);
4097
y = dc.LogicalToDeviceY (y);
4099
// now do edit (change state, show control)
4100
m_editCol = column; // only used in OnRenameAccept()
4101
m_editControl = new wxEditTextCtrl (this, -1, &m_editAccept, &m_editRes,
4102
this, m_editItem->GetText (column),
4103
wxPoint (x, y), wxSize (w, h), style);
4104
m_editControl->SetFocus();
4107
void wxTreeListMainWindow::OnRenameTimer() {
4108
EditLabel (m_curItem, GetCurrentColumn());
4111
void wxTreeListMainWindow::OnRenameAccept(bool isCancelled) {
4113
// TODO if the validator fails this causes a crash
4114
wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, 0 );
4115
le.SetLabel( m_editRes );
4116
le.SetEditCanceled(isCancelled);
4117
le.SetInt(m_editCol);
4118
SendEvent(0, m_editItem, &le); if (! isCancelled && le.IsAllowed())
4120
SetItemText (m_editItem, le.GetInt(), le.GetLabel());
4124
void wxTreeListMainWindow::EndEdit(bool /*isCancelled*/) {
4125
if (m_editControl) { m_editControl->EndEdit(true); }
4128
void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
4129
bool mayDrag = true;
4130
bool maySelect = true; // may change selection
4131
bool mayClick = true; // may process DOWN clicks to expand, send click events
4132
bool mayDoubleClick = true; // implies mayClick
4135
// send event to user code
4136
if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
4137
if (!m_rootItem) return;
4140
// ---------- DETERMINE EVENT ----------
4142
wxLogMessage("OnMouse: LMR down=<%d, %d, %d> up=<%d, %d, %d> LDblClick=<%d> dragging=<%d>",
4143
event.LeftDown(), event.MiddleDown(), event.RightDown(),
4144
event.LeftUp(), event.MiddleUp(), event.RightUp(),
4145
event.LeftDClick(), event.Dragging());
4147
wxPoint p = wxPoint (event.GetX(), event.GetY());
4149
wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
4150
this, flags, m_curColumn, 0);
4151
bool bCrosshair = (item && item->HasPlus() && (flags & wxTREE_HITTEST_ONITEMBUTTON));
4154
maySelect = mayDoubleClick = false;
4156
// we are starting or continuing to drag
4157
if (event.Dragging()) {
4158
maySelect = mayDoubleClick = mayClick = false;
4160
// crosshair area is special
4162
// left click does not select
4163
if (event.LeftDown()) maySelect = false;
4164
// double click is ignored
4165
mayDoubleClick = false;
4167
// double click only if simple click
4168
if (mayDoubleClick) mayDoubleClick = mayClick;
4169
// selection conditions --remember also that selection exludes editing
4170
if (maySelect) maySelect = mayClick; // yes, select/unselect requires a click
4173
// multiple selection mode complicates things, sometimes we
4174
// select on button-up instead of down:
4175
if (HasFlag(wxTR_MULTIPLE)) {
4177
// CONTROL/SHIFT key used, don't care about anything else, will
4178
// toggle on key down
4179
if (event.ControlDown() || event.ShiftDown()) {
4180
maySelect = maySelect && (event.LeftDown() || event.RightDown());
4181
m_lastOnSame = false; // prevent editing when keys are used
4183
// already selected item: to allow drag or contextual menu for multiple
4184
// items, we only select/unselect on click-up --and only on LEFT
4185
// click, right is reserved for contextual menu
4186
} else if ((item != NULL && item->IsSelected())) {
4187
maySelect = maySelect && event.LeftUp();
4189
// non-selected items: select on click-down like simple select (so
4190
// that a right-click contextual menu may be chained)
4192
maySelect = maySelect && (event.LeftDown() || event.RightDown());
4195
// single-select is simply on left or right click-down
4197
maySelect = maySelect && (event.LeftDown() || event.RightDown());
4202
// ---------- GENERAL ACTIONS ----------
4204
// set focus if window clicked
4205
if (event.LeftDown() || event.MiddleDown() || event.RightDown()) SetFocus();
4208
if (item != m_toolTipItem) {
4210
// not over an item, use global tip
4212
m_toolTipItem = NULL;
4213
wxScrolledWindow::SetToolTip(m_toolTip);
4217
const wxString *tip = item->GetToolTip();
4219
// is there an item-specific tip ?
4221
m_toolTipItem = item;
4222
wxScrolledWindow::SetToolTip(*tip);
4224
// no item tip, but we are in item-specific mode (SetItemToolTip()
4225
// was called after SetToolTip() )
4226
} else if (m_isItemToolTip) {
4227
m_toolTipItem = item;
4228
wxScrolledWindow::SetToolTip(wxString());
4230
// no item tip, display global tip instead; item change ignored
4231
} else if (m_toolTipItem != NULL) {
4232
m_toolTipItem = NULL;
4233
wxScrolledWindow::SetToolTip(m_toolTip);
4239
// ---------- HANDLE SIMPLE-CLICKS (selection change, contextual menu) ----------
4242
// 2nd left-click on an item might trigger edit
4243
if (event.LeftDown()) m_lastOnSame = (item == m_curItem);
4245
// left-click on haircross is expand (and no select)
4246
if (bCrosshair && event.LeftDown()) {
4250
// note that we only toggle the item for a single click, double
4251
// click on the button doesn't do anything
4258
// set / remember item at shift down before current item gets changed
4259
if (event.LeftDown() && HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
4260
if (!m_shiftItem) m_shiftItem = m_curItem;
4262
m_shiftItem = (wxTreeListItem*)NULL;
4265
// how is selection altered
4266
// keep or discard already selected ?
4267
bool unselect_others = ! (HasFlag(wxTR_MULTIPLE) && (
4269
|| event.ControlDown()
4272
// check is selection change is not vetoed
4273
if (SelectItem(item, m_shiftItem, unselect_others)) {
4274
// make the new item the current item
4275
EnsureVisible (item);
4276
SetCurrentItem(item);
4280
// generate click & menu events
4281
if (event.MiddleDown()) {
4283
SendEvent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, item);
4285
if (event.RightDown()) {
4287
SendEvent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, item);
4289
if (event.RightUp()) {
4290
wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MENU, 0);
4292
nevent.SetInt(m_curColumn);
4293
SendEvent(0, item, &nevent);
4296
// if 2nd left click finishes on same item, will edit it
4297
if (m_lastOnSame && event.LeftUp()) {
4298
if ((item == m_curItem) && (m_curColumn != -1) &&
4299
(m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
4300
(flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))
4302
m_editTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
4305
m_lastOnSame = false;
4310
// ---------- HANDLE DOUBLE-CLICKS ----------
4311
if (mayDoubleClick && event.LeftDClick()) {
4315
// double clicking should not start editing the item label
4316
m_editTimer->Stop();
4317
m_lastOnSame = false;
4319
// selection reset to that single item which was double-clicked
4320
if (SelectItem(item, (wxTreeItemId*)NULL, true)) { // unselect others --return false if vetoed
4322
// selection change not vetoed, send activate event
4323
if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item)) {
4325
// if the user code didn't process the activate event,
4326
// handle it ourselves by toggling the item when it is
4328
if (item && item->HasPlus()) Toggle(item);
4334
// ---------- HANDLE DRAGGING ----------
4335
// NOTE: drag itself makes no change to selection
4336
if (mayDrag) { // actually this is always true
4338
// CASE 1: we were dragging => continue, end, abort
4341
// CASE 1.1: click aborts drag:
4342
if (event.LeftDown() || event.MiddleDown() || event.RightDown()) {
4347
m_isDragStarted = m_isDragging = false;
4348
if (HasCapture()) ReleaseMouse();
4351
// CASE 1.2: still dragging
4352
} else if (event.Dragging()) {
4356
// CASE 1.3: dragging now ends normally
4362
m_isDragStarted = m_isDragging = false;
4363
if (HasCapture()) ReleaseMouse();
4366
// send drag end event
4367
wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, 0);
4369
event.SetInt(m_curColumn);
4370
SendEvent(0, item, &event);
4373
// CASE 2: not were not dragging => continue, start
4374
} else if (event.Dragging()) {
4376
// We will really start dragging if we've moved beyond a few pixels
4377
if (m_isDragStarted) {
4378
const int tolerance = 3;
4379
int dx = abs(p.x - m_dragStartPos.x);
4380
int dy = abs(p.y - m_dragStartPos.y);
4381
if (dx <= tolerance && dy <= tolerance)
4383
// determine drag start
4386
m_dragCol = GetCurrentColumn();
4388
m_isDragStarted = true;
4394
// we are now dragging
4395
m_isDragging = true;
4397
CaptureMouse(); // TODO: usefulness unclear
4399
wxTreeEvent nevent(event.LeftIsDown()
4400
? wxEVT_COMMAND_TREE_BEGIN_DRAG
4401
: wxEVT_COMMAND_TREE_BEGIN_RDRAG, 0);
4403
nevent.SetInt(m_dragCol);
4405
SendEvent(0, m_dragItem, &nevent);
4410
if (bSkip) event.Skip();
4414
void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
4415
/* after all changes have been done to the tree control,
4416
* we actually redraw the tree when everything is over */
4418
if (!m_dirty) return;
4422
CalculatePositions();
4424
AdjustMyScrollbars();
4427
void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
4429
// send event to wxTreeListCtrl (for user code)
4430
if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
4433
#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4434
wxScrolledWindow::OnScroll(event);
4436
HandleOnScroll( event );
4439
if(event.GetOrientation() == wxHORIZONTAL) {
4440
m_owner->GetHeaderWindow()->Refresh();
4441
m_owner->GetHeaderWindow()->Update();
4445
void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
4449
dc.SetFont (GetItemFont (item));
4450
dc.GetTextExtent (item->GetText(m_main_column).size() > 0
4451
? item->GetText (m_main_column)
4452
: _T(" "), // blank to avoid zero height and no highlight width
4454
// restore normal font
4455
dc.SetFont (m_normalFont);
4457
int max_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
4458
if (max_h < 30) { // add 10% space if greater than 30 pixels
4459
max_h += 2; // minimal 2 pixel space
4461
max_h += max_h / 10; // otherwise 10% space
4464
item->SetHeight (max_h);
4465
if (max_h > m_lineHeight) m_lineHeight = max_h;
4466
item->SetWidth(m_imgWidth + text_w+2);
4469
// -----------------------------------------------------------------------------
4470
void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
4471
int level, int &y, int x_colstart) {
4473
// calculate position of vertical lines
4474
int x = x_colstart + MARGIN; // start of column
4475
if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
4477
x += (m_btnWidth-m_btnWidth2); // half button space
4479
x += (m_indent-m_indent/2);
4481
if (HasFlag(wxTR_HIDE_ROOT)) {
4482
x += m_indent * (level-1); // indent but not level 1
4484
x += m_indent * level; // indent according to level
4487
// a hidden root is not evaluated, but its children are always
4488
if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
4490
CalculateSize( item, dc );
4495
y += GetLineHeight(item);
4497
// we don't need to calculate collapsed branches
4498
if ( !item->IsExpanded() ) return;
4501
wxArrayTreeListItems& children = item->GetChildren();
4502
long n, count = (long)children.Count();
4504
for (n = 0; n < count; ++n) {
4505
CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse
4509
void wxTreeListMainWindow::CalculatePositions() {
4510
if ( !m_rootItem ) return;
4512
wxClientDC dc(this);
4515
dc.SetFont( m_normalFont );
4517
dc.SetPen( m_dottedPen );
4518
//if(GetImageList() == NULL)
4519
// m_lineHeight = (int)(dc.GetCharHeight() + 4);
4523
for (int i = 0; i < (int)GetMainColumn(); ++i) {
4524
if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
4525
x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
4527
CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
4530
void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
4531
if (m_dirty) return;
4533
wxClientDC dc(this);
4538
GetVirtualSize( &cw, &ch );
4541
rect.x = dc.LogicalToDeviceX( 0 );
4543
rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4546
Refresh (true, &rect );
4547
AdjustMyScrollbars();
4550
void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
4551
if (m_dirty) return;
4553
wxClientDC dc(this);
4558
GetVirtualSize( &cw, &ch );
4561
rect.x = dc.LogicalToDeviceX( 0 );
4562
rect.y = dc.LogicalToDeviceY( item->GetY() );
4564
rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4566
Refresh (true, &rect);
4569
void wxTreeListMainWindow::RefreshSelected() {
4570
// TODO: this is awfully inefficient, we should keep the list of all
4571
// selected items internally, should be much faster
4573
RefreshSelectedUnder (m_rootItem);
4577
void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4578
if (item->IsSelected()) {
4582
const wxArrayTreeListItems& children = item->GetChildren();
4583
long count = (long)children.GetCount();
4584
for (long n = 0; n < count; n++ ) {
4585
RefreshSelectedUnder (children[n]);
4589
// ----------------------------------------------------------------------------
4590
// changing colours: we need to refresh the tree control
4591
// ----------------------------------------------------------------------------
4593
bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4594
if (!wxWindow::SetBackgroundColour(colour)) return false;
4600
bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4601
if (!wxWindow::SetForegroundColour(colour)) return false;
4607
void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column, const wxString& text) {
4608
wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
4610
wxClientDC dc (this);
4611
wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4612
item->SetText (column, text);
4613
CalculateSize (item, dc);
4617
std::list<wxTreeItemId> wxTreeListMainWindow::GetPublicChildren(const wxTreeItemId& itemId) const
4619
wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4620
return item->GetPublicChildren();
4623
wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId, int column) const {
4624
wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
4627
return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4629
if (itemId.m_pItem != NULL) {
4630
wxTreeListItem* item = (wxTreeListItem*) itemId.m_pItem;
4631
if (!item->GetText(column).IsNull()) {
4632
return item->GetText(column);
4635
return wxEmptyString;
4639
return wxEmptyString;
4643
wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item, int column) const {
4644
wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4645
return m_owner->OnGetItemText(item, column);
4648
void wxTreeListMainWindow::SetFocus() {
4649
wxWindow::SetFocus();
4653
int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4654
if (!item) return 0;
4656
// determine item width
4658
wxFont font = GetItemFont (item);
4659
GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4663
int width = w + 2*MARGIN;
4664
if (column == GetMainColumn()) {
4666
if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4667
if (HasButtons()) width += m_btnWidth + LINEATROOT;
4668
if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4670
// count indent level
4672
wxTreeListItem *parent = item->GetItemParent();
4673
wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4674
while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4676
parent = parent->GetItemParent();
4678
if (level) width += level * GetIndent();
4684
int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4686
GetClientSize (&maxWidth, &h);
4689
// get root if on item
4690
if (!parent.IsOk()) parent = GetRootItem();
4693
if (!HasFlag(wxTR_HIDE_ROOT)) {
4694
int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4695
if (width < w) width = w;
4696
if (width > maxWidth) return maxWidth;
4699
wxTreeItemIdValue cookie = 0;
4700
wxTreeItemId item = GetFirstChild (parent, cookie);
4701
while (item.IsOk()) {
4702
int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4703
if (width < w) width = w;
4704
if (width > maxWidth) return maxWidth;
4706
// check the children of this item
4707
if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4708
int w = GetBestColumnWidth (column, item);
4709
if (width < w) width = w;
4710
if (width > maxWidth) return maxWidth;
4714
item = GetNextChild (parent, cookie);
4721
bool wxTreeListMainWindow::SendEvent(wxEventType event_type, wxTreeListItem *item, wxTreeEvent *event) {
4722
wxTreeEvent nevent (event_type, 0);
4724
if (event == NULL) {
4726
event->SetInt (m_curColumn); // the mouse colum
4729
event->SetEventObject (m_owner);
4730
event->SetId(m_owner->GetId());
4732
#if !wxCHECK_VERSION(2, 5, 0)
4733
event->SetItem ((long)item);
4735
event->SetItem (item);
4739
return m_owner->GetEventHandler()->ProcessEvent (*event);
4743
//-----------------------------------------------------------------------------
4745
//-----------------------------------------------------------------------------
4747
IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
4749
BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4750
EVT_SIZE(wxTreeListCtrl::OnSize)
4753
bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4756
long style, const wxValidator &validator,
4757
const wxString& name)
4759
long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER|
4760
wxRAISED_BORDER|wxSTATIC_BORDER);
4761
main_style |= wxWANTS_CHARS ;
4762
long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
4764
if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4767
m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4768
main_style, validator);
4769
m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4770
wxPoint(0, 0), wxDefaultSize,
4772
CalculateAndSetHeaderHeight();
4776
void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4780
// we use 'g' to get the descent, too
4782
#if wxCHECK_VERSION_FULL(2, 7, 0, 1)
4784
h = (int)(wxRendererNative::Get().GetHeaderButtonHeight(m_header_win) * 0.8) + 2;
4786
h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
4790
m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
4791
h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
4794
// only update if changed
4795
if (h != m_headerHeight) {
4802
void wxTreeListCtrl::DoHeaderLayout()
4805
GetClientSize(&w, &h);
4807
m_header_win->SetSize (0, 0, w, m_headerHeight);
4808
m_header_win->Refresh();
4811
m_main_win->SetSize (0, m_headerHeight, w, h - m_headerHeight);
4815
void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4820
size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4822
unsigned int wxTreeListCtrl::GetIndent() const
4823
{ return m_main_win->GetIndent(); }
4825
void wxTreeListCtrl::SetIndent(unsigned int indent)
4826
{ m_main_win->SetIndent(indent); }
4828
unsigned int wxTreeListCtrl::GetLineSpacing() const
4829
{ return m_main_win->GetLineSpacing(); }
4831
void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4832
{ m_main_win->SetLineSpacing(spacing); }
4834
wxImageList* wxTreeListCtrl::GetImageList() const
4835
{ return m_main_win->GetImageList(); }
4837
wxImageList* wxTreeListCtrl::GetStateImageList() const
4838
{ return m_main_win->GetStateImageList(); }
4840
wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4841
{ return m_main_win->GetButtonsImageList(); }
4843
void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4844
{ m_main_win->SetImageList(imageList); }
4846
void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4847
{ m_main_win->SetStateImageList(imageList); }
4849
void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4850
{ m_main_win->SetButtonsImageList(imageList); }
4852
void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4853
{ m_main_win->AssignImageList(imageList); }
4855
void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4856
{ m_main_win->AssignStateImageList(imageList); }
4858
void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4859
{ m_main_win->AssignButtonsImageList(imageList); }
4861
std::list<wxTreeItemId> wxTreeListCtrl::GetPublicChildren(const wxTreeItemId& item) const
4863
return m_main_win->GetPublicChildren(item);
4866
wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4867
{ return m_main_win->GetItemText (item, column); }
4869
int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemIcon which) const
4870
{ return m_main_win->GetItemImage(item, which); }
4871
int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column) const
4872
{ return m_main_win->GetItemImage(item, column); }
4874
wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4875
{ return m_main_win->GetItemData(item); }
4876
wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item, int column) const
4877
{ return m_main_win->GetItemData(item, column); }
4879
bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4880
{ return m_main_win->GetItemBold(item); }
4881
bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item, int column) const
4882
{ return m_main_win->GetItemBold(item, column); }
4884
wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4885
{ return m_main_win->GetItemTextColour(item); }
4886
wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item, int column) const
4887
{ return m_main_win->GetItemTextColour(item, column); }
4889
wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
4890
{ return m_main_win->GetItemBackgroundColour(item); }
4891
wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item, int column) const
4892
{ return m_main_win->GetItemBackgroundColour(item, column); }
4894
wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4895
{ return m_main_win->GetItemFont(item); }
4896
wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item, int column) const
4897
{ return m_main_win->GetItemFont(item, column); }
4901
void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4902
{ m_main_win->SetItemHasChildren(item, has); }
4904
void wxTreeListCtrl::SetItemText (const wxTreeItemId& itemId, const wxString& text) {
4905
m_main_win->SetItemText (itemId, 0, text);
4907
void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column, const wxString& text)
4908
{ m_main_win->SetItemText (item, column, text); }
4910
void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int image, wxTreeItemIcon which)
4911
{ m_main_win->SetItemImage(item, image, which); }
4912
void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int column, int image)
4913
{ m_main_win->SetItemImage(item, column, image); }
4915
void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData* data)
4916
{ m_main_win->SetItemData(item, data); }
4917
void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, int column, wxTreeItemData* data)
4918
{ m_main_win->SetItemData(item, column, data); }
4920
void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
4921
{ m_main_win->SetItemBold(item, bold); }
4922
void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, int column, bool bold)
4923
{ m_main_win->SetItemBold(item, column, bold); }
4925
void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, const wxColour& colour)
4926
{ m_main_win->SetItemTextColour(item, colour); }
4927
void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour)
4928
{ m_main_win->SetItemTextColour(item, column, colour); }
4930
void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& colour)
4931
{ m_main_win->SetItemBackgroundColour(item, colour); }
4932
void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour)
4933
{ m_main_win->SetItemBackgroundColour(item, column, colour); }
4935
void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font)
4936
{ m_main_win->SetItemFont(item, font); }
4937
void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, int column, const wxFont& font)
4938
{ m_main_win->SetItemFont(item, column, font); }
4942
bool wxTreeListCtrl::SetFont(const wxFont& font)
4945
m_header_win->SetFont(font);
4946
CalculateAndSetHeaderHeight();
4947
m_header_win->Refresh();
4950
return m_main_win->SetFont(font);
4956
void wxTreeListCtrl::SetWindowStyle(const long style)
4959
m_main_win->SetWindowStyle(style);
4960
m_windowStyle = style;
4961
// TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4964
long wxTreeListCtrl::GetWindowStyle() const
4966
long style = m_windowStyle;
4968
style |= m_main_win->GetWindowStyle();
4972
bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const
4973
{ return m_main_win->IsVisible(item, fullRow, within); }
4975
bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4976
{ return m_main_win->HasChildren(item); }
4978
bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4979
{ return m_main_win->IsExpanded(item); }
4981
bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4982
{ return m_main_win->IsSelected(item); }
4984
size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4985
{ return m_main_win->GetChildrenCount(item, rec); }
4987
wxTreeItemId wxTreeListCtrl::GetRootItem() const
4988
{ return m_main_win->GetRootItem(); }
4990
wxTreeItemId wxTreeListCtrl::GetSelection() const
4991
{ return m_main_win->GetSelection(); }
4993
size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4994
{ return m_main_win->GetSelections(arr); }
4996
wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4997
{ return m_main_win->GetItemParent(item); }
4999
#if !wxCHECK_VERSION(2, 5, 0)
5000
wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
5003
wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
5004
wxTreeItemIdValue& cookie) const
5006
{ return m_main_win->GetFirstChild(item, cookie); }
5008
#if !wxCHECK_VERSION(2, 5, 0)
5009
wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
5012
wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
5013
wxTreeItemIdValue& cookie) const
5015
{ return m_main_win->GetNextChild(item, cookie); }
5017
#if !wxCHECK_VERSION(2, 5, 0)
5018
wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
5021
wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
5022
wxTreeItemIdValue& cookie) const
5024
{ return m_main_win->GetPrevChild(item, cookie); }
5026
#if !wxCHECK_VERSION(2, 5, 0)
5027
wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
5030
wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
5031
wxTreeItemIdValue& cookie) const
5033
{ return m_main_win->GetLastChild(item, cookie); }
5036
wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
5037
{ return m_main_win->GetNextSibling(item); }
5039
wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
5040
{ return m_main_win->GetPrevSibling(item); }
5042
wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
5043
{ return m_main_win->GetNext(item, true); }
5045
wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
5046
{ return m_main_win->GetPrev(item, true); }
5048
wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
5049
{ return m_main_win->GetFirstExpandedItem(); }
5051
wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
5052
{ return m_main_win->GetNextExpanded(item); }
5054
wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
5055
{ return m_main_win->GetPrevExpanded(item); }
5057
wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
5058
{ return GetFirstVisible(fullRow); }
5059
wxTreeItemId wxTreeListCtrl::GetFirstVisible(bool fullRow, bool within) const
5060
{ return m_main_win->GetFirstVisible(fullRow, within); }
5062
wxTreeItemId wxTreeListCtrl::GetLastVisible(bool fullRow, bool within) const
5063
{ return m_main_win->GetLastVisible(fullRow, within); }
5065
wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const
5066
{ return m_main_win->GetNextVisible(item, fullRow, within); }
5068
wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const
5069
{ return m_main_win->GetPrevVisible(item, fullRow, within); }
5071
wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
5072
int selectedImage, wxTreeItemData* data)
5073
{ return m_main_win->AddRoot (text, image, selectedImage, data); }
5075
wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
5076
const wxString& text, int image,
5078
wxTreeItemData* data)
5079
{ return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
5081
wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
5082
const wxTreeItemId& previous,
5083
const wxString& text, int image,
5085
wxTreeItemData* data)
5087
return m_main_win->InsertItem(parent, previous, text, image,
5088
selectedImage, data);
5091
wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
5093
const wxString& text, int image,
5095
wxTreeItemData* data)
5097
return m_main_win->InsertItem(parent, index, text, image,
5098
selectedImage, data);
5101
wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
5102
const wxString& text, int image,
5104
wxTreeItemData* data)
5105
{ return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
5107
void wxTreeListCtrl::Delete(const wxTreeItemId& item)
5108
{ m_main_win->Delete(item); }
5110
void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
5111
{ m_main_win->DeleteChildren(item); }
5113
void wxTreeListCtrl::DeleteRoot()
5114
{ m_main_win->DeleteRoot(); }
5116
void wxTreeListCtrl::Expand(const wxTreeItemId& item)
5117
{ m_main_win->Expand(item); }
5119
void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
5120
{ m_main_win->ExpandAll(item); }
5122
void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
5123
{ m_main_win->Collapse(item); }
5125
void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
5126
{ m_main_win->CollapseAndReset(item); }
5128
void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
5129
{ m_main_win->Toggle(item); }
5131
void wxTreeListCtrl::Unselect()
5132
{ m_main_win->Unselect(); }
5134
void wxTreeListCtrl::UnselectAll()
5135
{ m_main_win->UnselectAll(); }
5137
bool wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
5138
bool unselect_others)
5139
{ return m_main_win->SelectItem (item, last, unselect_others); }
5141
void wxTreeListCtrl::SelectAll()
5142
{ m_main_win->SelectAll(); }
5144
void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
5145
{ m_main_win->EnsureVisible(item); }
5147
void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
5148
{ m_main_win->ScrollTo(item); }
5150
wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
5152
wxPoint p = m_main_win->ScreenToClient (ClientToScreen (pos));
5153
return m_main_win->HitTest (p, flags, column);
5156
bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
5157
bool textOnly) const
5158
{ return m_main_win->GetBoundingRect(item, rect, textOnly); }
5160
void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
5161
{ m_main_win->EditLabel (item, column); }
5162
void wxTreeListCtrl::EndEdit(bool isCancelled)
5163
{ m_main_win->EndEdit(isCancelled); }
5165
int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
5167
// do the comparison here and not in m_main_win in order to allow
5168
// override in child class
5169
return wxStrcmp(GetItemText(item1), GetItemText(item2));
5171
int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2, int column)
5173
// do the comparison here and not in m_main_win in order to allow
5174
// override in child class
5175
return wxStrcmp(GetItemText(item1, column), GetItemText(item2, column));
5178
void wxTreeListCtrl::SortChildren(const wxTreeItemId& item, int column, bool reverseOrder)
5179
{ m_main_win->SortChildren(item, column, reverseOrder); }
5181
wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode)
5182
{ return m_main_win->FindItem (item, column, str, mode); }
5184
void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
5185
{ m_main_win->SetDragItem (item); }
5187
bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
5189
if (!m_main_win) return false;
5190
return m_main_win->SetBackgroundColour(colour);
5193
bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
5195
if (!m_main_win) return false;
5196
return m_main_win->SetForegroundColour(colour);
5199
int wxTreeListCtrl::GetColumnCount() const
5200
{ return m_main_win->GetColumnCount(); }
5202
void wxTreeListCtrl::SetColumnWidth(int column, int width)
5204
m_header_win->SetColumnWidth (column, width);
5205
m_header_win->Refresh();
5208
int wxTreeListCtrl::GetColumnWidth(int column) const
5209
{ return m_header_win->GetColumnWidth(column); }
5211
void wxTreeListCtrl::SetMainColumn(int column)
5212
{ m_main_win->SetMainColumn(column); }
5214
int wxTreeListCtrl::GetMainColumn() const
5215
{ return m_main_win->GetMainColumn(); }
5217
void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
5219
m_header_win->SetColumnText (column, text);
5220
m_header_win->Refresh();
5223
wxString wxTreeListCtrl::GetColumnText(int column) const
5224
{ return m_header_win->GetColumnText(column); }
5226
void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
5228
m_header_win->AddColumn (colInfo);
5232
void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
5234
m_header_win->InsertColumn (before, colInfo);
5235
m_header_win->Refresh();
5238
void wxTreeListCtrl::RemoveColumn(int column)
5240
m_header_win->RemoveColumn (column);
5241
m_header_win->Refresh();
5244
void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
5246
m_header_win->SetColumn (column, colInfo);
5247
m_header_win->Refresh();
5250
const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
5251
{ return m_header_win->GetColumn(column); }
5253
wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column)
5254
{ return m_header_win->GetColumn(column); }
5256
void wxTreeListCtrl::SetColumnImage(int column, int image)
5258
m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
5259
m_header_win->Refresh();
5262
int wxTreeListCtrl::GetColumnImage(int column) const
5264
return m_header_win->GetColumn(column).GetImage();
5267
void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
5269
m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
5272
void wxTreeListCtrl::SetColumnShown(int column, bool shown)
5274
wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
5275
m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
5276
m_header_win->Refresh();
5279
bool wxTreeListCtrl::IsColumnEditable(int column) const
5281
return m_header_win->GetColumn(column).IsEditable();
5284
bool wxTreeListCtrl::IsColumnShown(int column) const
5286
return m_header_win->GetColumn(column).IsShown();
5289
void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
5291
m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
5292
m_header_win->Refresh();
5295
int wxTreeListCtrl::GetColumnAlignment(int column) const
5297
return m_header_win->GetColumn(column).GetAlignment();
5300
void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
5302
m_main_win->Refresh (erase, rect);
5303
m_header_win->Refresh (erase, rect);
5306
void wxTreeListCtrl::SetFocus()
5307
{ m_main_win->SetFocus(); }
5309
wxSize wxTreeListCtrl::DoGetBestSize() const
5311
wxSize bestSizeHeader = m_header_win->GetBestSize();
5312
wxSize bestSizeMain = m_main_win->GetBestSize();
5313
return wxSize (bestSizeHeader.x > bestSizeMain.x ? bestSizeHeader.x : bestSizeMain.x, bestSizeHeader.y + bestSizeMain.y);
5316
wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
5318
return wxEmptyString;
5321
void wxTreeListCtrl::SetToolTip(const wxString& tip) {
5322
m_header_win->SetToolTip(tip);
5323
m_main_win->SetToolTip(tip);
5325
void wxTreeListCtrl::SetToolTip(wxToolTip *tip) {
5326
m_header_win->SetToolTip(tip);
5327
m_main_win->SetToolTip(tip);
5330
void wxTreeListCtrl::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
5331
m_main_win->SetItemToolTip(item, tip);
5334
void wxTreeListCtrl::SetCurrentItem(const wxTreeItemId& itemId) {
5335
m_main_win->SetCurrentItem(itemId);