1 /////////////////////////////////////////////////////////////////////////////
2 // Name: generic/listctrl.cpp
3 // Purpose: generic implementation of wxListCtrl
4 // Author: Robert Roebling
5 // Vadim Zeitlin (virtual list control support)
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
12 FIXME for virtual list controls
14 +1. clicking on the item with a mouse is awfully slow, what is going on?
15 note that selecting with keyboard seems to be much faster
16 => fixed HighlightAll() - iterating over 1000000 items *is* slow
18 2. background colour is wrong?
22 TODO for better virtual list control support:
24 1. less dumb line caching, we should cache at least all those visible
25 in the control itself and probably twice as many (we might also need to
26 cache the first one always for geometry calculations?)
28 +2. storing selections: we can't use an array to store the selected indices
29 like right now as selecting all in a control with 1000000 items is not
30 doable like this - instead, store selections as collection of individual
35 3. we need to implement searching/sorting somehow
37 4. the idea of storing the line index in the line itself is really stupid,
38 we shouldn't need it - but for this we have to get rid of all calles to
39 wxListLineData::GetFoo() and replace them with something like
41 ... we have it ourselves ...
47 5. attributes support: we need OnGetItemAttr() as well!
50 // ============================================================================
52 // ============================================================================
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
59 #pragma implementation "listctrl.h"
60 #pragma implementation "listctrlbase.h"
63 // For compilers that support precompilation, includes "wx.h".
64 #include "wx/wxprec.h"
72 #include "wx/dcscreen.h"
74 #include "wx/listctrl.h"
75 #include "wx/imaglist.h"
76 #include "wx/dynarray.h"
80 #include "wx/gtk/win_gtk.h"
83 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
)
88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
)
89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
)
90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
)
91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
)
92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
)
93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
)
94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
)
95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
)
96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
)
97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
)
98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
)
99 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
)
100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
)
101 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
)
102 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
)
103 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
)
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 // the height of the header window (FIXME: should depend on its font!)
110 static const int HEADER_HEIGHT
= 23;
112 // the scrollbar units
113 static const int SCROLL_UNIT_X
= 15;
114 static const int SCROLL_UNIT_Y
= 15;
116 // the spacing between the lines (in report mode)
117 static const int LINE_SPACING
= 0;
119 // extra margins around the text label
120 static const int EXTRA_WIDTH
= 3;
121 static const int EXTRA_HEIGHT
= 4;
123 // offset for the header window
124 static const int HEADER_OFFSET_X
= 1;
125 static const int HEADER_OFFSET_Y
= 1;
127 // when autosizing the columns, add some slack
128 static const int AUTOSIZE_COL_MARGIN
= 10;
130 // default and minimal widths for the header columns
131 static const int WIDTH_COL_DEFAULT
= 80;
132 static const int WIDTH_COL_MIN
= 10;
134 // ============================================================================
136 // ============================================================================
138 // ----------------------------------------------------------------------------
140 // ----------------------------------------------------------------------------
142 int CMPFUNC_CONV
wxSizeTCmpFn(size_t n1
, size_t n2
) { return n1
- n2
; }
144 WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray
);
146 // this class is used to store the selected items in the virtual list control
147 // (but it is not tied to list control and so can be used with other controls
148 // such as wxListBox in wxUniv)
150 // the idea is to make it really smart later (i.e. store the selections as an
151 // array of ranes + individual items) but, as I don't have time to do it now
152 // (this would require writing code to merge/break ranges and much more) keep
153 // it simple but define a clean interface to it which allows it to be made
155 class WXDLLEXPORT wxSelectionStore
158 wxSelectionStore() : m_itemsSel(wxSizeTCmpFn
) { Init(); }
160 // set the total number of items we handle
161 void SetItemCount(size_t count
) { m_count
= count
; }
163 // special case of SetItemCount(0)
164 void Clear() { m_itemsSel
.Clear(); m_count
= 0; }
166 // must be called when a new item is inserted/added
167 void OnItemAdd(size_t item
) { wxFAIL_MSG( _T("TODO") ); }
169 // must be called when an item is deleted
170 void OnItemDelete(size_t item
);
172 // select one item, use SelectRange() insted if possible!
174 // returns true if the items selection really changed
175 bool SelectItem(size_t item
, bool select
= TRUE
);
177 // select the range of items
178 void SelectRange(size_t itemFrom
, size_t itemTo
, bool select
= TRUE
);
180 // return true if the given item is selected
181 bool IsSelected(size_t item
) const;
183 // return the total number of selected items
184 size_t GetSelectedCount() const
186 return m_defaultState
? m_count
- m_itemsSel
.GetCount()
187 : m_itemsSel
.GetCount();
192 void Init() { m_defaultState
= FALSE
; }
194 // the total number of items we handle
197 // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
198 // there are more selected items than non selected ones - this allows to
199 // handle selection of all items efficiently
202 // the array of items whose selection state is different from default
203 wxIndexArray m_itemsSel
;
205 DECLARE_NO_COPY_CLASS(wxSelectionStore
)
208 //-----------------------------------------------------------------------------
209 // wxListItemData (internal)
210 //-----------------------------------------------------------------------------
212 class WXDLLEXPORT wxListItemData
215 wxListItemData(wxListMainWindow
*owner
);
218 void SetItem( const wxListItem
&info
);
219 void SetImage( int image
) { m_image
= image
; }
220 void SetData( long data
) { m_data
= data
; }
221 void SetPosition( int x
, int y
);
222 void SetSize( int width
, int height
);
224 bool HasText() const { return !m_text
.empty(); }
225 const wxString
& GetText() const { return m_text
; }
226 void SetText(const wxString
& text
) { m_text
= text
; }
228 // we can't use empty string for measuring the string width/height, so
229 // always return something
230 wxString
GetTextForMeasuring() const
232 wxString s
= GetText();
239 bool IsHit( int x
, int y
) const;
243 int GetWidth() const;
244 int GetHeight() const;
246 int GetImage() const { return m_image
; }
247 bool HasImage() const { return GetImage() != -1; }
249 void GetItem( wxListItem
&info
) const;
251 void SetAttr(wxListItemAttr
*attr
) { m_attr
= attr
; }
252 wxListItemAttr
*GetAttr() const { return m_attr
; }
255 // the item image or -1
258 // user data associated with the item
261 // the item coordinates are not used in report mode, instead this pointer
262 // is NULL and the owner window is used to retrieve the item position and
266 // the list ctrl we are in
267 wxListMainWindow
*m_owner
;
269 // custom attributes or NULL
270 wxListItemAttr
*m_attr
;
273 // common part of all ctors
279 //-----------------------------------------------------------------------------
280 // wxListHeaderData (internal)
281 //-----------------------------------------------------------------------------
283 class WXDLLEXPORT wxListHeaderData
: public wxObject
297 wxListHeaderData( const wxListItem
&info
);
298 void SetItem( const wxListItem
&item
);
299 void SetPosition( int x
, int y
);
300 void SetWidth( int w
);
301 void SetFormat( int format
);
302 void SetHeight( int h
);
303 bool HasImage() const;
305 bool HasText() const { return !m_text
.empty(); }
306 const wxString
& GetText() const { return m_text
; }
307 void SetText(const wxString
& text
) { m_text
= text
; }
309 void GetItem( wxListItem
&item
);
311 bool IsHit( int x
, int y
) const;
312 int GetImage() const;
313 int GetWidth() const;
314 int GetFormat() const;
317 DECLARE_DYNAMIC_CLASS(wxListHeaderData
);
320 //-----------------------------------------------------------------------------
321 // wxListLineData (internal)
322 //-----------------------------------------------------------------------------
324 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
);
325 #include "wx/listimpl.cpp"
326 WX_DEFINE_LIST(wxListItemDataList
);
328 class WXDLLEXPORT wxListLineData
331 // the list of subitems: only may have more than one item in report mode
332 wxListItemDataList m_items
;
334 // this is not used in report view
346 // the part to be highlighted
347 wxRect m_rectHighlight
;
350 // is this item selected? [NB: not used in virtual mode]
353 // back pointer to the list ctrl
354 wxListMainWindow
*m_owner
;
357 wxListLineData(wxListMainWindow
*owner
);
359 ~wxListLineData() { delete m_gi
; }
361 // are we in report mode?
362 inline bool InReportView() const;
364 // are we in virtual report mode?
365 inline bool IsVirtual() const;
367 // these 2 methods shouldn't be called for report view controls, in that
368 // case we determine our position/size ourselves
370 // calculate the size of the line
371 void CalculateSize( wxDC
*dc
, int spacing
);
373 // remember the position this line appears at
374 void SetPosition( int x
, int y
, int window_width
, int spacing
);
378 void SetImage( int image
) { SetImage(0, image
); }
379 int GetImage() const { return GetImage(0); }
380 bool HasImage() const { return GetImage() != -1; }
381 bool HasText() const { return !GetText(0).empty(); }
383 void SetItem( int index
, const wxListItem
&info
);
384 void GetItem( int index
, wxListItem
&info
);
386 wxString
GetText(int index
) const;
387 void SetText( int index
, const wxString s
);
389 wxListItemAttr
*GetAttr() const;
390 void SetAttr(wxListItemAttr
*attr
);
392 // return true if the highlighting really changed
393 bool Highlight( bool on
);
395 void ReverseHighlight();
397 bool IsHighlighted() const
399 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
401 return m_highlighted
;
404 // draw the line on the given DC in icon/list mode
405 void Draw( wxDC
*dc
);
407 // the same in report mode
408 void DrawInReportMode( wxDC
*dc
,
410 const wxRect
& rectHL
,
414 // set the line to contain num items (only can be > 1 in report mode)
415 void InitItems( int num
);
417 // get the mode (i.e. style) of the list control
418 inline int GetMode() const;
420 void SetAttributes(wxDC
*dc
,
421 const wxListItemAttr
*attr
,
422 const wxColour
& colText
,
426 // these are only used by GetImage/SetImage above, we don't support images
427 // with subitems at the public API level yet
428 void SetImage( int index
, int image
);
429 int GetImage( int index
) const;
432 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
);
433 #include "wx/arrimpl.cpp"
434 WX_DEFINE_OBJARRAY(wxListLineDataArray
);
436 //-----------------------------------------------------------------------------
437 // wxListHeaderWindow (internal)
438 //-----------------------------------------------------------------------------
440 class WXDLLEXPORT wxListHeaderWindow
: public wxWindow
443 wxListMainWindow
*m_owner
;
444 wxCursor
*m_currentCursor
;
445 wxCursor
*m_resizeCursor
;
448 // column being resized
451 // divider line position in logical (unscrolled) coords
454 // minimal position beyond which the divider line can't be dragged in
459 wxListHeaderWindow();
460 virtual ~wxListHeaderWindow();
462 wxListHeaderWindow( wxWindow
*win
,
464 wxListMainWindow
*owner
,
465 const wxPoint
&pos
= wxDefaultPosition
,
466 const wxSize
&size
= wxDefaultSize
,
468 const wxString
&name
= "wxlistctrlcolumntitles" );
470 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
472 void AdjustDC(wxDC
& dc
);
474 void OnPaint( wxPaintEvent
&event
);
475 void OnMouse( wxMouseEvent
&event
);
476 void OnSetFocus( wxFocusEvent
&event
);
482 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
)
483 DECLARE_EVENT_TABLE()
486 //-----------------------------------------------------------------------------
487 // wxListRenameTimer (internal)
488 //-----------------------------------------------------------------------------
490 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
493 wxListMainWindow
*m_owner
;
496 wxListRenameTimer( wxListMainWindow
*owner
);
500 //-----------------------------------------------------------------------------
501 // wxListTextCtrl (internal)
502 //-----------------------------------------------------------------------------
504 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
509 wxListMainWindow
*m_owner
;
510 wxString m_startValue
;
514 wxListTextCtrl( wxWindow
*parent
, const wxWindowID id
,
515 bool *accept
, wxString
*res
, wxListMainWindow
*owner
,
516 const wxString
&value
= "",
517 const wxPoint
&pos
= wxDefaultPosition
, const wxSize
&size
= wxDefaultSize
,
519 const wxValidator
& validator
= wxDefaultValidator
,
520 const wxString
&name
= "listctrltextctrl" );
521 void OnChar( wxKeyEvent
&event
);
522 void OnKeyUp( wxKeyEvent
&event
);
523 void OnKillFocus( wxFocusEvent
&event
);
526 DECLARE_DYNAMIC_CLASS(wxListTextCtrl
);
527 DECLARE_EVENT_TABLE()
530 //-----------------------------------------------------------------------------
531 // wxListMainWindow (internal)
532 //-----------------------------------------------------------------------------
534 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
);
535 #include "wx/listimpl.cpp"
536 WX_DEFINE_LIST(wxListHeaderDataList
);
538 class WXDLLEXPORT wxListMainWindow
: public wxScrolledWindow
542 wxListMainWindow( wxWindow
*parent
,
544 const wxPoint
& pos
= wxDefaultPosition
,
545 const wxSize
& size
= wxDefaultSize
,
547 const wxString
&name
= _T("listctrlmainwindow") );
549 virtual ~wxListMainWindow();
551 bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); }
553 // return true if this is a virtual list control
554 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); }
556 // return true if the control is in report mode
557 bool InReportView() const { return HasFlag(wxLC_REPORT
); }
559 // return true if we are in single selection mode, false if multi sel
560 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); }
562 // do we have a header window?
563 bool HasHeader() const
564 { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); }
566 void HighlightAll( bool on
);
568 // all these functions only do something if the line is currently visible
570 // change the line "selected" state, return TRUE if it really changed
571 bool HighlightLine( size_t line
, bool highlight
= TRUE
);
573 // as HighlightLine() but do it for the range of lines: this is incredibly
574 // more efficient for virtual list controls!
576 // NB: unlike HighlightLine() this one does refresh the lines on screen
577 void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on
= TRUE
);
579 // toggle the line state and refresh it
580 void ReverseHighlight( size_t line
)
581 { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); }
583 // return true if the line is highlighted
584 bool IsHighlighted(size_t line
) const;
586 // refresh one or several lines at once
587 void RefreshLine( size_t line
);
588 void RefreshLines( size_t lineFrom
, size_t lineTo
);
590 // refresh all lines below the given one: the difference with
591 // RefreshLines() is that the index here might not be a valid one (happens
592 // when the last line is deleted)
593 void RefreshAfter( size_t lineFrom
);
595 // the methods which are forwarded to wxListLineData itself in list/icon
596 // modes but are here because the lines don't store their positions in the
599 // get the bound rect for the entire line
600 wxRect
GetLineRect(size_t line
) const;
602 // get the bound rect of the label
603 wxRect
GetLineLabelRect(size_t line
) const;
605 // get the bound rect of the items icon (only may be called if we do have
607 wxRect
GetLineIconRect(size_t line
) const;
609 // get the rect to be highlighted when the item has focus
610 wxRect
GetLineHighlightRect(size_t line
) const;
612 // get the size of the total line rect
613 wxSize
GetLineSize(size_t line
) const
614 { return GetLineRect(line
).GetSize(); }
616 // return the hit code for the corresponding position (in this line)
617 long HitTestLine(size_t line
, int x
, int y
) const;
619 void EditLabel( long item
);
620 void OnRenameTimer();
621 void OnRenameAccept();
623 void OnMouse( wxMouseEvent
&event
);
626 // called to switch the selection from the current item to newCurrent,
627 void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event
);
629 void OnChar( wxKeyEvent
&event
);
630 void OnKeyDown( wxKeyEvent
&event
);
631 void OnSetFocus( wxFocusEvent
&event
);
632 void OnKillFocus( wxFocusEvent
&event
);
633 void OnScroll(wxScrollWinEvent
& event
) ;
635 void OnPaint( wxPaintEvent
&event
);
637 void DrawImage( int index
, wxDC
*dc
, int x
, int y
);
638 void GetImageSize( int index
, int &width
, int &height
) const;
639 int GetTextLength( const wxString
&s
) const;
641 void SetImageList( wxImageList
*imageList
, int which
);
642 void SetItemSpacing( int spacing
, bool isSmall
= FALSE
);
643 int GetItemSpacing( bool isSmall
= FALSE
);
645 void SetColumn( int col
, wxListItem
&item
);
646 void SetColumnWidth( int col
, int width
);
647 void GetColumn( int col
, wxListItem
&item
) const;
648 int GetColumnWidth( int col
) const;
649 int GetColumnCount() const { return m_columns
.GetCount(); }
651 // returns the sum of the heights of all columns
652 int GetHeaderWidth() const;
654 int GetCountPerPage() const;
656 void SetItem( wxListItem
&item
);
657 void GetItem( wxListItem
&item
);
658 void SetItemState( long item
, long state
, long stateMask
);
659 int GetItemState( long item
, long stateMask
);
660 void GetItemRect( long index
, wxRect
&rect
);
661 bool GetItemPosition( long item
, wxPoint
& pos
);
662 int GetSelectedItemCount();
664 // set the scrollbars and update the positions of the items
665 void RecalculatePositions();
667 // refresh the window and the header
670 long GetNextItem( long item
, int geometry
, int state
);
671 void DeleteItem( long index
);
672 void DeleteAllItems();
673 void DeleteColumn( int col
);
674 void DeleteEverything();
675 void EnsureVisible( long index
);
676 long FindItem( long start
, const wxString
& str
, bool partial
= FALSE
);
677 long FindItem( long start
, long data
);
678 long HitTest( int x
, int y
, int &flags
);
679 void InsertItem( wxListItem
&item
);
680 void InsertColumn( long col
, wxListItem
&item
);
681 void SortItems( wxListCtrlCompare fn
, long data
);
683 size_t GetItemCount() const;
684 bool IsEmpty() const { return GetItemCount() == 0; }
685 void SetItemCount(long count
);
687 void ResetCurrent() { m_current
= (size_t)-1; }
688 bool HasCurrent() const { return m_current
!= (size_t)-1; }
690 // send out a wxListEvent
691 void SendNotify( size_t line
,
693 wxPoint point
= wxDefaultPosition
);
695 // override base class virtual to reset m_lineHeight when the font changes
696 virtual bool SetFont(const wxFont
& font
)
698 if ( !wxScrolledWindow::SetFont(font
) )
706 // these are for wxListLineData usage only
708 // get the backpointer to the list ctrl
709 wxListCtrl
*GetListCtrl() const
711 return wxStaticCast(GetParent(), wxListCtrl
);
714 // get the height of all lines (assuming they all do have the same height)
715 wxCoord
GetLineHeight() const;
717 // get the y position of the given line (only for report view)
718 wxCoord
GetLineY(size_t line
) const;
721 // the array of all line objects for a non virtual list control
722 wxListLineDataArray m_lines
;
724 // the list of column objects
725 wxListHeaderDataList m_columns
;
727 // currently focused item or -1
730 // the item currently being edited or -1
731 size_t m_currentEdit
;
733 // the number of lines per page
736 // this flag is set when something which should result in the window
737 // redrawing happens (i.e. an item was added or deleted, or its appearance
738 // changed) and OnPaint() doesn't redraw the window while it is set which
739 // allows to minimize the number of repaintings when a lot of items are
740 // being added. The real repainting occurs only after the next OnIdle()
744 wxBrush
*m_highlightBrush
;
745 wxColour
*m_highlightColour
;
748 wxImageList
*m_small_image_list
;
749 wxImageList
*m_normal_image_list
;
751 int m_normal_spacing
;
755 wxTimer
*m_renameTimer
;
757 wxString m_renameRes
;
762 // for double click logic
763 size_t m_lineLastClicked
,
764 m_lineBeforeLastClicked
;
767 // the total count of items in a virtual list control
770 // the object maintaining the items selection state, only used in virtual
772 wxSelectionStore m_selStore
;
774 // common part of all ctors
777 // intiialize m_[xy]Scroll
778 void InitScrolling();
780 // get the line data for the given index
781 wxListLineData
*GetLine(size_t n
) const
783 wxASSERT_MSG( n
!= (size_t)-1, _T("invalid line index") );
787 wxConstCast(this, wxListMainWindow
)->CacheLineData(n
);
795 // get a dummy line which can be used for geometry calculations and such:
796 // you must use GetLine() if you want to really draw the line
797 wxListLineData
*GetDummyLine() const;
799 // cache the line data of the n-th line in m_lines[0]
800 void CacheLineData(size_t line
);
802 // get the range of visible lines
803 void GetVisibleLinesRange(size_t *from
, size_t *to
);
805 // force us to recalculate the range of visible lines
806 void ResetVisibleLinesRange() { m_lineFrom
= (size_t)-1; }
808 // get the colour to be used for drawing the rules
809 wxColour
GetRuleColour() const
814 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
);
819 // initialize the current item if needed
820 void UpdateCurrent();
822 // delete all items but don't refresh: called from dtor
823 void DoDeleteAllItems();
825 // called when an item is [un]focuded, i.e. becomes [not] current
828 void OnFocusLine( size_t line
);
829 void OnUnfocusLine( size_t line
);
831 // the height of one line using the current font
832 wxCoord m_lineHeight
;
834 // the total header width or 0 if not calculated yet
835 wxCoord m_headerWidth
;
837 // the first and last lines being shown on screen right now (inclusive),
838 // both may be -1 if they must be calculated so never access them directly:
839 // use GetVisibleLinesRange() above instead
843 DECLARE_DYNAMIC_CLASS(wxListMainWindow
);
844 DECLARE_EVENT_TABLE()
847 // ============================================================================
849 // ============================================================================
851 // ----------------------------------------------------------------------------
853 // ----------------------------------------------------------------------------
855 bool wxSelectionStore::IsSelected(size_t item
) const
857 bool isSel
= m_itemsSel
.Index(item
) != wxNOT_FOUND
;
859 // if the default state is to be selected, being in m_itemsSel means that
860 // the item is not selected, so we have to inverse the logic
861 return m_defaultState
? !isSel
: isSel
;
864 bool wxSelectionStore::SelectItem(size_t item
, bool select
)
866 // search for the item ourselves as like this we get the index where to
867 // insert it later if needed, so we do only one search in the array instead
868 // of two (adding item to a sorted array requires a search)
869 size_t index
= m_itemsSel
.IndexForInsert(item
);
870 bool isSel
= index
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
;
872 if ( select
!= m_defaultState
)
876 m_itemsSel
.AddAt(item
, index
);
881 else // reset to default state
885 m_itemsSel
.RemoveAt(index
);
893 void wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, bool select
)
895 wxASSERT_MSG( itemFrom
<= itemTo
, _T("should be in order") );
897 // are we going to have more [un]selected items than the other ones?
898 if ( itemTo
- itemFrom
> m_count
/ 2 )
900 if ( select
!= m_defaultState
)
902 // the default state now becomes the same as 'select'
903 m_defaultState
= select
;
905 // so all the old selections (which had state select) shouldn't be
906 // selected any more, but all the other ones should
907 wxIndexArray selOld
= m_itemsSel
;
910 // TODO: it should be possible to optimize the searches a bit
911 // knowing the possible range
914 for ( item
= 0; item
< itemFrom
; item
++ )
916 if ( selOld
.Index(item
) == wxNOT_FOUND
)
917 m_itemsSel
.Add(item
);
920 for ( item
= itemTo
+ 1; item
< m_count
; item
++ )
922 if ( selOld
.Index(item
) == wxNOT_FOUND
)
923 m_itemsSel
.Add(item
);
926 else // select == m_defaultState
928 // get the inclusive range of items between itemFrom and itemTo
929 size_t count
= m_itemsSel
.GetCount(),
930 start
= m_itemsSel
.IndexForInsert(itemFrom
),
931 end
= m_itemsSel
.IndexForInsert(itemTo
);
933 if ( start
== count
|| m_itemsSel
[start
] < itemFrom
)
938 if ( end
== count
|| m_itemsSel
[end
] > itemTo
)
945 // delete all of them (from end to avoid changing indices)
946 for ( int i
= end
; i
>= (int)start
; i
-- )
948 m_itemsSel
.RemoveAt(i
);
953 else // "few" items change state
955 // just add the items to the selection
956 for ( size_t item
= itemFrom
; item
<= itemTo
; item
++ )
958 SelectItem(item
, select
);
963 void wxSelectionStore::OnItemDelete(size_t item
)
965 size_t count
= m_itemsSel
.GetCount(),
966 i
= m_itemsSel
.IndexForInsert(item
);
968 if ( i
< count
&& m_itemsSel
[i
] == item
)
970 // this item itself was in m_itemsSel, remove it from there
971 m_itemsSel
.RemoveAt(i
);
976 // and adjust the index of all which follow it
979 // all following elements must be greater than the one we deleted
980 wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") );
986 //-----------------------------------------------------------------------------
988 //-----------------------------------------------------------------------------
990 wxListItemData::~wxListItemData()
992 // in the virtual list control the attributes are managed by the main
993 // program, so don't delete them
994 if ( !m_owner
->IsVirtual() )
1002 void wxListItemData::Init()
1010 wxListItemData::wxListItemData(wxListMainWindow
*owner
)
1016 if ( owner
->InReportView() )
1022 m_rect
= new wxRect
;
1026 void wxListItemData::SetItem( const wxListItem
&info
)
1028 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
1029 SetText(info
.m_text
);
1030 if ( info
.m_mask
& wxLIST_MASK_IMAGE
)
1031 m_image
= info
.m_image
;
1032 if ( info
.m_mask
& wxLIST_MASK_DATA
)
1033 m_data
= info
.m_data
;
1035 if ( info
.HasAttributes() )
1038 *m_attr
= *info
.GetAttributes();
1040 m_attr
= new wxListItemAttr(*info
.GetAttributes());
1048 m_rect
->width
= info
.m_width
;
1052 void wxListItemData::SetPosition( int x
, int y
)
1054 wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") );
1060 void wxListItemData::SetSize( int width
, int height
)
1062 wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") );
1065 m_rect
->width
= width
;
1067 m_rect
->height
= height
;
1070 bool wxListItemData::IsHit( int x
, int y
) const
1072 wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") );
1074 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
);
1077 int wxListItemData::GetX() const
1079 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1084 int wxListItemData::GetY() const
1086 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1091 int wxListItemData::GetWidth() const
1093 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1095 return m_rect
->width
;
1098 int wxListItemData::GetHeight() const
1100 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1102 return m_rect
->height
;
1105 void wxListItemData::GetItem( wxListItem
&info
) const
1107 info
.m_text
= m_text
;
1108 info
.m_image
= m_image
;
1109 info
.m_data
= m_data
;
1113 if ( m_attr
->HasTextColour() )
1114 info
.SetTextColour(m_attr
->GetTextColour());
1115 if ( m_attr
->HasBackgroundColour() )
1116 info
.SetBackgroundColour(m_attr
->GetBackgroundColour());
1117 if ( m_attr
->HasFont() )
1118 info
.SetFont(m_attr
->GetFont());
1122 //-----------------------------------------------------------------------------
1124 //-----------------------------------------------------------------------------
1126 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
);
1128 wxListHeaderData::wxListHeaderData()
1139 wxListHeaderData::wxListHeaderData( const wxListItem
&item
)
1147 void wxListHeaderData::SetItem( const wxListItem
&item
)
1149 m_mask
= item
.m_mask
;
1150 m_text
= item
.m_text
;
1151 m_image
= item
.m_image
;
1152 m_format
= item
.m_format
;
1154 SetWidth(item
.m_width
);
1157 void wxListHeaderData::SetPosition( int x
, int y
)
1163 void wxListHeaderData::SetHeight( int h
)
1168 void wxListHeaderData::SetWidth( int w
)
1172 m_width
= WIDTH_COL_DEFAULT
;
1173 if (m_width
< WIDTH_COL_MIN
)
1174 m_width
= WIDTH_COL_MIN
;
1177 void wxListHeaderData::SetFormat( int format
)
1182 bool wxListHeaderData::HasImage() const
1184 return (m_image
!= 0);
1187 bool wxListHeaderData::IsHit( int x
, int y
) const
1189 return ((x
>= m_xpos
) && (x
<= m_xpos
+m_width
) && (y
>= m_ypos
) && (y
<= m_ypos
+m_height
));
1192 void wxListHeaderData::GetItem( wxListItem
&item
)
1194 item
.m_mask
= m_mask
;
1195 item
.m_text
= m_text
;
1196 item
.m_image
= m_image
;
1197 item
.m_format
= m_format
;
1198 item
.m_width
= m_width
;
1201 int wxListHeaderData::GetImage() const
1206 int wxListHeaderData::GetWidth() const
1211 int wxListHeaderData::GetFormat() const
1216 //-----------------------------------------------------------------------------
1218 //-----------------------------------------------------------------------------
1220 inline int wxListLineData::GetMode() const
1222 return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
;
1225 inline bool wxListLineData::InReportView() const
1227 return m_owner
->HasFlag(wxLC_REPORT
);
1230 inline bool wxListLineData::IsVirtual() const
1232 return m_owner
->IsVirtual();
1235 wxListLineData::wxListLineData( wxListMainWindow
*owner
)
1238 m_items
.DeleteContents( TRUE
);
1240 if ( InReportView() )
1246 m_gi
= new GeometryInfo
;
1249 m_highlighted
= FALSE
;
1251 InitItems( GetMode() == wxLC_REPORT
? m_owner
->GetColumnCount() : 1 );
1254 void wxListLineData::CalculateSize( wxDC
*dc
, int spacing
)
1256 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1257 wxCHECK_RET( node
, _T("no subitems at all??") );
1259 wxListItemData
*item
= node
->GetData();
1261 switch ( GetMode() )
1264 case wxLC_SMALL_ICON
:
1266 m_gi
->m_rectAll
.width
= spacing
;
1268 wxString s
= item
->GetText();
1274 m_gi
->m_rectLabel
.width
=
1275 m_gi
->m_rectLabel
.height
= 0;
1279 dc
->GetTextExtent( s
, &lw
, &lh
);
1280 if (lh
< SCROLL_UNIT_Y
)
1285 m_gi
->m_rectAll
.height
= spacing
+ lh
;
1287 m_gi
->m_rectAll
.width
= lw
;
1289 m_gi
->m_rectLabel
.width
= lw
;
1290 m_gi
->m_rectLabel
.height
= lh
;
1293 if (item
->HasImage())
1296 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1297 m_gi
->m_rectIcon
.width
= w
+ 8;
1298 m_gi
->m_rectIcon
.height
= h
+ 8;
1300 if ( m_gi
->m_rectIcon
.width
> m_gi
->m_rectAll
.width
)
1301 m_gi
->m_rectAll
.width
= m_gi
->m_rectIcon
.width
;
1302 if ( m_gi
->m_rectIcon
.height
+ lh
> m_gi
->m_rectAll
.height
- 4 )
1303 m_gi
->m_rectAll
.height
= m_gi
->m_rectIcon
.height
+ lh
+ 4;
1306 if ( item
->HasText() )
1308 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectLabel
.width
;
1309 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectLabel
.height
;
1311 else // no text, highlight the icon
1313 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectIcon
.width
;
1314 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectIcon
.height
;
1321 wxString s
= item
->GetTextForMeasuring();
1324 dc
->GetTextExtent( s
, &lw
, &lh
);
1325 if (lh
< SCROLL_UNIT_Y
)
1330 m_gi
->m_rectLabel
.width
= lw
;
1331 m_gi
->m_rectLabel
.height
= lh
;
1333 m_gi
->m_rectAll
.width
= lw
;
1334 m_gi
->m_rectAll
.height
= lh
;
1336 if (item
->HasImage())
1339 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1340 m_gi
->m_rectIcon
.width
= w
;
1341 m_gi
->m_rectIcon
.height
= h
;
1343 m_gi
->m_rectAll
.width
+= 4 + w
;
1344 if (h
> m_gi
->m_rectAll
.height
)
1345 m_gi
->m_rectAll
.height
= h
;
1348 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectAll
.width
;
1349 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectAll
.height
;
1354 wxFAIL_MSG( _T("unexpected call to SetSize") );
1358 wxFAIL_MSG( _T("unknown mode") );
1362 void wxListLineData::SetPosition( int x
, int y
,
1366 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1367 wxCHECK_RET( node
, _T("no subitems at all??") );
1369 wxListItemData
*item
= node
->GetData();
1371 switch ( GetMode() )
1374 case wxLC_SMALL_ICON
:
1375 m_gi
->m_rectAll
.x
= x
;
1376 m_gi
->m_rectAll
.y
= y
;
1378 if ( item
->HasImage() )
1380 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 4
1381 + (spacing
- m_gi
->m_rectIcon
.width
)/2;
1382 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 4;
1385 if ( item
->HasText() )
1387 if (m_gi
->m_rectAll
.width
> spacing
)
1388 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1390 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2);
1391 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ m_gi
->m_rectAll
.height
+ 2 - m_gi
->m_rectLabel
.height
;
1392 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectLabel
.x
- 2;
1393 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectLabel
.y
- 2;
1395 else // no text, highlight the icon
1397 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectIcon
.x
- 4;
1398 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectIcon
.y
- 4;
1403 m_gi
->m_rectAll
.x
= x
;
1404 m_gi
->m_rectAll
.y
= y
;
1406 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectAll
.x
;
1407 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectAll
.y
;
1408 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ 2;
1410 if (item
->HasImage())
1412 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 2;
1413 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 2;
1414 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 6 + m_gi
->m_rectIcon
.width
;
1418 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1423 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1427 wxFAIL_MSG( _T("unknown mode") );
1431 void wxListLineData::InitItems( int num
)
1433 for (int i
= 0; i
< num
; i
++)
1434 m_items
.Append( new wxListItemData(m_owner
) );
1437 void wxListLineData::SetItem( int index
, const wxListItem
&info
)
1439 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1440 wxCHECK_RET( node
, _T("invalid column index in SetItem") );
1442 wxListItemData
*item
= node
->GetData();
1443 item
->SetItem( info
);
1446 void wxListLineData::GetItem( int index
, wxListItem
&info
)
1448 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1451 wxListItemData
*item
= node
->GetData();
1452 item
->GetItem( info
);
1456 wxString
wxListLineData::GetText(int index
) const
1460 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1463 wxListItemData
*item
= node
->GetData();
1464 s
= item
->GetText();
1470 void wxListLineData::SetText( int index
, const wxString s
)
1472 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1475 wxListItemData
*item
= node
->GetData();
1480 void wxListLineData::SetImage( int index
, int image
)
1482 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1483 wxCHECK_RET( node
, _T("invalid column index in SetImage()") );
1485 wxListItemData
*item
= node
->GetData();
1486 item
->SetImage(image
);
1489 int wxListLineData::GetImage( int index
) const
1491 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1492 wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") );
1494 wxListItemData
*item
= node
->GetData();
1495 return item
->GetImage();
1498 wxListItemAttr
*wxListLineData::GetAttr() const
1500 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1501 wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") );
1503 wxListItemData
*item
= node
->GetData();
1504 return item
->GetAttr();
1507 void wxListLineData::SetAttr(wxListItemAttr
*attr
)
1509 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1510 wxCHECK_RET( node
, _T("invalid column index in SetAttr()") );
1512 wxListItemData
*item
= node
->GetData();
1513 item
->SetAttr(attr
);
1516 void wxListLineData::SetAttributes(wxDC
*dc
,
1517 const wxListItemAttr
*attr
,
1518 const wxColour
& colText
,
1522 // don't use foregroud colour for drawing highlighted items - this might
1523 // make them completely invisible (and there is no way to do bit
1524 // arithmetics on wxColour, unfortunately)
1525 if ( !highlight
&& attr
&& attr
->HasTextColour() )
1527 dc
->SetTextForeground(attr
->GetTextColour());
1531 dc
->SetTextForeground(colText
);
1534 if ( attr
&& attr
->HasFont() )
1536 dc
->SetFont(attr
->GetFont());
1544 void wxListLineData::Draw( wxDC
*dc
)
1546 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1547 wxCHECK_RET( node
, _T("no subitems at all??") );
1549 wxListItemData
*item
= node
->GetData();
1550 if (item
->HasImage())
1552 wxRect rectIcon
= m_gi
->m_rectIcon
;
1553 m_owner
->DrawImage( item
->GetImage(), dc
,
1554 rectIcon
.x
, rectIcon
.y
);
1557 if (item
->HasText())
1559 wxRect rectLabel
= m_gi
->m_rectLabel
;
1560 dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y
);
1564 void wxListLineData::DrawInReportMode( wxDC
*dc
,
1566 const wxRect
& rectHL
,
1569 // use our own flag if we maintain it
1571 highlighted
= m_highlighted
;
1573 // default foreground colour
1574 wxWindow
*listctrl
= m_owner
->GetParent();
1578 colText
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT
);
1582 colText
= listctrl
->GetForegroundColour();
1586 wxFont font
= listctrl
->GetFont();
1588 // TODO: later we should support setting different attributes for
1589 // different columns - to do it, just add "col" argument to
1590 // GetAttr() and move this code into the loop below
1591 wxListItemAttr
*attr
= GetAttr();
1592 SetAttributes(dc
, attr
, colText
, font
, highlighted
);
1594 bool hasBgCol
= attr
&& attr
->HasBackgroundColour();
1595 if ( highlighted
|| hasBgCol
)
1599 dc
->SetBrush( *m_owner
->m_highlightBrush
);
1604 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
1606 dc
->SetBrush( * wxWHITE_BRUSH
);
1609 dc
->SetPen( * wxTRANSPARENT_PEN
);
1610 dc
->DrawRectangle( rectHL
);
1613 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1614 wxCHECK_RET( node
, _T("no subitems at all??") );
1617 wxCoord x
= rect
.x
+ HEADER_OFFSET_X
,
1618 y
= rect
.y
+ (LINE_SPACING
+ EXTRA_HEIGHT
) / 2;
1622 wxListItemData
*item
= node
->GetData();
1626 if ( item
->HasImage() )
1629 m_owner
->DrawImage( item
->GetImage(), dc
, x
, y
);
1630 m_owner
->GetImageSize( item
->GetImage(), ix
, iy
);
1631 x
+= ix
+ 5; // FIXME: what is "5"?
1634 int width
= m_owner
->GetColumnWidth(col
++);
1636 wxDCClipper
clipper(*dc
, x
, y
, width
, rect
.height
);
1638 if ( item
->HasText() )
1640 dc
->DrawText( item
->GetText(), x
, y
);
1645 node
= node
->GetNext();
1649 bool wxListLineData::Highlight( bool on
)
1651 wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") );
1653 if ( on
== m_highlighted
)
1661 void wxListLineData::ReverseHighlight( void )
1663 Highlight(!IsHighlighted());
1666 //-----------------------------------------------------------------------------
1667 // wxListHeaderWindow
1668 //-----------------------------------------------------------------------------
1670 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
);
1672 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
)
1673 EVT_PAINT (wxListHeaderWindow::OnPaint
)
1674 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse
)
1675 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus
)
1678 wxListHeaderWindow::wxListHeaderWindow( void )
1680 m_owner
= (wxListMainWindow
*) NULL
;
1681 m_currentCursor
= (wxCursor
*) NULL
;
1682 m_resizeCursor
= (wxCursor
*) NULL
;
1683 m_isDragging
= FALSE
;
1686 wxListHeaderWindow::wxListHeaderWindow( wxWindow
*win
, wxWindowID id
, wxListMainWindow
*owner
,
1687 const wxPoint
&pos
, const wxSize
&size
,
1688 long style
, const wxString
&name
) :
1689 wxWindow( win
, id
, pos
, size
, style
, name
)
1692 // m_currentCursor = wxSTANDARD_CURSOR;
1693 m_currentCursor
= (wxCursor
*) NULL
;
1694 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
1695 m_isDragging
= FALSE
;
1698 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE
) );
1701 wxListHeaderWindow::~wxListHeaderWindow( void )
1703 delete m_resizeCursor
;
1706 void wxListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1709 GtkStateType state
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
1710 : GTK_STATE_INSENSITIVE
;
1712 x
= dc
->XLOG2DEV( x
);
1714 gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
,
1715 state
, GTK_SHADOW_OUT
,
1716 (GdkRectangle
*) NULL
, m_wxwindow
, "button",
1717 x
-1, y
-1, w
+2, h
+2);
1718 #elif defined( __WXMAC__ )
1719 const int m_corner
= 1;
1721 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1723 dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
) , 1 , wxSOLID
) );
1724 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1725 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1727 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1730 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1731 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1733 dc
->SetPen( *wxWHITE_PEN
);
1734 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1735 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1736 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1737 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1739 const int m_corner
= 1;
1741 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1743 dc
->SetPen( *wxBLACK_PEN
);
1744 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1745 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1747 wxPen
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1750 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1751 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1753 dc
->SetPen( *wxWHITE_PEN
);
1754 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1755 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1756 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1757 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1761 // shift the DC origin to match the position of the main window horz
1762 // scrollbar: this allows us to always use logical coords
1763 void wxListHeaderWindow::AdjustDC(wxDC
& dc
)
1766 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1769 m_owner
->GetViewStart( &x
, NULL
);
1771 // account for the horz scrollbar offset
1772 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1775 void wxListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1778 wxClientDC
dc( this );
1780 wxPaintDC
dc( this );
1788 dc
.SetFont( GetFont() );
1790 // width and height of the entire header window
1792 GetClientSize( &w
, &h
);
1793 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1795 dc
.SetBackgroundMode(wxTRANSPARENT
);
1797 // do *not* use the listctrl colour for headers - one day we will have a
1798 // function to set it separately
1799 //dc.SetTextForeground( *wxBLACK );
1800 dc
.SetTextForeground(wxSystemSettings::
1801 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1803 int x
= HEADER_OFFSET_X
;
1805 int numColumns
= m_owner
->GetColumnCount();
1807 for (int i
= 0; i
< numColumns
; i
++)
1809 m_owner
->GetColumn( i
, item
);
1810 int wCol
= item
.m_width
;
1811 int cw
= wCol
- 2; // the width of the rect to draw
1813 int xEnd
= x
+ wCol
;
1815 dc
.SetPen( *wxWHITE_PEN
);
1817 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1818 dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 );
1819 dc
.DrawText( item
.GetText(), x
+ EXTRA_WIDTH
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1820 dc
.DestroyClippingRegion();
1829 void wxListHeaderWindow::DrawCurrent()
1831 int x1
= m_currentX
;
1833 ClientToScreen( &x1
, &y1
);
1835 int x2
= m_currentX
-1;
1837 m_owner
->GetClientSize( NULL
, &y2
);
1838 m_owner
->ClientToScreen( &x2
, &y2
);
1841 dc
.SetLogicalFunction( wxINVERT
);
1842 dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID
) );
1843 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1847 dc
.DrawLine( x1
, y1
, x2
, y2
);
1849 dc
.SetLogicalFunction( wxCOPY
);
1851 dc
.SetPen( wxNullPen
);
1852 dc
.SetBrush( wxNullBrush
);
1855 void wxListHeaderWindow::OnMouse( wxMouseEvent
&event
)
1857 // we want to work with logical coords
1859 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1860 int y
= event
.GetY();
1864 // we don't draw the line beyond our window, but we allow dragging it
1867 GetClientSize( &w
, NULL
);
1868 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1871 // erase the line if it was drawn
1872 if ( m_currentX
< w
)
1875 if (event
.ButtonUp())
1878 m_isDragging
= FALSE
;
1880 m_owner
->SetColumnWidth( m_column
, m_currentX
- m_minX
);
1887 m_currentX
= m_minX
+ 7;
1889 // draw in the new location
1890 if ( m_currentX
< w
)
1894 else // not dragging
1897 bool hit_border
= FALSE
;
1899 // end of the current column
1902 // find the column where this event occured
1903 int countCol
= m_owner
->GetColumnCount();
1904 for (int col
= 0; col
< countCol
; col
++)
1906 xpos
+= m_owner
->GetColumnWidth( col
);
1909 if ( (abs(x
-xpos
) < 3) && (y
< 22) )
1911 // near the column border
1918 // inside the column
1925 if (event
.LeftDown())
1929 m_isDragging
= TRUE
;
1936 wxWindow
*parent
= GetParent();
1937 wxListEvent
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() );
1938 le
.SetEventObject( parent
);
1939 le
.m_col
= m_column
;
1940 parent
->GetEventHandler()->ProcessEvent( le
);
1943 else if (event
.Moving())
1948 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1949 m_currentCursor
= m_resizeCursor
;
1953 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1954 m_currentCursor
= wxSTANDARD_CURSOR
;
1958 SetCursor(*m_currentCursor
);
1963 void wxListHeaderWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
1965 m_owner
->SetFocus();
1968 //-----------------------------------------------------------------------------
1969 // wxListRenameTimer (internal)
1970 //-----------------------------------------------------------------------------
1972 wxListRenameTimer::wxListRenameTimer( wxListMainWindow
*owner
)
1977 void wxListRenameTimer::Notify()
1979 m_owner
->OnRenameTimer();
1982 //-----------------------------------------------------------------------------
1983 // wxListTextCtrl (internal)
1984 //-----------------------------------------------------------------------------
1986 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
);
1988 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
)
1989 EVT_CHAR (wxListTextCtrl::OnChar
)
1990 EVT_KEY_UP (wxListTextCtrl::OnKeyUp
)
1991 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus
)
1994 wxListTextCtrl::wxListTextCtrl( wxWindow
*parent
,
1995 const wxWindowID id
,
1998 wxListMainWindow
*owner
,
1999 const wxString
&value
,
2003 const wxValidator
& validator
,
2004 const wxString
&name
)
2005 : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name
)
2010 (*m_accept
) = FALSE
;
2012 m_startValue
= value
;
2015 void wxListTextCtrl::OnChar( wxKeyEvent
&event
)
2017 if (event
.m_keyCode
== WXK_RETURN
)
2020 (*m_res
) = GetValue();
2022 if (!wxPendingDelete
.Member(this))
2023 wxPendingDelete
.Append(this);
2025 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2026 m_owner
->OnRenameAccept();
2030 if (event
.m_keyCode
== WXK_ESCAPE
)
2032 (*m_accept
) = FALSE
;
2035 if (!wxPendingDelete
.Member(this))
2036 wxPendingDelete
.Append(this);
2044 void wxListTextCtrl::OnKeyUp( wxKeyEvent
&event
)
2046 // auto-grow the textctrl:
2047 wxSize parentSize
= m_owner
->GetSize();
2048 wxPoint myPos
= GetPosition();
2049 wxSize mySize
= GetSize();
2051 GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM??
2052 if (myPos
.x
+ sx
> parentSize
.x
)
2053 sx
= parentSize
.x
- myPos
.x
;
2061 void wxListTextCtrl::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
2063 if (!wxPendingDelete
.Member(this))
2064 wxPendingDelete
.Append(this);
2066 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2067 m_owner
->OnRenameAccept();
2070 //-----------------------------------------------------------------------------
2072 //-----------------------------------------------------------------------------
2074 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
);
2076 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
)
2077 EVT_PAINT (wxListMainWindow::OnPaint
)
2078 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse
)
2079 EVT_CHAR (wxListMainWindow::OnChar
)
2080 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown
)
2081 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus
)
2082 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus
)
2083 EVT_SCROLLWIN (wxListMainWindow::OnScroll
)
2086 void wxListMainWindow::Init()
2088 m_columns
.DeleteContents( TRUE
);
2092 m_lineTo
= (size_t)-1;
2098 m_small_image_list
= (wxImageList
*) NULL
;
2099 m_normal_image_list
= (wxImageList
*) NULL
;
2101 m_small_spacing
= 30;
2102 m_normal_spacing
= 40;
2106 m_isCreated
= FALSE
;
2108 m_lastOnSame
= FALSE
;
2109 m_renameTimer
= new wxListRenameTimer( this );
2110 m_renameAccept
= FALSE
;
2115 m_lineBeforeLastClicked
= (size_t)-1;
2118 void wxListMainWindow::InitScrolling()
2120 if ( HasFlag(wxLC_REPORT
) )
2122 m_xScroll
= SCROLL_UNIT_X
;
2123 m_yScroll
= SCROLL_UNIT_Y
;
2127 m_xScroll
= SCROLL_UNIT_Y
;
2132 wxListMainWindow::wxListMainWindow()
2136 m_highlightBrush
= (wxBrush
*) NULL
;
2142 wxListMainWindow::wxListMainWindow( wxWindow
*parent
,
2147 const wxString
&name
)
2148 : wxScrolledWindow( parent
, id
, pos
, size
,
2149 style
| wxHSCROLL
| wxVSCROLL
, name
)
2153 m_highlightBrush
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
2158 SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 );
2160 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX
) );
2163 wxListMainWindow::~wxListMainWindow()
2167 delete m_highlightBrush
;
2169 delete m_renameTimer
;
2172 void wxListMainWindow::CacheLineData(size_t line
)
2174 wxListCtrl
*listctrl
= GetListCtrl();
2176 wxListLineData
*ld
= GetDummyLine();
2178 size_t countCol
= GetColumnCount();
2179 for ( size_t col
= 0; col
< countCol
; col
++ )
2181 ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
));
2184 ld
->SetImage(listctrl
->OnGetItemImage(line
));
2185 ld
->SetAttr(listctrl
->OnGetItemAttr(line
));
2188 wxListLineData
*wxListMainWindow::GetDummyLine() const
2190 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2192 if ( m_lines
.IsEmpty() )
2194 // normal controls are supposed to have something in m_lines
2195 // already if it's not empty
2196 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2198 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2199 wxListLineData
*line
= new wxListLineData(self
);
2200 self
->m_lines
.Add(line
);
2206 // ----------------------------------------------------------------------------
2207 // line geometry (report mode only)
2208 // ----------------------------------------------------------------------------
2210 wxCoord
wxListMainWindow::GetLineHeight() const
2212 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2214 // we cache the line height as calling GetTextExtent() is slow
2215 if ( !m_lineHeight
)
2217 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2219 wxClientDC
dc( self
);
2220 dc
.SetFont( GetFont() );
2223 dc
.GetTextExtent(_T("H"), NULL
, &y
);
2225 if ( y
< SCROLL_UNIT_Y
)
2229 self
->m_lineHeight
= y
+ LINE_SPACING
;
2232 return m_lineHeight
;
2235 wxCoord
wxListMainWindow::GetLineY(size_t line
) const
2237 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2239 return LINE_SPACING
+ line
*GetLineHeight();
2242 wxRect
wxListMainWindow::GetLineRect(size_t line
) const
2244 if ( !InReportView() )
2245 return GetLine(line
)->m_gi
->m_rectAll
;
2248 rect
.x
= HEADER_OFFSET_X
;
2249 rect
.y
= GetLineY(line
);
2250 rect
.width
= GetHeaderWidth();
2251 rect
.height
= GetLineHeight();
2256 wxRect
wxListMainWindow::GetLineLabelRect(size_t line
) const
2258 if ( !InReportView() )
2259 return GetLine(line
)->m_gi
->m_rectLabel
;
2262 rect
.x
= HEADER_OFFSET_X
;
2263 rect
.y
= GetLineY(line
);
2264 rect
.width
= GetColumnWidth(0);
2265 rect
.height
= GetLineHeight();
2270 wxRect
wxListMainWindow::GetLineIconRect(size_t line
) const
2272 if ( !InReportView() )
2273 return GetLine(line
)->m_gi
->m_rectIcon
;
2275 wxListLineData
*ld
= GetLine(line
);
2276 wxASSERT_MSG( ld
->HasImage(), _T("should have an image") );
2279 rect
.x
= HEADER_OFFSET_X
;
2280 rect
.y
= GetLineY(line
);
2281 GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
);
2286 wxRect
wxListMainWindow::GetLineHighlightRect(size_t line
) const
2288 return InReportView() ? GetLineRect(line
)
2289 : GetLine(line
)->m_gi
->m_rectHighlight
;
2292 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const
2294 wxListLineData
*ld
= GetLine(line
);
2296 if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) )
2297 return wxLIST_HITTEST_ONITEMICON
;
2299 if ( ld
->HasText() )
2301 wxRect rect
= InReportView() ? GetLineRect(line
)
2302 : GetLineLabelRect(line
);
2304 if ( rect
.Inside(x
, y
) )
2305 return wxLIST_HITTEST_ONITEMLABEL
;
2311 // ----------------------------------------------------------------------------
2312 // highlight (selection) handling
2313 // ----------------------------------------------------------------------------
2315 bool wxListMainWindow::IsHighlighted(size_t line
) const
2319 return m_selStore
.IsSelected(line
);
2323 wxListLineData
*ld
= GetLine(line
);
2324 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2326 return ld
->IsHighlighted();
2330 void wxListMainWindow::HighlightLines( size_t lineFrom
, size_t lineTo
, bool highlight
)
2334 m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
);
2335 RefreshLines(lineFrom
, lineTo
);
2339 // do it the dumb way
2340 bool needsRefresh
= FALSE
;
2341 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2343 if ( HighlightLine(line
, highlight
) )
2344 needsRefresh
= TRUE
;
2348 RefreshLines(lineFrom
, lineTo
);
2352 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight
)
2358 changed
= m_selStore
.SelectItem(line
, highlight
);
2362 wxListLineData
*ld
= GetLine(line
);
2363 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2365 changed
= ld
->Highlight(highlight
);
2370 SendNotify( line
, highlight
? wxEVT_COMMAND_LIST_ITEM_SELECTED
2371 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
);
2377 void wxListMainWindow::RefreshLine( size_t line
)
2379 wxRect rect
= GetLineRect(line
);
2381 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2382 RefreshRect( rect
);
2385 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo
)
2387 // we suppose that they are ordered by caller
2388 wxASSERT_MSG( lineFrom
<= lineTo
, _T("indices in disorder") );
2390 wxASSERT_MSG( lineTo
< GetItemCount(), _T("invalid line range") );
2392 if ( HasFlag(wxLC_REPORT
) )
2394 size_t visibleFrom
, visibleTo
;
2395 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2397 if ( lineFrom
< visibleFrom
)
2398 lineFrom
= visibleFrom
;
2399 if ( lineTo
> visibleTo
)
2404 rect
.y
= GetLineY(lineFrom
);
2405 rect
.width
= GetClientSize().x
;
2406 rect
.height
= GetLineY(lineTo
) - rect
.y
;
2408 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2409 RefreshRect( rect
);
2413 // TODO: this should be optimized...
2414 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2421 void wxListMainWindow::RefreshAfter( size_t lineFrom
)
2423 if ( HasFlag(wxLC_REPORT
) )
2426 GetVisibleLinesRange(&visibleFrom
, NULL
);
2428 if ( lineFrom
< visibleFrom
)
2429 lineFrom
= visibleFrom
;
2433 rect
.y
= GetLineY(lineFrom
);
2435 wxSize size
= GetClientSize();
2436 rect
.width
= size
.x
;
2437 // refresh till the bottom of the window
2438 rect
.height
= size
.y
- rect
.y
;
2440 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2441 RefreshRect( rect
);
2445 // TODO: how to do it more efficiently?
2450 void wxListMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2452 // Note: a wxPaintDC must be constructed even if no drawing is
2453 // done (a Windows requirement).
2454 wxPaintDC
dc( this );
2458 // empty control. nothing to draw
2464 // delay the repainting until we calculate all the items positions
2471 CalcScrolledPosition( 0, 0, &dev_x
, &dev_y
);
2475 dc
.SetFont( GetFont() );
2477 if ( HasFlag(wxLC_REPORT
) )
2479 int lineHeight
= GetLineHeight();
2481 size_t visibleFrom
, visibleTo
;
2482 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2485 wxCoord xOrig
, yOrig
;
2486 CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
);
2488 // tell the caller cache to cache the data
2489 wxListEvent
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, GetParent()->GetId());
2490 evCache
.SetEventObject( GetParent() );
2491 evCache
.m_oldItemIndex
= visibleFrom
;
2492 evCache
.m_itemIndex
= visibleTo
;
2493 GetParent()->GetEventHandler()->ProcessEvent( evCache
);
2495 for ( size_t line
= visibleFrom
; line
<= visibleTo
; line
++ )
2497 rectLine
= GetLineRect(line
);
2499 if ( !IsExposed(rectLine
.x
- xOrig
, rectLine
.y
- yOrig
,
2500 rectLine
.width
, rectLine
.height
) )
2502 // don't redraw unaffected lines to avoid flicker
2506 GetLine(line
)->DrawInReportMode( &dc
,
2508 GetLineHighlightRect(line
),
2509 IsHighlighted(line
) );
2512 if ( HasFlag(wxLC_HRULES
) )
2514 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2515 wxSize clientSize
= GetClientSize();
2517 for ( size_t i
= visibleFrom
; i
<= visibleTo
; i
++ )
2520 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2521 dc
.DrawLine(0 - dev_x
, i
*lineHeight
,
2522 clientSize
.x
- dev_x
, i
*lineHeight
);
2525 // Draw last horizontal rule
2526 if ( visibleTo
> visibleFrom
)
2529 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2530 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
,
2531 clientSize
.x
- dev_x
, m_lineTo
*lineHeight
);
2535 // Draw vertical rules if required
2536 if ( HasFlag(wxLC_VRULES
) && !IsEmpty() )
2538 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2541 wxRect firstItemRect
;
2542 wxRect lastItemRect
;
2543 GetItemRect(0, firstItemRect
);
2544 GetItemRect(GetItemCount() - 1, lastItemRect
);
2545 int x
= firstItemRect
.GetX();
2547 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2548 for (col
= 0; col
< GetColumnCount(); col
++)
2550 int colWidth
= GetColumnWidth(col
);
2552 dc
.DrawLine(x
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
,
2553 x
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
);
2559 size_t count
= GetItemCount();
2560 for ( size_t i
= 0; i
< count
; i
++ )
2562 GetLine(i
)->Draw( &dc
);
2566 if ( HasCurrent() && m_hasFocus
)
2569 // no rect outline, we already have the background color
2571 dc
.SetPen( *wxBLACK_PEN
);
2572 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2573 dc
.DrawRectangle( GetLineHighlightRect(m_current
) );
2580 void wxListMainWindow::HighlightAll( bool on
)
2582 if ( IsSingleSel() )
2584 wxASSERT_MSG( !on
, _T("can't do this in a single sel control") );
2586 // we just have one item to turn off
2587 if ( HasCurrent() && IsHighlighted(m_current
) )
2589 HighlightLine(m_current
, FALSE
);
2590 RefreshLine(m_current
);
2595 HighlightLines(0, GetItemCount() - 1, on
);
2599 void wxListMainWindow::SendNotify( size_t line
,
2600 wxEventType command
,
2603 wxListEvent
le( command
, GetParent()->GetId() );
2604 le
.SetEventObject( GetParent() );
2605 le
.m_itemIndex
= line
;
2607 // set only for events which have position
2608 if ( point
!= wxDefaultPosition
)
2609 le
.m_pointDrag
= point
;
2611 GetLine(line
)->GetItem( 0, le
.m_item
);
2612 GetParent()->GetEventHandler()->ProcessEvent( le
);
2615 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) )
2617 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
2620 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) )
2622 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
2625 void wxListMainWindow::EditLabel( long item
)
2627 wxCHECK_RET( (item
>= 0) && ((size_t)item
< GetItemCount()),
2628 wxT("wrong index in wxListCtrl::EditLabel()") );
2630 m_currentEdit
= (size_t)item
;
2632 wxListEvent
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() );
2633 le
.SetEventObject( GetParent() );
2634 le
.m_itemIndex
= item
;
2635 wxListLineData
*data
= GetLine(m_currentEdit
);
2636 wxCHECK_RET( data
, _T("invalid index in EditLabel()") );
2637 data
->GetItem( 0, le
.m_item
);
2638 GetParent()->GetEventHandler()->ProcessEvent( le
);
2640 if (!le
.IsAllowed())
2643 // We have to call this here because the label in question might just have
2644 // been added and no screen update taken place.
2648 wxClientDC
dc(this);
2651 wxString s
= data
->GetText(0);
2652 wxRect rectLabel
= GetLineLabelRect(m_currentEdit
);
2654 rectLabel
.x
= dc
.LogicalToDeviceX( rectLabel
.x
);
2655 rectLabel
.y
= dc
.LogicalToDeviceY( rectLabel
.y
);
2657 wxListTextCtrl
*text
= new wxListTextCtrl
2664 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4),
2665 wxSize(rectLabel
.width
+11,rectLabel
.height
+8)
2670 void wxListMainWindow::OnRenameTimer()
2672 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2674 EditLabel( m_current
);
2677 void wxListMainWindow::OnRenameAccept()
2679 wxListEvent
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() );
2680 le
.SetEventObject( GetParent() );
2681 le
.m_itemIndex
= m_currentEdit
;
2683 wxListLineData
*data
= GetLine(m_currentEdit
);
2684 wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") );
2686 data
->GetItem( 0, le
.m_item
);
2687 le
.m_item
.m_text
= m_renameRes
;
2688 GetParent()->GetEventHandler()->ProcessEvent( le
);
2690 if (!le
.IsAllowed()) return;
2693 info
.m_mask
= wxLIST_MASK_TEXT
;
2694 info
.m_itemId
= le
.m_itemIndex
;
2695 info
.m_text
= m_renameRes
;
2696 info
.SetTextColour(le
.m_item
.GetTextColour());
2700 void wxListMainWindow::OnMouse( wxMouseEvent
&event
)
2702 event
.SetEventObject( GetParent() );
2703 if ( GetParent()->GetEventHandler()->ProcessEvent( event
) )
2706 if ( !HasCurrent() || IsEmpty() )
2712 if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() ||
2713 event
.ButtonDClick()) )
2716 int x
= event
.GetX();
2717 int y
= event
.GetY();
2718 CalcUnscrolledPosition( x
, y
, &x
, &y
);
2720 // where did we hit it (if we did)?
2723 size_t count
= GetItemCount(),
2726 if ( HasFlag(wxLC_REPORT
) )
2728 current
= y
/ GetLineHeight();
2729 if ( current
< count
)
2730 hitResult
= HitTestLine(current
, x
, y
);
2734 // TODO: optimize it too! this is less simple than for report view but
2735 // enumerating all items is still not a way to do it!!
2736 for ( current
= 0; current
< count
; current
++ )
2738 hitResult
= HitTestLine(current
, x
, y
);
2744 if (event
.Dragging())
2746 if (m_dragCount
== 0)
2747 m_dragStart
= wxPoint(x
,y
);
2751 if (m_dragCount
!= 3)
2754 int command
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2755 : wxEVT_COMMAND_LIST_BEGIN_DRAG
;
2757 wxListEvent
le( command
, GetParent()->GetId() );
2758 le
.SetEventObject( GetParent() );
2759 le
.m_pointDrag
= m_dragStart
;
2760 GetParent()->GetEventHandler()->ProcessEvent( le
);
2771 // outside of any item
2775 bool forceClick
= FALSE
;
2776 if (event
.ButtonDClick())
2778 m_renameTimer
->Stop();
2779 m_lastOnSame
= FALSE
;
2781 if ( current
== m_lineBeforeLastClicked
)
2783 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED
);
2789 // the first click was on another item, so don't interpret this as
2790 // a double click, but as a simple click instead
2795 if (event
.LeftUp() && m_lastOnSame
)
2797 if ((current
== m_current
) &&
2798 (hitResult
== wxLIST_HITTEST_ONITEMLABEL
) &&
2799 HasFlag(wxLC_EDIT_LABELS
) )
2801 m_renameTimer
->Start( 100, TRUE
);
2803 m_lastOnSame
= FALSE
;
2805 else if (event
.RightDown())
2807 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
,
2808 event
.GetPosition() );
2810 else if (event
.MiddleDown())
2812 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
);
2814 else if ( event
.LeftDown() || forceClick
)
2816 m_lineBeforeLastClicked
= m_lineLastClicked
;
2817 m_lineLastClicked
= current
;
2819 size_t oldCurrent
= m_current
;
2821 if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) )
2823 HighlightAll( FALSE
);
2824 m_current
= current
;
2826 ReverseHighlight(m_current
);
2828 else // multi sel & either ctrl or shift is down
2830 if (event
.ControlDown())
2832 m_current
= current
;
2834 ReverseHighlight(m_current
);
2836 else if (event
.ShiftDown())
2838 m_current
= current
;
2840 size_t lineFrom
= oldCurrent
,
2843 if ( lineTo
< lineFrom
)
2846 lineFrom
= m_current
;
2849 HighlightLines(lineFrom
, lineTo
);
2851 else // !ctrl, !shift
2853 // test in the enclosing if should make it impossible
2854 wxFAIL_MSG( _T("how did we get here?") );
2858 if (m_current
!= oldCurrent
)
2860 RefreshLine( oldCurrent
);
2861 OnUnfocusLine( oldCurrent
);
2862 OnFocusLine( m_current
);
2865 // forceClick is only set if the previous click was on another item
2866 m_lastOnSame
= !forceClick
&& (m_current
== oldCurrent
);
2870 void wxListMainWindow::MoveToFocus()
2872 if ( !HasCurrent() )
2875 wxRect rect
= GetLineRect(m_current
);
2877 int client_w
, client_h
;
2878 GetClientSize( &client_w
, &client_h
);
2880 int view_x
= m_xScroll
*GetScrollPos( wxHORIZONTAL
);
2881 int view_y
= m_yScroll
*GetScrollPos( wxVERTICAL
);
2883 if ( HasFlag(wxLC_REPORT
) )
2885 // the next we need the range of lines shown it might be different, so
2887 ResetVisibleLinesRange();
2889 if (rect
.y
< view_y
)
2890 Scroll( -1, rect
.y
/m_yScroll
);
2891 if (rect
.y
+rect
.height
+5 > view_y
+client_h
)
2892 Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll
);
2896 if (rect
.x
-view_x
< 5)
2897 Scroll( (rect
.x
-5)/m_xScroll
, -1 );
2898 if (rect
.x
+rect
.width
-5 > view_x
+client_w
)
2899 Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 );
2903 // ----------------------------------------------------------------------------
2904 // keyboard handling
2905 // ----------------------------------------------------------------------------
2907 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
2909 wxCHECK_RET( newCurrent
< (size_t)GetItemCount(),
2910 _T("invalid item index in OnArrowChar()") );
2912 size_t oldCurrent
= m_current
;
2914 // in single selection we just ignore Shift as we can't select several
2916 if ( event
.ShiftDown() && !IsSingleSel() )
2918 m_current
= newCurrent
;
2920 // select all the items between the old and the new one
2921 if ( oldCurrent
> newCurrent
)
2923 newCurrent
= oldCurrent
;
2924 oldCurrent
= m_current
;
2927 HighlightLines(oldCurrent
, newCurrent
);
2931 // all previously selected items are unselected unless ctrl is held
2932 if ( !event
.ControlDown() )
2933 HighlightAll(FALSE
);
2935 m_current
= newCurrent
;
2937 HighlightLine( oldCurrent
, FALSE
);
2938 RefreshLine( oldCurrent
);
2940 if ( !event
.ControlDown() )
2942 HighlightLine( m_current
, TRUE
);
2946 OnUnfocusLine( oldCurrent
);
2947 OnFocusLine( m_current
);
2948 RefreshLine( m_current
);
2953 void wxListMainWindow::OnKeyDown( wxKeyEvent
&event
)
2955 wxWindow
*parent
= GetParent();
2957 /* we propagate the key event up */
2958 wxKeyEvent
ke( wxEVT_KEY_DOWN
);
2959 ke
.m_shiftDown
= event
.m_shiftDown
;
2960 ke
.m_controlDown
= event
.m_controlDown
;
2961 ke
.m_altDown
= event
.m_altDown
;
2962 ke
.m_metaDown
= event
.m_metaDown
;
2963 ke
.m_keyCode
= event
.m_keyCode
;
2966 ke
.SetEventObject( parent
);
2967 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2972 void wxListMainWindow::OnChar( wxKeyEvent
&event
)
2974 wxWindow
*parent
= GetParent();
2976 /* we send a list_key event up */
2979 wxListEvent
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() );
2980 le
.m_itemIndex
= m_current
;
2981 GetLine(m_current
)->GetItem( 0, le
.m_item
);
2982 le
.m_code
= (int)event
.KeyCode();
2983 le
.SetEventObject( parent
);
2984 parent
->GetEventHandler()->ProcessEvent( le
);
2987 /* we propagate the char event up */
2988 wxKeyEvent
ke( wxEVT_CHAR
);
2989 ke
.m_shiftDown
= event
.m_shiftDown
;
2990 ke
.m_controlDown
= event
.m_controlDown
;
2991 ke
.m_altDown
= event
.m_altDown
;
2992 ke
.m_metaDown
= event
.m_metaDown
;
2993 ke
.m_keyCode
= event
.m_keyCode
;
2996 ke
.SetEventObject( parent
);
2997 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2999 if (event
.KeyCode() == WXK_TAB
)
3001 wxNavigationKeyEvent nevent
;
3002 nevent
.SetWindowChange( event
.ControlDown() );
3003 nevent
.SetDirection( !event
.ShiftDown() );
3004 nevent
.SetEventObject( GetParent()->GetParent() );
3005 nevent
.SetCurrentFocus( m_parent
);
3006 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
)) return;
3009 /* no item -> nothing to do */
3016 switch (event
.KeyCode())
3019 if ( m_current
> 0 )
3020 OnArrowChar( m_current
- 1, event
);
3024 if ( m_current
< (size_t)GetItemCount() - 1 )
3025 OnArrowChar( m_current
+ 1, event
);
3030 OnArrowChar( GetItemCount() - 1, event
);
3035 OnArrowChar( 0, event
);
3041 if ( HasFlag(wxLC_REPORT
) )
3043 steps
= m_linesPerPage
- 1;
3047 steps
= m_current
% m_linesPerPage
;
3050 int index
= m_current
- steps
;
3054 OnArrowChar( index
, event
);
3061 if ( HasFlag(wxLC_REPORT
) )
3063 steps
= m_linesPerPage
- 1;
3067 steps
= m_linesPerPage
- (m_current
% m_linesPerPage
) - 1;
3070 size_t index
= m_current
+ steps
;
3071 size_t count
= GetItemCount();
3072 if ( index
>= count
)
3075 OnArrowChar( index
, event
);
3080 if ( !HasFlag(wxLC_REPORT
) )
3082 int index
= m_current
- m_linesPerPage
;
3086 OnArrowChar( index
, event
);
3091 if ( !HasFlag(wxLC_REPORT
) )
3093 size_t index
= m_current
+ m_linesPerPage
;
3095 size_t count
= GetItemCount();
3096 if ( index
>= count
)
3099 OnArrowChar( index
, event
);
3104 if ( IsSingleSel() )
3106 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3107 GetParent()->GetId() );
3108 le
.SetEventObject( GetParent() );
3109 le
.m_itemIndex
= m_current
;
3110 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3111 GetParent()->GetEventHandler()->ProcessEvent( le
);
3115 ReverseHighlight(m_current
);
3122 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3123 GetParent()->GetId() );
3124 le
.SetEventObject( GetParent() );
3125 le
.m_itemIndex
= m_current
;
3126 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3127 GetParent()->GetEventHandler()->ProcessEvent( le
);
3136 // ----------------------------------------------------------------------------
3138 // ----------------------------------------------------------------------------
3141 extern wxWindow
*g_focusWindow
;
3144 void wxListMainWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
3149 RefreshLine( m_current
);
3155 g_focusWindow
= GetParent();
3158 wxFocusEvent
event( wxEVT_SET_FOCUS
, GetParent()->GetId() );
3159 event
.SetEventObject( GetParent() );
3160 GetParent()->GetEventHandler()->ProcessEvent( event
);
3163 void wxListMainWindow::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
3168 RefreshLine( m_current
);
3171 void wxListMainWindow::DrawImage( int index
, wxDC
*dc
, int x
, int y
)
3173 if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
))
3175 m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3177 else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
))
3179 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3181 else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
))
3183 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3185 else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
))
3187 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3191 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height
) const
3193 if ( HasFlag(wxLC_ICON
) && m_normal_image_list
)
3195 m_normal_image_list
->GetSize( index
, width
, height
);
3197 else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list
)
3199 m_small_image_list
->GetSize( index
, width
, height
);
3201 else if ( HasFlag(wxLC_LIST
) && m_small_image_list
)
3203 m_small_image_list
->GetSize( index
, width
, height
);
3205 else if ( HasFlag(wxLC_REPORT
) && m_small_image_list
)
3207 m_small_image_list
->GetSize( index
, width
, height
);
3216 int wxListMainWindow::GetTextLength( const wxString
&s
) const
3218 wxClientDC
dc( wxConstCast(this, wxListMainWindow
) );
3219 dc
.SetFont( GetFont() );
3222 dc
.GetTextExtent( s
, &lw
, NULL
);
3224 return lw
+ AUTOSIZE_COL_MARGIN
;
3227 void wxListMainWindow::SetImageList( wxImageList
*imageList
, int which
)
3231 // calc the spacing from the icon size
3234 if ((imageList
) && (imageList
->GetImageCount()) )
3236 imageList
->GetSize(0, width
, height
);
3239 if (which
== wxIMAGE_LIST_NORMAL
)
3241 m_normal_image_list
= imageList
;
3242 m_normal_spacing
= width
+ 8;
3245 if (which
== wxIMAGE_LIST_SMALL
)
3247 m_small_image_list
= imageList
;
3248 m_small_spacing
= width
+ 14;
3252 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall
)
3257 m_small_spacing
= spacing
;
3261 m_normal_spacing
= spacing
;
3265 int wxListMainWindow::GetItemSpacing( bool isSmall
)
3267 return isSmall
? m_small_spacing
: m_normal_spacing
;
3270 // ----------------------------------------------------------------------------
3272 // ----------------------------------------------------------------------------
3274 void wxListMainWindow::SetColumn( int col
, wxListItem
&item
)
3276 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3278 wxCHECK_RET( node
, _T("invalid column index in SetColumn") );
3280 if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3281 item
.m_width
= GetTextLength( item
.m_text
);
3283 wxListHeaderData
*column
= node
->GetData();
3284 column
->SetItem( item
);
3286 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3288 headerWin
->m_dirty
= TRUE
;
3292 // invalidate it as it has to be recalculated
3296 void wxListMainWindow::SetColumnWidth( int col
, int width
)
3298 wxCHECK_RET( col
>= 0 && col
< GetColumnCount(),
3299 _T("invalid column index") );
3301 wxCHECK_RET( HasFlag(wxLC_REPORT
),
3302 _T("SetColumnWidth() can only be called in report mode.") );
3306 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3307 wxCHECK_RET( node
, _T("no column?") );
3309 wxListHeaderData
*column
= node
->GetData();
3311 size_t count
= GetItemCount();
3313 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
3315 width
= GetTextLength(column
->GetText());
3317 else if ( width
== wxLIST_AUTOSIZE
)
3321 // TODO: determine the max width somehow...
3322 width
= WIDTH_COL_DEFAULT
;
3326 wxClientDC
dc(this);
3327 dc
.SetFont( GetFont() );
3329 int max
= AUTOSIZE_COL_MARGIN
;
3331 for ( size_t i
= 0; i
< count
; i
++ )
3333 wxListLineData
*line
= GetLine(i
);
3334 wxListItemDataList::Node
*n
= line
->m_items
.Item( col
);
3336 wxCHECK_RET( n
, _T("no subitem?") );
3338 wxListItemData
*item
= n
->GetData();
3341 if (item
->HasImage())
3344 GetImageSize( item
->GetImage(), ix
, iy
);
3348 if (item
->HasText())
3351 dc
.GetTextExtent( item
->GetText(), &w
, NULL
);
3359 width
= max
+ AUTOSIZE_COL_MARGIN
;
3363 column
->SetWidth( width
);
3365 // invalidate it as it has to be recalculated
3369 int wxListMainWindow::GetHeaderWidth() const
3371 if ( !m_headerWidth
)
3373 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
3375 size_t count
= GetColumnCount();
3376 for ( size_t col
= 0; col
< count
; col
++ )
3378 self
->m_headerWidth
+= GetColumnWidth(col
);
3382 return m_headerWidth
;
3385 void wxListMainWindow::GetColumn( int col
, wxListItem
&item
) const
3387 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3388 wxCHECK_RET( node
, _T("invalid column index in GetColumn") );
3390 wxListHeaderData
*column
= node
->GetData();
3391 column
->GetItem( item
);
3394 int wxListMainWindow::GetColumnWidth( int col
) const
3396 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3397 wxCHECK_MSG( node
, 0, _T("invalid column index") );
3399 wxListHeaderData
*column
= node
->GetData();
3400 return column
->GetWidth();
3403 // ----------------------------------------------------------------------------
3405 // ----------------------------------------------------------------------------
3407 void wxListMainWindow::SetItem( wxListItem
&item
)
3409 long id
= item
.m_itemId
;
3410 wxCHECK_RET( id
>= 0 && (size_t)id
< GetItemCount(),
3411 _T("invalid item index in SetItem") );
3415 wxListLineData
*line
= GetLine((size_t)id
);
3416 line
->SetItem( item
.m_col
, item
);
3419 if ( InReportView() )
3421 // just refresh the line to show the new value of the text/image
3422 RefreshLine((size_t)id
);
3426 // refresh everything (resulting in horrible flicker - FIXME!)
3431 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask
)
3433 wxCHECK_RET( litem
>= 0 && (size_t)litem
< GetItemCount(),
3434 _T("invalid list ctrl item index in SetItem") );
3436 size_t oldCurrent
= m_current
;
3437 size_t item
= (size_t)litem
; // sdafe because of the check above
3439 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3441 if ( state
& wxLIST_STATE_FOCUSED
)
3443 // don't do anything if this item is already focused
3444 if ( item
!= m_current
)
3446 OnUnfocusLine( m_current
);
3448 OnFocusLine( m_current
);
3450 if ( IsSingleSel() && (oldCurrent
!= (size_t)-1) )
3452 HighlightLine(oldCurrent
, FALSE
);
3453 RefreshLine(oldCurrent
);
3456 RefreshLine( m_current
);
3461 // don't do anything if this item is not focused
3462 if ( item
== m_current
)
3464 OnUnfocusLine( m_current
);
3465 m_current
= (size_t)-1;
3470 if ( stateMask
& wxLIST_STATE_SELECTED
)
3472 bool on
= (state
& wxLIST_STATE_SELECTED
) != 0;
3474 if ( IsSingleSel() )
3478 // selecting the item also makes it the focused one in the
3480 if ( m_current
!= item
)
3482 OnUnfocusLine( m_current
);
3484 OnFocusLine( m_current
);
3486 if ( oldCurrent
!= (size_t)-1 )
3488 HighlightLine( oldCurrent
, FALSE
);
3489 RefreshLine( oldCurrent
);
3495 // only the current item may be selected anyhow
3496 if ( item
!= m_current
)
3501 if ( HighlightLine(item
, on
) )
3508 int wxListMainWindow::GetItemState( long item
, long stateMask
)
3510 wxCHECK_MSG( item
>= 0 && (size_t)item
< GetItemCount(), 0,
3511 _T("invalid list ctrl item index in GetItemState()") );
3513 int ret
= wxLIST_STATE_DONTCARE
;
3515 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3517 if ( (size_t)item
== m_current
)
3518 ret
|= wxLIST_STATE_FOCUSED
;
3521 if ( stateMask
& wxLIST_STATE_SELECTED
)
3523 if ( IsHighlighted(item
) )
3524 ret
|= wxLIST_STATE_SELECTED
;
3530 void wxListMainWindow::GetItem( wxListItem
&item
)
3532 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
< GetItemCount(),
3533 _T("invalid item index in GetItem") );
3535 wxListLineData
*line
= GetLine((size_t)item
.m_itemId
);
3536 line
->GetItem( item
.m_col
, item
);
3539 // ----------------------------------------------------------------------------
3541 // ----------------------------------------------------------------------------
3543 size_t wxListMainWindow::GetItemCount() const
3545 return IsVirtual() ? m_countVirt
: m_lines
.GetCount();
3548 void wxListMainWindow::SetItemCount(long count
)
3550 m_selStore
.SetItemCount(count
);
3551 m_countVirt
= count
;
3553 ResetVisibleLinesRange();
3555 // scrollbars must be reset
3559 int wxListMainWindow::GetSelectedItemCount()
3561 // deal with the quick case first
3562 if ( IsSingleSel() )
3564 return HasCurrent() ? IsHighlighted(m_current
) : FALSE
;
3567 // virtual controls remmebers all its selections itself
3569 return m_selStore
.GetSelectedCount();
3571 // TODO: we probably should maintain the number of items selected even for
3572 // non virtual controls as enumerating all lines is really slow...
3573 size_t countSel
= 0;
3574 size_t count
= GetItemCount();
3575 for ( size_t line
= 0; line
< count
; line
++ )
3577 if ( GetLine(line
)->IsHighlighted() )
3584 // ----------------------------------------------------------------------------
3585 // item position/size
3586 // ----------------------------------------------------------------------------
3588 void wxListMainWindow::GetItemRect( long index
, wxRect
&rect
)
3590 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3591 _T("invalid index in GetItemRect") );
3593 rect
= GetLineRect((size_t)index
);
3595 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
3598 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
)
3601 GetItemRect(item
, rect
);
3609 // ----------------------------------------------------------------------------
3610 // geometry calculation
3611 // ----------------------------------------------------------------------------
3613 void wxListMainWindow::RecalculatePositions()
3615 wxClientDC
dc( this );
3616 dc
.SetFont( GetFont() );
3619 if ( HasFlag(wxLC_ICON
) )
3620 iconSpacing
= m_normal_spacing
;
3621 else if ( HasFlag(wxLC_SMALL_ICON
) )
3622 iconSpacing
= m_small_spacing
;
3628 GetClientSize( &clientWidth
, &clientHeight
);
3630 if ( HasFlag(wxLC_REPORT
) )
3632 // all lines have the same height
3633 int lineHeight
= GetLineHeight();
3635 // scroll one line per step
3636 m_yScroll
= lineHeight
;
3638 size_t lineCount
= GetItemCount();
3639 int entireHeight
= lineCount
*lineHeight
+ LINE_SPACING
;
3641 m_linesPerPage
= clientHeight
/ lineHeight
;
3643 ResetVisibleLinesRange();
3645 SetScrollbars( m_xScroll
, m_yScroll
,
3646 (GetHeaderWidth() + m_xScroll
- 1)/m_xScroll
,
3647 (entireHeight
+ m_yScroll
- 1)/m_yScroll
,
3648 GetScrollPos(wxHORIZONTAL
),
3649 GetScrollPos(wxVERTICAL
),
3654 // at first we try without any scrollbar. if the items don't
3655 // fit into the window, we recalculate after subtracting an
3656 // approximated 15 pt for the horizontal scrollbar
3658 clientHeight
-= 4; // sunken frame
3660 int entireWidth
= 0;
3662 for (int tries
= 0; tries
< 2; tries
++)
3669 int currentlyVisibleLines
= 0;
3671 size_t count
= GetItemCount();
3672 for (size_t i
= 0; i
< count
; i
++)
3674 currentlyVisibleLines
++;
3675 wxListLineData
*line
= GetLine(i
);
3676 line
->CalculateSize( &dc
, iconSpacing
);
3677 line
->SetPosition( x
, y
, clientWidth
, iconSpacing
);
3679 wxSize sizeLine
= GetLineSize(i
);
3681 if ( maxWidth
< sizeLine
.x
)
3682 maxWidth
= sizeLine
.x
;
3685 if (currentlyVisibleLines
> m_linesPerPage
)
3686 m_linesPerPage
= currentlyVisibleLines
;
3688 // assume that the size of the next one is the same... (FIXME)
3689 if ( y
+ sizeLine
.y
- 6 >= clientHeight
)
3691 currentlyVisibleLines
= 0;
3694 entireWidth
+= maxWidth
+6;
3697 if ( i
== count
- 1 )
3698 entireWidth
+= maxWidth
;
3699 if ((tries
== 0) && (entireWidth
> clientWidth
))
3701 clientHeight
-= 15; // scrollbar height
3703 currentlyVisibleLines
= 0;
3706 if ( i
== count
- 1 )
3707 tries
= 1; // everything fits, no second try required
3711 int scroll_pos
= GetScrollPos( wxHORIZONTAL
);
3712 SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE
);
3715 // FIXME: why should we call it from here?
3721 void wxListMainWindow::RefreshAll()
3726 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3729 headerWin
->m_dirty
= FALSE
;
3730 headerWin
->Refresh();
3734 void wxListMainWindow::UpdateCurrent()
3736 if ( !HasCurrent() && !IsEmpty() )
3741 if ( m_current
!= (size_t)-1 )
3743 OnFocusLine( m_current
);
3747 long wxListMainWindow::GetNextItem( long item
,
3748 int WXUNUSED(geometry
),
3752 max
= GetItemCount();
3753 wxCHECK_MSG( (ret
== -1) || (ret
< max
), -1,
3754 _T("invalid listctrl index in GetNextItem()") );
3756 // notice that we start with the next item (or the first one if item == -1)
3757 // and this is intentional to allow writing a simple loop to iterate over
3758 // all selected items
3762 // this is not an error because the index was ok initially, just no
3773 size_t count
= GetItemCount();
3774 for ( size_t line
= (size_t)ret
; line
< count
; line
++ )
3776 if ( (state
& wxLIST_STATE_FOCUSED
) && (line
== m_current
) )
3779 if ( (state
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) )
3786 // ----------------------------------------------------------------------------
3788 // ----------------------------------------------------------------------------
3790 void wxListMainWindow::DeleteItem( long lindex
)
3792 size_t count
= GetItemCount();
3794 wxCHECK_RET( (lindex
>= 0) && ((size_t)lindex
< count
),
3795 _T("invalid item index in DeleteItem") );
3797 size_t index
= (size_t)lindex
;
3801 // select the next item when the selected one is deleted
3802 if ( m_current
== index
)
3804 // the last valid index after deleting the item will be count-2
3805 if ( m_current
== count
- 1 )
3811 SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
);
3813 if ( InReportView() )
3815 ResetVisibleLinesRange();
3822 m_selStore
.OnItemDelete(index
);
3826 m_lines
.RemoveAt( index
);
3830 RefreshAfter(index
);
3833 void wxListMainWindow::DeleteColumn( int col
)
3835 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3837 wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") );
3840 m_columns
.DeleteNode( node
);
3843 void wxListMainWindow::DoDeleteAllItems()
3847 // nothing to do - in particular, don't send the event
3853 // to make the deletion of all items faster, we don't send the
3854 // notifications for each item deletion in this case but only one event
3855 // for all of them: this is compatible with wxMSW and documented in
3856 // DeleteAllItems() description
3858 wxListEvent
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() );
3859 event
.SetEventObject( GetParent() );
3860 GetParent()->GetEventHandler()->ProcessEvent( event
);
3869 if ( InReportView() )
3871 ResetVisibleLinesRange();
3877 void wxListMainWindow::DeleteAllItems()
3881 RecalculatePositions();
3884 void wxListMainWindow::DeleteEverything()
3891 // ----------------------------------------------------------------------------
3892 // scanning for an item
3893 // ----------------------------------------------------------------------------
3895 void wxListMainWindow::EnsureVisible( long index
)
3897 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3898 _T("invalid index in EnsureVisible") );
3900 // We have to call this here because the label in question might just have
3901 // been added and no screen update taken place.
3905 size_t oldCurrent
= m_current
;
3906 m_current
= (size_t)index
;
3908 m_current
= oldCurrent
;
3911 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) )
3918 size_t count
= GetItemCount();
3919 for ( size_t i
= (size_t)pos
; i
< count
; i
++ )
3921 wxListLineData
*line
= GetLine(i
);
3922 if ( line
->GetText(0) == tmp
)
3929 long wxListMainWindow::FindItem(long start
, long data
)
3935 size_t count
= GetItemCount();
3936 for (size_t i
= (size_t)pos
; i
< count
; i
++)
3938 wxListLineData
*line
= GetLine(i
);
3940 line
->GetItem( 0, item
);
3941 if (item
.m_data
== data
)
3948 long wxListMainWindow::HitTest( int x
, int y
, int &flags
)
3950 CalcUnscrolledPosition( x
, y
, &x
, &y
);
3952 if ( HasFlag(wxLC_REPORT
) )
3954 size_t current
= y
/ GetLineHeight();
3955 flags
= HitTestLine(current
, x
, y
);
3961 // TODO: optimize it too! this is less simple than for report view but
3962 // enumerating all items is still not a way to do it!!
3963 size_t count
= GetItemCount();
3964 for ( size_t current
= 0; current
< count
; current
++ )
3966 flags
= HitTestLine(current
, x
, y
);
3975 // ----------------------------------------------------------------------------
3977 // ----------------------------------------------------------------------------
3979 void wxListMainWindow::InsertItem( wxListItem
&item
)
3981 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
3983 size_t count
= GetItemCount();
3984 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
<= count
,
3985 _T("invalid item index") );
3987 size_t id
= item
.m_itemId
;
3992 if ( HasFlag(wxLC_REPORT
) )
3994 else if ( HasFlag(wxLC_LIST
) )
3996 else if ( HasFlag(wxLC_ICON
) )
3998 else if ( HasFlag(wxLC_SMALL_ICON
) )
3999 mode
= wxLC_ICON
; // no typo
4002 wxFAIL_MSG( _T("unknown mode") );
4005 wxListLineData
*line
= new wxListLineData(this);
4007 line
->SetItem( 0, item
);
4009 m_lines
.Insert( line
, id
);
4012 RefreshLines(id
, GetItemCount() - 1);
4015 void wxListMainWindow::InsertColumn( long col
, wxListItem
&item
)
4018 if ( HasFlag(wxLC_REPORT
) )
4020 if (item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
4021 item
.m_width
= GetTextLength( item
.m_text
);
4022 wxListHeaderData
*column
= new wxListHeaderData( item
);
4023 if ((col
>= 0) && (col
< (int)m_columns
.GetCount()))
4025 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
4026 m_columns
.Insert( node
, column
);
4030 m_columns
.Append( column
);
4035 // ----------------------------------------------------------------------------
4037 // ----------------------------------------------------------------------------
4039 wxListCtrlCompare list_ctrl_compare_func_2
;
4040 long list_ctrl_compare_data
;
4042 int LINKAGEMODE
list_ctrl_compare_func_1( wxListLineData
**arg1
, wxListLineData
**arg2
)
4044 wxListLineData
*line1
= *arg1
;
4045 wxListLineData
*line2
= *arg2
;
4047 line1
->GetItem( 0, item
);
4048 long data1
= item
.m_data
;
4049 line2
->GetItem( 0, item
);
4050 long data2
= item
.m_data
;
4051 return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data
);
4054 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data
)
4056 list_ctrl_compare_func_2
= fn
;
4057 list_ctrl_compare_data
= data
;
4058 m_lines
.Sort( list_ctrl_compare_func_1
);
4062 // ----------------------------------------------------------------------------
4064 // ----------------------------------------------------------------------------
4066 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
)
4068 // update our idea of which lines are shown when we redraw the window the
4070 ResetVisibleLinesRange();
4073 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4074 wxScrolledWindow::OnScroll(event
);
4076 HandleOnScroll( event
);
4079 if ( event
.GetOrientation() == wxHORIZONTAL
&& HasHeader() )
4081 wxListCtrl
* lc
= GetListCtrl();
4082 wxCHECK_RET( lc
, _T("no listctrl window?") );
4084 lc
->m_headerWin
->Refresh() ;
4086 lc
->m_headerWin
->MacUpdateImmediately() ;
4091 int wxListMainWindow::GetCountPerPage() const
4093 if ( !m_linesPerPage
)
4095 wxConstCast(this, wxListMainWindow
)->
4096 m_linesPerPage
= GetClientSize().y
/ GetLineHeight();
4099 return m_linesPerPage
;
4102 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
)
4104 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") );
4106 if ( m_lineFrom
== (size_t)-1 )
4108 size_t count
= GetItemCount();
4111 m_lineFrom
= GetScrollPos(wxVERTICAL
);
4113 // this may happen if SetScrollbars() hadn't been called yet
4114 if ( m_lineFrom
>= count
)
4115 m_lineFrom
= count
- 1;
4117 // we redraw one extra line but this is needed to make the redrawing
4118 // logic work when there is a fractional number of lines on screen
4119 m_lineTo
= m_lineFrom
+ m_linesPerPage
;
4120 if ( m_lineTo
>= count
)
4121 m_lineTo
= count
- 1;
4123 else // empty control
4126 m_lineTo
= (size_t)-1;
4130 wxASSERT_MSG( IsEmpty() ||
4131 (m_lineFrom
<= m_lineTo
&& m_lineTo
< GetItemCount()),
4132 _T("GetVisibleLinesRange() returns incorrect result") );
4140 // -------------------------------------------------------------------------------------
4142 // -------------------------------------------------------------------------------------
4144 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
4146 wxListItem::wxListItem()
4155 m_format
= wxLIST_FORMAT_CENTRE
;
4161 void wxListItem::Clear()
4170 m_format
= wxLIST_FORMAT_CENTRE
;
4177 void wxListItem::ClearAttributes()
4186 // -------------------------------------------------------------------------------------
4188 // -------------------------------------------------------------------------------------
4190 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
4192 wxListEvent::wxListEvent( wxEventType commandType
, int id
)
4193 : wxNotifyEvent( commandType
, id
)
4199 m_cancelled
= FALSE
;
4204 void wxListEvent::CopyObject(wxObject
& object_dest
) const
4206 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
4208 wxNotifyEvent::CopyObject(object_dest
);
4210 obj
->m_code
= m_code
;
4211 obj
->m_itemIndex
= m_itemIndex
;
4212 obj
->m_oldItemIndex
= m_oldItemIndex
;
4214 obj
->m_cancelled
= m_cancelled
;
4215 obj
->m_pointDrag
= m_pointDrag
;
4216 obj
->m_item
.m_mask
= m_item
.m_mask
;
4217 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
4218 obj
->m_item
.m_col
= m_item
.m_col
;
4219 obj
->m_item
.m_state
= m_item
.m_state
;
4220 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
4221 obj
->m_item
.m_text
= m_item
.m_text
;
4222 obj
->m_item
.m_image
= m_item
.m_image
;
4223 obj
->m_item
.m_data
= m_item
.m_data
;
4224 obj
->m_item
.m_format
= m_item
.m_format
;
4225 obj
->m_item
.m_width
= m_item
.m_width
;
4227 if ( m_item
.HasAttributes() )
4229 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
4233 // -------------------------------------------------------------------------------------
4235 // -------------------------------------------------------------------------------------
4237 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
4239 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
)
4240 EVT_SIZE(wxListCtrl::OnSize
)
4241 EVT_IDLE(wxListCtrl::OnIdle
)
4244 wxListCtrl::wxListCtrl()
4246 m_imageListNormal
= (wxImageList
*) NULL
;
4247 m_imageListSmall
= (wxImageList
*) NULL
;
4248 m_imageListState
= (wxImageList
*) NULL
;
4250 m_ownsImageListNormal
=
4251 m_ownsImageListSmall
=
4252 m_ownsImageListState
= FALSE
;
4254 m_mainWin
= (wxListMainWindow
*) NULL
;
4255 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4258 wxListCtrl::~wxListCtrl()
4261 m_mainWin
->ResetCurrent();
4263 if (m_ownsImageListNormal
)
4264 delete m_imageListNormal
;
4265 if (m_ownsImageListSmall
)
4266 delete m_imageListSmall
;
4267 if (m_ownsImageListState
)
4268 delete m_imageListState
;
4271 void wxListCtrl::CreateHeaderWindow()
4273 m_headerWin
= new wxListHeaderWindow
4275 this, -1, m_mainWin
,
4277 wxSize(GetClientSize().x
, HEADER_HEIGHT
),
4282 bool wxListCtrl::Create(wxWindow
*parent
,
4287 const wxValidator
&validator
,
4288 const wxString
&name
)
4292 m_imageListState
= (wxImageList
*) NULL
;
4293 m_ownsImageListNormal
=
4294 m_ownsImageListSmall
=
4295 m_ownsImageListState
= FALSE
;
4297 m_mainWin
= (wxListMainWindow
*) NULL
;
4298 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4300 if ( !(style
& wxLC_MASK_TYPE
) )
4302 style
= style
| wxLC_LIST
;
4305 if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name
) )
4308 // don't create the inner window with the border
4309 style
&= ~wxSUNKEN_BORDER
;
4311 m_mainWin
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style
);
4313 if ( HasFlag(wxLC_REPORT
) )
4315 CreateHeaderWindow();
4317 if ( HasFlag(wxLC_NO_HEADER
) )
4319 // VZ: why do we create it at all then?
4320 m_headerWin
->Show( FALSE
);
4327 void wxListCtrl::SetSingleStyle( long style
, bool add
)
4329 wxASSERT_MSG( !(style
& wxLC_VIRTUAL
),
4330 _T("wxLC_VIRTUAL can't be [un]set") );
4332 long flag
= GetWindowStyle();
4336 if (style
& wxLC_MASK_TYPE
)
4337 flag
&= ~(wxLC_MASK_TYPE
| wxLC_VIRTUAL
);
4338 if (style
& wxLC_MASK_ALIGN
)
4339 flag
&= ~wxLC_MASK_ALIGN
;
4340 if (style
& wxLC_MASK_SORT
)
4341 flag
&= ~wxLC_MASK_SORT
;
4353 SetWindowStyleFlag( flag
);
4356 void wxListCtrl::SetWindowStyleFlag( long flag
)
4360 m_mainWin
->DeleteEverything();
4364 GetClientSize( &width
, &height
);
4366 if (flag
& wxLC_REPORT
)
4368 if (!HasFlag(wxLC_REPORT
))
4372 CreateHeaderWindow();
4374 if (HasFlag(wxLC_NO_HEADER
))
4375 m_headerWin
->Show( FALSE
);
4379 if (flag
& wxLC_NO_HEADER
)
4380 m_headerWin
->Show( FALSE
);
4382 m_headerWin
->Show( TRUE
);
4388 if ( m_mainWin
->HasHeader() )
4390 m_headerWin
->Show( FALSE
);
4395 wxWindow::SetWindowStyleFlag( flag
);
4398 bool wxListCtrl::GetColumn(int col
, wxListItem
&item
) const
4400 m_mainWin
->GetColumn( col
, item
);
4404 bool wxListCtrl::SetColumn( int col
, wxListItem
& item
)
4406 m_mainWin
->SetColumn( col
, item
);
4410 int wxListCtrl::GetColumnWidth( int col
) const
4412 return m_mainWin
->GetColumnWidth( col
);
4415 bool wxListCtrl::SetColumnWidth( int col
, int width
)
4417 m_mainWin
->SetColumnWidth( col
, width
);
4421 int wxListCtrl::GetCountPerPage() const
4423 return m_mainWin
->GetCountPerPage(); // different from Windows ?
4426 bool wxListCtrl::GetItem( wxListItem
&info
) const
4428 m_mainWin
->GetItem( info
);
4432 bool wxListCtrl::SetItem( wxListItem
&info
)
4434 m_mainWin
->SetItem( info
);
4438 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId
)
4441 info
.m_text
= label
;
4442 info
.m_mask
= wxLIST_MASK_TEXT
;
4443 info
.m_itemId
= index
;
4447 info
.m_image
= imageId
;
4448 info
.m_mask
|= wxLIST_MASK_IMAGE
;
4450 m_mainWin
->SetItem(info
);
4454 int wxListCtrl::GetItemState( long item
, long stateMask
) const
4456 return m_mainWin
->GetItemState( item
, stateMask
);
4459 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask
)
4461 m_mainWin
->SetItemState( item
, state
, stateMask
);
4465 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) )
4468 info
.m_image
= image
;
4469 info
.m_mask
= wxLIST_MASK_IMAGE
;
4470 info
.m_itemId
= item
;
4471 m_mainWin
->SetItem( info
);
4475 wxString
wxListCtrl::GetItemText( long item
) const
4478 info
.m_itemId
= item
;
4479 m_mainWin
->GetItem( info
);
4483 void wxListCtrl::SetItemText( long item
, const wxString
&str
)
4486 info
.m_mask
= wxLIST_MASK_TEXT
;
4487 info
.m_itemId
= item
;
4489 m_mainWin
->SetItem( info
);
4492 long wxListCtrl::GetItemData( long item
) const
4495 info
.m_itemId
= item
;
4496 m_mainWin
->GetItem( info
);
4500 bool wxListCtrl::SetItemData( long item
, long data
)
4503 info
.m_mask
= wxLIST_MASK_DATA
;
4504 info
.m_itemId
= item
;
4506 m_mainWin
->SetItem( info
);
4510 bool wxListCtrl::GetItemRect( long item
, wxRect
&rect
, int WXUNUSED(code
) ) const
4512 m_mainWin
->GetItemRect( item
, rect
);
4516 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos
) const
4518 m_mainWin
->GetItemPosition( item
, pos
);
4522 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) )
4527 int wxListCtrl::GetItemCount() const
4529 return m_mainWin
->GetItemCount();
4532 int wxListCtrl::GetColumnCount() const
4534 return m_mainWin
->GetColumnCount();
4537 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall
)
4539 m_mainWin
->SetItemSpacing( spacing
, isSmall
);
4542 int wxListCtrl::GetItemSpacing( bool isSmall
) const
4544 return m_mainWin
->GetItemSpacing( isSmall
);
4547 int wxListCtrl::GetSelectedItemCount() const
4549 return m_mainWin
->GetSelectedItemCount();
4552 wxColour
wxListCtrl::GetTextColour() const
4554 return GetForegroundColour();
4557 void wxListCtrl::SetTextColour(const wxColour
& col
)
4559 SetForegroundColour(col
);
4562 long wxListCtrl::GetTopItem() const
4567 long wxListCtrl::GetNextItem( long item
, int geom
, int state
) const
4569 return m_mainWin
->GetNextItem( item
, geom
, state
);
4572 wxImageList
*wxListCtrl::GetImageList(int which
) const
4574 if (which
== wxIMAGE_LIST_NORMAL
)
4576 return m_imageListNormal
;
4578 else if (which
== wxIMAGE_LIST_SMALL
)
4580 return m_imageListSmall
;
4582 else if (which
== wxIMAGE_LIST_STATE
)
4584 return m_imageListState
;
4586 return (wxImageList
*) NULL
;
4589 void wxListCtrl::SetImageList( wxImageList
*imageList
, int which
)
4591 if ( which
== wxIMAGE_LIST_NORMAL
)
4593 if (m_ownsImageListNormal
) delete m_imageListNormal
;
4594 m_imageListNormal
= imageList
;
4595 m_ownsImageListNormal
= FALSE
;
4597 else if ( which
== wxIMAGE_LIST_SMALL
)
4599 if (m_ownsImageListSmall
) delete m_imageListSmall
;
4600 m_imageListSmall
= imageList
;
4601 m_ownsImageListSmall
= FALSE
;
4603 else if ( which
== wxIMAGE_LIST_STATE
)
4605 if (m_ownsImageListState
) delete m_imageListState
;
4606 m_imageListState
= imageList
;
4607 m_ownsImageListState
= FALSE
;
4610 m_mainWin
->SetImageList( imageList
, which
);
4613 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
4615 SetImageList(imageList
, which
);
4616 if ( which
== wxIMAGE_LIST_NORMAL
)
4617 m_ownsImageListNormal
= TRUE
;
4618 else if ( which
== wxIMAGE_LIST_SMALL
)
4619 m_ownsImageListSmall
= TRUE
;
4620 else if ( which
== wxIMAGE_LIST_STATE
)
4621 m_ownsImageListState
= TRUE
;
4624 bool wxListCtrl::Arrange( int WXUNUSED(flag
) )
4629 bool wxListCtrl::DeleteItem( long item
)
4631 m_mainWin
->DeleteItem( item
);
4635 bool wxListCtrl::DeleteAllItems()
4637 m_mainWin
->DeleteAllItems();
4641 bool wxListCtrl::DeleteAllColumns()
4643 size_t count
= m_mainWin
->m_columns
.GetCount();
4644 for ( size_t n
= 0; n
< count
; n
++ )
4650 void wxListCtrl::ClearAll()
4652 m_mainWin
->DeleteEverything();
4655 bool wxListCtrl::DeleteColumn( int col
)
4657 m_mainWin
->DeleteColumn( col
);
4661 void wxListCtrl::Edit( long item
)
4663 m_mainWin
->EditLabel( item
);
4666 bool wxListCtrl::EnsureVisible( long item
)
4668 m_mainWin
->EnsureVisible( item
);
4672 long wxListCtrl::FindItem( long start
, const wxString
& str
, bool partial
)
4674 return m_mainWin
->FindItem( start
, str
, partial
);
4677 long wxListCtrl::FindItem( long start
, long data
)
4679 return m_mainWin
->FindItem( start
, data
);
4682 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
),
4683 int WXUNUSED(direction
))
4688 long wxListCtrl::HitTest( const wxPoint
&point
, int &flags
)
4690 return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags
);
4693 long wxListCtrl::InsertItem( wxListItem
& info
)
4695 m_mainWin
->InsertItem( info
);
4696 return info
.m_itemId
;
4699 long wxListCtrl::InsertItem( long index
, const wxString
&label
)
4702 info
.m_text
= label
;
4703 info
.m_mask
= wxLIST_MASK_TEXT
;
4704 info
.m_itemId
= index
;
4705 return InsertItem( info
);
4708 long wxListCtrl::InsertItem( long index
, int imageIndex
)
4711 info
.m_mask
= wxLIST_MASK_IMAGE
;
4712 info
.m_image
= imageIndex
;
4713 info
.m_itemId
= index
;
4714 return InsertItem( info
);
4717 long wxListCtrl::InsertItem( long index
, const wxString
&label
, int imageIndex
)
4720 info
.m_text
= label
;
4721 info
.m_image
= imageIndex
;
4722 info
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_IMAGE
;
4723 info
.m_itemId
= index
;
4724 return InsertItem( info
);
4727 long wxListCtrl::InsertColumn( long col
, wxListItem
&item
)
4729 wxASSERT( m_headerWin
);
4730 m_mainWin
->InsertColumn( col
, item
);
4731 m_headerWin
->Refresh();
4736 long wxListCtrl::InsertColumn( long col
, const wxString
&heading
,
4737 int format
, int width
)
4740 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
4741 item
.m_text
= heading
;
4744 item
.m_mask
|= wxLIST_MASK_WIDTH
;
4745 item
.m_width
= width
;
4747 item
.m_format
= format
;
4749 return InsertColumn( col
, item
);
4752 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) )
4758 // fn is a function which takes 3 long arguments: item1, item2, data.
4759 // item1 is the long data associated with a first item (NOT the index).
4760 // item2 is the long data associated with a second item (NOT the index).
4761 // data is the same value as passed to SortItems.
4762 // The return value is a negative number if the first item should precede the second
4763 // item, a positive number of the second item should precede the first,
4764 // or zero if the two items are equivalent.
4765 // data is arbitrary data to be passed to the sort function.
4767 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data
)
4769 m_mainWin
->SortItems( fn
, data
);
4773 // ----------------------------------------------------------------------------
4775 // ----------------------------------------------------------------------------
4777 void wxListCtrl::OnSize(wxSizeEvent
& event
)
4783 GetClientSize( &cw
, &ch
);
4785 if ( m_mainWin
->HasHeader() )
4787 m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT
);
4788 m_mainWin
->SetSize( 0, HEADER_HEIGHT
+ 1, cw
, ch
- HEADER_HEIGHT
- 1 );
4790 else // no header window
4792 m_mainWin
->SetSize( 0, 0, cw
, ch
);
4795 m_mainWin
->RecalculatePositions();
4798 void wxListCtrl::OnIdle( wxIdleEvent
& event
)
4802 // do it only if needed
4803 if ( !m_mainWin
->m_dirty
)
4806 m_mainWin
->RecalculatePositions();
4809 // ----------------------------------------------------------------------------
4811 // ----------------------------------------------------------------------------
4813 bool wxListCtrl::SetBackgroundColour( const wxColour
&colour
)
4817 m_mainWin
->SetBackgroundColour( colour
);
4818 m_mainWin
->m_dirty
= TRUE
;
4824 bool wxListCtrl::SetForegroundColour( const wxColour
&colour
)
4826 if ( !wxWindow::SetForegroundColour( colour
) )
4831 m_mainWin
->SetForegroundColour( colour
);
4832 m_mainWin
->m_dirty
= TRUE
;
4837 m_headerWin
->SetForegroundColour( colour
);
4843 bool wxListCtrl::SetFont( const wxFont
&font
)
4845 if ( !wxWindow::SetFont( font
) )
4850 m_mainWin
->SetFont( font
);
4851 m_mainWin
->m_dirty
= TRUE
;
4856 m_headerWin
->SetFont( font
);
4862 // ----------------------------------------------------------------------------
4863 // methods forwarded to m_mainWin
4864 // ----------------------------------------------------------------------------
4866 #if wxUSE_DRAG_AND_DROP
4868 void wxListCtrl::SetDropTarget( wxDropTarget
*dropTarget
)
4870 m_mainWin
->SetDropTarget( dropTarget
);
4873 wxDropTarget
*wxListCtrl::GetDropTarget() const
4875 return m_mainWin
->GetDropTarget();
4878 #endif // wxUSE_DRAG_AND_DROP
4880 bool wxListCtrl::SetCursor( const wxCursor
&cursor
)
4882 return m_mainWin
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
;
4885 wxColour
wxListCtrl::GetBackgroundColour() const
4887 return m_mainWin
? m_mainWin
->GetBackgroundColour() : wxColour();
4890 wxColour
wxListCtrl::GetForegroundColour() const
4892 return m_mainWin
? m_mainWin
->GetForegroundColour() : wxColour();
4895 bool wxListCtrl::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4898 return m_mainWin
->PopupMenu( menu
, x
, y
);
4901 #endif // wxUSE_MENUS
4904 void wxListCtrl::SetFocus()
4906 /* The test in window.cpp fails as we are a composite
4907 window, so it checks against "this", but not m_mainWin. */
4908 if ( FindFocus() != this )
4909 m_mainWin
->SetFocus();
4912 // ----------------------------------------------------------------------------
4913 // virtual list control support
4914 // ----------------------------------------------------------------------------
4916 wxString
wxListCtrl::OnGetItemText(long item
, long col
) const
4918 // this is a pure virtual function, in fact - which is not really pure
4919 // because the controls which are not virtual don't need to implement it
4920 wxFAIL_MSG( _T("not supposed to be called") );
4922 return wxEmptyString
;
4925 int wxListCtrl::OnGetItemImage(long item
) const
4928 wxFAIL_MSG( _T("not supposed to be called") );
4933 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long item
) const
4935 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
4936 _T("invalid item index in OnGetItemAttr()") );
4938 // no attributes by default
4942 void wxListCtrl::SetItemCount(long count
)
4944 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4946 m_mainWin
->SetItemCount(count
);
4949 void wxListCtrl::RefreshItem(long item
)
4951 m_mainWin
->RefreshLine(item
);
4954 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
)
4956 m_mainWin
->RefreshLines(itemFrom
, itemTo
);
4959 #endif // wxUSE_LISTCTRL