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