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 TODO for better virtual list control support:
14 1. less dumb line caching, we should cache at least all those visible
15 in the control itself and probably twice as many (we might also need to
16 cache the first one always for geometry calculations?)
18 +2. storing selections: we can't use an array to store the selected indices
19 like right now as selecting all in a control with 1000000 items is not
20 doable like this - instead, store selections as collection of individual
25 3. we need to implement searching/sorting somehow
27 4. the idea of storing the line index in the line itself is really stupid,
28 we shouldn't need it - but for this we have to get rid of all calles to
29 wxListLineData::GetFoo() and replace them with something like
31 ... we have it ourselves ...
37 5. attributes support: we need OnGetItemAttr() as well!
40 // ============================================================================
42 // ============================================================================
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
49 #pragma implementation "listctrl.h"
50 #pragma implementation "listctrlbase.h"
53 // For compilers that support precompilation, includes "wx.h".
54 #include "wx/wxprec.h"
62 #include "wx/dcscreen.h"
64 #include "wx/listctrl.h"
65 #include "wx/imaglist.h"
66 #include "wx/dynarray.h"
70 #include "wx/gtk/win_gtk.h"
73 // ----------------------------------------------------------------------------
75 // ----------------------------------------------------------------------------
77 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
)
78 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
)
79 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
)
80 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
)
81 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
)
82 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
)
83 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
)
84 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
)
85 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
)
86 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
)
87 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
)
88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
)
89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
)
90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
)
91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
)
92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
)
93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
)
95 // ----------------------------------------------------------------------------
97 // ----------------------------------------------------------------------------
99 // the height of the header window (FIXME: should depend on its font!)
100 static const int HEADER_HEIGHT
= 23;
102 // the scrollbar units
103 static const int SCROLL_UNIT_X
= 15;
104 static const int SCROLL_UNIT_Y
= 15;
106 // the spacing between the lines (in report mode)
107 static const int LINE_SPACING
= 0;
109 // extra margins around the text label
110 static const int EXTRA_WIDTH
= 3;
111 static const int EXTRA_HEIGHT
= 4;
113 // offset for the header window
114 static const int HEADER_OFFSET_X
= 1;
115 static const int HEADER_OFFSET_Y
= 1;
117 // when autosizing the columns, add some slack
118 static const int AUTOSIZE_COL_MARGIN
= 10;
120 // default and minimal widths for the header columns
121 static const int WIDTH_COL_DEFAULT
= 80;
122 static const int WIDTH_COL_MIN
= 10;
124 // ============================================================================
126 // ============================================================================
128 // ----------------------------------------------------------------------------
130 // ----------------------------------------------------------------------------
132 int CMPFUNC_CONV
wxSizeTCmpFn(size_t n1
, size_t n2
) { return n1
- n2
; }
134 WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray
);
136 // this class is used to store the selected items in the virtual list control
137 // (but it is not tied to list control and so can be used with other controls
138 // such as wxListBox in wxUniv)
140 // the idea is to make it really smart later (i.e. store the selections as an
141 // array of ranes + individual items) but, as I don't have time to do it now
142 // (this would require writing code to merge/break ranges and much more) keep
143 // it simple but define a clean interface to it which allows it to be made
145 class WXDLLEXPORT wxSelectionStore
148 wxSelectionStore() : m_itemsSel(wxSizeTCmpFn
) { Init(); }
150 // set the total number of items we handle
151 void SetItemCount(size_t count
) { m_count
= count
; }
153 // special case of SetItemCount(0)
154 void Clear() { m_itemsSel
.Clear(); m_count
= 0; }
156 // must be called when a new item is inserted/added
157 void OnItemAdd(size_t item
) { wxFAIL_MSG( _T("TODO") ); }
159 // must be called when an item is deleted
160 void OnItemDelete(size_t item
);
162 // select one item, use SelectRange() insted if possible!
164 // returns true if the items selection really changed
165 bool SelectItem(size_t item
, bool select
= TRUE
);
167 // select the range of items
169 // return true and fill the itemsChanged array with the indices of items
170 // which have changed state if "few" of them did, otherwise return false
171 // (meaning that too many items changed state to bother counting them
173 bool SelectRange(size_t itemFrom
, size_t itemTo
,
175 wxArrayInt
*itemsChanged
= NULL
);
177 // return true if the given item is selected
178 bool IsSelected(size_t item
) const;
180 // return the total number of selected items
181 size_t GetSelectedCount() const
183 return m_defaultState
? m_count
- m_itemsSel
.GetCount()
184 : m_itemsSel
.GetCount();
189 void Init() { m_defaultState
= FALSE
; }
191 // the total number of items we handle
194 // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
195 // there are more selected items than non selected ones - this allows to
196 // handle selection of all items efficiently
199 // the array of items whose selection state is different from default
200 wxIndexArray m_itemsSel
;
202 DECLARE_NO_COPY_CLASS(wxSelectionStore
)
205 //-----------------------------------------------------------------------------
206 // wxListItemData (internal)
207 //-----------------------------------------------------------------------------
209 class WXDLLEXPORT wxListItemData
212 wxListItemData(wxListMainWindow
*owner
);
215 void SetItem( const wxListItem
&info
);
216 void SetImage( int image
) { m_image
= image
; }
217 void SetData( long data
) { m_data
= data
; }
218 void SetPosition( int x
, int y
);
219 void SetSize( int width
, int height
);
221 bool HasText() const { return !m_text
.empty(); }
222 const wxString
& GetText() const { return m_text
; }
223 void SetText(const wxString
& text
) { m_text
= text
; }
225 // we can't use empty string for measuring the string width/height, so
226 // always return something
227 wxString
GetTextForMeasuring() const
229 wxString s
= GetText();
236 bool IsHit( int x
, int y
) const;
240 int GetWidth() const;
241 int GetHeight() const;
243 int GetImage() const { return m_image
; }
244 bool HasImage() const { return GetImage() != -1; }
246 void GetItem( wxListItem
&info
) const;
248 void SetAttr(wxListItemAttr
*attr
) { m_attr
= attr
; }
249 wxListItemAttr
*GetAttr() const { return m_attr
; }
252 // the item image or -1
255 // user data associated with the item
258 // the item coordinates are not used in report mode, instead this pointer
259 // is NULL and the owner window is used to retrieve the item position and
263 // the list ctrl we are in
264 wxListMainWindow
*m_owner
;
266 // custom attributes or NULL
267 wxListItemAttr
*m_attr
;
270 // common part of all ctors
276 //-----------------------------------------------------------------------------
277 // wxListHeaderData (internal)
278 //-----------------------------------------------------------------------------
280 class WXDLLEXPORT wxListHeaderData
: public wxObject
294 wxListHeaderData( const wxListItem
&info
);
295 void SetItem( const wxListItem
&item
);
296 void SetPosition( int x
, int y
);
297 void SetWidth( int w
);
298 void SetFormat( int format
);
299 void SetHeight( int h
);
300 bool HasImage() const;
302 bool HasText() const { return !m_text
.empty(); }
303 const wxString
& GetText() const { return m_text
; }
304 void SetText(const wxString
& text
) { m_text
= text
; }
306 void GetItem( wxListItem
&item
);
308 bool IsHit( int x
, int y
) const;
309 int GetImage() const;
310 int GetWidth() const;
311 int GetFormat() const;
314 DECLARE_DYNAMIC_CLASS(wxListHeaderData
);
317 //-----------------------------------------------------------------------------
318 // wxListLineData (internal)
319 //-----------------------------------------------------------------------------
321 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
);
322 #include "wx/listimpl.cpp"
323 WX_DEFINE_LIST(wxListItemDataList
);
325 class WXDLLEXPORT wxListLineData
328 // the list of subitems: only may have more than one item in report mode
329 wxListItemDataList m_items
;
331 // this is not used in report view
343 // the part to be highlighted
344 wxRect m_rectHighlight
;
347 // is this item selected? [NB: not used in virtual mode]
350 // back pointer to the list ctrl
351 wxListMainWindow
*m_owner
;
354 wxListLineData(wxListMainWindow
*owner
);
356 ~wxListLineData() { delete m_gi
; }
358 // are we in report mode?
359 inline bool InReportView() const;
361 // are we in virtual report mode?
362 inline bool IsVirtual() const;
364 // these 2 methods shouldn't be called for report view controls, in that
365 // case we determine our position/size ourselves
367 // calculate the size of the line
368 void CalculateSize( wxDC
*dc
, int spacing
);
370 // remember the position this line appears at
371 void SetPosition( int x
, int y
, int window_width
, int spacing
);
375 void SetImage( int image
) { SetImage(0, image
); }
376 int GetImage() const { return GetImage(0); }
377 bool HasImage() const { return GetImage() != -1; }
378 bool HasText() const { return !GetText(0).empty(); }
380 void SetItem( int index
, const wxListItem
&info
);
381 void GetItem( int index
, wxListItem
&info
);
383 wxString
GetText(int index
) const;
384 void SetText( int index
, const wxString s
);
386 wxListItemAttr
*GetAttr() const;
387 void SetAttr(wxListItemAttr
*attr
);
389 // return true if the highlighting really changed
390 bool Highlight( bool on
);
392 void ReverseHighlight();
394 bool IsHighlighted() const
396 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
398 return m_highlighted
;
401 // draw the line on the given DC in icon/list mode
402 void Draw( wxDC
*dc
);
404 // the same in report mode
405 void DrawInReportMode( wxDC
*dc
,
407 const wxRect
& rectHL
,
411 // set the line to contain num items (only can be > 1 in report mode)
412 void InitItems( int num
);
414 // get the mode (i.e. style) of the list control
415 inline int GetMode() const;
417 // prepare the DC for drawing with these item's attributes, return true if
418 // we need to draw the items background to highlight it, false otherwise
419 bool SetAttributes(wxDC
*dc
,
420 const wxListItemAttr
*attr
,
423 // these are only used by GetImage/SetImage above, we don't support images
424 // with subitems at the public API level yet
425 void SetImage( int index
, int image
);
426 int GetImage( int index
) const;
429 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
);
430 #include "wx/arrimpl.cpp"
431 WX_DEFINE_OBJARRAY(wxListLineDataArray
);
433 //-----------------------------------------------------------------------------
434 // wxListHeaderWindow (internal)
435 //-----------------------------------------------------------------------------
437 class WXDLLEXPORT wxListHeaderWindow
: public wxWindow
440 wxListMainWindow
*m_owner
;
441 wxCursor
*m_currentCursor
;
442 wxCursor
*m_resizeCursor
;
445 // column being resized
448 // divider line position in logical (unscrolled) coords
451 // minimal position beyond which the divider line can't be dragged in
456 wxListHeaderWindow();
457 virtual ~wxListHeaderWindow();
459 wxListHeaderWindow( wxWindow
*win
,
461 wxListMainWindow
*owner
,
462 const wxPoint
&pos
= wxDefaultPosition
,
463 const wxSize
&size
= wxDefaultSize
,
465 const wxString
&name
= "wxlistctrlcolumntitles" );
467 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
469 void AdjustDC(wxDC
& dc
);
471 void OnPaint( wxPaintEvent
&event
);
472 void OnMouse( wxMouseEvent
&event
);
473 void OnSetFocus( wxFocusEvent
&event
);
479 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
)
480 DECLARE_EVENT_TABLE()
483 //-----------------------------------------------------------------------------
484 // wxListRenameTimer (internal)
485 //-----------------------------------------------------------------------------
487 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
490 wxListMainWindow
*m_owner
;
493 wxListRenameTimer( wxListMainWindow
*owner
);
497 //-----------------------------------------------------------------------------
498 // wxListTextCtrl (internal)
499 //-----------------------------------------------------------------------------
501 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
506 wxListMainWindow
*m_owner
;
507 wxString m_startValue
;
511 wxListTextCtrl( wxWindow
*parent
, const wxWindowID id
,
512 bool *accept
, wxString
*res
, wxListMainWindow
*owner
,
513 const wxString
&value
= "",
514 const wxPoint
&pos
= wxDefaultPosition
, const wxSize
&size
= wxDefaultSize
,
516 const wxValidator
& validator
= wxDefaultValidator
,
517 const wxString
&name
= "listctrltextctrl" );
518 void OnChar( wxKeyEvent
&event
);
519 void OnKeyUp( wxKeyEvent
&event
);
520 void OnKillFocus( wxFocusEvent
&event
);
523 DECLARE_DYNAMIC_CLASS(wxListTextCtrl
);
524 DECLARE_EVENT_TABLE()
527 //-----------------------------------------------------------------------------
528 // wxListMainWindow (internal)
529 //-----------------------------------------------------------------------------
531 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
);
532 #include "wx/listimpl.cpp"
533 WX_DEFINE_LIST(wxListHeaderDataList
);
535 class WXDLLEXPORT wxListMainWindow
: public wxScrolledWindow
539 wxListMainWindow( wxWindow
*parent
,
541 const wxPoint
& pos
= wxDefaultPosition
,
542 const wxSize
& size
= wxDefaultSize
,
544 const wxString
&name
= _T("listctrlmainwindow") );
546 virtual ~wxListMainWindow();
548 bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); }
550 // return true if this is a virtual list control
551 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); }
553 // return true if the control is in report mode
554 bool InReportView() const { return HasFlag(wxLC_REPORT
); }
556 // return true if we are in single selection mode, false if multi sel
557 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); }
559 // do we have a header window?
560 bool HasHeader() const
561 { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); }
563 void HighlightAll( bool on
);
565 // all these functions only do something if the line is currently visible
567 // change the line "selected" state, return TRUE if it really changed
568 bool HighlightLine( size_t line
, bool highlight
= TRUE
);
570 // as HighlightLine() but do it for the range of lines: this is incredibly
571 // more efficient for virtual list controls!
573 // NB: unlike HighlightLine() this one does refresh the lines on screen
574 void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on
= TRUE
);
576 // toggle the line state and refresh it
577 void ReverseHighlight( size_t line
)
578 { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); }
580 // return true if the line is highlighted
581 bool IsHighlighted(size_t line
) const;
583 // refresh one or several lines at once
584 void RefreshLine( size_t line
);
585 void RefreshLines( size_t lineFrom
, size_t lineTo
);
587 // refresh all lines below the given one: the difference with
588 // RefreshLines() is that the index here might not be a valid one (happens
589 // when the last line is deleted)
590 void RefreshAfter( size_t lineFrom
);
592 // the methods which are forwarded to wxListLineData itself in list/icon
593 // modes but are here because the lines don't store their positions in the
596 // get the bound rect for the entire line
597 wxRect
GetLineRect(size_t line
) const;
599 // get the bound rect of the label
600 wxRect
GetLineLabelRect(size_t line
) const;
602 // get the bound rect of the items icon (only may be called if we do have
604 wxRect
GetLineIconRect(size_t line
) const;
606 // get the rect to be highlighted when the item has focus
607 wxRect
GetLineHighlightRect(size_t line
) const;
609 // get the size of the total line rect
610 wxSize
GetLineSize(size_t line
) const
611 { return GetLineRect(line
).GetSize(); }
613 // return the hit code for the corresponding position (in this line)
614 long HitTestLine(size_t line
, int x
, int y
) const;
616 // bring the selected item into view, scrolling to it if necessary
617 void MoveToItem(size_t item
);
619 // bring the current item into view
620 void MoveToFocus() { MoveToItem(m_current
); }
622 void EditLabel( long item
);
623 void OnRenameTimer();
624 void OnRenameAccept();
626 void OnMouse( wxMouseEvent
&event
);
628 // called to switch the selection from the current item to newCurrent,
629 void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event
);
631 void OnChar( wxKeyEvent
&event
);
632 void OnKeyDown( wxKeyEvent
&event
);
633 void OnSetFocus( wxFocusEvent
&event
);
634 void OnKillFocus( wxFocusEvent
&event
);
635 void OnScroll(wxScrollWinEvent
& event
) ;
637 void OnPaint( wxPaintEvent
&event
);
639 void DrawImage( int index
, wxDC
*dc
, int x
, int y
);
640 void GetImageSize( int index
, int &width
, int &height
) const;
641 int GetTextLength( const wxString
&s
) const;
643 void SetImageList( wxImageList
*imageList
, int which
);
644 void SetItemSpacing( int spacing
, bool isSmall
= FALSE
);
645 int GetItemSpacing( bool isSmall
= FALSE
);
647 void SetColumn( int col
, wxListItem
&item
);
648 void SetColumnWidth( int col
, int width
);
649 void GetColumn( int col
, wxListItem
&item
) const;
650 int GetColumnWidth( int col
) const;
651 int GetColumnCount() const { return m_columns
.GetCount(); }
653 // returns the sum of the heights of all columns
654 int GetHeaderWidth() const;
656 int GetCountPerPage() const;
658 void SetItem( wxListItem
&item
);
659 void GetItem( wxListItem
&item
);
660 void SetItemState( long item
, long state
, long stateMask
);
661 int GetItemState( long item
, long stateMask
);
662 void GetItemRect( long index
, wxRect
&rect
);
663 bool GetItemPosition( long item
, wxPoint
& pos
);
664 int GetSelectedItemCount();
666 // set the scrollbars and update the positions of the items
667 void RecalculatePositions(bool noRefresh
= FALSE
);
669 // refresh the window and the header
672 long GetNextItem( long item
, int geometry
, int state
);
673 void DeleteItem( long index
);
674 void DeleteAllItems();
675 void DeleteColumn( int col
);
676 void DeleteEverything();
677 void EnsureVisible( long index
);
678 long FindItem( long start
, const wxString
& str
, bool partial
= FALSE
);
679 long FindItem( long start
, long data
);
680 long HitTest( int x
, int y
, int &flags
);
681 void InsertItem( wxListItem
&item
);
682 void InsertColumn( long col
, wxListItem
&item
);
683 void SortItems( wxListCtrlCompare fn
, long data
);
685 size_t GetItemCount() const;
686 bool IsEmpty() const { return GetItemCount() == 0; }
687 void SetItemCount(long count
);
689 void ResetCurrent() { m_current
= (size_t)-1; }
690 bool HasCurrent() const { return m_current
!= (size_t)-1; }
692 // send out a wxListEvent
693 void SendNotify( size_t line
,
695 wxPoint point
= wxDefaultPosition
);
697 // override base class virtual to reset m_lineHeight when the font changes
698 virtual bool SetFont(const wxFont
& font
)
700 if ( !wxScrolledWindow::SetFont(font
) )
708 // these are for wxListLineData usage only
710 // get the backpointer to the list ctrl
711 wxListCtrl
*GetListCtrl() const
713 return wxStaticCast(GetParent(), wxListCtrl
);
716 // get the height of all lines (assuming they all do have the same height)
717 wxCoord
GetLineHeight() const;
719 // get the y position of the given line (only for report view)
720 wxCoord
GetLineY(size_t line
) const;
723 // the array of all line objects for a non virtual list control
724 wxListLineDataArray m_lines
;
726 // the list of column objects
727 wxListHeaderDataList m_columns
;
729 // currently focused item or -1
732 // the item currently being edited or -1
733 size_t m_currentEdit
;
735 // the number of lines per page
738 // this flag is set when something which should result in the window
739 // redrawing happens (i.e. an item was added or deleted, or its appearance
740 // changed) and OnPaint() doesn't redraw the window while it is set which
741 // allows to minimize the number of repaintings when a lot of items are
742 // being added. The real repainting occurs only after the next OnIdle()
746 wxBrush
*m_highlightBrush
;
747 wxColour
*m_highlightColour
;
750 wxImageList
*m_small_image_list
;
751 wxImageList
*m_normal_image_list
;
753 int m_normal_spacing
;
757 wxTimer
*m_renameTimer
;
759 wxString m_renameRes
;
764 // for double click logic
765 size_t m_lineLastClicked
,
766 m_lineBeforeLastClicked
;
769 // the total count of items in a virtual list control
772 // the object maintaining the items selection state, only used in virtual
774 wxSelectionStore m_selStore
;
776 // common part of all ctors
779 // intiialize m_[xy]Scroll
780 void InitScrolling();
782 // get the line data for the given index
783 wxListLineData
*GetLine(size_t n
) const
785 wxASSERT_MSG( n
!= (size_t)-1, _T("invalid line index") );
789 wxConstCast(this, wxListMainWindow
)->CacheLineData(n
);
797 // get a dummy line which can be used for geometry calculations and such:
798 // you must use GetLine() if you want to really draw the line
799 wxListLineData
*GetDummyLine() const;
801 // cache the line data of the n-th line in m_lines[0]
802 void CacheLineData(size_t line
);
804 // get the range of visible lines
805 void GetVisibleLinesRange(size_t *from
, size_t *to
);
807 // force us to recalculate the range of visible lines
808 void ResetVisibleLinesRange() { m_lineFrom
= (size_t)-1; }
810 // get the colour to be used for drawing the rules
811 wxColour
GetRuleColour() const
816 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
);
821 // initialize the current item if needed
822 void UpdateCurrent();
824 // delete all items but don't refresh: called from dtor
825 void DoDeleteAllItems();
827 // called when an item is [un]focuded, i.e. becomes [not] current
830 void OnFocusLine( size_t line
);
831 void OnUnfocusLine( size_t line
);
833 // the height of one line using the current font
834 wxCoord m_lineHeight
;
836 // the total header width or 0 if not calculated yet
837 wxCoord m_headerWidth
;
839 // the first and last lines being shown on screen right now (inclusive),
840 // both may be -1 if they must be calculated so never access them directly:
841 // use GetVisibleLinesRange() above instead
845 DECLARE_DYNAMIC_CLASS(wxListMainWindow
);
846 DECLARE_EVENT_TABLE()
849 // ============================================================================
851 // ============================================================================
853 // ----------------------------------------------------------------------------
855 // ----------------------------------------------------------------------------
857 bool wxSelectionStore::IsSelected(size_t item
) const
859 bool isSel
= m_itemsSel
.Index(item
) != wxNOT_FOUND
;
861 // if the default state is to be selected, being in m_itemsSel means that
862 // the item is not selected, so we have to inverse the logic
863 return m_defaultState
? !isSel
: isSel
;
866 bool wxSelectionStore::SelectItem(size_t item
, bool select
)
868 // search for the item ourselves as like this we get the index where to
869 // insert it later if needed, so we do only one search in the array instead
870 // of two (adding item to a sorted array requires a search)
871 size_t index
= m_itemsSel
.IndexForInsert(item
);
872 bool isSel
= index
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
;
874 if ( select
!= m_defaultState
)
878 m_itemsSel
.AddAt(item
, index
);
883 else // reset to default state
887 m_itemsSel
.RemoveAt(index
);
895 bool wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
,
897 wxArrayInt
*itemsChanged
)
899 // 100 is hardcoded but it shouldn't matter much: the important thing is
900 // that we don't refresh everything when really few (e.g. 1 or 2) items
902 static const size_t MANY_ITEMS
= 100;
904 wxASSERT_MSG( itemFrom
<= itemTo
, _T("should be in order") );
906 // are we going to have more [un]selected items than the other ones?
907 if ( itemTo
- itemFrom
> m_count
/2 )
909 if ( select
!= m_defaultState
)
911 // the default state now becomes the same as 'select'
912 m_defaultState
= select
;
914 // so all the old selections (which had state select) shouldn't be
915 // selected any more, but all the other ones should
916 wxIndexArray selOld
= m_itemsSel
;
919 // TODO: it should be possible to optimize the searches a bit
920 // knowing the possible range
923 for ( item
= 0; item
< itemFrom
; item
++ )
925 if ( selOld
.Index(item
) == wxNOT_FOUND
)
926 m_itemsSel
.Add(item
);
929 for ( item
= itemTo
+ 1; item
< m_count
; item
++ )
931 if ( selOld
.Index(item
) == wxNOT_FOUND
)
932 m_itemsSel
.Add(item
);
935 // many items (> half) changed state
938 else // select == m_defaultState
940 // get the inclusive range of items between itemFrom and itemTo
941 size_t count
= m_itemsSel
.GetCount(),
942 start
= m_itemsSel
.IndexForInsert(itemFrom
),
943 end
= m_itemsSel
.IndexForInsert(itemTo
);
945 if ( start
== count
|| m_itemsSel
[start
] < itemFrom
)
950 if ( end
== count
|| m_itemsSel
[end
] > itemTo
)
957 // delete all of them (from end to avoid changing indices)
958 for ( int i
= end
; i
>= (int)start
; i
-- )
962 if ( itemsChanged
->GetCount() > MANY_ITEMS
)
964 // stop counting (see comment below)
968 itemsChanged
->Add(m_itemsSel
[i
]);
971 m_itemsSel
.RemoveAt(i
);
976 else // "few" items change state
980 itemsChanged
->Empty();
983 // just add the items to the selection
984 for ( size_t item
= itemFrom
; item
<= itemTo
; item
++ )
986 if ( SelectItem(item
, select
) && itemsChanged
)
988 itemsChanged
->Add(item
);
990 if ( itemsChanged
->GetCount() > MANY_ITEMS
)
992 // stop counting them, we'll just eat gobs of memory
993 // for nothing at all - faster to refresh everything in
1001 // we set it to NULL if there are many items changing state
1002 return itemsChanged
!= NULL
;
1005 void wxSelectionStore::OnItemDelete(size_t item
)
1007 size_t count
= m_itemsSel
.GetCount(),
1008 i
= m_itemsSel
.IndexForInsert(item
);
1010 if ( i
< count
&& m_itemsSel
[i
] == item
)
1012 // this item itself was in m_itemsSel, remove it from there
1013 m_itemsSel
.RemoveAt(i
);
1018 // and adjust the index of all which follow it
1021 // all following elements must be greater than the one we deleted
1022 wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") );
1028 //-----------------------------------------------------------------------------
1030 //-----------------------------------------------------------------------------
1032 wxListItemData::~wxListItemData()
1034 // in the virtual list control the attributes are managed by the main
1035 // program, so don't delete them
1036 if ( !m_owner
->IsVirtual() )
1044 void wxListItemData::Init()
1052 wxListItemData::wxListItemData(wxListMainWindow
*owner
)
1058 if ( owner
->InReportView() )
1064 m_rect
= new wxRect
;
1068 void wxListItemData::SetItem( const wxListItem
&info
)
1070 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
1071 SetText(info
.m_text
);
1072 if ( info
.m_mask
& wxLIST_MASK_IMAGE
)
1073 m_image
= info
.m_image
;
1074 if ( info
.m_mask
& wxLIST_MASK_DATA
)
1075 m_data
= info
.m_data
;
1077 if ( info
.HasAttributes() )
1080 *m_attr
= *info
.GetAttributes();
1082 m_attr
= new wxListItemAttr(*info
.GetAttributes());
1090 m_rect
->width
= info
.m_width
;
1094 void wxListItemData::SetPosition( int x
, int y
)
1096 wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") );
1102 void wxListItemData::SetSize( int width
, int height
)
1104 wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") );
1107 m_rect
->width
= width
;
1109 m_rect
->height
= height
;
1112 bool wxListItemData::IsHit( int x
, int y
) const
1114 wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") );
1116 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
);
1119 int wxListItemData::GetX() const
1121 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1126 int wxListItemData::GetY() const
1128 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1133 int wxListItemData::GetWidth() const
1135 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1137 return m_rect
->width
;
1140 int wxListItemData::GetHeight() const
1142 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1144 return m_rect
->height
;
1147 void wxListItemData::GetItem( wxListItem
&info
) const
1149 info
.m_text
= m_text
;
1150 info
.m_image
= m_image
;
1151 info
.m_data
= m_data
;
1155 if ( m_attr
->HasTextColour() )
1156 info
.SetTextColour(m_attr
->GetTextColour());
1157 if ( m_attr
->HasBackgroundColour() )
1158 info
.SetBackgroundColour(m_attr
->GetBackgroundColour());
1159 if ( m_attr
->HasFont() )
1160 info
.SetFont(m_attr
->GetFont());
1164 //-----------------------------------------------------------------------------
1166 //-----------------------------------------------------------------------------
1168 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
);
1170 wxListHeaderData::wxListHeaderData()
1181 wxListHeaderData::wxListHeaderData( const wxListItem
&item
)
1189 void wxListHeaderData::SetItem( const wxListItem
&item
)
1191 m_mask
= item
.m_mask
;
1192 m_text
= item
.m_text
;
1193 m_image
= item
.m_image
;
1194 m_format
= item
.m_format
;
1196 SetWidth(item
.m_width
);
1199 void wxListHeaderData::SetPosition( int x
, int y
)
1205 void wxListHeaderData::SetHeight( int h
)
1210 void wxListHeaderData::SetWidth( int w
)
1214 m_width
= WIDTH_COL_DEFAULT
;
1215 if (m_width
< WIDTH_COL_MIN
)
1216 m_width
= WIDTH_COL_MIN
;
1219 void wxListHeaderData::SetFormat( int format
)
1224 bool wxListHeaderData::HasImage() const
1226 return (m_image
!= 0);
1229 bool wxListHeaderData::IsHit( int x
, int y
) const
1231 return ((x
>= m_xpos
) && (x
<= m_xpos
+m_width
) && (y
>= m_ypos
) && (y
<= m_ypos
+m_height
));
1234 void wxListHeaderData::GetItem( wxListItem
&item
)
1236 item
.m_mask
= m_mask
;
1237 item
.m_text
= m_text
;
1238 item
.m_image
= m_image
;
1239 item
.m_format
= m_format
;
1240 item
.m_width
= m_width
;
1243 int wxListHeaderData::GetImage() const
1248 int wxListHeaderData::GetWidth() const
1253 int wxListHeaderData::GetFormat() const
1258 //-----------------------------------------------------------------------------
1260 //-----------------------------------------------------------------------------
1262 inline int wxListLineData::GetMode() const
1264 return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
;
1267 inline bool wxListLineData::InReportView() const
1269 return m_owner
->HasFlag(wxLC_REPORT
);
1272 inline bool wxListLineData::IsVirtual() const
1274 return m_owner
->IsVirtual();
1277 wxListLineData::wxListLineData( wxListMainWindow
*owner
)
1280 m_items
.DeleteContents( TRUE
);
1282 if ( InReportView() )
1288 m_gi
= new GeometryInfo
;
1291 m_highlighted
= FALSE
;
1293 InitItems( GetMode() == wxLC_REPORT
? m_owner
->GetColumnCount() : 1 );
1296 void wxListLineData::CalculateSize( wxDC
*dc
, int spacing
)
1298 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1299 wxCHECK_RET( node
, _T("no subitems at all??") );
1301 wxListItemData
*item
= node
->GetData();
1303 switch ( GetMode() )
1306 case wxLC_SMALL_ICON
:
1308 m_gi
->m_rectAll
.width
= spacing
;
1310 wxString s
= item
->GetText();
1316 m_gi
->m_rectLabel
.width
=
1317 m_gi
->m_rectLabel
.height
= 0;
1321 dc
->GetTextExtent( s
, &lw
, &lh
);
1322 if (lh
< SCROLL_UNIT_Y
)
1327 m_gi
->m_rectAll
.height
= spacing
+ lh
;
1329 m_gi
->m_rectAll
.width
= lw
;
1331 m_gi
->m_rectLabel
.width
= lw
;
1332 m_gi
->m_rectLabel
.height
= lh
;
1335 if (item
->HasImage())
1338 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1339 m_gi
->m_rectIcon
.width
= w
+ 8;
1340 m_gi
->m_rectIcon
.height
= h
+ 8;
1342 if ( m_gi
->m_rectIcon
.width
> m_gi
->m_rectAll
.width
)
1343 m_gi
->m_rectAll
.width
= m_gi
->m_rectIcon
.width
;
1344 if ( m_gi
->m_rectIcon
.height
+ lh
> m_gi
->m_rectAll
.height
- 4 )
1345 m_gi
->m_rectAll
.height
= m_gi
->m_rectIcon
.height
+ lh
+ 4;
1348 if ( item
->HasText() )
1350 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectLabel
.width
;
1351 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectLabel
.height
;
1353 else // no text, highlight the icon
1355 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectIcon
.width
;
1356 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectIcon
.height
;
1363 wxString s
= item
->GetTextForMeasuring();
1366 dc
->GetTextExtent( s
, &lw
, &lh
);
1367 if (lh
< SCROLL_UNIT_Y
)
1372 m_gi
->m_rectLabel
.width
= lw
;
1373 m_gi
->m_rectLabel
.height
= lh
;
1375 m_gi
->m_rectAll
.width
= lw
;
1376 m_gi
->m_rectAll
.height
= lh
;
1378 if (item
->HasImage())
1381 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1382 m_gi
->m_rectIcon
.width
= w
;
1383 m_gi
->m_rectIcon
.height
= h
;
1385 m_gi
->m_rectAll
.width
+= 4 + w
;
1386 if (h
> m_gi
->m_rectAll
.height
)
1387 m_gi
->m_rectAll
.height
= h
;
1390 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectAll
.width
;
1391 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectAll
.height
;
1396 wxFAIL_MSG( _T("unexpected call to SetSize") );
1400 wxFAIL_MSG( _T("unknown mode") );
1404 void wxListLineData::SetPosition( int x
, int y
,
1408 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1409 wxCHECK_RET( node
, _T("no subitems at all??") );
1411 wxListItemData
*item
= node
->GetData();
1413 switch ( GetMode() )
1416 case wxLC_SMALL_ICON
:
1417 m_gi
->m_rectAll
.x
= x
;
1418 m_gi
->m_rectAll
.y
= y
;
1420 if ( item
->HasImage() )
1422 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 4
1423 + (spacing
- m_gi
->m_rectIcon
.width
)/2;
1424 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 4;
1427 if ( item
->HasText() )
1429 if (m_gi
->m_rectAll
.width
> spacing
)
1430 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1432 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2);
1433 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ m_gi
->m_rectAll
.height
+ 2 - m_gi
->m_rectLabel
.height
;
1434 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectLabel
.x
- 2;
1435 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectLabel
.y
- 2;
1437 else // no text, highlight the icon
1439 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectIcon
.x
- 4;
1440 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectIcon
.y
- 4;
1445 m_gi
->m_rectAll
.x
= x
;
1446 m_gi
->m_rectAll
.y
= y
;
1448 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectAll
.x
;
1449 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectAll
.y
;
1450 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ 2;
1452 if (item
->HasImage())
1454 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 2;
1455 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 2;
1456 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 6 + m_gi
->m_rectIcon
.width
;
1460 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1465 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1469 wxFAIL_MSG( _T("unknown mode") );
1473 void wxListLineData::InitItems( int num
)
1475 for (int i
= 0; i
< num
; i
++)
1476 m_items
.Append( new wxListItemData(m_owner
) );
1479 void wxListLineData::SetItem( int index
, const wxListItem
&info
)
1481 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1482 wxCHECK_RET( node
, _T("invalid column index in SetItem") );
1484 wxListItemData
*item
= node
->GetData();
1485 item
->SetItem( info
);
1488 void wxListLineData::GetItem( int index
, wxListItem
&info
)
1490 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1493 wxListItemData
*item
= node
->GetData();
1494 item
->GetItem( info
);
1498 wxString
wxListLineData::GetText(int index
) const
1502 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1505 wxListItemData
*item
= node
->GetData();
1506 s
= item
->GetText();
1512 void wxListLineData::SetText( int index
, const wxString s
)
1514 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1517 wxListItemData
*item
= node
->GetData();
1522 void wxListLineData::SetImage( int index
, int image
)
1524 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1525 wxCHECK_RET( node
, _T("invalid column index in SetImage()") );
1527 wxListItemData
*item
= node
->GetData();
1528 item
->SetImage(image
);
1531 int wxListLineData::GetImage( int index
) const
1533 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1534 wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") );
1536 wxListItemData
*item
= node
->GetData();
1537 return item
->GetImage();
1540 wxListItemAttr
*wxListLineData::GetAttr() const
1542 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1543 wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") );
1545 wxListItemData
*item
= node
->GetData();
1546 return item
->GetAttr();
1549 void wxListLineData::SetAttr(wxListItemAttr
*attr
)
1551 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1552 wxCHECK_RET( node
, _T("invalid column index in SetAttr()") );
1554 wxListItemData
*item
= node
->GetData();
1555 item
->SetAttr(attr
);
1558 bool wxListLineData::SetAttributes(wxDC
*dc
,
1559 const wxListItemAttr
*attr
,
1562 wxWindow
*listctrl
= m_owner
->GetParent();
1566 // don't use foreground colour for drawing highlighted items - this might
1567 // make them completely invisible (and there is no way to do bit
1568 // arithmetics on wxColour, unfortunately)
1572 colText
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
1576 if ( attr
&& attr
->HasTextColour() )
1578 colText
= attr
->GetTextColour();
1582 colText
= listctrl
->GetForegroundColour();
1586 dc
->SetTextForeground(colText
);
1590 if ( attr
&& attr
->HasFont() )
1592 font
= attr
->GetFont();
1596 font
= listctrl
->GetFont();
1602 bool hasBgCol
= attr
&& attr
->HasBackgroundColour();
1603 if ( highlighted
|| hasBgCol
)
1607 dc
->SetBrush( *m_owner
->m_highlightBrush
);
1611 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
1614 dc
->SetPen( *wxTRANSPARENT_PEN
);
1622 void wxListLineData::Draw( wxDC
*dc
)
1624 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1625 wxCHECK_RET( node
, _T("no subitems at all??") );
1627 bool highlighted
= IsHighlighted();
1629 wxListItemAttr
*attr
= GetAttr();
1631 if ( SetAttributes(dc
, attr
, highlighted
) )
1633 dc
->DrawRectangle( m_gi
->m_rectHighlight
);
1636 wxListItemData
*item
= node
->GetData();
1637 if (item
->HasImage())
1639 wxRect rectIcon
= m_gi
->m_rectIcon
;
1640 m_owner
->DrawImage( item
->GetImage(), dc
,
1641 rectIcon
.x
, rectIcon
.y
);
1644 if (item
->HasText())
1646 wxRect rectLabel
= m_gi
->m_rectLabel
;
1647 dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y
);
1651 void wxListLineData::DrawInReportMode( wxDC
*dc
,
1653 const wxRect
& rectHL
,
1656 // use our own flag if we maintain it
1658 highlighted
= m_highlighted
;
1660 // TODO: later we should support setting different attributes for
1661 // different columns - to do it, just add "col" argument to
1662 // GetAttr() and move these lines into the loop below
1663 wxListItemAttr
*attr
= GetAttr();
1664 if ( SetAttributes(dc
, attr
, highlighted
) )
1666 dc
->DrawRectangle( rectHL
);
1669 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1670 wxCHECK_RET( node
, _T("no subitems at all??") );
1673 wxCoord x
= rect
.x
+ HEADER_OFFSET_X
,
1674 y
= rect
.y
+ (LINE_SPACING
+ EXTRA_HEIGHT
) / 2;
1678 wxListItemData
*item
= node
->GetData();
1682 if ( item
->HasImage() )
1685 m_owner
->DrawImage( item
->GetImage(), dc
, x
, y
);
1686 m_owner
->GetImageSize( item
->GetImage(), ix
, iy
);
1687 x
+= ix
+ 5; // FIXME: what is "5"?
1690 int width
= m_owner
->GetColumnWidth(col
++);
1692 wxDCClipper
clipper(*dc
, x
, y
, width
, rect
.height
);
1694 if ( item
->HasText() )
1696 dc
->DrawText( item
->GetText(), x
, y
);
1701 node
= node
->GetNext();
1705 bool wxListLineData::Highlight( bool on
)
1707 wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") );
1709 if ( on
== m_highlighted
)
1717 void wxListLineData::ReverseHighlight( void )
1719 Highlight(!IsHighlighted());
1722 //-----------------------------------------------------------------------------
1723 // wxListHeaderWindow
1724 //-----------------------------------------------------------------------------
1726 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
);
1728 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
)
1729 EVT_PAINT (wxListHeaderWindow::OnPaint
)
1730 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse
)
1731 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus
)
1734 wxListHeaderWindow::wxListHeaderWindow( void )
1736 m_owner
= (wxListMainWindow
*) NULL
;
1737 m_currentCursor
= (wxCursor
*) NULL
;
1738 m_resizeCursor
= (wxCursor
*) NULL
;
1739 m_isDragging
= FALSE
;
1742 wxListHeaderWindow::wxListHeaderWindow( wxWindow
*win
, wxWindowID id
, wxListMainWindow
*owner
,
1743 const wxPoint
&pos
, const wxSize
&size
,
1744 long style
, const wxString
&name
) :
1745 wxWindow( win
, id
, pos
, size
, style
, name
)
1748 // m_currentCursor = wxSTANDARD_CURSOR;
1749 m_currentCursor
= (wxCursor
*) NULL
;
1750 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
1751 m_isDragging
= FALSE
;
1754 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE
) );
1757 wxListHeaderWindow::~wxListHeaderWindow( void )
1759 delete m_resizeCursor
;
1762 void wxListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1765 GtkStateType state
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
1766 : GTK_STATE_INSENSITIVE
;
1768 x
= dc
->XLOG2DEV( x
);
1770 gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
,
1771 state
, GTK_SHADOW_OUT
,
1772 (GdkRectangle
*) NULL
, m_wxwindow
, "button",
1773 x
-1, y
-1, w
+2, h
+2);
1774 #elif defined( __WXMAC__ )
1775 const int m_corner
= 1;
1777 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1779 dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
) , 1 , wxSOLID
) );
1780 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1781 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1783 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1786 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1787 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1789 dc
->SetPen( *wxWHITE_PEN
);
1790 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1791 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1792 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1793 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1795 const int m_corner
= 1;
1797 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1799 dc
->SetPen( *wxBLACK_PEN
);
1800 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1801 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1803 wxPen
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1806 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1807 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1809 dc
->SetPen( *wxWHITE_PEN
);
1810 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1811 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1812 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1813 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1817 // shift the DC origin to match the position of the main window horz
1818 // scrollbar: this allows us to always use logical coords
1819 void wxListHeaderWindow::AdjustDC(wxDC
& dc
)
1822 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1825 m_owner
->GetViewStart( &x
, NULL
);
1827 // account for the horz scrollbar offset
1828 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1831 void wxListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1834 wxClientDC
dc( this );
1836 wxPaintDC
dc( this );
1844 dc
.SetFont( GetFont() );
1846 // width and height of the entire header window
1848 GetClientSize( &w
, &h
);
1849 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1851 dc
.SetBackgroundMode(wxTRANSPARENT
);
1853 // do *not* use the listctrl colour for headers - one day we will have a
1854 // function to set it separately
1855 //dc.SetTextForeground( *wxBLACK );
1856 dc
.SetTextForeground(wxSystemSettings::
1857 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1859 int x
= HEADER_OFFSET_X
;
1861 int numColumns
= m_owner
->GetColumnCount();
1863 for (int i
= 0; i
< numColumns
; i
++)
1865 m_owner
->GetColumn( i
, item
);
1866 int wCol
= item
.m_width
;
1867 int cw
= wCol
- 2; // the width of the rect to draw
1869 int xEnd
= x
+ wCol
;
1871 dc
.SetPen( *wxWHITE_PEN
);
1873 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1874 dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 );
1875 dc
.DrawText( item
.GetText(), x
+ EXTRA_WIDTH
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1876 dc
.DestroyClippingRegion();
1885 void wxListHeaderWindow::DrawCurrent()
1887 int x1
= m_currentX
;
1889 ClientToScreen( &x1
, &y1
);
1891 int x2
= m_currentX
-1;
1893 m_owner
->GetClientSize( NULL
, &y2
);
1894 m_owner
->ClientToScreen( &x2
, &y2
);
1897 dc
.SetLogicalFunction( wxINVERT
);
1898 dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID
) );
1899 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1903 dc
.DrawLine( x1
, y1
, x2
, y2
);
1905 dc
.SetLogicalFunction( wxCOPY
);
1907 dc
.SetPen( wxNullPen
);
1908 dc
.SetBrush( wxNullBrush
);
1911 void wxListHeaderWindow::OnMouse( wxMouseEvent
&event
)
1913 // we want to work with logical coords
1915 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1916 int y
= event
.GetY();
1920 // we don't draw the line beyond our window, but we allow dragging it
1923 GetClientSize( &w
, NULL
);
1924 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1927 // erase the line if it was drawn
1928 if ( m_currentX
< w
)
1931 if (event
.ButtonUp())
1934 m_isDragging
= FALSE
;
1936 m_owner
->SetColumnWidth( m_column
, m_currentX
- m_minX
);
1943 m_currentX
= m_minX
+ 7;
1945 // draw in the new location
1946 if ( m_currentX
< w
)
1950 else // not dragging
1953 bool hit_border
= FALSE
;
1955 // end of the current column
1958 // find the column where this event occured
1959 int countCol
= m_owner
->GetColumnCount();
1960 for (int col
= 0; col
< countCol
; col
++)
1962 xpos
+= m_owner
->GetColumnWidth( col
);
1965 if ( (abs(x
-xpos
) < 3) && (y
< 22) )
1967 // near the column border
1974 // inside the column
1981 if (event
.LeftDown())
1985 m_isDragging
= TRUE
;
1992 wxWindow
*parent
= GetParent();
1993 wxListEvent
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() );
1994 le
.SetEventObject( parent
);
1995 le
.m_col
= m_column
;
1996 parent
->GetEventHandler()->ProcessEvent( le
);
1999 else if (event
.Moving())
2004 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
2005 m_currentCursor
= m_resizeCursor
;
2009 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
2010 m_currentCursor
= wxSTANDARD_CURSOR
;
2014 SetCursor(*m_currentCursor
);
2019 void wxListHeaderWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
2021 m_owner
->SetFocus();
2024 //-----------------------------------------------------------------------------
2025 // wxListRenameTimer (internal)
2026 //-----------------------------------------------------------------------------
2028 wxListRenameTimer::wxListRenameTimer( wxListMainWindow
*owner
)
2033 void wxListRenameTimer::Notify()
2035 m_owner
->OnRenameTimer();
2038 //-----------------------------------------------------------------------------
2039 // wxListTextCtrl (internal)
2040 //-----------------------------------------------------------------------------
2042 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
);
2044 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
)
2045 EVT_CHAR (wxListTextCtrl::OnChar
)
2046 EVT_KEY_UP (wxListTextCtrl::OnKeyUp
)
2047 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus
)
2050 wxListTextCtrl::wxListTextCtrl( wxWindow
*parent
,
2051 const wxWindowID id
,
2054 wxListMainWindow
*owner
,
2055 const wxString
&value
,
2059 const wxValidator
& validator
,
2060 const wxString
&name
)
2061 : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name
)
2066 (*m_accept
) = FALSE
;
2068 m_startValue
= value
;
2071 void wxListTextCtrl::OnChar( wxKeyEvent
&event
)
2073 if (event
.m_keyCode
== WXK_RETURN
)
2076 (*m_res
) = GetValue();
2078 if (!wxPendingDelete
.Member(this))
2079 wxPendingDelete
.Append(this);
2081 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2082 m_owner
->OnRenameAccept();
2086 if (event
.m_keyCode
== WXK_ESCAPE
)
2088 (*m_accept
) = FALSE
;
2091 if (!wxPendingDelete
.Member(this))
2092 wxPendingDelete
.Append(this);
2100 void wxListTextCtrl::OnKeyUp( wxKeyEvent
&event
)
2102 // auto-grow the textctrl:
2103 wxSize parentSize
= m_owner
->GetSize();
2104 wxPoint myPos
= GetPosition();
2105 wxSize mySize
= GetSize();
2107 GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM??
2108 if (myPos
.x
+ sx
> parentSize
.x
)
2109 sx
= parentSize
.x
- myPos
.x
;
2117 void wxListTextCtrl::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
2119 if (!wxPendingDelete
.Member(this))
2120 wxPendingDelete
.Append(this);
2122 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2123 m_owner
->OnRenameAccept();
2126 //-----------------------------------------------------------------------------
2128 //-----------------------------------------------------------------------------
2130 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
);
2132 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
)
2133 EVT_PAINT (wxListMainWindow::OnPaint
)
2134 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse
)
2135 EVT_CHAR (wxListMainWindow::OnChar
)
2136 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown
)
2137 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus
)
2138 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus
)
2139 EVT_SCROLLWIN (wxListMainWindow::OnScroll
)
2142 void wxListMainWindow::Init()
2144 m_columns
.DeleteContents( TRUE
);
2148 m_lineTo
= (size_t)-1;
2154 m_small_image_list
= (wxImageList
*) NULL
;
2155 m_normal_image_list
= (wxImageList
*) NULL
;
2157 m_small_spacing
= 30;
2158 m_normal_spacing
= 40;
2162 m_isCreated
= FALSE
;
2164 m_lastOnSame
= FALSE
;
2165 m_renameTimer
= new wxListRenameTimer( this );
2166 m_renameAccept
= FALSE
;
2171 m_lineBeforeLastClicked
= (size_t)-1;
2174 void wxListMainWindow::InitScrolling()
2176 if ( HasFlag(wxLC_REPORT
) )
2178 m_xScroll
= SCROLL_UNIT_X
;
2179 m_yScroll
= SCROLL_UNIT_Y
;
2183 m_xScroll
= SCROLL_UNIT_Y
;
2188 wxListMainWindow::wxListMainWindow()
2192 m_highlightBrush
= (wxBrush
*) NULL
;
2198 wxListMainWindow::wxListMainWindow( wxWindow
*parent
,
2203 const wxString
&name
)
2204 : wxScrolledWindow( parent
, id
, pos
, size
,
2205 style
| wxHSCROLL
| wxVSCROLL
, name
)
2209 m_highlightBrush
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
2214 SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 );
2216 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX
) );
2219 wxListMainWindow::~wxListMainWindow()
2223 delete m_highlightBrush
;
2225 delete m_renameTimer
;
2228 void wxListMainWindow::CacheLineData(size_t line
)
2230 wxListCtrl
*listctrl
= GetListCtrl();
2232 wxListLineData
*ld
= GetDummyLine();
2234 size_t countCol
= GetColumnCount();
2235 for ( size_t col
= 0; col
< countCol
; col
++ )
2237 ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
));
2240 ld
->SetImage(listctrl
->OnGetItemImage(line
));
2241 ld
->SetAttr(listctrl
->OnGetItemAttr(line
));
2244 wxListLineData
*wxListMainWindow::GetDummyLine() const
2246 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2248 if ( m_lines
.IsEmpty() )
2250 // normal controls are supposed to have something in m_lines
2251 // already if it's not empty
2252 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2254 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2255 wxListLineData
*line
= new wxListLineData(self
);
2256 self
->m_lines
.Add(line
);
2262 // ----------------------------------------------------------------------------
2263 // line geometry (report mode only)
2264 // ----------------------------------------------------------------------------
2266 wxCoord
wxListMainWindow::GetLineHeight() const
2268 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2270 // we cache the line height as calling GetTextExtent() is slow
2271 if ( !m_lineHeight
)
2273 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2275 wxClientDC
dc( self
);
2276 dc
.SetFont( GetFont() );
2279 dc
.GetTextExtent(_T("H"), NULL
, &y
);
2281 if ( y
< SCROLL_UNIT_Y
)
2285 self
->m_lineHeight
= y
+ LINE_SPACING
;
2288 return m_lineHeight
;
2291 wxCoord
wxListMainWindow::GetLineY(size_t line
) const
2293 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2295 return LINE_SPACING
+ line
*GetLineHeight();
2298 wxRect
wxListMainWindow::GetLineRect(size_t line
) const
2300 if ( !InReportView() )
2301 return GetLine(line
)->m_gi
->m_rectAll
;
2304 rect
.x
= HEADER_OFFSET_X
;
2305 rect
.y
= GetLineY(line
);
2306 rect
.width
= GetHeaderWidth();
2307 rect
.height
= GetLineHeight();
2312 wxRect
wxListMainWindow::GetLineLabelRect(size_t line
) const
2314 if ( !InReportView() )
2315 return GetLine(line
)->m_gi
->m_rectLabel
;
2318 rect
.x
= HEADER_OFFSET_X
;
2319 rect
.y
= GetLineY(line
);
2320 rect
.width
= GetColumnWidth(0);
2321 rect
.height
= GetLineHeight();
2326 wxRect
wxListMainWindow::GetLineIconRect(size_t line
) const
2328 if ( !InReportView() )
2329 return GetLine(line
)->m_gi
->m_rectIcon
;
2331 wxListLineData
*ld
= GetLine(line
);
2332 wxASSERT_MSG( ld
->HasImage(), _T("should have an image") );
2335 rect
.x
= HEADER_OFFSET_X
;
2336 rect
.y
= GetLineY(line
);
2337 GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
);
2342 wxRect
wxListMainWindow::GetLineHighlightRect(size_t line
) const
2344 return InReportView() ? GetLineRect(line
)
2345 : GetLine(line
)->m_gi
->m_rectHighlight
;
2348 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const
2350 wxListLineData
*ld
= GetLine(line
);
2352 if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) )
2353 return wxLIST_HITTEST_ONITEMICON
;
2355 if ( ld
->HasText() )
2357 wxRect rect
= InReportView() ? GetLineRect(line
)
2358 : GetLineLabelRect(line
);
2360 if ( rect
.Inside(x
, y
) )
2361 return wxLIST_HITTEST_ONITEMLABEL
;
2367 // ----------------------------------------------------------------------------
2368 // highlight (selection) handling
2369 // ----------------------------------------------------------------------------
2371 bool wxListMainWindow::IsHighlighted(size_t line
) const
2375 return m_selStore
.IsSelected(line
);
2379 wxListLineData
*ld
= GetLine(line
);
2380 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2382 return ld
->IsHighlighted();
2386 void wxListMainWindow::HighlightLines( size_t lineFrom
,
2392 wxArrayInt linesChanged
;
2393 if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
,
2396 // meny items changed state, refresh everything
2397 RefreshLines(lineFrom
, lineTo
);
2399 else // only a few items changed state, refresh only them
2401 size_t count
= linesChanged
.GetCount();
2402 for ( size_t n
= 0; n
< count
; n
++ )
2404 RefreshLine(linesChanged
[n
]);
2408 else // iterate over all items in non report view
2410 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2412 if ( HighlightLine(line
, highlight
) )
2420 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight
)
2426 changed
= m_selStore
.SelectItem(line
, highlight
);
2430 wxListLineData
*ld
= GetLine(line
);
2431 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2433 changed
= ld
->Highlight(highlight
);
2438 SendNotify( line
, highlight
? wxEVT_COMMAND_LIST_ITEM_SELECTED
2439 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
);
2445 void wxListMainWindow::RefreshLine( size_t line
)
2447 wxRect rect
= GetLineRect(line
);
2449 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2450 RefreshRect( rect
);
2453 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo
)
2455 // we suppose that they are ordered by caller
2456 wxASSERT_MSG( lineFrom
<= lineTo
, _T("indices in disorder") );
2458 wxASSERT_MSG( lineTo
< GetItemCount(), _T("invalid line range") );
2460 if ( HasFlag(wxLC_REPORT
) )
2462 size_t visibleFrom
, visibleTo
;
2463 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2465 if ( lineFrom
< visibleFrom
)
2466 lineFrom
= visibleFrom
;
2467 if ( lineTo
> visibleTo
)
2472 rect
.y
= GetLineY(lineFrom
);
2473 rect
.width
= GetClientSize().x
;
2474 rect
.height
= GetLineY(lineTo
) - rect
.y
+ GetLineHeight();
2476 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2477 RefreshRect( rect
);
2481 // TODO: this should be optimized...
2482 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2489 void wxListMainWindow::RefreshAfter( size_t lineFrom
)
2491 if ( HasFlag(wxLC_REPORT
) )
2494 GetVisibleLinesRange(&visibleFrom
, NULL
);
2496 if ( lineFrom
< visibleFrom
)
2497 lineFrom
= visibleFrom
;
2501 rect
.y
= GetLineY(lineFrom
);
2503 wxSize size
= GetClientSize();
2504 rect
.width
= size
.x
;
2505 // refresh till the bottom of the window
2506 rect
.height
= size
.y
- rect
.y
;
2508 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2509 RefreshRect( rect
);
2513 // TODO: how to do it more efficiently?
2518 void wxListMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2520 // Note: a wxPaintDC must be constructed even if no drawing is
2521 // done (a Windows requirement).
2522 wxPaintDC
dc( this );
2526 // empty control. nothing to draw
2532 // delay the repainting until we calculate all the items positions
2539 CalcScrolledPosition( 0, 0, &dev_x
, &dev_y
);
2543 dc
.SetFont( GetFont() );
2545 if ( HasFlag(wxLC_REPORT
) )
2547 int lineHeight
= GetLineHeight();
2549 size_t visibleFrom
, visibleTo
;
2550 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2553 wxCoord xOrig
, yOrig
;
2554 CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
);
2556 // tell the caller cache to cache the data
2559 wxListEvent
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
,
2560 GetParent()->GetId());
2561 evCache
.SetEventObject( GetParent() );
2562 evCache
.m_oldItemIndex
= visibleFrom
;
2563 evCache
.m_itemIndex
= visibleTo
;
2564 GetParent()->GetEventHandler()->ProcessEvent( evCache
);
2567 for ( size_t line
= visibleFrom
; line
<= visibleTo
; line
++ )
2569 rectLine
= GetLineRect(line
);
2571 if ( !IsExposed(rectLine
.x
- xOrig
, rectLine
.y
- yOrig
,
2572 rectLine
.width
, rectLine
.height
) )
2574 // don't redraw unaffected lines to avoid flicker
2578 GetLine(line
)->DrawInReportMode( &dc
,
2580 GetLineHighlightRect(line
),
2581 IsHighlighted(line
) );
2584 if ( HasFlag(wxLC_HRULES
) )
2586 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2587 wxSize clientSize
= GetClientSize();
2589 for ( size_t i
= visibleFrom
; i
<= visibleTo
; i
++ )
2592 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2593 dc
.DrawLine(0 - dev_x
, i
*lineHeight
,
2594 clientSize
.x
- dev_x
, i
*lineHeight
);
2597 // Draw last horizontal rule
2598 if ( visibleTo
> visibleFrom
)
2601 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2602 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
,
2603 clientSize
.x
- dev_x
, m_lineTo
*lineHeight
);
2607 // Draw vertical rules if required
2608 if ( HasFlag(wxLC_VRULES
) && !IsEmpty() )
2610 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2613 wxRect firstItemRect
;
2614 wxRect lastItemRect
;
2615 GetItemRect(0, firstItemRect
);
2616 GetItemRect(GetItemCount() - 1, lastItemRect
);
2617 int x
= firstItemRect
.GetX();
2619 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2620 for (col
= 0; col
< GetColumnCount(); col
++)
2622 int colWidth
= GetColumnWidth(col
);
2624 dc
.DrawLine(x
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
,
2625 x
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
);
2631 size_t count
= GetItemCount();
2632 for ( size_t i
= 0; i
< count
; i
++ )
2634 GetLine(i
)->Draw( &dc
);
2638 if ( HasCurrent() && m_hasFocus
)
2641 // no rect outline, we already have the background color
2643 dc
.SetPen( *wxBLACK_PEN
);
2644 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2645 dc
.DrawRectangle( GetLineHighlightRect(m_current
) );
2652 void wxListMainWindow::HighlightAll( bool on
)
2654 if ( IsSingleSel() )
2656 wxASSERT_MSG( !on
, _T("can't do this in a single sel control") );
2658 // we just have one item to turn off
2659 if ( HasCurrent() && IsHighlighted(m_current
) )
2661 HighlightLine(m_current
, FALSE
);
2662 RefreshLine(m_current
);
2667 HighlightLines(0, GetItemCount() - 1, on
);
2671 void wxListMainWindow::SendNotify( size_t line
,
2672 wxEventType command
,
2675 wxListEvent
le( command
, GetParent()->GetId() );
2676 le
.SetEventObject( GetParent() );
2677 le
.m_itemIndex
= line
;
2679 // set only for events which have position
2680 if ( point
!= wxDefaultPosition
)
2681 le
.m_pointDrag
= point
;
2683 if ( command
!= wxEVT_COMMAND_LIST_DELETE_ITEM
)
2685 GetLine(line
)->GetItem( 0, le
.m_item
);
2687 //else: there may be no more such item
2689 GetParent()->GetEventHandler()->ProcessEvent( le
);
2692 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) )
2694 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
2697 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) )
2699 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
2702 void wxListMainWindow::EditLabel( long item
)
2704 wxCHECK_RET( (item
>= 0) && ((size_t)item
< GetItemCount()),
2705 wxT("wrong index in wxListCtrl::EditLabel()") );
2707 m_currentEdit
= (size_t)item
;
2709 wxListEvent
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() );
2710 le
.SetEventObject( GetParent() );
2711 le
.m_itemIndex
= item
;
2712 wxListLineData
*data
= GetLine(m_currentEdit
);
2713 wxCHECK_RET( data
, _T("invalid index in EditLabel()") );
2714 data
->GetItem( 0, le
.m_item
);
2715 GetParent()->GetEventHandler()->ProcessEvent( le
);
2717 if (!le
.IsAllowed())
2720 // We have to call this here because the label in question might just have
2721 // been added and no screen update taken place.
2725 wxClientDC
dc(this);
2728 wxString s
= data
->GetText(0);
2729 wxRect rectLabel
= GetLineLabelRect(m_currentEdit
);
2731 rectLabel
.x
= dc
.LogicalToDeviceX( rectLabel
.x
);
2732 rectLabel
.y
= dc
.LogicalToDeviceY( rectLabel
.y
);
2734 wxListTextCtrl
*text
= new wxListTextCtrl
2741 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4),
2742 wxSize(rectLabel
.width
+11,rectLabel
.height
+8)
2747 void wxListMainWindow::OnRenameTimer()
2749 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2751 EditLabel( m_current
);
2754 void wxListMainWindow::OnRenameAccept()
2756 wxListEvent
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() );
2757 le
.SetEventObject( GetParent() );
2758 le
.m_itemIndex
= m_currentEdit
;
2760 wxListLineData
*data
= GetLine(m_currentEdit
);
2761 wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") );
2763 data
->GetItem( 0, le
.m_item
);
2764 le
.m_item
.m_text
= m_renameRes
;
2765 GetParent()->GetEventHandler()->ProcessEvent( le
);
2767 if (!le
.IsAllowed()) return;
2770 info
.m_mask
= wxLIST_MASK_TEXT
;
2771 info
.m_itemId
= le
.m_itemIndex
;
2772 info
.m_text
= m_renameRes
;
2773 info
.SetTextColour(le
.m_item
.GetTextColour());
2777 void wxListMainWindow::OnMouse( wxMouseEvent
&event
)
2779 event
.SetEventObject( GetParent() );
2780 if ( GetParent()->GetEventHandler()->ProcessEvent( event
) )
2783 if ( !HasCurrent() || IsEmpty() )
2789 if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() ||
2790 event
.ButtonDClick()) )
2793 int x
= event
.GetX();
2794 int y
= event
.GetY();
2795 CalcUnscrolledPosition( x
, y
, &x
, &y
);
2797 // where did we hit it (if we did)?
2800 size_t count
= GetItemCount(),
2803 if ( HasFlag(wxLC_REPORT
) )
2805 current
= y
/ GetLineHeight();
2806 if ( current
< count
)
2807 hitResult
= HitTestLine(current
, x
, y
);
2811 // TODO: optimize it too! this is less simple than for report view but
2812 // enumerating all items is still not a way to do it!!
2813 for ( current
= 0; current
< count
; current
++ )
2815 hitResult
= HitTestLine(current
, x
, y
);
2821 if (event
.Dragging())
2823 if (m_dragCount
== 0)
2824 m_dragStart
= wxPoint(x
,y
);
2828 if (m_dragCount
!= 3)
2831 int command
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2832 : wxEVT_COMMAND_LIST_BEGIN_DRAG
;
2834 wxListEvent
le( command
, GetParent()->GetId() );
2835 le
.SetEventObject( GetParent() );
2836 le
.m_pointDrag
= m_dragStart
;
2837 GetParent()->GetEventHandler()->ProcessEvent( le
);
2848 // outside of any item
2852 bool forceClick
= FALSE
;
2853 if (event
.ButtonDClick())
2855 m_renameTimer
->Stop();
2856 m_lastOnSame
= FALSE
;
2858 if ( current
== m_lineBeforeLastClicked
)
2860 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED
);
2866 // the first click was on another item, so don't interpret this as
2867 // a double click, but as a simple click instead
2872 if (event
.LeftUp() && m_lastOnSame
)
2874 if ((current
== m_current
) &&
2875 (hitResult
== wxLIST_HITTEST_ONITEMLABEL
) &&
2876 HasFlag(wxLC_EDIT_LABELS
) )
2878 m_renameTimer
->Start( 100, TRUE
);
2880 m_lastOnSame
= FALSE
;
2882 else if (event
.RightDown())
2884 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
,
2885 event
.GetPosition() );
2887 else if (event
.MiddleDown())
2889 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
);
2891 else if ( event
.LeftDown() || forceClick
)
2893 m_lineBeforeLastClicked
= m_lineLastClicked
;
2894 m_lineLastClicked
= current
;
2896 size_t oldCurrent
= m_current
;
2898 if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) )
2900 HighlightAll( FALSE
);
2901 m_current
= current
;
2903 ReverseHighlight(m_current
);
2905 else // multi sel & either ctrl or shift is down
2907 if (event
.ControlDown())
2909 m_current
= current
;
2911 ReverseHighlight(m_current
);
2913 else if (event
.ShiftDown())
2915 m_current
= current
;
2917 size_t lineFrom
= oldCurrent
,
2920 if ( lineTo
< lineFrom
)
2923 lineFrom
= m_current
;
2926 HighlightLines(lineFrom
, lineTo
);
2928 else // !ctrl, !shift
2930 // test in the enclosing if should make it impossible
2931 wxFAIL_MSG( _T("how did we get here?") );
2935 if (m_current
!= oldCurrent
)
2937 RefreshLine( oldCurrent
);
2938 OnUnfocusLine( oldCurrent
);
2939 OnFocusLine( m_current
);
2942 // forceClick is only set if the previous click was on another item
2943 m_lastOnSame
= !forceClick
&& (m_current
== oldCurrent
);
2947 void wxListMainWindow::MoveToItem(size_t item
)
2949 if ( item
== (size_t)-1 )
2952 wxRect rect
= GetLineRect(item
);
2954 int client_w
, client_h
;
2955 GetClientSize( &client_w
, &client_h
);
2957 int view_x
= m_xScroll
*GetScrollPos( wxHORIZONTAL
);
2958 int view_y
= m_yScroll
*GetScrollPos( wxVERTICAL
);
2960 if ( HasFlag(wxLC_REPORT
) )
2962 // the next we need the range of lines shown it might be different, so
2964 ResetVisibleLinesRange();
2966 if (rect
.y
< view_y
)
2967 Scroll( -1, rect
.y
/m_yScroll
);
2968 if (rect
.y
+rect
.height
+5 > view_y
+client_h
)
2969 Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll
);
2973 if (rect
.x
-view_x
< 5)
2974 Scroll( (rect
.x
-5)/m_xScroll
, -1 );
2975 if (rect
.x
+rect
.width
-5 > view_x
+client_w
)
2976 Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 );
2980 // ----------------------------------------------------------------------------
2981 // keyboard handling
2982 // ----------------------------------------------------------------------------
2984 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
2986 wxCHECK_RET( newCurrent
< (size_t)GetItemCount(),
2987 _T("invalid item index in OnArrowChar()") );
2989 size_t oldCurrent
= m_current
;
2991 // in single selection we just ignore Shift as we can't select several
2993 if ( event
.ShiftDown() && !IsSingleSel() )
2995 m_current
= newCurrent
;
2997 // select all the items between the old and the new one
2998 if ( oldCurrent
> newCurrent
)
3000 newCurrent
= oldCurrent
;
3001 oldCurrent
= m_current
;
3004 HighlightLines(oldCurrent
, newCurrent
);
3008 // all previously selected items are unselected unless ctrl is held
3009 if ( !event
.ControlDown() )
3010 HighlightAll(FALSE
);
3012 m_current
= newCurrent
;
3014 HighlightLine( oldCurrent
, FALSE
);
3015 RefreshLine( oldCurrent
);
3017 if ( !event
.ControlDown() )
3019 HighlightLine( m_current
, TRUE
);
3023 OnUnfocusLine( oldCurrent
);
3024 OnFocusLine( m_current
);
3025 RefreshLine( m_current
);
3030 void wxListMainWindow::OnKeyDown( wxKeyEvent
&event
)
3032 wxWindow
*parent
= GetParent();
3034 /* we propagate the key event up */
3035 wxKeyEvent
ke( wxEVT_KEY_DOWN
);
3036 ke
.m_shiftDown
= event
.m_shiftDown
;
3037 ke
.m_controlDown
= event
.m_controlDown
;
3038 ke
.m_altDown
= event
.m_altDown
;
3039 ke
.m_metaDown
= event
.m_metaDown
;
3040 ke
.m_keyCode
= event
.m_keyCode
;
3043 ke
.SetEventObject( parent
);
3044 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
3049 void wxListMainWindow::OnChar( wxKeyEvent
&event
)
3051 wxWindow
*parent
= GetParent();
3053 /* we send a list_key event up */
3056 wxListEvent
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() );
3057 le
.m_itemIndex
= m_current
;
3058 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3059 le
.m_code
= (int)event
.KeyCode();
3060 le
.SetEventObject( parent
);
3061 parent
->GetEventHandler()->ProcessEvent( le
);
3064 /* we propagate the char event up */
3065 wxKeyEvent
ke( wxEVT_CHAR
);
3066 ke
.m_shiftDown
= event
.m_shiftDown
;
3067 ke
.m_controlDown
= event
.m_controlDown
;
3068 ke
.m_altDown
= event
.m_altDown
;
3069 ke
.m_metaDown
= event
.m_metaDown
;
3070 ke
.m_keyCode
= event
.m_keyCode
;
3073 ke
.SetEventObject( parent
);
3074 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
3076 if (event
.KeyCode() == WXK_TAB
)
3078 wxNavigationKeyEvent nevent
;
3079 nevent
.SetWindowChange( event
.ControlDown() );
3080 nevent
.SetDirection( !event
.ShiftDown() );
3081 nevent
.SetEventObject( GetParent()->GetParent() );
3082 nevent
.SetCurrentFocus( m_parent
);
3083 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
)) return;
3086 /* no item -> nothing to do */
3093 switch (event
.KeyCode())
3096 if ( m_current
> 0 )
3097 OnArrowChar( m_current
- 1, event
);
3101 if ( m_current
< (size_t)GetItemCount() - 1 )
3102 OnArrowChar( m_current
+ 1, event
);
3107 OnArrowChar( GetItemCount() - 1, event
);
3112 OnArrowChar( 0, event
);
3118 if ( HasFlag(wxLC_REPORT
) )
3120 steps
= m_linesPerPage
- 1;
3124 steps
= m_current
% m_linesPerPage
;
3127 int index
= m_current
- steps
;
3131 OnArrowChar( index
, event
);
3138 if ( HasFlag(wxLC_REPORT
) )
3140 steps
= m_linesPerPage
- 1;
3144 steps
= m_linesPerPage
- (m_current
% m_linesPerPage
) - 1;
3147 size_t index
= m_current
+ steps
;
3148 size_t count
= GetItemCount();
3149 if ( index
>= count
)
3152 OnArrowChar( index
, event
);
3157 if ( !HasFlag(wxLC_REPORT
) )
3159 int index
= m_current
- m_linesPerPage
;
3163 OnArrowChar( index
, event
);
3168 if ( !HasFlag(wxLC_REPORT
) )
3170 size_t index
= m_current
+ m_linesPerPage
;
3172 size_t count
= GetItemCount();
3173 if ( index
>= count
)
3176 OnArrowChar( index
, event
);
3181 if ( IsSingleSel() )
3183 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3184 GetParent()->GetId() );
3185 le
.SetEventObject( GetParent() );
3186 le
.m_itemIndex
= m_current
;
3187 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3188 GetParent()->GetEventHandler()->ProcessEvent( le
);
3192 ReverseHighlight(m_current
);
3199 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3200 GetParent()->GetId() );
3201 le
.SetEventObject( GetParent() );
3202 le
.m_itemIndex
= m_current
;
3203 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3204 GetParent()->GetEventHandler()->ProcessEvent( le
);
3213 // ----------------------------------------------------------------------------
3215 // ----------------------------------------------------------------------------
3218 extern wxWindow
*g_focusWindow
;
3221 void wxListMainWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
3226 RefreshLine( m_current
);
3232 g_focusWindow
= GetParent();
3235 wxFocusEvent
event( wxEVT_SET_FOCUS
, GetParent()->GetId() );
3236 event
.SetEventObject( GetParent() );
3237 GetParent()->GetEventHandler()->ProcessEvent( event
);
3240 void wxListMainWindow::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
3245 RefreshLine( m_current
);
3248 void wxListMainWindow::DrawImage( int index
, wxDC
*dc
, int x
, int y
)
3250 if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
))
3252 m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3254 else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
))
3256 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3258 else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
))
3260 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3262 else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
))
3264 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3268 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height
) const
3270 if ( HasFlag(wxLC_ICON
) && m_normal_image_list
)
3272 m_normal_image_list
->GetSize( index
, width
, height
);
3274 else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list
)
3276 m_small_image_list
->GetSize( index
, width
, height
);
3278 else if ( HasFlag(wxLC_LIST
) && m_small_image_list
)
3280 m_small_image_list
->GetSize( index
, width
, height
);
3282 else if ( HasFlag(wxLC_REPORT
) && m_small_image_list
)
3284 m_small_image_list
->GetSize( index
, width
, height
);
3293 int wxListMainWindow::GetTextLength( const wxString
&s
) const
3295 wxClientDC
dc( wxConstCast(this, wxListMainWindow
) );
3296 dc
.SetFont( GetFont() );
3299 dc
.GetTextExtent( s
, &lw
, NULL
);
3301 return lw
+ AUTOSIZE_COL_MARGIN
;
3304 void wxListMainWindow::SetImageList( wxImageList
*imageList
, int which
)
3308 // calc the spacing from the icon size
3311 if ((imageList
) && (imageList
->GetImageCount()) )
3313 imageList
->GetSize(0, width
, height
);
3316 if (which
== wxIMAGE_LIST_NORMAL
)
3318 m_normal_image_list
= imageList
;
3319 m_normal_spacing
= width
+ 8;
3322 if (which
== wxIMAGE_LIST_SMALL
)
3324 m_small_image_list
= imageList
;
3325 m_small_spacing
= width
+ 14;
3329 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall
)
3334 m_small_spacing
= spacing
;
3338 m_normal_spacing
= spacing
;
3342 int wxListMainWindow::GetItemSpacing( bool isSmall
)
3344 return isSmall
? m_small_spacing
: m_normal_spacing
;
3347 // ----------------------------------------------------------------------------
3349 // ----------------------------------------------------------------------------
3351 void wxListMainWindow::SetColumn( int col
, wxListItem
&item
)
3353 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3355 wxCHECK_RET( node
, _T("invalid column index in SetColumn") );
3357 if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3358 item
.m_width
= GetTextLength( item
.m_text
);
3360 wxListHeaderData
*column
= node
->GetData();
3361 column
->SetItem( item
);
3363 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3365 headerWin
->m_dirty
= TRUE
;
3369 // invalidate it as it has to be recalculated
3373 void wxListMainWindow::SetColumnWidth( int col
, int width
)
3375 wxCHECK_RET( col
>= 0 && col
< GetColumnCount(),
3376 _T("invalid column index") );
3378 wxCHECK_RET( HasFlag(wxLC_REPORT
),
3379 _T("SetColumnWidth() can only be called in report mode.") );
3383 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3384 wxCHECK_RET( node
, _T("no column?") );
3386 wxListHeaderData
*column
= node
->GetData();
3388 size_t count
= GetItemCount();
3390 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
3392 width
= GetTextLength(column
->GetText());
3394 else if ( width
== wxLIST_AUTOSIZE
)
3398 // TODO: determine the max width somehow...
3399 width
= WIDTH_COL_DEFAULT
;
3403 wxClientDC
dc(this);
3404 dc
.SetFont( GetFont() );
3406 int max
= AUTOSIZE_COL_MARGIN
;
3408 for ( size_t i
= 0; i
< count
; i
++ )
3410 wxListLineData
*line
= GetLine(i
);
3411 wxListItemDataList::Node
*n
= line
->m_items
.Item( col
);
3413 wxCHECK_RET( n
, _T("no subitem?") );
3415 wxListItemData
*item
= n
->GetData();
3418 if (item
->HasImage())
3421 GetImageSize( item
->GetImage(), ix
, iy
);
3425 if (item
->HasText())
3428 dc
.GetTextExtent( item
->GetText(), &w
, NULL
);
3436 width
= max
+ AUTOSIZE_COL_MARGIN
;
3440 column
->SetWidth( width
);
3442 // invalidate it as it has to be recalculated
3446 int wxListMainWindow::GetHeaderWidth() const
3448 if ( !m_headerWidth
)
3450 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
3452 size_t count
= GetColumnCount();
3453 for ( size_t col
= 0; col
< count
; col
++ )
3455 self
->m_headerWidth
+= GetColumnWidth(col
);
3459 return m_headerWidth
;
3462 void wxListMainWindow::GetColumn( int col
, wxListItem
&item
) const
3464 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3465 wxCHECK_RET( node
, _T("invalid column index in GetColumn") );
3467 wxListHeaderData
*column
= node
->GetData();
3468 column
->GetItem( item
);
3471 int wxListMainWindow::GetColumnWidth( int col
) const
3473 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3474 wxCHECK_MSG( node
, 0, _T("invalid column index") );
3476 wxListHeaderData
*column
= node
->GetData();
3477 return column
->GetWidth();
3480 // ----------------------------------------------------------------------------
3482 // ----------------------------------------------------------------------------
3484 void wxListMainWindow::SetItem( wxListItem
&item
)
3486 long id
= item
.m_itemId
;
3487 wxCHECK_RET( id
>= 0 && (size_t)id
< GetItemCount(),
3488 _T("invalid item index in SetItem") );
3492 wxListLineData
*line
= GetLine((size_t)id
);
3493 line
->SetItem( item
.m_col
, item
);
3496 if ( InReportView() )
3498 // just refresh the line to show the new value of the text/image
3499 RefreshLine((size_t)id
);
3503 // refresh everything (resulting in horrible flicker - FIXME!)
3508 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask
)
3510 wxCHECK_RET( litem
>= 0 && (size_t)litem
< GetItemCount(),
3511 _T("invalid list ctrl item index in SetItem") );
3513 size_t oldCurrent
= m_current
;
3514 size_t item
= (size_t)litem
; // sdafe because of the check above
3516 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3518 if ( state
& wxLIST_STATE_FOCUSED
)
3520 // don't do anything if this item is already focused
3521 if ( item
!= m_current
)
3523 OnUnfocusLine( m_current
);
3525 OnFocusLine( m_current
);
3527 if ( IsSingleSel() && (oldCurrent
!= (size_t)-1) )
3529 HighlightLine(oldCurrent
, FALSE
);
3530 RefreshLine(oldCurrent
);
3533 RefreshLine( m_current
);
3538 // don't do anything if this item is not focused
3539 if ( item
== m_current
)
3541 OnUnfocusLine( m_current
);
3542 m_current
= (size_t)-1;
3547 if ( stateMask
& wxLIST_STATE_SELECTED
)
3549 bool on
= (state
& wxLIST_STATE_SELECTED
) != 0;
3551 if ( IsSingleSel() )
3555 // selecting the item also makes it the focused one in the
3557 if ( m_current
!= item
)
3559 OnUnfocusLine( m_current
);
3561 OnFocusLine( m_current
);
3563 if ( oldCurrent
!= (size_t)-1 )
3565 HighlightLine( oldCurrent
, FALSE
);
3566 RefreshLine( oldCurrent
);
3572 // only the current item may be selected anyhow
3573 if ( item
!= m_current
)
3578 if ( HighlightLine(item
, on
) )
3585 int wxListMainWindow::GetItemState( long item
, long stateMask
)
3587 wxCHECK_MSG( item
>= 0 && (size_t)item
< GetItemCount(), 0,
3588 _T("invalid list ctrl item index in GetItemState()") );
3590 int ret
= wxLIST_STATE_DONTCARE
;
3592 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3594 if ( (size_t)item
== m_current
)
3595 ret
|= wxLIST_STATE_FOCUSED
;
3598 if ( stateMask
& wxLIST_STATE_SELECTED
)
3600 if ( IsHighlighted(item
) )
3601 ret
|= wxLIST_STATE_SELECTED
;
3607 void wxListMainWindow::GetItem( wxListItem
&item
)
3609 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
< GetItemCount(),
3610 _T("invalid item index in GetItem") );
3612 wxListLineData
*line
= GetLine((size_t)item
.m_itemId
);
3613 line
->GetItem( item
.m_col
, item
);
3616 // ----------------------------------------------------------------------------
3618 // ----------------------------------------------------------------------------
3620 size_t wxListMainWindow::GetItemCount() const
3622 return IsVirtual() ? m_countVirt
: m_lines
.GetCount();
3625 void wxListMainWindow::SetItemCount(long count
)
3627 m_selStore
.SetItemCount(count
);
3628 m_countVirt
= count
;
3630 ResetVisibleLinesRange();
3632 // scrollbars must be reset
3636 int wxListMainWindow::GetSelectedItemCount()
3638 // deal with the quick case first
3639 if ( IsSingleSel() )
3641 return HasCurrent() ? IsHighlighted(m_current
) : FALSE
;
3644 // virtual controls remmebers all its selections itself
3646 return m_selStore
.GetSelectedCount();
3648 // TODO: we probably should maintain the number of items selected even for
3649 // non virtual controls as enumerating all lines is really slow...
3650 size_t countSel
= 0;
3651 size_t count
= GetItemCount();
3652 for ( size_t line
= 0; line
< count
; line
++ )
3654 if ( GetLine(line
)->IsHighlighted() )
3661 // ----------------------------------------------------------------------------
3662 // item position/size
3663 // ----------------------------------------------------------------------------
3665 void wxListMainWindow::GetItemRect( long index
, wxRect
&rect
)
3667 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3668 _T("invalid index in GetItemRect") );
3670 rect
= GetLineRect((size_t)index
);
3672 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
3675 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
)
3678 GetItemRect(item
, rect
);
3686 // ----------------------------------------------------------------------------
3687 // geometry calculation
3688 // ----------------------------------------------------------------------------
3690 void wxListMainWindow::RecalculatePositions(bool noRefresh
)
3692 wxClientDC
dc( this );
3693 dc
.SetFont( GetFont() );
3696 if ( HasFlag(wxLC_ICON
) )
3697 iconSpacing
= m_normal_spacing
;
3698 else if ( HasFlag(wxLC_SMALL_ICON
) )
3699 iconSpacing
= m_small_spacing
;
3705 GetClientSize( &clientWidth
, &clientHeight
);
3707 if ( HasFlag(wxLC_REPORT
) )
3709 // all lines have the same height
3710 int lineHeight
= GetLineHeight();
3712 // scroll one line per step
3713 m_yScroll
= lineHeight
;
3715 size_t lineCount
= GetItemCount();
3716 int entireHeight
= lineCount
*lineHeight
+ LINE_SPACING
;
3718 m_linesPerPage
= clientHeight
/ lineHeight
;
3720 ResetVisibleLinesRange();
3722 SetScrollbars( m_xScroll
, m_yScroll
,
3723 (GetHeaderWidth() + m_xScroll
- 1)/m_xScroll
,
3724 (entireHeight
+ m_yScroll
- 1)/m_yScroll
,
3725 GetScrollPos(wxHORIZONTAL
),
3726 GetScrollPos(wxVERTICAL
),
3731 // at first we try without any scrollbar. if the items don't
3732 // fit into the window, we recalculate after subtracting an
3733 // approximated 15 pt for the horizontal scrollbar
3735 clientHeight
-= 4; // sunken frame
3737 int entireWidth
= 0;
3739 for (int tries
= 0; tries
< 2; tries
++)
3746 int currentlyVisibleLines
= 0;
3748 size_t count
= GetItemCount();
3749 for (size_t i
= 0; i
< count
; i
++)
3751 currentlyVisibleLines
++;
3752 wxListLineData
*line
= GetLine(i
);
3753 line
->CalculateSize( &dc
, iconSpacing
);
3754 line
->SetPosition( x
, y
, clientWidth
, iconSpacing
);
3756 wxSize sizeLine
= GetLineSize(i
);
3758 if ( maxWidth
< sizeLine
.x
)
3759 maxWidth
= sizeLine
.x
;
3762 if (currentlyVisibleLines
> m_linesPerPage
)
3763 m_linesPerPage
= currentlyVisibleLines
;
3765 // assume that the size of the next one is the same... (FIXME)
3766 if ( y
+ sizeLine
.y
- 6 >= clientHeight
)
3768 currentlyVisibleLines
= 0;
3771 entireWidth
+= maxWidth
+6;
3774 if ( i
== count
- 1 )
3775 entireWidth
+= maxWidth
;
3776 if ((tries
== 0) && (entireWidth
> clientWidth
))
3778 clientHeight
-= 15; // scrollbar height
3780 currentlyVisibleLines
= 0;
3783 if ( i
== count
- 1 )
3784 tries
= 1; // everything fits, no second try required
3788 int scroll_pos
= GetScrollPos( wxHORIZONTAL
);
3789 SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE
);
3794 // FIXME: why should we call it from here?
3801 void wxListMainWindow::RefreshAll()
3806 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3809 headerWin
->m_dirty
= FALSE
;
3810 headerWin
->Refresh();
3814 void wxListMainWindow::UpdateCurrent()
3816 if ( !HasCurrent() && !IsEmpty() )
3821 if ( m_current
!= (size_t)-1 )
3823 OnFocusLine( m_current
);
3827 long wxListMainWindow::GetNextItem( long item
,
3828 int WXUNUSED(geometry
),
3832 max
= GetItemCount();
3833 wxCHECK_MSG( (ret
== -1) || (ret
< max
), -1,
3834 _T("invalid listctrl index in GetNextItem()") );
3836 // notice that we start with the next item (or the first one if item == -1)
3837 // and this is intentional to allow writing a simple loop to iterate over
3838 // all selected items
3842 // this is not an error because the index was ok initially, just no
3853 size_t count
= GetItemCount();
3854 for ( size_t line
= (size_t)ret
; line
< count
; line
++ )
3856 if ( (state
& wxLIST_STATE_FOCUSED
) && (line
== m_current
) )
3859 if ( (state
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) )
3866 // ----------------------------------------------------------------------------
3868 // ----------------------------------------------------------------------------
3870 void wxListMainWindow::DeleteItem( long lindex
)
3872 size_t count
= GetItemCount();
3874 wxCHECK_RET( (lindex
>= 0) && ((size_t)lindex
< count
),
3875 _T("invalid item index in DeleteItem") );
3877 size_t index
= (size_t)lindex
;
3879 // we don't need to adjust the index for the previous items
3880 if ( HasCurrent() && m_current
>= index
)
3882 // if the current item is being deleted, we want the next one to
3883 // become selected - unless there is no next one - so don't adjust
3884 // m_current in this case
3885 if ( m_current
!= index
|| m_current
== count
- 1 )
3891 if ( InReportView() )
3893 ResetVisibleLinesRange();
3900 m_selStore
.OnItemDelete(index
);
3904 m_lines
.RemoveAt( index
);
3909 SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
);
3911 RefreshAfter(index
);
3914 void wxListMainWindow::DeleteColumn( int col
)
3916 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3918 wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") );
3921 m_columns
.DeleteNode( node
);
3924 void wxListMainWindow::DoDeleteAllItems()
3928 // nothing to do - in particular, don't send the event
3934 // to make the deletion of all items faster, we don't send the
3935 // notifications for each item deletion in this case but only one event
3936 // for all of them: this is compatible with wxMSW and documented in
3937 // DeleteAllItems() description
3939 wxListEvent
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() );
3940 event
.SetEventObject( GetParent() );
3941 GetParent()->GetEventHandler()->ProcessEvent( event
);
3950 if ( InReportView() )
3952 ResetVisibleLinesRange();
3958 void wxListMainWindow::DeleteAllItems()
3962 RecalculatePositions();
3965 void wxListMainWindow::DeleteEverything()
3972 // ----------------------------------------------------------------------------
3973 // scanning for an item
3974 // ----------------------------------------------------------------------------
3976 void wxListMainWindow::EnsureVisible( long index
)
3978 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3979 _T("invalid index in EnsureVisible") );
3981 // We have to call this here because the label in question might just have
3982 // been added and its position is not known yet
3987 RecalculatePositions(TRUE
/* no refresh */);
3990 MoveToItem((size_t)index
);
3993 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) )
4000 size_t count
= GetItemCount();
4001 for ( size_t i
= (size_t)pos
; i
< count
; i
++ )
4003 wxListLineData
*line
= GetLine(i
);
4004 if ( line
->GetText(0) == tmp
)
4011 long wxListMainWindow::FindItem(long start
, long data
)
4017 size_t count
= GetItemCount();
4018 for (size_t i
= (size_t)pos
; i
< count
; i
++)
4020 wxListLineData
*line
= GetLine(i
);
4022 line
->GetItem( 0, item
);
4023 if (item
.m_data
== data
)
4030 long wxListMainWindow::HitTest( int x
, int y
, int &flags
)
4032 CalcUnscrolledPosition( x
, y
, &x
, &y
);
4034 if ( HasFlag(wxLC_REPORT
) )
4036 size_t current
= y
/ GetLineHeight();
4037 flags
= HitTestLine(current
, x
, y
);
4043 // TODO: optimize it too! this is less simple than for report view but
4044 // enumerating all items is still not a way to do it!!
4045 size_t count
= GetItemCount();
4046 for ( size_t current
= 0; current
< count
; current
++ )
4048 flags
= HitTestLine(current
, x
, y
);
4057 // ----------------------------------------------------------------------------
4059 // ----------------------------------------------------------------------------
4061 void wxListMainWindow::InsertItem( wxListItem
&item
)
4063 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
4065 size_t count
= GetItemCount();
4066 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
<= count
,
4067 _T("invalid item index") );
4069 size_t id
= item
.m_itemId
;
4074 if ( HasFlag(wxLC_REPORT
) )
4076 else if ( HasFlag(wxLC_LIST
) )
4078 else if ( HasFlag(wxLC_ICON
) )
4080 else if ( HasFlag(wxLC_SMALL_ICON
) )
4081 mode
= wxLC_ICON
; // no typo
4084 wxFAIL_MSG( _T("unknown mode") );
4087 wxListLineData
*line
= new wxListLineData(this);
4089 line
->SetItem( 0, item
);
4091 m_lines
.Insert( line
, id
);
4094 RefreshLines(id
, GetItemCount() - 1);
4097 void wxListMainWindow::InsertColumn( long col
, wxListItem
&item
)
4100 if ( HasFlag(wxLC_REPORT
) )
4102 if (item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
4103 item
.m_width
= GetTextLength( item
.m_text
);
4104 wxListHeaderData
*column
= new wxListHeaderData( item
);
4105 if ((col
>= 0) && (col
< (int)m_columns
.GetCount()))
4107 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
4108 m_columns
.Insert( node
, column
);
4112 m_columns
.Append( column
);
4117 // ----------------------------------------------------------------------------
4119 // ----------------------------------------------------------------------------
4121 wxListCtrlCompare list_ctrl_compare_func_2
;
4122 long list_ctrl_compare_data
;
4124 int LINKAGEMODE
list_ctrl_compare_func_1( wxListLineData
**arg1
, wxListLineData
**arg2
)
4126 wxListLineData
*line1
= *arg1
;
4127 wxListLineData
*line2
= *arg2
;
4129 line1
->GetItem( 0, item
);
4130 long data1
= item
.m_data
;
4131 line2
->GetItem( 0, item
);
4132 long data2
= item
.m_data
;
4133 return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data
);
4136 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data
)
4138 list_ctrl_compare_func_2
= fn
;
4139 list_ctrl_compare_data
= data
;
4140 m_lines
.Sort( list_ctrl_compare_func_1
);
4144 // ----------------------------------------------------------------------------
4146 // ----------------------------------------------------------------------------
4148 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
)
4150 // update our idea of which lines are shown when we redraw the window the
4152 ResetVisibleLinesRange();
4155 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4156 wxScrolledWindow::OnScroll(event
);
4158 HandleOnScroll( event
);
4161 if ( event
.GetOrientation() == wxHORIZONTAL
&& HasHeader() )
4163 wxListCtrl
* lc
= GetListCtrl();
4164 wxCHECK_RET( lc
, _T("no listctrl window?") );
4166 lc
->m_headerWin
->Refresh() ;
4168 lc
->m_headerWin
->MacUpdateImmediately() ;
4173 int wxListMainWindow::GetCountPerPage() const
4175 if ( !m_linesPerPage
)
4177 wxConstCast(this, wxListMainWindow
)->
4178 m_linesPerPage
= GetClientSize().y
/ GetLineHeight();
4181 return m_linesPerPage
;
4184 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
)
4186 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") );
4188 if ( m_lineFrom
== (size_t)-1 )
4190 size_t count
= GetItemCount();
4193 m_lineFrom
= GetScrollPos(wxVERTICAL
);
4195 // this may happen if SetScrollbars() hadn't been called yet
4196 if ( m_lineFrom
>= count
)
4197 m_lineFrom
= count
- 1;
4199 // we redraw one extra line but this is needed to make the redrawing
4200 // logic work when there is a fractional number of lines on screen
4201 m_lineTo
= m_lineFrom
+ m_linesPerPage
;
4202 if ( m_lineTo
>= count
)
4203 m_lineTo
= count
- 1;
4205 else // empty control
4208 m_lineTo
= (size_t)-1;
4212 wxASSERT_MSG( IsEmpty() ||
4213 (m_lineFrom
<= m_lineTo
&& m_lineTo
< GetItemCount()),
4214 _T("GetVisibleLinesRange() returns incorrect result") );
4222 // -------------------------------------------------------------------------------------
4224 // -------------------------------------------------------------------------------------
4226 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
4228 wxListItem::wxListItem()
4237 m_format
= wxLIST_FORMAT_CENTRE
;
4243 void wxListItem::Clear()
4252 m_format
= wxLIST_FORMAT_CENTRE
;
4259 void wxListItem::ClearAttributes()
4268 // -------------------------------------------------------------------------------------
4270 // -------------------------------------------------------------------------------------
4272 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
4274 wxListEvent::wxListEvent( wxEventType commandType
, int id
)
4275 : wxNotifyEvent( commandType
, id
)
4281 m_cancelled
= FALSE
;
4286 void wxListEvent::CopyObject(wxObject
& object_dest
) const
4288 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
4290 wxNotifyEvent::CopyObject(object_dest
);
4292 obj
->m_code
= m_code
;
4293 obj
->m_itemIndex
= m_itemIndex
;
4294 obj
->m_oldItemIndex
= m_oldItemIndex
;
4296 obj
->m_cancelled
= m_cancelled
;
4297 obj
->m_pointDrag
= m_pointDrag
;
4298 obj
->m_item
.m_mask
= m_item
.m_mask
;
4299 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
4300 obj
->m_item
.m_col
= m_item
.m_col
;
4301 obj
->m_item
.m_state
= m_item
.m_state
;
4302 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
4303 obj
->m_item
.m_text
= m_item
.m_text
;
4304 obj
->m_item
.m_image
= m_item
.m_image
;
4305 obj
->m_item
.m_data
= m_item
.m_data
;
4306 obj
->m_item
.m_format
= m_item
.m_format
;
4307 obj
->m_item
.m_width
= m_item
.m_width
;
4309 if ( m_item
.HasAttributes() )
4311 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
4315 // -------------------------------------------------------------------------------------
4317 // -------------------------------------------------------------------------------------
4319 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
4321 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
)
4322 EVT_SIZE(wxListCtrl::OnSize
)
4323 EVT_IDLE(wxListCtrl::OnIdle
)
4326 wxListCtrl::wxListCtrl()
4328 m_imageListNormal
= (wxImageList
*) NULL
;
4329 m_imageListSmall
= (wxImageList
*) NULL
;
4330 m_imageListState
= (wxImageList
*) NULL
;
4332 m_ownsImageListNormal
=
4333 m_ownsImageListSmall
=
4334 m_ownsImageListState
= FALSE
;
4336 m_mainWin
= (wxListMainWindow
*) NULL
;
4337 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4340 wxListCtrl::~wxListCtrl()
4343 m_mainWin
->ResetCurrent();
4345 if (m_ownsImageListNormal
)
4346 delete m_imageListNormal
;
4347 if (m_ownsImageListSmall
)
4348 delete m_imageListSmall
;
4349 if (m_ownsImageListState
)
4350 delete m_imageListState
;
4353 void wxListCtrl::CreateHeaderWindow()
4355 m_headerWin
= new wxListHeaderWindow
4357 this, -1, m_mainWin
,
4359 wxSize(GetClientSize().x
, HEADER_HEIGHT
),
4364 bool wxListCtrl::Create(wxWindow
*parent
,
4369 const wxValidator
&validator
,
4370 const wxString
&name
)
4374 m_imageListState
= (wxImageList
*) NULL
;
4375 m_ownsImageListNormal
=
4376 m_ownsImageListSmall
=
4377 m_ownsImageListState
= FALSE
;
4379 m_mainWin
= (wxListMainWindow
*) NULL
;
4380 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4382 if ( !(style
& wxLC_MASK_TYPE
) )
4384 style
= style
| wxLC_LIST
;
4387 if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name
) )
4390 // don't create the inner window with the border
4391 style
&= ~wxSUNKEN_BORDER
;
4393 m_mainWin
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style
);
4395 if ( HasFlag(wxLC_REPORT
) )
4397 CreateHeaderWindow();
4399 if ( HasFlag(wxLC_NO_HEADER
) )
4401 // VZ: why do we create it at all then?
4402 m_headerWin
->Show( FALSE
);
4409 void wxListCtrl::SetSingleStyle( long style
, bool add
)
4411 wxASSERT_MSG( !(style
& wxLC_VIRTUAL
),
4412 _T("wxLC_VIRTUAL can't be [un]set") );
4414 long flag
= GetWindowStyle();
4418 if (style
& wxLC_MASK_TYPE
)
4419 flag
&= ~(wxLC_MASK_TYPE
| wxLC_VIRTUAL
);
4420 if (style
& wxLC_MASK_ALIGN
)
4421 flag
&= ~wxLC_MASK_ALIGN
;
4422 if (style
& wxLC_MASK_SORT
)
4423 flag
&= ~wxLC_MASK_SORT
;
4435 SetWindowStyleFlag( flag
);
4438 void wxListCtrl::SetWindowStyleFlag( long flag
)
4442 m_mainWin
->DeleteEverything();
4444 // has the header visibility changed?
4445 bool hasHeader
= HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
),
4446 willHaveHeader
= (flag
& wxLC_REPORT
) && !(flag
& wxLC_NO_HEADER
);
4448 if ( hasHeader
!= willHaveHeader
)
4455 // don't delete, just hide, as we can reuse it later
4456 m_headerWin
->Show(FALSE
);
4458 //else: nothing to do
4460 else // must show header
4464 CreateHeaderWindow();
4466 else // already have it, just show
4468 m_headerWin
->Show( TRUE
);
4472 ResizeReportView(willHaveHeader
);
4476 wxWindow::SetWindowStyleFlag( flag
);
4479 bool wxListCtrl::GetColumn(int col
, wxListItem
&item
) const
4481 m_mainWin
->GetColumn( col
, item
);
4485 bool wxListCtrl::SetColumn( int col
, wxListItem
& item
)
4487 m_mainWin
->SetColumn( col
, item
);
4491 int wxListCtrl::GetColumnWidth( int col
) const
4493 return m_mainWin
->GetColumnWidth( col
);
4496 bool wxListCtrl::SetColumnWidth( int col
, int width
)
4498 m_mainWin
->SetColumnWidth( col
, width
);
4502 int wxListCtrl::GetCountPerPage() const
4504 return m_mainWin
->GetCountPerPage(); // different from Windows ?
4507 bool wxListCtrl::GetItem( wxListItem
&info
) const
4509 m_mainWin
->GetItem( info
);
4513 bool wxListCtrl::SetItem( wxListItem
&info
)
4515 m_mainWin
->SetItem( info
);
4519 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId
)
4522 info
.m_text
= label
;
4523 info
.m_mask
= wxLIST_MASK_TEXT
;
4524 info
.m_itemId
= index
;
4528 info
.m_image
= imageId
;
4529 info
.m_mask
|= wxLIST_MASK_IMAGE
;
4531 m_mainWin
->SetItem(info
);
4535 int wxListCtrl::GetItemState( long item
, long stateMask
) const
4537 return m_mainWin
->GetItemState( item
, stateMask
);
4540 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask
)
4542 m_mainWin
->SetItemState( item
, state
, stateMask
);
4546 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) )
4549 info
.m_image
= image
;
4550 info
.m_mask
= wxLIST_MASK_IMAGE
;
4551 info
.m_itemId
= item
;
4552 m_mainWin
->SetItem( info
);
4556 wxString
wxListCtrl::GetItemText( long item
) const
4559 info
.m_itemId
= item
;
4560 m_mainWin
->GetItem( info
);
4564 void wxListCtrl::SetItemText( long item
, const wxString
&str
)
4567 info
.m_mask
= wxLIST_MASK_TEXT
;
4568 info
.m_itemId
= item
;
4570 m_mainWin
->SetItem( info
);
4573 long wxListCtrl::GetItemData( long item
) const
4576 info
.m_itemId
= item
;
4577 m_mainWin
->GetItem( info
);
4581 bool wxListCtrl::SetItemData( long item
, long data
)
4584 info
.m_mask
= wxLIST_MASK_DATA
;
4585 info
.m_itemId
= item
;
4587 m_mainWin
->SetItem( info
);
4591 bool wxListCtrl::GetItemRect( long item
, wxRect
&rect
, int WXUNUSED(code
) ) const
4593 m_mainWin
->GetItemRect( item
, rect
);
4597 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos
) const
4599 m_mainWin
->GetItemPosition( item
, pos
);
4603 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) )
4608 int wxListCtrl::GetItemCount() const
4610 return m_mainWin
->GetItemCount();
4613 int wxListCtrl::GetColumnCount() const
4615 return m_mainWin
->GetColumnCount();
4618 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall
)
4620 m_mainWin
->SetItemSpacing( spacing
, isSmall
);
4623 int wxListCtrl::GetItemSpacing( bool isSmall
) const
4625 return m_mainWin
->GetItemSpacing( isSmall
);
4628 int wxListCtrl::GetSelectedItemCount() const
4630 return m_mainWin
->GetSelectedItemCount();
4633 wxColour
wxListCtrl::GetTextColour() const
4635 return GetForegroundColour();
4638 void wxListCtrl::SetTextColour(const wxColour
& col
)
4640 SetForegroundColour(col
);
4643 long wxListCtrl::GetTopItem() const
4648 long wxListCtrl::GetNextItem( long item
, int geom
, int state
) const
4650 return m_mainWin
->GetNextItem( item
, geom
, state
);
4653 wxImageList
*wxListCtrl::GetImageList(int which
) const
4655 if (which
== wxIMAGE_LIST_NORMAL
)
4657 return m_imageListNormal
;
4659 else if (which
== wxIMAGE_LIST_SMALL
)
4661 return m_imageListSmall
;
4663 else if (which
== wxIMAGE_LIST_STATE
)
4665 return m_imageListState
;
4667 return (wxImageList
*) NULL
;
4670 void wxListCtrl::SetImageList( wxImageList
*imageList
, int which
)
4672 if ( which
== wxIMAGE_LIST_NORMAL
)
4674 if (m_ownsImageListNormal
) delete m_imageListNormal
;
4675 m_imageListNormal
= imageList
;
4676 m_ownsImageListNormal
= FALSE
;
4678 else if ( which
== wxIMAGE_LIST_SMALL
)
4680 if (m_ownsImageListSmall
) delete m_imageListSmall
;
4681 m_imageListSmall
= imageList
;
4682 m_ownsImageListSmall
= FALSE
;
4684 else if ( which
== wxIMAGE_LIST_STATE
)
4686 if (m_ownsImageListState
) delete m_imageListState
;
4687 m_imageListState
= imageList
;
4688 m_ownsImageListState
= FALSE
;
4691 m_mainWin
->SetImageList( imageList
, which
);
4694 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
4696 SetImageList(imageList
, which
);
4697 if ( which
== wxIMAGE_LIST_NORMAL
)
4698 m_ownsImageListNormal
= TRUE
;
4699 else if ( which
== wxIMAGE_LIST_SMALL
)
4700 m_ownsImageListSmall
= TRUE
;
4701 else if ( which
== wxIMAGE_LIST_STATE
)
4702 m_ownsImageListState
= TRUE
;
4705 bool wxListCtrl::Arrange( int WXUNUSED(flag
) )
4710 bool wxListCtrl::DeleteItem( long item
)
4712 m_mainWin
->DeleteItem( item
);
4716 bool wxListCtrl::DeleteAllItems()
4718 m_mainWin
->DeleteAllItems();
4722 bool wxListCtrl::DeleteAllColumns()
4724 size_t count
= m_mainWin
->m_columns
.GetCount();
4725 for ( size_t n
= 0; n
< count
; n
++ )
4731 void wxListCtrl::ClearAll()
4733 m_mainWin
->DeleteEverything();
4736 bool wxListCtrl::DeleteColumn( int col
)
4738 m_mainWin
->DeleteColumn( col
);
4742 void wxListCtrl::Edit( long item
)
4744 m_mainWin
->EditLabel( item
);
4747 bool wxListCtrl::EnsureVisible( long item
)
4749 m_mainWin
->EnsureVisible( item
);
4753 long wxListCtrl::FindItem( long start
, const wxString
& str
, bool partial
)
4755 return m_mainWin
->FindItem( start
, str
, partial
);
4758 long wxListCtrl::FindItem( long start
, long data
)
4760 return m_mainWin
->FindItem( start
, data
);
4763 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
),
4764 int WXUNUSED(direction
))
4769 long wxListCtrl::HitTest( const wxPoint
&point
, int &flags
)
4771 return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags
);
4774 long wxListCtrl::InsertItem( wxListItem
& info
)
4776 m_mainWin
->InsertItem( info
);
4777 return info
.m_itemId
;
4780 long wxListCtrl::InsertItem( long index
, const wxString
&label
)
4783 info
.m_text
= label
;
4784 info
.m_mask
= wxLIST_MASK_TEXT
;
4785 info
.m_itemId
= index
;
4786 return InsertItem( info
);
4789 long wxListCtrl::InsertItem( long index
, int imageIndex
)
4792 info
.m_mask
= wxLIST_MASK_IMAGE
;
4793 info
.m_image
= imageIndex
;
4794 info
.m_itemId
= index
;
4795 return InsertItem( info
);
4798 long wxListCtrl::InsertItem( long index
, const wxString
&label
, int imageIndex
)
4801 info
.m_text
= label
;
4802 info
.m_image
= imageIndex
;
4803 info
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_IMAGE
;
4804 info
.m_itemId
= index
;
4805 return InsertItem( info
);
4808 long wxListCtrl::InsertColumn( long col
, wxListItem
&item
)
4810 wxASSERT( m_headerWin
);
4811 m_mainWin
->InsertColumn( col
, item
);
4812 m_headerWin
->Refresh();
4817 long wxListCtrl::InsertColumn( long col
, const wxString
&heading
,
4818 int format
, int width
)
4821 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
4822 item
.m_text
= heading
;
4825 item
.m_mask
|= wxLIST_MASK_WIDTH
;
4826 item
.m_width
= width
;
4828 item
.m_format
= format
;
4830 return InsertColumn( col
, item
);
4833 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) )
4839 // fn is a function which takes 3 long arguments: item1, item2, data.
4840 // item1 is the long data associated with a first item (NOT the index).
4841 // item2 is the long data associated with a second item (NOT the index).
4842 // data is the same value as passed to SortItems.
4843 // The return value is a negative number if the first item should precede the second
4844 // item, a positive number of the second item should precede the first,
4845 // or zero if the two items are equivalent.
4846 // data is arbitrary data to be passed to the sort function.
4848 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data
)
4850 m_mainWin
->SortItems( fn
, data
);
4854 // ----------------------------------------------------------------------------
4856 // ----------------------------------------------------------------------------
4858 void wxListCtrl::OnSize(wxSizeEvent
& event
)
4863 ResizeReportView(m_mainWin
->HasHeader());
4865 m_mainWin
->RecalculatePositions();
4868 void wxListCtrl::ResizeReportView(bool showHeader
)
4871 GetClientSize( &cw
, &ch
);
4875 m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT
);
4876 m_mainWin
->SetSize( 0, HEADER_HEIGHT
+ 1, cw
, ch
- HEADER_HEIGHT
- 1 );
4878 else // no header window
4880 m_mainWin
->SetSize( 0, 0, cw
, ch
);
4884 void wxListCtrl::OnIdle( wxIdleEvent
& event
)
4888 // do it only if needed
4889 if ( !m_mainWin
->m_dirty
)
4892 m_mainWin
->RecalculatePositions();
4895 // ----------------------------------------------------------------------------
4897 // ----------------------------------------------------------------------------
4899 bool wxListCtrl::SetBackgroundColour( const wxColour
&colour
)
4903 m_mainWin
->SetBackgroundColour( colour
);
4904 m_mainWin
->m_dirty
= TRUE
;
4910 bool wxListCtrl::SetForegroundColour( const wxColour
&colour
)
4912 if ( !wxWindow::SetForegroundColour( colour
) )
4917 m_mainWin
->SetForegroundColour( colour
);
4918 m_mainWin
->m_dirty
= TRUE
;
4923 m_headerWin
->SetForegroundColour( colour
);
4929 bool wxListCtrl::SetFont( const wxFont
&font
)
4931 if ( !wxWindow::SetFont( font
) )
4936 m_mainWin
->SetFont( font
);
4937 m_mainWin
->m_dirty
= TRUE
;
4942 m_headerWin
->SetFont( font
);
4948 // ----------------------------------------------------------------------------
4949 // methods forwarded to m_mainWin
4950 // ----------------------------------------------------------------------------
4952 #if wxUSE_DRAG_AND_DROP
4954 void wxListCtrl::SetDropTarget( wxDropTarget
*dropTarget
)
4956 m_mainWin
->SetDropTarget( dropTarget
);
4959 wxDropTarget
*wxListCtrl::GetDropTarget() const
4961 return m_mainWin
->GetDropTarget();
4964 #endif // wxUSE_DRAG_AND_DROP
4966 bool wxListCtrl::SetCursor( const wxCursor
&cursor
)
4968 return m_mainWin
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
;
4971 wxColour
wxListCtrl::GetBackgroundColour() const
4973 return m_mainWin
? m_mainWin
->GetBackgroundColour() : wxColour();
4976 wxColour
wxListCtrl::GetForegroundColour() const
4978 return m_mainWin
? m_mainWin
->GetForegroundColour() : wxColour();
4981 bool wxListCtrl::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4984 return m_mainWin
->PopupMenu( menu
, x
, y
);
4987 #endif // wxUSE_MENUS
4990 void wxListCtrl::SetFocus()
4992 /* The test in window.cpp fails as we are a composite
4993 window, so it checks against "this", but not m_mainWin. */
4994 if ( FindFocus() != this )
4995 m_mainWin
->SetFocus();
4998 // ----------------------------------------------------------------------------
4999 // virtual list control support
5000 // ----------------------------------------------------------------------------
5002 wxString
wxListCtrl::OnGetItemText(long item
, long col
) const
5004 // this is a pure virtual function, in fact - which is not really pure
5005 // because the controls which are not virtual don't need to implement it
5006 wxFAIL_MSG( _T("not supposed to be called") );
5008 return wxEmptyString
;
5011 int wxListCtrl::OnGetItemImage(long item
) const
5014 wxFAIL_MSG( _T("not supposed to be called") );
5019 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long item
) const
5021 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
5022 _T("invalid item index in OnGetItemAttr()") );
5024 // no attributes by default
5028 void wxListCtrl::SetItemCount(long count
)
5030 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
5032 m_mainWin
->SetItemCount(count
);
5035 void wxListCtrl::RefreshItem(long item
)
5037 m_mainWin
->RefreshLine(item
);
5040 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
)
5042 m_mainWin
->RefreshLines(itemFrom
, itemTo
);
5045 #endif // wxUSE_LISTCTRL