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 // called when an item is [un]focuded, i.e. becomes [not] current
825 void OnFocusLine( size_t line
);
826 void OnUnfocusLine( size_t line
);
828 // the height of one line using the current font
829 wxCoord m_lineHeight
;
831 // the total header width or 0 if not calculated yet
832 wxCoord m_headerWidth
;
834 // the first and last lines being shown on screen right now (inclusive),
835 // both may be -1 if they must be calculated so never access them directly:
836 // use GetVisibleLinesRange() above instead
840 DECLARE_DYNAMIC_CLASS(wxListMainWindow
);
841 DECLARE_EVENT_TABLE()
844 // ============================================================================
846 // ============================================================================
848 // ----------------------------------------------------------------------------
850 // ----------------------------------------------------------------------------
852 bool wxSelectionStore::IsSelected(size_t item
) const
854 bool isSel
= m_itemsSel
.Index(item
) != wxNOT_FOUND
;
856 // if the default state is to be selected, being in m_itemsSel means that
857 // the item is not selected, so we have to inverse the logic
858 return m_defaultState
? !isSel
: isSel
;
861 bool wxSelectionStore::SelectItem(size_t item
, bool select
)
863 // search for the item ourselves as like this we get the index where to
864 // insert it later if needed, so we do only one search in the array instead
865 // of two (adding item to a sorted array requires a search)
866 size_t index
= m_itemsSel
.IndexForInsert(item
);
867 bool isSel
= index
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
;
869 if ( select
!= m_defaultState
)
873 m_itemsSel
.AddAt(item
, index
);
878 else // reset to default state
882 m_itemsSel
.RemoveAt(index
);
890 void wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, bool select
)
892 wxASSERT_MSG( itemFrom
<= itemTo
, _T("should be in order") );
894 // are we going to have more [un]selected items than the other ones?
895 if ( itemTo
- itemFrom
> m_count
/ 2 )
897 if ( select
!= m_defaultState
)
899 // the default state now becomes the same as 'select'
900 m_defaultState
= select
;
902 // so all the old selections (which had state select) shouldn't be
903 // selected any more, but all the other ones should
904 wxIndexArray selOld
= m_itemsSel
;
907 // TODO: it should be possible to optimize the searches a bit
908 // knowing the possible range
911 for ( item
= 0; item
< itemFrom
; item
++ )
913 if ( selOld
.Index(item
) == wxNOT_FOUND
)
914 m_itemsSel
.Add(item
);
917 for ( item
= itemTo
+ 1; item
< m_count
; item
++ )
919 if ( selOld
.Index(item
) == wxNOT_FOUND
)
920 m_itemsSel
.Add(item
);
923 else // select == m_defaultState
925 // get the inclusive range of items between itemFrom and itemTo
926 size_t count
= m_itemsSel
.GetCount(),
927 start
= m_itemsSel
.IndexForInsert(itemFrom
),
928 end
= m_itemsSel
.IndexForInsert(itemTo
);
930 if ( start
== count
|| m_itemsSel
[start
] < itemFrom
)
935 if ( end
== count
|| m_itemsSel
[end
] > itemTo
)
942 // delete all of them (from end to avoid changing indices)
943 for ( int i
= end
; i
>= (int)start
; i
-- )
945 m_itemsSel
.RemoveAt(i
);
950 else // "few" items change state
952 // just add the items to the selection
953 for ( size_t item
= itemFrom
; item
<= itemTo
; item
++ )
955 SelectItem(item
, select
);
960 void wxSelectionStore::OnItemDelete(size_t item
)
962 size_t count
= m_itemsSel
.GetCount(),
963 i
= m_itemsSel
.IndexForInsert(item
);
965 if ( i
< count
&& m_itemsSel
[i
] == item
)
967 // this item itself was in m_itemsSel, remove it from there
968 m_itemsSel
.RemoveAt(i
);
973 // and adjust the index of all which follow it
976 // all following elements must be greater than the one we deleted
977 wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") );
983 //-----------------------------------------------------------------------------
985 //-----------------------------------------------------------------------------
987 wxListItemData::~wxListItemData()
989 // in the virtual list control the attributes are managed by the main
990 // program, so don't delete them
991 if ( !m_owner
->IsVirtual() )
999 void wxListItemData::Init()
1007 wxListItemData::wxListItemData(wxListMainWindow
*owner
)
1013 if ( owner
->InReportView() )
1019 m_rect
= new wxRect
;
1023 void wxListItemData::SetItem( const wxListItem
&info
)
1025 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
1026 SetText(info
.m_text
);
1027 if ( info
.m_mask
& wxLIST_MASK_IMAGE
)
1028 m_image
= info
.m_image
;
1029 if ( info
.m_mask
& wxLIST_MASK_DATA
)
1030 m_data
= info
.m_data
;
1032 if ( info
.HasAttributes() )
1035 *m_attr
= *info
.GetAttributes();
1037 m_attr
= new wxListItemAttr(*info
.GetAttributes());
1045 m_rect
->width
= info
.m_width
;
1049 void wxListItemData::SetPosition( int x
, int y
)
1051 wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") );
1057 void wxListItemData::SetSize( int width
, int height
)
1059 wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") );
1062 m_rect
->width
= width
;
1064 m_rect
->height
= height
;
1067 bool wxListItemData::IsHit( int x
, int y
) const
1069 wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") );
1071 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
);
1074 int wxListItemData::GetX() const
1076 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1081 int wxListItemData::GetY() const
1083 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1088 int wxListItemData::GetWidth() const
1090 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1092 return m_rect
->width
;
1095 int wxListItemData::GetHeight() const
1097 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1099 return m_rect
->height
;
1102 void wxListItemData::GetItem( wxListItem
&info
) const
1104 info
.m_text
= m_text
;
1105 info
.m_image
= m_image
;
1106 info
.m_data
= m_data
;
1110 if ( m_attr
->HasTextColour() )
1111 info
.SetTextColour(m_attr
->GetTextColour());
1112 if ( m_attr
->HasBackgroundColour() )
1113 info
.SetBackgroundColour(m_attr
->GetBackgroundColour());
1114 if ( m_attr
->HasFont() )
1115 info
.SetFont(m_attr
->GetFont());
1119 //-----------------------------------------------------------------------------
1121 //-----------------------------------------------------------------------------
1123 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
);
1125 wxListHeaderData::wxListHeaderData()
1136 wxListHeaderData::wxListHeaderData( const wxListItem
&item
)
1144 void wxListHeaderData::SetItem( const wxListItem
&item
)
1146 m_mask
= item
.m_mask
;
1147 m_text
= item
.m_text
;
1148 m_image
= item
.m_image
;
1149 m_format
= item
.m_format
;
1151 SetWidth(item
.m_width
);
1154 void wxListHeaderData::SetPosition( int x
, int y
)
1160 void wxListHeaderData::SetHeight( int h
)
1165 void wxListHeaderData::SetWidth( int w
)
1169 m_width
= WIDTH_COL_DEFAULT
;
1170 if (m_width
< WIDTH_COL_MIN
)
1171 m_width
= WIDTH_COL_MIN
;
1174 void wxListHeaderData::SetFormat( int format
)
1179 bool wxListHeaderData::HasImage() const
1181 return (m_image
!= 0);
1184 bool wxListHeaderData::IsHit( int x
, int y
) const
1186 return ((x
>= m_xpos
) && (x
<= m_xpos
+m_width
) && (y
>= m_ypos
) && (y
<= m_ypos
+m_height
));
1189 void wxListHeaderData::GetItem( wxListItem
&item
)
1191 item
.m_mask
= m_mask
;
1192 item
.m_text
= m_text
;
1193 item
.m_image
= m_image
;
1194 item
.m_format
= m_format
;
1195 item
.m_width
= m_width
;
1198 int wxListHeaderData::GetImage() const
1203 int wxListHeaderData::GetWidth() const
1208 int wxListHeaderData::GetFormat() const
1213 //-----------------------------------------------------------------------------
1215 //-----------------------------------------------------------------------------
1217 inline int wxListLineData::GetMode() const
1219 return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
;
1222 inline bool wxListLineData::InReportView() const
1224 return m_owner
->HasFlag(wxLC_REPORT
);
1227 inline bool wxListLineData::IsVirtual() const
1229 return m_owner
->IsVirtual();
1232 wxListLineData::wxListLineData( wxListMainWindow
*owner
)
1235 m_items
.DeleteContents( TRUE
);
1237 if ( InReportView() )
1243 m_gi
= new GeometryInfo
;
1246 m_highlighted
= FALSE
;
1248 InitItems( GetMode() == wxLC_REPORT
? m_owner
->GetColumnCount() : 1 );
1251 void wxListLineData::CalculateSize( wxDC
*dc
, int spacing
)
1253 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1254 wxCHECK_RET( node
, _T("no subitems at all??") );
1256 wxListItemData
*item
= node
->GetData();
1258 switch ( GetMode() )
1261 case wxLC_SMALL_ICON
:
1263 m_gi
->m_rectAll
.width
= spacing
;
1265 wxString s
= item
->GetText();
1271 m_gi
->m_rectLabel
.width
=
1272 m_gi
->m_rectLabel
.height
= 0;
1276 dc
->GetTextExtent( s
, &lw
, &lh
);
1277 if (lh
< SCROLL_UNIT_Y
)
1282 m_gi
->m_rectAll
.height
= spacing
+ lh
;
1284 m_gi
->m_rectAll
.width
= lw
;
1286 m_gi
->m_rectLabel
.width
= lw
;
1287 m_gi
->m_rectLabel
.height
= lh
;
1290 if (item
->HasImage())
1293 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1294 m_gi
->m_rectIcon
.width
= w
+ 8;
1295 m_gi
->m_rectIcon
.height
= h
+ 8;
1297 if ( m_gi
->m_rectIcon
.width
> m_gi
->m_rectAll
.width
)
1298 m_gi
->m_rectAll
.width
= m_gi
->m_rectIcon
.width
;
1299 if ( m_gi
->m_rectIcon
.height
+ lh
> m_gi
->m_rectAll
.height
- 4 )
1300 m_gi
->m_rectAll
.height
= m_gi
->m_rectIcon
.height
+ lh
+ 4;
1303 if ( item
->HasText() )
1305 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectLabel
.width
;
1306 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectLabel
.height
;
1308 else // no text, highlight the icon
1310 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectIcon
.width
;
1311 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectIcon
.height
;
1318 wxString s
= item
->GetTextForMeasuring();
1321 dc
->GetTextExtent( s
, &lw
, &lh
);
1322 if (lh
< SCROLL_UNIT_Y
)
1327 m_gi
->m_rectLabel
.width
= lw
;
1328 m_gi
->m_rectLabel
.height
= lh
;
1330 m_gi
->m_rectAll
.width
= lw
;
1331 m_gi
->m_rectAll
.height
= lh
;
1333 if (item
->HasImage())
1336 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1337 m_gi
->m_rectIcon
.width
= w
;
1338 m_gi
->m_rectIcon
.height
= h
;
1340 m_gi
->m_rectAll
.width
+= 4 + w
;
1341 if (h
> m_gi
->m_rectAll
.height
)
1342 m_gi
->m_rectAll
.height
= h
;
1345 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectAll
.width
;
1346 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectAll
.height
;
1351 wxFAIL_MSG( _T("unexpected call to SetSize") );
1355 wxFAIL_MSG( _T("unknown mode") );
1359 void wxListLineData::SetPosition( int x
, int y
,
1363 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1364 wxCHECK_RET( node
, _T("no subitems at all??") );
1366 wxListItemData
*item
= node
->GetData();
1368 switch ( GetMode() )
1371 case wxLC_SMALL_ICON
:
1372 m_gi
->m_rectAll
.x
= x
;
1373 m_gi
->m_rectAll
.y
= y
;
1375 if ( item
->HasImage() )
1377 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 4
1378 + (spacing
- m_gi
->m_rectIcon
.width
)/2;
1379 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 4;
1382 if ( item
->HasText() )
1384 if (m_gi
->m_rectAll
.width
> spacing
)
1385 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1387 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2);
1388 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ m_gi
->m_rectAll
.height
+ 2 - m_gi
->m_rectLabel
.height
;
1389 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectLabel
.x
- 2;
1390 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectLabel
.y
- 2;
1392 else // no text, highlight the icon
1394 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectIcon
.x
- 4;
1395 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectIcon
.y
- 4;
1400 m_gi
->m_rectAll
.x
= x
;
1401 m_gi
->m_rectAll
.y
= y
;
1403 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectAll
.x
;
1404 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectAll
.y
;
1405 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ 2;
1407 if (item
->HasImage())
1409 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 2;
1410 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 2;
1411 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 6 + m_gi
->m_rectIcon
.width
;
1415 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1420 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1424 wxFAIL_MSG( _T("unknown mode") );
1428 void wxListLineData::InitItems( int num
)
1430 for (int i
= 0; i
< num
; i
++)
1431 m_items
.Append( new wxListItemData(m_owner
) );
1434 void wxListLineData::SetItem( int index
, const wxListItem
&info
)
1436 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1437 wxCHECK_RET( node
, _T("invalid column index in SetItem") );
1439 wxListItemData
*item
= node
->GetData();
1440 item
->SetItem( info
);
1443 void wxListLineData::GetItem( int index
, wxListItem
&info
)
1445 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1448 wxListItemData
*item
= node
->GetData();
1449 item
->GetItem( info
);
1453 wxString
wxListLineData::GetText(int index
) const
1457 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1460 wxListItemData
*item
= node
->GetData();
1461 s
= item
->GetText();
1467 void wxListLineData::SetText( int index
, const wxString s
)
1469 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1472 wxListItemData
*item
= node
->GetData();
1477 void wxListLineData::SetImage( int index
, int image
)
1479 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1480 wxCHECK_RET( node
, _T("invalid column index in SetImage()") );
1482 wxListItemData
*item
= node
->GetData();
1483 item
->SetImage(image
);
1486 int wxListLineData::GetImage( int index
) const
1488 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1489 wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") );
1491 wxListItemData
*item
= node
->GetData();
1492 return item
->GetImage();
1495 wxListItemAttr
*wxListLineData::GetAttr() const
1497 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1498 wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") );
1500 wxListItemData
*item
= node
->GetData();
1501 return item
->GetAttr();
1504 void wxListLineData::SetAttr(wxListItemAttr
*attr
)
1506 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1507 wxCHECK_RET( node
, _T("invalid column index in SetAttr()") );
1509 wxListItemData
*item
= node
->GetData();
1510 item
->SetAttr(attr
);
1513 void wxListLineData::SetAttributes(wxDC
*dc
,
1514 const wxListItemAttr
*attr
,
1515 const wxColour
& colText
,
1519 // don't use foregroud colour for drawing highlighted items - this might
1520 // make them completely invisible (and there is no way to do bit
1521 // arithmetics on wxColour, unfortunately)
1522 if ( !highlight
&& attr
&& attr
->HasTextColour() )
1524 dc
->SetTextForeground(attr
->GetTextColour());
1528 dc
->SetTextForeground(colText
);
1531 if ( attr
&& attr
->HasFont() )
1533 dc
->SetFont(attr
->GetFont());
1541 void wxListLineData::Draw( wxDC
*dc
)
1543 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1544 wxCHECK_RET( node
, _T("no subitems at all??") );
1546 wxListItemData
*item
= node
->GetData();
1547 if (item
->HasImage())
1549 wxRect rectIcon
= m_gi
->m_rectIcon
;
1550 m_owner
->DrawImage( item
->GetImage(), dc
,
1551 rectIcon
.x
, rectIcon
.y
);
1554 if (item
->HasText())
1556 wxRect rectLabel
= m_gi
->m_rectLabel
;
1557 dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y
);
1561 void wxListLineData::DrawInReportMode( wxDC
*dc
,
1563 const wxRect
& rectHL
,
1566 // use our own flag if we maintain it
1568 highlighted
= m_highlighted
;
1570 // default foreground colour
1571 wxWindow
*listctrl
= m_owner
->GetParent();
1575 colText
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT
);
1579 colText
= listctrl
->GetForegroundColour();
1583 wxFont font
= listctrl
->GetFont();
1585 // TODO: later we should support setting different attributes for
1586 // different columns - to do it, just add "col" argument to
1587 // GetAttr() and move this code into the loop below
1588 wxListItemAttr
*attr
= GetAttr();
1589 SetAttributes(dc
, attr
, colText
, font
, highlighted
);
1591 bool hasBgCol
= attr
&& attr
->HasBackgroundColour();
1592 if ( highlighted
|| hasBgCol
)
1596 dc
->SetBrush( *m_owner
->m_highlightBrush
);
1601 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
1603 dc
->SetBrush( * wxWHITE_BRUSH
);
1606 dc
->SetPen( * wxTRANSPARENT_PEN
);
1607 dc
->DrawRectangle( rectHL
);
1610 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1611 wxCHECK_RET( node
, _T("no subitems at all??") );
1614 wxCoord x
= rect
.x
+ HEADER_OFFSET_X
,
1615 y
= rect
.y
+ (LINE_SPACING
+ EXTRA_HEIGHT
) / 2;
1619 wxListItemData
*item
= node
->GetData();
1623 if ( item
->HasImage() )
1626 m_owner
->DrawImage( item
->GetImage(), dc
, x
, y
);
1627 m_owner
->GetImageSize( item
->GetImage(), ix
, iy
);
1628 x
+= ix
+ 5; // FIXME: what is "5"?
1631 int width
= m_owner
->GetColumnWidth(col
++);
1633 wxDCClipper
clipper(*dc
, x
, y
, width
, rect
.height
);
1635 if ( item
->HasText() )
1637 dc
->DrawText( item
->GetText(), x
, y
);
1642 node
= node
->GetNext();
1646 bool wxListLineData::Highlight( bool on
)
1648 wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") );
1650 if ( on
== m_highlighted
)
1658 void wxListLineData::ReverseHighlight( void )
1660 Highlight(!IsHighlighted());
1663 //-----------------------------------------------------------------------------
1664 // wxListHeaderWindow
1665 //-----------------------------------------------------------------------------
1667 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
);
1669 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
)
1670 EVT_PAINT (wxListHeaderWindow::OnPaint
)
1671 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse
)
1672 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus
)
1675 wxListHeaderWindow::wxListHeaderWindow( void )
1677 m_owner
= (wxListMainWindow
*) NULL
;
1678 m_currentCursor
= (wxCursor
*) NULL
;
1679 m_resizeCursor
= (wxCursor
*) NULL
;
1680 m_isDragging
= FALSE
;
1683 wxListHeaderWindow::wxListHeaderWindow( wxWindow
*win
, wxWindowID id
, wxListMainWindow
*owner
,
1684 const wxPoint
&pos
, const wxSize
&size
,
1685 long style
, const wxString
&name
) :
1686 wxWindow( win
, id
, pos
, size
, style
, name
)
1689 // m_currentCursor = wxSTANDARD_CURSOR;
1690 m_currentCursor
= (wxCursor
*) NULL
;
1691 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
1692 m_isDragging
= FALSE
;
1695 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE
) );
1698 wxListHeaderWindow::~wxListHeaderWindow( void )
1700 delete m_resizeCursor
;
1703 void wxListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1706 GtkStateType state
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
1707 : GTK_STATE_INSENSITIVE
;
1709 x
= dc
->XLOG2DEV( x
);
1711 gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
,
1712 state
, GTK_SHADOW_OUT
,
1713 (GdkRectangle
*) NULL
, m_wxwindow
, "button",
1714 x
-1, y
-1, w
+2, h
+2);
1715 #elif defined( __WXMAC__ )
1716 const int m_corner
= 1;
1718 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1720 dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
) , 1 , wxSOLID
) );
1721 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1722 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1724 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1727 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1728 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1730 dc
->SetPen( *wxWHITE_PEN
);
1731 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1732 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1733 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1734 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1736 const int m_corner
= 1;
1738 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1740 dc
->SetPen( *wxBLACK_PEN
);
1741 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1742 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1744 wxPen
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1747 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1748 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1750 dc
->SetPen( *wxWHITE_PEN
);
1751 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1752 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1753 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1754 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1758 // shift the DC origin to match the position of the main window horz
1759 // scrollbar: this allows us to always use logical coords
1760 void wxListHeaderWindow::AdjustDC(wxDC
& dc
)
1763 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1766 m_owner
->GetViewStart( &x
, NULL
);
1768 // account for the horz scrollbar offset
1769 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1772 void wxListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1775 wxClientDC
dc( this );
1777 wxPaintDC
dc( this );
1785 dc
.SetFont( GetFont() );
1787 // width and height of the entire header window
1789 GetClientSize( &w
, &h
);
1790 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1792 dc
.SetBackgroundMode(wxTRANSPARENT
);
1794 // do *not* use the listctrl colour for headers - one day we will have a
1795 // function to set it separately
1796 //dc.SetTextForeground( *wxBLACK );
1797 dc
.SetTextForeground(wxSystemSettings::
1798 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1800 int x
= HEADER_OFFSET_X
;
1802 int numColumns
= m_owner
->GetColumnCount();
1804 for (int i
= 0; i
< numColumns
; i
++)
1806 m_owner
->GetColumn( i
, item
);
1807 int wCol
= item
.m_width
;
1808 int cw
= wCol
- 2; // the width of the rect to draw
1810 int xEnd
= x
+ wCol
;
1812 dc
.SetPen( *wxWHITE_PEN
);
1814 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1815 dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 );
1816 dc
.DrawText( item
.GetText(), x
+ EXTRA_WIDTH
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1817 dc
.DestroyClippingRegion();
1826 void wxListHeaderWindow::DrawCurrent()
1828 int x1
= m_currentX
;
1830 ClientToScreen( &x1
, &y1
);
1832 int x2
= m_currentX
-1;
1834 m_owner
->GetClientSize( NULL
, &y2
);
1835 m_owner
->ClientToScreen( &x2
, &y2
);
1838 dc
.SetLogicalFunction( wxINVERT
);
1839 dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID
) );
1840 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1844 dc
.DrawLine( x1
, y1
, x2
, y2
);
1846 dc
.SetLogicalFunction( wxCOPY
);
1848 dc
.SetPen( wxNullPen
);
1849 dc
.SetBrush( wxNullBrush
);
1852 void wxListHeaderWindow::OnMouse( wxMouseEvent
&event
)
1854 // we want to work with logical coords
1856 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1857 int y
= event
.GetY();
1861 // we don't draw the line beyond our window, but we allow dragging it
1864 GetClientSize( &w
, NULL
);
1865 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1868 // erase the line if it was drawn
1869 if ( m_currentX
< w
)
1872 if (event
.ButtonUp())
1875 m_isDragging
= FALSE
;
1877 m_owner
->SetColumnWidth( m_column
, m_currentX
- m_minX
);
1884 m_currentX
= m_minX
+ 7;
1886 // draw in the new location
1887 if ( m_currentX
< w
)
1891 else // not dragging
1894 bool hit_border
= FALSE
;
1896 // end of the current column
1899 // find the column where this event occured
1900 int countCol
= m_owner
->GetColumnCount();
1901 for (int col
= 0; col
< countCol
; col
++)
1903 xpos
+= m_owner
->GetColumnWidth( col
);
1906 if ( (abs(x
-xpos
) < 3) && (y
< 22) )
1908 // near the column border
1915 // inside the column
1922 if (event
.LeftDown())
1926 m_isDragging
= TRUE
;
1933 wxWindow
*parent
= GetParent();
1934 wxListEvent
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() );
1935 le
.SetEventObject( parent
);
1936 le
.m_col
= m_column
;
1937 parent
->GetEventHandler()->ProcessEvent( le
);
1940 else if (event
.Moving())
1945 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1946 m_currentCursor
= m_resizeCursor
;
1950 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1951 m_currentCursor
= wxSTANDARD_CURSOR
;
1955 SetCursor(*m_currentCursor
);
1960 void wxListHeaderWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
1962 m_owner
->SetFocus();
1965 //-----------------------------------------------------------------------------
1966 // wxListRenameTimer (internal)
1967 //-----------------------------------------------------------------------------
1969 wxListRenameTimer::wxListRenameTimer( wxListMainWindow
*owner
)
1974 void wxListRenameTimer::Notify()
1976 m_owner
->OnRenameTimer();
1979 //-----------------------------------------------------------------------------
1980 // wxListTextCtrl (internal)
1981 //-----------------------------------------------------------------------------
1983 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
);
1985 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
)
1986 EVT_CHAR (wxListTextCtrl::OnChar
)
1987 EVT_KEY_UP (wxListTextCtrl::OnKeyUp
)
1988 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus
)
1991 wxListTextCtrl::wxListTextCtrl( wxWindow
*parent
,
1992 const wxWindowID id
,
1995 wxListMainWindow
*owner
,
1996 const wxString
&value
,
2000 const wxValidator
& validator
,
2001 const wxString
&name
)
2002 : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name
)
2007 (*m_accept
) = FALSE
;
2009 m_startValue
= value
;
2012 void wxListTextCtrl::OnChar( wxKeyEvent
&event
)
2014 if (event
.m_keyCode
== WXK_RETURN
)
2017 (*m_res
) = GetValue();
2019 if (!wxPendingDelete
.Member(this))
2020 wxPendingDelete
.Append(this);
2022 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2023 m_owner
->OnRenameAccept();
2027 if (event
.m_keyCode
== WXK_ESCAPE
)
2029 (*m_accept
) = FALSE
;
2032 if (!wxPendingDelete
.Member(this))
2033 wxPendingDelete
.Append(this);
2041 void wxListTextCtrl::OnKeyUp( wxKeyEvent
&event
)
2043 // auto-grow the textctrl:
2044 wxSize parentSize
= m_owner
->GetSize();
2045 wxPoint myPos
= GetPosition();
2046 wxSize mySize
= GetSize();
2048 GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM??
2049 if (myPos
.x
+ sx
> parentSize
.x
)
2050 sx
= parentSize
.x
- myPos
.x
;
2058 void wxListTextCtrl::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
2060 if (!wxPendingDelete
.Member(this))
2061 wxPendingDelete
.Append(this);
2063 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2064 m_owner
->OnRenameAccept();
2067 //-----------------------------------------------------------------------------
2069 //-----------------------------------------------------------------------------
2071 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
);
2073 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
)
2074 EVT_PAINT (wxListMainWindow::OnPaint
)
2075 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse
)
2076 EVT_CHAR (wxListMainWindow::OnChar
)
2077 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown
)
2078 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus
)
2079 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus
)
2080 EVT_SCROLLWIN (wxListMainWindow::OnScroll
)
2083 void wxListMainWindow::Init()
2085 m_columns
.DeleteContents( TRUE
);
2089 m_lineTo
= (size_t)-1;
2095 m_small_image_list
= (wxImageList
*) NULL
;
2096 m_normal_image_list
= (wxImageList
*) NULL
;
2098 m_small_spacing
= 30;
2099 m_normal_spacing
= 40;
2103 m_isCreated
= FALSE
;
2105 m_lastOnSame
= FALSE
;
2106 m_renameTimer
= new wxListRenameTimer( this );
2107 m_renameAccept
= FALSE
;
2112 m_lineBeforeLastClicked
= (size_t)-1;
2115 void wxListMainWindow::InitScrolling()
2117 if ( HasFlag(wxLC_REPORT
) )
2119 m_xScroll
= SCROLL_UNIT_X
;
2120 m_yScroll
= SCROLL_UNIT_Y
;
2124 m_xScroll
= SCROLL_UNIT_Y
;
2129 wxListMainWindow::wxListMainWindow()
2133 m_highlightBrush
= (wxBrush
*) NULL
;
2139 wxListMainWindow::wxListMainWindow( wxWindow
*parent
,
2144 const wxString
&name
)
2145 : wxScrolledWindow( parent
, id
, pos
, size
,
2146 style
| wxHSCROLL
| wxVSCROLL
, name
)
2150 m_highlightBrush
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
2155 SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 );
2157 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX
) );
2160 wxListMainWindow::~wxListMainWindow()
2164 delete m_highlightBrush
;
2166 delete m_renameTimer
;
2169 void wxListMainWindow::CacheLineData(size_t line
)
2171 wxListCtrl
*listctrl
= GetListCtrl();
2173 wxListLineData
*ld
= GetDummyLine();
2175 size_t countCol
= GetColumnCount();
2176 for ( size_t col
= 0; col
< countCol
; col
++ )
2178 ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
));
2181 ld
->SetImage(listctrl
->OnGetItemImage(line
));
2182 ld
->SetAttr(listctrl
->OnGetItemAttr(line
));
2185 wxListLineData
*wxListMainWindow::GetDummyLine() const
2187 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2189 if ( m_lines
.IsEmpty() )
2191 // normal controls are supposed to have something in m_lines
2192 // already if it's not empty
2193 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2195 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2196 wxListLineData
*line
= new wxListLineData(self
);
2197 self
->m_lines
.Add(line
);
2203 // ----------------------------------------------------------------------------
2204 // line geometry (report mode only)
2205 // ----------------------------------------------------------------------------
2207 wxCoord
wxListMainWindow::GetLineHeight() const
2209 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2211 // we cache the line height as calling GetTextExtent() is slow
2212 if ( !m_lineHeight
)
2214 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2216 wxClientDC
dc( self
);
2217 dc
.SetFont( GetFont() );
2220 dc
.GetTextExtent(_T("H"), NULL
, &y
);
2222 if ( y
< SCROLL_UNIT_Y
)
2226 self
->m_lineHeight
= y
+ LINE_SPACING
;
2229 return m_lineHeight
;
2232 wxCoord
wxListMainWindow::GetLineY(size_t line
) const
2234 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2236 return LINE_SPACING
+ line
*GetLineHeight();
2239 wxRect
wxListMainWindow::GetLineRect(size_t line
) const
2241 if ( !InReportView() )
2242 return GetLine(line
)->m_gi
->m_rectAll
;
2245 rect
.x
= HEADER_OFFSET_X
;
2246 rect
.y
= GetLineY(line
);
2247 rect
.width
= GetHeaderWidth();
2248 rect
.height
= GetLineHeight();
2253 wxRect
wxListMainWindow::GetLineLabelRect(size_t line
) const
2255 if ( !InReportView() )
2256 return GetLine(line
)->m_gi
->m_rectLabel
;
2259 rect
.x
= HEADER_OFFSET_X
;
2260 rect
.y
= GetLineY(line
);
2261 rect
.width
= GetColumnWidth(0);
2262 rect
.height
= GetLineHeight();
2267 wxRect
wxListMainWindow::GetLineIconRect(size_t line
) const
2269 if ( !InReportView() )
2270 return GetLine(line
)->m_gi
->m_rectIcon
;
2272 wxListLineData
*ld
= GetLine(line
);
2273 wxASSERT_MSG( ld
->HasImage(), _T("should have an image") );
2276 rect
.x
= HEADER_OFFSET_X
;
2277 rect
.y
= GetLineY(line
);
2278 GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
);
2283 wxRect
wxListMainWindow::GetLineHighlightRect(size_t line
) const
2285 return InReportView() ? GetLineRect(line
)
2286 : GetLine(line
)->m_gi
->m_rectHighlight
;
2289 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const
2291 wxListLineData
*ld
= GetLine(line
);
2293 if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) )
2294 return wxLIST_HITTEST_ONITEMICON
;
2296 if ( ld
->HasText() )
2298 wxRect rect
= InReportView() ? GetLineRect(line
)
2299 : GetLineLabelRect(line
);
2301 if ( rect
.Inside(x
, y
) )
2302 return wxLIST_HITTEST_ONITEMLABEL
;
2308 // ----------------------------------------------------------------------------
2309 // highlight (selection) handling
2310 // ----------------------------------------------------------------------------
2312 bool wxListMainWindow::IsHighlighted(size_t line
) const
2316 return m_selStore
.IsSelected(line
);
2320 wxListLineData
*ld
= GetLine(line
);
2321 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2323 return ld
->IsHighlighted();
2327 void wxListMainWindow::HighlightLines( size_t lineFrom
, size_t lineTo
, bool highlight
)
2331 m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
);
2332 RefreshLines(lineFrom
, lineTo
);
2336 // do it the dumb way
2337 bool needsRefresh
= FALSE
;
2338 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2340 if ( HighlightLine(line
, highlight
) )
2341 needsRefresh
= TRUE
;
2345 RefreshLines(lineFrom
, lineTo
);
2349 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight
)
2355 changed
= m_selStore
.SelectItem(line
, highlight
);
2359 wxListLineData
*ld
= GetLine(line
);
2360 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2362 changed
= ld
->Highlight(highlight
);
2367 SendNotify( line
, highlight
? wxEVT_COMMAND_LIST_ITEM_SELECTED
2368 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
);
2374 void wxListMainWindow::RefreshLine( size_t line
)
2376 wxRect rect
= GetLineRect(line
);
2378 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2379 RefreshRect( rect
);
2382 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo
)
2384 // we suppose that they are ordered by caller
2385 wxASSERT_MSG( lineFrom
<= lineTo
, _T("indices in disorder") );
2387 wxASSERT_MSG( lineTo
< GetItemCount(), _T("invalid line range") );
2389 if ( HasFlag(wxLC_REPORT
) )
2391 size_t visibleFrom
, visibleTo
;
2392 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2394 if ( lineFrom
< visibleFrom
)
2395 lineFrom
= visibleFrom
;
2396 if ( lineTo
> visibleTo
)
2401 rect
.y
= GetLineY(lineFrom
);
2402 rect
.width
= GetClientSize().x
;
2403 rect
.height
= GetLineY(lineTo
) - rect
.y
;
2405 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2406 RefreshRect( rect
);
2410 // TODO: this should be optimized...
2411 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2418 void wxListMainWindow::RefreshAfter( size_t lineFrom
)
2420 if ( HasFlag(wxLC_REPORT
) )
2423 GetVisibleLinesRange(&visibleFrom
, NULL
);
2425 if ( lineFrom
< visibleFrom
)
2426 lineFrom
= visibleFrom
;
2430 rect
.y
= GetLineY(lineFrom
);
2432 wxSize size
= GetClientSize();
2433 rect
.width
= size
.x
;
2434 // refresh till the bottom of the window
2435 rect
.height
= size
.y
- rect
.y
;
2437 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2438 RefreshRect( rect
);
2442 // TODO: how to do it more efficiently?
2447 void wxListMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2449 // Note: a wxPaintDC must be constructed even if no drawing is
2450 // done (a Windows requirement).
2451 wxPaintDC
dc( this );
2455 // empty control. nothing to draw
2461 // delay the repainting until we calculate all the items positions
2468 CalcScrolledPosition( 0, 0, &dev_x
, &dev_y
);
2472 dc
.SetFont( GetFont() );
2474 if ( HasFlag(wxLC_REPORT
) )
2476 int lineHeight
= GetLineHeight();
2478 size_t visibleFrom
, visibleTo
;
2479 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2482 wxCoord xOrig
, yOrig
;
2483 CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
);
2485 for ( size_t line
= visibleFrom
; line
<= visibleTo
; line
++ )
2487 rectLine
= GetLineRect(line
);
2489 if ( !IsExposed(rectLine
.x
- xOrig
, rectLine
.y
- yOrig
,
2490 rectLine
.width
, rectLine
.height
) )
2492 // don't redraw unaffected lines to avoid flicker
2496 GetLine(line
)->DrawInReportMode( &dc
,
2498 GetLineHighlightRect(line
),
2499 IsHighlighted(line
) );
2502 if ( HasFlag(wxLC_HRULES
) )
2504 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2505 wxSize clientSize
= GetClientSize();
2507 for ( size_t i
= visibleFrom
; i
<= visibleTo
; i
++ )
2510 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2511 dc
.DrawLine(0 - dev_x
, i
*lineHeight
,
2512 clientSize
.x
- dev_x
, i
*lineHeight
);
2515 // Draw last horizontal rule
2516 if ( visibleTo
> visibleFrom
)
2519 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2520 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
,
2521 clientSize
.x
- dev_x
, m_lineTo
*lineHeight
);
2525 // Draw vertical rules if required
2526 if ( HasFlag(wxLC_VRULES
) && !IsEmpty() )
2528 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2531 wxRect firstItemRect
;
2532 wxRect lastItemRect
;
2533 GetItemRect(0, firstItemRect
);
2534 GetItemRect(GetItemCount() - 1, lastItemRect
);
2535 int x
= firstItemRect
.GetX();
2537 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2538 for (col
= 0; col
< GetColumnCount(); col
++)
2540 int colWidth
= GetColumnWidth(col
);
2542 dc
.DrawLine(x
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
,
2543 x
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
);
2549 size_t count
= GetItemCount();
2550 for ( size_t i
= 0; i
< count
; i
++ )
2552 GetLine(i
)->Draw( &dc
);
2556 if ( HasCurrent() && m_hasFocus
)
2559 // no rect outline, we already have the background color
2561 dc
.SetPen( *wxBLACK_PEN
);
2562 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2563 dc
.DrawRectangle( GetLineHighlightRect(m_current
) );
2570 void wxListMainWindow::HighlightAll( bool on
)
2572 if ( IsSingleSel() )
2574 wxASSERT_MSG( !on
, _T("can't do this in a single sel control") );
2576 // we just have one item to turn off
2577 if ( HasCurrent() && IsHighlighted(m_current
) )
2579 HighlightLine(m_current
, FALSE
);
2580 RefreshLine(m_current
);
2585 HighlightLines(0, GetItemCount() - 1, on
);
2589 void wxListMainWindow::SendNotify( size_t line
,
2590 wxEventType command
,
2593 wxListEvent
le( command
, GetParent()->GetId() );
2594 le
.SetEventObject( GetParent() );
2595 le
.m_itemIndex
= line
;
2597 // set only for events which have position
2598 if ( point
!= wxDefaultPosition
)
2599 le
.m_pointDrag
= point
;
2601 GetLine(line
)->GetItem( 0, le
.m_item
);
2602 GetParent()->GetEventHandler()->ProcessEvent( le
);
2605 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) )
2607 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
2610 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) )
2612 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
2615 void wxListMainWindow::EditLabel( long item
)
2617 wxCHECK_RET( (item
>= 0) && ((size_t)item
< GetItemCount()),
2618 wxT("wrong index in wxListCtrl::EditLabel()") );
2620 m_currentEdit
= (size_t)item
;
2622 wxListEvent
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() );
2623 le
.SetEventObject( GetParent() );
2624 le
.m_itemIndex
= item
;
2625 wxListLineData
*data
= GetLine(m_currentEdit
);
2626 wxCHECK_RET( data
, _T("invalid index in EditLabel()") );
2627 data
->GetItem( 0, le
.m_item
);
2628 GetParent()->GetEventHandler()->ProcessEvent( le
);
2630 if (!le
.IsAllowed())
2633 // We have to call this here because the label in question might just have
2634 // been added and no screen update taken place.
2638 wxClientDC
dc(this);
2641 wxString s
= data
->GetText(0);
2642 wxRect rectLabel
= GetLineLabelRect(m_currentEdit
);
2644 rectLabel
.x
= dc
.LogicalToDeviceX( rectLabel
.x
);
2645 rectLabel
.y
= dc
.LogicalToDeviceY( rectLabel
.y
);
2647 wxListTextCtrl
*text
= new wxListTextCtrl
2654 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4),
2655 wxSize(rectLabel
.width
+11,rectLabel
.height
+8)
2660 void wxListMainWindow::OnRenameTimer()
2662 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2664 EditLabel( m_current
);
2667 void wxListMainWindow::OnRenameAccept()
2669 wxListEvent
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() );
2670 le
.SetEventObject( GetParent() );
2671 le
.m_itemIndex
= m_currentEdit
;
2673 wxListLineData
*data
= GetLine(m_currentEdit
);
2674 wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") );
2676 data
->GetItem( 0, le
.m_item
);
2677 le
.m_item
.m_text
= m_renameRes
;
2678 GetParent()->GetEventHandler()->ProcessEvent( le
);
2680 if (!le
.IsAllowed()) return;
2683 info
.m_mask
= wxLIST_MASK_TEXT
;
2684 info
.m_itemId
= le
.m_itemIndex
;
2685 info
.m_text
= m_renameRes
;
2686 info
.SetTextColour(le
.m_item
.GetTextColour());
2690 void wxListMainWindow::OnMouse( wxMouseEvent
&event
)
2692 event
.SetEventObject( GetParent() );
2693 if ( GetParent()->GetEventHandler()->ProcessEvent( event
) )
2696 if ( !HasCurrent() || IsEmpty() )
2702 if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() ||
2703 event
.ButtonDClick()) )
2706 int x
= event
.GetX();
2707 int y
= event
.GetY();
2708 CalcUnscrolledPosition( x
, y
, &x
, &y
);
2710 // where did we hit it (if we did)?
2713 size_t count
= GetItemCount(),
2716 if ( HasFlag(wxLC_REPORT
) )
2718 current
= y
/ GetLineHeight();
2719 if ( current
< count
)
2720 hitResult
= HitTestLine(current
, x
, y
);
2724 // TODO: optimize it too! this is less simple than for report view but
2725 // enumerating all items is still not a way to do it!!
2726 for ( current
= 0; current
< count
; current
++ )
2728 hitResult
= HitTestLine(current
, x
, y
);
2734 if (event
.Dragging())
2736 if (m_dragCount
== 0)
2737 m_dragStart
= wxPoint(x
,y
);
2741 if (m_dragCount
!= 3)
2744 int command
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2745 : wxEVT_COMMAND_LIST_BEGIN_DRAG
;
2747 wxListEvent
le( command
, GetParent()->GetId() );
2748 le
.SetEventObject( GetParent() );
2749 le
.m_pointDrag
= m_dragStart
;
2750 GetParent()->GetEventHandler()->ProcessEvent( le
);
2761 // outside of any item
2765 bool forceClick
= FALSE
;
2766 if (event
.ButtonDClick())
2768 m_renameTimer
->Stop();
2769 m_lastOnSame
= FALSE
;
2771 if ( current
== m_lineBeforeLastClicked
)
2773 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED
);
2779 // the first click was on another item, so don't interpret this as
2780 // a double click, but as a simple click instead
2785 if (event
.LeftUp() && m_lastOnSame
)
2787 if ((current
== m_current
) &&
2788 (hitResult
== wxLIST_HITTEST_ONITEMLABEL
) &&
2789 HasFlag(wxLC_EDIT_LABELS
) )
2791 m_renameTimer
->Start( 100, TRUE
);
2793 m_lastOnSame
= FALSE
;
2795 else if (event
.RightDown())
2797 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
,
2798 event
.GetPosition() );
2800 else if (event
.MiddleDown())
2802 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
);
2804 else if ( event
.LeftDown() || forceClick
)
2806 m_lineBeforeLastClicked
= m_lineLastClicked
;
2807 m_lineLastClicked
= current
;
2809 size_t oldCurrent
= m_current
;
2811 if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) )
2813 HighlightAll( FALSE
);
2814 m_current
= current
;
2816 ReverseHighlight(m_current
);
2818 else // multi sel & either ctrl or shift is down
2820 if (event
.ControlDown())
2822 m_current
= current
;
2824 ReverseHighlight(m_current
);
2826 else if (event
.ShiftDown())
2828 m_current
= current
;
2830 size_t lineFrom
= oldCurrent
,
2833 if ( lineTo
< lineFrom
)
2836 lineFrom
= m_current
;
2839 HighlightLines(lineFrom
, lineTo
);
2841 else // !ctrl, !shift
2843 // test in the enclosing if should make it impossible
2844 wxFAIL_MSG( _T("how did we get here?") );
2848 if (m_current
!= oldCurrent
)
2850 RefreshLine( oldCurrent
);
2851 OnUnfocusLine( oldCurrent
);
2852 OnFocusLine( m_current
);
2855 // forceClick is only set if the previous click was on another item
2856 m_lastOnSame
= !forceClick
&& (m_current
== oldCurrent
);
2860 void wxListMainWindow::MoveToFocus()
2862 if ( !HasCurrent() )
2865 wxRect rect
= GetLineRect(m_current
);
2867 int client_w
, client_h
;
2868 GetClientSize( &client_w
, &client_h
);
2870 int view_x
= m_xScroll
*GetScrollPos( wxHORIZONTAL
);
2871 int view_y
= m_yScroll
*GetScrollPos( wxVERTICAL
);
2873 if ( HasFlag(wxLC_REPORT
) )
2875 // the next we need the range of lines shown it might be different, so
2877 ResetVisibleLinesRange();
2879 if (rect
.y
< view_y
)
2880 Scroll( -1, rect
.y
/m_yScroll
);
2881 if (rect
.y
+rect
.height
+5 > view_y
+client_h
)
2882 Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll
);
2886 if (rect
.x
-view_x
< 5)
2887 Scroll( (rect
.x
-5)/m_xScroll
, -1 );
2888 if (rect
.x
+rect
.width
-5 > view_x
+client_w
)
2889 Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 );
2893 // ----------------------------------------------------------------------------
2894 // keyboard handling
2895 // ----------------------------------------------------------------------------
2897 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
2899 wxCHECK_RET( newCurrent
< (size_t)GetItemCount(),
2900 _T("invalid item index in OnArrowChar()") );
2902 size_t oldCurrent
= m_current
;
2904 // in single selection we just ignore Shift as we can't select several
2906 if ( event
.ShiftDown() && !IsSingleSel() )
2908 m_current
= newCurrent
;
2910 // select all the items between the old and the new one
2911 if ( oldCurrent
> newCurrent
)
2913 newCurrent
= oldCurrent
;
2914 oldCurrent
= m_current
;
2917 HighlightLines(oldCurrent
, newCurrent
);
2921 // all previously selected items are unselected unless ctrl is held
2922 if ( !event
.ControlDown() )
2923 HighlightAll(FALSE
);
2925 m_current
= newCurrent
;
2927 HighlightLine( oldCurrent
, FALSE
);
2928 RefreshLine( oldCurrent
);
2930 if ( !event
.ControlDown() )
2932 HighlightLine( m_current
, TRUE
);
2936 OnUnfocusLine( oldCurrent
);
2937 OnFocusLine( m_current
);
2938 RefreshLine( m_current
);
2943 void wxListMainWindow::OnKeyDown( wxKeyEvent
&event
)
2945 wxWindow
*parent
= GetParent();
2947 /* we propagate the key event up */
2948 wxKeyEvent
ke( wxEVT_KEY_DOWN
);
2949 ke
.m_shiftDown
= event
.m_shiftDown
;
2950 ke
.m_controlDown
= event
.m_controlDown
;
2951 ke
.m_altDown
= event
.m_altDown
;
2952 ke
.m_metaDown
= event
.m_metaDown
;
2953 ke
.m_keyCode
= event
.m_keyCode
;
2956 ke
.SetEventObject( parent
);
2957 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2962 void wxListMainWindow::OnChar( wxKeyEvent
&event
)
2964 wxWindow
*parent
= GetParent();
2966 /* we send a list_key event up */
2969 wxListEvent
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() );
2970 le
.m_itemIndex
= m_current
;
2971 GetLine(m_current
)->GetItem( 0, le
.m_item
);
2972 le
.m_code
= (int)event
.KeyCode();
2973 le
.SetEventObject( parent
);
2974 parent
->GetEventHandler()->ProcessEvent( le
);
2977 /* we propagate the char event up */
2978 wxKeyEvent
ke( wxEVT_CHAR
);
2979 ke
.m_shiftDown
= event
.m_shiftDown
;
2980 ke
.m_controlDown
= event
.m_controlDown
;
2981 ke
.m_altDown
= event
.m_altDown
;
2982 ke
.m_metaDown
= event
.m_metaDown
;
2983 ke
.m_keyCode
= event
.m_keyCode
;
2986 ke
.SetEventObject( parent
);
2987 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2989 if (event
.KeyCode() == WXK_TAB
)
2991 wxNavigationKeyEvent nevent
;
2992 nevent
.SetWindowChange( event
.ControlDown() );
2993 nevent
.SetDirection( !event
.ShiftDown() );
2994 nevent
.SetEventObject( GetParent()->GetParent() );
2995 nevent
.SetCurrentFocus( m_parent
);
2996 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
)) return;
2999 /* no item -> nothing to do */
3006 switch (event
.KeyCode())
3009 if ( m_current
> 0 )
3010 OnArrowChar( m_current
- 1, event
);
3014 if ( m_current
< (size_t)GetItemCount() - 1 )
3015 OnArrowChar( m_current
+ 1, event
);
3020 OnArrowChar( GetItemCount() - 1, event
);
3025 OnArrowChar( 0, event
);
3031 if ( HasFlag(wxLC_REPORT
) )
3033 steps
= m_linesPerPage
- 1;
3037 steps
= m_current
% m_linesPerPage
;
3040 int index
= m_current
- steps
;
3044 OnArrowChar( index
, event
);
3051 if ( HasFlag(wxLC_REPORT
) )
3053 steps
= m_linesPerPage
- 1;
3057 steps
= m_linesPerPage
- (m_current
% m_linesPerPage
) - 1;
3060 size_t index
= m_current
+ steps
;
3061 size_t count
= GetItemCount();
3062 if ( index
>= count
)
3065 OnArrowChar( index
, event
);
3070 if ( !HasFlag(wxLC_REPORT
) )
3072 int index
= m_current
- m_linesPerPage
;
3076 OnArrowChar( index
, event
);
3081 if ( !HasFlag(wxLC_REPORT
) )
3083 size_t index
= m_current
+ m_linesPerPage
;
3085 size_t count
= GetItemCount();
3086 if ( index
>= count
)
3089 OnArrowChar( index
, event
);
3094 if ( IsSingleSel() )
3096 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3097 GetParent()->GetId() );
3098 le
.SetEventObject( GetParent() );
3099 le
.m_itemIndex
= m_current
;
3100 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3101 GetParent()->GetEventHandler()->ProcessEvent( le
);
3105 ReverseHighlight(m_current
);
3112 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3113 GetParent()->GetId() );
3114 le
.SetEventObject( GetParent() );
3115 le
.m_itemIndex
= m_current
;
3116 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3117 GetParent()->GetEventHandler()->ProcessEvent( le
);
3126 // ----------------------------------------------------------------------------
3128 // ----------------------------------------------------------------------------
3131 extern wxWindow
*g_focusWindow
;
3134 void wxListMainWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
3139 RefreshLine( m_current
);
3145 g_focusWindow
= GetParent();
3148 wxFocusEvent
event( wxEVT_SET_FOCUS
, GetParent()->GetId() );
3149 event
.SetEventObject( GetParent() );
3150 GetParent()->GetEventHandler()->ProcessEvent( event
);
3153 void wxListMainWindow::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
3158 RefreshLine( m_current
);
3161 void wxListMainWindow::DrawImage( int index
, wxDC
*dc
, int x
, int y
)
3163 if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
))
3165 m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3167 else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
))
3169 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3171 else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
))
3173 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3175 else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
))
3177 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3181 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height
) const
3183 if ( HasFlag(wxLC_ICON
) && m_normal_image_list
)
3185 m_normal_image_list
->GetSize( index
, width
, height
);
3187 else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list
)
3189 m_small_image_list
->GetSize( index
, width
, height
);
3191 else if ( HasFlag(wxLC_LIST
) && m_small_image_list
)
3193 m_small_image_list
->GetSize( index
, width
, height
);
3195 else if ( HasFlag(wxLC_REPORT
) && m_small_image_list
)
3197 m_small_image_list
->GetSize( index
, width
, height
);
3206 int wxListMainWindow::GetTextLength( const wxString
&s
) const
3208 wxClientDC
dc( wxConstCast(this, wxListMainWindow
) );
3209 dc
.SetFont( GetFont() );
3212 dc
.GetTextExtent( s
, &lw
, NULL
);
3214 return lw
+ AUTOSIZE_COL_MARGIN
;
3217 void wxListMainWindow::SetImageList( wxImageList
*imageList
, int which
)
3221 // calc the spacing from the icon size
3224 if ((imageList
) && (imageList
->GetImageCount()) )
3226 imageList
->GetSize(0, width
, height
);
3229 if (which
== wxIMAGE_LIST_NORMAL
)
3231 m_normal_image_list
= imageList
;
3232 m_normal_spacing
= width
+ 8;
3235 if (which
== wxIMAGE_LIST_SMALL
)
3237 m_small_image_list
= imageList
;
3238 m_small_spacing
= width
+ 14;
3242 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall
)
3247 m_small_spacing
= spacing
;
3251 m_normal_spacing
= spacing
;
3255 int wxListMainWindow::GetItemSpacing( bool isSmall
)
3257 return isSmall
? m_small_spacing
: m_normal_spacing
;
3260 // ----------------------------------------------------------------------------
3262 // ----------------------------------------------------------------------------
3264 void wxListMainWindow::SetColumn( int col
, wxListItem
&item
)
3266 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3268 wxCHECK_RET( node
, _T("invalid column index in SetColumn") );
3270 if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3271 item
.m_width
= GetTextLength( item
.m_text
);
3273 wxListHeaderData
*column
= node
->GetData();
3274 column
->SetItem( item
);
3276 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3278 headerWin
->m_dirty
= TRUE
;
3282 // invalidate it as it has to be recalculated
3286 void wxListMainWindow::SetColumnWidth( int col
, int width
)
3288 wxCHECK_RET( col
>= 0 && col
< GetColumnCount(),
3289 _T("invalid column index") );
3291 wxCHECK_RET( HasFlag(wxLC_REPORT
),
3292 _T("SetColumnWidth() can only be called in report mode.") );
3296 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3297 wxCHECK_RET( node
, _T("no column?") );
3299 wxListHeaderData
*column
= node
->GetData();
3301 size_t count
= GetItemCount();
3303 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
3305 width
= GetTextLength(column
->GetText());
3307 else if ( width
== wxLIST_AUTOSIZE
)
3311 // TODO: determine the max width somehow...
3312 width
= WIDTH_COL_DEFAULT
;
3316 wxClientDC
dc(this);
3317 dc
.SetFont( GetFont() );
3319 int max
= AUTOSIZE_COL_MARGIN
;
3321 for ( size_t i
= 0; i
< count
; i
++ )
3323 wxListLineData
*line
= GetLine(i
);
3324 wxListItemDataList::Node
*n
= line
->m_items
.Item( col
);
3326 wxCHECK_RET( n
, _T("no subitem?") );
3328 wxListItemData
*item
= n
->GetData();
3331 if (item
->HasImage())
3334 GetImageSize( item
->GetImage(), ix
, iy
);
3338 if (item
->HasText())
3341 dc
.GetTextExtent( item
->GetText(), &w
, NULL
);
3349 width
= max
+ AUTOSIZE_COL_MARGIN
;
3353 column
->SetWidth( width
);
3355 // invalidate it as it has to be recalculated
3359 int wxListMainWindow::GetHeaderWidth() const
3361 if ( !m_headerWidth
)
3363 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
3365 size_t count
= GetColumnCount();
3366 for ( size_t col
= 0; col
< count
; col
++ )
3368 self
->m_headerWidth
+= GetColumnWidth(col
);
3372 return m_headerWidth
;
3375 void wxListMainWindow::GetColumn( int col
, wxListItem
&item
) const
3377 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3378 wxCHECK_RET( node
, _T("invalid column index in GetColumn") );
3380 wxListHeaderData
*column
= node
->GetData();
3381 column
->GetItem( item
);
3384 int wxListMainWindow::GetColumnWidth( int col
) const
3386 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3387 wxCHECK_MSG( node
, 0, _T("invalid column index") );
3389 wxListHeaderData
*column
= node
->GetData();
3390 return column
->GetWidth();
3393 // ----------------------------------------------------------------------------
3395 // ----------------------------------------------------------------------------
3397 void wxListMainWindow::SetItem( wxListItem
&item
)
3399 long id
= item
.m_itemId
;
3400 wxCHECK_RET( id
>= 0 && (size_t)id
< GetItemCount(),
3401 _T("invalid item index in SetItem") );
3405 wxListLineData
*line
= GetLine((size_t)id
);
3406 line
->SetItem( item
.m_col
, item
);
3409 if ( InReportView() )
3411 // just refresh the line to show the new value of the text/image
3412 RefreshLine((size_t)id
);
3416 // refresh everything (resulting in horrible flicker - FIXME!)
3421 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask
)
3423 wxCHECK_RET( litem
>= 0 && (size_t)litem
< GetItemCount(),
3424 _T("invalid list ctrl item index in SetItem") );
3426 size_t oldCurrent
= m_current
;
3427 size_t item
= (size_t)litem
; // sdafe because of the check above
3429 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3431 if ( state
& wxLIST_STATE_FOCUSED
)
3433 // don't do anything if this item is already focused
3434 if ( item
!= m_current
)
3436 OnUnfocusLine( m_current
);
3438 OnFocusLine( m_current
);
3440 if ( IsSingleSel() && (oldCurrent
!= (size_t)-1) )
3442 HighlightLine(oldCurrent
, FALSE
);
3443 RefreshLine(oldCurrent
);
3446 RefreshLine( m_current
);
3451 // don't do anything if this item is not focused
3452 if ( item
== m_current
)
3454 OnUnfocusLine( m_current
);
3455 m_current
= (size_t)-1;
3460 if ( stateMask
& wxLIST_STATE_SELECTED
)
3462 bool on
= (state
& wxLIST_STATE_SELECTED
) != 0;
3464 if ( IsSingleSel() )
3468 // selecting the item also makes it the focused one in the
3470 if ( m_current
!= item
)
3472 OnUnfocusLine( m_current
);
3474 OnFocusLine( m_current
);
3476 if ( oldCurrent
!= (size_t)-1 )
3478 HighlightLine( oldCurrent
, FALSE
);
3479 RefreshLine( oldCurrent
);
3485 // only the current item may be selected anyhow
3486 if ( item
!= m_current
)
3491 if ( HighlightLine(item
, on
) )
3498 int wxListMainWindow::GetItemState( long item
, long stateMask
)
3500 wxCHECK_MSG( item
>= 0 && (size_t)item
< GetItemCount(), 0,
3501 _T("invalid list ctrl item index in GetItemState()") );
3503 int ret
= wxLIST_STATE_DONTCARE
;
3505 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3507 if ( (size_t)item
== m_current
)
3508 ret
|= wxLIST_STATE_FOCUSED
;
3511 if ( stateMask
& wxLIST_STATE_SELECTED
)
3513 if ( IsHighlighted(item
) )
3514 ret
|= wxLIST_STATE_SELECTED
;
3520 void wxListMainWindow::GetItem( wxListItem
&item
)
3522 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
< GetItemCount(),
3523 _T("invalid item index in GetItem") );
3525 wxListLineData
*line
= GetLine((size_t)item
.m_itemId
);
3526 line
->GetItem( item
.m_col
, item
);
3529 // ----------------------------------------------------------------------------
3531 // ----------------------------------------------------------------------------
3533 size_t wxListMainWindow::GetItemCount() const
3535 return IsVirtual() ? m_countVirt
: m_lines
.GetCount();
3538 void wxListMainWindow::SetItemCount(long count
)
3540 m_selStore
.SetItemCount(count
);
3541 m_countVirt
= count
;
3543 ResetVisibleLinesRange();
3548 int wxListMainWindow::GetSelectedItemCount()
3550 // deal with the quick case first
3551 if ( IsSingleSel() )
3553 return HasCurrent() ? IsHighlighted(m_current
) : FALSE
;
3556 // virtual controls remmebers all its selections itself
3558 return m_selStore
.GetSelectedCount();
3560 // TODO: we probably should maintain the number of items selected even for
3561 // non virtual controls as enumerating all lines is really slow...
3562 size_t countSel
= 0;
3563 size_t count
= GetItemCount();
3564 for ( size_t line
= 0; line
< count
; line
++ )
3566 if ( GetLine(line
)->IsHighlighted() )
3573 // ----------------------------------------------------------------------------
3574 // item position/size
3575 // ----------------------------------------------------------------------------
3577 void wxListMainWindow::GetItemRect( long index
, wxRect
&rect
)
3579 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3580 _T("invalid index in GetItemRect") );
3582 rect
= GetLineRect((size_t)index
);
3584 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
3587 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
)
3590 GetItemRect(item
, rect
);
3598 // ----------------------------------------------------------------------------
3599 // geometry calculation
3600 // ----------------------------------------------------------------------------
3602 void wxListMainWindow::RecalculatePositions()
3607 wxClientDC
dc( this );
3608 dc
.SetFont( GetFont() );
3611 if ( HasFlag(wxLC_ICON
) )
3612 iconSpacing
= m_normal_spacing
;
3613 else if ( HasFlag(wxLC_SMALL_ICON
) )
3614 iconSpacing
= m_small_spacing
;
3620 GetClientSize( &clientWidth
, &clientHeight
);
3622 if ( HasFlag(wxLC_REPORT
) )
3624 // all lines have the same height
3625 int lineHeight
= GetLineHeight();
3627 // scroll one line per step
3628 m_yScroll
= lineHeight
;
3630 size_t lineCount
= GetItemCount();
3631 int entireHeight
= lineCount
*lineHeight
+ LINE_SPACING
;
3633 m_linesPerPage
= clientHeight
/ lineHeight
;
3635 ResetVisibleLinesRange();
3637 SetScrollbars( m_xScroll
, m_yScroll
,
3638 (GetHeaderWidth() + m_xScroll
- 1)/m_xScroll
,
3639 (entireHeight
+ m_yScroll
- 1)/m_yScroll
,
3640 GetScrollPos(wxHORIZONTAL
),
3641 GetScrollPos(wxVERTICAL
),
3646 // at first we try without any scrollbar. if the items don't
3647 // fit into the window, we recalculate after subtracting an
3648 // approximated 15 pt for the horizontal scrollbar
3650 clientHeight
-= 4; // sunken frame
3652 int entireWidth
= 0;
3654 for (int tries
= 0; tries
< 2; tries
++)
3661 int currentlyVisibleLines
= 0;
3663 size_t count
= GetItemCount();
3664 for (size_t i
= 0; i
< count
; i
++)
3666 currentlyVisibleLines
++;
3667 wxListLineData
*line
= GetLine(i
);
3668 line
->CalculateSize( &dc
, iconSpacing
);
3669 line
->SetPosition( x
, y
, clientWidth
, iconSpacing
);
3671 wxSize sizeLine
= GetLineSize(i
);
3673 if ( maxWidth
< sizeLine
.x
)
3674 maxWidth
= sizeLine
.x
;
3677 if (currentlyVisibleLines
> m_linesPerPage
)
3678 m_linesPerPage
= currentlyVisibleLines
;
3680 // assume that the size of the next one is the same... (FIXME)
3681 if ( y
+ sizeLine
.y
- 6 >= clientHeight
)
3683 currentlyVisibleLines
= 0;
3686 entireWidth
+= maxWidth
+6;
3689 if ( i
== count
- 1 )
3690 entireWidth
+= maxWidth
;
3691 if ((tries
== 0) && (entireWidth
> clientWidth
))
3693 clientHeight
-= 15; // scrollbar height
3695 currentlyVisibleLines
= 0;
3698 if ( i
== count
- 1 )
3699 tries
= 1; // everything fits, no second try required
3703 int scroll_pos
= GetScrollPos( wxHORIZONTAL
);
3704 SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE
);
3707 // FIXME: why should we call it from here?
3713 void wxListMainWindow::RefreshAll()
3718 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3721 headerWin
->m_dirty
= FALSE
;
3722 headerWin
->Refresh();
3726 void wxListMainWindow::UpdateCurrent()
3728 if ( !HasCurrent() && !IsEmpty() )
3733 if ( m_current
!= (size_t)-1 )
3735 OnFocusLine( m_current
);
3739 long wxListMainWindow::GetNextItem( long item
,
3740 int WXUNUSED(geometry
),
3744 max
= GetItemCount();
3745 wxCHECK_MSG( (ret
== -1) || (ret
< max
), -1,
3746 _T("invalid listctrl index in GetNextItem()") );
3748 // notice that we start with the next item (or the first one if item == -1)
3749 // and this is intentional to allow writing a simple loop to iterate over
3750 // all selected items
3754 // this is not an error because the index was ok initially, just no
3765 size_t count
= GetItemCount();
3766 for ( size_t line
= (size_t)ret
; line
< count
; line
++ )
3768 if ( (state
& wxLIST_STATE_FOCUSED
) && (line
== m_current
) )
3771 if ( (state
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) )
3778 // ----------------------------------------------------------------------------
3780 // ----------------------------------------------------------------------------
3782 void wxListMainWindow::DeleteItem( long lindex
)
3784 size_t count
= GetItemCount();
3786 wxCHECK_RET( (lindex
>= 0) && ((size_t)lindex
< count
),
3787 _T("invalid item index in DeleteItem") );
3789 size_t index
= (size_t)lindex
;
3793 // select the next item when the selected one is deleted
3794 if ( m_current
== index
)
3796 // the last valid index after deleting the item will be count-2
3797 if ( m_current
== count
- 1 )
3803 SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
);
3805 if ( InReportView() )
3807 ResetVisibleLinesRange();
3814 m_selStore
.OnItemDelete(index
);
3818 m_lines
.RemoveAt( index
);
3822 RefreshAfter(index
);
3825 void wxListMainWindow::DeleteColumn( int col
)
3827 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3829 wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") );
3832 m_columns
.DeleteNode( node
);
3835 void wxListMainWindow::DeleteAllItems()
3839 // nothing to do - in particular, don't send the event
3845 // to make the deletion of all items faster, we don't send the
3846 // notifications for each item deletion in this case but only one event
3847 // for all of them: this is compatible with wxMSW and documented in
3848 // DeleteAllItems() description
3850 wxListEvent
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() );
3851 event
.SetEventObject( GetParent() );
3852 GetParent()->GetEventHandler()->ProcessEvent( event
);
3861 if ( InReportView() )
3863 ResetVisibleLinesRange();
3868 // NB: don't just set m_dirty to TRUE here as RecalculatePositions()
3869 // doesn't do anything if the control is empty and so we won't be
3874 void wxListMainWindow::DeleteEverything()
3881 // ----------------------------------------------------------------------------
3882 // scanning for an item
3883 // ----------------------------------------------------------------------------
3885 void wxListMainWindow::EnsureVisible( long index
)
3887 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3888 _T("invalid index in EnsureVisible") );
3890 // We have to call this here because the label in question might just have
3891 // been added and no screen update taken place.
3895 size_t oldCurrent
= m_current
;
3896 m_current
= (size_t)index
;
3898 m_current
= oldCurrent
;
3901 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) )
3908 size_t count
= GetItemCount();
3909 for ( size_t i
= (size_t)pos
; i
< count
; i
++ )
3911 wxListLineData
*line
= GetLine(i
);
3912 if ( line
->GetText(0) == tmp
)
3919 long wxListMainWindow::FindItem(long start
, long data
)
3925 size_t count
= GetItemCount();
3926 for (size_t i
= (size_t)pos
; i
< count
; i
++)
3928 wxListLineData
*line
= GetLine(i
);
3930 line
->GetItem( 0, item
);
3931 if (item
.m_data
== data
)
3938 long wxListMainWindow::HitTest( int x
, int y
, int &flags
)
3940 CalcUnscrolledPosition( x
, y
, &x
, &y
);
3942 if ( HasFlag(wxLC_REPORT
) )
3944 size_t current
= y
/ GetLineHeight();
3945 flags
= HitTestLine(current
, x
, y
);
3951 // TODO: optimize it too! this is less simple than for report view but
3952 // enumerating all items is still not a way to do it!!
3953 size_t count
= GetItemCount();
3954 for ( size_t current
= 0; current
< count
; current
++ )
3956 flags
= HitTestLine(current
, x
, y
);
3965 // ----------------------------------------------------------------------------
3967 // ----------------------------------------------------------------------------
3969 void wxListMainWindow::InsertItem( wxListItem
&item
)
3971 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
3973 size_t count
= GetItemCount();
3974 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
<= count
,
3975 _T("invalid item index") );
3977 size_t id
= item
.m_itemId
;
3982 if ( HasFlag(wxLC_REPORT
) )
3984 else if ( HasFlag(wxLC_LIST
) )
3986 else if ( HasFlag(wxLC_ICON
) )
3988 else if ( HasFlag(wxLC_SMALL_ICON
) )
3989 mode
= wxLC_ICON
; // no typo
3992 wxFAIL_MSG( _T("unknown mode") );
3995 wxListLineData
*line
= new wxListLineData(this);
3997 line
->SetItem( 0, item
);
3999 m_lines
.Insert( line
, id
);
4002 RefreshLines(id
, GetItemCount() - 1);
4005 void wxListMainWindow::InsertColumn( long col
, wxListItem
&item
)
4008 if ( HasFlag(wxLC_REPORT
) )
4010 if (item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
4011 item
.m_width
= GetTextLength( item
.m_text
);
4012 wxListHeaderData
*column
= new wxListHeaderData( item
);
4013 if ((col
>= 0) && (col
< (int)m_columns
.GetCount()))
4015 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
4016 m_columns
.Insert( node
, column
);
4020 m_columns
.Append( column
);
4025 // ----------------------------------------------------------------------------
4027 // ----------------------------------------------------------------------------
4029 wxListCtrlCompare list_ctrl_compare_func_2
;
4030 long list_ctrl_compare_data
;
4032 int LINKAGEMODE
list_ctrl_compare_func_1( wxListLineData
**arg1
, wxListLineData
**arg2
)
4034 wxListLineData
*line1
= *arg1
;
4035 wxListLineData
*line2
= *arg2
;
4037 line1
->GetItem( 0, item
);
4038 long data1
= item
.m_data
;
4039 line2
->GetItem( 0, item
);
4040 long data2
= item
.m_data
;
4041 return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data
);
4044 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data
)
4046 list_ctrl_compare_func_2
= fn
;
4047 list_ctrl_compare_data
= data
;
4048 m_lines
.Sort( list_ctrl_compare_func_1
);
4052 // ----------------------------------------------------------------------------
4054 // ----------------------------------------------------------------------------
4056 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
)
4058 // update our idea of which lines are shown when we redraw the window the
4060 ResetVisibleLinesRange();
4063 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4064 wxScrolledWindow::OnScroll(event
);
4066 HandleOnScroll( event
);
4069 if ( event
.GetOrientation() == wxHORIZONTAL
&& HasHeader() )
4071 wxListCtrl
* lc
= GetListCtrl();
4072 wxCHECK_RET( lc
, _T("no listctrl window?") );
4074 lc
->m_headerWin
->Refresh() ;
4076 lc
->m_headerWin
->MacUpdateImmediately() ;
4081 int wxListMainWindow::GetCountPerPage() const
4083 if ( !m_linesPerPage
)
4085 wxConstCast(this, wxListMainWindow
)->
4086 m_linesPerPage
= GetClientSize().y
/ GetLineHeight();
4089 return m_linesPerPage
;
4092 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
)
4094 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") );
4096 if ( m_lineFrom
== (size_t)-1 )
4098 size_t count
= GetItemCount();
4101 m_lineFrom
= GetScrollPos(wxVERTICAL
);
4103 // this may happen if SetScrollbars() hadn't been called yet
4104 if ( m_lineFrom
>= count
)
4105 m_lineFrom
= count
- 1;
4107 // we redraw one extra line but this is needed to make the redrawing
4108 // logic work when there is a fractional number of lines on screen
4109 m_lineTo
= m_lineFrom
+ m_linesPerPage
;
4110 if ( m_lineTo
>= count
)
4111 m_lineTo
= count
- 1;
4113 else // empty control
4116 m_lineTo
= (size_t)-1;
4120 wxASSERT_MSG( IsEmpty() ||
4121 (m_lineFrom
<= m_lineTo
&& m_lineTo
< GetItemCount()),
4122 _T("GetVisibleLinesRange() returns incorrect result") );
4130 // -------------------------------------------------------------------------------------
4132 // -------------------------------------------------------------------------------------
4134 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
4136 wxListItem::wxListItem()
4145 m_format
= wxLIST_FORMAT_CENTRE
;
4151 void wxListItem::Clear()
4160 m_format
= wxLIST_FORMAT_CENTRE
;
4167 void wxListItem::ClearAttributes()
4176 // -------------------------------------------------------------------------------------
4178 // -------------------------------------------------------------------------------------
4180 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
4182 wxListEvent::wxListEvent( wxEventType commandType
, int id
)
4183 : wxNotifyEvent( commandType
, id
)
4189 m_cancelled
= FALSE
;
4194 void wxListEvent::CopyObject(wxObject
& object_dest
) const
4196 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
4198 wxNotifyEvent::CopyObject(object_dest
);
4200 obj
->m_code
= m_code
;
4201 obj
->m_itemIndex
= m_itemIndex
;
4202 obj
->m_oldItemIndex
= m_oldItemIndex
;
4204 obj
->m_cancelled
= m_cancelled
;
4205 obj
->m_pointDrag
= m_pointDrag
;
4206 obj
->m_item
.m_mask
= m_item
.m_mask
;
4207 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
4208 obj
->m_item
.m_col
= m_item
.m_col
;
4209 obj
->m_item
.m_state
= m_item
.m_state
;
4210 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
4211 obj
->m_item
.m_text
= m_item
.m_text
;
4212 obj
->m_item
.m_image
= m_item
.m_image
;
4213 obj
->m_item
.m_data
= m_item
.m_data
;
4214 obj
->m_item
.m_format
= m_item
.m_format
;
4215 obj
->m_item
.m_width
= m_item
.m_width
;
4217 if ( m_item
.HasAttributes() )
4219 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
4223 // -------------------------------------------------------------------------------------
4225 // -------------------------------------------------------------------------------------
4227 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
4229 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
)
4230 EVT_SIZE(wxListCtrl::OnSize
)
4231 EVT_IDLE(wxListCtrl::OnIdle
)
4234 wxListCtrl::wxListCtrl()
4236 m_imageListNormal
= (wxImageList
*) NULL
;
4237 m_imageListSmall
= (wxImageList
*) NULL
;
4238 m_imageListState
= (wxImageList
*) NULL
;
4240 m_ownsImageListNormal
=
4241 m_ownsImageListSmall
=
4242 m_ownsImageListState
= FALSE
;
4244 m_mainWin
= (wxListMainWindow
*) NULL
;
4245 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4248 wxListCtrl::~wxListCtrl()
4251 m_mainWin
->ResetCurrent();
4253 if (m_ownsImageListNormal
)
4254 delete m_imageListNormal
;
4255 if (m_ownsImageListSmall
)
4256 delete m_imageListSmall
;
4257 if (m_ownsImageListState
)
4258 delete m_imageListState
;
4261 void wxListCtrl::CreateHeaderWindow()
4263 m_headerWin
= new wxListHeaderWindow
4265 this, -1, m_mainWin
,
4267 wxSize(GetClientSize().x
, HEADER_HEIGHT
),
4272 bool wxListCtrl::Create(wxWindow
*parent
,
4277 const wxValidator
&validator
,
4278 const wxString
&name
)
4282 m_imageListState
= (wxImageList
*) NULL
;
4283 m_ownsImageListNormal
=
4284 m_ownsImageListSmall
=
4285 m_ownsImageListState
= FALSE
;
4287 m_mainWin
= (wxListMainWindow
*) NULL
;
4288 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4290 if ( !(style
& wxLC_MASK_TYPE
) )
4292 style
= style
| wxLC_LIST
;
4295 if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name
) )
4298 // don't create the inner window with the border
4299 style
&= ~wxSUNKEN_BORDER
;
4301 m_mainWin
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style
);
4303 if ( HasFlag(wxLC_REPORT
) )
4305 CreateHeaderWindow();
4307 if ( HasFlag(wxLC_NO_HEADER
) )
4309 // VZ: why do we create it at all then?
4310 m_headerWin
->Show( FALSE
);
4317 void wxListCtrl::SetSingleStyle( long style
, bool add
)
4319 wxASSERT_MSG( !(style
& wxLC_VIRTUAL
),
4320 _T("wxLC_VIRTUAL can't be [un]set") );
4322 long flag
= GetWindowStyle();
4326 if (style
& wxLC_MASK_TYPE
)
4327 flag
&= ~(wxLC_MASK_TYPE
| wxLC_VIRTUAL
);
4328 if (style
& wxLC_MASK_ALIGN
)
4329 flag
&= ~wxLC_MASK_ALIGN
;
4330 if (style
& wxLC_MASK_SORT
)
4331 flag
&= ~wxLC_MASK_SORT
;
4343 SetWindowStyleFlag( flag
);
4346 void wxListCtrl::SetWindowStyleFlag( long flag
)
4350 m_mainWin
->DeleteEverything();
4354 GetClientSize( &width
, &height
);
4356 if (flag
& wxLC_REPORT
)
4358 if (!HasFlag(wxLC_REPORT
))
4362 CreateHeaderWindow();
4364 if (HasFlag(wxLC_NO_HEADER
))
4365 m_headerWin
->Show( FALSE
);
4369 if (flag
& wxLC_NO_HEADER
)
4370 m_headerWin
->Show( FALSE
);
4372 m_headerWin
->Show( TRUE
);
4378 if ( m_mainWin
->HasHeader() )
4380 m_headerWin
->Show( FALSE
);
4385 wxWindow::SetWindowStyleFlag( flag
);
4388 bool wxListCtrl::GetColumn(int col
, wxListItem
&item
) const
4390 m_mainWin
->GetColumn( col
, item
);
4394 bool wxListCtrl::SetColumn( int col
, wxListItem
& item
)
4396 m_mainWin
->SetColumn( col
, item
);
4400 int wxListCtrl::GetColumnWidth( int col
) const
4402 return m_mainWin
->GetColumnWidth( col
);
4405 bool wxListCtrl::SetColumnWidth( int col
, int width
)
4407 m_mainWin
->SetColumnWidth( col
, width
);
4411 int wxListCtrl::GetCountPerPage() const
4413 return m_mainWin
->GetCountPerPage(); // different from Windows ?
4416 bool wxListCtrl::GetItem( wxListItem
&info
) const
4418 m_mainWin
->GetItem( info
);
4422 bool wxListCtrl::SetItem( wxListItem
&info
)
4424 m_mainWin
->SetItem( info
);
4428 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId
)
4431 info
.m_text
= label
;
4432 info
.m_mask
= wxLIST_MASK_TEXT
;
4433 info
.m_itemId
= index
;
4437 info
.m_image
= imageId
;
4438 info
.m_mask
|= wxLIST_MASK_IMAGE
;
4440 m_mainWin
->SetItem(info
);
4444 int wxListCtrl::GetItemState( long item
, long stateMask
) const
4446 return m_mainWin
->GetItemState( item
, stateMask
);
4449 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask
)
4451 m_mainWin
->SetItemState( item
, state
, stateMask
);
4455 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) )
4458 info
.m_image
= image
;
4459 info
.m_mask
= wxLIST_MASK_IMAGE
;
4460 info
.m_itemId
= item
;
4461 m_mainWin
->SetItem( info
);
4465 wxString
wxListCtrl::GetItemText( long item
) const
4468 info
.m_itemId
= item
;
4469 m_mainWin
->GetItem( info
);
4473 void wxListCtrl::SetItemText( long item
, const wxString
&str
)
4476 info
.m_mask
= wxLIST_MASK_TEXT
;
4477 info
.m_itemId
= item
;
4479 m_mainWin
->SetItem( info
);
4482 long wxListCtrl::GetItemData( long item
) const
4485 info
.m_itemId
= item
;
4486 m_mainWin
->GetItem( info
);
4490 bool wxListCtrl::SetItemData( long item
, long data
)
4493 info
.m_mask
= wxLIST_MASK_DATA
;
4494 info
.m_itemId
= item
;
4496 m_mainWin
->SetItem( info
);
4500 bool wxListCtrl::GetItemRect( long item
, wxRect
&rect
, int WXUNUSED(code
) ) const
4502 m_mainWin
->GetItemRect( item
, rect
);
4506 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos
) const
4508 m_mainWin
->GetItemPosition( item
, pos
);
4512 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) )
4517 int wxListCtrl::GetItemCount() const
4519 return m_mainWin
->GetItemCount();
4522 int wxListCtrl::GetColumnCount() const
4524 return m_mainWin
->GetColumnCount();
4527 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall
)
4529 m_mainWin
->SetItemSpacing( spacing
, isSmall
);
4532 int wxListCtrl::GetItemSpacing( bool isSmall
) const
4534 return m_mainWin
->GetItemSpacing( isSmall
);
4537 int wxListCtrl::GetSelectedItemCount() const
4539 return m_mainWin
->GetSelectedItemCount();
4542 wxColour
wxListCtrl::GetTextColour() const
4544 return GetForegroundColour();
4547 void wxListCtrl::SetTextColour(const wxColour
& col
)
4549 SetForegroundColour(col
);
4552 long wxListCtrl::GetTopItem() const
4557 long wxListCtrl::GetNextItem( long item
, int geom
, int state
) const
4559 return m_mainWin
->GetNextItem( item
, geom
, state
);
4562 wxImageList
*wxListCtrl::GetImageList(int which
) const
4564 if (which
== wxIMAGE_LIST_NORMAL
)
4566 return m_imageListNormal
;
4568 else if (which
== wxIMAGE_LIST_SMALL
)
4570 return m_imageListSmall
;
4572 else if (which
== wxIMAGE_LIST_STATE
)
4574 return m_imageListState
;
4576 return (wxImageList
*) NULL
;
4579 void wxListCtrl::SetImageList( wxImageList
*imageList
, int which
)
4581 if ( which
== wxIMAGE_LIST_NORMAL
)
4583 if (m_ownsImageListNormal
) delete m_imageListNormal
;
4584 m_imageListNormal
= imageList
;
4585 m_ownsImageListNormal
= FALSE
;
4587 else if ( which
== wxIMAGE_LIST_SMALL
)
4589 if (m_ownsImageListSmall
) delete m_imageListSmall
;
4590 m_imageListSmall
= imageList
;
4591 m_ownsImageListSmall
= FALSE
;
4593 else if ( which
== wxIMAGE_LIST_STATE
)
4595 if (m_ownsImageListState
) delete m_imageListState
;
4596 m_imageListState
= imageList
;
4597 m_ownsImageListState
= FALSE
;
4600 m_mainWin
->SetImageList( imageList
, which
);
4603 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
4605 SetImageList(imageList
, which
);
4606 if ( which
== wxIMAGE_LIST_NORMAL
)
4607 m_ownsImageListNormal
= TRUE
;
4608 else if ( which
== wxIMAGE_LIST_SMALL
)
4609 m_ownsImageListSmall
= TRUE
;
4610 else if ( which
== wxIMAGE_LIST_STATE
)
4611 m_ownsImageListState
= TRUE
;
4614 bool wxListCtrl::Arrange( int WXUNUSED(flag
) )
4619 bool wxListCtrl::DeleteItem( long item
)
4621 m_mainWin
->DeleteItem( item
);
4625 bool wxListCtrl::DeleteAllItems()
4627 m_mainWin
->DeleteAllItems();
4631 bool wxListCtrl::DeleteAllColumns()
4633 size_t count
= m_mainWin
->m_columns
.GetCount();
4634 for ( size_t n
= 0; n
< count
; n
++ )
4640 void wxListCtrl::ClearAll()
4642 m_mainWin
->DeleteEverything();
4645 bool wxListCtrl::DeleteColumn( int col
)
4647 m_mainWin
->DeleteColumn( col
);
4651 void wxListCtrl::Edit( long item
)
4653 m_mainWin
->EditLabel( item
);
4656 bool wxListCtrl::EnsureVisible( long item
)
4658 m_mainWin
->EnsureVisible( item
);
4662 long wxListCtrl::FindItem( long start
, const wxString
& str
, bool partial
)
4664 return m_mainWin
->FindItem( start
, str
, partial
);
4667 long wxListCtrl::FindItem( long start
, long data
)
4669 return m_mainWin
->FindItem( start
, data
);
4672 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
),
4673 int WXUNUSED(direction
))
4678 long wxListCtrl::HitTest( const wxPoint
&point
, int &flags
)
4680 return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags
);
4683 long wxListCtrl::InsertItem( wxListItem
& info
)
4685 m_mainWin
->InsertItem( info
);
4686 return info
.m_itemId
;
4689 long wxListCtrl::InsertItem( long index
, const wxString
&label
)
4692 info
.m_text
= label
;
4693 info
.m_mask
= wxLIST_MASK_TEXT
;
4694 info
.m_itemId
= index
;
4695 return InsertItem( info
);
4698 long wxListCtrl::InsertItem( long index
, int imageIndex
)
4701 info
.m_mask
= wxLIST_MASK_IMAGE
;
4702 info
.m_image
= imageIndex
;
4703 info
.m_itemId
= index
;
4704 return InsertItem( info
);
4707 long wxListCtrl::InsertItem( long index
, const wxString
&label
, int imageIndex
)
4710 info
.m_text
= label
;
4711 info
.m_image
= imageIndex
;
4712 info
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_IMAGE
;
4713 info
.m_itemId
= index
;
4714 return InsertItem( info
);
4717 long wxListCtrl::InsertColumn( long col
, wxListItem
&item
)
4719 wxASSERT( m_headerWin
);
4720 m_mainWin
->InsertColumn( col
, item
);
4721 m_headerWin
->Refresh();
4726 long wxListCtrl::InsertColumn( long col
, const wxString
&heading
,
4727 int format
, int width
)
4730 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
4731 item
.m_text
= heading
;
4734 item
.m_mask
|= wxLIST_MASK_WIDTH
;
4735 item
.m_width
= width
;
4737 item
.m_format
= format
;
4739 return InsertColumn( col
, item
);
4742 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) )
4748 // fn is a function which takes 3 long arguments: item1, item2, data.
4749 // item1 is the long data associated with a first item (NOT the index).
4750 // item2 is the long data associated with a second item (NOT the index).
4751 // data is the same value as passed to SortItems.
4752 // The return value is a negative number if the first item should precede the second
4753 // item, a positive number of the second item should precede the first,
4754 // or zero if the two items are equivalent.
4755 // data is arbitrary data to be passed to the sort function.
4757 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data
)
4759 m_mainWin
->SortItems( fn
, data
);
4763 // ----------------------------------------------------------------------------
4765 // ----------------------------------------------------------------------------
4767 void wxListCtrl::OnSize(wxSizeEvent
& event
)
4773 GetClientSize( &cw
, &ch
);
4775 if ( m_mainWin
->HasHeader() )
4777 m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT
);
4778 m_mainWin
->SetSize( 0, HEADER_HEIGHT
+ 1, cw
, ch
- HEADER_HEIGHT
- 1 );
4780 else // no header window
4782 m_mainWin
->SetSize( 0, 0, cw
, ch
);
4785 m_mainWin
->RecalculatePositions();
4788 void wxListCtrl::OnIdle( wxIdleEvent
& event
)
4792 // do it only if needed
4793 if ( !m_mainWin
->m_dirty
)
4796 m_mainWin
->RecalculatePositions();
4799 // ----------------------------------------------------------------------------
4801 // ----------------------------------------------------------------------------
4803 bool wxListCtrl::SetBackgroundColour( const wxColour
&colour
)
4807 m_mainWin
->SetBackgroundColour( colour
);
4808 m_mainWin
->m_dirty
= TRUE
;
4814 bool wxListCtrl::SetForegroundColour( const wxColour
&colour
)
4816 if ( !wxWindow::SetForegroundColour( colour
) )
4821 m_mainWin
->SetForegroundColour( colour
);
4822 m_mainWin
->m_dirty
= TRUE
;
4827 m_headerWin
->SetForegroundColour( colour
);
4833 bool wxListCtrl::SetFont( const wxFont
&font
)
4835 if ( !wxWindow::SetFont( font
) )
4840 m_mainWin
->SetFont( font
);
4841 m_mainWin
->m_dirty
= TRUE
;
4846 m_headerWin
->SetFont( font
);
4852 // ----------------------------------------------------------------------------
4853 // methods forwarded to m_mainWin
4854 // ----------------------------------------------------------------------------
4856 #if wxUSE_DRAG_AND_DROP
4858 void wxListCtrl::SetDropTarget( wxDropTarget
*dropTarget
)
4860 m_mainWin
->SetDropTarget( dropTarget
);
4863 wxDropTarget
*wxListCtrl::GetDropTarget() const
4865 return m_mainWin
->GetDropTarget();
4868 #endif // wxUSE_DRAG_AND_DROP
4870 bool wxListCtrl::SetCursor( const wxCursor
&cursor
)
4872 return m_mainWin
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
;
4875 wxColour
wxListCtrl::GetBackgroundColour() const
4877 return m_mainWin
? m_mainWin
->GetBackgroundColour() : wxColour();
4880 wxColour
wxListCtrl::GetForegroundColour() const
4882 return m_mainWin
? m_mainWin
->GetForegroundColour() : wxColour();
4885 bool wxListCtrl::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4888 return m_mainWin
->PopupMenu( menu
, x
, y
);
4891 #endif // wxUSE_MENUS
4894 void wxListCtrl::SetFocus()
4896 /* The test in window.cpp fails as we are a composite
4897 window, so it checks against "this", but not m_mainWin. */
4898 if ( FindFocus() != this )
4899 m_mainWin
->SetFocus();
4902 // ----------------------------------------------------------------------------
4903 // virtual list control support
4904 // ----------------------------------------------------------------------------
4906 wxString
wxListCtrl::OnGetItemText(long item
, long col
) const
4908 // this is a pure virtual function, in fact - which is not really pure
4909 // because the controls which are not virtual don't need to implement it
4910 wxFAIL_MSG( _T("not supposed to be called") );
4912 return wxEmptyString
;
4915 int wxListCtrl::OnGetItemImage(long item
) const
4918 wxFAIL_MSG( _T("not supposed to be called") );
4923 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long item
) const
4925 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
4926 _T("invalid item index in OnGetItemAttr()") );
4928 // no attributes by default
4932 void wxListCtrl::SetItemCount(long count
)
4934 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4936 m_mainWin
->SetItemCount(count
);
4939 void wxListCtrl::RefreshItem(long item
)
4941 m_mainWin
->RefreshLine(item
);
4944 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
)
4946 m_mainWin
->RefreshLines(itemFrom
, itemTo
);
4949 #endif // wxUSE_LISTCTRL