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
)
104 // ----------------------------------------------------------------------------
106 // ----------------------------------------------------------------------------
108 // the height of the header window (FIXME: should depend on its font!)
109 static const int HEADER_HEIGHT
= 23;
111 // the scrollbar units
112 static const int SCROLL_UNIT_X
= 15;
113 static const int SCROLL_UNIT_Y
= 15;
115 // the spacing between the lines (in report mode)
116 static const int LINE_SPACING
= 0;
118 // extra margins around the text label
119 static const int EXTRA_WIDTH
= 3;
120 static const int EXTRA_HEIGHT
= 4;
122 // offset for the header window
123 static const int HEADER_OFFSET_X
= 1;
124 static const int HEADER_OFFSET_Y
= 1;
126 // when autosizing the columns, add some slack
127 static const int AUTOSIZE_COL_MARGIN
= 10;
129 // default and minimal widths for the header columns
130 static const int WIDTH_COL_DEFAULT
= 80;
131 static const int WIDTH_COL_MIN
= 10;
133 // ============================================================================
135 // ============================================================================
137 // ----------------------------------------------------------------------------
139 // ----------------------------------------------------------------------------
141 int CMPFUNC_CONV
wxSizeTCmpFn(size_t n1
, size_t n2
) { return n1
- n2
; }
143 WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray
);
145 // this class is used to store the selected items in the virtual list control
146 // (but it is not tied to list control and so can be used with other controls
147 // such as wxListBox in wxUniv)
149 // the idea is to make it really smart later (i.e. store the selections as an
150 // array of ranes + individual items) but, as I don't have time to do it now
151 // (this would require writing code to merge/break ranges and much more) keep
152 // it simple but define a clean interface to it which allows it to be made
154 class WXDLLEXPORT wxSelectionStore
157 wxSelectionStore() : m_itemsSel(wxSizeTCmpFn
) { Init(); }
159 // set the total number of items we handle
160 void SetItemCount(size_t count
) { m_count
= count
; }
162 // special case of SetItemCount(0)
163 void Clear() { m_itemsSel
.Clear(); m_count
= 0; }
165 // must be called when a new item is inserted/added
166 void OnItemAdd(size_t item
) { wxFAIL_MSG( _T("TODO") ); }
168 // must be called when an item is deleted
169 void OnItemDelete(size_t item
);
171 // select one item, use SelectRange() insted if possible!
173 // returns true if the items selection really changed
174 bool SelectItem(size_t item
, bool select
= TRUE
);
176 // select the range of items
177 void SelectRange(size_t itemFrom
, size_t itemTo
, bool select
= TRUE
);
179 // return true if the given item is selected
180 bool IsSelected(size_t item
) const;
182 // return the total number of selected items
183 size_t GetSelectedCount() const
185 return m_defaultState
? m_count
- m_itemsSel
.GetCount()
186 : m_itemsSel
.GetCount();
191 void Init() { m_defaultState
= FALSE
; }
193 // the total number of items we handle
196 // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
197 // there are more selected items than non selected ones - this allows to
198 // handle selection of all items efficiently
201 // the array of items whose selection state is different from default
202 wxIndexArray m_itemsSel
;
204 DECLARE_NO_COPY_CLASS(wxSelectionStore
)
207 //-----------------------------------------------------------------------------
208 // wxListItemData (internal)
209 //-----------------------------------------------------------------------------
211 class WXDLLEXPORT wxListItemData
214 wxListItemData(wxListMainWindow
*owner
);
217 void SetItem( const wxListItem
&info
);
218 void SetImage( int image
) { m_image
= image
; }
219 void SetData( long data
) { m_data
= data
; }
220 void SetPosition( int x
, int y
);
221 void SetSize( int width
, int height
);
223 bool HasText() const { return !m_text
.empty(); }
224 const wxString
& GetText() const { return m_text
; }
225 void SetText(const wxString
& text
) { m_text
= text
; }
227 // we can't use empty string for measuring the string width/height, so
228 // always return something
229 wxString
GetTextForMeasuring() const
231 wxString s
= GetText();
238 bool IsHit( int x
, int y
) const;
242 int GetWidth() const;
243 int GetHeight() const;
245 int GetImage() const { return m_image
; }
246 bool HasImage() const { return GetImage() != -1; }
248 void GetItem( wxListItem
&info
) const;
250 void SetAttr(wxListItemAttr
*attr
) { m_attr
= attr
; }
251 wxListItemAttr
*GetAttr() const { return m_attr
; }
254 // the item image or -1
257 // user data associated with the item
260 // the item coordinates are not used in report mode, instead this pointer
261 // is NULL and the owner window is used to retrieve the item position and
265 // the list ctrl we are in
266 wxListMainWindow
*m_owner
;
268 // custom attributes or NULL
269 wxListItemAttr
*m_attr
;
272 // common part of all ctors
278 //-----------------------------------------------------------------------------
279 // wxListHeaderData (internal)
280 //-----------------------------------------------------------------------------
282 class WXDLLEXPORT wxListHeaderData
: public wxObject
296 wxListHeaderData( const wxListItem
&info
);
297 void SetItem( const wxListItem
&item
);
298 void SetPosition( int x
, int y
);
299 void SetWidth( int w
);
300 void SetFormat( int format
);
301 void SetHeight( int h
);
302 bool HasImage() const;
304 bool HasText() const { return !m_text
.empty(); }
305 const wxString
& GetText() const { return m_text
; }
306 void SetText(const wxString
& text
) { m_text
= text
; }
308 void GetItem( wxListItem
&item
);
310 bool IsHit( int x
, int y
) const;
311 int GetImage() const;
312 int GetWidth() const;
313 int GetFormat() const;
316 DECLARE_DYNAMIC_CLASS(wxListHeaderData
);
319 //-----------------------------------------------------------------------------
320 // wxListLineData (internal)
321 //-----------------------------------------------------------------------------
323 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
);
324 #include "wx/listimpl.cpp"
325 WX_DEFINE_LIST(wxListItemDataList
);
327 class WXDLLEXPORT wxListLineData
330 // the list of subitems: only may have more than one item in report mode
331 wxListItemDataList m_items
;
333 // this is not used in report view
345 // the part to be highlighted
346 wxRect m_rectHighlight
;
349 // is this item selected? [NB: not used in virtual mode]
352 // back pointer to the list ctrl
353 wxListMainWindow
*m_owner
;
356 wxListLineData(wxListMainWindow
*owner
);
358 ~wxListLineData() { delete m_gi
; }
360 // are we in report mode?
361 inline bool InReportView() const;
363 // are we in virtual report mode?
364 inline bool IsVirtual() const;
366 // these 2 methods shouldn't be called for report view controls, in that
367 // case we determine our position/size ourselves
369 // calculate the size of the line
370 void CalculateSize( wxDC
*dc
, int spacing
);
372 // remember the position this line appears at
373 void SetPosition( int x
, int y
, int window_width
, int spacing
);
377 void SetImage( int image
) { SetImage(0, image
); }
378 int GetImage() const { return GetImage(0); }
379 bool HasImage() const { return GetImage() != -1; }
380 bool HasText() const { return !GetText(0).empty(); }
382 void SetItem( int index
, const wxListItem
&info
);
383 void GetItem( int index
, wxListItem
&info
);
385 wxString
GetText(int index
) const;
386 void SetText( int index
, const wxString s
);
388 wxListItemAttr
*GetAttr() const;
389 void SetAttr(wxListItemAttr
*attr
);
391 // return true if the highlighting really changed
392 bool Highlight( bool on
);
394 void ReverseHighlight();
396 bool IsHighlighted() const
398 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
400 return m_highlighted
;
403 // draw the line on the given DC in icon/list mode
404 void Draw( wxDC
*dc
);
406 // the same in report mode
407 void DrawInReportMode( wxDC
*dc
,
409 const wxRect
& rectHL
,
413 // set the line to contain num items (only can be > 1 in report mode)
414 void InitItems( int num
);
416 // get the mode (i.e. style) of the list control
417 inline int GetMode() const;
419 void SetAttributes(wxDC
*dc
,
420 const wxListItemAttr
*attr
,
421 const wxColour
& colText
,
425 // these are only used by GetImage/SetImage above, we don't support images
426 // with subitems at the public API level yet
427 void SetImage( int index
, int image
);
428 int GetImage( int index
) const;
431 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
);
432 #include "wx/arrimpl.cpp"
433 WX_DEFINE_OBJARRAY(wxListLineDataArray
);
435 //-----------------------------------------------------------------------------
436 // wxListHeaderWindow (internal)
437 //-----------------------------------------------------------------------------
439 class WXDLLEXPORT wxListHeaderWindow
: public wxWindow
442 wxListMainWindow
*m_owner
;
443 wxCursor
*m_currentCursor
;
444 wxCursor
*m_resizeCursor
;
447 // column being resized
450 // divider line position in logical (unscrolled) coords
453 // minimal position beyond which the divider line can't be dragged in
458 wxListHeaderWindow();
459 virtual ~wxListHeaderWindow();
461 wxListHeaderWindow( wxWindow
*win
,
463 wxListMainWindow
*owner
,
464 const wxPoint
&pos
= wxDefaultPosition
,
465 const wxSize
&size
= wxDefaultSize
,
467 const wxString
&name
= "wxlistctrlcolumntitles" );
469 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
471 void AdjustDC(wxDC
& dc
);
473 void OnPaint( wxPaintEvent
&event
);
474 void OnMouse( wxMouseEvent
&event
);
475 void OnSetFocus( wxFocusEvent
&event
);
481 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
)
482 DECLARE_EVENT_TABLE()
485 //-----------------------------------------------------------------------------
486 // wxListRenameTimer (internal)
487 //-----------------------------------------------------------------------------
489 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
492 wxListMainWindow
*m_owner
;
495 wxListRenameTimer( wxListMainWindow
*owner
);
499 //-----------------------------------------------------------------------------
500 // wxListTextCtrl (internal)
501 //-----------------------------------------------------------------------------
503 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
508 wxListMainWindow
*m_owner
;
509 wxString m_startValue
;
513 wxListTextCtrl( wxWindow
*parent
, const wxWindowID id
,
514 bool *accept
, wxString
*res
, wxListMainWindow
*owner
,
515 const wxString
&value
= "",
516 const wxPoint
&pos
= wxDefaultPosition
, const wxSize
&size
= wxDefaultSize
,
518 const wxValidator
& validator
= wxDefaultValidator
,
519 const wxString
&name
= "listctrltextctrl" );
520 void OnChar( wxKeyEvent
&event
);
521 void OnKeyUp( wxKeyEvent
&event
);
522 void OnKillFocus( wxFocusEvent
&event
);
525 DECLARE_DYNAMIC_CLASS(wxListTextCtrl
);
526 DECLARE_EVENT_TABLE()
529 //-----------------------------------------------------------------------------
530 // wxListMainWindow (internal)
531 //-----------------------------------------------------------------------------
533 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
);
534 #include "wx/listimpl.cpp"
535 WX_DEFINE_LIST(wxListHeaderDataList
);
537 class WXDLLEXPORT wxListMainWindow
: public wxScrolledWindow
541 wxListMainWindow( wxWindow
*parent
,
543 const wxPoint
& pos
= wxDefaultPosition
,
544 const wxSize
& size
= wxDefaultSize
,
546 const wxString
&name
= _T("listctrlmainwindow") );
548 virtual ~wxListMainWindow();
550 bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); }
552 // return true if this is a virtual list control
553 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); }
555 // return true if the control is in report mode
556 bool InReportView() const { return HasFlag(wxLC_REPORT
); }
558 // return true if we are in single selection mode, false if multi sel
559 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); }
561 // do we have a header window?
562 bool HasHeader() const
563 { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); }
565 void HighlightAll( bool on
);
567 // all these functions only do something if the line is currently visible
569 // change the line "selected" state, return TRUE if it really changed
570 bool HighlightLine( size_t line
, bool highlight
= TRUE
);
572 // as HighlightLine() but do it for the range of lines: this is incredibly
573 // more efficient for virtual list controls!
575 // NB: unlike HighlightLine() this one does refresh the lines on screen
576 void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on
= TRUE
);
578 // toggle the line state and refresh it
579 void ReverseHighlight( size_t line
)
580 { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); }
582 // return true if the line is highlighted
583 bool IsHighlighted(size_t line
) const;
585 // refresh one or several lines at once
586 void RefreshLine( size_t line
);
587 void RefreshLines( size_t lineFrom
, size_t lineTo
);
589 // refresh all lines below the given one: the difference with
590 // RefreshLines() is that the index here might not be a valid one (happens
591 // when the last line is deleted)
592 void RefreshAfter( size_t lineFrom
);
594 // the methods which are forwarded to wxListLineData itself in list/icon
595 // modes but are here because the lines don't store their positions in the
598 // get the bound rect for the entire line
599 wxRect
GetLineRect(size_t line
) const;
601 // get the bound rect of the label
602 wxRect
GetLineLabelRect(size_t line
) const;
604 // get the bound rect of the items icon (only may be called if we do have
606 wxRect
GetLineIconRect(size_t line
) const;
608 // get the rect to be highlighted when the item has focus
609 wxRect
GetLineHighlightRect(size_t line
) const;
611 // get the size of the total line rect
612 wxSize
GetLineSize(size_t line
) const
613 { return GetLineRect(line
).GetSize(); }
615 // return the hit code for the corresponding position (in this line)
616 long HitTestLine(size_t line
, int x
, int y
) const;
618 void EditLabel( long item
);
619 void OnRenameTimer();
620 void OnRenameAccept();
622 void OnMouse( wxMouseEvent
&event
);
625 // called to switch the selection from the current item to newCurrent,
626 void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event
);
628 void OnChar( wxKeyEvent
&event
);
629 void OnKeyDown( wxKeyEvent
&event
);
630 void OnSetFocus( wxFocusEvent
&event
);
631 void OnKillFocus( wxFocusEvent
&event
);
632 void OnScroll(wxScrollWinEvent
& event
) ;
634 void OnPaint( wxPaintEvent
&event
);
636 void DrawImage( int index
, wxDC
*dc
, int x
, int y
);
637 void GetImageSize( int index
, int &width
, int &height
) const;
638 int GetTextLength( const wxString
&s
) const;
640 void SetImageList( wxImageList
*imageList
, int which
);
641 void SetItemSpacing( int spacing
, bool isSmall
= FALSE
);
642 int GetItemSpacing( bool isSmall
= FALSE
);
644 void SetColumn( int col
, wxListItem
&item
);
645 void SetColumnWidth( int col
, int width
);
646 void GetColumn( int col
, wxListItem
&item
) const;
647 int GetColumnWidth( int col
) const;
648 int GetColumnCount() const { return m_columns
.GetCount(); }
650 // returns the sum of the heights of all columns
651 int GetHeaderWidth() const;
653 int GetCountPerPage() const;
655 void SetItem( wxListItem
&item
);
656 void GetItem( wxListItem
&item
);
657 void SetItemState( long item
, long state
, long stateMask
);
658 int GetItemState( long item
, long stateMask
);
659 void GetItemRect( long index
, wxRect
&rect
);
660 bool GetItemPosition( long item
, wxPoint
& pos
);
661 int GetSelectedItemCount();
663 // set the scrollbars and update the positions of the items
664 void RecalculatePositions();
666 // refresh the window and the header
669 long GetNextItem( long item
, int geometry
, int state
);
670 void DeleteItem( long index
);
671 void DeleteAllItems();
672 void DeleteColumn( int col
);
673 void DeleteEverything();
674 void EnsureVisible( long index
);
675 long FindItem( long start
, const wxString
& str
, bool partial
= FALSE
);
676 long FindItem( long start
, long data
);
677 long HitTest( int x
, int y
, int &flags
);
678 void InsertItem( wxListItem
&item
);
679 void InsertColumn( long col
, wxListItem
&item
);
680 void SortItems( wxListCtrlCompare fn
, long data
);
682 size_t GetItemCount() const;
683 bool IsEmpty() const { return GetItemCount() == 0; }
684 void SetItemCount(long count
);
686 void ResetCurrent() { m_current
= (size_t)-1; }
687 bool HasCurrent() const { return m_current
!= (size_t)-1; }
689 // send out a wxListEvent
690 void SendNotify( size_t line
,
692 wxPoint point
= wxDefaultPosition
);
694 // override base class virtual to reset m_lineHeight when the font changes
695 virtual bool SetFont(const wxFont
& font
)
697 if ( !wxScrolledWindow::SetFont(font
) )
705 // these are for wxListLineData usage only
707 // get the backpointer to the list ctrl
708 wxListCtrl
*GetListCtrl() const
710 return wxStaticCast(GetParent(), wxListCtrl
);
713 // get the height of all lines (assuming they all do have the same height)
714 wxCoord
GetLineHeight() const;
716 // get the y position of the given line (only for report view)
717 wxCoord
GetLineY(size_t line
) const;
720 // the array of all line objects for a non virtual list control
721 wxListLineDataArray m_lines
;
723 // the list of column objects
724 wxListHeaderDataList m_columns
;
726 // currently focused item or -1
729 // the item currently being edited or -1
730 size_t m_currentEdit
;
732 // the number of lines per page
735 // this flag is set when something which should result in the window
736 // redrawing happens (i.e. an item was added or deleted, or its appearance
737 // changed) and OnPaint() doesn't redraw the window while it is set which
738 // allows to minimize the number of repaintings when a lot of items are
739 // being added. The real repainting occurs only after the next OnIdle()
743 wxBrush
*m_highlightBrush
;
744 wxColour
*m_highlightColour
;
747 wxImageList
*m_small_image_list
;
748 wxImageList
*m_normal_image_list
;
750 int m_normal_spacing
;
754 wxTimer
*m_renameTimer
;
756 wxString m_renameRes
;
761 // for double click logic
762 size_t m_lineLastClicked
,
763 m_lineBeforeLastClicked
;
766 // the total count of items in a virtual list control
769 // the object maintaining the items selection state, only used in virtual
771 wxSelectionStore m_selStore
;
773 // common part of all ctors
776 // intiialize m_[xy]Scroll
777 void InitScrolling();
779 // get the line data for the given index
780 wxListLineData
*GetLine(size_t n
) const
782 wxASSERT_MSG( n
!= (size_t)-1, _T("invalid line index") );
786 wxConstCast(this, wxListMainWindow
)->CacheLineData(n
);
794 // get a dummy line which can be used for geometry calculations and such:
795 // you must use GetLine() if you want to really draw the line
796 wxListLineData
*GetDummyLine() const;
798 // cache the line data of the n-th line in m_lines[0]
799 void CacheLineData(size_t line
);
801 // get the range of visible lines
802 void GetVisibleLinesRange(size_t *from
, size_t *to
);
804 // force us to recalculate the range of visible lines
805 void ResetVisibleLinesRange() { m_lineFrom
= (size_t)-1; }
807 // get the colour to be used for drawing the rules
808 wxColour
GetRuleColour() const
813 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
);
818 // initialize the current item if needed
819 void UpdateCurrent();
821 // called when an item is [un]focuded, i.e. becomes [not] current
824 void OnFocusLine( size_t line
);
825 void OnUnfocusLine( size_t line
);
827 // the height of one line using the current font
828 wxCoord m_lineHeight
;
830 // the total header width or 0 if not calculated yet
831 wxCoord m_headerWidth
;
833 // the first and last lines being shown on screen right now (inclusive),
834 // both may be -1 if they must be calculated so never access them directly:
835 // use GetVisibleLinesRange() above instead
839 DECLARE_DYNAMIC_CLASS(wxListMainWindow
);
840 DECLARE_EVENT_TABLE()
843 // ============================================================================
845 // ============================================================================
847 // ----------------------------------------------------------------------------
849 // ----------------------------------------------------------------------------
851 bool wxSelectionStore::IsSelected(size_t item
) const
853 bool isSel
= m_itemsSel
.Index(item
) != wxNOT_FOUND
;
855 // if the default state is to be selected, being in m_itemsSel means that
856 // the item is not selected, so we have to inverse the logic
857 return m_defaultState
? !isSel
: isSel
;
860 bool wxSelectionStore::SelectItem(size_t item
, bool select
)
862 // search for the item ourselves as like this we get the index where to
863 // insert it later if needed, so we do only one search in the array instead
864 // of two (adding item to a sorted array requires a search)
865 size_t index
= m_itemsSel
.IndexForInsert(item
);
866 bool isSel
= index
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
;
868 if ( select
!= m_defaultState
)
872 m_itemsSel
.AddAt(item
, index
);
877 else // reset to default state
881 m_itemsSel
.RemoveAt(index
);
889 void wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, bool select
)
891 wxASSERT_MSG( itemFrom
<= itemTo
, _T("should be in order") );
893 // are we going to have more [un]selected items than the other ones?
894 if ( itemTo
- itemFrom
> m_count
/ 2 )
896 if ( select
!= m_defaultState
)
898 // the default state now becomes the same as 'select'
899 m_defaultState
= select
;
901 // so all the old selections (which had state select) shouldn't be
902 // selected any more, but all the other ones should
903 wxIndexArray selOld
= m_itemsSel
;
906 // TODO: it should be possible to optimize the searches a bit
907 // knowing the possible range
910 for ( item
= 0; item
< itemFrom
; item
++ )
912 if ( selOld
.Index(item
) == wxNOT_FOUND
)
913 m_itemsSel
.Add(item
);
916 for ( item
= itemTo
+ 1; item
< m_count
; item
++ )
918 if ( selOld
.Index(item
) == wxNOT_FOUND
)
919 m_itemsSel
.Add(item
);
922 else // select == m_defaultState
924 // get the inclusive range of items between itemFrom and itemTo
925 size_t count
= m_itemsSel
.GetCount(),
926 start
= m_itemsSel
.IndexForInsert(itemFrom
),
927 end
= m_itemsSel
.IndexForInsert(itemTo
);
929 if ( start
== count
|| m_itemsSel
[start
] < itemFrom
)
934 if ( end
== count
|| m_itemsSel
[end
] > itemTo
)
941 // delete all of them (from end to avoid changing indices)
942 for ( int i
= end
; i
>= (int)start
; i
-- )
944 m_itemsSel
.RemoveAt(i
);
949 else // "few" items change state
951 // just add the items to the selection
952 for ( size_t item
= itemFrom
; item
<= itemTo
; item
++ )
954 SelectItem(item
, select
);
959 void wxSelectionStore::OnItemDelete(size_t item
)
961 size_t count
= m_itemsSel
.GetCount(),
962 i
= m_itemsSel
.IndexForInsert(item
);
964 if ( i
< count
&& m_itemsSel
[i
] == item
)
966 // this item itself was in m_itemsSel, remove it from there
967 m_itemsSel
.RemoveAt(i
);
972 // and adjust the index of all which follow it
975 // all following elements must be greater than the one we deleted
976 wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") );
982 //-----------------------------------------------------------------------------
984 //-----------------------------------------------------------------------------
986 wxListItemData::~wxListItemData()
988 // in the virtual list control the attributes are managed by the main
989 // program, so don't delete them
990 if ( !m_owner
->IsVirtual() )
998 void wxListItemData::Init()
1006 wxListItemData::wxListItemData(wxListMainWindow
*owner
)
1012 if ( owner
->InReportView() )
1018 m_rect
= new wxRect
;
1022 void wxListItemData::SetItem( const wxListItem
&info
)
1024 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
1025 SetText(info
.m_text
);
1026 if ( info
.m_mask
& wxLIST_MASK_IMAGE
)
1027 m_image
= info
.m_image
;
1028 if ( info
.m_mask
& wxLIST_MASK_DATA
)
1029 m_data
= info
.m_data
;
1031 if ( info
.HasAttributes() )
1034 *m_attr
= *info
.GetAttributes();
1036 m_attr
= new wxListItemAttr(*info
.GetAttributes());
1044 m_rect
->width
= info
.m_width
;
1048 void wxListItemData::SetPosition( int x
, int y
)
1050 wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") );
1056 void wxListItemData::SetSize( int width
, int height
)
1058 wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") );
1061 m_rect
->width
= width
;
1063 m_rect
->height
= height
;
1066 bool wxListItemData::IsHit( int x
, int y
) const
1068 wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") );
1070 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
);
1073 int wxListItemData::GetX() const
1075 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1080 int wxListItemData::GetY() const
1082 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1087 int wxListItemData::GetWidth() const
1089 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1091 return m_rect
->width
;
1094 int wxListItemData::GetHeight() const
1096 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1098 return m_rect
->height
;
1101 void wxListItemData::GetItem( wxListItem
&info
) const
1103 info
.m_text
= m_text
;
1104 info
.m_image
= m_image
;
1105 info
.m_data
= m_data
;
1109 if ( m_attr
->HasTextColour() )
1110 info
.SetTextColour(m_attr
->GetTextColour());
1111 if ( m_attr
->HasBackgroundColour() )
1112 info
.SetBackgroundColour(m_attr
->GetBackgroundColour());
1113 if ( m_attr
->HasFont() )
1114 info
.SetFont(m_attr
->GetFont());
1118 //-----------------------------------------------------------------------------
1120 //-----------------------------------------------------------------------------
1122 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
);
1124 wxListHeaderData::wxListHeaderData()
1135 wxListHeaderData::wxListHeaderData( const wxListItem
&item
)
1143 void wxListHeaderData::SetItem( const wxListItem
&item
)
1145 m_mask
= item
.m_mask
;
1146 m_text
= item
.m_text
;
1147 m_image
= item
.m_image
;
1148 m_format
= item
.m_format
;
1150 SetWidth(item
.m_width
);
1153 void wxListHeaderData::SetPosition( int x
, int y
)
1159 void wxListHeaderData::SetHeight( int h
)
1164 void wxListHeaderData::SetWidth( int w
)
1168 m_width
= WIDTH_COL_DEFAULT
;
1169 if (m_width
< WIDTH_COL_MIN
)
1170 m_width
= WIDTH_COL_MIN
;
1173 void wxListHeaderData::SetFormat( int format
)
1178 bool wxListHeaderData::HasImage() const
1180 return (m_image
!= 0);
1183 bool wxListHeaderData::IsHit( int x
, int y
) const
1185 return ((x
>= m_xpos
) && (x
<= m_xpos
+m_width
) && (y
>= m_ypos
) && (y
<= m_ypos
+m_height
));
1188 void wxListHeaderData::GetItem( wxListItem
&item
)
1190 item
.m_mask
= m_mask
;
1191 item
.m_text
= m_text
;
1192 item
.m_image
= m_image
;
1193 item
.m_format
= m_format
;
1194 item
.m_width
= m_width
;
1197 int wxListHeaderData::GetImage() const
1202 int wxListHeaderData::GetWidth() const
1207 int wxListHeaderData::GetFormat() const
1212 //-----------------------------------------------------------------------------
1214 //-----------------------------------------------------------------------------
1216 inline int wxListLineData::GetMode() const
1218 return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
;
1221 inline bool wxListLineData::InReportView() const
1223 return m_owner
->HasFlag(wxLC_REPORT
);
1226 inline bool wxListLineData::IsVirtual() const
1228 return m_owner
->IsVirtual();
1231 wxListLineData::wxListLineData( wxListMainWindow
*owner
)
1234 m_items
.DeleteContents( TRUE
);
1236 if ( InReportView() )
1242 m_gi
= new GeometryInfo
;
1245 m_highlighted
= FALSE
;
1247 InitItems( GetMode() == wxLC_REPORT
? m_owner
->GetColumnCount() : 1 );
1250 void wxListLineData::CalculateSize( wxDC
*dc
, int spacing
)
1252 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1253 wxCHECK_RET( node
, _T("no subitems at all??") );
1255 wxListItemData
*item
= node
->GetData();
1257 switch ( GetMode() )
1260 case wxLC_SMALL_ICON
:
1262 m_gi
->m_rectAll
.width
= spacing
;
1264 wxString s
= item
->GetText();
1270 m_gi
->m_rectLabel
.width
=
1271 m_gi
->m_rectLabel
.height
= 0;
1275 dc
->GetTextExtent( s
, &lw
, &lh
);
1276 if (lh
< SCROLL_UNIT_Y
)
1281 m_gi
->m_rectAll
.height
= spacing
+ lh
;
1283 m_gi
->m_rectAll
.width
= lw
;
1285 m_gi
->m_rectLabel
.width
= lw
;
1286 m_gi
->m_rectLabel
.height
= lh
;
1289 if (item
->HasImage())
1292 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1293 m_gi
->m_rectIcon
.width
= w
+ 8;
1294 m_gi
->m_rectIcon
.height
= h
+ 8;
1296 if ( m_gi
->m_rectIcon
.width
> m_gi
->m_rectAll
.width
)
1297 m_gi
->m_rectAll
.width
= m_gi
->m_rectIcon
.width
;
1298 if ( m_gi
->m_rectIcon
.height
+ lh
> m_gi
->m_rectAll
.height
- 4 )
1299 m_gi
->m_rectAll
.height
= m_gi
->m_rectIcon
.height
+ lh
+ 4;
1302 if ( item
->HasText() )
1304 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectLabel
.width
;
1305 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectLabel
.height
;
1307 else // no text, highlight the icon
1309 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectIcon
.width
;
1310 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectIcon
.height
;
1317 wxString s
= item
->GetTextForMeasuring();
1320 dc
->GetTextExtent( s
, &lw
, &lh
);
1321 if (lh
< SCROLL_UNIT_Y
)
1326 m_gi
->m_rectLabel
.width
= lw
;
1327 m_gi
->m_rectLabel
.height
= lh
;
1329 m_gi
->m_rectAll
.width
= lw
;
1330 m_gi
->m_rectAll
.height
= lh
;
1332 if (item
->HasImage())
1335 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1336 m_gi
->m_rectIcon
.width
= w
;
1337 m_gi
->m_rectIcon
.height
= h
;
1339 m_gi
->m_rectAll
.width
+= 4 + w
;
1340 if (h
> m_gi
->m_rectAll
.height
)
1341 m_gi
->m_rectAll
.height
= h
;
1344 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectAll
.width
;
1345 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectAll
.height
;
1350 wxFAIL_MSG( _T("unexpected call to SetSize") );
1354 wxFAIL_MSG( _T("unknown mode") );
1358 void wxListLineData::SetPosition( int x
, int y
,
1362 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1363 wxCHECK_RET( node
, _T("no subitems at all??") );
1365 wxListItemData
*item
= node
->GetData();
1367 switch ( GetMode() )
1370 case wxLC_SMALL_ICON
:
1371 m_gi
->m_rectAll
.x
= x
;
1372 m_gi
->m_rectAll
.y
= y
;
1374 if ( item
->HasImage() )
1376 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 4
1377 + (spacing
- m_gi
->m_rectIcon
.width
)/2;
1378 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 4;
1381 if ( item
->HasText() )
1383 if (m_gi
->m_rectAll
.width
> spacing
)
1384 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1386 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2);
1387 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ m_gi
->m_rectAll
.height
+ 2 - m_gi
->m_rectLabel
.height
;
1388 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectLabel
.x
- 2;
1389 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectLabel
.y
- 2;
1391 else // no text, highlight the icon
1393 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectIcon
.x
- 4;
1394 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectIcon
.y
- 4;
1399 m_gi
->m_rectAll
.x
= x
;
1400 m_gi
->m_rectAll
.y
= y
;
1402 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectAll
.x
;
1403 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectAll
.y
;
1404 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ 2;
1406 if (item
->HasImage())
1408 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 2;
1409 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 2;
1410 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 6 + m_gi
->m_rectIcon
.width
;
1414 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1419 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1423 wxFAIL_MSG( _T("unknown mode") );
1427 void wxListLineData::InitItems( int num
)
1429 for (int i
= 0; i
< num
; i
++)
1430 m_items
.Append( new wxListItemData(m_owner
) );
1433 void wxListLineData::SetItem( int index
, const wxListItem
&info
)
1435 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1436 wxCHECK_RET( node
, _T("invalid column index in SetItem") );
1438 wxListItemData
*item
= node
->GetData();
1439 item
->SetItem( info
);
1442 void wxListLineData::GetItem( int index
, wxListItem
&info
)
1444 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1447 wxListItemData
*item
= node
->GetData();
1448 item
->GetItem( info
);
1452 wxString
wxListLineData::GetText(int index
) const
1456 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1459 wxListItemData
*item
= node
->GetData();
1460 s
= item
->GetText();
1466 void wxListLineData::SetText( int index
, const wxString s
)
1468 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1471 wxListItemData
*item
= node
->GetData();
1476 void wxListLineData::SetImage( int index
, int image
)
1478 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1479 wxCHECK_RET( node
, _T("invalid column index in SetImage()") );
1481 wxListItemData
*item
= node
->GetData();
1482 item
->SetImage(image
);
1485 int wxListLineData::GetImage( int index
) const
1487 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1488 wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") );
1490 wxListItemData
*item
= node
->GetData();
1491 return item
->GetImage();
1494 wxListItemAttr
*wxListLineData::GetAttr() const
1496 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1497 wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") );
1499 wxListItemData
*item
= node
->GetData();
1500 return item
->GetAttr();
1503 void wxListLineData::SetAttr(wxListItemAttr
*attr
)
1505 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1506 wxCHECK_RET( node
, _T("invalid column index in SetAttr()") );
1508 wxListItemData
*item
= node
->GetData();
1509 item
->SetAttr(attr
);
1512 void wxListLineData::SetAttributes(wxDC
*dc
,
1513 const wxListItemAttr
*attr
,
1514 const wxColour
& colText
,
1518 // don't use foregroud colour for drawing highlighted items - this might
1519 // make them completely invisible (and there is no way to do bit
1520 // arithmetics on wxColour, unfortunately)
1521 if ( !highlight
&& attr
&& attr
->HasTextColour() )
1523 dc
->SetTextForeground(attr
->GetTextColour());
1527 dc
->SetTextForeground(colText
);
1530 if ( attr
&& attr
->HasFont() )
1532 dc
->SetFont(attr
->GetFont());
1540 void wxListLineData::Draw( wxDC
*dc
)
1542 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1543 wxCHECK_RET( node
, _T("no subitems at all??") );
1545 wxListItemData
*item
= node
->GetData();
1546 if (item
->HasImage())
1548 wxRect rectIcon
= m_gi
->m_rectIcon
;
1549 m_owner
->DrawImage( item
->GetImage(), dc
,
1550 rectIcon
.x
, rectIcon
.y
);
1553 if (item
->HasText())
1555 wxRect rectLabel
= m_gi
->m_rectLabel
;
1556 dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y
);
1560 void wxListLineData::DrawInReportMode( wxDC
*dc
,
1562 const wxRect
& rectHL
,
1565 // use our own flag if we maintain it
1567 highlighted
= m_highlighted
;
1569 // default foreground colour
1570 wxWindow
*listctrl
= m_owner
->GetParent();
1574 colText
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT
);
1578 colText
= listctrl
->GetForegroundColour();
1582 wxFont font
= listctrl
->GetFont();
1584 // TODO: later we should support setting different attributes for
1585 // different columns - to do it, just add "col" argument to
1586 // GetAttr() and move this code into the loop below
1587 wxListItemAttr
*attr
= GetAttr();
1588 SetAttributes(dc
, attr
, colText
, font
, highlighted
);
1590 bool hasBgCol
= attr
&& attr
->HasBackgroundColour();
1591 if ( highlighted
|| hasBgCol
)
1595 dc
->SetBrush( *m_owner
->m_highlightBrush
);
1600 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
1602 dc
->SetBrush( * wxWHITE_BRUSH
);
1605 dc
->SetPen( * wxTRANSPARENT_PEN
);
1606 dc
->DrawRectangle( rectHL
);
1609 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1610 wxCHECK_RET( node
, _T("no subitems at all??") );
1613 wxCoord x
= rect
.x
+ HEADER_OFFSET_X
,
1614 y
= rect
.y
+ (LINE_SPACING
+ EXTRA_HEIGHT
) / 2;
1618 wxListItemData
*item
= node
->GetData();
1622 if ( item
->HasImage() )
1625 m_owner
->DrawImage( item
->GetImage(), dc
, x
, y
);
1626 m_owner
->GetImageSize( item
->GetImage(), ix
, iy
);
1627 x
+= ix
+ 5; // FIXME: what is "5"?
1630 int width
= m_owner
->GetColumnWidth(col
++);
1632 wxDCClipper
clipper(*dc
, x
, y
, width
, rect
.height
);
1634 if ( item
->HasText() )
1636 dc
->DrawText( item
->GetText(), x
, y
);
1641 node
= node
->GetNext();
1645 bool wxListLineData::Highlight( bool on
)
1647 wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") );
1649 if ( on
== m_highlighted
)
1657 void wxListLineData::ReverseHighlight( void )
1659 Highlight(!IsHighlighted());
1662 //-----------------------------------------------------------------------------
1663 // wxListHeaderWindow
1664 //-----------------------------------------------------------------------------
1666 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
);
1668 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
)
1669 EVT_PAINT (wxListHeaderWindow::OnPaint
)
1670 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse
)
1671 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus
)
1674 wxListHeaderWindow::wxListHeaderWindow( void )
1676 m_owner
= (wxListMainWindow
*) NULL
;
1677 m_currentCursor
= (wxCursor
*) NULL
;
1678 m_resizeCursor
= (wxCursor
*) NULL
;
1679 m_isDragging
= FALSE
;
1682 wxListHeaderWindow::wxListHeaderWindow( wxWindow
*win
, wxWindowID id
, wxListMainWindow
*owner
,
1683 const wxPoint
&pos
, const wxSize
&size
,
1684 long style
, const wxString
&name
) :
1685 wxWindow( win
, id
, pos
, size
, style
, name
)
1688 // m_currentCursor = wxSTANDARD_CURSOR;
1689 m_currentCursor
= (wxCursor
*) NULL
;
1690 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
1691 m_isDragging
= FALSE
;
1694 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE
) );
1697 wxListHeaderWindow::~wxListHeaderWindow( void )
1699 delete m_resizeCursor
;
1702 void wxListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1705 GtkStateType state
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
1706 : GTK_STATE_INSENSITIVE
;
1708 x
= dc
->XLOG2DEV( x
);
1710 gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
,
1711 state
, GTK_SHADOW_OUT
,
1712 (GdkRectangle
*) NULL
, m_wxwindow
, "button",
1713 x
-1, y
-1, w
+2, h
+2);
1714 #elif defined( __WXMAC__ )
1715 const int m_corner
= 1;
1717 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1719 dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
) , 1 , wxSOLID
) );
1720 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1721 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1723 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1726 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1727 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1729 dc
->SetPen( *wxWHITE_PEN
);
1730 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1731 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1732 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1733 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1735 const int m_corner
= 1;
1737 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1739 dc
->SetPen( *wxBLACK_PEN
);
1740 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1741 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1743 wxPen
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1746 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1747 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1749 dc
->SetPen( *wxWHITE_PEN
);
1750 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1751 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1752 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1753 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1757 // shift the DC origin to match the position of the main window horz
1758 // scrollbar: this allows us to always use logical coords
1759 void wxListHeaderWindow::AdjustDC(wxDC
& dc
)
1762 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1765 m_owner
->GetViewStart( &x
, NULL
);
1767 // account for the horz scrollbar offset
1768 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1771 void wxListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1774 wxClientDC
dc( this );
1776 wxPaintDC
dc( this );
1784 dc
.SetFont( GetFont() );
1786 // width and height of the entire header window
1788 GetClientSize( &w
, &h
);
1789 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1791 dc
.SetBackgroundMode(wxTRANSPARENT
);
1793 // do *not* use the listctrl colour for headers - one day we will have a
1794 // function to set it separately
1795 //dc.SetTextForeground( *wxBLACK );
1796 dc
.SetTextForeground(wxSystemSettings::
1797 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1799 int x
= HEADER_OFFSET_X
;
1801 int numColumns
= m_owner
->GetColumnCount();
1803 for (int i
= 0; i
< numColumns
; i
++)
1805 m_owner
->GetColumn( i
, item
);
1806 int wCol
= item
.m_width
;
1807 int cw
= wCol
- 2; // the width of the rect to draw
1809 int xEnd
= x
+ wCol
;
1811 dc
.SetPen( *wxWHITE_PEN
);
1813 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1814 dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 );
1815 dc
.DrawText( item
.GetText(), x
+ EXTRA_WIDTH
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1816 dc
.DestroyClippingRegion();
1825 void wxListHeaderWindow::DrawCurrent()
1827 int x1
= m_currentX
;
1829 ClientToScreen( &x1
, &y1
);
1831 int x2
= m_currentX
-1;
1833 m_owner
->GetClientSize( NULL
, &y2
);
1834 m_owner
->ClientToScreen( &x2
, &y2
);
1837 dc
.SetLogicalFunction( wxINVERT
);
1838 dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID
) );
1839 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1843 dc
.DrawLine( x1
, y1
, x2
, y2
);
1845 dc
.SetLogicalFunction( wxCOPY
);
1847 dc
.SetPen( wxNullPen
);
1848 dc
.SetBrush( wxNullBrush
);
1851 void wxListHeaderWindow::OnMouse( wxMouseEvent
&event
)
1853 // we want to work with logical coords
1855 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1856 int y
= event
.GetY();
1860 // we don't draw the line beyond our window, but we allow dragging it
1863 GetClientSize( &w
, NULL
);
1864 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1867 // erase the line if it was drawn
1868 if ( m_currentX
< w
)
1871 if (event
.ButtonUp())
1874 m_isDragging
= FALSE
;
1876 m_owner
->SetColumnWidth( m_column
, m_currentX
- m_minX
);
1883 m_currentX
= m_minX
+ 7;
1885 // draw in the new location
1886 if ( m_currentX
< w
)
1890 else // not dragging
1893 bool hit_border
= FALSE
;
1895 // end of the current column
1898 // find the column where this event occured
1899 int countCol
= m_owner
->GetColumnCount();
1900 for (int col
= 0; col
< countCol
; col
++)
1902 xpos
+= m_owner
->GetColumnWidth( col
);
1905 if ( (abs(x
-xpos
) < 3) && (y
< 22) )
1907 // near the column border
1914 // inside the column
1921 if (event
.LeftDown())
1925 m_isDragging
= TRUE
;
1932 wxWindow
*parent
= GetParent();
1933 wxListEvent
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() );
1934 le
.SetEventObject( parent
);
1935 le
.m_col
= m_column
;
1936 parent
->GetEventHandler()->ProcessEvent( le
);
1939 else if (event
.Moving())
1944 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1945 m_currentCursor
= m_resizeCursor
;
1949 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1950 m_currentCursor
= wxSTANDARD_CURSOR
;
1954 SetCursor(*m_currentCursor
);
1959 void wxListHeaderWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
1961 m_owner
->SetFocus();
1964 //-----------------------------------------------------------------------------
1965 // wxListRenameTimer (internal)
1966 //-----------------------------------------------------------------------------
1968 wxListRenameTimer::wxListRenameTimer( wxListMainWindow
*owner
)
1973 void wxListRenameTimer::Notify()
1975 m_owner
->OnRenameTimer();
1978 //-----------------------------------------------------------------------------
1979 // wxListTextCtrl (internal)
1980 //-----------------------------------------------------------------------------
1982 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
);
1984 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
)
1985 EVT_CHAR (wxListTextCtrl::OnChar
)
1986 EVT_KEY_UP (wxListTextCtrl::OnKeyUp
)
1987 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus
)
1990 wxListTextCtrl::wxListTextCtrl( wxWindow
*parent
,
1991 const wxWindowID id
,
1994 wxListMainWindow
*owner
,
1995 const wxString
&value
,
1999 const wxValidator
& validator
,
2000 const wxString
&name
)
2001 : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name
)
2006 (*m_accept
) = FALSE
;
2008 m_startValue
= value
;
2011 void wxListTextCtrl::OnChar( wxKeyEvent
&event
)
2013 if (event
.m_keyCode
== WXK_RETURN
)
2016 (*m_res
) = GetValue();
2018 if (!wxPendingDelete
.Member(this))
2019 wxPendingDelete
.Append(this);
2021 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2022 m_owner
->OnRenameAccept();
2026 if (event
.m_keyCode
== WXK_ESCAPE
)
2028 (*m_accept
) = FALSE
;
2031 if (!wxPendingDelete
.Member(this))
2032 wxPendingDelete
.Append(this);
2040 void wxListTextCtrl::OnKeyUp( wxKeyEvent
&event
)
2042 // auto-grow the textctrl:
2043 wxSize parentSize
= m_owner
->GetSize();
2044 wxPoint myPos
= GetPosition();
2045 wxSize mySize
= GetSize();
2047 GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM??
2048 if (myPos
.x
+ sx
> parentSize
.x
)
2049 sx
= parentSize
.x
- myPos
.x
;
2057 void wxListTextCtrl::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
2059 if (!wxPendingDelete
.Member(this))
2060 wxPendingDelete
.Append(this);
2062 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2063 m_owner
->OnRenameAccept();
2066 //-----------------------------------------------------------------------------
2068 //-----------------------------------------------------------------------------
2070 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
);
2072 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
)
2073 EVT_PAINT (wxListMainWindow::OnPaint
)
2074 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse
)
2075 EVT_CHAR (wxListMainWindow::OnChar
)
2076 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown
)
2077 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus
)
2078 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus
)
2079 EVT_SCROLLWIN (wxListMainWindow::OnScroll
)
2082 void wxListMainWindow::Init()
2084 m_columns
.DeleteContents( TRUE
);
2088 m_lineTo
= (size_t)-1;
2094 m_small_image_list
= (wxImageList
*) NULL
;
2095 m_normal_image_list
= (wxImageList
*) NULL
;
2097 m_small_spacing
= 30;
2098 m_normal_spacing
= 40;
2102 m_isCreated
= FALSE
;
2104 m_lastOnSame
= FALSE
;
2105 m_renameTimer
= new wxListRenameTimer( this );
2106 m_renameAccept
= FALSE
;
2111 m_lineBeforeLastClicked
= (size_t)-1;
2114 void wxListMainWindow::InitScrolling()
2116 if ( HasFlag(wxLC_REPORT
) )
2118 m_xScroll
= SCROLL_UNIT_X
;
2119 m_yScroll
= SCROLL_UNIT_Y
;
2123 m_xScroll
= SCROLL_UNIT_Y
;
2128 wxListMainWindow::wxListMainWindow()
2132 m_highlightBrush
= (wxBrush
*) NULL
;
2138 wxListMainWindow::wxListMainWindow( wxWindow
*parent
,
2143 const wxString
&name
)
2144 : wxScrolledWindow( parent
, id
, pos
, size
,
2145 style
| wxHSCROLL
| wxVSCROLL
, name
)
2149 m_highlightBrush
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
2154 SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 );
2156 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX
) );
2159 wxListMainWindow::~wxListMainWindow()
2163 delete m_highlightBrush
;
2165 delete m_renameTimer
;
2168 void wxListMainWindow::CacheLineData(size_t line
)
2170 wxListCtrl
*listctrl
= GetListCtrl();
2172 wxListLineData
*ld
= GetDummyLine();
2174 size_t countCol
= GetColumnCount();
2175 for ( size_t col
= 0; col
< countCol
; col
++ )
2177 ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
));
2180 ld
->SetImage(listctrl
->OnGetItemImage(line
));
2181 ld
->SetAttr(listctrl
->OnGetItemAttr(line
));
2184 wxListLineData
*wxListMainWindow::GetDummyLine() const
2186 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2188 if ( m_lines
.IsEmpty() )
2190 // normal controls are supposed to have something in m_lines
2191 // already if it's not empty
2192 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2194 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2195 wxListLineData
*line
= new wxListLineData(self
);
2196 self
->m_lines
.Add(line
);
2202 // ----------------------------------------------------------------------------
2203 // line geometry (report mode only)
2204 // ----------------------------------------------------------------------------
2206 wxCoord
wxListMainWindow::GetLineHeight() const
2208 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2210 // we cache the line height as calling GetTextExtent() is slow
2211 if ( !m_lineHeight
)
2213 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2215 wxClientDC
dc( self
);
2216 dc
.SetFont( GetFont() );
2219 dc
.GetTextExtent(_T("H"), NULL
, &y
);
2221 if ( y
< SCROLL_UNIT_Y
)
2225 self
->m_lineHeight
= y
+ LINE_SPACING
;
2228 return m_lineHeight
;
2231 wxCoord
wxListMainWindow::GetLineY(size_t line
) const
2233 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2235 return LINE_SPACING
+ line
*GetLineHeight();
2238 wxRect
wxListMainWindow::GetLineRect(size_t line
) const
2240 if ( !InReportView() )
2241 return GetLine(line
)->m_gi
->m_rectAll
;
2244 rect
.x
= HEADER_OFFSET_X
;
2245 rect
.y
= GetLineY(line
);
2246 rect
.width
= GetHeaderWidth();
2247 rect
.height
= GetLineHeight();
2252 wxRect
wxListMainWindow::GetLineLabelRect(size_t line
) const
2254 if ( !InReportView() )
2255 return GetLine(line
)->m_gi
->m_rectLabel
;
2258 rect
.x
= HEADER_OFFSET_X
;
2259 rect
.y
= GetLineY(line
);
2260 rect
.width
= GetColumnWidth(0);
2261 rect
.height
= GetLineHeight();
2266 wxRect
wxListMainWindow::GetLineIconRect(size_t line
) const
2268 if ( !InReportView() )
2269 return GetLine(line
)->m_gi
->m_rectIcon
;
2271 wxListLineData
*ld
= GetLine(line
);
2272 wxASSERT_MSG( ld
->HasImage(), _T("should have an image") );
2275 rect
.x
= HEADER_OFFSET_X
;
2276 rect
.y
= GetLineY(line
);
2277 GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
);
2282 wxRect
wxListMainWindow::GetLineHighlightRect(size_t line
) const
2284 return InReportView() ? GetLineRect(line
)
2285 : GetLine(line
)->m_gi
->m_rectHighlight
;
2288 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const
2290 wxListLineData
*ld
= GetLine(line
);
2292 if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) )
2293 return wxLIST_HITTEST_ONITEMICON
;
2295 if ( ld
->HasText() )
2297 wxRect rect
= InReportView() ? GetLineRect(line
)
2298 : GetLineLabelRect(line
);
2300 if ( rect
.Inside(x
, y
) )
2301 return wxLIST_HITTEST_ONITEMLABEL
;
2307 // ----------------------------------------------------------------------------
2308 // highlight (selection) handling
2309 // ----------------------------------------------------------------------------
2311 bool wxListMainWindow::IsHighlighted(size_t line
) const
2315 return m_selStore
.IsSelected(line
);
2319 wxListLineData
*ld
= GetLine(line
);
2320 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2322 return ld
->IsHighlighted();
2326 void wxListMainWindow::HighlightLines( size_t lineFrom
, size_t lineTo
, bool highlight
)
2330 m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
);
2331 RefreshLines(lineFrom
, lineTo
);
2335 // do it the dumb way
2336 bool needsRefresh
= FALSE
;
2337 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2339 if ( HighlightLine(line
, highlight
) )
2340 needsRefresh
= TRUE
;
2344 RefreshLines(lineFrom
, lineTo
);
2348 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight
)
2354 changed
= m_selStore
.SelectItem(line
, highlight
);
2358 wxListLineData
*ld
= GetLine(line
);
2359 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2361 changed
= ld
->Highlight(highlight
);
2366 SendNotify( line
, highlight
? wxEVT_COMMAND_LIST_ITEM_SELECTED
2367 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
);
2373 void wxListMainWindow::RefreshLine( size_t line
)
2375 wxRect rect
= GetLineRect(line
);
2377 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2378 RefreshRect( rect
);
2381 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo
)
2383 // we suppose that they are ordered by caller
2384 wxASSERT_MSG( lineFrom
<= lineTo
, _T("indices in disorder") );
2386 wxASSERT_MSG( lineTo
< GetItemCount(), _T("invalid line range") );
2388 if ( HasFlag(wxLC_REPORT
) )
2390 size_t visibleFrom
, visibleTo
;
2391 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2393 if ( lineFrom
< visibleFrom
)
2394 lineFrom
= visibleFrom
;
2395 if ( lineTo
> visibleTo
)
2400 rect
.y
= GetLineY(lineFrom
);
2401 rect
.width
= GetClientSize().x
;
2402 rect
.height
= GetLineY(lineTo
) - rect
.y
;
2404 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2405 RefreshRect( rect
);
2409 // TODO: this should be optimized...
2410 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2417 void wxListMainWindow::RefreshAfter( size_t lineFrom
)
2419 if ( HasFlag(wxLC_REPORT
) )
2422 GetVisibleLinesRange(&visibleFrom
, NULL
);
2424 if ( lineFrom
< visibleFrom
)
2425 lineFrom
= visibleFrom
;
2429 rect
.y
= GetLineY(lineFrom
);
2431 wxSize size
= GetClientSize();
2432 rect
.width
= size
.x
;
2433 // refresh till the bottom of the window
2434 rect
.height
= size
.y
- rect
.y
;
2436 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2437 RefreshRect( rect
);
2441 // TODO: how to do it more efficiently?
2446 void wxListMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2448 // Note: a wxPaintDC must be constructed even if no drawing is
2449 // done (a Windows requirement).
2450 wxPaintDC
dc( this );
2454 // empty control. nothing to draw
2460 // delay the repainting until we calculate all the items positions
2467 CalcScrolledPosition( 0, 0, &dev_x
, &dev_y
);
2471 dc
.SetFont( GetFont() );
2473 if ( HasFlag(wxLC_REPORT
) )
2475 int lineHeight
= GetLineHeight();
2477 size_t visibleFrom
, visibleTo
;
2478 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2481 wxCoord xOrig
, yOrig
;
2482 CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
);
2484 for ( size_t line
= visibleFrom
; line
<= visibleTo
; line
++ )
2486 rectLine
= GetLineRect(line
);
2488 if ( !IsExposed(rectLine
.x
- xOrig
, rectLine
.y
- yOrig
,
2489 rectLine
.width
, rectLine
.height
) )
2491 // don't redraw unaffected lines to avoid flicker
2495 GetLine(line
)->DrawInReportMode( &dc
,
2497 GetLineHighlightRect(line
),
2498 IsHighlighted(line
) );
2501 if ( HasFlag(wxLC_HRULES
) )
2503 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2504 wxSize clientSize
= GetClientSize();
2506 for ( size_t i
= visibleFrom
; i
<= visibleTo
; i
++ )
2509 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2510 dc
.DrawLine(0 - dev_x
, i
*lineHeight
,
2511 clientSize
.x
- dev_x
, i
*lineHeight
);
2514 // Draw last horizontal rule
2515 if ( visibleTo
> visibleFrom
)
2518 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2519 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
,
2520 clientSize
.x
- dev_x
, m_lineTo
*lineHeight
);
2524 // Draw vertical rules if required
2525 if ( HasFlag(wxLC_VRULES
) && !IsEmpty() )
2527 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2530 wxRect firstItemRect
;
2531 wxRect lastItemRect
;
2532 GetItemRect(0, firstItemRect
);
2533 GetItemRect(GetItemCount() - 1, lastItemRect
);
2534 int x
= firstItemRect
.GetX();
2536 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2537 for (col
= 0; col
< GetColumnCount(); col
++)
2539 int colWidth
= GetColumnWidth(col
);
2541 dc
.DrawLine(x
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
,
2542 x
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
);
2548 size_t count
= GetItemCount();
2549 for ( size_t i
= 0; i
< count
; i
++ )
2551 GetLine(i
)->Draw( &dc
);
2555 if ( HasCurrent() && m_hasFocus
)
2558 // no rect outline, we already have the background color
2560 dc
.SetPen( *wxBLACK_PEN
);
2561 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2562 dc
.DrawRectangle( GetLineHighlightRect(m_current
) );
2569 void wxListMainWindow::HighlightAll( bool on
)
2571 if ( IsSingleSel() )
2573 wxASSERT_MSG( !on
, _T("can't do this in a single sel control") );
2575 // we just have one item to turn off
2576 if ( HasCurrent() && IsHighlighted(m_current
) )
2578 HighlightLine(m_current
, FALSE
);
2579 RefreshLine(m_current
);
2584 HighlightLines(0, GetItemCount() - 1, on
);
2588 void wxListMainWindow::SendNotify( size_t line
,
2589 wxEventType command
,
2592 wxListEvent
le( command
, GetParent()->GetId() );
2593 le
.SetEventObject( GetParent() );
2594 le
.m_itemIndex
= line
;
2596 // set only for events which have position
2597 if ( point
!= wxDefaultPosition
)
2598 le
.m_pointDrag
= point
;
2600 GetLine(line
)->GetItem( 0, le
.m_item
);
2601 GetParent()->GetEventHandler()->ProcessEvent( le
);
2604 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) )
2606 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
2609 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) )
2611 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
2614 void wxListMainWindow::EditLabel( long item
)
2616 wxCHECK_RET( (item
>= 0) && ((size_t)item
< GetItemCount()),
2617 wxT("wrong index in wxListCtrl::EditLabel()") );
2619 m_currentEdit
= (size_t)item
;
2621 wxListEvent
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() );
2622 le
.SetEventObject( GetParent() );
2623 le
.m_itemIndex
= item
;
2624 wxListLineData
*data
= GetLine(m_currentEdit
);
2625 wxCHECK_RET( data
, _T("invalid index in EditLabel()") );
2626 data
->GetItem( 0, le
.m_item
);
2627 GetParent()->GetEventHandler()->ProcessEvent( le
);
2629 if (!le
.IsAllowed())
2632 // We have to call this here because the label in question might just have
2633 // been added and no screen update taken place.
2637 wxClientDC
dc(this);
2640 wxString s
= data
->GetText(0);
2641 wxRect rectLabel
= GetLineLabelRect(m_currentEdit
);
2643 rectLabel
.x
= dc
.LogicalToDeviceX( rectLabel
.x
);
2644 rectLabel
.y
= dc
.LogicalToDeviceY( rectLabel
.y
);
2646 wxListTextCtrl
*text
= new wxListTextCtrl
2653 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4),
2654 wxSize(rectLabel
.width
+11,rectLabel
.height
+8)
2659 void wxListMainWindow::OnRenameTimer()
2661 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2663 EditLabel( m_current
);
2666 void wxListMainWindow::OnRenameAccept()
2668 wxListEvent
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() );
2669 le
.SetEventObject( GetParent() );
2670 le
.m_itemIndex
= m_currentEdit
;
2672 wxListLineData
*data
= GetLine(m_currentEdit
);
2673 wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") );
2675 data
->GetItem( 0, le
.m_item
);
2676 le
.m_item
.m_text
= m_renameRes
;
2677 GetParent()->GetEventHandler()->ProcessEvent( le
);
2679 if (!le
.IsAllowed()) return;
2682 info
.m_mask
= wxLIST_MASK_TEXT
;
2683 info
.m_itemId
= le
.m_itemIndex
;
2684 info
.m_text
= m_renameRes
;
2685 info
.SetTextColour(le
.m_item
.GetTextColour());
2689 void wxListMainWindow::OnMouse( wxMouseEvent
&event
)
2691 event
.SetEventObject( GetParent() );
2692 if ( GetParent()->GetEventHandler()->ProcessEvent( event
) )
2695 if ( !HasCurrent() || IsEmpty() )
2701 if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() ||
2702 event
.ButtonDClick()) )
2705 int x
= event
.GetX();
2706 int y
= event
.GetY();
2707 CalcUnscrolledPosition( x
, y
, &x
, &y
);
2709 // where did we hit it (if we did)?
2712 size_t count
= GetItemCount(),
2715 if ( HasFlag(wxLC_REPORT
) )
2717 current
= y
/ GetLineHeight();
2718 if ( current
< count
)
2719 hitResult
= HitTestLine(current
, x
, y
);
2723 // TODO: optimize it too! this is less simple than for report view but
2724 // enumerating all items is still not a way to do it!!
2725 for ( current
= 0; current
< count
; current
++ )
2727 hitResult
= HitTestLine(current
, x
, y
);
2733 if (event
.Dragging())
2735 if (m_dragCount
== 0)
2736 m_dragStart
= wxPoint(x
,y
);
2740 if (m_dragCount
!= 3)
2743 int command
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2744 : wxEVT_COMMAND_LIST_BEGIN_DRAG
;
2746 wxListEvent
le( command
, GetParent()->GetId() );
2747 le
.SetEventObject( GetParent() );
2748 le
.m_pointDrag
= m_dragStart
;
2749 GetParent()->GetEventHandler()->ProcessEvent( le
);
2760 // outside of any item
2764 bool forceClick
= FALSE
;
2765 if (event
.ButtonDClick())
2767 m_renameTimer
->Stop();
2768 m_lastOnSame
= FALSE
;
2770 if ( current
== m_lineBeforeLastClicked
)
2772 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED
);
2778 // the first click was on another item, so don't interpret this as
2779 // a double click, but as a simple click instead
2784 if (event
.LeftUp() && m_lastOnSame
)
2786 if ((current
== m_current
) &&
2787 (hitResult
== wxLIST_HITTEST_ONITEMLABEL
) &&
2788 HasFlag(wxLC_EDIT_LABELS
) )
2790 m_renameTimer
->Start( 100, TRUE
);
2792 m_lastOnSame
= FALSE
;
2794 else if (event
.RightDown())
2796 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
,
2797 event
.GetPosition() );
2799 else if (event
.MiddleDown())
2801 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
);
2803 else if ( event
.LeftDown() || forceClick
)
2805 m_lineBeforeLastClicked
= m_lineLastClicked
;
2806 m_lineLastClicked
= current
;
2808 size_t oldCurrent
= m_current
;
2810 if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) )
2812 HighlightAll( FALSE
);
2813 m_current
= current
;
2815 ReverseHighlight(m_current
);
2817 else // multi sel & either ctrl or shift is down
2819 if (event
.ControlDown())
2821 m_current
= current
;
2823 ReverseHighlight(m_current
);
2825 else if (event
.ShiftDown())
2827 m_current
= current
;
2829 size_t lineFrom
= oldCurrent
,
2832 if ( lineTo
< lineFrom
)
2835 lineFrom
= m_current
;
2838 HighlightLines(lineFrom
, lineTo
);
2840 else // !ctrl, !shift
2842 // test in the enclosing if should make it impossible
2843 wxFAIL_MSG( _T("how did we get here?") );
2847 if (m_current
!= oldCurrent
)
2849 RefreshLine( oldCurrent
);
2850 OnUnfocusLine( oldCurrent
);
2851 OnFocusLine( m_current
);
2854 // forceClick is only set if the previous click was on another item
2855 m_lastOnSame
= !forceClick
&& (m_current
== oldCurrent
);
2859 void wxListMainWindow::MoveToFocus()
2861 if ( !HasCurrent() )
2864 wxRect rect
= GetLineRect(m_current
);
2866 int client_w
, client_h
;
2867 GetClientSize( &client_w
, &client_h
);
2869 int view_x
= m_xScroll
*GetScrollPos( wxHORIZONTAL
);
2870 int view_y
= m_yScroll
*GetScrollPos( wxVERTICAL
);
2872 if ( HasFlag(wxLC_REPORT
) )
2874 // the next we need the range of lines shown it might be different, so
2876 ResetVisibleLinesRange();
2878 if (rect
.y
< view_y
)
2879 Scroll( -1, rect
.y
/m_yScroll
);
2880 if (rect
.y
+rect
.height
+5 > view_y
+client_h
)
2881 Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll
);
2885 if (rect
.x
-view_x
< 5)
2886 Scroll( (rect
.x
-5)/m_xScroll
, -1 );
2887 if (rect
.x
+rect
.width
-5 > view_x
+client_w
)
2888 Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 );
2892 // ----------------------------------------------------------------------------
2893 // keyboard handling
2894 // ----------------------------------------------------------------------------
2896 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
2898 wxCHECK_RET( newCurrent
< (size_t)GetItemCount(),
2899 _T("invalid item index in OnArrowChar()") );
2901 size_t oldCurrent
= m_current
;
2903 // in single selection we just ignore Shift as we can't select several
2905 if ( event
.ShiftDown() && !IsSingleSel() )
2907 m_current
= newCurrent
;
2909 // select all the items between the old and the new one
2910 if ( oldCurrent
> newCurrent
)
2912 newCurrent
= oldCurrent
;
2913 oldCurrent
= m_current
;
2916 HighlightLines(oldCurrent
, newCurrent
);
2920 // all previously selected items are unselected unless ctrl is held
2921 if ( !event
.ControlDown() )
2922 HighlightAll(FALSE
);
2924 m_current
= newCurrent
;
2926 HighlightLine( oldCurrent
, FALSE
);
2927 RefreshLine( oldCurrent
);
2929 if ( !event
.ControlDown() )
2931 HighlightLine( m_current
, TRUE
);
2935 OnUnfocusLine( oldCurrent
);
2936 OnFocusLine( m_current
);
2937 RefreshLine( m_current
);
2942 void wxListMainWindow::OnKeyDown( wxKeyEvent
&event
)
2944 wxWindow
*parent
= GetParent();
2946 /* we propagate the key event up */
2947 wxKeyEvent
ke( wxEVT_KEY_DOWN
);
2948 ke
.m_shiftDown
= event
.m_shiftDown
;
2949 ke
.m_controlDown
= event
.m_controlDown
;
2950 ke
.m_altDown
= event
.m_altDown
;
2951 ke
.m_metaDown
= event
.m_metaDown
;
2952 ke
.m_keyCode
= event
.m_keyCode
;
2955 ke
.SetEventObject( parent
);
2956 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2961 void wxListMainWindow::OnChar( wxKeyEvent
&event
)
2963 wxWindow
*parent
= GetParent();
2965 /* we send a list_key event up */
2968 wxListEvent
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() );
2969 le
.m_itemIndex
= m_current
;
2970 GetLine(m_current
)->GetItem( 0, le
.m_item
);
2971 le
.m_code
= (int)event
.KeyCode();
2972 le
.SetEventObject( parent
);
2973 parent
->GetEventHandler()->ProcessEvent( le
);
2976 /* we propagate the char event up */
2977 wxKeyEvent
ke( wxEVT_CHAR
);
2978 ke
.m_shiftDown
= event
.m_shiftDown
;
2979 ke
.m_controlDown
= event
.m_controlDown
;
2980 ke
.m_altDown
= event
.m_altDown
;
2981 ke
.m_metaDown
= event
.m_metaDown
;
2982 ke
.m_keyCode
= event
.m_keyCode
;
2985 ke
.SetEventObject( parent
);
2986 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2988 if (event
.KeyCode() == WXK_TAB
)
2990 wxNavigationKeyEvent nevent
;
2991 nevent
.SetWindowChange( event
.ControlDown() );
2992 nevent
.SetDirection( !event
.ShiftDown() );
2993 nevent
.SetEventObject( GetParent()->GetParent() );
2994 nevent
.SetCurrentFocus( m_parent
);
2995 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
)) return;
2998 /* no item -> nothing to do */
3005 switch (event
.KeyCode())
3008 if ( m_current
> 0 )
3009 OnArrowChar( m_current
- 1, event
);
3013 if ( m_current
< (size_t)GetItemCount() - 1 )
3014 OnArrowChar( m_current
+ 1, event
);
3019 OnArrowChar( GetItemCount() - 1, event
);
3024 OnArrowChar( 0, event
);
3030 if ( HasFlag(wxLC_REPORT
) )
3032 steps
= m_linesPerPage
- 1;
3036 steps
= m_current
% m_linesPerPage
;
3039 int index
= m_current
- steps
;
3043 OnArrowChar( index
, event
);
3050 if ( HasFlag(wxLC_REPORT
) )
3052 steps
= m_linesPerPage
- 1;
3056 steps
= m_linesPerPage
- (m_current
% m_linesPerPage
) - 1;
3059 size_t index
= m_current
+ steps
;
3060 size_t count
= GetItemCount();
3061 if ( index
>= count
)
3064 OnArrowChar( index
, event
);
3069 if ( !HasFlag(wxLC_REPORT
) )
3071 int index
= m_current
- m_linesPerPage
;
3075 OnArrowChar( index
, event
);
3080 if ( !HasFlag(wxLC_REPORT
) )
3082 size_t index
= m_current
+ m_linesPerPage
;
3084 size_t count
= GetItemCount();
3085 if ( index
>= count
)
3088 OnArrowChar( index
, event
);
3093 if ( IsSingleSel() )
3095 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3096 GetParent()->GetId() );
3097 le
.SetEventObject( GetParent() );
3098 le
.m_itemIndex
= m_current
;
3099 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3100 GetParent()->GetEventHandler()->ProcessEvent( le
);
3104 ReverseHighlight(m_current
);
3111 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3112 GetParent()->GetId() );
3113 le
.SetEventObject( GetParent() );
3114 le
.m_itemIndex
= m_current
;
3115 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3116 GetParent()->GetEventHandler()->ProcessEvent( le
);
3125 // ----------------------------------------------------------------------------
3127 // ----------------------------------------------------------------------------
3130 extern wxWindow
*g_focusWindow
;
3133 void wxListMainWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
3138 RefreshLine( m_current
);
3144 g_focusWindow
= GetParent();
3147 wxFocusEvent
event( wxEVT_SET_FOCUS
, GetParent()->GetId() );
3148 event
.SetEventObject( GetParent() );
3149 GetParent()->GetEventHandler()->ProcessEvent( event
);
3152 void wxListMainWindow::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
3157 RefreshLine( m_current
);
3160 void wxListMainWindow::DrawImage( int index
, wxDC
*dc
, int x
, int y
)
3162 if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
))
3164 m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3166 else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
))
3168 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3170 else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
))
3172 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3174 else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
))
3176 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3180 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height
) const
3182 if ( HasFlag(wxLC_ICON
) && m_normal_image_list
)
3184 m_normal_image_list
->GetSize( index
, width
, height
);
3186 else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list
)
3188 m_small_image_list
->GetSize( index
, width
, height
);
3190 else if ( HasFlag(wxLC_LIST
) && m_small_image_list
)
3192 m_small_image_list
->GetSize( index
, width
, height
);
3194 else if ( HasFlag(wxLC_REPORT
) && m_small_image_list
)
3196 m_small_image_list
->GetSize( index
, width
, height
);
3205 int wxListMainWindow::GetTextLength( const wxString
&s
) const
3207 wxClientDC
dc( wxConstCast(this, wxListMainWindow
) );
3208 dc
.SetFont( GetFont() );
3211 dc
.GetTextExtent( s
, &lw
, NULL
);
3213 return lw
+ AUTOSIZE_COL_MARGIN
;
3216 void wxListMainWindow::SetImageList( wxImageList
*imageList
, int which
)
3220 // calc the spacing from the icon size
3223 if ((imageList
) && (imageList
->GetImageCount()) )
3225 imageList
->GetSize(0, width
, height
);
3228 if (which
== wxIMAGE_LIST_NORMAL
)
3230 m_normal_image_list
= imageList
;
3231 m_normal_spacing
= width
+ 8;
3234 if (which
== wxIMAGE_LIST_SMALL
)
3236 m_small_image_list
= imageList
;
3237 m_small_spacing
= width
+ 14;
3241 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall
)
3246 m_small_spacing
= spacing
;
3250 m_normal_spacing
= spacing
;
3254 int wxListMainWindow::GetItemSpacing( bool isSmall
)
3256 return isSmall
? m_small_spacing
: m_normal_spacing
;
3259 // ----------------------------------------------------------------------------
3261 // ----------------------------------------------------------------------------
3263 void wxListMainWindow::SetColumn( int col
, wxListItem
&item
)
3265 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3267 wxCHECK_RET( node
, _T("invalid column index in SetColumn") );
3269 if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3270 item
.m_width
= GetTextLength( item
.m_text
);
3272 wxListHeaderData
*column
= node
->GetData();
3273 column
->SetItem( item
);
3275 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3277 headerWin
->m_dirty
= TRUE
;
3281 // invalidate it as it has to be recalculated
3285 void wxListMainWindow::SetColumnWidth( int col
, int width
)
3287 wxCHECK_RET( col
>= 0 && col
< GetColumnCount(),
3288 _T("invalid column index") );
3290 wxCHECK_RET( HasFlag(wxLC_REPORT
),
3291 _T("SetColumnWidth() can only be called in report mode.") );
3295 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3296 wxCHECK_RET( node
, _T("no column?") );
3298 wxListHeaderData
*column
= node
->GetData();
3300 size_t count
= GetItemCount();
3302 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
3304 width
= GetTextLength(column
->GetText());
3306 else if ( width
== wxLIST_AUTOSIZE
)
3310 // TODO: determine the max width somehow...
3311 width
= WIDTH_COL_DEFAULT
;
3315 wxClientDC
dc(this);
3316 dc
.SetFont( GetFont() );
3318 int max
= AUTOSIZE_COL_MARGIN
;
3320 for ( size_t i
= 0; i
< count
; i
++ )
3322 wxListLineData
*line
= GetLine(i
);
3323 wxListItemDataList::Node
*n
= line
->m_items
.Item( col
);
3325 wxCHECK_RET( n
, _T("no subitem?") );
3327 wxListItemData
*item
= n
->GetData();
3330 if (item
->HasImage())
3333 GetImageSize( item
->GetImage(), ix
, iy
);
3337 if (item
->HasText())
3340 dc
.GetTextExtent( item
->GetText(), &w
, NULL
);
3348 width
= max
+ AUTOSIZE_COL_MARGIN
;
3352 column
->SetWidth( width
);
3354 // invalidate it as it has to be recalculated
3358 int wxListMainWindow::GetHeaderWidth() const
3360 if ( !m_headerWidth
)
3362 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
3364 size_t count
= GetColumnCount();
3365 for ( size_t col
= 0; col
< count
; col
++ )
3367 self
->m_headerWidth
+= GetColumnWidth(col
);
3371 return m_headerWidth
;
3374 void wxListMainWindow::GetColumn( int col
, wxListItem
&item
) const
3376 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3377 wxCHECK_RET( node
, _T("invalid column index in GetColumn") );
3379 wxListHeaderData
*column
= node
->GetData();
3380 column
->GetItem( item
);
3383 int wxListMainWindow::GetColumnWidth( int col
) const
3385 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3386 wxCHECK_MSG( node
, 0, _T("invalid column index") );
3388 wxListHeaderData
*column
= node
->GetData();
3389 return column
->GetWidth();
3392 // ----------------------------------------------------------------------------
3394 // ----------------------------------------------------------------------------
3396 void wxListMainWindow::SetItem( wxListItem
&item
)
3398 long id
= item
.m_itemId
;
3399 wxCHECK_RET( id
>= 0 && (size_t)id
< GetItemCount(),
3400 _T("invalid item index in SetItem") );
3404 wxListLineData
*line
= GetLine((size_t)id
);
3405 line
->SetItem( item
.m_col
, item
);
3408 if ( InReportView() )
3410 // just refresh the line to show the new value of the text/image
3411 RefreshLine((size_t)id
);
3415 // refresh everything (resulting in horrible flicker - FIXME!)
3420 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask
)
3422 wxCHECK_RET( litem
>= 0 && (size_t)litem
< GetItemCount(),
3423 _T("invalid list ctrl item index in SetItem") );
3425 size_t oldCurrent
= m_current
;
3426 size_t item
= (size_t)litem
; // sdafe because of the check above
3428 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3430 if ( state
& wxLIST_STATE_FOCUSED
)
3432 // don't do anything if this item is already focused
3433 if ( item
!= m_current
)
3435 OnUnfocusLine( m_current
);
3437 OnFocusLine( m_current
);
3439 if ( IsSingleSel() && (oldCurrent
!= (size_t)-1) )
3441 HighlightLine(oldCurrent
, FALSE
);
3442 RefreshLine(oldCurrent
);
3445 RefreshLine( m_current
);
3450 // don't do anything if this item is not focused
3451 if ( item
== m_current
)
3453 OnUnfocusLine( m_current
);
3454 m_current
= (size_t)-1;
3459 if ( stateMask
& wxLIST_STATE_SELECTED
)
3461 bool on
= (state
& wxLIST_STATE_SELECTED
) != 0;
3463 if ( IsSingleSel() )
3467 // selecting the item also makes it the focused one in the
3469 if ( m_current
!= item
)
3471 OnUnfocusLine( m_current
);
3473 OnFocusLine( m_current
);
3475 if ( oldCurrent
!= (size_t)-1 )
3477 HighlightLine( oldCurrent
, FALSE
);
3478 RefreshLine( oldCurrent
);
3484 // only the current item may be selected anyhow
3485 if ( item
!= m_current
)
3490 if ( HighlightLine(item
, on
) )
3497 int wxListMainWindow::GetItemState( long item
, long stateMask
)
3499 wxCHECK_MSG( item
>= 0 && (size_t)item
< GetItemCount(), 0,
3500 _T("invalid list ctrl item index in GetItemState()") );
3502 int ret
= wxLIST_STATE_DONTCARE
;
3504 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3506 if ( (size_t)item
== m_current
)
3507 ret
|= wxLIST_STATE_FOCUSED
;
3510 if ( stateMask
& wxLIST_STATE_SELECTED
)
3512 if ( IsHighlighted(item
) )
3513 ret
|= wxLIST_STATE_SELECTED
;
3519 void wxListMainWindow::GetItem( wxListItem
&item
)
3521 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
< GetItemCount(),
3522 _T("invalid item index in GetItem") );
3524 wxListLineData
*line
= GetLine((size_t)item
.m_itemId
);
3525 line
->GetItem( item
.m_col
, item
);
3528 // ----------------------------------------------------------------------------
3530 // ----------------------------------------------------------------------------
3532 size_t wxListMainWindow::GetItemCount() const
3534 return IsVirtual() ? m_countVirt
: m_lines
.GetCount();
3537 void wxListMainWindow::SetItemCount(long count
)
3539 m_selStore
.SetItemCount(count
);
3540 m_countVirt
= count
;
3542 ResetVisibleLinesRange();
3547 int wxListMainWindow::GetSelectedItemCount()
3549 // deal with the quick case first
3550 if ( IsSingleSel() )
3552 return HasCurrent() ? IsHighlighted(m_current
) : FALSE
;
3555 // virtual controls remmebers all its selections itself
3557 return m_selStore
.GetSelectedCount();
3559 // TODO: we probably should maintain the number of items selected even for
3560 // non virtual controls as enumerating all lines is really slow...
3561 size_t countSel
= 0;
3562 size_t count
= GetItemCount();
3563 for ( size_t line
= 0; line
< count
; line
++ )
3565 if ( GetLine(line
)->IsHighlighted() )
3572 // ----------------------------------------------------------------------------
3573 // item position/size
3574 // ----------------------------------------------------------------------------
3576 void wxListMainWindow::GetItemRect( long index
, wxRect
&rect
)
3578 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3579 _T("invalid index in GetItemRect") );
3581 rect
= GetLineRect((size_t)index
);
3583 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
3586 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
)
3589 GetItemRect(item
, rect
);
3597 // ----------------------------------------------------------------------------
3598 // geometry calculation
3599 // ----------------------------------------------------------------------------
3601 void wxListMainWindow::RecalculatePositions()
3606 wxClientDC
dc( this );
3607 dc
.SetFont( GetFont() );
3610 if ( HasFlag(wxLC_ICON
) )
3611 iconSpacing
= m_normal_spacing
;
3612 else if ( HasFlag(wxLC_SMALL_ICON
) )
3613 iconSpacing
= m_small_spacing
;
3619 GetClientSize( &clientWidth
, &clientHeight
);
3621 if ( HasFlag(wxLC_REPORT
) )
3623 // all lines have the same height
3624 int lineHeight
= GetLineHeight();
3626 // scroll one line per step
3627 m_yScroll
= lineHeight
;
3629 size_t lineCount
= GetItemCount();
3630 int entireHeight
= lineCount
*lineHeight
+ LINE_SPACING
;
3632 m_linesPerPage
= clientHeight
/ lineHeight
;
3634 ResetVisibleLinesRange();
3636 SetScrollbars( m_xScroll
, m_yScroll
,
3637 (GetHeaderWidth() + m_xScroll
- 1)/m_xScroll
,
3638 (entireHeight
+ m_yScroll
- 1)/m_yScroll
,
3639 GetScrollPos(wxHORIZONTAL
),
3640 GetScrollPos(wxVERTICAL
),
3645 // at first we try without any scrollbar. if the items don't
3646 // fit into the window, we recalculate after subtracting an
3647 // approximated 15 pt for the horizontal scrollbar
3649 clientHeight
-= 4; // sunken frame
3651 int entireWidth
= 0;
3653 for (int tries
= 0; tries
< 2; tries
++)
3660 int currentlyVisibleLines
= 0;
3662 size_t count
= GetItemCount();
3663 for (size_t i
= 0; i
< count
; i
++)
3665 currentlyVisibleLines
++;
3666 wxListLineData
*line
= GetLine(i
);
3667 line
->CalculateSize( &dc
, iconSpacing
);
3668 line
->SetPosition( x
, y
, clientWidth
, iconSpacing
);
3670 wxSize sizeLine
= GetLineSize(i
);
3672 if ( maxWidth
< sizeLine
.x
)
3673 maxWidth
= sizeLine
.x
;
3676 if (currentlyVisibleLines
> m_linesPerPage
)
3677 m_linesPerPage
= currentlyVisibleLines
;
3679 // assume that the size of the next one is the same... (FIXME)
3680 if ( y
+ sizeLine
.y
- 6 >= clientHeight
)
3682 currentlyVisibleLines
= 0;
3685 entireWidth
+= maxWidth
+6;
3688 if ( i
== count
- 1 )
3689 entireWidth
+= maxWidth
;
3690 if ((tries
== 0) && (entireWidth
> clientWidth
))
3692 clientHeight
-= 15; // scrollbar height
3694 currentlyVisibleLines
= 0;
3697 if ( i
== count
- 1 )
3698 tries
= 1; // everything fits, no second try required
3702 int scroll_pos
= GetScrollPos( wxHORIZONTAL
);
3703 SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE
);
3706 // FIXME: why should we call it from here?
3712 void wxListMainWindow::RefreshAll()
3717 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3720 headerWin
->m_dirty
= FALSE
;
3721 headerWin
->Refresh();
3725 void wxListMainWindow::UpdateCurrent()
3727 if ( !HasCurrent() && !IsEmpty() )
3732 if ( m_current
!= (size_t)-1 )
3734 OnFocusLine( m_current
);
3738 long wxListMainWindow::GetNextItem( long item
,
3739 int WXUNUSED(geometry
),
3743 max
= GetItemCount();
3744 wxCHECK_MSG( (ret
== -1) || (ret
< max
), -1,
3745 _T("invalid listctrl index in GetNextItem()") );
3747 // notice that we start with the next item (or the first one if item == -1)
3748 // and this is intentional to allow writing a simple loop to iterate over
3749 // all selected items
3753 // this is not an error because the index was ok initially, just no
3764 size_t count
= GetItemCount();
3765 for ( size_t line
= (size_t)ret
; line
< count
; line
++ )
3767 if ( (state
& wxLIST_STATE_FOCUSED
) && (line
== m_current
) )
3770 if ( (state
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) )
3777 // ----------------------------------------------------------------------------
3779 // ----------------------------------------------------------------------------
3781 void wxListMainWindow::DeleteItem( long lindex
)
3783 size_t count
= GetItemCount();
3785 wxCHECK_RET( (lindex
>= 0) && ((size_t)lindex
< count
),
3786 _T("invalid item index in DeleteItem") );
3788 size_t index
= (size_t)lindex
;
3792 // select the next item when the selected one is deleted
3793 if ( m_current
== index
)
3795 // the last valid index after deleting the item will be count-2
3796 if ( m_current
== count
- 1 )
3802 SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
);
3804 if ( InReportView() )
3806 ResetVisibleLinesRange();
3813 m_selStore
.OnItemDelete(index
);
3817 m_lines
.RemoveAt( index
);
3821 RefreshAfter(index
);
3824 void wxListMainWindow::DeleteColumn( int col
)
3826 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3828 wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") );
3831 m_columns
.DeleteNode( node
);
3834 void wxListMainWindow::DeleteAllItems()
3838 // nothing to do - in particular, don't send the event
3844 // to make the deletion of all items faster, we don't send the
3845 // notifications for each item deletion in this case but only one event
3846 // for all of them: this is compatible with wxMSW and documented in
3847 // DeleteAllItems() description
3849 wxListEvent
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() );
3850 event
.SetEventObject( GetParent() );
3851 GetParent()->GetEventHandler()->ProcessEvent( event
);
3860 if ( InReportView() )
3862 ResetVisibleLinesRange();
3867 // NB: don't just set m_dirty to TRUE here as RecalculatePositions()
3868 // doesn't do anything if the control is empty and so we won't be
3873 void wxListMainWindow::DeleteEverything()
3880 // ----------------------------------------------------------------------------
3881 // scanning for an item
3882 // ----------------------------------------------------------------------------
3884 void wxListMainWindow::EnsureVisible( long index
)
3886 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3887 _T("invalid index in EnsureVisible") );
3889 // We have to call this here because the label in question might just have
3890 // been added and no screen update taken place.
3894 size_t oldCurrent
= m_current
;
3895 m_current
= (size_t)index
;
3897 m_current
= oldCurrent
;
3900 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) )
3907 size_t count
= GetItemCount();
3908 for ( size_t i
= (size_t)pos
; i
< count
; i
++ )
3910 wxListLineData
*line
= GetLine(i
);
3911 if ( line
->GetText(0) == tmp
)
3918 long wxListMainWindow::FindItem(long start
, long data
)
3924 size_t count
= GetItemCount();
3925 for (size_t i
= (size_t)pos
; i
< count
; i
++)
3927 wxListLineData
*line
= GetLine(i
);
3929 line
->GetItem( 0, item
);
3930 if (item
.m_data
== data
)
3937 long wxListMainWindow::HitTest( int x
, int y
, int &flags
)
3939 CalcUnscrolledPosition( x
, y
, &x
, &y
);
3941 if ( HasFlag(wxLC_REPORT
) )
3943 size_t current
= y
/ GetLineHeight();
3944 flags
= HitTestLine(current
, x
, y
);
3950 // TODO: optimize it too! this is less simple than for report view but
3951 // enumerating all items is still not a way to do it!!
3952 size_t count
= GetItemCount();
3953 for ( size_t current
= 0; current
< count
; current
++ )
3955 flags
= HitTestLine(current
, x
, y
);
3964 // ----------------------------------------------------------------------------
3966 // ----------------------------------------------------------------------------
3968 void wxListMainWindow::InsertItem( wxListItem
&item
)
3970 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
3972 size_t count
= GetItemCount();
3973 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
<= count
,
3974 _T("invalid item index") );
3976 size_t id
= item
.m_itemId
;
3981 if ( HasFlag(wxLC_REPORT
) )
3983 else if ( HasFlag(wxLC_LIST
) )
3985 else if ( HasFlag(wxLC_ICON
) )
3987 else if ( HasFlag(wxLC_SMALL_ICON
) )
3988 mode
= wxLC_ICON
; // no typo
3991 wxFAIL_MSG( _T("unknown mode") );
3994 wxListLineData
*line
= new wxListLineData(this);
3996 line
->SetItem( 0, item
);
3998 m_lines
.Insert( line
, id
);
4001 RefreshLines(id
, GetItemCount() - 1);
4004 void wxListMainWindow::InsertColumn( long col
, wxListItem
&item
)
4007 if ( HasFlag(wxLC_REPORT
) )
4009 if (item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
4010 item
.m_width
= GetTextLength( item
.m_text
);
4011 wxListHeaderData
*column
= new wxListHeaderData( item
);
4012 if ((col
>= 0) && (col
< (int)m_columns
.GetCount()))
4014 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
4015 m_columns
.Insert( node
, column
);
4019 m_columns
.Append( column
);
4024 // ----------------------------------------------------------------------------
4026 // ----------------------------------------------------------------------------
4028 wxListCtrlCompare list_ctrl_compare_func_2
;
4029 long list_ctrl_compare_data
;
4031 int LINKAGEMODE
list_ctrl_compare_func_1( wxListLineData
**arg1
, wxListLineData
**arg2
)
4033 wxListLineData
*line1
= *arg1
;
4034 wxListLineData
*line2
= *arg2
;
4036 line1
->GetItem( 0, item
);
4037 long data1
= item
.m_data
;
4038 line2
->GetItem( 0, item
);
4039 long data2
= item
.m_data
;
4040 return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data
);
4043 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data
)
4045 list_ctrl_compare_func_2
= fn
;
4046 list_ctrl_compare_data
= data
;
4047 m_lines
.Sort( list_ctrl_compare_func_1
);
4051 // ----------------------------------------------------------------------------
4053 // ----------------------------------------------------------------------------
4055 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
)
4057 // update our idea of which lines are shown when we redraw the window the
4059 ResetVisibleLinesRange();
4062 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4063 wxScrolledWindow::OnScroll(event
);
4065 HandleOnScroll( event
);
4068 if ( event
.GetOrientation() == wxHORIZONTAL
&& HasHeader() )
4070 wxListCtrl
* lc
= GetListCtrl();
4071 wxCHECK_RET( lc
, _T("no listctrl window?") );
4073 lc
->m_headerWin
->Refresh() ;
4075 lc
->m_headerWin
->MacUpdateImmediately() ;
4080 int wxListMainWindow::GetCountPerPage() const
4082 if ( !m_linesPerPage
)
4084 wxConstCast(this, wxListMainWindow
)->
4085 m_linesPerPage
= GetClientSize().y
/ GetLineHeight();
4088 return m_linesPerPage
;
4091 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
)
4093 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") );
4095 if ( m_lineFrom
== (size_t)-1 )
4097 size_t count
= GetItemCount();
4100 m_lineFrom
= GetScrollPos(wxVERTICAL
);
4102 // this may happen if SetScrollbars() hadn't been called yet
4103 if ( m_lineFrom
>= count
)
4104 m_lineFrom
= count
- 1;
4106 // we redraw one extra line but this is needed to make the redrawing
4107 // logic work when there is a fractional number of lines on screen
4108 m_lineTo
= m_lineFrom
+ m_linesPerPage
;
4109 if ( m_lineTo
>= count
)
4110 m_lineTo
= count
- 1;
4112 else // empty control
4115 m_lineTo
= (size_t)-1;
4119 wxASSERT_MSG( IsEmpty() ||
4120 (m_lineFrom
<= m_lineTo
&& m_lineTo
< GetItemCount()),
4121 _T("GetVisibleLinesRange() returns incorrect result") );
4129 // -------------------------------------------------------------------------------------
4131 // -------------------------------------------------------------------------------------
4133 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
4135 wxListItem::wxListItem()
4144 m_format
= wxLIST_FORMAT_CENTRE
;
4150 void wxListItem::Clear()
4159 m_format
= wxLIST_FORMAT_CENTRE
;
4166 void wxListItem::ClearAttributes()
4175 // -------------------------------------------------------------------------------------
4177 // -------------------------------------------------------------------------------------
4179 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
4181 wxListEvent::wxListEvent( wxEventType commandType
, int id
)
4182 : wxNotifyEvent( commandType
, id
)
4188 m_cancelled
= FALSE
;
4193 void wxListEvent::CopyObject(wxObject
& object_dest
) const
4195 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
4197 wxNotifyEvent::CopyObject(object_dest
);
4199 obj
->m_code
= m_code
;
4200 obj
->m_itemIndex
= m_itemIndex
;
4201 obj
->m_oldItemIndex
= m_oldItemIndex
;
4203 obj
->m_cancelled
= m_cancelled
;
4204 obj
->m_pointDrag
= m_pointDrag
;
4205 obj
->m_item
.m_mask
= m_item
.m_mask
;
4206 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
4207 obj
->m_item
.m_col
= m_item
.m_col
;
4208 obj
->m_item
.m_state
= m_item
.m_state
;
4209 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
4210 obj
->m_item
.m_text
= m_item
.m_text
;
4211 obj
->m_item
.m_image
= m_item
.m_image
;
4212 obj
->m_item
.m_data
= m_item
.m_data
;
4213 obj
->m_item
.m_format
= m_item
.m_format
;
4214 obj
->m_item
.m_width
= m_item
.m_width
;
4216 if ( m_item
.HasAttributes() )
4218 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
4222 // -------------------------------------------------------------------------------------
4224 // -------------------------------------------------------------------------------------
4226 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
4228 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
)
4229 EVT_SIZE(wxListCtrl::OnSize
)
4230 EVT_IDLE(wxListCtrl::OnIdle
)
4233 wxListCtrl::wxListCtrl()
4235 m_imageListNormal
= (wxImageList
*) NULL
;
4236 m_imageListSmall
= (wxImageList
*) NULL
;
4237 m_imageListState
= (wxImageList
*) NULL
;
4239 m_ownsImageListNormal
=
4240 m_ownsImageListSmall
=
4241 m_ownsImageListState
= FALSE
;
4243 m_mainWin
= (wxListMainWindow
*) NULL
;
4244 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4247 wxListCtrl::~wxListCtrl()
4250 m_mainWin
->ResetCurrent();
4252 if (m_ownsImageListNormal
)
4253 delete m_imageListNormal
;
4254 if (m_ownsImageListSmall
)
4255 delete m_imageListSmall
;
4256 if (m_ownsImageListState
)
4257 delete m_imageListState
;
4260 void wxListCtrl::CreateHeaderWindow()
4262 m_headerWin
= new wxListHeaderWindow
4264 this, -1, m_mainWin
,
4266 wxSize(GetClientSize().x
, HEADER_HEIGHT
),
4271 bool wxListCtrl::Create(wxWindow
*parent
,
4276 const wxValidator
&validator
,
4277 const wxString
&name
)
4281 m_imageListState
= (wxImageList
*) NULL
;
4282 m_ownsImageListNormal
=
4283 m_ownsImageListSmall
=
4284 m_ownsImageListState
= FALSE
;
4286 m_mainWin
= (wxListMainWindow
*) NULL
;
4287 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4289 if ( !(style
& wxLC_MASK_TYPE
) )
4291 style
= style
| wxLC_LIST
;
4294 if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name
) )
4297 // don't create the inner window with the border
4298 style
&= ~wxSUNKEN_BORDER
;
4300 m_mainWin
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style
);
4302 if ( HasFlag(wxLC_REPORT
) )
4304 CreateHeaderWindow();
4306 if ( HasFlag(wxLC_NO_HEADER
) )
4308 // VZ: why do we create it at all then?
4309 m_headerWin
->Show( FALSE
);
4316 void wxListCtrl::SetSingleStyle( long style
, bool add
)
4318 wxASSERT_MSG( !(style
& wxLC_VIRTUAL
),
4319 _T("wxLC_VIRTUAL can't be [un]set") );
4321 long flag
= GetWindowStyle();
4325 if (style
& wxLC_MASK_TYPE
)
4326 flag
&= ~(wxLC_MASK_TYPE
| wxLC_VIRTUAL
);
4327 if (style
& wxLC_MASK_ALIGN
)
4328 flag
&= ~wxLC_MASK_ALIGN
;
4329 if (style
& wxLC_MASK_SORT
)
4330 flag
&= ~wxLC_MASK_SORT
;
4342 SetWindowStyleFlag( flag
);
4345 void wxListCtrl::SetWindowStyleFlag( long flag
)
4349 m_mainWin
->DeleteEverything();
4353 GetClientSize( &width
, &height
);
4355 if (flag
& wxLC_REPORT
)
4357 if (!HasFlag(wxLC_REPORT
))
4361 CreateHeaderWindow();
4363 if (HasFlag(wxLC_NO_HEADER
))
4364 m_headerWin
->Show( FALSE
);
4368 if (flag
& wxLC_NO_HEADER
)
4369 m_headerWin
->Show( FALSE
);
4371 m_headerWin
->Show( TRUE
);
4377 if ( m_mainWin
->HasHeader() )
4379 m_headerWin
->Show( FALSE
);
4384 wxWindow::SetWindowStyleFlag( flag
);
4387 bool wxListCtrl::GetColumn(int col
, wxListItem
&item
) const
4389 m_mainWin
->GetColumn( col
, item
);
4393 bool wxListCtrl::SetColumn( int col
, wxListItem
& item
)
4395 m_mainWin
->SetColumn( col
, item
);
4399 int wxListCtrl::GetColumnWidth( int col
) const
4401 return m_mainWin
->GetColumnWidth( col
);
4404 bool wxListCtrl::SetColumnWidth( int col
, int width
)
4406 m_mainWin
->SetColumnWidth( col
, width
);
4410 int wxListCtrl::GetCountPerPage() const
4412 return m_mainWin
->GetCountPerPage(); // different from Windows ?
4415 bool wxListCtrl::GetItem( wxListItem
&info
) const
4417 m_mainWin
->GetItem( info
);
4421 bool wxListCtrl::SetItem( wxListItem
&info
)
4423 m_mainWin
->SetItem( info
);
4427 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId
)
4430 info
.m_text
= label
;
4431 info
.m_mask
= wxLIST_MASK_TEXT
;
4432 info
.m_itemId
= index
;
4436 info
.m_image
= imageId
;
4437 info
.m_mask
|= wxLIST_MASK_IMAGE
;
4439 m_mainWin
->SetItem(info
);
4443 int wxListCtrl::GetItemState( long item
, long stateMask
) const
4445 return m_mainWin
->GetItemState( item
, stateMask
);
4448 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask
)
4450 m_mainWin
->SetItemState( item
, state
, stateMask
);
4454 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) )
4457 info
.m_image
= image
;
4458 info
.m_mask
= wxLIST_MASK_IMAGE
;
4459 info
.m_itemId
= item
;
4460 m_mainWin
->SetItem( info
);
4464 wxString
wxListCtrl::GetItemText( long item
) const
4467 info
.m_itemId
= item
;
4468 m_mainWin
->GetItem( info
);
4472 void wxListCtrl::SetItemText( long item
, const wxString
&str
)
4475 info
.m_mask
= wxLIST_MASK_TEXT
;
4476 info
.m_itemId
= item
;
4478 m_mainWin
->SetItem( info
);
4481 long wxListCtrl::GetItemData( long item
) const
4484 info
.m_itemId
= item
;
4485 m_mainWin
->GetItem( info
);
4489 bool wxListCtrl::SetItemData( long item
, long data
)
4492 info
.m_mask
= wxLIST_MASK_DATA
;
4493 info
.m_itemId
= item
;
4495 m_mainWin
->SetItem( info
);
4499 bool wxListCtrl::GetItemRect( long item
, wxRect
&rect
, int WXUNUSED(code
) ) const
4501 m_mainWin
->GetItemRect( item
, rect
);
4505 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos
) const
4507 m_mainWin
->GetItemPosition( item
, pos
);
4511 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) )
4516 int wxListCtrl::GetItemCount() const
4518 return m_mainWin
->GetItemCount();
4521 int wxListCtrl::GetColumnCount() const
4523 return m_mainWin
->GetColumnCount();
4526 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall
)
4528 m_mainWin
->SetItemSpacing( spacing
, isSmall
);
4531 int wxListCtrl::GetItemSpacing( bool isSmall
) const
4533 return m_mainWin
->GetItemSpacing( isSmall
);
4536 int wxListCtrl::GetSelectedItemCount() const
4538 return m_mainWin
->GetSelectedItemCount();
4541 wxColour
wxListCtrl::GetTextColour() const
4543 return GetForegroundColour();
4546 void wxListCtrl::SetTextColour(const wxColour
& col
)
4548 SetForegroundColour(col
);
4551 long wxListCtrl::GetTopItem() const
4556 long wxListCtrl::GetNextItem( long item
, int geom
, int state
) const
4558 return m_mainWin
->GetNextItem( item
, geom
, state
);
4561 wxImageList
*wxListCtrl::GetImageList(int which
) const
4563 if (which
== wxIMAGE_LIST_NORMAL
)
4565 return m_imageListNormal
;
4567 else if (which
== wxIMAGE_LIST_SMALL
)
4569 return m_imageListSmall
;
4571 else if (which
== wxIMAGE_LIST_STATE
)
4573 return m_imageListState
;
4575 return (wxImageList
*) NULL
;
4578 void wxListCtrl::SetImageList( wxImageList
*imageList
, int which
)
4580 if ( which
== wxIMAGE_LIST_NORMAL
)
4582 if (m_ownsImageListNormal
) delete m_imageListNormal
;
4583 m_imageListNormal
= imageList
;
4584 m_ownsImageListNormal
= FALSE
;
4586 else if ( which
== wxIMAGE_LIST_SMALL
)
4588 if (m_ownsImageListSmall
) delete m_imageListSmall
;
4589 m_imageListSmall
= imageList
;
4590 m_ownsImageListSmall
= FALSE
;
4592 else if ( which
== wxIMAGE_LIST_STATE
)
4594 if (m_ownsImageListState
) delete m_imageListState
;
4595 m_imageListState
= imageList
;
4596 m_ownsImageListState
= FALSE
;
4599 m_mainWin
->SetImageList( imageList
, which
);
4602 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
4604 SetImageList(imageList
, which
);
4605 if ( which
== wxIMAGE_LIST_NORMAL
)
4606 m_ownsImageListNormal
= TRUE
;
4607 else if ( which
== wxIMAGE_LIST_SMALL
)
4608 m_ownsImageListSmall
= TRUE
;
4609 else if ( which
== wxIMAGE_LIST_STATE
)
4610 m_ownsImageListState
= TRUE
;
4613 bool wxListCtrl::Arrange( int WXUNUSED(flag
) )
4618 bool wxListCtrl::DeleteItem( long item
)
4620 m_mainWin
->DeleteItem( item
);
4624 bool wxListCtrl::DeleteAllItems()
4626 m_mainWin
->DeleteAllItems();
4630 bool wxListCtrl::DeleteAllColumns()
4632 size_t count
= m_mainWin
->m_columns
.GetCount();
4633 for ( size_t n
= 0; n
< count
; n
++ )
4639 void wxListCtrl::ClearAll()
4641 m_mainWin
->DeleteEverything();
4644 bool wxListCtrl::DeleteColumn( int col
)
4646 m_mainWin
->DeleteColumn( col
);
4650 void wxListCtrl::Edit( long item
)
4652 m_mainWin
->EditLabel( item
);
4655 bool wxListCtrl::EnsureVisible( long item
)
4657 m_mainWin
->EnsureVisible( item
);
4661 long wxListCtrl::FindItem( long start
, const wxString
& str
, bool partial
)
4663 return m_mainWin
->FindItem( start
, str
, partial
);
4666 long wxListCtrl::FindItem( long start
, long data
)
4668 return m_mainWin
->FindItem( start
, data
);
4671 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
),
4672 int WXUNUSED(direction
))
4677 long wxListCtrl::HitTest( const wxPoint
&point
, int &flags
)
4679 return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags
);
4682 long wxListCtrl::InsertItem( wxListItem
& info
)
4684 m_mainWin
->InsertItem( info
);
4685 return info
.m_itemId
;
4688 long wxListCtrl::InsertItem( long index
, const wxString
&label
)
4691 info
.m_text
= label
;
4692 info
.m_mask
= wxLIST_MASK_TEXT
;
4693 info
.m_itemId
= index
;
4694 return InsertItem( info
);
4697 long wxListCtrl::InsertItem( long index
, int imageIndex
)
4700 info
.m_mask
= wxLIST_MASK_IMAGE
;
4701 info
.m_image
= imageIndex
;
4702 info
.m_itemId
= index
;
4703 return InsertItem( info
);
4706 long wxListCtrl::InsertItem( long index
, const wxString
&label
, int imageIndex
)
4709 info
.m_text
= label
;
4710 info
.m_image
= imageIndex
;
4711 info
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_IMAGE
;
4712 info
.m_itemId
= index
;
4713 return InsertItem( info
);
4716 long wxListCtrl::InsertColumn( long col
, wxListItem
&item
)
4718 wxASSERT( m_headerWin
);
4719 m_mainWin
->InsertColumn( col
, item
);
4720 m_headerWin
->Refresh();
4725 long wxListCtrl::InsertColumn( long col
, const wxString
&heading
,
4726 int format
, int width
)
4729 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
4730 item
.m_text
= heading
;
4733 item
.m_mask
|= wxLIST_MASK_WIDTH
;
4734 item
.m_width
= width
;
4736 item
.m_format
= format
;
4738 return InsertColumn( col
, item
);
4741 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) )
4747 // fn is a function which takes 3 long arguments: item1, item2, data.
4748 // item1 is the long data associated with a first item (NOT the index).
4749 // item2 is the long data associated with a second item (NOT the index).
4750 // data is the same value as passed to SortItems.
4751 // The return value is a negative number if the first item should precede the second
4752 // item, a positive number of the second item should precede the first,
4753 // or zero if the two items are equivalent.
4754 // data is arbitrary data to be passed to the sort function.
4756 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data
)
4758 m_mainWin
->SortItems( fn
, data
);
4762 // ----------------------------------------------------------------------------
4764 // ----------------------------------------------------------------------------
4766 void wxListCtrl::OnSize(wxSizeEvent
& event
)
4772 GetClientSize( &cw
, &ch
);
4774 if ( m_mainWin
->HasHeader() )
4776 m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT
);
4777 m_mainWin
->SetSize( 0, HEADER_HEIGHT
+ 1, cw
, ch
- HEADER_HEIGHT
- 1 );
4779 else // no header window
4781 m_mainWin
->SetSize( 0, 0, cw
, ch
);
4784 m_mainWin
->RecalculatePositions();
4787 void wxListCtrl::OnIdle( wxIdleEvent
& event
)
4791 // do it only if needed
4792 if ( !m_mainWin
->m_dirty
)
4795 m_mainWin
->RecalculatePositions();
4798 // ----------------------------------------------------------------------------
4800 // ----------------------------------------------------------------------------
4802 bool wxListCtrl::SetBackgroundColour( const wxColour
&colour
)
4806 m_mainWin
->SetBackgroundColour( colour
);
4807 m_mainWin
->m_dirty
= TRUE
;
4813 bool wxListCtrl::SetForegroundColour( const wxColour
&colour
)
4815 if ( !wxWindow::SetForegroundColour( colour
) )
4820 m_mainWin
->SetForegroundColour( colour
);
4821 m_mainWin
->m_dirty
= TRUE
;
4826 m_headerWin
->SetForegroundColour( colour
);
4832 bool wxListCtrl::SetFont( const wxFont
&font
)
4834 if ( !wxWindow::SetFont( font
) )
4839 m_mainWin
->SetFont( font
);
4840 m_mainWin
->m_dirty
= TRUE
;
4845 m_headerWin
->SetFont( font
);
4851 // ----------------------------------------------------------------------------
4852 // methods forwarded to m_mainWin
4853 // ----------------------------------------------------------------------------
4855 #if wxUSE_DRAG_AND_DROP
4857 void wxListCtrl::SetDropTarget( wxDropTarget
*dropTarget
)
4859 m_mainWin
->SetDropTarget( dropTarget
);
4862 wxDropTarget
*wxListCtrl::GetDropTarget() const
4864 return m_mainWin
->GetDropTarget();
4867 #endif // wxUSE_DRAG_AND_DROP
4869 bool wxListCtrl::SetCursor( const wxCursor
&cursor
)
4871 return m_mainWin
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
;
4874 wxColour
wxListCtrl::GetBackgroundColour() const
4876 return m_mainWin
? m_mainWin
->GetBackgroundColour() : wxColour();
4879 wxColour
wxListCtrl::GetForegroundColour() const
4881 return m_mainWin
? m_mainWin
->GetForegroundColour() : wxColour();
4884 bool wxListCtrl::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4887 return m_mainWin
->PopupMenu( menu
, x
, y
);
4890 #endif // wxUSE_MENUS
4893 void wxListCtrl::SetFocus()
4895 /* The test in window.cpp fails as we are a composite
4896 window, so it checks against "this", but not m_mainWin. */
4897 if ( FindFocus() != this )
4898 m_mainWin
->SetFocus();
4901 // ----------------------------------------------------------------------------
4902 // virtual list control support
4903 // ----------------------------------------------------------------------------
4905 wxString
wxListCtrl::OnGetItemText(long item
, long col
) const
4907 // this is a pure virtual function, in fact - which is not really pure
4908 // because the controls which are not virtual don't need to implement it
4909 wxFAIL_MSG( _T("not supposed to be called") );
4911 return wxEmptyString
;
4914 int wxListCtrl::OnGetItemImage(long item
) const
4917 wxFAIL_MSG( _T("not supposed to be called") );
4922 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long item
) const
4924 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
4925 _T("invalid item index in OnGetItemAttr()") );
4927 // no attributes by default
4931 void wxListCtrl::SetItemCount(long count
)
4933 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4935 m_mainWin
->SetItemCount(count
);
4938 void wxListCtrl::RefreshItem(long item
)
4940 m_mainWin
->RefreshLine(item
);
4943 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
)
4945 m_mainWin
->RefreshLines(itemFrom
, itemTo
);
4948 #endif // wxUSE_LISTCTRL