1 /////////////////////////////////////////////////////////////////////////////
2 // Name: generic/listctrl.cpp
3 // Purpose: generic implementation of wxListCtrl
4 // Author: Robert Roebling
5 // Vadim Zeitlin (virtual list control support)
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
12 FIXME for virtual list controls
14 +1. clicking on the item with a mouse is awfully slow, what is going on?
15 note that selecting with keyboard seems to be much faster
16 => fixed HighlightAll() - iterating over 1000000 items *is* slow
18 2. background colour is wrong?
22 TODO for better virtual list control support:
24 1. less dumb line caching, we should cache at least all those visible
25 in the control itself and probably twice as many (we might also need to
26 cache the first one always for geometry calculations?)
28 +2. storing selections: we can't use an array to store the selected indices
29 like right now as selecting all in a control with 1000000 items is not
30 doable like this - instead, store selections as collection of individual
35 3. we need to implement searching/sorting somehow
37 4. the idea of storing the line index in the line itself is really stupid,
38 we shouldn't need it - but for this we have to get rid of all calles to
39 wxListLineData::GetFoo() and replace them with something like
41 ... we have it ourselves ...
47 5. attributes support: we need OnGetItemAttr() as well!
50 // ============================================================================
52 // ============================================================================
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
59 #pragma implementation "listctrl.h"
60 #pragma implementation "listctrlbase.h"
63 // For compilers that support precompilation, includes "wx.h".
64 #include "wx/wxprec.h"
72 #include "wx/dcscreen.h"
74 #include "wx/listctrl.h"
75 #include "wx/imaglist.h"
76 #include "wx/dynarray.h"
80 #include "wx/gtk/win_gtk.h"
83 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
)
88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
)
89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
)
90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
)
91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
)
92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
)
93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
)
94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
)
95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
)
96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
)
97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
)
98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
)
99 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
)
100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
)
101 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
)
102 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
)
104 // ----------------------------------------------------------------------------
106 // ----------------------------------------------------------------------------
108 // the height of the header window (FIXME: should depend on its font!)
109 static const int HEADER_HEIGHT
= 23;
111 // the scrollbar units
112 static const int SCROLL_UNIT_X
= 15;
113 static const int SCROLL_UNIT_Y
= 15;
115 // the spacing between the lines (in report mode)
116 static const int LINE_SPACING
= 0;
118 // extra margins around the text label
119 static const int EXTRA_WIDTH
= 3;
120 static const int EXTRA_HEIGHT
= 4;
122 // offset for the header window
123 static const int HEADER_OFFSET_X
= 1;
124 static const int HEADER_OFFSET_Y
= 1;
126 // when autosizing the columns, add some slack
127 static const int AUTOSIZE_COL_MARGIN
= 10;
129 // default and minimal widths for the header columns
130 static const int WIDTH_COL_DEFAULT
= 80;
131 static const int WIDTH_COL_MIN
= 10;
133 // ============================================================================
135 // ============================================================================
137 // ----------------------------------------------------------------------------
139 // ----------------------------------------------------------------------------
141 int CMPFUNC_CONV
wxSizeTCmpFn(size_t n1
, size_t n2
) { return n1
- n2
; }
143 WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray
);
145 // this class is used to store the selected items in the virtual list control
146 // (but it is not tied to list control and so can be used with other controls
147 // such as wxListBox in wxUniv)
149 // the idea is to make it really smart later (i.e. store the selections as an
150 // array of ranes + individual items) but, as I don't have time to do it now
151 // (this would require writing code to merge/break ranges and much more) keep
152 // it simple but define a clean interface to it which allows it to be made
154 class WXDLLEXPORT wxSelectionStore
157 wxSelectionStore() : m_itemsSel(wxSizeTCmpFn
) { Init(); }
159 // set the total number of items we handle
160 void SetItemCount(size_t count
) { m_count
= count
; }
162 // special case of SetItemCount(0)
163 void Clear() { m_itemsSel
.Clear(); m_count
= 0; }
165 // must be called when a new item is inserted/added
166 void OnItemAdd(size_t item
) { wxFAIL_MSG( _T("TODO") ); }
168 // must be called when an item is deleted
169 void OnItemDelete(size_t item
);
171 // select one item, use SelectRange() insted if possible!
173 // returns true if the items selection really changed
174 bool SelectItem(size_t item
, bool select
= TRUE
);
176 // select the range of items
177 void SelectRange(size_t itemFrom
, size_t itemTo
, bool select
= TRUE
);
179 // return true if the given item is selected
180 bool IsSelected(size_t item
) const;
182 // return the total number of selected items
183 size_t GetSelectedCount() const
185 return m_defaultState
? m_count
- m_itemsSel
.GetCount()
186 : m_itemsSel
.GetCount();
191 void Init() { m_defaultState
= FALSE
; }
193 // the total number of items we handle
196 // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
197 // there are more selected items than non selected ones - this allows to
198 // handle selection of all items efficiently
201 // the array of items whose selection state is different from default
202 wxIndexArray m_itemsSel
;
204 DECLARE_NO_COPY_CLASS(wxSelectionStore
)
207 //-----------------------------------------------------------------------------
208 // wxListItemData (internal)
209 //-----------------------------------------------------------------------------
211 class WXDLLEXPORT wxListItemData
214 wxListItemData(wxListMainWindow
*owner
);
215 ~wxListItemData() { delete m_attr
; delete m_rect
; }
217 void SetItem( const wxListItem
&info
);
218 void SetImage( int image
) { m_image
= image
; }
219 void SetData( long data
) { m_data
= data
; }
220 void SetPosition( int x
, int y
);
221 void SetSize( int width
, int height
);
223 bool HasText() const { return !m_text
.empty(); }
224 const wxString
& GetText() const { return m_text
; }
225 void SetText(const wxString
& text
) { m_text
= text
; }
227 // we can't use empty string for measuring the string width/height, so
228 // always return something
229 wxString
GetTextForMeasuring() const
231 wxString s
= GetText();
238 bool IsHit( int x
, int y
) const;
242 int GetWidth() const;
243 int GetHeight() const;
245 int GetImage() const { return m_image
; }
246 bool HasImage() const { return GetImage() != -1; }
248 void GetItem( wxListItem
&info
) const;
250 void SetAttr(wxListItemAttr
*attr
) { m_attr
= attr
; }
251 wxListItemAttr
*GetAttr() const { return m_attr
; }
254 // the item image or -1
257 // user data associated with the item
260 // the item coordinates are not used in report mode, instead this pointer
261 // is NULL and the owner window is used to retrieve the item position and
265 // the list ctrl we are in
266 wxListMainWindow
*m_owner
;
268 // custom attributes or NULL
269 wxListItemAttr
*m_attr
;
272 // common part of all ctors
278 //-----------------------------------------------------------------------------
279 // wxListHeaderData (internal)
280 //-----------------------------------------------------------------------------
282 class WXDLLEXPORT wxListHeaderData
: public wxObject
296 wxListHeaderData( const wxListItem
&info
);
297 void SetItem( const wxListItem
&item
);
298 void SetPosition( int x
, int y
);
299 void SetWidth( int w
);
300 void SetFormat( int format
);
301 void SetHeight( int h
);
302 bool HasImage() const;
304 bool HasText() const { return !m_text
.empty(); }
305 const wxString
& GetText() const { return m_text
; }
306 void SetText(const wxString
& text
) { m_text
= text
; }
308 void GetItem( wxListItem
&item
);
310 bool IsHit( int x
, int y
) const;
311 int GetImage() const;
312 int GetWidth() const;
313 int GetFormat() const;
316 DECLARE_DYNAMIC_CLASS(wxListHeaderData
);
319 //-----------------------------------------------------------------------------
320 // wxListLineData (internal)
321 //-----------------------------------------------------------------------------
323 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
);
324 #include "wx/listimpl.cpp"
325 WX_DEFINE_LIST(wxListItemDataList
);
327 class WXDLLEXPORT wxListLineData
330 // the list of subitems: only may have more than one item in report mode
331 wxListItemDataList m_items
;
333 // this is not used in report view
345 // the part to be highlighted
346 wxRect m_rectHighlight
;
349 // is this item selected? [NB: not used in virtual mode]
352 // back pointer to the list ctrl
353 wxListMainWindow
*m_owner
;
356 wxListLineData(wxListMainWindow
*owner
);
358 ~wxListLineData() { delete m_gi
; }
360 // are we in report mode?
361 inline bool InReportView() const;
363 // are we in virtual report mode?
364 inline bool IsVirtual() const;
366 // these 2 methods shouldn't be called for report view controls, in that
367 // case we determine our position/size ourselves
369 // calculate the size of the line
370 void CalculateSize( wxDC
*dc
, int spacing
);
372 // remember the position this line appears at
373 void SetPosition( int x
, int y
, int window_width
, int spacing
);
377 void SetImage( int image
) { SetImage(0, image
); }
378 int GetImage() const { return GetImage(0); }
379 bool HasImage() const { return GetImage() != -1; }
380 bool HasText() const { return !GetText(0).empty(); }
382 void SetItem( int index
, const wxListItem
&info
);
383 void GetItem( int index
, wxListItem
&info
);
385 wxString
GetText(int index
) const;
386 void SetText( int index
, const wxString s
);
388 wxListItemAttr
*GetAttr() const;
389 void SetAttr(wxListItemAttr
*attr
);
391 // return true if the highlighting really changed
392 bool Highlight( bool on
);
394 void ReverseHighlight();
396 bool IsHighlighted() const
398 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
400 return m_highlighted
;
403 // draw the line on the given DC in icon/list mode
404 void Draw( wxDC
*dc
);
406 // the same in report mode
407 void DrawInReportMode( wxDC
*dc
,
409 const wxRect
& rectHL
,
413 // set the line to contain num items (only can be > 1 in report mode)
414 void InitItems( int num
);
416 // get the mode (i.e. style) of the list control
417 inline int GetMode() const;
419 void SetAttributes(wxDC
*dc
,
420 const wxListItemAttr
*attr
,
421 const wxColour
& colText
,
425 // these are only used by GetImage/SetImage above, we don't support images
426 // with subitems at the public API level yet
427 void SetImage( int index
, int image
);
428 int GetImage( int index
) const;
431 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
);
432 #include "wx/arrimpl.cpp"
433 WX_DEFINE_OBJARRAY(wxListLineDataArray
);
435 //-----------------------------------------------------------------------------
436 // wxListHeaderWindow (internal)
437 //-----------------------------------------------------------------------------
439 class WXDLLEXPORT wxListHeaderWindow
: public wxWindow
442 wxListMainWindow
*m_owner
;
443 wxCursor
*m_currentCursor
;
444 wxCursor
*m_resizeCursor
;
447 // column being resized
450 // divider line position in logical (unscrolled) coords
453 // minimal position beyond which the divider line can't be dragged in
458 wxListHeaderWindow();
459 virtual ~wxListHeaderWindow();
461 wxListHeaderWindow( wxWindow
*win
,
463 wxListMainWindow
*owner
,
464 const wxPoint
&pos
= wxDefaultPosition
,
465 const wxSize
&size
= wxDefaultSize
,
467 const wxString
&name
= "wxlistctrlcolumntitles" );
469 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
471 void AdjustDC(wxDC
& dc
);
473 void OnPaint( wxPaintEvent
&event
);
474 void OnMouse( wxMouseEvent
&event
);
475 void OnSetFocus( wxFocusEvent
&event
);
481 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
)
482 DECLARE_EVENT_TABLE()
485 //-----------------------------------------------------------------------------
486 // wxListRenameTimer (internal)
487 //-----------------------------------------------------------------------------
489 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
492 wxListMainWindow
*m_owner
;
495 wxListRenameTimer( wxListMainWindow
*owner
);
499 //-----------------------------------------------------------------------------
500 // wxListTextCtrl (internal)
501 //-----------------------------------------------------------------------------
503 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
508 wxListMainWindow
*m_owner
;
509 wxString m_startValue
;
513 wxListTextCtrl( wxWindow
*parent
, const wxWindowID id
,
514 bool *accept
, wxString
*res
, wxListMainWindow
*owner
,
515 const wxString
&value
= "",
516 const wxPoint
&pos
= wxDefaultPosition
, const wxSize
&size
= wxDefaultSize
,
518 const wxValidator
& validator
= wxDefaultValidator
,
519 const wxString
&name
= "listctrltextctrl" );
520 void OnChar( wxKeyEvent
&event
);
521 void OnKeyUp( wxKeyEvent
&event
);
522 void OnKillFocus( wxFocusEvent
&event
);
525 DECLARE_DYNAMIC_CLASS(wxListTextCtrl
);
526 DECLARE_EVENT_TABLE()
529 //-----------------------------------------------------------------------------
530 // wxListMainWindow (internal)
531 //-----------------------------------------------------------------------------
533 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
);
534 #include "wx/listimpl.cpp"
535 WX_DEFINE_LIST(wxListHeaderDataList
);
537 class WXDLLEXPORT wxListMainWindow
: public wxScrolledWindow
541 wxListMainWindow( wxWindow
*parent
,
543 const wxPoint
& pos
= wxDefaultPosition
,
544 const wxSize
& size
= wxDefaultSize
,
546 const wxString
&name
= _T("listctrlmainwindow") );
548 virtual ~wxListMainWindow();
550 bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); }
552 // return true if this is a virtual list control
553 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); }
555 // return true if the control is in report mode
556 bool InReportView() const { return HasFlag(wxLC_REPORT
); }
558 // return true if we are in single selection mode, false if multi sel
559 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); }
561 // do we have a header window?
562 bool HasHeader() const
563 { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); }
565 void HighlightAll( bool on
);
567 // all these functions only do something if the line is currently visible
569 // change the line "selected" state, return TRUE if it really changed
570 bool HighlightLine( size_t line
, bool highlight
= TRUE
);
572 // as HighlightLine() but do it for the range of lines: this is incredibly
573 // more efficient for virtual list controls!
575 // NB: unlike HighlightLine() this one does refresh the lines on screen
576 void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on
= TRUE
);
578 // toggle the line state and refresh it
579 void ReverseHighlight( size_t line
)
580 { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); }
582 // return true if the line is highlighted
583 bool IsHighlighted(size_t line
) const;
585 // refresh one or several lines at once
586 void RefreshLine( size_t line
);
587 void RefreshLines( size_t lineFrom
, size_t lineTo
);
589 // refresh all lines below the given one: the difference with
590 // RefreshLines() is that the index here might not be a valid one (happens
591 // when the last line is deleted)
592 void RefreshAfter( size_t lineFrom
);
594 // the methods which are forwarded to wxListLineData itself in list/icon
595 // modes but are here because the lines don't store their positions in the
598 // get the bound rect for the entire line
599 wxRect
GetLineRect(size_t line
) const;
601 // get the bound rect of the label
602 wxRect
GetLineLabelRect(size_t line
) const;
604 // get the bound rect of the items icon (only may be called if we do have
606 wxRect
GetLineIconRect(size_t line
) const;
608 // get the rect to be highlighted when the item has focus
609 wxRect
GetLineHighlightRect(size_t line
) const;
611 // get the size of the total line rect
612 wxSize
GetLineSize(size_t line
) const
613 { return GetLineRect(line
).GetSize(); }
615 // return the hit code for the corresponding position (in this line)
616 long HitTestLine(size_t line
, int x
, int y
) const;
618 void EditLabel( long item
);
619 void OnRenameTimer();
620 void OnRenameAccept();
622 void OnMouse( wxMouseEvent
&event
);
625 // called to switch the selection from the current item to newCurrent,
626 void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event
);
628 void OnChar( wxKeyEvent
&event
);
629 void OnKeyDown( wxKeyEvent
&event
);
630 void OnSetFocus( wxFocusEvent
&event
);
631 void OnKillFocus( wxFocusEvent
&event
);
632 void OnScroll(wxScrollWinEvent
& event
) ;
634 void OnPaint( wxPaintEvent
&event
);
636 void DrawImage( int index
, wxDC
*dc
, int x
, int y
);
637 void GetImageSize( int index
, int &width
, int &height
) const;
638 int GetTextLength( const wxString
&s
) const;
640 void SetImageList( wxImageList
*imageList
, int which
);
641 void SetItemSpacing( int spacing
, bool isSmall
= FALSE
);
642 int GetItemSpacing( bool isSmall
= FALSE
);
644 void SetColumn( int col
, wxListItem
&item
);
645 void SetColumnWidth( int col
, int width
);
646 void GetColumn( int col
, wxListItem
&item
) const;
647 int GetColumnWidth( int col
) const;
648 int GetColumnCount() const { return m_columns
.GetCount(); }
650 // returns the sum of the heights of all columns
651 int GetHeaderWidth() const;
653 int GetCountPerPage() const;
655 void SetItem( wxListItem
&item
);
656 void GetItem( wxListItem
&item
);
657 void SetItemState( long item
, long state
, long stateMask
);
658 int GetItemState( long item
, long stateMask
);
659 void GetItemRect( long index
, wxRect
&rect
);
660 bool GetItemPosition( long item
, wxPoint
& pos
);
661 int GetSelectedItemCount();
663 // set the scrollbars and update the positions of the items
664 void RecalculatePositions();
666 // refresh the window and the header
669 long GetNextItem( long item
, int geometry
, int state
);
670 void DeleteItem( long index
);
671 void DeleteAllItems();
672 void DeleteColumn( int col
);
673 void DeleteEverything();
674 void EnsureVisible( long index
);
675 long FindItem( long start
, const wxString
& str
, bool partial
= FALSE
);
676 long FindItem( long start
, long data
);
677 long HitTest( int x
, int y
, int &flags
);
678 void InsertItem( wxListItem
&item
);
679 void InsertColumn( long col
, wxListItem
&item
);
680 void SortItems( wxListCtrlCompare fn
, long data
);
682 size_t GetItemCount() const;
683 bool IsEmpty() const { return GetItemCount() == 0; }
684 void SetItemCount(long count
);
686 void ResetCurrent() { m_current
= (size_t)-1; }
687 bool HasCurrent() const { return m_current
!= (size_t)-1; }
689 // send out a wxListEvent
690 void SendNotify( size_t line
,
692 wxPoint point
= wxDefaultPosition
);
694 // override base class virtual to reset m_lineHeight when the font changes
695 virtual bool SetFont(const wxFont
& font
)
697 if ( !wxScrolledWindow::SetFont(font
) )
705 // these are for wxListLineData usage only
707 // get the backpointer to the list ctrl
708 wxListCtrl
*GetListCtrl() const
710 return wxStaticCast(GetParent(), wxListCtrl
);
713 // get the height of all lines (assuming they all do have the same height)
714 wxCoord
GetLineHeight() const;
716 // get the y position of the given line (only for report view)
717 wxCoord
GetLineY(size_t line
) const;
720 // the array of all line objects for a non virtual list control
721 wxListLineDataArray m_lines
;
723 // the list of column objects
724 wxListHeaderDataList m_columns
;
726 // currently focused item or -1
729 // the item currently being edited or -1
730 size_t m_currentEdit
;
732 // the number of lines per page
735 // this flag is set when something which should result in the window
736 // redrawing happens (i.e. an item was added or deleted, or its appearance
737 // changed) and OnPaint() doesn't redraw the window while it is set which
738 // allows to minimize the number of repaintings when a lot of items are
739 // being added. The real repainting occurs only after the next OnIdle()
743 wxBrush
*m_highlightBrush
;
744 wxColour
*m_highlightColour
;
747 wxImageList
*m_small_image_list
;
748 wxImageList
*m_normal_image_list
;
750 int m_normal_spacing
;
754 wxTimer
*m_renameTimer
;
756 wxString m_renameRes
;
761 // for double click logic
762 size_t m_lineLastClicked
,
763 m_lineBeforeLastClicked
;
766 // the total count of items in a virtual list control
769 // the object maintaining the items selection state, only used in virtual
771 wxSelectionStore m_selStore
;
773 // common part of all ctors
776 // intiialize m_[xy]Scroll
777 void InitScrolling();
779 // get the line data for the given index
780 wxListLineData
*GetLine(size_t n
) const
782 wxASSERT_MSG( n
!= (size_t)-1, _T("invalid line index") );
786 wxConstCast(this, wxListMainWindow
)->CacheLineData(n
);
794 // get a dummy line which can be used for geometry calculations and such:
795 // you must use GetLine() if you want to really draw the line
796 wxListLineData
*GetDummyLine() const;
798 // cache the line data of the n-th line in m_lines[0]
799 void CacheLineData(size_t line
);
801 // get the range of visible lines
802 void GetVisibleLinesRange(size_t *from
, size_t *to
);
804 // force us to recalculate the range of visible lines
805 void ResetVisibleLinesRange() { m_lineFrom
= (size_t)-1; }
807 // get the colour to be used for drawing the rules
808 wxColour
GetRuleColour() const
813 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
);
818 // initialize the current item if needed
819 void UpdateCurrent();
821 // called when an item is [un]focuded, i.e. becomes [not] current
824 void OnFocusLine( size_t line
);
825 void OnUnfocusLine( size_t line
);
827 // the height of one line using the current font
828 wxCoord m_lineHeight
;
830 // the total header width or 0 if not calculated yet
831 wxCoord m_headerWidth
;
833 // the first and last lines being shown on screen right now (inclusive),
834 // both may be -1 if they must be calculated so never access them directly:
835 // use GetVisibleLinesRange() above instead
839 DECLARE_DYNAMIC_CLASS(wxListMainWindow
);
840 DECLARE_EVENT_TABLE()
843 // ============================================================================
845 // ============================================================================
847 // ----------------------------------------------------------------------------
849 // ----------------------------------------------------------------------------
851 bool wxSelectionStore::IsSelected(size_t item
) const
853 bool isSel
= m_itemsSel
.Index(item
) != wxNOT_FOUND
;
855 // if the default state is to be selected, being in m_itemsSel means that
856 // the item is not selected, so we have to inverse the logic
857 return m_defaultState
? !isSel
: isSel
;
860 bool wxSelectionStore::SelectItem(size_t item
, bool select
)
862 // search for the item ourselves as like this we get the index where to
863 // insert it later if needed, so we do only one search in the array instead
864 // of two (adding item to a sorted array requires a search)
865 size_t index
= m_itemsSel
.IndexForInsert(item
);
866 bool isSel
= index
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
;
868 if ( select
!= m_defaultState
)
872 m_itemsSel
.AddAt(item
, index
);
877 else // reset to default state
881 m_itemsSel
.RemoveAt(index
);
889 void wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, bool select
)
891 wxASSERT_MSG( itemFrom
<= itemTo
, _T("should be in order") );
893 // are we going to have more [un]selected items than the other ones?
894 if ( itemTo
- itemFrom
> m_count
/ 2 )
896 if ( select
!= m_defaultState
)
898 // the default state now becomes the same as 'select'
899 m_defaultState
= select
;
901 // so all the old selections (which had state select) shouldn't be
902 // selected any more, but all the other ones should
903 wxIndexArray selOld
= m_itemsSel
;
906 // TODO: it should be possible to optimize the searches a bit
907 // knowing the possible range
910 for ( item
= 0; item
< itemFrom
; item
++ )
912 if ( selOld
.Index(item
) == wxNOT_FOUND
)
913 m_itemsSel
.Add(item
);
916 for ( item
= itemTo
+ 1; item
< m_count
; item
++ )
918 if ( selOld
.Index(item
) == wxNOT_FOUND
)
919 m_itemsSel
.Add(item
);
922 else // select == m_defaultState
924 // get the inclusive range of items between itemFrom and itemTo
925 size_t count
= m_itemsSel
.GetCount(),
926 start
= m_itemsSel
.IndexForInsert(itemFrom
),
927 end
= m_itemsSel
.IndexForInsert(itemTo
);
929 if ( start
== count
|| m_itemsSel
[start
] < itemFrom
)
934 if ( end
== count
|| m_itemsSel
[end
] > itemTo
)
941 // delete all of them (from end to avoid changing indices)
942 for ( int i
= end
; i
>= (int)start
; i
-- )
944 m_itemsSel
.RemoveAt(i
);
949 else // "few" items change state
951 // just add the items to the selection
952 for ( size_t item
= itemFrom
; item
<= itemTo
; item
++ )
954 SelectItem(item
, select
);
959 void wxSelectionStore::OnItemDelete(size_t item
)
961 size_t count
= m_itemsSel
.GetCount(),
962 i
= m_itemsSel
.IndexForInsert(item
);
964 if ( i
< count
&& m_itemsSel
[i
] == item
)
966 // this item itself was in m_itemsSel, remove it from there
967 m_itemsSel
.RemoveAt(i
);
972 // and adjust the index of all which follow it
975 // all following elements must be greater than the one we deleted
976 wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") );
982 //-----------------------------------------------------------------------------
984 //-----------------------------------------------------------------------------
986 void wxListItemData::Init()
994 wxListItemData::wxListItemData(wxListMainWindow
*owner
)
1000 if ( owner
->HasFlag(wxLC_REPORT
) )
1006 m_rect
= new wxRect
;
1010 void wxListItemData::SetItem( const wxListItem
&info
)
1012 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
1013 SetText(info
.m_text
);
1014 if ( info
.m_mask
& wxLIST_MASK_IMAGE
)
1015 m_image
= info
.m_image
;
1016 if ( info
.m_mask
& wxLIST_MASK_DATA
)
1017 m_data
= info
.m_data
;
1019 if ( info
.HasAttributes() )
1022 *m_attr
= *info
.GetAttributes();
1024 m_attr
= new wxListItemAttr(*info
.GetAttributes());
1032 m_rect
->width
= info
.m_width
;
1036 void wxListItemData::SetPosition( int x
, int y
)
1038 wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") );
1044 void wxListItemData::SetSize( int width
, int height
)
1046 wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") );
1049 m_rect
->width
= width
;
1051 m_rect
->height
= height
;
1054 bool wxListItemData::IsHit( int x
, int y
) const
1056 wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") );
1058 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
);
1061 int wxListItemData::GetX() const
1063 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1068 int wxListItemData::GetY() const
1070 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1075 int wxListItemData::GetWidth() const
1077 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1079 return m_rect
->width
;
1082 int wxListItemData::GetHeight() const
1084 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1086 return m_rect
->height
;
1089 void wxListItemData::GetItem( wxListItem
&info
) const
1091 info
.m_text
= m_text
;
1092 info
.m_image
= m_image
;
1093 info
.m_data
= m_data
;
1097 if ( m_attr
->HasTextColour() )
1098 info
.SetTextColour(m_attr
->GetTextColour());
1099 if ( m_attr
->HasBackgroundColour() )
1100 info
.SetBackgroundColour(m_attr
->GetBackgroundColour());
1101 if ( m_attr
->HasFont() )
1102 info
.SetFont(m_attr
->GetFont());
1106 //-----------------------------------------------------------------------------
1108 //-----------------------------------------------------------------------------
1110 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
);
1112 wxListHeaderData::wxListHeaderData()
1123 wxListHeaderData::wxListHeaderData( const wxListItem
&item
)
1131 void wxListHeaderData::SetItem( const wxListItem
&item
)
1133 m_mask
= item
.m_mask
;
1134 m_text
= item
.m_text
;
1135 m_image
= item
.m_image
;
1136 m_format
= item
.m_format
;
1138 SetWidth(item
.m_width
);
1141 void wxListHeaderData::SetPosition( int x
, int y
)
1147 void wxListHeaderData::SetHeight( int h
)
1152 void wxListHeaderData::SetWidth( int w
)
1156 m_width
= WIDTH_COL_DEFAULT
;
1157 if (m_width
< WIDTH_COL_MIN
)
1158 m_width
= WIDTH_COL_MIN
;
1161 void wxListHeaderData::SetFormat( int format
)
1166 bool wxListHeaderData::HasImage() const
1168 return (m_image
!= 0);
1171 bool wxListHeaderData::IsHit( int x
, int y
) const
1173 return ((x
>= m_xpos
) && (x
<= m_xpos
+m_width
) && (y
>= m_ypos
) && (y
<= m_ypos
+m_height
));
1176 void wxListHeaderData::GetItem( wxListItem
&item
)
1178 item
.m_mask
= m_mask
;
1179 item
.m_text
= m_text
;
1180 item
.m_image
= m_image
;
1181 item
.m_format
= m_format
;
1182 item
.m_width
= m_width
;
1185 int wxListHeaderData::GetImage() const
1190 int wxListHeaderData::GetWidth() const
1195 int wxListHeaderData::GetFormat() const
1200 //-----------------------------------------------------------------------------
1202 //-----------------------------------------------------------------------------
1204 inline int wxListLineData::GetMode() const
1206 return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
;
1209 inline bool wxListLineData::InReportView() const
1211 return m_owner
->HasFlag(wxLC_REPORT
);
1214 inline bool wxListLineData::IsVirtual() const
1216 return m_owner
->IsVirtual();
1219 wxListLineData::wxListLineData( wxListMainWindow
*owner
)
1222 m_items
.DeleteContents( TRUE
);
1224 if ( InReportView() )
1230 m_gi
= new GeometryInfo
;
1233 m_highlighted
= FALSE
;
1235 InitItems( GetMode() == wxLC_REPORT
? m_owner
->GetColumnCount() : 1 );
1238 void wxListLineData::CalculateSize( wxDC
*dc
, int spacing
)
1240 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1241 wxCHECK_RET( node
, _T("no subitems at all??") );
1243 wxListItemData
*item
= node
->GetData();
1245 switch ( GetMode() )
1248 case wxLC_SMALL_ICON
:
1250 m_gi
->m_rectAll
.width
= spacing
;
1252 wxString s
= item
->GetText();
1258 m_gi
->m_rectLabel
.width
=
1259 m_gi
->m_rectLabel
.height
= 0;
1263 dc
->GetTextExtent( s
, &lw
, &lh
);
1264 if (lh
< SCROLL_UNIT_Y
)
1269 m_gi
->m_rectAll
.height
= spacing
+ lh
;
1271 m_gi
->m_rectAll
.width
= lw
;
1273 m_gi
->m_rectLabel
.width
= lw
;
1274 m_gi
->m_rectLabel
.height
= lh
;
1277 if (item
->HasImage())
1280 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1281 m_gi
->m_rectIcon
.width
= w
+ 8;
1282 m_gi
->m_rectIcon
.height
= h
+ 8;
1284 if ( m_gi
->m_rectIcon
.width
> m_gi
->m_rectAll
.width
)
1285 m_gi
->m_rectAll
.width
= m_gi
->m_rectIcon
.width
;
1286 if ( m_gi
->m_rectIcon
.height
+ lh
> m_gi
->m_rectAll
.height
- 4 )
1287 m_gi
->m_rectAll
.height
= m_gi
->m_rectIcon
.height
+ lh
+ 4;
1290 if ( item
->HasText() )
1292 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectLabel
.width
;
1293 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectLabel
.height
;
1295 else // no text, highlight the icon
1297 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectIcon
.width
;
1298 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectIcon
.height
;
1305 wxString s
= item
->GetTextForMeasuring();
1308 dc
->GetTextExtent( s
, &lw
, &lh
);
1309 if (lh
< SCROLL_UNIT_Y
)
1314 m_gi
->m_rectLabel
.width
= lw
;
1315 m_gi
->m_rectLabel
.height
= lh
;
1317 m_gi
->m_rectAll
.width
= lw
;
1318 m_gi
->m_rectAll
.height
= lh
;
1320 if (item
->HasImage())
1323 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1324 m_gi
->m_rectIcon
.width
= w
;
1325 m_gi
->m_rectIcon
.height
= h
;
1327 m_gi
->m_rectAll
.width
+= 4 + w
;
1328 if (h
> m_gi
->m_rectAll
.height
)
1329 m_gi
->m_rectAll
.height
= h
;
1332 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectAll
.width
;
1333 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectAll
.height
;
1338 wxFAIL_MSG( _T("unexpected call to SetSize") );
1342 wxFAIL_MSG( _T("unknown mode") );
1346 void wxListLineData::SetPosition( int x
, int y
,
1350 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1351 wxCHECK_RET( node
, _T("no subitems at all??") );
1353 wxListItemData
*item
= node
->GetData();
1355 switch ( GetMode() )
1358 case wxLC_SMALL_ICON
:
1359 m_gi
->m_rectAll
.x
= x
;
1360 m_gi
->m_rectAll
.y
= y
;
1362 if ( item
->HasImage() )
1364 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 4
1365 + (spacing
- m_gi
->m_rectIcon
.width
)/2;
1366 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 4;
1369 if ( item
->HasText() )
1371 if (m_gi
->m_rectAll
.width
> spacing
)
1372 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1374 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2);
1375 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ m_gi
->m_rectAll
.height
+ 2 - m_gi
->m_rectLabel
.height
;
1376 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectLabel
.x
- 2;
1377 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectLabel
.y
- 2;
1379 else // no text, highlight the icon
1381 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectIcon
.x
- 4;
1382 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectIcon
.y
- 4;
1387 m_gi
->m_rectAll
.x
= x
;
1388 m_gi
->m_rectAll
.y
= y
;
1390 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectAll
.x
;
1391 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectAll
.y
;
1392 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ 2;
1394 if (item
->HasImage())
1396 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 2;
1397 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 2;
1398 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 6 + m_gi
->m_rectIcon
.width
;
1402 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1407 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1411 wxFAIL_MSG( _T("unknown mode") );
1415 void wxListLineData::InitItems( int num
)
1417 for (int i
= 0; i
< num
; i
++)
1418 m_items
.Append( new wxListItemData(m_owner
) );
1421 void wxListLineData::SetItem( int index
, const wxListItem
&info
)
1423 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1424 wxCHECK_RET( node
, _T("invalid column index in SetItem") );
1426 wxListItemData
*item
= node
->GetData();
1427 item
->SetItem( info
);
1430 void wxListLineData::GetItem( int index
, wxListItem
&info
)
1432 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1435 wxListItemData
*item
= node
->GetData();
1436 item
->GetItem( info
);
1440 wxString
wxListLineData::GetText(int index
) const
1444 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1447 wxListItemData
*item
= node
->GetData();
1448 s
= item
->GetText();
1454 void wxListLineData::SetText( int index
, const wxString s
)
1456 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1459 wxListItemData
*item
= node
->GetData();
1464 void wxListLineData::SetImage( int index
, int image
)
1466 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1467 wxCHECK_RET( node
, _T("invalid column index in SetImage()") );
1469 wxListItemData
*item
= node
->GetData();
1470 item
->SetImage(image
);
1473 int wxListLineData::GetImage( int index
) const
1475 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1476 wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") );
1478 wxListItemData
*item
= node
->GetData();
1479 return item
->GetImage();
1482 wxListItemAttr
*wxListLineData::GetAttr() const
1484 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1485 wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") );
1487 wxListItemData
*item
= node
->GetData();
1488 return item
->GetAttr();
1491 void wxListLineData::SetAttr(wxListItemAttr
*attr
)
1493 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1494 wxCHECK_RET( node
, _T("invalid column index in SetAttr()") );
1496 wxListItemData
*item
= node
->GetData();
1497 item
->SetAttr(attr
);
1500 void wxListLineData::SetAttributes(wxDC
*dc
,
1501 const wxListItemAttr
*attr
,
1502 const wxColour
& colText
,
1506 // don't use foregroud colour for drawing highlighted items - this might
1507 // make them completely invisible (and there is no way to do bit
1508 // arithmetics on wxColour, unfortunately)
1509 if ( !highlight
&& attr
&& attr
->HasTextColour() )
1511 dc
->SetTextForeground(attr
->GetTextColour());
1515 dc
->SetTextForeground(colText
);
1518 if ( attr
&& attr
->HasFont() )
1520 dc
->SetFont(attr
->GetFont());
1528 void wxListLineData::Draw( wxDC
*dc
)
1530 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1531 wxCHECK_RET( node
, _T("no subitems at all??") );
1533 wxListItemData
*item
= node
->GetData();
1534 if (item
->HasImage())
1536 wxRect rectIcon
= m_gi
->m_rectIcon
;
1537 m_owner
->DrawImage( item
->GetImage(), dc
,
1538 rectIcon
.x
, rectIcon
.y
);
1541 if (item
->HasText())
1543 wxRect rectLabel
= m_gi
->m_rectLabel
;
1544 dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y
);
1548 void wxListLineData::DrawInReportMode( wxDC
*dc
,
1550 const wxRect
& rectHL
,
1553 // use our own flag if we maintain it
1555 highlighted
= m_highlighted
;
1557 // default foreground colour
1558 wxWindow
*listctrl
= m_owner
->GetParent();
1562 colText
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT
);
1566 colText
= listctrl
->GetForegroundColour();
1570 wxFont font
= listctrl
->GetFont();
1572 // TODO: later we should support setting different attributes for
1573 // different columns - to do it, just add "col" argument to
1574 // GetAttr() and move this code into the loop below
1575 wxListItemAttr
*attr
= GetAttr();
1576 SetAttributes(dc
, attr
, colText
, font
, highlighted
);
1578 bool hasBgCol
= attr
&& attr
->HasBackgroundColour();
1579 if ( highlighted
|| hasBgCol
)
1583 dc
->SetBrush( *m_owner
->m_highlightBrush
);
1588 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
1590 dc
->SetBrush( * wxWHITE_BRUSH
);
1593 dc
->SetPen( * wxTRANSPARENT_PEN
);
1594 dc
->DrawRectangle( rectHL
);
1597 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1598 wxCHECK_RET( node
, _T("no subitems at all??") );
1601 wxCoord x
= rect
.x
+ HEADER_OFFSET_X
,
1602 y
= rect
.y
+ (LINE_SPACING
+ EXTRA_HEIGHT
) / 2;
1606 wxListItemData
*item
= node
->GetData();
1610 if ( item
->HasImage() )
1613 m_owner
->DrawImage( item
->GetImage(), dc
, x
, y
);
1614 m_owner
->GetImageSize( item
->GetImage(), ix
, iy
);
1615 x
+= ix
+ 5; // FIXME: what is "5"?
1618 int width
= m_owner
->GetColumnWidth(col
++);
1620 wxDCClipper
clipper(*dc
, x
, y
, width
, rect
.height
);
1622 if ( item
->HasText() )
1624 dc
->DrawText( item
->GetText(), x
, y
);
1629 node
= node
->GetNext();
1633 bool wxListLineData::Highlight( bool on
)
1635 wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") );
1637 if ( on
== m_highlighted
)
1645 void wxListLineData::ReverseHighlight( void )
1647 Highlight(!IsHighlighted());
1650 //-----------------------------------------------------------------------------
1651 // wxListHeaderWindow
1652 //-----------------------------------------------------------------------------
1654 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
);
1656 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
)
1657 EVT_PAINT (wxListHeaderWindow::OnPaint
)
1658 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse
)
1659 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus
)
1662 wxListHeaderWindow::wxListHeaderWindow( void )
1664 m_owner
= (wxListMainWindow
*) NULL
;
1665 m_currentCursor
= (wxCursor
*) NULL
;
1666 m_resizeCursor
= (wxCursor
*) NULL
;
1667 m_isDragging
= FALSE
;
1670 wxListHeaderWindow::wxListHeaderWindow( wxWindow
*win
, wxWindowID id
, wxListMainWindow
*owner
,
1671 const wxPoint
&pos
, const wxSize
&size
,
1672 long style
, const wxString
&name
) :
1673 wxWindow( win
, id
, pos
, size
, style
, name
)
1676 // m_currentCursor = wxSTANDARD_CURSOR;
1677 m_currentCursor
= (wxCursor
*) NULL
;
1678 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
1679 m_isDragging
= FALSE
;
1682 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE
) );
1685 wxListHeaderWindow::~wxListHeaderWindow( void )
1687 delete m_resizeCursor
;
1690 void wxListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1693 GtkStateType state
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
1694 : GTK_STATE_INSENSITIVE
;
1696 x
= dc
->XLOG2DEV( x
);
1698 gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
,
1699 state
, GTK_SHADOW_OUT
,
1700 (GdkRectangle
*) NULL
, m_wxwindow
, "button",
1701 x
-1, y
-1, w
+2, h
+2);
1702 #elif defined( __WXMAC__ )
1703 const int m_corner
= 1;
1705 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1707 dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
) , 1 , wxSOLID
) );
1708 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1709 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1711 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1714 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1715 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1717 dc
->SetPen( *wxWHITE_PEN
);
1718 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1719 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1720 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1721 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1723 const int m_corner
= 1;
1725 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1727 dc
->SetPen( *wxBLACK_PEN
);
1728 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1729 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1731 wxPen
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1734 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1735 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1737 dc
->SetPen( *wxWHITE_PEN
);
1738 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1739 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1740 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1741 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1745 // shift the DC origin to match the position of the main window horz
1746 // scrollbar: this allows us to always use logical coords
1747 void wxListHeaderWindow::AdjustDC(wxDC
& dc
)
1750 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1753 m_owner
->GetViewStart( &x
, NULL
);
1755 // account for the horz scrollbar offset
1756 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1759 void wxListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1762 wxClientDC
dc( this );
1764 wxPaintDC
dc( this );
1772 dc
.SetFont( GetFont() );
1774 // width and height of the entire header window
1776 GetClientSize( &w
, &h
);
1777 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1779 dc
.SetBackgroundMode(wxTRANSPARENT
);
1781 // do *not* use the listctrl colour for headers - one day we will have a
1782 // function to set it separately
1783 //dc.SetTextForeground( *wxBLACK );
1784 dc
.SetTextForeground(wxSystemSettings::
1785 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1787 int x
= HEADER_OFFSET_X
;
1789 int numColumns
= m_owner
->GetColumnCount();
1791 for (int i
= 0; i
< numColumns
; i
++)
1793 m_owner
->GetColumn( i
, item
);
1794 int wCol
= item
.m_width
;
1795 int cw
= wCol
- 2; // the width of the rect to draw
1797 int xEnd
= x
+ wCol
;
1799 dc
.SetPen( *wxWHITE_PEN
);
1801 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1802 dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 );
1803 dc
.DrawText( item
.GetText(), x
+ EXTRA_WIDTH
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1804 dc
.DestroyClippingRegion();
1813 void wxListHeaderWindow::DrawCurrent()
1815 int x1
= m_currentX
;
1817 ClientToScreen( &x1
, &y1
);
1819 int x2
= m_currentX
-1;
1821 m_owner
->GetClientSize( NULL
, &y2
);
1822 m_owner
->ClientToScreen( &x2
, &y2
);
1825 dc
.SetLogicalFunction( wxINVERT
);
1826 dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID
) );
1827 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1831 dc
.DrawLine( x1
, y1
, x2
, y2
);
1833 dc
.SetLogicalFunction( wxCOPY
);
1835 dc
.SetPen( wxNullPen
);
1836 dc
.SetBrush( wxNullBrush
);
1839 void wxListHeaderWindow::OnMouse( wxMouseEvent
&event
)
1841 // we want to work with logical coords
1843 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1844 int y
= event
.GetY();
1848 // we don't draw the line beyond our window, but we allow dragging it
1851 GetClientSize( &w
, NULL
);
1852 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1855 // erase the line if it was drawn
1856 if ( m_currentX
< w
)
1859 if (event
.ButtonUp())
1862 m_isDragging
= FALSE
;
1864 m_owner
->SetColumnWidth( m_column
, m_currentX
- m_minX
);
1871 m_currentX
= m_minX
+ 7;
1873 // draw in the new location
1874 if ( m_currentX
< w
)
1878 else // not dragging
1881 bool hit_border
= FALSE
;
1883 // end of the current column
1886 // find the column where this event occured
1887 int countCol
= m_owner
->GetColumnCount();
1888 for (int col
= 0; col
< countCol
; col
++)
1890 xpos
+= m_owner
->GetColumnWidth( col
);
1893 if ( (abs(x
-xpos
) < 3) && (y
< 22) )
1895 // near the column border
1902 // inside the column
1909 if (event
.LeftDown())
1913 m_isDragging
= TRUE
;
1920 wxWindow
*parent
= GetParent();
1921 wxListEvent
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() );
1922 le
.SetEventObject( parent
);
1923 le
.m_col
= m_column
;
1924 parent
->GetEventHandler()->ProcessEvent( le
);
1927 else if (event
.Moving())
1932 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1933 m_currentCursor
= m_resizeCursor
;
1937 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1938 m_currentCursor
= wxSTANDARD_CURSOR
;
1942 SetCursor(*m_currentCursor
);
1947 void wxListHeaderWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
1949 m_owner
->SetFocus();
1952 //-----------------------------------------------------------------------------
1953 // wxListRenameTimer (internal)
1954 //-----------------------------------------------------------------------------
1956 wxListRenameTimer::wxListRenameTimer( wxListMainWindow
*owner
)
1961 void wxListRenameTimer::Notify()
1963 m_owner
->OnRenameTimer();
1966 //-----------------------------------------------------------------------------
1967 // wxListTextCtrl (internal)
1968 //-----------------------------------------------------------------------------
1970 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
);
1972 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
)
1973 EVT_CHAR (wxListTextCtrl::OnChar
)
1974 EVT_KEY_UP (wxListTextCtrl::OnKeyUp
)
1975 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus
)
1978 wxListTextCtrl::wxListTextCtrl( wxWindow
*parent
,
1979 const wxWindowID id
,
1982 wxListMainWindow
*owner
,
1983 const wxString
&value
,
1987 const wxValidator
& validator
,
1988 const wxString
&name
)
1989 : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name
)
1994 (*m_accept
) = FALSE
;
1996 m_startValue
= value
;
1999 void wxListTextCtrl::OnChar( wxKeyEvent
&event
)
2001 if (event
.m_keyCode
== WXK_RETURN
)
2004 (*m_res
) = GetValue();
2006 if (!wxPendingDelete
.Member(this))
2007 wxPendingDelete
.Append(this);
2009 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2010 m_owner
->OnRenameAccept();
2014 if (event
.m_keyCode
== WXK_ESCAPE
)
2016 (*m_accept
) = FALSE
;
2019 if (!wxPendingDelete
.Member(this))
2020 wxPendingDelete
.Append(this);
2028 void wxListTextCtrl::OnKeyUp( wxKeyEvent
&event
)
2030 // auto-grow the textctrl:
2031 wxSize parentSize
= m_owner
->GetSize();
2032 wxPoint myPos
= GetPosition();
2033 wxSize mySize
= GetSize();
2035 GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM??
2036 if (myPos
.x
+ sx
> parentSize
.x
)
2037 sx
= parentSize
.x
- myPos
.x
;
2045 void wxListTextCtrl::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
2047 if (!wxPendingDelete
.Member(this))
2048 wxPendingDelete
.Append(this);
2050 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2051 m_owner
->OnRenameAccept();
2054 //-----------------------------------------------------------------------------
2056 //-----------------------------------------------------------------------------
2058 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
);
2060 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
)
2061 EVT_PAINT (wxListMainWindow::OnPaint
)
2062 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse
)
2063 EVT_CHAR (wxListMainWindow::OnChar
)
2064 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown
)
2065 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus
)
2066 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus
)
2067 EVT_SCROLLWIN (wxListMainWindow::OnScroll
)
2070 void wxListMainWindow::Init()
2072 m_columns
.DeleteContents( TRUE
);
2076 m_lineTo
= (size_t)-1;
2082 m_small_image_list
= (wxImageList
*) NULL
;
2083 m_normal_image_list
= (wxImageList
*) NULL
;
2085 m_small_spacing
= 30;
2086 m_normal_spacing
= 40;
2090 m_isCreated
= FALSE
;
2092 m_lastOnSame
= FALSE
;
2093 m_renameTimer
= new wxListRenameTimer( this );
2094 m_renameAccept
= FALSE
;
2099 m_lineBeforeLastClicked
= (size_t)-1;
2102 void wxListMainWindow::InitScrolling()
2104 if ( HasFlag(wxLC_REPORT
) )
2106 m_xScroll
= SCROLL_UNIT_X
;
2107 m_yScroll
= SCROLL_UNIT_Y
;
2111 m_xScroll
= SCROLL_UNIT_Y
;
2116 wxListMainWindow::wxListMainWindow()
2120 m_highlightBrush
= (wxBrush
*) NULL
;
2126 wxListMainWindow::wxListMainWindow( wxWindow
*parent
,
2131 const wxString
&name
)
2132 : wxScrolledWindow( parent
, id
, pos
, size
,
2133 style
| wxHSCROLL
| wxVSCROLL
, name
)
2137 m_highlightBrush
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
2142 SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 );
2144 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX
) );
2147 wxListMainWindow::~wxListMainWindow()
2151 delete m_highlightBrush
;
2153 delete m_renameTimer
;
2156 void wxListMainWindow::CacheLineData(size_t line
)
2158 wxListCtrl
*listctrl
= GetListCtrl();
2160 wxListLineData
*ld
= GetDummyLine();
2162 size_t countCol
= GetColumnCount();
2163 for ( size_t col
= 0; col
< countCol
; col
++ )
2165 ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
));
2168 ld
->SetImage(listctrl
->OnGetItemImage(line
));
2169 ld
->SetAttr(listctrl
->OnGetItemAttr(line
));
2172 wxListLineData
*wxListMainWindow::GetDummyLine() const
2174 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2176 if ( m_lines
.IsEmpty() )
2178 // normal controls are supposed to have something in m_lines
2179 // already if it's not empty
2180 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2182 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2183 wxListLineData
*line
= new wxListLineData(self
);
2184 self
->m_lines
.Add(line
);
2190 // ----------------------------------------------------------------------------
2191 // line geometry (report mode only)
2192 // ----------------------------------------------------------------------------
2194 wxCoord
wxListMainWindow::GetLineHeight() const
2196 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2198 // we cache the line height as calling GetTextExtent() is slow
2199 if ( !m_lineHeight
)
2201 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2203 wxClientDC
dc( self
);
2204 dc
.SetFont( GetFont() );
2207 dc
.GetTextExtent(_T("H"), NULL
, &y
);
2209 if ( y
< SCROLL_UNIT_Y
)
2213 self
->m_lineHeight
= y
+ LINE_SPACING
;
2216 return m_lineHeight
;
2219 wxCoord
wxListMainWindow::GetLineY(size_t line
) const
2221 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2223 return LINE_SPACING
+ line
*GetLineHeight();
2226 wxRect
wxListMainWindow::GetLineRect(size_t line
) const
2228 if ( !InReportView() )
2229 return GetLine(line
)->m_gi
->m_rectAll
;
2232 rect
.x
= HEADER_OFFSET_X
;
2233 rect
.y
= GetLineY(line
);
2234 rect
.width
= GetHeaderWidth();
2235 rect
.height
= GetLineHeight();
2240 wxRect
wxListMainWindow::GetLineLabelRect(size_t line
) const
2242 if ( !InReportView() )
2243 return GetLine(line
)->m_gi
->m_rectLabel
;
2246 rect
.x
= HEADER_OFFSET_X
;
2247 rect
.y
= GetLineY(line
);
2248 rect
.width
= GetColumnWidth(0);
2249 rect
.height
= GetLineHeight();
2254 wxRect
wxListMainWindow::GetLineIconRect(size_t line
) const
2256 if ( !InReportView() )
2257 return GetLine(line
)->m_gi
->m_rectIcon
;
2259 wxListLineData
*ld
= GetLine(line
);
2260 wxASSERT_MSG( ld
->HasImage(), _T("should have an image") );
2263 rect
.x
= HEADER_OFFSET_X
;
2264 rect
.y
= GetLineY(line
);
2265 GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
);
2270 wxRect
wxListMainWindow::GetLineHighlightRect(size_t line
) const
2272 return InReportView() ? GetLineRect(line
)
2273 : GetLine(line
)->m_gi
->m_rectHighlight
;
2276 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const
2278 wxListLineData
*ld
= GetLine(line
);
2280 if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) )
2281 return wxLIST_HITTEST_ONITEMICON
;
2283 if ( ld
->HasText() )
2285 wxRect rect
= InReportView() ? GetLineRect(line
)
2286 : GetLineLabelRect(line
);
2288 if ( rect
.Inside(x
, y
) )
2289 return wxLIST_HITTEST_ONITEMLABEL
;
2295 // ----------------------------------------------------------------------------
2296 // highlight (selection) handling
2297 // ----------------------------------------------------------------------------
2299 bool wxListMainWindow::IsHighlighted(size_t line
) const
2303 return m_selStore
.IsSelected(line
);
2307 wxListLineData
*ld
= GetLine(line
);
2308 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2310 return ld
->IsHighlighted();
2314 void wxListMainWindow::HighlightLines( size_t lineFrom
, size_t lineTo
, bool highlight
)
2318 m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
);
2319 RefreshLines(lineFrom
, lineTo
);
2323 // do it the dumb way
2324 bool needsRefresh
= FALSE
;
2325 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2327 if ( HighlightLine(line
, highlight
) )
2328 needsRefresh
= TRUE
;
2332 RefreshLines(lineFrom
, lineTo
);
2336 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight
)
2342 changed
= m_selStore
.SelectItem(line
, highlight
);
2346 wxListLineData
*ld
= GetLine(line
);
2347 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2349 changed
= ld
->Highlight(highlight
);
2354 SendNotify( line
, highlight
? wxEVT_COMMAND_LIST_ITEM_SELECTED
2355 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
);
2361 void wxListMainWindow::RefreshLine( size_t line
)
2363 wxRect rect
= GetLineRect(line
);
2365 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2366 RefreshRect( rect
);
2369 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo
)
2371 // we suppose that they are ordered by caller
2372 wxASSERT_MSG( lineFrom
<= lineTo
, _T("indices in disorder") );
2374 wxASSERT_MSG( lineTo
< GetItemCount(), _T("invalid line range") );
2376 if ( HasFlag(wxLC_REPORT
) )
2378 size_t visibleFrom
, visibleTo
;
2379 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2381 if ( lineFrom
< visibleFrom
)
2382 lineFrom
= visibleFrom
;
2383 if ( lineTo
> visibleTo
)
2388 rect
.y
= GetLineY(lineFrom
);
2389 rect
.width
= GetClientSize().x
;
2390 rect
.height
= GetLineY(lineTo
) - rect
.y
;
2392 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2393 RefreshRect( rect
);
2397 // TODO: this should be optimized...
2398 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2405 void wxListMainWindow::RefreshAfter( size_t lineFrom
)
2407 if ( HasFlag(wxLC_REPORT
) )
2410 GetVisibleLinesRange(&visibleFrom
, NULL
);
2412 if ( lineFrom
< visibleFrom
)
2413 lineFrom
= visibleFrom
;
2417 rect
.y
= GetLineY(lineFrom
);
2419 wxSize size
= GetClientSize();
2420 rect
.width
= size
.x
;
2421 // refresh till the bottom of the window
2422 rect
.height
= size
.y
- rect
.y
;
2424 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2425 RefreshRect( rect
);
2429 // TODO: how to do it more efficiently?
2434 void wxListMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2436 // Note: a wxPaintDC must be constructed even if no drawing is
2437 // done (a Windows requirement).
2438 wxPaintDC
dc( this );
2442 // empty control. nothing to draw
2448 // delay the repainting until we calculate all the items positions
2455 CalcScrolledPosition( 0, 0, &dev_x
, &dev_y
);
2459 dc
.SetFont( GetFont() );
2461 if ( HasFlag(wxLC_REPORT
) )
2463 int lineHeight
= GetLineHeight();
2465 size_t visibleFrom
, visibleTo
;
2466 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2469 wxCoord xOrig
, yOrig
;
2470 CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
);
2472 for ( size_t line
= visibleFrom
; line
<= visibleTo
; line
++ )
2474 rectLine
= GetLineRect(line
);
2476 if ( !IsExposed(rectLine
.x
- xOrig
, rectLine
.y
- yOrig
,
2477 rectLine
.width
, rectLine
.height
) )
2479 // don't redraw unaffected lines to avoid flicker
2483 printf("Redrawing line %u\n", line
);
2485 GetLine(line
)->DrawInReportMode( &dc
,
2487 GetLineHighlightRect(line
),
2488 IsHighlighted(line
) );
2491 if ( HasFlag(wxLC_HRULES
) )
2493 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2494 wxSize clientSize
= GetClientSize();
2496 for ( size_t i
= visibleFrom
; i
<= visibleTo
; i
++ )
2499 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2500 dc
.DrawLine(0 - dev_x
, i
*lineHeight
,
2501 clientSize
.x
- dev_x
, i
*lineHeight
);
2504 // Draw last horizontal rule
2505 if ( visibleTo
> visibleFrom
)
2508 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2509 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
,
2510 clientSize
.x
- dev_x
, m_lineTo
*lineHeight
);
2514 // Draw vertical rules if required
2515 if ( HasFlag(wxLC_VRULES
) && !IsEmpty() )
2517 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2520 wxRect firstItemRect
;
2521 wxRect lastItemRect
;
2522 GetItemRect(0, firstItemRect
);
2523 GetItemRect(GetItemCount() - 1, lastItemRect
);
2524 int x
= firstItemRect
.GetX();
2526 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2527 for (col
= 0; col
< GetColumnCount(); col
++)
2529 int colWidth
= GetColumnWidth(col
);
2531 dc
.DrawLine(x
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
,
2532 x
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
);
2538 size_t count
= GetItemCount();
2539 for ( size_t i
= 0; i
< count
; i
++ )
2541 GetLine(i
)->Draw( &dc
);
2545 if ( HasCurrent() && m_hasFocus
)
2548 // no rect outline, we already have the background color
2550 dc
.SetPen( *wxBLACK_PEN
);
2551 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2552 dc
.DrawRectangle( GetLineHighlightRect(m_current
) );
2559 void wxListMainWindow::HighlightAll( bool on
)
2561 if ( IsSingleSel() )
2563 wxASSERT_MSG( !on
, _T("can't do this in a single sel control") );
2565 // we just have one item to turn off
2566 if ( HasCurrent() && IsHighlighted(m_current
) )
2568 HighlightLine(m_current
, FALSE
);
2569 RefreshLine(m_current
);
2574 HighlightLines(0, GetItemCount() - 1, on
);
2578 void wxListMainWindow::SendNotify( size_t line
,
2579 wxEventType command
,
2582 wxListEvent
le( command
, GetParent()->GetId() );
2583 le
.SetEventObject( GetParent() );
2584 le
.m_itemIndex
= line
;
2586 // set only for events which have position
2587 if ( point
!= wxDefaultPosition
)
2588 le
.m_pointDrag
= point
;
2590 GetLine(line
)->GetItem( 0, le
.m_item
);
2591 GetParent()->GetEventHandler()->ProcessEvent( le
);
2594 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) )
2596 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
2599 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) )
2601 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
2604 void wxListMainWindow::EditLabel( long item
)
2606 wxCHECK_RET( (item
>= 0) && ((size_t)item
< GetItemCount()),
2607 wxT("wrong index in wxListCtrl::EditLabel()") );
2609 m_currentEdit
= (size_t)item
;
2611 wxListEvent
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() );
2612 le
.SetEventObject( GetParent() );
2613 le
.m_itemIndex
= item
;
2614 wxListLineData
*data
= GetLine(m_currentEdit
);
2615 wxCHECK_RET( data
, _T("invalid index in EditLabel()") );
2616 data
->GetItem( 0, le
.m_item
);
2617 GetParent()->GetEventHandler()->ProcessEvent( le
);
2619 if (!le
.IsAllowed())
2622 // We have to call this here because the label in question might just have
2623 // been added and no screen update taken place.
2627 wxClientDC
dc(this);
2630 wxString s
= data
->GetText(0);
2631 wxRect rectLabel
= GetLineLabelRect(m_currentEdit
);
2633 rectLabel
.x
= dc
.LogicalToDeviceX( rectLabel
.x
);
2634 rectLabel
.y
= dc
.LogicalToDeviceY( rectLabel
.y
);
2636 wxListTextCtrl
*text
= new wxListTextCtrl
2643 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4),
2644 wxSize(rectLabel
.width
+11,rectLabel
.height
+8)
2649 void wxListMainWindow::OnRenameTimer()
2651 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2653 EditLabel( m_current
);
2656 void wxListMainWindow::OnRenameAccept()
2658 wxListEvent
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() );
2659 le
.SetEventObject( GetParent() );
2660 le
.m_itemIndex
= m_currentEdit
;
2662 wxListLineData
*data
= GetLine(m_currentEdit
);
2663 wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") );
2665 data
->GetItem( 0, le
.m_item
);
2666 le
.m_item
.m_text
= m_renameRes
;
2667 GetParent()->GetEventHandler()->ProcessEvent( le
);
2669 if (!le
.IsAllowed()) return;
2672 info
.m_mask
= wxLIST_MASK_TEXT
;
2673 info
.m_itemId
= le
.m_itemIndex
;
2674 info
.m_text
= m_renameRes
;
2675 info
.SetTextColour(le
.m_item
.GetTextColour());
2679 void wxListMainWindow::OnMouse( wxMouseEvent
&event
)
2681 event
.SetEventObject( GetParent() );
2682 if ( GetParent()->GetEventHandler()->ProcessEvent( event
) )
2685 if ( !HasCurrent() || IsEmpty() )
2691 if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() ||
2692 event
.ButtonDClick()) )
2695 int x
= event
.GetX();
2696 int y
= event
.GetY();
2697 CalcUnscrolledPosition( x
, y
, &x
, &y
);
2699 // where did we hit it (if we did)?
2702 size_t count
= GetItemCount(),
2705 if ( HasFlag(wxLC_REPORT
) )
2707 current
= y
/ GetLineHeight();
2708 if ( current
< count
)
2709 hitResult
= HitTestLine(current
, x
, y
);
2713 // TODO: optimize it too! this is less simple than for report view but
2714 // enumerating all items is still not a way to do it!!
2715 for ( current
= 0; current
< count
; current
++ )
2717 hitResult
= HitTestLine(current
, x
, y
);
2723 if (event
.Dragging())
2725 if (m_dragCount
== 0)
2726 m_dragStart
= wxPoint(x
,y
);
2730 if (m_dragCount
!= 3)
2733 int command
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2734 : wxEVT_COMMAND_LIST_BEGIN_DRAG
;
2736 wxListEvent
le( command
, GetParent()->GetId() );
2737 le
.SetEventObject( GetParent() );
2738 le
.m_pointDrag
= m_dragStart
;
2739 GetParent()->GetEventHandler()->ProcessEvent( le
);
2750 // outside of any item
2754 bool forceClick
= FALSE
;
2755 if (event
.ButtonDClick())
2757 m_renameTimer
->Stop();
2758 m_lastOnSame
= FALSE
;
2760 if ( current
== m_lineBeforeLastClicked
)
2762 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED
);
2768 // the first click was on another item, so don't interpret this as
2769 // a double click, but as a simple click instead
2774 if (event
.LeftUp() && m_lastOnSame
)
2776 if ((current
== m_current
) &&
2777 (hitResult
== wxLIST_HITTEST_ONITEMLABEL
) &&
2778 HasFlag(wxLC_EDIT_LABELS
) )
2780 m_renameTimer
->Start( 100, TRUE
);
2782 m_lastOnSame
= FALSE
;
2784 else if (event
.RightDown())
2786 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
,
2787 event
.GetPosition() );
2789 else if (event
.MiddleDown())
2791 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
);
2793 else if ( event
.LeftDown() || forceClick
)
2795 m_lineBeforeLastClicked
= m_lineLastClicked
;
2796 m_lineLastClicked
= current
;
2798 size_t oldCurrent
= m_current
;
2800 if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) )
2802 HighlightAll( FALSE
);
2803 m_current
= current
;
2805 ReverseHighlight(m_current
);
2807 else // multi sel & either ctrl or shift is down
2809 if (event
.ControlDown())
2811 m_current
= current
;
2813 ReverseHighlight(m_current
);
2815 else if (event
.ShiftDown())
2817 m_current
= current
;
2819 size_t lineFrom
= oldCurrent
,
2822 if ( lineTo
< lineFrom
)
2825 lineFrom
= m_current
;
2828 HighlightLines(lineFrom
, lineTo
);
2830 else // !ctrl, !shift
2832 // test in the enclosing if should make it impossible
2833 wxFAIL_MSG( _T("how did we get here?") );
2837 if (m_current
!= oldCurrent
)
2839 RefreshLine( oldCurrent
);
2840 OnUnfocusLine( oldCurrent
);
2841 OnFocusLine( m_current
);
2844 // forceClick is only set if the previous click was on another item
2845 m_lastOnSame
= !forceClick
&& (m_current
== oldCurrent
);
2849 void wxListMainWindow::MoveToFocus()
2851 if ( !HasCurrent() )
2854 wxRect rect
= GetLineRect(m_current
);
2856 int client_w
, client_h
;
2857 GetClientSize( &client_w
, &client_h
);
2859 int view_x
= m_xScroll
*GetScrollPos( wxHORIZONTAL
);
2860 int view_y
= m_yScroll
*GetScrollPos( wxVERTICAL
);
2862 if ( HasFlag(wxLC_REPORT
) )
2864 // the next we need the range of lines shown it might be different, so
2866 ResetVisibleLinesRange();
2868 if (rect
.y
< view_y
)
2869 Scroll( -1, rect
.y
/m_yScroll
);
2870 if (rect
.y
+rect
.height
+5 > view_y
+client_h
)
2871 Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll
);
2875 if (rect
.x
-view_x
< 5)
2876 Scroll( (rect
.x
-5)/m_xScroll
, -1 );
2877 if (rect
.x
+rect
.width
-5 > view_x
+client_w
)
2878 Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 );
2882 // ----------------------------------------------------------------------------
2883 // keyboard handling
2884 // ----------------------------------------------------------------------------
2886 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
2888 wxCHECK_RET( newCurrent
< (size_t)GetItemCount(),
2889 _T("invalid item index in OnArrowChar()") );
2891 size_t oldCurrent
= m_current
;
2893 // in single selection we just ignore Shift as we can't select several
2895 if ( event
.ShiftDown() && !IsSingleSel() )
2897 m_current
= newCurrent
;
2899 // select all the items between the old and the new one
2900 if ( oldCurrent
> newCurrent
)
2902 newCurrent
= oldCurrent
;
2903 oldCurrent
= m_current
;
2906 HighlightLines(oldCurrent
, newCurrent
);
2910 // all previously selected items are unselected unless ctrl is held
2911 if ( !event
.ControlDown() )
2912 HighlightAll(FALSE
);
2914 m_current
= newCurrent
;
2916 HighlightLine( oldCurrent
, FALSE
);
2917 RefreshLine( oldCurrent
);
2919 if ( !event
.ControlDown() )
2921 HighlightLine( m_current
, TRUE
);
2925 OnUnfocusLine( oldCurrent
);
2926 OnFocusLine( m_current
);
2927 RefreshLine( m_current
);
2932 void wxListMainWindow::OnKeyDown( wxKeyEvent
&event
)
2934 wxWindow
*parent
= GetParent();
2936 /* we propagate the key event up */
2937 wxKeyEvent
ke( wxEVT_KEY_DOWN
);
2938 ke
.m_shiftDown
= event
.m_shiftDown
;
2939 ke
.m_controlDown
= event
.m_controlDown
;
2940 ke
.m_altDown
= event
.m_altDown
;
2941 ke
.m_metaDown
= event
.m_metaDown
;
2942 ke
.m_keyCode
= event
.m_keyCode
;
2945 ke
.SetEventObject( parent
);
2946 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2951 void wxListMainWindow::OnChar( wxKeyEvent
&event
)
2953 wxWindow
*parent
= GetParent();
2955 /* we send a list_key event up */
2958 wxListEvent
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() );
2959 le
.m_itemIndex
= m_current
;
2960 GetLine(m_current
)->GetItem( 0, le
.m_item
);
2961 le
.m_code
= (int)event
.KeyCode();
2962 le
.SetEventObject( parent
);
2963 parent
->GetEventHandler()->ProcessEvent( le
);
2966 /* we propagate the char event up */
2967 wxKeyEvent
ke( wxEVT_CHAR
);
2968 ke
.m_shiftDown
= event
.m_shiftDown
;
2969 ke
.m_controlDown
= event
.m_controlDown
;
2970 ke
.m_altDown
= event
.m_altDown
;
2971 ke
.m_metaDown
= event
.m_metaDown
;
2972 ke
.m_keyCode
= event
.m_keyCode
;
2975 ke
.SetEventObject( parent
);
2976 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2978 if (event
.KeyCode() == WXK_TAB
)
2980 wxNavigationKeyEvent nevent
;
2981 nevent
.SetWindowChange( event
.ControlDown() );
2982 nevent
.SetDirection( !event
.ShiftDown() );
2983 nevent
.SetEventObject( GetParent()->GetParent() );
2984 nevent
.SetCurrentFocus( m_parent
);
2985 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
)) return;
2988 /* no item -> nothing to do */
2995 switch (event
.KeyCode())
2998 if ( m_current
> 0 )
2999 OnArrowChar( m_current
- 1, event
);
3003 if ( m_current
< (size_t)GetItemCount() - 1 )
3004 OnArrowChar( m_current
+ 1, event
);
3009 OnArrowChar( GetItemCount() - 1, event
);
3014 OnArrowChar( 0, event
);
3020 if ( HasFlag(wxLC_REPORT
) )
3022 steps
= m_linesPerPage
- 1;
3026 steps
= m_current
% m_linesPerPage
;
3029 int index
= m_current
- steps
;
3033 OnArrowChar( index
, event
);
3040 if ( HasFlag(wxLC_REPORT
) )
3042 steps
= m_linesPerPage
- 1;
3046 steps
= m_linesPerPage
- (m_current
% m_linesPerPage
) - 1;
3049 size_t index
= m_current
+ steps
;
3050 size_t count
= GetItemCount();
3051 if ( index
>= count
)
3054 OnArrowChar( index
, event
);
3059 if ( !HasFlag(wxLC_REPORT
) )
3061 int index
= m_current
- m_linesPerPage
;
3065 OnArrowChar( index
, event
);
3070 if ( !HasFlag(wxLC_REPORT
) )
3072 size_t index
= m_current
+ m_linesPerPage
;
3074 size_t count
= GetItemCount();
3075 if ( index
>= count
)
3078 OnArrowChar( index
, event
);
3083 if ( IsSingleSel() )
3085 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3086 GetParent()->GetId() );
3087 le
.SetEventObject( GetParent() );
3088 le
.m_itemIndex
= m_current
;
3089 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3090 GetParent()->GetEventHandler()->ProcessEvent( le
);
3094 ReverseHighlight(m_current
);
3101 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3102 GetParent()->GetId() );
3103 le
.SetEventObject( GetParent() );
3104 le
.m_itemIndex
= m_current
;
3105 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3106 GetParent()->GetEventHandler()->ProcessEvent( le
);
3115 // ----------------------------------------------------------------------------
3117 // ----------------------------------------------------------------------------
3120 extern wxWindow
*g_focusWindow
;
3123 void wxListMainWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
3128 RefreshLine( m_current
);
3134 g_focusWindow
= GetParent();
3137 wxFocusEvent
event( wxEVT_SET_FOCUS
, GetParent()->GetId() );
3138 event
.SetEventObject( GetParent() );
3139 GetParent()->GetEventHandler()->ProcessEvent( event
);
3142 void wxListMainWindow::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
3147 RefreshLine( m_current
);
3150 void wxListMainWindow::DrawImage( int index
, wxDC
*dc
, int x
, int y
)
3152 if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
))
3154 m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3156 else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
))
3158 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3160 else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
))
3162 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3164 else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
))
3166 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3170 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height
) const
3172 if ( HasFlag(wxLC_ICON
) && m_normal_image_list
)
3174 m_normal_image_list
->GetSize( index
, width
, height
);
3176 else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list
)
3178 m_small_image_list
->GetSize( index
, width
, height
);
3180 else if ( HasFlag(wxLC_LIST
) && m_small_image_list
)
3182 m_small_image_list
->GetSize( index
, width
, height
);
3184 else if ( HasFlag(wxLC_REPORT
) && m_small_image_list
)
3186 m_small_image_list
->GetSize( index
, width
, height
);
3195 int wxListMainWindow::GetTextLength( const wxString
&s
) const
3197 wxClientDC
dc( wxConstCast(this, wxListMainWindow
) );
3198 dc
.SetFont( GetFont() );
3201 dc
.GetTextExtent( s
, &lw
, NULL
);
3203 return lw
+ AUTOSIZE_COL_MARGIN
;
3206 void wxListMainWindow::SetImageList( wxImageList
*imageList
, int which
)
3210 // calc the spacing from the icon size
3213 if ((imageList
) && (imageList
->GetImageCount()) )
3215 imageList
->GetSize(0, width
, height
);
3218 if (which
== wxIMAGE_LIST_NORMAL
)
3220 m_normal_image_list
= imageList
;
3221 m_normal_spacing
= width
+ 8;
3224 if (which
== wxIMAGE_LIST_SMALL
)
3226 m_small_image_list
= imageList
;
3227 m_small_spacing
= width
+ 14;
3231 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall
)
3236 m_small_spacing
= spacing
;
3240 m_normal_spacing
= spacing
;
3244 int wxListMainWindow::GetItemSpacing( bool isSmall
)
3246 return isSmall
? m_small_spacing
: m_normal_spacing
;
3249 // ----------------------------------------------------------------------------
3251 // ----------------------------------------------------------------------------
3253 void wxListMainWindow::SetColumn( int col
, wxListItem
&item
)
3255 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3257 wxCHECK_RET( node
, _T("invalid column index in SetColumn") );
3259 if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3260 item
.m_width
= GetTextLength( item
.m_text
);
3262 wxListHeaderData
*column
= node
->GetData();
3263 column
->SetItem( item
);
3265 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3267 headerWin
->m_dirty
= TRUE
;
3271 // invalidate it as it has to be recalculated
3275 void wxListMainWindow::SetColumnWidth( int col
, int width
)
3277 wxCHECK_RET( col
>= 0 && col
< GetColumnCount(),
3278 _T("invalid column index") );
3280 wxCHECK_RET( HasFlag(wxLC_REPORT
),
3281 _T("SetColumnWidth() can only be called in report mode.") );
3285 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3286 wxCHECK_RET( node
, _T("no column?") );
3288 wxListHeaderData
*column
= node
->GetData();
3290 size_t count
= GetItemCount();
3292 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
3294 width
= GetTextLength(column
->GetText());
3296 else if ( width
== wxLIST_AUTOSIZE
)
3300 // TODO: determine the max width somehow...
3301 width
= WIDTH_COL_DEFAULT
;
3305 wxClientDC
dc(this);
3306 dc
.SetFont( GetFont() );
3308 int max
= AUTOSIZE_COL_MARGIN
;
3310 for ( size_t i
= 0; i
< count
; i
++ )
3312 wxListLineData
*line
= GetLine(i
);
3313 wxListItemDataList::Node
*n
= line
->m_items
.Item( col
);
3315 wxCHECK_RET( n
, _T("no subitem?") );
3317 wxListItemData
*item
= n
->GetData();
3320 if (item
->HasImage())
3323 GetImageSize( item
->GetImage(), ix
, iy
);
3327 if (item
->HasText())
3330 dc
.GetTextExtent( item
->GetText(), &w
, NULL
);
3338 width
= max
+ AUTOSIZE_COL_MARGIN
;
3342 column
->SetWidth( width
);
3344 // invalidate it as it has to be recalculated
3348 int wxListMainWindow::GetHeaderWidth() const
3350 if ( !m_headerWidth
)
3352 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
3354 size_t count
= GetColumnCount();
3355 for ( size_t col
= 0; col
< count
; col
++ )
3357 self
->m_headerWidth
+= GetColumnWidth(col
);
3361 return m_headerWidth
;
3364 void wxListMainWindow::GetColumn( int col
, wxListItem
&item
) const
3366 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3367 wxCHECK_RET( node
, _T("invalid column index in GetColumn") );
3369 wxListHeaderData
*column
= node
->GetData();
3370 column
->GetItem( item
);
3373 int wxListMainWindow::GetColumnWidth( int col
) const
3375 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3376 wxCHECK_MSG( node
, 0, _T("invalid column index") );
3378 wxListHeaderData
*column
= node
->GetData();
3379 return column
->GetWidth();
3382 // ----------------------------------------------------------------------------
3384 // ----------------------------------------------------------------------------
3386 void wxListMainWindow::SetItem( wxListItem
&item
)
3388 long id
= item
.m_itemId
;
3389 wxCHECK_RET( id
>= 0 && (size_t)id
< GetItemCount(),
3390 _T("invalid item index in SetItem") );
3394 wxListLineData
*line
= GetLine((size_t)id
);
3395 line
->SetItem( item
.m_col
, item
);
3398 if ( InReportView() )
3400 // just refresh the line to show the new value of the text/image
3401 RefreshLine((size_t)id
);
3405 // refresh everything (resulting in horrible flicker - FIXME!)
3410 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask
)
3412 wxCHECK_RET( litem
>= 0 && (size_t)litem
< GetItemCount(),
3413 _T("invalid list ctrl item index in SetItem") );
3415 size_t oldCurrent
= m_current
;
3416 size_t item
= (size_t)litem
; // sdafe because of the check above
3418 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3420 if ( state
& wxLIST_STATE_FOCUSED
)
3422 // don't do anything if this item is already focused
3423 if ( item
!= m_current
)
3425 OnUnfocusLine( m_current
);
3427 OnFocusLine( m_current
);
3429 if ( IsSingleSel() && (oldCurrent
!= (size_t)-1) )
3431 HighlightLine(oldCurrent
, FALSE
);
3432 RefreshLine(oldCurrent
);
3435 RefreshLine( m_current
);
3440 // don't do anything if this item is not focused
3441 if ( item
== m_current
)
3443 OnUnfocusLine( m_current
);
3444 m_current
= (size_t)-1;
3449 if ( stateMask
& wxLIST_STATE_SELECTED
)
3451 bool on
= (state
& wxLIST_STATE_SELECTED
) != 0;
3453 if ( IsSingleSel() )
3457 // selecting the item also makes it the focused one in the
3459 if ( m_current
!= item
)
3461 OnUnfocusLine( m_current
);
3463 OnFocusLine( m_current
);
3465 if ( oldCurrent
!= (size_t)-1 )
3467 HighlightLine( oldCurrent
, FALSE
);
3468 RefreshLine( oldCurrent
);
3474 // only the current item may be selected anyhow
3475 if ( item
!= m_current
)
3480 if ( HighlightLine(item
, on
) )
3487 int wxListMainWindow::GetItemState( long item
, long stateMask
)
3489 wxCHECK_MSG( item
>= 0 && (size_t)item
< GetItemCount(), 0,
3490 _T("invalid list ctrl item index in GetItemState()") );
3492 int ret
= wxLIST_STATE_DONTCARE
;
3494 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3496 if ( (size_t)item
== m_current
)
3497 ret
|= wxLIST_STATE_FOCUSED
;
3500 if ( stateMask
& wxLIST_STATE_SELECTED
)
3502 if ( IsHighlighted(item
) )
3503 ret
|= wxLIST_STATE_SELECTED
;
3509 void wxListMainWindow::GetItem( wxListItem
&item
)
3511 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
< GetItemCount(),
3512 _T("invalid item index in GetItem") );
3514 wxListLineData
*line
= GetLine((size_t)item
.m_itemId
);
3515 line
->GetItem( item
.m_col
, item
);
3518 // ----------------------------------------------------------------------------
3520 // ----------------------------------------------------------------------------
3522 size_t wxListMainWindow::GetItemCount() const
3524 return IsVirtual() ? m_countVirt
: m_lines
.GetCount();
3527 void wxListMainWindow::SetItemCount(long count
)
3529 m_selStore
.SetItemCount(count
);
3530 m_countVirt
= count
;
3535 int wxListMainWindow::GetSelectedItemCount()
3537 // deal with the quick case first
3538 if ( IsSingleSel() )
3540 return HasCurrent() ? IsHighlighted(m_current
) : FALSE
;
3543 // virtual controls remmebers all its selections itself
3545 return m_selStore
.GetSelectedCount();
3547 // TODO: we probably should maintain the number of items selected even for
3548 // non virtual controls as enumerating all lines is really slow...
3549 size_t countSel
= 0;
3550 size_t count
= GetItemCount();
3551 for ( size_t line
= 0; line
< count
; line
++ )
3553 if ( GetLine(line
)->IsHighlighted() )
3560 // ----------------------------------------------------------------------------
3561 // item position/size
3562 // ----------------------------------------------------------------------------
3564 void wxListMainWindow::GetItemRect( long index
, wxRect
&rect
)
3566 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3567 _T("invalid index in GetItemRect") );
3569 rect
= GetLineRect((size_t)index
);
3571 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
3574 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
)
3577 GetItemRect(item
, rect
);
3585 // ----------------------------------------------------------------------------
3586 // geometry calculation
3587 // ----------------------------------------------------------------------------
3589 void wxListMainWindow::RecalculatePositions()
3594 wxClientDC
dc( this );
3595 dc
.SetFont( GetFont() );
3598 if ( HasFlag(wxLC_ICON
) )
3599 iconSpacing
= m_normal_spacing
;
3600 else if ( HasFlag(wxLC_SMALL_ICON
) )
3601 iconSpacing
= m_small_spacing
;
3607 GetClientSize( &clientWidth
, &clientHeight
);
3609 if ( HasFlag(wxLC_REPORT
) )
3611 // all lines have the same height
3612 int lineHeight
= GetLineHeight();
3614 // scroll one line per step
3615 m_yScroll
= lineHeight
;
3617 size_t lineCount
= GetItemCount();
3618 int entireHeight
= lineCount
*lineHeight
+ LINE_SPACING
;
3620 m_linesPerPage
= clientHeight
/ lineHeight
;
3622 ResetVisibleLinesRange();
3624 SetScrollbars( m_xScroll
, m_yScroll
,
3625 (GetHeaderWidth() + m_xScroll
- 1)/m_xScroll
,
3626 (entireHeight
+ m_yScroll
- 1)/m_yScroll
,
3627 GetScrollPos(wxHORIZONTAL
),
3628 GetScrollPos(wxVERTICAL
),
3633 // at first we try without any scrollbar. if the items don't
3634 // fit into the window, we recalculate after subtracting an
3635 // approximated 15 pt for the horizontal scrollbar
3637 clientHeight
-= 4; // sunken frame
3639 int entireWidth
= 0;
3641 for (int tries
= 0; tries
< 2; tries
++)
3648 int currentlyVisibleLines
= 0;
3650 size_t count
= GetItemCount();
3651 for (size_t i
= 0; i
< count
; i
++)
3653 currentlyVisibleLines
++;
3654 wxListLineData
*line
= GetLine(i
);
3655 line
->CalculateSize( &dc
, iconSpacing
);
3656 line
->SetPosition( x
, y
, clientWidth
, iconSpacing
);
3658 wxSize sizeLine
= GetLineSize(i
);
3660 if ( maxWidth
< sizeLine
.x
)
3661 maxWidth
= sizeLine
.x
;
3664 if (currentlyVisibleLines
> m_linesPerPage
)
3665 m_linesPerPage
= currentlyVisibleLines
;
3667 // assume that the size of the next one is the same... (FIXME)
3668 if ( y
+ sizeLine
.y
- 6 >= clientHeight
)
3670 currentlyVisibleLines
= 0;
3673 entireWidth
+= maxWidth
+6;
3676 if ( i
== count
- 1 )
3677 entireWidth
+= maxWidth
;
3678 if ((tries
== 0) && (entireWidth
> clientWidth
))
3680 clientHeight
-= 15; // scrollbar height
3682 currentlyVisibleLines
= 0;
3685 if ( i
== count
- 1 )
3686 tries
= 1; // everything fits, no second try required
3690 int scroll_pos
= GetScrollPos( wxHORIZONTAL
);
3691 SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE
);
3694 // FIXME: why should we call it from here?
3700 void wxListMainWindow::RefreshAll()
3705 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3708 headerWin
->m_dirty
= FALSE
;
3709 headerWin
->Refresh();
3713 void wxListMainWindow::UpdateCurrent()
3715 if ( !HasCurrent() && !IsEmpty() )
3720 if ( m_current
!= (size_t)-1 )
3722 OnFocusLine( m_current
);
3726 long wxListMainWindow::GetNextItem( long item
,
3727 int WXUNUSED(geometry
),
3731 max
= GetItemCount();
3732 wxCHECK_MSG( (ret
== -1) || (ret
< max
), -1,
3733 _T("invalid listctrl index in GetNextItem()") );
3735 // notice that we start with the next item (or the first one if item == -1)
3736 // and this is intentional to allow writing a simple loop to iterate over
3737 // all selected items
3741 // this is not an error because the index was ok initially, just no
3752 size_t count
= GetItemCount();
3753 for ( size_t line
= (size_t)ret
; line
< count
; line
++ )
3755 if ( (state
& wxLIST_STATE_FOCUSED
) && (line
== m_current
) )
3758 if ( (state
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) )
3765 // ----------------------------------------------------------------------------
3767 // ----------------------------------------------------------------------------
3769 void wxListMainWindow::DeleteItem( long lindex
)
3771 size_t count
= GetItemCount();
3773 wxCHECK_RET( (lindex
>= 0) && ((size_t)lindex
< count
),
3774 _T("invalid item index in DeleteItem") );
3776 size_t index
= (size_t)lindex
;
3780 // select the next item when the selected one is deleted
3781 if ( m_current
== index
)
3783 // the last valid index after deleting the item will be count-2
3784 if ( m_current
== count
- 1 )
3790 SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
);
3792 if ( InReportView() )
3794 ResetVisibleLinesRange();
3801 m_selStore
.OnItemDelete(index
);
3805 m_lines
.RemoveAt( index
);
3809 RefreshAfter(index
);
3812 void wxListMainWindow::DeleteColumn( int col
)
3814 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3816 wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") );
3819 m_columns
.DeleteNode( node
);
3822 void wxListMainWindow::DeleteAllItems()
3826 // nothing to do - in particular, don't send the event
3834 // to make the deletion of all items faster, we don't send the
3835 // notifications for each item deletion in this case but only one event
3836 // for all of them: this is compatible with wxMSW and documented in
3837 // DeleteAllItems() description
3839 wxListEvent
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() );
3840 event
.SetEventObject( GetParent() );
3841 GetParent()->GetEventHandler()->ProcessEvent( event
);
3847 ResetVisibleLinesRange();
3850 if ( InReportView() )
3852 ResetVisibleLinesRange();
3860 void wxListMainWindow::DeleteEverything()
3867 // ----------------------------------------------------------------------------
3868 // scanning for an item
3869 // ----------------------------------------------------------------------------
3871 void wxListMainWindow::EnsureVisible( long index
)
3873 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3874 _T("invalid index in EnsureVisible") );
3876 // We have to call this here because the label in question might just have
3877 // been added and no screen update taken place.
3881 size_t oldCurrent
= m_current
;
3882 m_current
= (size_t)index
;
3884 m_current
= oldCurrent
;
3887 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) )
3894 size_t count
= GetItemCount();
3895 for ( size_t i
= (size_t)pos
; i
< count
; i
++ )
3897 wxListLineData
*line
= GetLine(i
);
3898 if ( line
->GetText(0) == tmp
)
3905 long wxListMainWindow::FindItem(long start
, long data
)
3911 size_t count
= GetItemCount();
3912 for (size_t i
= (size_t)pos
; i
< count
; i
++)
3914 wxListLineData
*line
= GetLine(i
);
3916 line
->GetItem( 0, item
);
3917 if (item
.m_data
== data
)
3924 long wxListMainWindow::HitTest( int x
, int y
, int &flags
)
3926 CalcUnscrolledPosition( x
, y
, &x
, &y
);
3928 if ( HasFlag(wxLC_REPORT
) )
3930 size_t current
= y
/ GetLineHeight();
3931 flags
= HitTestLine(current
, x
, y
);
3937 // TODO: optimize it too! this is less simple than for report view but
3938 // enumerating all items is still not a way to do it!!
3939 size_t count
= GetItemCount();
3940 for ( size_t current
= 0; current
< count
; current
++ )
3942 flags
= HitTestLine(current
, x
, y
);
3951 // ----------------------------------------------------------------------------
3953 // ----------------------------------------------------------------------------
3955 void wxListMainWindow::InsertItem( wxListItem
&item
)
3957 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
3959 size_t count
= GetItemCount();
3960 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
<= count
,
3961 _T("invalid item index") );
3963 size_t id
= item
.m_itemId
;
3968 if ( HasFlag(wxLC_REPORT
) )
3970 else if ( HasFlag(wxLC_LIST
) )
3972 else if ( HasFlag(wxLC_ICON
) )
3974 else if ( HasFlag(wxLC_SMALL_ICON
) )
3975 mode
= wxLC_ICON
; // no typo
3978 wxFAIL_MSG( _T("unknown mode") );
3981 wxListLineData
*line
= new wxListLineData(this);
3983 line
->SetItem( 0, item
);
3985 m_lines
.Insert( line
, id
);
3988 RefreshLines(id
, GetItemCount() - 1);
3991 void wxListMainWindow::InsertColumn( long col
, wxListItem
&item
)
3994 if ( HasFlag(wxLC_REPORT
) )
3996 if (item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3997 item
.m_width
= GetTextLength( item
.m_text
);
3998 wxListHeaderData
*column
= new wxListHeaderData( item
);
3999 if ((col
>= 0) && (col
< (int)m_columns
.GetCount()))
4001 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
4002 m_columns
.Insert( node
, column
);
4006 m_columns
.Append( column
);
4011 // ----------------------------------------------------------------------------
4013 // ----------------------------------------------------------------------------
4015 wxListCtrlCompare list_ctrl_compare_func_2
;
4016 long list_ctrl_compare_data
;
4018 int LINKAGEMODE
list_ctrl_compare_func_1( wxListLineData
**arg1
, wxListLineData
**arg2
)
4020 wxListLineData
*line1
= *arg1
;
4021 wxListLineData
*line2
= *arg2
;
4023 line1
->GetItem( 0, item
);
4024 long data1
= item
.m_data
;
4025 line2
->GetItem( 0, item
);
4026 long data2
= item
.m_data
;
4027 return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data
);
4030 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data
)
4032 list_ctrl_compare_func_2
= fn
;
4033 list_ctrl_compare_data
= data
;
4034 m_lines
.Sort( list_ctrl_compare_func_1
);
4038 // ----------------------------------------------------------------------------
4040 // ----------------------------------------------------------------------------
4042 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
)
4044 // update our idea of which lines are shown when we redraw the window the
4046 ResetVisibleLinesRange();
4049 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4050 wxScrolledWindow::OnScroll(event
);
4052 HandleOnScroll( event
);
4055 if ( event
.GetOrientation() == wxHORIZONTAL
&& HasHeader() )
4057 wxListCtrl
* lc
= GetListCtrl();
4058 wxCHECK_RET( lc
, _T("no listctrl window?") );
4060 lc
->m_headerWin
->Refresh() ;
4062 lc
->m_headerWin
->MacUpdateImmediately() ;
4067 int wxListMainWindow::GetCountPerPage() const
4069 if ( !m_linesPerPage
)
4071 wxConstCast(this, wxListMainWindow
)->
4072 m_linesPerPage
= GetClientSize().y
/ GetLineHeight();
4075 return m_linesPerPage
;
4078 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
)
4080 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") );
4082 if ( m_lineFrom
== (size_t)-1 )
4084 size_t count
= GetItemCount();
4087 m_lineFrom
= GetScrollPos(wxVERTICAL
);
4089 // this may happen if SetScrollbars() hadn't been called yet
4090 if ( m_lineFrom
>= count
)
4091 m_lineFrom
= count
- 1;
4093 // we redraw one extra line but this is needed to make the redrawing
4094 // logic work when there is a fractional number of lines on screen
4095 m_lineTo
= m_lineFrom
+ m_linesPerPage
;
4096 if ( m_lineTo
>= count
)
4097 m_lineTo
= count
- 1;
4099 else // empty control
4102 m_lineTo
= (size_t)-1;
4106 wxASSERT_MSG( IsEmpty() ||
4107 (m_lineFrom
<= m_lineTo
&& m_lineTo
< GetItemCount()),
4108 _T("GetVisibleLinesRange() returns incorrect result") );
4116 // -------------------------------------------------------------------------------------
4118 // -------------------------------------------------------------------------------------
4120 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
4122 wxListItem::wxListItem()
4131 m_format
= wxLIST_FORMAT_CENTRE
;
4137 void wxListItem::Clear()
4146 m_format
= wxLIST_FORMAT_CENTRE
;
4153 void wxListItem::ClearAttributes()
4162 // -------------------------------------------------------------------------------------
4164 // -------------------------------------------------------------------------------------
4166 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
4168 wxListEvent::wxListEvent( wxEventType commandType
, int id
)
4169 : wxNotifyEvent( commandType
, id
)
4175 m_cancelled
= FALSE
;
4180 void wxListEvent::CopyObject(wxObject
& object_dest
) const
4182 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
4184 wxNotifyEvent::CopyObject(object_dest
);
4186 obj
->m_code
= m_code
;
4187 obj
->m_itemIndex
= m_itemIndex
;
4188 obj
->m_oldItemIndex
= m_oldItemIndex
;
4190 obj
->m_cancelled
= m_cancelled
;
4191 obj
->m_pointDrag
= m_pointDrag
;
4192 obj
->m_item
.m_mask
= m_item
.m_mask
;
4193 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
4194 obj
->m_item
.m_col
= m_item
.m_col
;
4195 obj
->m_item
.m_state
= m_item
.m_state
;
4196 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
4197 obj
->m_item
.m_text
= m_item
.m_text
;
4198 obj
->m_item
.m_image
= m_item
.m_image
;
4199 obj
->m_item
.m_data
= m_item
.m_data
;
4200 obj
->m_item
.m_format
= m_item
.m_format
;
4201 obj
->m_item
.m_width
= m_item
.m_width
;
4203 if ( m_item
.HasAttributes() )
4205 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
4209 // -------------------------------------------------------------------------------------
4211 // -------------------------------------------------------------------------------------
4213 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
4215 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
)
4216 EVT_SIZE(wxListCtrl::OnSize
)
4217 EVT_IDLE(wxListCtrl::OnIdle
)
4220 wxListCtrl::wxListCtrl()
4222 m_imageListNormal
= (wxImageList
*) NULL
;
4223 m_imageListSmall
= (wxImageList
*) NULL
;
4224 m_imageListState
= (wxImageList
*) NULL
;
4226 m_ownsImageListNormal
=
4227 m_ownsImageListSmall
=
4228 m_ownsImageListState
= FALSE
;
4230 m_mainWin
= (wxListMainWindow
*) NULL
;
4231 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4234 wxListCtrl::~wxListCtrl()
4237 m_mainWin
->ResetCurrent();
4239 if (m_ownsImageListNormal
)
4240 delete m_imageListNormal
;
4241 if (m_ownsImageListSmall
)
4242 delete m_imageListSmall
;
4243 if (m_ownsImageListState
)
4244 delete m_imageListState
;
4247 void wxListCtrl::CreateHeaderWindow()
4249 m_headerWin
= new wxListHeaderWindow
4251 this, -1, m_mainWin
,
4253 wxSize(GetClientSize().x
, HEADER_HEIGHT
),
4258 bool wxListCtrl::Create(wxWindow
*parent
,
4263 const wxValidator
&validator
,
4264 const wxString
&name
)
4268 m_imageListState
= (wxImageList
*) NULL
;
4269 m_ownsImageListNormal
=
4270 m_ownsImageListSmall
=
4271 m_ownsImageListState
= FALSE
;
4273 m_mainWin
= (wxListMainWindow
*) NULL
;
4274 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4276 if ( !(style
& wxLC_MASK_TYPE
) )
4278 style
= style
| wxLC_LIST
;
4281 if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name
) )
4284 // don't create the inner window with the border
4285 style
&= ~wxSUNKEN_BORDER
;
4287 m_mainWin
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style
);
4289 if ( HasFlag(wxLC_REPORT
) )
4291 CreateHeaderWindow();
4293 if ( HasFlag(wxLC_NO_HEADER
) )
4295 // VZ: why do we create it at all then?
4296 m_headerWin
->Show( FALSE
);
4303 void wxListCtrl::SetSingleStyle( long style
, bool add
)
4305 wxASSERT_MSG( !(style
& wxLC_VIRTUAL
),
4306 _T("wxLC_VIRTUAL can't be [un]set") );
4308 long flag
= GetWindowStyle();
4312 if (style
& wxLC_MASK_TYPE
)
4313 flag
&= ~(wxLC_MASK_TYPE
| wxLC_VIRTUAL
);
4314 if (style
& wxLC_MASK_ALIGN
)
4315 flag
&= ~wxLC_MASK_ALIGN
;
4316 if (style
& wxLC_MASK_SORT
)
4317 flag
&= ~wxLC_MASK_SORT
;
4329 SetWindowStyleFlag( flag
);
4332 void wxListCtrl::SetWindowStyleFlag( long flag
)
4336 m_mainWin
->DeleteEverything();
4340 GetClientSize( &width
, &height
);
4342 if (flag
& wxLC_REPORT
)
4344 if (!HasFlag(wxLC_REPORT
))
4348 CreateHeaderWindow();
4350 if (HasFlag(wxLC_NO_HEADER
))
4351 m_headerWin
->Show( FALSE
);
4355 if (flag
& wxLC_NO_HEADER
)
4356 m_headerWin
->Show( FALSE
);
4358 m_headerWin
->Show( TRUE
);
4364 if ( m_mainWin
->HasHeader() )
4366 m_headerWin
->Show( FALSE
);
4371 wxWindow::SetWindowStyleFlag( flag
);
4374 bool wxListCtrl::GetColumn(int col
, wxListItem
&item
) const
4376 m_mainWin
->GetColumn( col
, item
);
4380 bool wxListCtrl::SetColumn( int col
, wxListItem
& item
)
4382 m_mainWin
->SetColumn( col
, item
);
4386 int wxListCtrl::GetColumnWidth( int col
) const
4388 return m_mainWin
->GetColumnWidth( col
);
4391 bool wxListCtrl::SetColumnWidth( int col
, int width
)
4393 m_mainWin
->SetColumnWidth( col
, width
);
4397 int wxListCtrl::GetCountPerPage() const
4399 return m_mainWin
->GetCountPerPage(); // different from Windows ?
4402 bool wxListCtrl::GetItem( wxListItem
&info
) const
4404 m_mainWin
->GetItem( info
);
4408 bool wxListCtrl::SetItem( wxListItem
&info
)
4410 m_mainWin
->SetItem( info
);
4414 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId
)
4417 info
.m_text
= label
;
4418 info
.m_mask
= wxLIST_MASK_TEXT
;
4419 info
.m_itemId
= index
;
4423 info
.m_image
= imageId
;
4424 info
.m_mask
|= wxLIST_MASK_IMAGE
;
4426 m_mainWin
->SetItem(info
);
4430 int wxListCtrl::GetItemState( long item
, long stateMask
) const
4432 return m_mainWin
->GetItemState( item
, stateMask
);
4435 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask
)
4437 m_mainWin
->SetItemState( item
, state
, stateMask
);
4441 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) )
4444 info
.m_image
= image
;
4445 info
.m_mask
= wxLIST_MASK_IMAGE
;
4446 info
.m_itemId
= item
;
4447 m_mainWin
->SetItem( info
);
4451 wxString
wxListCtrl::GetItemText( long item
) const
4454 info
.m_itemId
= item
;
4455 m_mainWin
->GetItem( info
);
4459 void wxListCtrl::SetItemText( long item
, const wxString
&str
)
4462 info
.m_mask
= wxLIST_MASK_TEXT
;
4463 info
.m_itemId
= item
;
4465 m_mainWin
->SetItem( info
);
4468 long wxListCtrl::GetItemData( long item
) const
4471 info
.m_itemId
= item
;
4472 m_mainWin
->GetItem( info
);
4476 bool wxListCtrl::SetItemData( long item
, long data
)
4479 info
.m_mask
= wxLIST_MASK_DATA
;
4480 info
.m_itemId
= item
;
4482 m_mainWin
->SetItem( info
);
4486 bool wxListCtrl::GetItemRect( long item
, wxRect
&rect
, int WXUNUSED(code
) ) const
4488 m_mainWin
->GetItemRect( item
, rect
);
4492 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos
) const
4494 m_mainWin
->GetItemPosition( item
, pos
);
4498 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) )
4503 int wxListCtrl::GetItemCount() const
4505 return m_mainWin
->GetItemCount();
4508 int wxListCtrl::GetColumnCount() const
4510 return m_mainWin
->GetColumnCount();
4513 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall
)
4515 m_mainWin
->SetItemSpacing( spacing
, isSmall
);
4518 int wxListCtrl::GetItemSpacing( bool isSmall
) const
4520 return m_mainWin
->GetItemSpacing( isSmall
);
4523 int wxListCtrl::GetSelectedItemCount() const
4525 return m_mainWin
->GetSelectedItemCount();
4528 wxColour
wxListCtrl::GetTextColour() const
4530 return GetForegroundColour();
4533 void wxListCtrl::SetTextColour(const wxColour
& col
)
4535 SetForegroundColour(col
);
4538 long wxListCtrl::GetTopItem() const
4543 long wxListCtrl::GetNextItem( long item
, int geom
, int state
) const
4545 return m_mainWin
->GetNextItem( item
, geom
, state
);
4548 wxImageList
*wxListCtrl::GetImageList(int which
) const
4550 if (which
== wxIMAGE_LIST_NORMAL
)
4552 return m_imageListNormal
;
4554 else if (which
== wxIMAGE_LIST_SMALL
)
4556 return m_imageListSmall
;
4558 else if (which
== wxIMAGE_LIST_STATE
)
4560 return m_imageListState
;
4562 return (wxImageList
*) NULL
;
4565 void wxListCtrl::SetImageList( wxImageList
*imageList
, int which
)
4567 if ( which
== wxIMAGE_LIST_NORMAL
)
4569 if (m_ownsImageListNormal
) delete m_imageListNormal
;
4570 m_imageListNormal
= imageList
;
4571 m_ownsImageListNormal
= FALSE
;
4573 else if ( which
== wxIMAGE_LIST_SMALL
)
4575 if (m_ownsImageListSmall
) delete m_imageListSmall
;
4576 m_imageListSmall
= imageList
;
4577 m_ownsImageListSmall
= FALSE
;
4579 else if ( which
== wxIMAGE_LIST_STATE
)
4581 if (m_ownsImageListState
) delete m_imageListState
;
4582 m_imageListState
= imageList
;
4583 m_ownsImageListState
= FALSE
;
4586 m_mainWin
->SetImageList( imageList
, which
);
4589 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
4591 SetImageList(imageList
, which
);
4592 if ( which
== wxIMAGE_LIST_NORMAL
)
4593 m_ownsImageListNormal
= TRUE
;
4594 else if ( which
== wxIMAGE_LIST_SMALL
)
4595 m_ownsImageListSmall
= TRUE
;
4596 else if ( which
== wxIMAGE_LIST_STATE
)
4597 m_ownsImageListState
= TRUE
;
4600 bool wxListCtrl::Arrange( int WXUNUSED(flag
) )
4605 bool wxListCtrl::DeleteItem( long item
)
4607 m_mainWin
->DeleteItem( item
);
4611 bool wxListCtrl::DeleteAllItems()
4613 m_mainWin
->DeleteAllItems();
4617 bool wxListCtrl::DeleteAllColumns()
4619 size_t count
= m_mainWin
->m_columns
.GetCount();
4620 for ( size_t n
= 0; n
< count
; n
++ )
4626 void wxListCtrl::ClearAll()
4628 m_mainWin
->DeleteEverything();
4631 bool wxListCtrl::DeleteColumn( int col
)
4633 m_mainWin
->DeleteColumn( col
);
4637 void wxListCtrl::Edit( long item
)
4639 m_mainWin
->EditLabel( item
);
4642 bool wxListCtrl::EnsureVisible( long item
)
4644 m_mainWin
->EnsureVisible( item
);
4648 long wxListCtrl::FindItem( long start
, const wxString
& str
, bool partial
)
4650 return m_mainWin
->FindItem( start
, str
, partial
);
4653 long wxListCtrl::FindItem( long start
, long data
)
4655 return m_mainWin
->FindItem( start
, data
);
4658 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
),
4659 int WXUNUSED(direction
))
4664 long wxListCtrl::HitTest( const wxPoint
&point
, int &flags
)
4666 return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags
);
4669 long wxListCtrl::InsertItem( wxListItem
& info
)
4671 m_mainWin
->InsertItem( info
);
4672 return info
.m_itemId
;
4675 long wxListCtrl::InsertItem( long index
, const wxString
&label
)
4678 info
.m_text
= label
;
4679 info
.m_mask
= wxLIST_MASK_TEXT
;
4680 info
.m_itemId
= index
;
4681 return InsertItem( info
);
4684 long wxListCtrl::InsertItem( long index
, int imageIndex
)
4687 info
.m_mask
= wxLIST_MASK_IMAGE
;
4688 info
.m_image
= imageIndex
;
4689 info
.m_itemId
= index
;
4690 return InsertItem( info
);
4693 long wxListCtrl::InsertItem( long index
, const wxString
&label
, int imageIndex
)
4696 info
.m_text
= label
;
4697 info
.m_image
= imageIndex
;
4698 info
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_IMAGE
;
4699 info
.m_itemId
= index
;
4700 return InsertItem( info
);
4703 long wxListCtrl::InsertColumn( long col
, wxListItem
&item
)
4705 wxASSERT( m_headerWin
);
4706 m_mainWin
->InsertColumn( col
, item
);
4707 m_headerWin
->Refresh();
4712 long wxListCtrl::InsertColumn( long col
, const wxString
&heading
,
4713 int format
, int width
)
4716 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
4717 item
.m_text
= heading
;
4720 item
.m_mask
|= wxLIST_MASK_WIDTH
;
4721 item
.m_width
= width
;
4723 item
.m_format
= format
;
4725 return InsertColumn( col
, item
);
4728 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) )
4734 // fn is a function which takes 3 long arguments: item1, item2, data.
4735 // item1 is the long data associated with a first item (NOT the index).
4736 // item2 is the long data associated with a second item (NOT the index).
4737 // data is the same value as passed to SortItems.
4738 // The return value is a negative number if the first item should precede the second
4739 // item, a positive number of the second item should precede the first,
4740 // or zero if the two items are equivalent.
4741 // data is arbitrary data to be passed to the sort function.
4743 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data
)
4745 m_mainWin
->SortItems( fn
, data
);
4749 // ----------------------------------------------------------------------------
4751 // ----------------------------------------------------------------------------
4753 void wxListCtrl::OnSize(wxSizeEvent
& event
)
4759 GetClientSize( &cw
, &ch
);
4761 if ( m_mainWin
->HasHeader() )
4763 m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT
);
4764 m_mainWin
->SetSize( 0, HEADER_HEIGHT
+ 1, cw
, ch
- HEADER_HEIGHT
- 1 );
4766 else // no header window
4768 m_mainWin
->SetSize( 0, 0, cw
, ch
);
4771 m_mainWin
->RecalculatePositions();
4774 void wxListCtrl::OnIdle( wxIdleEvent
& event
)
4778 // do it only if needed
4779 if ( !m_mainWin
->m_dirty
)
4782 m_mainWin
->RecalculatePositions();
4785 // ----------------------------------------------------------------------------
4787 // ----------------------------------------------------------------------------
4789 bool wxListCtrl::SetBackgroundColour( const wxColour
&colour
)
4793 m_mainWin
->SetBackgroundColour( colour
);
4794 m_mainWin
->m_dirty
= TRUE
;
4800 bool wxListCtrl::SetForegroundColour( const wxColour
&colour
)
4802 if ( !wxWindow::SetForegroundColour( colour
) )
4807 m_mainWin
->SetForegroundColour( colour
);
4808 m_mainWin
->m_dirty
= TRUE
;
4813 m_headerWin
->SetForegroundColour( colour
);
4819 bool wxListCtrl::SetFont( const wxFont
&font
)
4821 if ( !wxWindow::SetFont( font
) )
4826 m_mainWin
->SetFont( font
);
4827 m_mainWin
->m_dirty
= TRUE
;
4832 m_headerWin
->SetFont( font
);
4838 // ----------------------------------------------------------------------------
4839 // methods forwarded to m_mainWin
4840 // ----------------------------------------------------------------------------
4842 #if wxUSE_DRAG_AND_DROP
4844 void wxListCtrl::SetDropTarget( wxDropTarget
*dropTarget
)
4846 m_mainWin
->SetDropTarget( dropTarget
);
4849 wxDropTarget
*wxListCtrl::GetDropTarget() const
4851 return m_mainWin
->GetDropTarget();
4854 #endif // wxUSE_DRAG_AND_DROP
4856 bool wxListCtrl::SetCursor( const wxCursor
&cursor
)
4858 return m_mainWin
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
;
4861 wxColour
wxListCtrl::GetBackgroundColour() const
4863 return m_mainWin
? m_mainWin
->GetBackgroundColour() : wxColour();
4866 wxColour
wxListCtrl::GetForegroundColour() const
4868 return m_mainWin
? m_mainWin
->GetForegroundColour() : wxColour();
4871 bool wxListCtrl::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4874 return m_mainWin
->PopupMenu( menu
, x
, y
);
4877 #endif // wxUSE_MENUS
4880 void wxListCtrl::SetFocus()
4882 /* The test in window.cpp fails as we are a composite
4883 window, so it checks against "this", but not m_mainWin. */
4884 if ( FindFocus() != this )
4885 m_mainWin
->SetFocus();
4888 // ----------------------------------------------------------------------------
4889 // virtual list control support
4890 // ----------------------------------------------------------------------------
4892 wxString
wxListCtrl::OnGetItemText(long item
, long col
) const
4894 // this is a pure virtual function, in fact - which is not really pure
4895 // because the controls which are not virtual don't need to implement it
4896 wxFAIL_MSG( _T("not supposed to be called") );
4898 return wxEmptyString
;
4901 int wxListCtrl::OnGetItemImage(long item
) const
4904 wxFAIL_MSG( _T("not supposed to be called") );
4909 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long item
) const
4911 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
4912 _T("invalid item index in OnGetItemAttr()") );
4914 // no attributes by default
4918 void wxListCtrl::SetItemCount(long count
)
4920 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4922 m_mainWin
->SetItemCount(count
);
4925 #endif // wxUSE_LISTCTRL