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