1 /////////////////////////////////////////////////////////////////////////////
2 // Name: generic/listctrl.cpp
3 // Purpose: generic implementation of wxListCtrl
4 // Author: Robert Roebling
5 // Vadim Zeitlin (virtual list control support)
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
12 FIXME for virtual list controls
14 +1. clicking on the item with a mouse is awfully slow, what is going on?
15 note that selecting with keyboard seems to be much faster
16 => fixed HighlightAll() - iterating over 1000000 items *is* slow
18 2. background colour is wrong?
22 TODO for better virtual list control support:
24 1. less dumb line caching, we should cache at least all those visible
25 in the control itself and probably twice as many (we might also need to
26 cache the first one always for geometry calculations?)
28 +2. storing selections: we can't use an array to store the selected indices
29 like right now as selecting all in a control with 1000000 items is not
30 doable like this - instead, store selections as collection of individual
35 3. we need to implement searching/sorting somehow
37 4. the idea of storing the line index in the line itself is really stupid,
38 we shouldn't need it - but for this we have to get rid of all calles to
39 wxListLineData::GetFoo() and replace them with something like
41 ... we have it ourselves ...
47 5. attributes support: we need OnGetItemAttr() as well!
50 // ============================================================================
52 // ============================================================================
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
59 #pragma implementation "listctrl.h"
60 #pragma implementation "listctrlbase.h"
63 // For compilers that support precompilation, includes "wx.h".
64 #include "wx/wxprec.h"
72 #include "wx/dcscreen.h"
74 #include "wx/listctrl.h"
75 #include "wx/imaglist.h"
76 #include "wx/dynarray.h"
80 #include "wx/gtk/win_gtk.h"
83 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
)
88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
)
89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
)
90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
)
91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
)
92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
)
93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
)
94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
)
95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
)
96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
)
97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
)
98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
)
99 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
)
100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
)
101 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
)
102 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
)
103 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
)
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 // the height of the header window (FIXME: should depend on its font!)
110 static const int HEADER_HEIGHT
= 23;
112 // the scrollbar units
113 static const int SCROLL_UNIT_X
= 15;
114 static const int SCROLL_UNIT_Y
= 15;
116 // the spacing between the lines (in report mode)
117 static const int LINE_SPACING
= 0;
119 // extra margins around the text label
120 static const int EXTRA_WIDTH
= 3;
121 static const int EXTRA_HEIGHT
= 4;
123 // offset for the header window
124 static const int HEADER_OFFSET_X
= 1;
125 static const int HEADER_OFFSET_Y
= 1;
127 // when autosizing the columns, add some slack
128 static const int AUTOSIZE_COL_MARGIN
= 10;
130 // default and minimal widths for the header columns
131 static const int WIDTH_COL_DEFAULT
= 80;
132 static const int WIDTH_COL_MIN
= 10;
134 // ============================================================================
136 // ============================================================================
138 // ----------------------------------------------------------------------------
140 // ----------------------------------------------------------------------------
142 int CMPFUNC_CONV
wxSizeTCmpFn(size_t n1
, size_t n2
) { return n1
- n2
; }
144 WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray
);
146 // this class is used to store the selected items in the virtual list control
147 // (but it is not tied to list control and so can be used with other controls
148 // such as wxListBox in wxUniv)
150 // the idea is to make it really smart later (i.e. store the selections as an
151 // array of ranes + individual items) but, as I don't have time to do it now
152 // (this would require writing code to merge/break ranges and much more) keep
153 // it simple but define a clean interface to it which allows it to be made
155 class WXDLLEXPORT wxSelectionStore
158 wxSelectionStore() : m_itemsSel(wxSizeTCmpFn
) { Init(); }
160 // set the total number of items we handle
161 void SetItemCount(size_t count
) { m_count
= count
; }
163 // special case of SetItemCount(0)
164 void Clear() { m_itemsSel
.Clear(); m_count
= 0; }
166 // must be called when a new item is inserted/added
167 void OnItemAdd(size_t item
) { wxFAIL_MSG( _T("TODO") ); }
169 // must be called when an item is deleted
170 void OnItemDelete(size_t item
);
172 // select one item, use SelectRange() insted if possible!
174 // returns true if the items selection really changed
175 bool SelectItem(size_t item
, bool select
= TRUE
);
177 // select the range of items
178 void SelectRange(size_t itemFrom
, size_t itemTo
, bool select
= TRUE
);
180 // return true if the given item is selected
181 bool IsSelected(size_t item
) const;
183 // return the total number of selected items
184 size_t GetSelectedCount() const
186 return m_defaultState
? m_count
- m_itemsSel
.GetCount()
187 : m_itemsSel
.GetCount();
192 void Init() { m_defaultState
= FALSE
; }
194 // the total number of items we handle
197 // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
198 // there are more selected items than non selected ones - this allows to
199 // handle selection of all items efficiently
202 // the array of items whose selection state is different from default
203 wxIndexArray m_itemsSel
;
205 DECLARE_NO_COPY_CLASS(wxSelectionStore
)
208 //-----------------------------------------------------------------------------
209 // wxListItemData (internal)
210 //-----------------------------------------------------------------------------
212 class WXDLLEXPORT wxListItemData
215 wxListItemData(wxListMainWindow
*owner
);
218 void SetItem( const wxListItem
&info
);
219 void SetImage( int image
) { m_image
= image
; }
220 void SetData( long data
) { m_data
= data
; }
221 void SetPosition( int x
, int y
);
222 void SetSize( int width
, int height
);
224 bool HasText() const { return !m_text
.empty(); }
225 const wxString
& GetText() const { return m_text
; }
226 void SetText(const wxString
& text
) { m_text
= text
; }
228 // we can't use empty string for measuring the string width/height, so
229 // always return something
230 wxString
GetTextForMeasuring() const
232 wxString s
= GetText();
239 bool IsHit( int x
, int y
) const;
243 int GetWidth() const;
244 int GetHeight() const;
246 int GetImage() const { return m_image
; }
247 bool HasImage() const { return GetImage() != -1; }
249 void GetItem( wxListItem
&info
) const;
251 void SetAttr(wxListItemAttr
*attr
) { m_attr
= attr
; }
252 wxListItemAttr
*GetAttr() const { return m_attr
; }
255 // the item image or -1
258 // user data associated with the item
261 // the item coordinates are not used in report mode, instead this pointer
262 // is NULL and the owner window is used to retrieve the item position and
266 // the list ctrl we are in
267 wxListMainWindow
*m_owner
;
269 // custom attributes or NULL
270 wxListItemAttr
*m_attr
;
273 // common part of all ctors
279 //-----------------------------------------------------------------------------
280 // wxListHeaderData (internal)
281 //-----------------------------------------------------------------------------
283 class WXDLLEXPORT wxListHeaderData
: public wxObject
297 wxListHeaderData( const wxListItem
&info
);
298 void SetItem( const wxListItem
&item
);
299 void SetPosition( int x
, int y
);
300 void SetWidth( int w
);
301 void SetFormat( int format
);
302 void SetHeight( int h
);
303 bool HasImage() const;
305 bool HasText() const { return !m_text
.empty(); }
306 const wxString
& GetText() const { return m_text
; }
307 void SetText(const wxString
& text
) { m_text
= text
; }
309 void GetItem( wxListItem
&item
);
311 bool IsHit( int x
, int y
) const;
312 int GetImage() const;
313 int GetWidth() const;
314 int GetFormat() const;
317 DECLARE_DYNAMIC_CLASS(wxListHeaderData
);
320 //-----------------------------------------------------------------------------
321 // wxListLineData (internal)
322 //-----------------------------------------------------------------------------
324 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
);
325 #include "wx/listimpl.cpp"
326 WX_DEFINE_LIST(wxListItemDataList
);
328 class WXDLLEXPORT wxListLineData
331 // the list of subitems: only may have more than one item in report mode
332 wxListItemDataList m_items
;
334 // this is not used in report view
346 // the part to be highlighted
347 wxRect m_rectHighlight
;
350 // is this item selected? [NB: not used in virtual mode]
353 // back pointer to the list ctrl
354 wxListMainWindow
*m_owner
;
357 wxListLineData(wxListMainWindow
*owner
);
359 ~wxListLineData() { delete m_gi
; }
361 // are we in report mode?
362 inline bool InReportView() const;
364 // are we in virtual report mode?
365 inline bool IsVirtual() const;
367 // these 2 methods shouldn't be called for report view controls, in that
368 // case we determine our position/size ourselves
370 // calculate the size of the line
371 void CalculateSize( wxDC
*dc
, int spacing
);
373 // remember the position this line appears at
374 void SetPosition( int x
, int y
, int window_width
, int spacing
);
378 void SetImage( int image
) { SetImage(0, image
); }
379 int GetImage() const { return GetImage(0); }
380 bool HasImage() const { return GetImage() != -1; }
381 bool HasText() const { return !GetText(0).empty(); }
383 void SetItem( int index
, const wxListItem
&info
);
384 void GetItem( int index
, wxListItem
&info
);
386 wxString
GetText(int index
) const;
387 void SetText( int index
, const wxString s
);
389 wxListItemAttr
*GetAttr() const;
390 void SetAttr(wxListItemAttr
*attr
);
392 // return true if the highlighting really changed
393 bool Highlight( bool on
);
395 void ReverseHighlight();
397 bool IsHighlighted() const
399 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
401 return m_highlighted
;
404 // draw the line on the given DC in icon/list mode
405 void Draw( wxDC
*dc
);
407 // the same in report mode
408 void DrawInReportMode( wxDC
*dc
,
410 const wxRect
& rectHL
,
414 // set the line to contain num items (only can be > 1 in report mode)
415 void InitItems( int num
);
417 // get the mode (i.e. style) of the list control
418 inline int GetMode() const;
420 void SetAttributes(wxDC
*dc
,
421 const wxListItemAttr
*attr
,
422 const wxColour
& colText
,
426 // these are only used by GetImage/SetImage above, we don't support images
427 // with subitems at the public API level yet
428 void SetImage( int index
, int image
);
429 int GetImage( int index
) const;
432 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
);
433 #include "wx/arrimpl.cpp"
434 WX_DEFINE_OBJARRAY(wxListLineDataArray
);
436 //-----------------------------------------------------------------------------
437 // wxListHeaderWindow (internal)
438 //-----------------------------------------------------------------------------
440 class WXDLLEXPORT wxListHeaderWindow
: public wxWindow
443 wxListMainWindow
*m_owner
;
444 wxCursor
*m_currentCursor
;
445 wxCursor
*m_resizeCursor
;
448 // column being resized
451 // divider line position in logical (unscrolled) coords
454 // minimal position beyond which the divider line can't be dragged in
459 wxListHeaderWindow();
460 virtual ~wxListHeaderWindow();
462 wxListHeaderWindow( wxWindow
*win
,
464 wxListMainWindow
*owner
,
465 const wxPoint
&pos
= wxDefaultPosition
,
466 const wxSize
&size
= wxDefaultSize
,
468 const wxString
&name
= "wxlistctrlcolumntitles" );
470 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
472 void AdjustDC(wxDC
& dc
);
474 void OnPaint( wxPaintEvent
&event
);
475 void OnMouse( wxMouseEvent
&event
);
476 void OnSetFocus( wxFocusEvent
&event
);
482 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
)
483 DECLARE_EVENT_TABLE()
486 //-----------------------------------------------------------------------------
487 // wxListRenameTimer (internal)
488 //-----------------------------------------------------------------------------
490 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
493 wxListMainWindow
*m_owner
;
496 wxListRenameTimer( wxListMainWindow
*owner
);
500 //-----------------------------------------------------------------------------
501 // wxListTextCtrl (internal)
502 //-----------------------------------------------------------------------------
504 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
509 wxListMainWindow
*m_owner
;
510 wxString m_startValue
;
514 wxListTextCtrl( wxWindow
*parent
, const wxWindowID id
,
515 bool *accept
, wxString
*res
, wxListMainWindow
*owner
,
516 const wxString
&value
= "",
517 const wxPoint
&pos
= wxDefaultPosition
, const wxSize
&size
= wxDefaultSize
,
519 const wxValidator
& validator
= wxDefaultValidator
,
520 const wxString
&name
= "listctrltextctrl" );
521 void OnChar( wxKeyEvent
&event
);
522 void OnKeyUp( wxKeyEvent
&event
);
523 void OnKillFocus( wxFocusEvent
&event
);
526 DECLARE_DYNAMIC_CLASS(wxListTextCtrl
);
527 DECLARE_EVENT_TABLE()
530 //-----------------------------------------------------------------------------
531 // wxListMainWindow (internal)
532 //-----------------------------------------------------------------------------
534 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
);
535 #include "wx/listimpl.cpp"
536 WX_DEFINE_LIST(wxListHeaderDataList
);
538 class WXDLLEXPORT wxListMainWindow
: public wxScrolledWindow
542 wxListMainWindow( wxWindow
*parent
,
544 const wxPoint
& pos
= wxDefaultPosition
,
545 const wxSize
& size
= wxDefaultSize
,
547 const wxString
&name
= _T("listctrlmainwindow") );
549 virtual ~wxListMainWindow();
551 bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); }
553 // return true if this is a virtual list control
554 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); }
556 // return true if the control is in report mode
557 bool InReportView() const { return HasFlag(wxLC_REPORT
); }
559 // return true if we are in single selection mode, false if multi sel
560 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); }
562 // do we have a header window?
563 bool HasHeader() const
564 { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); }
566 void HighlightAll( bool on
);
568 // all these functions only do something if the line is currently visible
570 // change the line "selected" state, return TRUE if it really changed
571 bool HighlightLine( size_t line
, bool highlight
= TRUE
);
573 // as HighlightLine() but do it for the range of lines: this is incredibly
574 // more efficient for virtual list controls!
576 // NB: unlike HighlightLine() this one does refresh the lines on screen
577 void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on
= TRUE
);
579 // toggle the line state and refresh it
580 void ReverseHighlight( size_t line
)
581 { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); }
583 // return true if the line is highlighted
584 bool IsHighlighted(size_t line
) const;
586 // refresh one or several lines at once
587 void RefreshLine( size_t line
);
588 void RefreshLines( size_t lineFrom
, size_t lineTo
);
590 // refresh all lines below the given one: the difference with
591 // RefreshLines() is that the index here might not be a valid one (happens
592 // when the last line is deleted)
593 void RefreshAfter( size_t lineFrom
);
595 // the methods which are forwarded to wxListLineData itself in list/icon
596 // modes but are here because the lines don't store their positions in the
599 // get the bound rect for the entire line
600 wxRect
GetLineRect(size_t line
) const;
602 // get the bound rect of the label
603 wxRect
GetLineLabelRect(size_t line
) const;
605 // get the bound rect of the items icon (only may be called if we do have
607 wxRect
GetLineIconRect(size_t line
) const;
609 // get the rect to be highlighted when the item has focus
610 wxRect
GetLineHighlightRect(size_t line
) const;
612 // get the size of the total line rect
613 wxSize
GetLineSize(size_t line
) const
614 { return GetLineRect(line
).GetSize(); }
616 // return the hit code for the corresponding position (in this line)
617 long HitTestLine(size_t line
, int x
, int y
) const;
619 // bring the selected item into view, scrolling to it if necessary
620 void MoveToItem(size_t item
);
622 // bring the current item into view
623 void MoveToFocus() { MoveToItem(m_current
); }
625 void EditLabel( long item
);
626 void OnRenameTimer();
627 void OnRenameAccept();
629 void OnMouse( wxMouseEvent
&event
);
631 // called to switch the selection from the current item to newCurrent,
632 void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event
);
634 void OnChar( wxKeyEvent
&event
);
635 void OnKeyDown( wxKeyEvent
&event
);
636 void OnSetFocus( wxFocusEvent
&event
);
637 void OnKillFocus( wxFocusEvent
&event
);
638 void OnScroll(wxScrollWinEvent
& event
) ;
640 void OnPaint( wxPaintEvent
&event
);
642 void DrawImage( int index
, wxDC
*dc
, int x
, int y
);
643 void GetImageSize( int index
, int &width
, int &height
) const;
644 int GetTextLength( const wxString
&s
) const;
646 void SetImageList( wxImageList
*imageList
, int which
);
647 void SetItemSpacing( int spacing
, bool isSmall
= FALSE
);
648 int GetItemSpacing( bool isSmall
= FALSE
);
650 void SetColumn( int col
, wxListItem
&item
);
651 void SetColumnWidth( int col
, int width
);
652 void GetColumn( int col
, wxListItem
&item
) const;
653 int GetColumnWidth( int col
) const;
654 int GetColumnCount() const { return m_columns
.GetCount(); }
656 // returns the sum of the heights of all columns
657 int GetHeaderWidth() const;
659 int GetCountPerPage() const;
661 void SetItem( wxListItem
&item
);
662 void GetItem( wxListItem
&item
);
663 void SetItemState( long item
, long state
, long stateMask
);
664 int GetItemState( long item
, long stateMask
);
665 void GetItemRect( long index
, wxRect
&rect
);
666 bool GetItemPosition( long item
, wxPoint
& pos
);
667 int GetSelectedItemCount();
669 // set the scrollbars and update the positions of the items
670 void RecalculatePositions(bool noRefresh
= FALSE
);
672 // refresh the window and the header
675 long GetNextItem( long item
, int geometry
, int state
);
676 void DeleteItem( long index
);
677 void DeleteAllItems();
678 void DeleteColumn( int col
);
679 void DeleteEverything();
680 void EnsureVisible( long index
);
681 long FindItem( long start
, const wxString
& str
, bool partial
= FALSE
);
682 long FindItem( long start
, long data
);
683 long HitTest( int x
, int y
, int &flags
);
684 void InsertItem( wxListItem
&item
);
685 void InsertColumn( long col
, wxListItem
&item
);
686 void SortItems( wxListCtrlCompare fn
, long data
);
688 size_t GetItemCount() const;
689 bool IsEmpty() const { return GetItemCount() == 0; }
690 void SetItemCount(long count
);
692 void ResetCurrent() { m_current
= (size_t)-1; }
693 bool HasCurrent() const { return m_current
!= (size_t)-1; }
695 // send out a wxListEvent
696 void SendNotify( size_t line
,
698 wxPoint point
= wxDefaultPosition
);
700 // override base class virtual to reset m_lineHeight when the font changes
701 virtual bool SetFont(const wxFont
& font
)
703 if ( !wxScrolledWindow::SetFont(font
) )
711 // these are for wxListLineData usage only
713 // get the backpointer to the list ctrl
714 wxListCtrl
*GetListCtrl() const
716 return wxStaticCast(GetParent(), wxListCtrl
);
719 // get the height of all lines (assuming they all do have the same height)
720 wxCoord
GetLineHeight() const;
722 // get the y position of the given line (only for report view)
723 wxCoord
GetLineY(size_t line
) const;
726 // the array of all line objects for a non virtual list control
727 wxListLineDataArray m_lines
;
729 // the list of column objects
730 wxListHeaderDataList m_columns
;
732 // currently focused item or -1
735 // the item currently being edited or -1
736 size_t m_currentEdit
;
738 // the number of lines per page
741 // this flag is set when something which should result in the window
742 // redrawing happens (i.e. an item was added or deleted, or its appearance
743 // changed) and OnPaint() doesn't redraw the window while it is set which
744 // allows to minimize the number of repaintings when a lot of items are
745 // being added. The real repainting occurs only after the next OnIdle()
749 wxBrush
*m_highlightBrush
;
750 wxColour
*m_highlightColour
;
753 wxImageList
*m_small_image_list
;
754 wxImageList
*m_normal_image_list
;
756 int m_normal_spacing
;
760 wxTimer
*m_renameTimer
;
762 wxString m_renameRes
;
767 // for double click logic
768 size_t m_lineLastClicked
,
769 m_lineBeforeLastClicked
;
772 // the total count of items in a virtual list control
775 // the object maintaining the items selection state, only used in virtual
777 wxSelectionStore m_selStore
;
779 // common part of all ctors
782 // intiialize m_[xy]Scroll
783 void InitScrolling();
785 // get the line data for the given index
786 wxListLineData
*GetLine(size_t n
) const
788 wxASSERT_MSG( n
!= (size_t)-1, _T("invalid line index") );
792 wxConstCast(this, wxListMainWindow
)->CacheLineData(n
);
800 // get a dummy line which can be used for geometry calculations and such:
801 // you must use GetLine() if you want to really draw the line
802 wxListLineData
*GetDummyLine() const;
804 // cache the line data of the n-th line in m_lines[0]
805 void CacheLineData(size_t line
);
807 // get the range of visible lines
808 void GetVisibleLinesRange(size_t *from
, size_t *to
);
810 // force us to recalculate the range of visible lines
811 void ResetVisibleLinesRange() { m_lineFrom
= (size_t)-1; }
813 // get the colour to be used for drawing the rules
814 wxColour
GetRuleColour() const
819 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
);
824 // initialize the current item if needed
825 void UpdateCurrent();
827 // delete all items but don't refresh: called from dtor
828 void DoDeleteAllItems();
830 // called when an item is [un]focuded, i.e. becomes [not] current
833 void OnFocusLine( size_t line
);
834 void OnUnfocusLine( size_t line
);
836 // the height of one line using the current font
837 wxCoord m_lineHeight
;
839 // the total header width or 0 if not calculated yet
840 wxCoord m_headerWidth
;
842 // the first and last lines being shown on screen right now (inclusive),
843 // both may be -1 if they must be calculated so never access them directly:
844 // use GetVisibleLinesRange() above instead
848 DECLARE_DYNAMIC_CLASS(wxListMainWindow
);
849 DECLARE_EVENT_TABLE()
852 // ============================================================================
854 // ============================================================================
856 // ----------------------------------------------------------------------------
858 // ----------------------------------------------------------------------------
860 bool wxSelectionStore::IsSelected(size_t item
) const
862 bool isSel
= m_itemsSel
.Index(item
) != wxNOT_FOUND
;
864 // if the default state is to be selected, being in m_itemsSel means that
865 // the item is not selected, so we have to inverse the logic
866 return m_defaultState
? !isSel
: isSel
;
869 bool wxSelectionStore::SelectItem(size_t item
, bool select
)
871 // search for the item ourselves as like this we get the index where to
872 // insert it later if needed, so we do only one search in the array instead
873 // of two (adding item to a sorted array requires a search)
874 size_t index
= m_itemsSel
.IndexForInsert(item
);
875 bool isSel
= index
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
;
877 if ( select
!= m_defaultState
)
881 m_itemsSel
.AddAt(item
, index
);
886 else // reset to default state
890 m_itemsSel
.RemoveAt(index
);
898 void wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, bool select
)
900 wxASSERT_MSG( itemFrom
<= itemTo
, _T("should be in order") );
902 // are we going to have more [un]selected items than the other ones?
903 if ( itemTo
- itemFrom
> m_count
/ 2 )
905 if ( select
!= m_defaultState
)
907 // the default state now becomes the same as 'select'
908 m_defaultState
= select
;
910 // so all the old selections (which had state select) shouldn't be
911 // selected any more, but all the other ones should
912 wxIndexArray selOld
= m_itemsSel
;
915 // TODO: it should be possible to optimize the searches a bit
916 // knowing the possible range
919 for ( item
= 0; item
< itemFrom
; item
++ )
921 if ( selOld
.Index(item
) == wxNOT_FOUND
)
922 m_itemsSel
.Add(item
);
925 for ( item
= itemTo
+ 1; item
< m_count
; item
++ )
927 if ( selOld
.Index(item
) == wxNOT_FOUND
)
928 m_itemsSel
.Add(item
);
931 else // select == m_defaultState
933 // get the inclusive range of items between itemFrom and itemTo
934 size_t count
= m_itemsSel
.GetCount(),
935 start
= m_itemsSel
.IndexForInsert(itemFrom
),
936 end
= m_itemsSel
.IndexForInsert(itemTo
);
938 if ( start
== count
|| m_itemsSel
[start
] < itemFrom
)
943 if ( end
== count
|| m_itemsSel
[end
] > itemTo
)
950 // delete all of them (from end to avoid changing indices)
951 for ( int i
= end
; i
>= (int)start
; i
-- )
953 m_itemsSel
.RemoveAt(i
);
958 else // "few" items change state
960 // just add the items to the selection
961 for ( size_t item
= itemFrom
; item
<= itemTo
; item
++ )
963 SelectItem(item
, select
);
968 void wxSelectionStore::OnItemDelete(size_t item
)
970 size_t count
= m_itemsSel
.GetCount(),
971 i
= m_itemsSel
.IndexForInsert(item
);
973 if ( i
< count
&& m_itemsSel
[i
] == item
)
975 // this item itself was in m_itemsSel, remove it from there
976 m_itemsSel
.RemoveAt(i
);
981 // and adjust the index of all which follow it
984 // all following elements must be greater than the one we deleted
985 wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") );
991 //-----------------------------------------------------------------------------
993 //-----------------------------------------------------------------------------
995 wxListItemData::~wxListItemData()
997 // in the virtual list control the attributes are managed by the main
998 // program, so don't delete them
999 if ( !m_owner
->IsVirtual() )
1007 void wxListItemData::Init()
1015 wxListItemData::wxListItemData(wxListMainWindow
*owner
)
1021 if ( owner
->InReportView() )
1027 m_rect
= new wxRect
;
1031 void wxListItemData::SetItem( const wxListItem
&info
)
1033 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
1034 SetText(info
.m_text
);
1035 if ( info
.m_mask
& wxLIST_MASK_IMAGE
)
1036 m_image
= info
.m_image
;
1037 if ( info
.m_mask
& wxLIST_MASK_DATA
)
1038 m_data
= info
.m_data
;
1040 if ( info
.HasAttributes() )
1043 *m_attr
= *info
.GetAttributes();
1045 m_attr
= new wxListItemAttr(*info
.GetAttributes());
1053 m_rect
->width
= info
.m_width
;
1057 void wxListItemData::SetPosition( int x
, int y
)
1059 wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") );
1065 void wxListItemData::SetSize( int width
, int height
)
1067 wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") );
1070 m_rect
->width
= width
;
1072 m_rect
->height
= height
;
1075 bool wxListItemData::IsHit( int x
, int y
) const
1077 wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") );
1079 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
);
1082 int wxListItemData::GetX() const
1084 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1089 int wxListItemData::GetY() const
1091 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1096 int wxListItemData::GetWidth() const
1098 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1100 return m_rect
->width
;
1103 int wxListItemData::GetHeight() const
1105 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1107 return m_rect
->height
;
1110 void wxListItemData::GetItem( wxListItem
&info
) const
1112 info
.m_text
= m_text
;
1113 info
.m_image
= m_image
;
1114 info
.m_data
= m_data
;
1118 if ( m_attr
->HasTextColour() )
1119 info
.SetTextColour(m_attr
->GetTextColour());
1120 if ( m_attr
->HasBackgroundColour() )
1121 info
.SetBackgroundColour(m_attr
->GetBackgroundColour());
1122 if ( m_attr
->HasFont() )
1123 info
.SetFont(m_attr
->GetFont());
1127 //-----------------------------------------------------------------------------
1129 //-----------------------------------------------------------------------------
1131 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
);
1133 wxListHeaderData::wxListHeaderData()
1144 wxListHeaderData::wxListHeaderData( const wxListItem
&item
)
1152 void wxListHeaderData::SetItem( const wxListItem
&item
)
1154 m_mask
= item
.m_mask
;
1155 m_text
= item
.m_text
;
1156 m_image
= item
.m_image
;
1157 m_format
= item
.m_format
;
1159 SetWidth(item
.m_width
);
1162 void wxListHeaderData::SetPosition( int x
, int y
)
1168 void wxListHeaderData::SetHeight( int h
)
1173 void wxListHeaderData::SetWidth( int w
)
1177 m_width
= WIDTH_COL_DEFAULT
;
1178 if (m_width
< WIDTH_COL_MIN
)
1179 m_width
= WIDTH_COL_MIN
;
1182 void wxListHeaderData::SetFormat( int format
)
1187 bool wxListHeaderData::HasImage() const
1189 return (m_image
!= 0);
1192 bool wxListHeaderData::IsHit( int x
, int y
) const
1194 return ((x
>= m_xpos
) && (x
<= m_xpos
+m_width
) && (y
>= m_ypos
) && (y
<= m_ypos
+m_height
));
1197 void wxListHeaderData::GetItem( wxListItem
&item
)
1199 item
.m_mask
= m_mask
;
1200 item
.m_text
= m_text
;
1201 item
.m_image
= m_image
;
1202 item
.m_format
= m_format
;
1203 item
.m_width
= m_width
;
1206 int wxListHeaderData::GetImage() const
1211 int wxListHeaderData::GetWidth() const
1216 int wxListHeaderData::GetFormat() const
1221 //-----------------------------------------------------------------------------
1223 //-----------------------------------------------------------------------------
1225 inline int wxListLineData::GetMode() const
1227 return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
;
1230 inline bool wxListLineData::InReportView() const
1232 return m_owner
->HasFlag(wxLC_REPORT
);
1235 inline bool wxListLineData::IsVirtual() const
1237 return m_owner
->IsVirtual();
1240 wxListLineData::wxListLineData( wxListMainWindow
*owner
)
1243 m_items
.DeleteContents( TRUE
);
1245 if ( InReportView() )
1251 m_gi
= new GeometryInfo
;
1254 m_highlighted
= FALSE
;
1256 InitItems( GetMode() == wxLC_REPORT
? m_owner
->GetColumnCount() : 1 );
1259 void wxListLineData::CalculateSize( wxDC
*dc
, int spacing
)
1261 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1262 wxCHECK_RET( node
, _T("no subitems at all??") );
1264 wxListItemData
*item
= node
->GetData();
1266 switch ( GetMode() )
1269 case wxLC_SMALL_ICON
:
1271 m_gi
->m_rectAll
.width
= spacing
;
1273 wxString s
= item
->GetText();
1279 m_gi
->m_rectLabel
.width
=
1280 m_gi
->m_rectLabel
.height
= 0;
1284 dc
->GetTextExtent( s
, &lw
, &lh
);
1285 if (lh
< SCROLL_UNIT_Y
)
1290 m_gi
->m_rectAll
.height
= spacing
+ lh
;
1292 m_gi
->m_rectAll
.width
= lw
;
1294 m_gi
->m_rectLabel
.width
= lw
;
1295 m_gi
->m_rectLabel
.height
= lh
;
1298 if (item
->HasImage())
1301 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1302 m_gi
->m_rectIcon
.width
= w
+ 8;
1303 m_gi
->m_rectIcon
.height
= h
+ 8;
1305 if ( m_gi
->m_rectIcon
.width
> m_gi
->m_rectAll
.width
)
1306 m_gi
->m_rectAll
.width
= m_gi
->m_rectIcon
.width
;
1307 if ( m_gi
->m_rectIcon
.height
+ lh
> m_gi
->m_rectAll
.height
- 4 )
1308 m_gi
->m_rectAll
.height
= m_gi
->m_rectIcon
.height
+ lh
+ 4;
1311 if ( item
->HasText() )
1313 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectLabel
.width
;
1314 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectLabel
.height
;
1316 else // no text, highlight the icon
1318 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectIcon
.width
;
1319 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectIcon
.height
;
1326 wxString s
= item
->GetTextForMeasuring();
1329 dc
->GetTextExtent( s
, &lw
, &lh
);
1330 if (lh
< SCROLL_UNIT_Y
)
1335 m_gi
->m_rectLabel
.width
= lw
;
1336 m_gi
->m_rectLabel
.height
= lh
;
1338 m_gi
->m_rectAll
.width
= lw
;
1339 m_gi
->m_rectAll
.height
= lh
;
1341 if (item
->HasImage())
1344 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1345 m_gi
->m_rectIcon
.width
= w
;
1346 m_gi
->m_rectIcon
.height
= h
;
1348 m_gi
->m_rectAll
.width
+= 4 + w
;
1349 if (h
> m_gi
->m_rectAll
.height
)
1350 m_gi
->m_rectAll
.height
= h
;
1353 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectAll
.width
;
1354 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectAll
.height
;
1359 wxFAIL_MSG( _T("unexpected call to SetSize") );
1363 wxFAIL_MSG( _T("unknown mode") );
1367 void wxListLineData::SetPosition( int x
, int y
,
1371 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1372 wxCHECK_RET( node
, _T("no subitems at all??") );
1374 wxListItemData
*item
= node
->GetData();
1376 switch ( GetMode() )
1379 case wxLC_SMALL_ICON
:
1380 m_gi
->m_rectAll
.x
= x
;
1381 m_gi
->m_rectAll
.y
= y
;
1383 if ( item
->HasImage() )
1385 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 4
1386 + (spacing
- m_gi
->m_rectIcon
.width
)/2;
1387 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 4;
1390 if ( item
->HasText() )
1392 if (m_gi
->m_rectAll
.width
> spacing
)
1393 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1395 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2);
1396 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ m_gi
->m_rectAll
.height
+ 2 - m_gi
->m_rectLabel
.height
;
1397 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectLabel
.x
- 2;
1398 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectLabel
.y
- 2;
1400 else // no text, highlight the icon
1402 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectIcon
.x
- 4;
1403 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectIcon
.y
- 4;
1408 m_gi
->m_rectAll
.x
= x
;
1409 m_gi
->m_rectAll
.y
= y
;
1411 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectAll
.x
;
1412 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectAll
.y
;
1413 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ 2;
1415 if (item
->HasImage())
1417 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 2;
1418 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 2;
1419 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 6 + m_gi
->m_rectIcon
.width
;
1423 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1428 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1432 wxFAIL_MSG( _T("unknown mode") );
1436 void wxListLineData::InitItems( int num
)
1438 for (int i
= 0; i
< num
; i
++)
1439 m_items
.Append( new wxListItemData(m_owner
) );
1442 void wxListLineData::SetItem( int index
, const wxListItem
&info
)
1444 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1445 wxCHECK_RET( node
, _T("invalid column index in SetItem") );
1447 wxListItemData
*item
= node
->GetData();
1448 item
->SetItem( info
);
1451 void wxListLineData::GetItem( int index
, wxListItem
&info
)
1453 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1456 wxListItemData
*item
= node
->GetData();
1457 item
->GetItem( info
);
1461 wxString
wxListLineData::GetText(int index
) const
1465 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1468 wxListItemData
*item
= node
->GetData();
1469 s
= item
->GetText();
1475 void wxListLineData::SetText( int index
, const wxString s
)
1477 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1480 wxListItemData
*item
= node
->GetData();
1485 void wxListLineData::SetImage( int index
, int image
)
1487 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1488 wxCHECK_RET( node
, _T("invalid column index in SetImage()") );
1490 wxListItemData
*item
= node
->GetData();
1491 item
->SetImage(image
);
1494 int wxListLineData::GetImage( int index
) const
1496 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1497 wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") );
1499 wxListItemData
*item
= node
->GetData();
1500 return item
->GetImage();
1503 wxListItemAttr
*wxListLineData::GetAttr() const
1505 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1506 wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") );
1508 wxListItemData
*item
= node
->GetData();
1509 return item
->GetAttr();
1512 void wxListLineData::SetAttr(wxListItemAttr
*attr
)
1514 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1515 wxCHECK_RET( node
, _T("invalid column index in SetAttr()") );
1517 wxListItemData
*item
= node
->GetData();
1518 item
->SetAttr(attr
);
1521 void wxListLineData::SetAttributes(wxDC
*dc
,
1522 const wxListItemAttr
*attr
,
1523 const wxColour
& colText
,
1527 // don't use foregroud colour for drawing highlighted items - this might
1528 // make them completely invisible (and there is no way to do bit
1529 // arithmetics on wxColour, unfortunately)
1530 if ( !highlight
&& attr
&& attr
->HasTextColour() )
1532 dc
->SetTextForeground(attr
->GetTextColour());
1536 dc
->SetTextForeground(colText
);
1539 if ( attr
&& attr
->HasFont() )
1541 dc
->SetFont(attr
->GetFont());
1549 void wxListLineData::Draw( wxDC
*dc
)
1551 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1552 wxCHECK_RET( node
, _T("no subitems at all??") );
1554 wxListItemData
*item
= node
->GetData();
1555 if (item
->HasImage())
1557 wxRect rectIcon
= m_gi
->m_rectIcon
;
1558 m_owner
->DrawImage( item
->GetImage(), dc
,
1559 rectIcon
.x
, rectIcon
.y
);
1562 if (item
->HasText())
1564 wxRect rectLabel
= m_gi
->m_rectLabel
;
1565 dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y
);
1569 void wxListLineData::DrawInReportMode( wxDC
*dc
,
1571 const wxRect
& rectHL
,
1574 // use our own flag if we maintain it
1576 highlighted
= m_highlighted
;
1578 // default foreground colour
1579 wxWindow
*listctrl
= m_owner
->GetParent();
1583 colText
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT
);
1587 colText
= listctrl
->GetForegroundColour();
1591 wxFont font
= listctrl
->GetFont();
1593 // TODO: later we should support setting different attributes for
1594 // different columns - to do it, just add "col" argument to
1595 // GetAttr() and move this code into the loop below
1596 wxListItemAttr
*attr
= GetAttr();
1597 SetAttributes(dc
, attr
, colText
, font
, highlighted
);
1599 bool hasBgCol
= attr
&& attr
->HasBackgroundColour();
1600 if ( highlighted
|| hasBgCol
)
1604 dc
->SetBrush( *m_owner
->m_highlightBrush
);
1609 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
1611 dc
->SetBrush( * wxWHITE_BRUSH
);
1614 dc
->SetPen( * wxTRANSPARENT_PEN
);
1615 dc
->DrawRectangle( rectHL
);
1618 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1619 wxCHECK_RET( node
, _T("no subitems at all??") );
1622 wxCoord x
= rect
.x
+ HEADER_OFFSET_X
,
1623 y
= rect
.y
+ (LINE_SPACING
+ EXTRA_HEIGHT
) / 2;
1627 wxListItemData
*item
= node
->GetData();
1631 if ( item
->HasImage() )
1634 m_owner
->DrawImage( item
->GetImage(), dc
, x
, y
);
1635 m_owner
->GetImageSize( item
->GetImage(), ix
, iy
);
1636 x
+= ix
+ 5; // FIXME: what is "5"?
1639 int width
= m_owner
->GetColumnWidth(col
++);
1641 wxDCClipper
clipper(*dc
, x
, y
, width
, rect
.height
);
1643 if ( item
->HasText() )
1645 dc
->DrawText( item
->GetText(), x
, y
);
1650 node
= node
->GetNext();
1654 bool wxListLineData::Highlight( bool on
)
1656 wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") );
1658 if ( on
== m_highlighted
)
1666 void wxListLineData::ReverseHighlight( void )
1668 Highlight(!IsHighlighted());
1671 //-----------------------------------------------------------------------------
1672 // wxListHeaderWindow
1673 //-----------------------------------------------------------------------------
1675 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
);
1677 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
)
1678 EVT_PAINT (wxListHeaderWindow::OnPaint
)
1679 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse
)
1680 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus
)
1683 wxListHeaderWindow::wxListHeaderWindow( void )
1685 m_owner
= (wxListMainWindow
*) NULL
;
1686 m_currentCursor
= (wxCursor
*) NULL
;
1687 m_resizeCursor
= (wxCursor
*) NULL
;
1688 m_isDragging
= FALSE
;
1691 wxListHeaderWindow::wxListHeaderWindow( wxWindow
*win
, wxWindowID id
, wxListMainWindow
*owner
,
1692 const wxPoint
&pos
, const wxSize
&size
,
1693 long style
, const wxString
&name
) :
1694 wxWindow( win
, id
, pos
, size
, style
, name
)
1697 // m_currentCursor = wxSTANDARD_CURSOR;
1698 m_currentCursor
= (wxCursor
*) NULL
;
1699 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
1700 m_isDragging
= FALSE
;
1703 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE
) );
1706 wxListHeaderWindow::~wxListHeaderWindow( void )
1708 delete m_resizeCursor
;
1711 void wxListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1714 GtkStateType state
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
1715 : GTK_STATE_INSENSITIVE
;
1717 x
= dc
->XLOG2DEV( x
);
1719 gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
,
1720 state
, GTK_SHADOW_OUT
,
1721 (GdkRectangle
*) NULL
, m_wxwindow
, "button",
1722 x
-1, y
-1, w
+2, h
+2);
1723 #elif defined( __WXMAC__ )
1724 const int m_corner
= 1;
1726 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1728 dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
) , 1 , wxSOLID
) );
1729 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1730 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1732 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1735 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1736 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1738 dc
->SetPen( *wxWHITE_PEN
);
1739 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1740 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1741 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1742 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1744 const int m_corner
= 1;
1746 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1748 dc
->SetPen( *wxBLACK_PEN
);
1749 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1750 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1752 wxPen
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1755 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1756 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1758 dc
->SetPen( *wxWHITE_PEN
);
1759 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1760 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1761 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1762 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1766 // shift the DC origin to match the position of the main window horz
1767 // scrollbar: this allows us to always use logical coords
1768 void wxListHeaderWindow::AdjustDC(wxDC
& dc
)
1771 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1774 m_owner
->GetViewStart( &x
, NULL
);
1776 // account for the horz scrollbar offset
1777 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1780 void wxListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1783 wxClientDC
dc( this );
1785 wxPaintDC
dc( this );
1793 dc
.SetFont( GetFont() );
1795 // width and height of the entire header window
1797 GetClientSize( &w
, &h
);
1798 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1800 dc
.SetBackgroundMode(wxTRANSPARENT
);
1802 // do *not* use the listctrl colour for headers - one day we will have a
1803 // function to set it separately
1804 //dc.SetTextForeground( *wxBLACK );
1805 dc
.SetTextForeground(wxSystemSettings::
1806 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1808 int x
= HEADER_OFFSET_X
;
1810 int numColumns
= m_owner
->GetColumnCount();
1812 for (int i
= 0; i
< numColumns
; i
++)
1814 m_owner
->GetColumn( i
, item
);
1815 int wCol
= item
.m_width
;
1816 int cw
= wCol
- 2; // the width of the rect to draw
1818 int xEnd
= x
+ wCol
;
1820 dc
.SetPen( *wxWHITE_PEN
);
1822 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1823 dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 );
1824 dc
.DrawText( item
.GetText(), x
+ EXTRA_WIDTH
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1825 dc
.DestroyClippingRegion();
1834 void wxListHeaderWindow::DrawCurrent()
1836 int x1
= m_currentX
;
1838 ClientToScreen( &x1
, &y1
);
1840 int x2
= m_currentX
-1;
1842 m_owner
->GetClientSize( NULL
, &y2
);
1843 m_owner
->ClientToScreen( &x2
, &y2
);
1846 dc
.SetLogicalFunction( wxINVERT
);
1847 dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID
) );
1848 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1852 dc
.DrawLine( x1
, y1
, x2
, y2
);
1854 dc
.SetLogicalFunction( wxCOPY
);
1856 dc
.SetPen( wxNullPen
);
1857 dc
.SetBrush( wxNullBrush
);
1860 void wxListHeaderWindow::OnMouse( wxMouseEvent
&event
)
1862 // we want to work with logical coords
1864 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1865 int y
= event
.GetY();
1869 // we don't draw the line beyond our window, but we allow dragging it
1872 GetClientSize( &w
, NULL
);
1873 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1876 // erase the line if it was drawn
1877 if ( m_currentX
< w
)
1880 if (event
.ButtonUp())
1883 m_isDragging
= FALSE
;
1885 m_owner
->SetColumnWidth( m_column
, m_currentX
- m_minX
);
1892 m_currentX
= m_minX
+ 7;
1894 // draw in the new location
1895 if ( m_currentX
< w
)
1899 else // not dragging
1902 bool hit_border
= FALSE
;
1904 // end of the current column
1907 // find the column where this event occured
1908 int countCol
= m_owner
->GetColumnCount();
1909 for (int col
= 0; col
< countCol
; col
++)
1911 xpos
+= m_owner
->GetColumnWidth( col
);
1914 if ( (abs(x
-xpos
) < 3) && (y
< 22) )
1916 // near the column border
1923 // inside the column
1930 if (event
.LeftDown())
1934 m_isDragging
= TRUE
;
1941 wxWindow
*parent
= GetParent();
1942 wxListEvent
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() );
1943 le
.SetEventObject( parent
);
1944 le
.m_col
= m_column
;
1945 parent
->GetEventHandler()->ProcessEvent( le
);
1948 else if (event
.Moving())
1953 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1954 m_currentCursor
= m_resizeCursor
;
1958 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1959 m_currentCursor
= wxSTANDARD_CURSOR
;
1963 SetCursor(*m_currentCursor
);
1968 void wxListHeaderWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
1970 m_owner
->SetFocus();
1973 //-----------------------------------------------------------------------------
1974 // wxListRenameTimer (internal)
1975 //-----------------------------------------------------------------------------
1977 wxListRenameTimer::wxListRenameTimer( wxListMainWindow
*owner
)
1982 void wxListRenameTimer::Notify()
1984 m_owner
->OnRenameTimer();
1987 //-----------------------------------------------------------------------------
1988 // wxListTextCtrl (internal)
1989 //-----------------------------------------------------------------------------
1991 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
);
1993 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
)
1994 EVT_CHAR (wxListTextCtrl::OnChar
)
1995 EVT_KEY_UP (wxListTextCtrl::OnKeyUp
)
1996 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus
)
1999 wxListTextCtrl::wxListTextCtrl( wxWindow
*parent
,
2000 const wxWindowID id
,
2003 wxListMainWindow
*owner
,
2004 const wxString
&value
,
2008 const wxValidator
& validator
,
2009 const wxString
&name
)
2010 : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name
)
2015 (*m_accept
) = FALSE
;
2017 m_startValue
= value
;
2020 void wxListTextCtrl::OnChar( wxKeyEvent
&event
)
2022 if (event
.m_keyCode
== WXK_RETURN
)
2025 (*m_res
) = GetValue();
2027 if (!wxPendingDelete
.Member(this))
2028 wxPendingDelete
.Append(this);
2030 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2031 m_owner
->OnRenameAccept();
2035 if (event
.m_keyCode
== WXK_ESCAPE
)
2037 (*m_accept
) = FALSE
;
2040 if (!wxPendingDelete
.Member(this))
2041 wxPendingDelete
.Append(this);
2049 void wxListTextCtrl::OnKeyUp( wxKeyEvent
&event
)
2051 // auto-grow the textctrl:
2052 wxSize parentSize
= m_owner
->GetSize();
2053 wxPoint myPos
= GetPosition();
2054 wxSize mySize
= GetSize();
2056 GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM??
2057 if (myPos
.x
+ sx
> parentSize
.x
)
2058 sx
= parentSize
.x
- myPos
.x
;
2066 void wxListTextCtrl::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
2068 if (!wxPendingDelete
.Member(this))
2069 wxPendingDelete
.Append(this);
2071 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2072 m_owner
->OnRenameAccept();
2075 //-----------------------------------------------------------------------------
2077 //-----------------------------------------------------------------------------
2079 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
);
2081 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
)
2082 EVT_PAINT (wxListMainWindow::OnPaint
)
2083 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse
)
2084 EVT_CHAR (wxListMainWindow::OnChar
)
2085 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown
)
2086 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus
)
2087 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus
)
2088 EVT_SCROLLWIN (wxListMainWindow::OnScroll
)
2091 void wxListMainWindow::Init()
2093 m_columns
.DeleteContents( TRUE
);
2097 m_lineTo
= (size_t)-1;
2103 m_small_image_list
= (wxImageList
*) NULL
;
2104 m_normal_image_list
= (wxImageList
*) NULL
;
2106 m_small_spacing
= 30;
2107 m_normal_spacing
= 40;
2111 m_isCreated
= FALSE
;
2113 m_lastOnSame
= FALSE
;
2114 m_renameTimer
= new wxListRenameTimer( this );
2115 m_renameAccept
= FALSE
;
2120 m_lineBeforeLastClicked
= (size_t)-1;
2123 void wxListMainWindow::InitScrolling()
2125 if ( HasFlag(wxLC_REPORT
) )
2127 m_xScroll
= SCROLL_UNIT_X
;
2128 m_yScroll
= SCROLL_UNIT_Y
;
2132 m_xScroll
= SCROLL_UNIT_Y
;
2137 wxListMainWindow::wxListMainWindow()
2141 m_highlightBrush
= (wxBrush
*) NULL
;
2147 wxListMainWindow::wxListMainWindow( wxWindow
*parent
,
2152 const wxString
&name
)
2153 : wxScrolledWindow( parent
, id
, pos
, size
,
2154 style
| wxHSCROLL
| wxVSCROLL
, name
)
2158 m_highlightBrush
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
2163 SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 );
2165 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX
) );
2168 wxListMainWindow::~wxListMainWindow()
2172 delete m_highlightBrush
;
2174 delete m_renameTimer
;
2177 void wxListMainWindow::CacheLineData(size_t line
)
2179 wxListCtrl
*listctrl
= GetListCtrl();
2181 wxListLineData
*ld
= GetDummyLine();
2183 size_t countCol
= GetColumnCount();
2184 for ( size_t col
= 0; col
< countCol
; col
++ )
2186 ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
));
2189 ld
->SetImage(listctrl
->OnGetItemImage(line
));
2190 ld
->SetAttr(listctrl
->OnGetItemAttr(line
));
2193 wxListLineData
*wxListMainWindow::GetDummyLine() const
2195 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2197 if ( m_lines
.IsEmpty() )
2199 // normal controls are supposed to have something in m_lines
2200 // already if it's not empty
2201 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2203 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2204 wxListLineData
*line
= new wxListLineData(self
);
2205 self
->m_lines
.Add(line
);
2211 // ----------------------------------------------------------------------------
2212 // line geometry (report mode only)
2213 // ----------------------------------------------------------------------------
2215 wxCoord
wxListMainWindow::GetLineHeight() const
2217 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2219 // we cache the line height as calling GetTextExtent() is slow
2220 if ( !m_lineHeight
)
2222 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2224 wxClientDC
dc( self
);
2225 dc
.SetFont( GetFont() );
2228 dc
.GetTextExtent(_T("H"), NULL
, &y
);
2230 if ( y
< SCROLL_UNIT_Y
)
2234 self
->m_lineHeight
= y
+ LINE_SPACING
;
2237 return m_lineHeight
;
2240 wxCoord
wxListMainWindow::GetLineY(size_t line
) const
2242 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2244 return LINE_SPACING
+ line
*GetLineHeight();
2247 wxRect
wxListMainWindow::GetLineRect(size_t line
) const
2249 if ( !InReportView() )
2250 return GetLine(line
)->m_gi
->m_rectAll
;
2253 rect
.x
= HEADER_OFFSET_X
;
2254 rect
.y
= GetLineY(line
);
2255 rect
.width
= GetHeaderWidth();
2256 rect
.height
= GetLineHeight();
2261 wxRect
wxListMainWindow::GetLineLabelRect(size_t line
) const
2263 if ( !InReportView() )
2264 return GetLine(line
)->m_gi
->m_rectLabel
;
2267 rect
.x
= HEADER_OFFSET_X
;
2268 rect
.y
= GetLineY(line
);
2269 rect
.width
= GetColumnWidth(0);
2270 rect
.height
= GetLineHeight();
2275 wxRect
wxListMainWindow::GetLineIconRect(size_t line
) const
2277 if ( !InReportView() )
2278 return GetLine(line
)->m_gi
->m_rectIcon
;
2280 wxListLineData
*ld
= GetLine(line
);
2281 wxASSERT_MSG( ld
->HasImage(), _T("should have an image") );
2284 rect
.x
= HEADER_OFFSET_X
;
2285 rect
.y
= GetLineY(line
);
2286 GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
);
2291 wxRect
wxListMainWindow::GetLineHighlightRect(size_t line
) const
2293 return InReportView() ? GetLineRect(line
)
2294 : GetLine(line
)->m_gi
->m_rectHighlight
;
2297 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const
2299 wxListLineData
*ld
= GetLine(line
);
2301 if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) )
2302 return wxLIST_HITTEST_ONITEMICON
;
2304 if ( ld
->HasText() )
2306 wxRect rect
= InReportView() ? GetLineRect(line
)
2307 : GetLineLabelRect(line
);
2309 if ( rect
.Inside(x
, y
) )
2310 return wxLIST_HITTEST_ONITEMLABEL
;
2316 // ----------------------------------------------------------------------------
2317 // highlight (selection) handling
2318 // ----------------------------------------------------------------------------
2320 bool wxListMainWindow::IsHighlighted(size_t line
) const
2324 return m_selStore
.IsSelected(line
);
2328 wxListLineData
*ld
= GetLine(line
);
2329 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2331 return ld
->IsHighlighted();
2335 void wxListMainWindow::HighlightLines( size_t lineFrom
, size_t lineTo
, bool highlight
)
2339 m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
);
2340 RefreshLines(lineFrom
, lineTo
);
2344 // do it the dumb way
2345 bool needsRefresh
= FALSE
;
2346 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2348 if ( HighlightLine(line
, highlight
) )
2349 needsRefresh
= TRUE
;
2353 RefreshLines(lineFrom
, lineTo
);
2357 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight
)
2363 changed
= m_selStore
.SelectItem(line
, highlight
);
2367 wxListLineData
*ld
= GetLine(line
);
2368 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2370 changed
= ld
->Highlight(highlight
);
2375 SendNotify( line
, highlight
? wxEVT_COMMAND_LIST_ITEM_SELECTED
2376 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
);
2382 void wxListMainWindow::RefreshLine( size_t line
)
2384 wxRect rect
= GetLineRect(line
);
2386 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2387 RefreshRect( rect
);
2390 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo
)
2392 // we suppose that they are ordered by caller
2393 wxASSERT_MSG( lineFrom
<= lineTo
, _T("indices in disorder") );
2395 wxASSERT_MSG( lineTo
< GetItemCount(), _T("invalid line range") );
2397 if ( HasFlag(wxLC_REPORT
) )
2399 size_t visibleFrom
, visibleTo
;
2400 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2402 if ( lineFrom
< visibleFrom
)
2403 lineFrom
= visibleFrom
;
2404 if ( lineTo
> visibleTo
)
2409 rect
.y
= GetLineY(lineFrom
);
2410 rect
.width
= GetClientSize().x
;
2411 rect
.height
= GetLineY(lineTo
) - rect
.y
+ GetLineHeight();
2413 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2414 RefreshRect( rect
);
2418 // TODO: this should be optimized...
2419 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2426 void wxListMainWindow::RefreshAfter( size_t lineFrom
)
2428 if ( HasFlag(wxLC_REPORT
) )
2431 GetVisibleLinesRange(&visibleFrom
, NULL
);
2433 if ( lineFrom
< visibleFrom
)
2434 lineFrom
= visibleFrom
;
2438 rect
.y
= GetLineY(lineFrom
);
2440 wxSize size
= GetClientSize();
2441 rect
.width
= size
.x
;
2442 // refresh till the bottom of the window
2443 rect
.height
= size
.y
- rect
.y
;
2445 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2446 RefreshRect( rect
);
2450 // TODO: how to do it more efficiently?
2455 void wxListMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2457 // Note: a wxPaintDC must be constructed even if no drawing is
2458 // done (a Windows requirement).
2459 wxPaintDC
dc( this );
2463 // empty control. nothing to draw
2469 // delay the repainting until we calculate all the items positions
2476 CalcScrolledPosition( 0, 0, &dev_x
, &dev_y
);
2480 dc
.SetFont( GetFont() );
2482 if ( HasFlag(wxLC_REPORT
) )
2484 int lineHeight
= GetLineHeight();
2486 size_t visibleFrom
, visibleTo
;
2487 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2490 wxCoord xOrig
, yOrig
;
2491 CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
);
2493 // tell the caller cache to cache the data
2496 wxListEvent
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
,
2497 GetParent()->GetId());
2498 evCache
.SetEventObject( GetParent() );
2499 evCache
.m_oldItemIndex
= visibleFrom
;
2500 evCache
.m_itemIndex
= visibleTo
;
2501 GetParent()->GetEventHandler()->ProcessEvent( evCache
);
2504 for ( size_t line
= visibleFrom
; line
<= visibleTo
; line
++ )
2506 rectLine
= GetLineRect(line
);
2508 if ( !IsExposed(rectLine
.x
- xOrig
, rectLine
.y
- yOrig
,
2509 rectLine
.width
, rectLine
.height
) )
2511 // don't redraw unaffected lines to avoid flicker
2515 GetLine(line
)->DrawInReportMode( &dc
,
2517 GetLineHighlightRect(line
),
2518 IsHighlighted(line
) );
2521 if ( HasFlag(wxLC_HRULES
) )
2523 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2524 wxSize clientSize
= GetClientSize();
2526 for ( size_t i
= visibleFrom
; i
<= visibleTo
; i
++ )
2529 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2530 dc
.DrawLine(0 - dev_x
, i
*lineHeight
,
2531 clientSize
.x
- dev_x
, i
*lineHeight
);
2534 // Draw last horizontal rule
2535 if ( visibleTo
> visibleFrom
)
2538 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2539 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
,
2540 clientSize
.x
- dev_x
, m_lineTo
*lineHeight
);
2544 // Draw vertical rules if required
2545 if ( HasFlag(wxLC_VRULES
) && !IsEmpty() )
2547 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2550 wxRect firstItemRect
;
2551 wxRect lastItemRect
;
2552 GetItemRect(0, firstItemRect
);
2553 GetItemRect(GetItemCount() - 1, lastItemRect
);
2554 int x
= firstItemRect
.GetX();
2556 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2557 for (col
= 0; col
< GetColumnCount(); col
++)
2559 int colWidth
= GetColumnWidth(col
);
2561 dc
.DrawLine(x
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
,
2562 x
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
);
2568 size_t count
= GetItemCount();
2569 for ( size_t i
= 0; i
< count
; i
++ )
2571 GetLine(i
)->Draw( &dc
);
2575 if ( HasCurrent() && m_hasFocus
)
2578 // no rect outline, we already have the background color
2580 dc
.SetPen( *wxBLACK_PEN
);
2581 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2582 dc
.DrawRectangle( GetLineHighlightRect(m_current
) );
2589 void wxListMainWindow::HighlightAll( bool on
)
2591 if ( IsSingleSel() )
2593 wxASSERT_MSG( !on
, _T("can't do this in a single sel control") );
2595 // we just have one item to turn off
2596 if ( HasCurrent() && IsHighlighted(m_current
) )
2598 HighlightLine(m_current
, FALSE
);
2599 RefreshLine(m_current
);
2604 HighlightLines(0, GetItemCount() - 1, on
);
2608 void wxListMainWindow::SendNotify( size_t line
,
2609 wxEventType command
,
2612 wxListEvent
le( command
, GetParent()->GetId() );
2613 le
.SetEventObject( GetParent() );
2614 le
.m_itemIndex
= line
;
2616 // set only for events which have position
2617 if ( point
!= wxDefaultPosition
)
2618 le
.m_pointDrag
= point
;
2620 if ( command
!= wxEVT_COMMAND_LIST_DELETE_ITEM
)
2622 GetLine(line
)->GetItem( 0, le
.m_item
);
2624 //else: there may be no more such item
2626 GetParent()->GetEventHandler()->ProcessEvent( le
);
2629 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) )
2631 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
2634 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) )
2636 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
2639 void wxListMainWindow::EditLabel( long item
)
2641 wxCHECK_RET( (item
>= 0) && ((size_t)item
< GetItemCount()),
2642 wxT("wrong index in wxListCtrl::EditLabel()") );
2644 m_currentEdit
= (size_t)item
;
2646 wxListEvent
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() );
2647 le
.SetEventObject( GetParent() );
2648 le
.m_itemIndex
= item
;
2649 wxListLineData
*data
= GetLine(m_currentEdit
);
2650 wxCHECK_RET( data
, _T("invalid index in EditLabel()") );
2651 data
->GetItem( 0, le
.m_item
);
2652 GetParent()->GetEventHandler()->ProcessEvent( le
);
2654 if (!le
.IsAllowed())
2657 // We have to call this here because the label in question might just have
2658 // been added and no screen update taken place.
2662 wxClientDC
dc(this);
2665 wxString s
= data
->GetText(0);
2666 wxRect rectLabel
= GetLineLabelRect(m_currentEdit
);
2668 rectLabel
.x
= dc
.LogicalToDeviceX( rectLabel
.x
);
2669 rectLabel
.y
= dc
.LogicalToDeviceY( rectLabel
.y
);
2671 wxListTextCtrl
*text
= new wxListTextCtrl
2678 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4),
2679 wxSize(rectLabel
.width
+11,rectLabel
.height
+8)
2684 void wxListMainWindow::OnRenameTimer()
2686 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2688 EditLabel( m_current
);
2691 void wxListMainWindow::OnRenameAccept()
2693 wxListEvent
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() );
2694 le
.SetEventObject( GetParent() );
2695 le
.m_itemIndex
= m_currentEdit
;
2697 wxListLineData
*data
= GetLine(m_currentEdit
);
2698 wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") );
2700 data
->GetItem( 0, le
.m_item
);
2701 le
.m_item
.m_text
= m_renameRes
;
2702 GetParent()->GetEventHandler()->ProcessEvent( le
);
2704 if (!le
.IsAllowed()) return;
2707 info
.m_mask
= wxLIST_MASK_TEXT
;
2708 info
.m_itemId
= le
.m_itemIndex
;
2709 info
.m_text
= m_renameRes
;
2710 info
.SetTextColour(le
.m_item
.GetTextColour());
2714 void wxListMainWindow::OnMouse( wxMouseEvent
&event
)
2716 event
.SetEventObject( GetParent() );
2717 if ( GetParent()->GetEventHandler()->ProcessEvent( event
) )
2720 if ( !HasCurrent() || IsEmpty() )
2726 if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() ||
2727 event
.ButtonDClick()) )
2730 int x
= event
.GetX();
2731 int y
= event
.GetY();
2732 CalcUnscrolledPosition( x
, y
, &x
, &y
);
2734 // where did we hit it (if we did)?
2737 size_t count
= GetItemCount(),
2740 if ( HasFlag(wxLC_REPORT
) )
2742 current
= y
/ GetLineHeight();
2743 if ( current
< count
)
2744 hitResult
= HitTestLine(current
, x
, y
);
2748 // TODO: optimize it too! this is less simple than for report view but
2749 // enumerating all items is still not a way to do it!!
2750 for ( current
= 0; current
< count
; current
++ )
2752 hitResult
= HitTestLine(current
, x
, y
);
2758 if (event
.Dragging())
2760 if (m_dragCount
== 0)
2761 m_dragStart
= wxPoint(x
,y
);
2765 if (m_dragCount
!= 3)
2768 int command
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2769 : wxEVT_COMMAND_LIST_BEGIN_DRAG
;
2771 wxListEvent
le( command
, GetParent()->GetId() );
2772 le
.SetEventObject( GetParent() );
2773 le
.m_pointDrag
= m_dragStart
;
2774 GetParent()->GetEventHandler()->ProcessEvent( le
);
2785 // outside of any item
2789 bool forceClick
= FALSE
;
2790 if (event
.ButtonDClick())
2792 m_renameTimer
->Stop();
2793 m_lastOnSame
= FALSE
;
2795 if ( current
== m_lineBeforeLastClicked
)
2797 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED
);
2803 // the first click was on another item, so don't interpret this as
2804 // a double click, but as a simple click instead
2809 if (event
.LeftUp() && m_lastOnSame
)
2811 if ((current
== m_current
) &&
2812 (hitResult
== wxLIST_HITTEST_ONITEMLABEL
) &&
2813 HasFlag(wxLC_EDIT_LABELS
) )
2815 m_renameTimer
->Start( 100, TRUE
);
2817 m_lastOnSame
= FALSE
;
2819 else if (event
.RightDown())
2821 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
,
2822 event
.GetPosition() );
2824 else if (event
.MiddleDown())
2826 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
);
2828 else if ( event
.LeftDown() || forceClick
)
2830 m_lineBeforeLastClicked
= m_lineLastClicked
;
2831 m_lineLastClicked
= current
;
2833 size_t oldCurrent
= m_current
;
2835 if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) )
2837 HighlightAll( FALSE
);
2838 m_current
= current
;
2840 ReverseHighlight(m_current
);
2842 else // multi sel & either ctrl or shift is down
2844 if (event
.ControlDown())
2846 m_current
= current
;
2848 ReverseHighlight(m_current
);
2850 else if (event
.ShiftDown())
2852 m_current
= current
;
2854 size_t lineFrom
= oldCurrent
,
2857 if ( lineTo
< lineFrom
)
2860 lineFrom
= m_current
;
2863 HighlightLines(lineFrom
, lineTo
);
2865 else // !ctrl, !shift
2867 // test in the enclosing if should make it impossible
2868 wxFAIL_MSG( _T("how did we get here?") );
2872 if (m_current
!= oldCurrent
)
2874 RefreshLine( oldCurrent
);
2875 OnUnfocusLine( oldCurrent
);
2876 OnFocusLine( m_current
);
2879 // forceClick is only set if the previous click was on another item
2880 m_lastOnSame
= !forceClick
&& (m_current
== oldCurrent
);
2884 void wxListMainWindow::MoveToItem(size_t item
)
2886 if ( item
== (size_t)-1 )
2889 wxRect rect
= GetLineRect(item
);
2891 int client_w
, client_h
;
2892 GetClientSize( &client_w
, &client_h
);
2894 int view_x
= m_xScroll
*GetScrollPos( wxHORIZONTAL
);
2895 int view_y
= m_yScroll
*GetScrollPos( wxVERTICAL
);
2897 if ( HasFlag(wxLC_REPORT
) )
2899 // the next we need the range of lines shown it might be different, so
2901 ResetVisibleLinesRange();
2903 if (rect
.y
< view_y
)
2904 Scroll( -1, rect
.y
/m_yScroll
);
2905 if (rect
.y
+rect
.height
+5 > view_y
+client_h
)
2906 Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll
);
2910 if (rect
.x
-view_x
< 5)
2911 Scroll( (rect
.x
-5)/m_xScroll
, -1 );
2912 if (rect
.x
+rect
.width
-5 > view_x
+client_w
)
2913 Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 );
2917 // ----------------------------------------------------------------------------
2918 // keyboard handling
2919 // ----------------------------------------------------------------------------
2921 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
2923 wxCHECK_RET( newCurrent
< (size_t)GetItemCount(),
2924 _T("invalid item index in OnArrowChar()") );
2926 size_t oldCurrent
= m_current
;
2928 // in single selection we just ignore Shift as we can't select several
2930 if ( event
.ShiftDown() && !IsSingleSel() )
2932 m_current
= newCurrent
;
2934 // select all the items between the old and the new one
2935 if ( oldCurrent
> newCurrent
)
2937 newCurrent
= oldCurrent
;
2938 oldCurrent
= m_current
;
2941 HighlightLines(oldCurrent
, newCurrent
);
2945 // all previously selected items are unselected unless ctrl is held
2946 if ( !event
.ControlDown() )
2947 HighlightAll(FALSE
);
2949 m_current
= newCurrent
;
2951 HighlightLine( oldCurrent
, FALSE
);
2952 RefreshLine( oldCurrent
);
2954 if ( !event
.ControlDown() )
2956 HighlightLine( m_current
, TRUE
);
2960 OnUnfocusLine( oldCurrent
);
2961 OnFocusLine( m_current
);
2962 RefreshLine( m_current
);
2967 void wxListMainWindow::OnKeyDown( wxKeyEvent
&event
)
2969 wxWindow
*parent
= GetParent();
2971 /* we propagate the key event up */
2972 wxKeyEvent
ke( wxEVT_KEY_DOWN
);
2973 ke
.m_shiftDown
= event
.m_shiftDown
;
2974 ke
.m_controlDown
= event
.m_controlDown
;
2975 ke
.m_altDown
= event
.m_altDown
;
2976 ke
.m_metaDown
= event
.m_metaDown
;
2977 ke
.m_keyCode
= event
.m_keyCode
;
2980 ke
.SetEventObject( parent
);
2981 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2986 void wxListMainWindow::OnChar( wxKeyEvent
&event
)
2988 wxWindow
*parent
= GetParent();
2990 /* we send a list_key event up */
2993 wxListEvent
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() );
2994 le
.m_itemIndex
= m_current
;
2995 GetLine(m_current
)->GetItem( 0, le
.m_item
);
2996 le
.m_code
= (int)event
.KeyCode();
2997 le
.SetEventObject( parent
);
2998 parent
->GetEventHandler()->ProcessEvent( le
);
3001 /* we propagate the char event up */
3002 wxKeyEvent
ke( wxEVT_CHAR
);
3003 ke
.m_shiftDown
= event
.m_shiftDown
;
3004 ke
.m_controlDown
= event
.m_controlDown
;
3005 ke
.m_altDown
= event
.m_altDown
;
3006 ke
.m_metaDown
= event
.m_metaDown
;
3007 ke
.m_keyCode
= event
.m_keyCode
;
3010 ke
.SetEventObject( parent
);
3011 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
3013 if (event
.KeyCode() == WXK_TAB
)
3015 wxNavigationKeyEvent nevent
;
3016 nevent
.SetWindowChange( event
.ControlDown() );
3017 nevent
.SetDirection( !event
.ShiftDown() );
3018 nevent
.SetEventObject( GetParent()->GetParent() );
3019 nevent
.SetCurrentFocus( m_parent
);
3020 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
)) return;
3023 /* no item -> nothing to do */
3030 switch (event
.KeyCode())
3033 if ( m_current
> 0 )
3034 OnArrowChar( m_current
- 1, event
);
3038 if ( m_current
< (size_t)GetItemCount() - 1 )
3039 OnArrowChar( m_current
+ 1, event
);
3044 OnArrowChar( GetItemCount() - 1, event
);
3049 OnArrowChar( 0, event
);
3055 if ( HasFlag(wxLC_REPORT
) )
3057 steps
= m_linesPerPage
- 1;
3061 steps
= m_current
% m_linesPerPage
;
3064 int index
= m_current
- steps
;
3068 OnArrowChar( index
, event
);
3075 if ( HasFlag(wxLC_REPORT
) )
3077 steps
= m_linesPerPage
- 1;
3081 steps
= m_linesPerPage
- (m_current
% m_linesPerPage
) - 1;
3084 size_t index
= m_current
+ steps
;
3085 size_t count
= GetItemCount();
3086 if ( index
>= count
)
3089 OnArrowChar( index
, event
);
3094 if ( !HasFlag(wxLC_REPORT
) )
3096 int index
= m_current
- m_linesPerPage
;
3100 OnArrowChar( index
, event
);
3105 if ( !HasFlag(wxLC_REPORT
) )
3107 size_t index
= m_current
+ m_linesPerPage
;
3109 size_t count
= GetItemCount();
3110 if ( index
>= count
)
3113 OnArrowChar( index
, event
);
3118 if ( IsSingleSel() )
3120 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3121 GetParent()->GetId() );
3122 le
.SetEventObject( GetParent() );
3123 le
.m_itemIndex
= m_current
;
3124 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3125 GetParent()->GetEventHandler()->ProcessEvent( le
);
3129 ReverseHighlight(m_current
);
3136 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3137 GetParent()->GetId() );
3138 le
.SetEventObject( GetParent() );
3139 le
.m_itemIndex
= m_current
;
3140 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3141 GetParent()->GetEventHandler()->ProcessEvent( le
);
3150 // ----------------------------------------------------------------------------
3152 // ----------------------------------------------------------------------------
3155 extern wxWindow
*g_focusWindow
;
3158 void wxListMainWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
3163 RefreshLine( m_current
);
3169 g_focusWindow
= GetParent();
3172 wxFocusEvent
event( wxEVT_SET_FOCUS
, GetParent()->GetId() );
3173 event
.SetEventObject( GetParent() );
3174 GetParent()->GetEventHandler()->ProcessEvent( event
);
3177 void wxListMainWindow::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
3182 RefreshLine( m_current
);
3185 void wxListMainWindow::DrawImage( int index
, wxDC
*dc
, int x
, int y
)
3187 if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
))
3189 m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3191 else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
))
3193 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3195 else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
))
3197 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3199 else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
))
3201 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3205 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height
) const
3207 if ( HasFlag(wxLC_ICON
) && m_normal_image_list
)
3209 m_normal_image_list
->GetSize( index
, width
, height
);
3211 else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list
)
3213 m_small_image_list
->GetSize( index
, width
, height
);
3215 else if ( HasFlag(wxLC_LIST
) && m_small_image_list
)
3217 m_small_image_list
->GetSize( index
, width
, height
);
3219 else if ( HasFlag(wxLC_REPORT
) && m_small_image_list
)
3221 m_small_image_list
->GetSize( index
, width
, height
);
3230 int wxListMainWindow::GetTextLength( const wxString
&s
) const
3232 wxClientDC
dc( wxConstCast(this, wxListMainWindow
) );
3233 dc
.SetFont( GetFont() );
3236 dc
.GetTextExtent( s
, &lw
, NULL
);
3238 return lw
+ AUTOSIZE_COL_MARGIN
;
3241 void wxListMainWindow::SetImageList( wxImageList
*imageList
, int which
)
3245 // calc the spacing from the icon size
3248 if ((imageList
) && (imageList
->GetImageCount()) )
3250 imageList
->GetSize(0, width
, height
);
3253 if (which
== wxIMAGE_LIST_NORMAL
)
3255 m_normal_image_list
= imageList
;
3256 m_normal_spacing
= width
+ 8;
3259 if (which
== wxIMAGE_LIST_SMALL
)
3261 m_small_image_list
= imageList
;
3262 m_small_spacing
= width
+ 14;
3266 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall
)
3271 m_small_spacing
= spacing
;
3275 m_normal_spacing
= spacing
;
3279 int wxListMainWindow::GetItemSpacing( bool isSmall
)
3281 return isSmall
? m_small_spacing
: m_normal_spacing
;
3284 // ----------------------------------------------------------------------------
3286 // ----------------------------------------------------------------------------
3288 void wxListMainWindow::SetColumn( int col
, wxListItem
&item
)
3290 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3292 wxCHECK_RET( node
, _T("invalid column index in SetColumn") );
3294 if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3295 item
.m_width
= GetTextLength( item
.m_text
);
3297 wxListHeaderData
*column
= node
->GetData();
3298 column
->SetItem( item
);
3300 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3302 headerWin
->m_dirty
= TRUE
;
3306 // invalidate it as it has to be recalculated
3310 void wxListMainWindow::SetColumnWidth( int col
, int width
)
3312 wxCHECK_RET( col
>= 0 && col
< GetColumnCount(),
3313 _T("invalid column index") );
3315 wxCHECK_RET( HasFlag(wxLC_REPORT
),
3316 _T("SetColumnWidth() can only be called in report mode.") );
3320 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3321 wxCHECK_RET( node
, _T("no column?") );
3323 wxListHeaderData
*column
= node
->GetData();
3325 size_t count
= GetItemCount();
3327 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
3329 width
= GetTextLength(column
->GetText());
3331 else if ( width
== wxLIST_AUTOSIZE
)
3335 // TODO: determine the max width somehow...
3336 width
= WIDTH_COL_DEFAULT
;
3340 wxClientDC
dc(this);
3341 dc
.SetFont( GetFont() );
3343 int max
= AUTOSIZE_COL_MARGIN
;
3345 for ( size_t i
= 0; i
< count
; i
++ )
3347 wxListLineData
*line
= GetLine(i
);
3348 wxListItemDataList::Node
*n
= line
->m_items
.Item( col
);
3350 wxCHECK_RET( n
, _T("no subitem?") );
3352 wxListItemData
*item
= n
->GetData();
3355 if (item
->HasImage())
3358 GetImageSize( item
->GetImage(), ix
, iy
);
3362 if (item
->HasText())
3365 dc
.GetTextExtent( item
->GetText(), &w
, NULL
);
3373 width
= max
+ AUTOSIZE_COL_MARGIN
;
3377 column
->SetWidth( width
);
3379 // invalidate it as it has to be recalculated
3383 int wxListMainWindow::GetHeaderWidth() const
3385 if ( !m_headerWidth
)
3387 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
3389 size_t count
= GetColumnCount();
3390 for ( size_t col
= 0; col
< count
; col
++ )
3392 self
->m_headerWidth
+= GetColumnWidth(col
);
3396 return m_headerWidth
;
3399 void wxListMainWindow::GetColumn( int col
, wxListItem
&item
) const
3401 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3402 wxCHECK_RET( node
, _T("invalid column index in GetColumn") );
3404 wxListHeaderData
*column
= node
->GetData();
3405 column
->GetItem( item
);
3408 int wxListMainWindow::GetColumnWidth( int col
) const
3410 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3411 wxCHECK_MSG( node
, 0, _T("invalid column index") );
3413 wxListHeaderData
*column
= node
->GetData();
3414 return column
->GetWidth();
3417 // ----------------------------------------------------------------------------
3419 // ----------------------------------------------------------------------------
3421 void wxListMainWindow::SetItem( wxListItem
&item
)
3423 long id
= item
.m_itemId
;
3424 wxCHECK_RET( id
>= 0 && (size_t)id
< GetItemCount(),
3425 _T("invalid item index in SetItem") );
3429 wxListLineData
*line
= GetLine((size_t)id
);
3430 line
->SetItem( item
.m_col
, item
);
3433 if ( InReportView() )
3435 // just refresh the line to show the new value of the text/image
3436 RefreshLine((size_t)id
);
3440 // refresh everything (resulting in horrible flicker - FIXME!)
3445 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask
)
3447 wxCHECK_RET( litem
>= 0 && (size_t)litem
< GetItemCount(),
3448 _T("invalid list ctrl item index in SetItem") );
3450 size_t oldCurrent
= m_current
;
3451 size_t item
= (size_t)litem
; // sdafe because of the check above
3453 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3455 if ( state
& wxLIST_STATE_FOCUSED
)
3457 // don't do anything if this item is already focused
3458 if ( item
!= m_current
)
3460 OnUnfocusLine( m_current
);
3462 OnFocusLine( m_current
);
3464 if ( IsSingleSel() && (oldCurrent
!= (size_t)-1) )
3466 HighlightLine(oldCurrent
, FALSE
);
3467 RefreshLine(oldCurrent
);
3470 RefreshLine( m_current
);
3475 // don't do anything if this item is not focused
3476 if ( item
== m_current
)
3478 OnUnfocusLine( m_current
);
3479 m_current
= (size_t)-1;
3484 if ( stateMask
& wxLIST_STATE_SELECTED
)
3486 bool on
= (state
& wxLIST_STATE_SELECTED
) != 0;
3488 if ( IsSingleSel() )
3492 // selecting the item also makes it the focused one in the
3494 if ( m_current
!= item
)
3496 OnUnfocusLine( m_current
);
3498 OnFocusLine( m_current
);
3500 if ( oldCurrent
!= (size_t)-1 )
3502 HighlightLine( oldCurrent
, FALSE
);
3503 RefreshLine( oldCurrent
);
3509 // only the current item may be selected anyhow
3510 if ( item
!= m_current
)
3515 if ( HighlightLine(item
, on
) )
3522 int wxListMainWindow::GetItemState( long item
, long stateMask
)
3524 wxCHECK_MSG( item
>= 0 && (size_t)item
< GetItemCount(), 0,
3525 _T("invalid list ctrl item index in GetItemState()") );
3527 int ret
= wxLIST_STATE_DONTCARE
;
3529 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3531 if ( (size_t)item
== m_current
)
3532 ret
|= wxLIST_STATE_FOCUSED
;
3535 if ( stateMask
& wxLIST_STATE_SELECTED
)
3537 if ( IsHighlighted(item
) )
3538 ret
|= wxLIST_STATE_SELECTED
;
3544 void wxListMainWindow::GetItem( wxListItem
&item
)
3546 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
< GetItemCount(),
3547 _T("invalid item index in GetItem") );
3549 wxListLineData
*line
= GetLine((size_t)item
.m_itemId
);
3550 line
->GetItem( item
.m_col
, item
);
3553 // ----------------------------------------------------------------------------
3555 // ----------------------------------------------------------------------------
3557 size_t wxListMainWindow::GetItemCount() const
3559 return IsVirtual() ? m_countVirt
: m_lines
.GetCount();
3562 void wxListMainWindow::SetItemCount(long count
)
3564 m_selStore
.SetItemCount(count
);
3565 m_countVirt
= count
;
3567 ResetVisibleLinesRange();
3569 // scrollbars must be reset
3573 int wxListMainWindow::GetSelectedItemCount()
3575 // deal with the quick case first
3576 if ( IsSingleSel() )
3578 return HasCurrent() ? IsHighlighted(m_current
) : FALSE
;
3581 // virtual controls remmebers all its selections itself
3583 return m_selStore
.GetSelectedCount();
3585 // TODO: we probably should maintain the number of items selected even for
3586 // non virtual controls as enumerating all lines is really slow...
3587 size_t countSel
= 0;
3588 size_t count
= GetItemCount();
3589 for ( size_t line
= 0; line
< count
; line
++ )
3591 if ( GetLine(line
)->IsHighlighted() )
3598 // ----------------------------------------------------------------------------
3599 // item position/size
3600 // ----------------------------------------------------------------------------
3602 void wxListMainWindow::GetItemRect( long index
, wxRect
&rect
)
3604 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3605 _T("invalid index in GetItemRect") );
3607 rect
= GetLineRect((size_t)index
);
3609 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
3612 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
)
3615 GetItemRect(item
, rect
);
3623 // ----------------------------------------------------------------------------
3624 // geometry calculation
3625 // ----------------------------------------------------------------------------
3627 void wxListMainWindow::RecalculatePositions(bool noRefresh
)
3629 wxClientDC
dc( this );
3630 dc
.SetFont( GetFont() );
3633 if ( HasFlag(wxLC_ICON
) )
3634 iconSpacing
= m_normal_spacing
;
3635 else if ( HasFlag(wxLC_SMALL_ICON
) )
3636 iconSpacing
= m_small_spacing
;
3642 GetClientSize( &clientWidth
, &clientHeight
);
3644 if ( HasFlag(wxLC_REPORT
) )
3646 // all lines have the same height
3647 int lineHeight
= GetLineHeight();
3649 // scroll one line per step
3650 m_yScroll
= lineHeight
;
3652 size_t lineCount
= GetItemCount();
3653 int entireHeight
= lineCount
*lineHeight
+ LINE_SPACING
;
3655 m_linesPerPage
= clientHeight
/ lineHeight
;
3657 ResetVisibleLinesRange();
3659 SetScrollbars( m_xScroll
, m_yScroll
,
3660 (GetHeaderWidth() + m_xScroll
- 1)/m_xScroll
,
3661 (entireHeight
+ m_yScroll
- 1)/m_yScroll
,
3662 GetScrollPos(wxHORIZONTAL
),
3663 GetScrollPos(wxVERTICAL
),
3668 // at first we try without any scrollbar. if the items don't
3669 // fit into the window, we recalculate after subtracting an
3670 // approximated 15 pt for the horizontal scrollbar
3672 clientHeight
-= 4; // sunken frame
3674 int entireWidth
= 0;
3676 for (int tries
= 0; tries
< 2; tries
++)
3683 int currentlyVisibleLines
= 0;
3685 size_t count
= GetItemCount();
3686 for (size_t i
= 0; i
< count
; i
++)
3688 currentlyVisibleLines
++;
3689 wxListLineData
*line
= GetLine(i
);
3690 line
->CalculateSize( &dc
, iconSpacing
);
3691 line
->SetPosition( x
, y
, clientWidth
, iconSpacing
);
3693 wxSize sizeLine
= GetLineSize(i
);
3695 if ( maxWidth
< sizeLine
.x
)
3696 maxWidth
= sizeLine
.x
;
3699 if (currentlyVisibleLines
> m_linesPerPage
)
3700 m_linesPerPage
= currentlyVisibleLines
;
3702 // assume that the size of the next one is the same... (FIXME)
3703 if ( y
+ sizeLine
.y
- 6 >= clientHeight
)
3705 currentlyVisibleLines
= 0;
3708 entireWidth
+= maxWidth
+6;
3711 if ( i
== count
- 1 )
3712 entireWidth
+= maxWidth
;
3713 if ((tries
== 0) && (entireWidth
> clientWidth
))
3715 clientHeight
-= 15; // scrollbar height
3717 currentlyVisibleLines
= 0;
3720 if ( i
== count
- 1 )
3721 tries
= 1; // everything fits, no second try required
3725 int scroll_pos
= GetScrollPos( wxHORIZONTAL
);
3726 SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE
);
3731 // FIXME: why should we call it from here?
3738 void wxListMainWindow::RefreshAll()
3743 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3746 headerWin
->m_dirty
= FALSE
;
3747 headerWin
->Refresh();
3751 void wxListMainWindow::UpdateCurrent()
3753 if ( !HasCurrent() && !IsEmpty() )
3758 if ( m_current
!= (size_t)-1 )
3760 OnFocusLine( m_current
);
3764 long wxListMainWindow::GetNextItem( long item
,
3765 int WXUNUSED(geometry
),
3769 max
= GetItemCount();
3770 wxCHECK_MSG( (ret
== -1) || (ret
< max
), -1,
3771 _T("invalid listctrl index in GetNextItem()") );
3773 // notice that we start with the next item (or the first one if item == -1)
3774 // and this is intentional to allow writing a simple loop to iterate over
3775 // all selected items
3779 // this is not an error because the index was ok initially, just no
3790 size_t count
= GetItemCount();
3791 for ( size_t line
= (size_t)ret
; line
< count
; line
++ )
3793 if ( (state
& wxLIST_STATE_FOCUSED
) && (line
== m_current
) )
3796 if ( (state
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) )
3803 // ----------------------------------------------------------------------------
3805 // ----------------------------------------------------------------------------
3807 void wxListMainWindow::DeleteItem( long lindex
)
3809 size_t count
= GetItemCount();
3811 wxCHECK_RET( (lindex
>= 0) && ((size_t)lindex
< count
),
3812 _T("invalid item index in DeleteItem") );
3814 size_t index
= (size_t)lindex
;
3816 // we don't need to adjust the index for the previous items
3817 if ( HasCurrent() && m_current
>= index
)
3819 // if the current item is being deleted, we want the next one to
3820 // become selected - unless there is no next one - so don't adjust
3821 // m_current in this case
3822 if ( m_current
!= index
|| m_current
== count
- 1 )
3828 if ( InReportView() )
3830 ResetVisibleLinesRange();
3837 m_selStore
.OnItemDelete(index
);
3841 m_lines
.RemoveAt( index
);
3846 SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
);
3848 RefreshAfter(index
);
3851 void wxListMainWindow::DeleteColumn( int col
)
3853 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3855 wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") );
3858 m_columns
.DeleteNode( node
);
3861 void wxListMainWindow::DoDeleteAllItems()
3865 // nothing to do - in particular, don't send the event
3871 // to make the deletion of all items faster, we don't send the
3872 // notifications for each item deletion in this case but only one event
3873 // for all of them: this is compatible with wxMSW and documented in
3874 // DeleteAllItems() description
3876 wxListEvent
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() );
3877 event
.SetEventObject( GetParent() );
3878 GetParent()->GetEventHandler()->ProcessEvent( event
);
3887 if ( InReportView() )
3889 ResetVisibleLinesRange();
3895 void wxListMainWindow::DeleteAllItems()
3899 RecalculatePositions();
3902 void wxListMainWindow::DeleteEverything()
3909 // ----------------------------------------------------------------------------
3910 // scanning for an item
3911 // ----------------------------------------------------------------------------
3913 void wxListMainWindow::EnsureVisible( long index
)
3915 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3916 _T("invalid index in EnsureVisible") );
3918 // We have to call this here because the label in question might just have
3919 // been added and its position is not known yet
3924 RecalculatePositions(TRUE
/* no refresh */);
3927 MoveToItem((size_t)index
);
3930 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) )
3937 size_t count
= GetItemCount();
3938 for ( size_t i
= (size_t)pos
; i
< count
; i
++ )
3940 wxListLineData
*line
= GetLine(i
);
3941 if ( line
->GetText(0) == tmp
)
3948 long wxListMainWindow::FindItem(long start
, long data
)
3954 size_t count
= GetItemCount();
3955 for (size_t i
= (size_t)pos
; i
< count
; i
++)
3957 wxListLineData
*line
= GetLine(i
);
3959 line
->GetItem( 0, item
);
3960 if (item
.m_data
== data
)
3967 long wxListMainWindow::HitTest( int x
, int y
, int &flags
)
3969 CalcUnscrolledPosition( x
, y
, &x
, &y
);
3971 if ( HasFlag(wxLC_REPORT
) )
3973 size_t current
= y
/ GetLineHeight();
3974 flags
= HitTestLine(current
, x
, y
);
3980 // TODO: optimize it too! this is less simple than for report view but
3981 // enumerating all items is still not a way to do it!!
3982 size_t count
= GetItemCount();
3983 for ( size_t current
= 0; current
< count
; current
++ )
3985 flags
= HitTestLine(current
, x
, y
);
3994 // ----------------------------------------------------------------------------
3996 // ----------------------------------------------------------------------------
3998 void wxListMainWindow::InsertItem( wxListItem
&item
)
4000 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
4002 size_t count
= GetItemCount();
4003 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
<= count
,
4004 _T("invalid item index") );
4006 size_t id
= item
.m_itemId
;
4011 if ( HasFlag(wxLC_REPORT
) )
4013 else if ( HasFlag(wxLC_LIST
) )
4015 else if ( HasFlag(wxLC_ICON
) )
4017 else if ( HasFlag(wxLC_SMALL_ICON
) )
4018 mode
= wxLC_ICON
; // no typo
4021 wxFAIL_MSG( _T("unknown mode") );
4024 wxListLineData
*line
= new wxListLineData(this);
4026 line
->SetItem( 0, item
);
4028 m_lines
.Insert( line
, id
);
4031 RefreshLines(id
, GetItemCount() - 1);
4034 void wxListMainWindow::InsertColumn( long col
, wxListItem
&item
)
4037 if ( HasFlag(wxLC_REPORT
) )
4039 if (item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
4040 item
.m_width
= GetTextLength( item
.m_text
);
4041 wxListHeaderData
*column
= new wxListHeaderData( item
);
4042 if ((col
>= 0) && (col
< (int)m_columns
.GetCount()))
4044 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
4045 m_columns
.Insert( node
, column
);
4049 m_columns
.Append( column
);
4054 // ----------------------------------------------------------------------------
4056 // ----------------------------------------------------------------------------
4058 wxListCtrlCompare list_ctrl_compare_func_2
;
4059 long list_ctrl_compare_data
;
4061 int LINKAGEMODE
list_ctrl_compare_func_1( wxListLineData
**arg1
, wxListLineData
**arg2
)
4063 wxListLineData
*line1
= *arg1
;
4064 wxListLineData
*line2
= *arg2
;
4066 line1
->GetItem( 0, item
);
4067 long data1
= item
.m_data
;
4068 line2
->GetItem( 0, item
);
4069 long data2
= item
.m_data
;
4070 return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data
);
4073 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data
)
4075 list_ctrl_compare_func_2
= fn
;
4076 list_ctrl_compare_data
= data
;
4077 m_lines
.Sort( list_ctrl_compare_func_1
);
4081 // ----------------------------------------------------------------------------
4083 // ----------------------------------------------------------------------------
4085 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
)
4087 // update our idea of which lines are shown when we redraw the window the
4089 ResetVisibleLinesRange();
4092 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4093 wxScrolledWindow::OnScroll(event
);
4095 HandleOnScroll( event
);
4098 if ( event
.GetOrientation() == wxHORIZONTAL
&& HasHeader() )
4100 wxListCtrl
* lc
= GetListCtrl();
4101 wxCHECK_RET( lc
, _T("no listctrl window?") );
4103 lc
->m_headerWin
->Refresh() ;
4105 lc
->m_headerWin
->MacUpdateImmediately() ;
4110 int wxListMainWindow::GetCountPerPage() const
4112 if ( !m_linesPerPage
)
4114 wxConstCast(this, wxListMainWindow
)->
4115 m_linesPerPage
= GetClientSize().y
/ GetLineHeight();
4118 return m_linesPerPage
;
4121 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
)
4123 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") );
4125 if ( m_lineFrom
== (size_t)-1 )
4127 size_t count
= GetItemCount();
4130 m_lineFrom
= GetScrollPos(wxVERTICAL
);
4132 // this may happen if SetScrollbars() hadn't been called yet
4133 if ( m_lineFrom
>= count
)
4134 m_lineFrom
= count
- 1;
4136 // we redraw one extra line but this is needed to make the redrawing
4137 // logic work when there is a fractional number of lines on screen
4138 m_lineTo
= m_lineFrom
+ m_linesPerPage
;
4139 if ( m_lineTo
>= count
)
4140 m_lineTo
= count
- 1;
4142 else // empty control
4145 m_lineTo
= (size_t)-1;
4149 wxASSERT_MSG( IsEmpty() ||
4150 (m_lineFrom
<= m_lineTo
&& m_lineTo
< GetItemCount()),
4151 _T("GetVisibleLinesRange() returns incorrect result") );
4159 // -------------------------------------------------------------------------------------
4161 // -------------------------------------------------------------------------------------
4163 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
4165 wxListItem::wxListItem()
4174 m_format
= wxLIST_FORMAT_CENTRE
;
4180 void wxListItem::Clear()
4189 m_format
= wxLIST_FORMAT_CENTRE
;
4196 void wxListItem::ClearAttributes()
4205 // -------------------------------------------------------------------------------------
4207 // -------------------------------------------------------------------------------------
4209 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
4211 wxListEvent::wxListEvent( wxEventType commandType
, int id
)
4212 : wxNotifyEvent( commandType
, id
)
4218 m_cancelled
= FALSE
;
4223 void wxListEvent::CopyObject(wxObject
& object_dest
) const
4225 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
4227 wxNotifyEvent::CopyObject(object_dest
);
4229 obj
->m_code
= m_code
;
4230 obj
->m_itemIndex
= m_itemIndex
;
4231 obj
->m_oldItemIndex
= m_oldItemIndex
;
4233 obj
->m_cancelled
= m_cancelled
;
4234 obj
->m_pointDrag
= m_pointDrag
;
4235 obj
->m_item
.m_mask
= m_item
.m_mask
;
4236 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
4237 obj
->m_item
.m_col
= m_item
.m_col
;
4238 obj
->m_item
.m_state
= m_item
.m_state
;
4239 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
4240 obj
->m_item
.m_text
= m_item
.m_text
;
4241 obj
->m_item
.m_image
= m_item
.m_image
;
4242 obj
->m_item
.m_data
= m_item
.m_data
;
4243 obj
->m_item
.m_format
= m_item
.m_format
;
4244 obj
->m_item
.m_width
= m_item
.m_width
;
4246 if ( m_item
.HasAttributes() )
4248 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
4252 // -------------------------------------------------------------------------------------
4254 // -------------------------------------------------------------------------------------
4256 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
4258 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
)
4259 EVT_SIZE(wxListCtrl::OnSize
)
4260 EVT_IDLE(wxListCtrl::OnIdle
)
4263 wxListCtrl::wxListCtrl()
4265 m_imageListNormal
= (wxImageList
*) NULL
;
4266 m_imageListSmall
= (wxImageList
*) NULL
;
4267 m_imageListState
= (wxImageList
*) NULL
;
4269 m_ownsImageListNormal
=
4270 m_ownsImageListSmall
=
4271 m_ownsImageListState
= FALSE
;
4273 m_mainWin
= (wxListMainWindow
*) NULL
;
4274 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4277 wxListCtrl::~wxListCtrl()
4280 m_mainWin
->ResetCurrent();
4282 if (m_ownsImageListNormal
)
4283 delete m_imageListNormal
;
4284 if (m_ownsImageListSmall
)
4285 delete m_imageListSmall
;
4286 if (m_ownsImageListState
)
4287 delete m_imageListState
;
4290 void wxListCtrl::CreateHeaderWindow()
4292 m_headerWin
= new wxListHeaderWindow
4294 this, -1, m_mainWin
,
4296 wxSize(GetClientSize().x
, HEADER_HEIGHT
),
4301 bool wxListCtrl::Create(wxWindow
*parent
,
4306 const wxValidator
&validator
,
4307 const wxString
&name
)
4311 m_imageListState
= (wxImageList
*) NULL
;
4312 m_ownsImageListNormal
=
4313 m_ownsImageListSmall
=
4314 m_ownsImageListState
= FALSE
;
4316 m_mainWin
= (wxListMainWindow
*) NULL
;
4317 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4319 if ( !(style
& wxLC_MASK_TYPE
) )
4321 style
= style
| wxLC_LIST
;
4324 if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name
) )
4327 // don't create the inner window with the border
4328 style
&= ~wxSUNKEN_BORDER
;
4330 m_mainWin
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style
);
4332 if ( HasFlag(wxLC_REPORT
) )
4334 CreateHeaderWindow();
4336 if ( HasFlag(wxLC_NO_HEADER
) )
4338 // VZ: why do we create it at all then?
4339 m_headerWin
->Show( FALSE
);
4346 void wxListCtrl::SetSingleStyle( long style
, bool add
)
4348 wxASSERT_MSG( !(style
& wxLC_VIRTUAL
),
4349 _T("wxLC_VIRTUAL can't be [un]set") );
4351 long flag
= GetWindowStyle();
4355 if (style
& wxLC_MASK_TYPE
)
4356 flag
&= ~(wxLC_MASK_TYPE
| wxLC_VIRTUAL
);
4357 if (style
& wxLC_MASK_ALIGN
)
4358 flag
&= ~wxLC_MASK_ALIGN
;
4359 if (style
& wxLC_MASK_SORT
)
4360 flag
&= ~wxLC_MASK_SORT
;
4372 SetWindowStyleFlag( flag
);
4375 void wxListCtrl::SetWindowStyleFlag( long flag
)
4379 m_mainWin
->DeleteEverything();
4381 // has the header visibility changed?
4382 bool hasHeader
= HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
),
4383 willHaveHeader
= (flag
& wxLC_REPORT
) && !(flag
& wxLC_NO_HEADER
);
4385 if ( hasHeader
!= willHaveHeader
)
4392 // don't delete, just hide, as we can reuse it later
4393 m_headerWin
->Show(FALSE
);
4395 //else: nothing to do
4397 else // must show header
4401 CreateHeaderWindow();
4403 else // already have it, just show
4405 m_headerWin
->Show( TRUE
);
4409 ResizeReportView(willHaveHeader
);
4413 wxWindow::SetWindowStyleFlag( flag
);
4416 bool wxListCtrl::GetColumn(int col
, wxListItem
&item
) const
4418 m_mainWin
->GetColumn( col
, item
);
4422 bool wxListCtrl::SetColumn( int col
, wxListItem
& item
)
4424 m_mainWin
->SetColumn( col
, item
);
4428 int wxListCtrl::GetColumnWidth( int col
) const
4430 return m_mainWin
->GetColumnWidth( col
);
4433 bool wxListCtrl::SetColumnWidth( int col
, int width
)
4435 m_mainWin
->SetColumnWidth( col
, width
);
4439 int wxListCtrl::GetCountPerPage() const
4441 return m_mainWin
->GetCountPerPage(); // different from Windows ?
4444 bool wxListCtrl::GetItem( wxListItem
&info
) const
4446 m_mainWin
->GetItem( info
);
4450 bool wxListCtrl::SetItem( wxListItem
&info
)
4452 m_mainWin
->SetItem( info
);
4456 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId
)
4459 info
.m_text
= label
;
4460 info
.m_mask
= wxLIST_MASK_TEXT
;
4461 info
.m_itemId
= index
;
4465 info
.m_image
= imageId
;
4466 info
.m_mask
|= wxLIST_MASK_IMAGE
;
4468 m_mainWin
->SetItem(info
);
4472 int wxListCtrl::GetItemState( long item
, long stateMask
) const
4474 return m_mainWin
->GetItemState( item
, stateMask
);
4477 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask
)
4479 m_mainWin
->SetItemState( item
, state
, stateMask
);
4483 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) )
4486 info
.m_image
= image
;
4487 info
.m_mask
= wxLIST_MASK_IMAGE
;
4488 info
.m_itemId
= item
;
4489 m_mainWin
->SetItem( info
);
4493 wxString
wxListCtrl::GetItemText( long item
) const
4496 info
.m_itemId
= item
;
4497 m_mainWin
->GetItem( info
);
4501 void wxListCtrl::SetItemText( long item
, const wxString
&str
)
4504 info
.m_mask
= wxLIST_MASK_TEXT
;
4505 info
.m_itemId
= item
;
4507 m_mainWin
->SetItem( info
);
4510 long wxListCtrl::GetItemData( long item
) const
4513 info
.m_itemId
= item
;
4514 m_mainWin
->GetItem( info
);
4518 bool wxListCtrl::SetItemData( long item
, long data
)
4521 info
.m_mask
= wxLIST_MASK_DATA
;
4522 info
.m_itemId
= item
;
4524 m_mainWin
->SetItem( info
);
4528 bool wxListCtrl::GetItemRect( long item
, wxRect
&rect
, int WXUNUSED(code
) ) const
4530 m_mainWin
->GetItemRect( item
, rect
);
4534 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos
) const
4536 m_mainWin
->GetItemPosition( item
, pos
);
4540 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) )
4545 int wxListCtrl::GetItemCount() const
4547 return m_mainWin
->GetItemCount();
4550 int wxListCtrl::GetColumnCount() const
4552 return m_mainWin
->GetColumnCount();
4555 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall
)
4557 m_mainWin
->SetItemSpacing( spacing
, isSmall
);
4560 int wxListCtrl::GetItemSpacing( bool isSmall
) const
4562 return m_mainWin
->GetItemSpacing( isSmall
);
4565 int wxListCtrl::GetSelectedItemCount() const
4567 return m_mainWin
->GetSelectedItemCount();
4570 wxColour
wxListCtrl::GetTextColour() const
4572 return GetForegroundColour();
4575 void wxListCtrl::SetTextColour(const wxColour
& col
)
4577 SetForegroundColour(col
);
4580 long wxListCtrl::GetTopItem() const
4585 long wxListCtrl::GetNextItem( long item
, int geom
, int state
) const
4587 return m_mainWin
->GetNextItem( item
, geom
, state
);
4590 wxImageList
*wxListCtrl::GetImageList(int which
) const
4592 if (which
== wxIMAGE_LIST_NORMAL
)
4594 return m_imageListNormal
;
4596 else if (which
== wxIMAGE_LIST_SMALL
)
4598 return m_imageListSmall
;
4600 else if (which
== wxIMAGE_LIST_STATE
)
4602 return m_imageListState
;
4604 return (wxImageList
*) NULL
;
4607 void wxListCtrl::SetImageList( wxImageList
*imageList
, int which
)
4609 if ( which
== wxIMAGE_LIST_NORMAL
)
4611 if (m_ownsImageListNormal
) delete m_imageListNormal
;
4612 m_imageListNormal
= imageList
;
4613 m_ownsImageListNormal
= FALSE
;
4615 else if ( which
== wxIMAGE_LIST_SMALL
)
4617 if (m_ownsImageListSmall
) delete m_imageListSmall
;
4618 m_imageListSmall
= imageList
;
4619 m_ownsImageListSmall
= FALSE
;
4621 else if ( which
== wxIMAGE_LIST_STATE
)
4623 if (m_ownsImageListState
) delete m_imageListState
;
4624 m_imageListState
= imageList
;
4625 m_ownsImageListState
= FALSE
;
4628 m_mainWin
->SetImageList( imageList
, which
);
4631 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
4633 SetImageList(imageList
, which
);
4634 if ( which
== wxIMAGE_LIST_NORMAL
)
4635 m_ownsImageListNormal
= TRUE
;
4636 else if ( which
== wxIMAGE_LIST_SMALL
)
4637 m_ownsImageListSmall
= TRUE
;
4638 else if ( which
== wxIMAGE_LIST_STATE
)
4639 m_ownsImageListState
= TRUE
;
4642 bool wxListCtrl::Arrange( int WXUNUSED(flag
) )
4647 bool wxListCtrl::DeleteItem( long item
)
4649 m_mainWin
->DeleteItem( item
);
4653 bool wxListCtrl::DeleteAllItems()
4655 m_mainWin
->DeleteAllItems();
4659 bool wxListCtrl::DeleteAllColumns()
4661 size_t count
= m_mainWin
->m_columns
.GetCount();
4662 for ( size_t n
= 0; n
< count
; n
++ )
4668 void wxListCtrl::ClearAll()
4670 m_mainWin
->DeleteEverything();
4673 bool wxListCtrl::DeleteColumn( int col
)
4675 m_mainWin
->DeleteColumn( col
);
4679 void wxListCtrl::Edit( long item
)
4681 m_mainWin
->EditLabel( item
);
4684 bool wxListCtrl::EnsureVisible( long item
)
4686 m_mainWin
->EnsureVisible( item
);
4690 long wxListCtrl::FindItem( long start
, const wxString
& str
, bool partial
)
4692 return m_mainWin
->FindItem( start
, str
, partial
);
4695 long wxListCtrl::FindItem( long start
, long data
)
4697 return m_mainWin
->FindItem( start
, data
);
4700 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
),
4701 int WXUNUSED(direction
))
4706 long wxListCtrl::HitTest( const wxPoint
&point
, int &flags
)
4708 return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags
);
4711 long wxListCtrl::InsertItem( wxListItem
& info
)
4713 m_mainWin
->InsertItem( info
);
4714 return info
.m_itemId
;
4717 long wxListCtrl::InsertItem( long index
, const wxString
&label
)
4720 info
.m_text
= label
;
4721 info
.m_mask
= wxLIST_MASK_TEXT
;
4722 info
.m_itemId
= index
;
4723 return InsertItem( info
);
4726 long wxListCtrl::InsertItem( long index
, int imageIndex
)
4729 info
.m_mask
= wxLIST_MASK_IMAGE
;
4730 info
.m_image
= imageIndex
;
4731 info
.m_itemId
= index
;
4732 return InsertItem( info
);
4735 long wxListCtrl::InsertItem( long index
, const wxString
&label
, int imageIndex
)
4738 info
.m_text
= label
;
4739 info
.m_image
= imageIndex
;
4740 info
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_IMAGE
;
4741 info
.m_itemId
= index
;
4742 return InsertItem( info
);
4745 long wxListCtrl::InsertColumn( long col
, wxListItem
&item
)
4747 wxASSERT( m_headerWin
);
4748 m_mainWin
->InsertColumn( col
, item
);
4749 m_headerWin
->Refresh();
4754 long wxListCtrl::InsertColumn( long col
, const wxString
&heading
,
4755 int format
, int width
)
4758 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
4759 item
.m_text
= heading
;
4762 item
.m_mask
|= wxLIST_MASK_WIDTH
;
4763 item
.m_width
= width
;
4765 item
.m_format
= format
;
4767 return InsertColumn( col
, item
);
4770 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) )
4776 // fn is a function which takes 3 long arguments: item1, item2, data.
4777 // item1 is the long data associated with a first item (NOT the index).
4778 // item2 is the long data associated with a second item (NOT the index).
4779 // data is the same value as passed to SortItems.
4780 // The return value is a negative number if the first item should precede the second
4781 // item, a positive number of the second item should precede the first,
4782 // or zero if the two items are equivalent.
4783 // data is arbitrary data to be passed to the sort function.
4785 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data
)
4787 m_mainWin
->SortItems( fn
, data
);
4791 // ----------------------------------------------------------------------------
4793 // ----------------------------------------------------------------------------
4795 void wxListCtrl::OnSize(wxSizeEvent
& event
)
4800 ResizeReportView(m_mainWin
->HasHeader());
4802 m_mainWin
->RecalculatePositions();
4805 void wxListCtrl::ResizeReportView(bool showHeader
)
4808 GetClientSize( &cw
, &ch
);
4812 m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT
);
4813 m_mainWin
->SetSize( 0, HEADER_HEIGHT
+ 1, cw
, ch
- HEADER_HEIGHT
- 1 );
4815 else // no header window
4817 m_mainWin
->SetSize( 0, 0, cw
, ch
);
4821 void wxListCtrl::OnIdle( wxIdleEvent
& event
)
4825 // do it only if needed
4826 if ( !m_mainWin
->m_dirty
)
4829 m_mainWin
->RecalculatePositions();
4832 // ----------------------------------------------------------------------------
4834 // ----------------------------------------------------------------------------
4836 bool wxListCtrl::SetBackgroundColour( const wxColour
&colour
)
4840 m_mainWin
->SetBackgroundColour( colour
);
4841 m_mainWin
->m_dirty
= TRUE
;
4847 bool wxListCtrl::SetForegroundColour( const wxColour
&colour
)
4849 if ( !wxWindow::SetForegroundColour( colour
) )
4854 m_mainWin
->SetForegroundColour( colour
);
4855 m_mainWin
->m_dirty
= TRUE
;
4860 m_headerWin
->SetForegroundColour( colour
);
4866 bool wxListCtrl::SetFont( const wxFont
&font
)
4868 if ( !wxWindow::SetFont( font
) )
4873 m_mainWin
->SetFont( font
);
4874 m_mainWin
->m_dirty
= TRUE
;
4879 m_headerWin
->SetFont( font
);
4885 // ----------------------------------------------------------------------------
4886 // methods forwarded to m_mainWin
4887 // ----------------------------------------------------------------------------
4889 #if wxUSE_DRAG_AND_DROP
4891 void wxListCtrl::SetDropTarget( wxDropTarget
*dropTarget
)
4893 m_mainWin
->SetDropTarget( dropTarget
);
4896 wxDropTarget
*wxListCtrl::GetDropTarget() const
4898 return m_mainWin
->GetDropTarget();
4901 #endif // wxUSE_DRAG_AND_DROP
4903 bool wxListCtrl::SetCursor( const wxCursor
&cursor
)
4905 return m_mainWin
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
;
4908 wxColour
wxListCtrl::GetBackgroundColour() const
4910 return m_mainWin
? m_mainWin
->GetBackgroundColour() : wxColour();
4913 wxColour
wxListCtrl::GetForegroundColour() const
4915 return m_mainWin
? m_mainWin
->GetForegroundColour() : wxColour();
4918 bool wxListCtrl::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4921 return m_mainWin
->PopupMenu( menu
, x
, y
);
4924 #endif // wxUSE_MENUS
4927 void wxListCtrl::SetFocus()
4929 /* The test in window.cpp fails as we are a composite
4930 window, so it checks against "this", but not m_mainWin. */
4931 if ( FindFocus() != this )
4932 m_mainWin
->SetFocus();
4935 // ----------------------------------------------------------------------------
4936 // virtual list control support
4937 // ----------------------------------------------------------------------------
4939 wxString
wxListCtrl::OnGetItemText(long item
, long col
) const
4941 // this is a pure virtual function, in fact - which is not really pure
4942 // because the controls which are not virtual don't need to implement it
4943 wxFAIL_MSG( _T("not supposed to be called") );
4945 return wxEmptyString
;
4948 int wxListCtrl::OnGetItemImage(long item
) const
4951 wxFAIL_MSG( _T("not supposed to be called") );
4956 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long item
) const
4958 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
4959 _T("invalid item index in OnGetItemAttr()") );
4961 // no attributes by default
4965 void wxListCtrl::SetItemCount(long count
)
4967 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4969 m_mainWin
->SetItemCount(count
);
4972 void wxListCtrl::RefreshItem(long item
)
4974 m_mainWin
->RefreshLine(item
);
4977 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
)
4979 m_mainWin
->RefreshLines(itemFrom
, itemTo
);
4982 #endif // wxUSE_LISTCTRL