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 wxListItemAttr
*GetAttributes() const { return m_attr
; }
253 // the item image or -1
256 // user data associated with the item
259 // the item coordinates are not used in report mode, instead this pointer
260 // is NULL and the owner window is used to retrieve the item position and
264 // the list ctrl we are in
265 wxListMainWindow
*m_owner
;
267 // custom attributes or NULL
268 wxListItemAttr
*m_attr
;
271 // common part of all ctors
277 //-----------------------------------------------------------------------------
278 // wxListHeaderData (internal)
279 //-----------------------------------------------------------------------------
281 class WXDLLEXPORT wxListHeaderData
: public wxObject
295 wxListHeaderData( const wxListItem
&info
);
296 void SetItem( const wxListItem
&item
);
297 void SetPosition( int x
, int y
);
298 void SetWidth( int w
);
299 void SetFormat( int format
);
300 void SetHeight( int h
);
301 bool HasImage() const;
303 bool HasText() const { return !m_text
.empty(); }
304 const wxString
& GetText() const { return m_text
; }
305 void SetText(const wxString
& text
) { m_text
= text
; }
307 void GetItem( wxListItem
&item
);
309 bool IsHit( int x
, int y
) const;
310 int GetImage() const;
311 int GetWidth() const;
312 int GetFormat() const;
315 DECLARE_DYNAMIC_CLASS(wxListHeaderData
);
318 //-----------------------------------------------------------------------------
319 // wxListLineData (internal)
320 //-----------------------------------------------------------------------------
322 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
);
323 #include "wx/listimpl.cpp"
324 WX_DEFINE_LIST(wxListItemDataList
);
326 class WXDLLEXPORT wxListLineData
329 // the list of subitems: only may have more than one item in report mode
330 wxListItemDataList m_items
;
332 // this is not used in report view
344 // the part to be highlighted
345 wxRect m_rectHighlight
;
348 // is this item selected? [NB: not used in virtual mode]
351 // back pointer to the list ctrl
352 wxListMainWindow
*m_owner
;
355 wxListLineData(wxListMainWindow
*owner
);
357 ~wxListLineData() { delete m_gi
; }
359 // are we in report mode?
360 inline bool InReportView() const;
362 // are we in virtual report mode?
363 inline bool IsVirtual() const;
365 // these 2 methods shouldn't be called for report view controls, in that
366 // case we determine our position/size ourselves
368 // calculate the size of the line
369 void CalculateSize( wxDC
*dc
, int spacing
);
371 // remember the position this line appears at
372 void SetPosition( int x
, int y
, int window_width
, int spacing
);
376 void SetImage( int image
) { SetImage(0, image
); }
377 int GetImage() const { return GetImage(0); }
378 bool HasImage() const { return GetImage() != -1; }
379 bool HasText() const { return !GetText(0).empty(); }
381 void SetItem( int index
, const wxListItem
&info
);
382 void GetItem( int index
, wxListItem
&info
);
384 wxString
GetText(int index
) const;
385 void SetText( int index
, const wxString s
);
387 // return true if the highlighting really changed
388 bool Highlight( bool on
);
390 void ReverseHighlight();
392 bool IsHighlighted() const
394 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
396 return m_highlighted
;
399 // draw the line on the given DC in icon/list mode
400 void Draw( wxDC
*dc
);
402 // the same in report mode
403 void DrawInReportMode( wxDC
*dc
,
405 const wxRect
& rectHL
,
409 // set the line to contain num items (only can be > 1 in report mode)
410 void InitItems( int num
);
412 // get the mode (i.e. style) of the list control
413 inline int GetMode() const;
415 void SetAttributes(wxDC
*dc
,
416 const wxListItemAttr
*attr
,
417 const wxColour
& colText
,
421 // these are only used by GetImage/SetImage above, we don't support images
422 // with subitems at the public API level yet
423 void SetImage( int index
, int image
);
424 int GetImage( int index
) const;
427 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
);
428 #include "wx/arrimpl.cpp"
429 WX_DEFINE_OBJARRAY(wxListLineDataArray
);
431 //-----------------------------------------------------------------------------
432 // wxListHeaderWindow (internal)
433 //-----------------------------------------------------------------------------
435 class WXDLLEXPORT wxListHeaderWindow
: public wxWindow
438 wxListMainWindow
*m_owner
;
439 wxCursor
*m_currentCursor
;
440 wxCursor
*m_resizeCursor
;
443 // column being resized
446 // divider line position in logical (unscrolled) coords
449 // minimal position beyond which the divider line can't be dragged in
454 wxListHeaderWindow();
455 virtual ~wxListHeaderWindow();
457 wxListHeaderWindow( wxWindow
*win
,
459 wxListMainWindow
*owner
,
460 const wxPoint
&pos
= wxDefaultPosition
,
461 const wxSize
&size
= wxDefaultSize
,
463 const wxString
&name
= "wxlistctrlcolumntitles" );
465 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
467 void AdjustDC(wxDC
& dc
);
469 void OnPaint( wxPaintEvent
&event
);
470 void OnMouse( wxMouseEvent
&event
);
471 void OnSetFocus( wxFocusEvent
&event
);
477 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
)
478 DECLARE_EVENT_TABLE()
481 //-----------------------------------------------------------------------------
482 // wxListRenameTimer (internal)
483 //-----------------------------------------------------------------------------
485 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
488 wxListMainWindow
*m_owner
;
491 wxListRenameTimer( wxListMainWindow
*owner
);
495 //-----------------------------------------------------------------------------
496 // wxListTextCtrl (internal)
497 //-----------------------------------------------------------------------------
499 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
504 wxListMainWindow
*m_owner
;
505 wxString m_startValue
;
509 wxListTextCtrl( wxWindow
*parent
, const wxWindowID id
,
510 bool *accept
, wxString
*res
, wxListMainWindow
*owner
,
511 const wxString
&value
= "",
512 const wxPoint
&pos
= wxDefaultPosition
, const wxSize
&size
= wxDefaultSize
,
514 const wxValidator
& validator
= wxDefaultValidator
,
515 const wxString
&name
= "listctrltextctrl" );
516 void OnChar( wxKeyEvent
&event
);
517 void OnKeyUp( wxKeyEvent
&event
);
518 void OnKillFocus( wxFocusEvent
&event
);
521 DECLARE_DYNAMIC_CLASS(wxListTextCtrl
);
522 DECLARE_EVENT_TABLE()
525 //-----------------------------------------------------------------------------
526 // wxListMainWindow (internal)
527 //-----------------------------------------------------------------------------
529 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
);
530 #include "wx/listimpl.cpp"
531 WX_DEFINE_LIST(wxListHeaderDataList
);
533 class WXDLLEXPORT wxListMainWindow
: public wxScrolledWindow
537 wxListMainWindow( wxWindow
*parent
,
539 const wxPoint
& pos
= wxDefaultPosition
,
540 const wxSize
& size
= wxDefaultSize
,
542 const wxString
&name
= _T("listctrlmainwindow") );
544 virtual ~wxListMainWindow();
546 bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); }
548 // return true if this is a virtual list control
549 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); }
551 // return true if the control is in report mode
552 bool InReportView() const { return HasFlag(wxLC_REPORT
); }
554 // return true if we are in single selection mode, false if multi sel
555 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); }
557 // do we have a header window?
558 bool HasHeader() const
559 { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); }
561 void HighlightAll( bool on
);
563 // all these functions only do something if the line is currently visible
565 // change the line "selected" state, return TRUE if it really changed
566 bool HighlightLine( size_t line
, bool highlight
= TRUE
);
568 // as HighlightLine() but do it for the range of lines: this is incredibly
569 // more efficient for virtual list controls!
571 // NB: unlike HighlightLine() this one does refresh the lines on screen
572 void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on
= TRUE
);
574 // toggle the line state and refresh it
575 void ReverseHighlight( size_t line
)
576 { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); }
578 // return true if the line is highlighted
579 bool IsHighlighted(size_t line
) const;
581 // refresh one or several lines at once
582 void RefreshLine( size_t line
);
583 void RefreshLines( size_t lineFrom
, size_t lineTo
);
585 // refresh all lines below the given one: the difference with
586 // RefreshLines() is that the index here might not be a valid one (happens
587 // when the last line is deleted)
588 void RefreshAfter( size_t lineFrom
);
590 // the methods which are forwarded to wxListLineData itself in list/icon
591 // modes but are here because the lines don't store their positions in the
594 // get the bound rect for the entire line
595 wxRect
GetLineRect(size_t line
) const;
597 // get the bound rect of the label
598 wxRect
GetLineLabelRect(size_t line
) const;
600 // get the bound rect of the items icon (only may be called if we do have
602 wxRect
GetLineIconRect(size_t line
) const;
604 // get the rect to be highlighted when the item has focus
605 wxRect
GetLineHighlightRect(size_t line
) const;
607 // get the size of the total line rect
608 wxSize
GetLineSize(size_t line
) const
609 { return GetLineRect(line
).GetSize(); }
611 // return the hit code for the corresponding position (in this line)
612 long HitTestLine(size_t line
, int x
, int y
) const;
614 void EditLabel( long item
);
615 void OnRenameTimer();
616 void OnRenameAccept();
618 void OnMouse( wxMouseEvent
&event
);
621 // called to switch the selection from the current item to newCurrent,
622 void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event
);
624 void OnChar( wxKeyEvent
&event
);
625 void OnKeyDown( wxKeyEvent
&event
);
626 void OnSetFocus( wxFocusEvent
&event
);
627 void OnKillFocus( wxFocusEvent
&event
);
628 void OnScroll(wxScrollWinEvent
& event
) ;
630 void OnPaint( wxPaintEvent
&event
);
632 void DrawImage( int index
, wxDC
*dc
, int x
, int y
);
633 void GetImageSize( int index
, int &width
, int &height
) const;
634 int GetTextLength( const wxString
&s
) const;
636 void SetImageList( wxImageList
*imageList
, int which
);
637 void SetItemSpacing( int spacing
, bool isSmall
= FALSE
);
638 int GetItemSpacing( bool isSmall
= FALSE
);
640 void SetColumn( int col
, wxListItem
&item
);
641 void SetColumnWidth( int col
, int width
);
642 void GetColumn( int col
, wxListItem
&item
) const;
643 int GetColumnWidth( int col
) const;
644 int GetColumnCount() const { return m_columns
.GetCount(); }
646 // returns the sum of the heights of all columns
647 int GetHeaderWidth() const;
649 int GetCountPerPage() const;
651 void SetItem( wxListItem
&item
);
652 void GetItem( wxListItem
&item
);
653 void SetItemState( long item
, long state
, long stateMask
);
654 int GetItemState( long item
, long stateMask
);
655 void GetItemRect( long index
, wxRect
&rect
);
656 bool GetItemPosition( long item
, wxPoint
& pos
);
657 int GetSelectedItemCount();
659 // set the scrollbars and update the positions of the items
660 void RecalculatePositions();
662 // refresh the window and the header
665 long GetNextItem( long item
, int geometry
, int state
);
666 void DeleteItem( long index
);
667 void DeleteAllItems();
668 void DeleteColumn( int col
);
669 void DeleteEverything();
670 void EnsureVisible( long index
);
671 long FindItem( long start
, const wxString
& str
, bool partial
= FALSE
);
672 long FindItem( long start
, long data
);
673 long HitTest( int x
, int y
, int &flags
);
674 void InsertItem( wxListItem
&item
);
675 void InsertColumn( long col
, wxListItem
&item
);
676 void SortItems( wxListCtrlCompare fn
, long data
);
678 size_t GetItemCount() const;
679 bool IsEmpty() const { return GetItemCount() == 0; }
680 void SetItemCount(long count
);
682 void ResetCurrent() { m_current
= (size_t)-1; }
683 bool HasCurrent() const { return m_current
!= (size_t)-1; }
685 // send out a wxListEvent
686 void SendNotify( size_t line
,
688 wxPoint point
= wxDefaultPosition
);
690 // override base class virtual to reset m_lineHeight when the font changes
691 virtual bool SetFont(const wxFont
& font
)
693 if ( !wxScrolledWindow::SetFont(font
) )
701 // these are for wxListLineData usage only
703 // get the backpointer to the list ctrl
704 wxListCtrl
*GetListCtrl() const
706 return wxStaticCast(GetParent(), wxListCtrl
);
709 // get the height of all lines (assuming they all do have the same height)
710 wxCoord
GetLineHeight() const;
712 // get the y position of the given line (only for report view)
713 wxCoord
GetLineY(size_t line
) const;
716 // the array of all line objects for a non virtual list control
717 wxListLineDataArray m_lines
;
719 // the list of column objects
720 wxListHeaderDataList m_columns
;
722 // currently focused item or -1
725 // the item currently being edited or -1
726 size_t m_currentEdit
;
728 // the number of lines per page
731 // this flag is set when something which should result in the window
732 // redrawing happens (i.e. an item was added or deleted, or its appearance
733 // changed) and OnPaint() doesn't redraw the window while it is set which
734 // allows to minimize the number of repaintings when a lot of items are
735 // being added. The real repainting occurs only after the next OnIdle()
739 wxBrush
*m_highlightBrush
;
740 wxColour
*m_highlightColour
;
743 wxImageList
*m_small_image_list
;
744 wxImageList
*m_normal_image_list
;
746 int m_normal_spacing
;
750 wxTimer
*m_renameTimer
;
752 wxString m_renameRes
;
757 // for double click logic
758 size_t m_lineLastClicked
,
759 m_lineBeforeLastClicked
;
762 // the total count of items in a virtual list control
765 // the object maintaining the items selection state, only used in virtual
767 wxSelectionStore m_selStore
;
769 // common part of all ctors
772 // intiialize m_[xy]Scroll
773 void InitScrolling();
775 // get the line data for the given index
776 wxListLineData
*GetLine(size_t n
) const
778 wxASSERT_MSG( n
!= (size_t)-1, _T("invalid line index") );
782 wxConstCast(this, wxListMainWindow
)->CacheLineData(n
);
790 // get a dummy line which can be used for geometry calculations and such:
791 // you must use GetLine() if you want to really draw the line
792 wxListLineData
*GetDummyLine() const;
794 // cache the line data of the n-th line in m_lines[0]
795 void CacheLineData(size_t line
);
797 // get the range of visible lines
798 void GetVisibleLinesRange(size_t *from
, size_t *to
);
800 // force us to recalculate the range of visible lines
801 void ResetVisibleLinesRange() { m_lineFrom
= (size_t)-1; }
803 // get the colour to be used for drawing the rules
804 wxColour
GetRuleColour() const
809 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
);
814 // initialize the current item if needed
815 void UpdateCurrent();
817 // called when an item is [un]focuded, i.e. becomes [not] current
820 void OnFocusLine( size_t line
);
821 void OnUnfocusLine( size_t line
);
823 // the height of one line using the current font
824 wxCoord m_lineHeight
;
826 // the total header width or 0 if not calculated yet
827 wxCoord m_headerWidth
;
829 // the first and last lines being shown on screen right now (inclusive),
830 // both may be -1 if they must be calculated so never access them directly:
831 // use GetVisibleLinesRange() above instead
835 DECLARE_DYNAMIC_CLASS(wxListMainWindow
);
836 DECLARE_EVENT_TABLE()
839 // ============================================================================
841 // ============================================================================
843 // ----------------------------------------------------------------------------
845 // ----------------------------------------------------------------------------
847 bool wxSelectionStore::IsSelected(size_t item
) const
849 bool isSel
= m_itemsSel
.Index(item
) != wxNOT_FOUND
;
851 // if the default state is to be selected, being in m_itemsSel means that
852 // the item is not selected, so we have to inverse the logic
853 return m_defaultState
? !isSel
: isSel
;
856 bool wxSelectionStore::SelectItem(size_t item
, bool select
)
858 // search for the item ourselves as like this we get the index where to
859 // insert it later if needed, so we do only one search in the array instead
860 // of two (adding item to a sorted array requires a search)
861 size_t index
= m_itemsSel
.IndexForInsert(item
);
862 bool isSel
= index
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
;
864 if ( select
!= m_defaultState
)
868 m_itemsSel
.AddAt(item
, index
);
873 else // reset to default state
877 m_itemsSel
.RemoveAt(index
);
885 void wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, bool select
)
887 wxASSERT_MSG( itemFrom
<= itemTo
, _T("should be in order") );
889 // are we going to have more [un]selected items than the other ones?
890 if ( itemTo
- itemFrom
> m_count
/ 2 )
892 if ( select
!= m_defaultState
)
894 // the default state now becomes the same as 'select'
895 m_defaultState
= select
;
897 // so all the old selections (which had state select) shouldn't be
898 // selected any more, but all the other ones should
899 wxIndexArray selOld
= m_itemsSel
;
902 // TODO: it should be possible to optimize the searches a bit
903 // knowing the possible range
906 for ( item
= 0; item
< itemFrom
; item
++ )
908 if ( selOld
.Index(item
) == wxNOT_FOUND
)
909 m_itemsSel
.Add(item
);
912 for ( item
= itemTo
+ 1; item
< m_count
; item
++ )
914 if ( selOld
.Index(item
) == wxNOT_FOUND
)
915 m_itemsSel
.Add(item
);
918 else // select == m_defaultState
920 // get the inclusive range of items between itemFrom and itemTo
921 size_t count
= m_itemsSel
.GetCount(),
922 start
= m_itemsSel
.IndexForInsert(itemFrom
),
923 end
= m_itemsSel
.IndexForInsert(itemTo
);
925 if ( start
== count
|| m_itemsSel
[start
] < itemFrom
)
930 if ( end
== count
|| m_itemsSel
[end
] > itemTo
)
937 // delete all of them (from end to avoid changing indices)
938 for ( int i
= end
; i
>= (int)start
; i
-- )
940 m_itemsSel
.RemoveAt(i
);
945 else // "few" items change state
947 // just add the items to the selection
948 for ( size_t item
= itemFrom
; item
<= itemTo
; item
++ )
950 SelectItem(item
, select
);
955 void wxSelectionStore::OnItemDelete(size_t item
)
957 size_t count
= m_itemsSel
.GetCount(),
958 i
= m_itemsSel
.IndexForInsert(item
);
960 if ( i
< count
&& m_itemsSel
[i
] == item
)
962 // this item itself was in m_itemsSel, remove it from there
963 m_itemsSel
.RemoveAt(i
);
968 // and adjust the index of all which follow it
971 // all following elements must be greater than the one we deleted
972 wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") );
978 //-----------------------------------------------------------------------------
980 //-----------------------------------------------------------------------------
982 void wxListItemData::Init()
990 wxListItemData::wxListItemData(wxListMainWindow
*owner
)
996 if ( owner
->HasFlag(wxLC_REPORT
) )
1002 m_rect
= new wxRect
;
1006 void wxListItemData::SetItem( const wxListItem
&info
)
1008 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
1009 SetText(info
.m_text
);
1010 if ( info
.m_mask
& wxLIST_MASK_IMAGE
)
1011 m_image
= info
.m_image
;
1012 if ( info
.m_mask
& wxLIST_MASK_DATA
)
1013 m_data
= info
.m_data
;
1015 if ( info
.HasAttributes() )
1018 *m_attr
= *info
.GetAttributes();
1020 m_attr
= new wxListItemAttr(*info
.GetAttributes());
1028 m_rect
->width
= info
.m_width
;
1032 void wxListItemData::SetPosition( int x
, int y
)
1034 wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") );
1040 void wxListItemData::SetSize( int width
, int height
)
1042 wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") );
1045 m_rect
->width
= width
;
1047 m_rect
->height
= height
;
1050 bool wxListItemData::IsHit( int x
, int y
) const
1052 wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") );
1054 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
);
1057 int wxListItemData::GetX() const
1059 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1064 int wxListItemData::GetY() const
1066 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1071 int wxListItemData::GetWidth() const
1073 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1075 return m_rect
->width
;
1078 int wxListItemData::GetHeight() const
1080 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1082 return m_rect
->height
;
1085 void wxListItemData::GetItem( wxListItem
&info
) const
1087 info
.m_text
= m_text
;
1088 info
.m_image
= m_image
;
1089 info
.m_data
= m_data
;
1093 if ( m_attr
->HasTextColour() )
1094 info
.SetTextColour(m_attr
->GetTextColour());
1095 if ( m_attr
->HasBackgroundColour() )
1096 info
.SetBackgroundColour(m_attr
->GetBackgroundColour());
1097 if ( m_attr
->HasFont() )
1098 info
.SetFont(m_attr
->GetFont());
1102 //-----------------------------------------------------------------------------
1104 //-----------------------------------------------------------------------------
1106 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
);
1108 wxListHeaderData::wxListHeaderData()
1119 wxListHeaderData::wxListHeaderData( const wxListItem
&item
)
1127 void wxListHeaderData::SetItem( const wxListItem
&item
)
1129 m_mask
= item
.m_mask
;
1130 m_text
= item
.m_text
;
1131 m_image
= item
.m_image
;
1132 m_format
= item
.m_format
;
1134 SetWidth(item
.m_width
);
1137 void wxListHeaderData::SetPosition( int x
, int y
)
1143 void wxListHeaderData::SetHeight( int h
)
1148 void wxListHeaderData::SetWidth( int w
)
1152 m_width
= WIDTH_COL_DEFAULT
;
1153 if (m_width
< WIDTH_COL_MIN
)
1154 m_width
= WIDTH_COL_MIN
;
1157 void wxListHeaderData::SetFormat( int format
)
1162 bool wxListHeaderData::HasImage() const
1164 return (m_image
!= 0);
1167 bool wxListHeaderData::IsHit( int x
, int y
) const
1169 return ((x
>= m_xpos
) && (x
<= m_xpos
+m_width
) && (y
>= m_ypos
) && (y
<= m_ypos
+m_height
));
1172 void wxListHeaderData::GetItem( wxListItem
&item
)
1174 item
.m_mask
= m_mask
;
1175 item
.m_text
= m_text
;
1176 item
.m_image
= m_image
;
1177 item
.m_format
= m_format
;
1178 item
.m_width
= m_width
;
1181 int wxListHeaderData::GetImage() const
1186 int wxListHeaderData::GetWidth() const
1191 int wxListHeaderData::GetFormat() const
1196 //-----------------------------------------------------------------------------
1198 //-----------------------------------------------------------------------------
1200 inline int wxListLineData::GetMode() const
1202 return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
;
1205 inline bool wxListLineData::InReportView() const
1207 return m_owner
->HasFlag(wxLC_REPORT
);
1210 inline bool wxListLineData::IsVirtual() const
1212 return m_owner
->IsVirtual();
1215 wxListLineData::wxListLineData( wxListMainWindow
*owner
)
1218 m_items
.DeleteContents( TRUE
);
1220 if ( InReportView() )
1226 m_gi
= new GeometryInfo
;
1229 m_highlighted
= FALSE
;
1231 InitItems( GetMode() == wxLC_REPORT
? m_owner
->GetColumnCount() : 1 );
1234 void wxListLineData::CalculateSize( wxDC
*dc
, int spacing
)
1236 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1237 wxCHECK_RET( node
, _T("no subitems at all??") );
1239 wxListItemData
*item
= node
->GetData();
1241 switch ( GetMode() )
1244 case wxLC_SMALL_ICON
:
1246 m_gi
->m_rectAll
.width
= spacing
;
1248 wxString s
= item
->GetText();
1254 m_gi
->m_rectLabel
.width
=
1255 m_gi
->m_rectLabel
.height
= 0;
1259 dc
->GetTextExtent( s
, &lw
, &lh
);
1260 if (lh
< SCROLL_UNIT_Y
)
1265 m_gi
->m_rectAll
.height
= spacing
+ lh
;
1267 m_gi
->m_rectAll
.width
= lw
;
1269 m_gi
->m_rectLabel
.width
= lw
;
1270 m_gi
->m_rectLabel
.height
= lh
;
1273 if (item
->HasImage())
1276 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1277 m_gi
->m_rectIcon
.width
= w
+ 8;
1278 m_gi
->m_rectIcon
.height
= h
+ 8;
1280 if ( m_gi
->m_rectIcon
.width
> m_gi
->m_rectAll
.width
)
1281 m_gi
->m_rectAll
.width
= m_gi
->m_rectIcon
.width
;
1282 if ( m_gi
->m_rectIcon
.height
+ lh
> m_gi
->m_rectAll
.height
- 4 )
1283 m_gi
->m_rectAll
.height
= m_gi
->m_rectIcon
.height
+ lh
+ 4;
1286 if ( item
->HasText() )
1288 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectLabel
.width
;
1289 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectLabel
.height
;
1291 else // no text, highlight the icon
1293 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectIcon
.width
;
1294 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectIcon
.height
;
1301 wxString s
= item
->GetTextForMeasuring();
1304 dc
->GetTextExtent( s
, &lw
, &lh
);
1305 if (lh
< SCROLL_UNIT_Y
)
1310 m_gi
->m_rectLabel
.width
= lw
;
1311 m_gi
->m_rectLabel
.height
= lh
;
1313 m_gi
->m_rectAll
.width
= lw
;
1314 m_gi
->m_rectAll
.height
= lh
;
1316 if (item
->HasImage())
1319 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1320 m_gi
->m_rectIcon
.width
= w
;
1321 m_gi
->m_rectIcon
.height
= h
;
1323 m_gi
->m_rectAll
.width
+= 4 + w
;
1324 if (h
> m_gi
->m_rectAll
.height
)
1325 m_gi
->m_rectAll
.height
= h
;
1328 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectAll
.width
;
1329 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectAll
.height
;
1334 wxFAIL_MSG( _T("unexpected call to SetSize") );
1338 wxFAIL_MSG( _T("unknown mode") );
1342 void wxListLineData::SetPosition( int x
, int y
,
1346 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1347 wxCHECK_RET( node
, _T("no subitems at all??") );
1349 wxListItemData
*item
= node
->GetData();
1351 switch ( GetMode() )
1354 case wxLC_SMALL_ICON
:
1355 m_gi
->m_rectAll
.x
= x
;
1356 m_gi
->m_rectAll
.y
= y
;
1358 if ( item
->HasImage() )
1360 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 4
1361 + (spacing
- m_gi
->m_rectIcon
.width
)/2;
1362 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 4;
1365 if ( item
->HasText() )
1367 if (m_gi
->m_rectAll
.width
> spacing
)
1368 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1370 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2);
1371 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ m_gi
->m_rectAll
.height
+ 2 - m_gi
->m_rectLabel
.height
;
1372 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectLabel
.x
- 2;
1373 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectLabel
.y
- 2;
1375 else // no text, highlight the icon
1377 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectIcon
.x
- 4;
1378 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectIcon
.y
- 4;
1383 m_gi
->m_rectAll
.x
= x
;
1384 m_gi
->m_rectAll
.y
= y
;
1386 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectAll
.x
;
1387 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectAll
.y
;
1388 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ 2;
1390 if (item
->HasImage())
1392 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 2;
1393 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 2;
1394 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 6 + m_gi
->m_rectIcon
.width
;
1398 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1403 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1407 wxFAIL_MSG( _T("unknown mode") );
1411 void wxListLineData::InitItems( int num
)
1413 for (int i
= 0; i
< num
; i
++)
1414 m_items
.Append( new wxListItemData(m_owner
) );
1417 void wxListLineData::SetItem( int index
, const wxListItem
&info
)
1419 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1420 wxCHECK_RET( node
, _T("invalid column index in SetItem") );
1422 wxListItemData
*item
= node
->GetData();
1423 item
->SetItem( info
);
1426 void wxListLineData::GetItem( int index
, wxListItem
&info
)
1428 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1431 wxListItemData
*item
= node
->GetData();
1432 item
->GetItem( info
);
1436 wxString
wxListLineData::GetText(int index
) const
1440 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1443 wxListItemData
*item
= node
->GetData();
1444 s
= item
->GetText();
1450 void wxListLineData::SetText( int index
, const wxString s
)
1452 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1455 wxListItemData
*item
= node
->GetData();
1460 void wxListLineData::SetImage( int index
, int image
)
1462 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1463 wxCHECK_RET( node
, _T("invalid column index in SetImage()") );
1465 wxListItemData
*item
= node
->GetData();
1466 item
->SetImage(image
);
1469 int wxListLineData::GetImage( int index
) const
1471 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1472 wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") );
1474 wxListItemData
*item
= node
->GetData();
1475 return item
->GetImage();
1478 void wxListLineData::SetAttributes(wxDC
*dc
,
1479 const wxListItemAttr
*attr
,
1480 const wxColour
& colText
,
1484 // don't use foregroud colour for drawing highlighted items - this might
1485 // make them completely invisible (and there is no way to do bit
1486 // arithmetics on wxColour, unfortunately)
1487 if ( !highlight
&& attr
&& attr
->HasTextColour() )
1489 dc
->SetTextForeground(attr
->GetTextColour());
1493 dc
->SetTextForeground(colText
);
1496 if ( attr
&& attr
->HasFont() )
1498 dc
->SetFont(attr
->GetFont());
1506 void wxListLineData::Draw( wxDC
*dc
)
1508 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1509 wxCHECK_RET( node
, _T("no subitems at all??") );
1511 wxListItemData
*item
= node
->GetData();
1512 if (item
->HasImage())
1514 wxRect rectIcon
= m_gi
->m_rectIcon
;
1515 m_owner
->DrawImage( item
->GetImage(), dc
,
1516 rectIcon
.x
, rectIcon
.y
);
1519 if (item
->HasText())
1521 wxRect rectLabel
= m_gi
->m_rectLabel
;
1522 dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y
);
1526 void wxListLineData::DrawInReportMode( wxDC
*dc
,
1528 const wxRect
& rectHL
,
1531 // use our own flag if we maintain it
1533 highlighted
= m_highlighted
;
1535 // default foreground colour
1536 wxWindow
*listctrl
= m_owner
->GetParent();
1540 colText
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT
);
1544 colText
= listctrl
->GetForegroundColour();
1548 wxFont font
= listctrl
->GetFont();
1550 // VZ: currently we set the colours/fonts only once, but like this (i.e.
1551 // using SetAttributes() inside the loop), it will be trivial to
1552 // customize the subitems (in report mode) too.
1553 wxListItemData
*item
= m_items
.GetFirst()->GetData();
1554 wxListItemAttr
*attr
= item
->GetAttributes();
1555 SetAttributes(dc
, attr
, colText
, font
, highlighted
);
1557 bool hasBgCol
= attr
&& attr
->HasBackgroundColour();
1558 if ( highlighted
|| hasBgCol
)
1562 dc
->SetBrush( *m_owner
->m_highlightBrush
);
1567 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
1569 dc
->SetBrush( * wxWHITE_BRUSH
);
1572 dc
->SetPen( * wxTRANSPARENT_PEN
);
1573 dc
->DrawRectangle( rectHL
);
1576 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1577 wxCHECK_RET( node
, _T("no subitems at all??") );
1580 wxCoord x
= rect
.x
+ HEADER_OFFSET_X
,
1581 y
= rect
.y
+ (LINE_SPACING
+ EXTRA_HEIGHT
) / 2;
1585 wxListItemData
*item
= node
->GetData();
1589 if ( item
->HasImage() )
1592 m_owner
->DrawImage( item
->GetImage(), dc
, x
, y
);
1593 m_owner
->GetImageSize( item
->GetImage(), ix
, iy
);
1594 x
+= ix
+ 5; // FIXME: what is "5"?
1597 int width
= m_owner
->GetColumnWidth(col
++);
1599 wxDCClipper
clipper(*dc
, x
, y
, width
, rect
.height
);
1601 if ( item
->HasText() )
1603 dc
->DrawText( item
->GetText(), x
, y
);
1608 node
= node
->GetNext();
1612 bool wxListLineData::Highlight( bool on
)
1614 wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") );
1616 if ( on
== m_highlighted
)
1624 void wxListLineData::ReverseHighlight( void )
1626 Highlight(!IsHighlighted());
1629 //-----------------------------------------------------------------------------
1630 // wxListHeaderWindow
1631 //-----------------------------------------------------------------------------
1633 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
);
1635 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
)
1636 EVT_PAINT (wxListHeaderWindow::OnPaint
)
1637 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse
)
1638 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus
)
1641 wxListHeaderWindow::wxListHeaderWindow( void )
1643 m_owner
= (wxListMainWindow
*) NULL
;
1644 m_currentCursor
= (wxCursor
*) NULL
;
1645 m_resizeCursor
= (wxCursor
*) NULL
;
1646 m_isDragging
= FALSE
;
1649 wxListHeaderWindow::wxListHeaderWindow( wxWindow
*win
, wxWindowID id
, wxListMainWindow
*owner
,
1650 const wxPoint
&pos
, const wxSize
&size
,
1651 long style
, const wxString
&name
) :
1652 wxWindow( win
, id
, pos
, size
, style
, name
)
1655 // m_currentCursor = wxSTANDARD_CURSOR;
1656 m_currentCursor
= (wxCursor
*) NULL
;
1657 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
1658 m_isDragging
= FALSE
;
1661 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE
) );
1664 wxListHeaderWindow::~wxListHeaderWindow( void )
1666 delete m_resizeCursor
;
1669 void wxListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1672 GtkStateType state
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
1673 : GTK_STATE_INSENSITIVE
;
1675 x
= dc
->XLOG2DEV( x
);
1677 gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
,
1678 state
, GTK_SHADOW_OUT
,
1679 (GdkRectangle
*) NULL
, m_wxwindow
, "button",
1680 x
-1, y
-1, w
+2, h
+2);
1681 #elif defined( __WXMAC__ )
1682 const int m_corner
= 1;
1684 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1686 dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
) , 1 , wxSOLID
) );
1687 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1688 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1690 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1693 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1694 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1696 dc
->SetPen( *wxWHITE_PEN
);
1697 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1698 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1699 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1700 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1702 const int m_corner
= 1;
1704 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1706 dc
->SetPen( *wxBLACK_PEN
);
1707 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1708 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1710 wxPen
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1713 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1714 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1716 dc
->SetPen( *wxWHITE_PEN
);
1717 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1718 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1719 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1720 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1724 // shift the DC origin to match the position of the main window horz
1725 // scrollbar: this allows us to always use logical coords
1726 void wxListHeaderWindow::AdjustDC(wxDC
& dc
)
1729 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1732 m_owner
->GetViewStart( &x
, NULL
);
1734 // account for the horz scrollbar offset
1735 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1738 void wxListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1741 wxClientDC
dc( this );
1743 wxPaintDC
dc( this );
1751 dc
.SetFont( GetFont() );
1753 // width and height of the entire header window
1755 GetClientSize( &w
, &h
);
1756 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1758 dc
.SetBackgroundMode(wxTRANSPARENT
);
1760 // do *not* use the listctrl colour for headers - one day we will have a
1761 // function to set it separately
1762 //dc.SetTextForeground( *wxBLACK );
1763 dc
.SetTextForeground(wxSystemSettings::
1764 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1766 int x
= HEADER_OFFSET_X
;
1768 int numColumns
= m_owner
->GetColumnCount();
1770 for (int i
= 0; i
< numColumns
; i
++)
1772 m_owner
->GetColumn( i
, item
);
1773 int wCol
= item
.m_width
;
1774 int cw
= wCol
- 2; // the width of the rect to draw
1776 int xEnd
= x
+ wCol
;
1778 dc
.SetPen( *wxWHITE_PEN
);
1780 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1781 dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 );
1782 dc
.DrawText( item
.GetText(), x
+ EXTRA_WIDTH
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1783 dc
.DestroyClippingRegion();
1792 void wxListHeaderWindow::DrawCurrent()
1794 int x1
= m_currentX
;
1796 ClientToScreen( &x1
, &y1
);
1798 int x2
= m_currentX
-1;
1800 m_owner
->GetClientSize( NULL
, &y2
);
1801 m_owner
->ClientToScreen( &x2
, &y2
);
1804 dc
.SetLogicalFunction( wxINVERT
);
1805 dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID
) );
1806 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1810 dc
.DrawLine( x1
, y1
, x2
, y2
);
1812 dc
.SetLogicalFunction( wxCOPY
);
1814 dc
.SetPen( wxNullPen
);
1815 dc
.SetBrush( wxNullBrush
);
1818 void wxListHeaderWindow::OnMouse( wxMouseEvent
&event
)
1820 // we want to work with logical coords
1822 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1823 int y
= event
.GetY();
1827 // we don't draw the line beyond our window, but we allow dragging it
1830 GetClientSize( &w
, NULL
);
1831 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1834 // erase the line if it was drawn
1835 if ( m_currentX
< w
)
1838 if (event
.ButtonUp())
1841 m_isDragging
= FALSE
;
1843 m_owner
->SetColumnWidth( m_column
, m_currentX
- m_minX
);
1850 m_currentX
= m_minX
+ 7;
1852 // draw in the new location
1853 if ( m_currentX
< w
)
1857 else // not dragging
1860 bool hit_border
= FALSE
;
1862 // end of the current column
1865 // find the column where this event occured
1866 int countCol
= m_owner
->GetColumnCount();
1867 for (int col
= 0; col
< countCol
; col
++)
1869 xpos
+= m_owner
->GetColumnWidth( col
);
1872 if ( (abs(x
-xpos
) < 3) && (y
< 22) )
1874 // near the column border
1881 // inside the column
1888 if (event
.LeftDown())
1892 m_isDragging
= TRUE
;
1899 wxWindow
*parent
= GetParent();
1900 wxListEvent
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() );
1901 le
.SetEventObject( parent
);
1902 le
.m_col
= m_column
;
1903 parent
->GetEventHandler()->ProcessEvent( le
);
1906 else if (event
.Moving())
1911 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1912 m_currentCursor
= m_resizeCursor
;
1916 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1917 m_currentCursor
= wxSTANDARD_CURSOR
;
1921 SetCursor(*m_currentCursor
);
1926 void wxListHeaderWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
1928 m_owner
->SetFocus();
1931 //-----------------------------------------------------------------------------
1932 // wxListRenameTimer (internal)
1933 //-----------------------------------------------------------------------------
1935 wxListRenameTimer::wxListRenameTimer( wxListMainWindow
*owner
)
1940 void wxListRenameTimer::Notify()
1942 m_owner
->OnRenameTimer();
1945 //-----------------------------------------------------------------------------
1946 // wxListTextCtrl (internal)
1947 //-----------------------------------------------------------------------------
1949 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
);
1951 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
)
1952 EVT_CHAR (wxListTextCtrl::OnChar
)
1953 EVT_KEY_UP (wxListTextCtrl::OnKeyUp
)
1954 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus
)
1957 wxListTextCtrl::wxListTextCtrl( wxWindow
*parent
,
1958 const wxWindowID id
,
1961 wxListMainWindow
*owner
,
1962 const wxString
&value
,
1966 const wxValidator
& validator
,
1967 const wxString
&name
)
1968 : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name
)
1973 (*m_accept
) = FALSE
;
1975 m_startValue
= value
;
1978 void wxListTextCtrl::OnChar( wxKeyEvent
&event
)
1980 if (event
.m_keyCode
== WXK_RETURN
)
1983 (*m_res
) = GetValue();
1985 if (!wxPendingDelete
.Member(this))
1986 wxPendingDelete
.Append(this);
1988 if ((*m_accept
) && ((*m_res
) != m_startValue
))
1989 m_owner
->OnRenameAccept();
1993 if (event
.m_keyCode
== WXK_ESCAPE
)
1995 (*m_accept
) = FALSE
;
1998 if (!wxPendingDelete
.Member(this))
1999 wxPendingDelete
.Append(this);
2007 void wxListTextCtrl::OnKeyUp( wxKeyEvent
&event
)
2009 // auto-grow the textctrl:
2010 wxSize parentSize
= m_owner
->GetSize();
2011 wxPoint myPos
= GetPosition();
2012 wxSize mySize
= GetSize();
2014 GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM??
2015 if (myPos
.x
+ sx
> parentSize
.x
)
2016 sx
= parentSize
.x
- myPos
.x
;
2024 void wxListTextCtrl::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
2026 if (!wxPendingDelete
.Member(this))
2027 wxPendingDelete
.Append(this);
2029 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2030 m_owner
->OnRenameAccept();
2033 //-----------------------------------------------------------------------------
2035 //-----------------------------------------------------------------------------
2037 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
);
2039 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
)
2040 EVT_PAINT (wxListMainWindow::OnPaint
)
2041 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse
)
2042 EVT_CHAR (wxListMainWindow::OnChar
)
2043 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown
)
2044 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus
)
2045 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus
)
2046 EVT_SCROLLWIN (wxListMainWindow::OnScroll
)
2049 void wxListMainWindow::Init()
2051 m_columns
.DeleteContents( TRUE
);
2055 m_lineTo
= (size_t)-1;
2061 m_small_image_list
= (wxImageList
*) NULL
;
2062 m_normal_image_list
= (wxImageList
*) NULL
;
2064 m_small_spacing
= 30;
2065 m_normal_spacing
= 40;
2069 m_isCreated
= FALSE
;
2071 m_lastOnSame
= FALSE
;
2072 m_renameTimer
= new wxListRenameTimer( this );
2073 m_renameAccept
= FALSE
;
2078 m_lineBeforeLastClicked
= (size_t)-1;
2081 void wxListMainWindow::InitScrolling()
2083 if ( HasFlag(wxLC_REPORT
) )
2085 m_xScroll
= SCROLL_UNIT_X
;
2086 m_yScroll
= SCROLL_UNIT_Y
;
2090 m_xScroll
= SCROLL_UNIT_Y
;
2095 wxListMainWindow::wxListMainWindow()
2099 m_highlightBrush
= (wxBrush
*) NULL
;
2105 wxListMainWindow::wxListMainWindow( wxWindow
*parent
,
2110 const wxString
&name
)
2111 : wxScrolledWindow( parent
, id
, pos
, size
,
2112 style
| wxHSCROLL
| wxVSCROLL
, name
)
2116 m_highlightBrush
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
2121 SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 );
2123 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX
) );
2126 wxListMainWindow::~wxListMainWindow()
2130 delete m_highlightBrush
;
2132 delete m_renameTimer
;
2135 void wxListMainWindow::CacheLineData(size_t line
)
2137 wxListCtrl
*listctrl
= GetListCtrl();
2139 wxListLineData
*ld
= GetDummyLine();
2141 size_t countCol
= GetColumnCount();
2142 for ( size_t col
= 0; col
< countCol
; col
++ )
2144 ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
));
2147 ld
->SetImage(listctrl
->OnGetItemImage(line
));
2150 wxListLineData
*wxListMainWindow::GetDummyLine() const
2152 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2154 if ( m_lines
.IsEmpty() )
2156 // normal controls are supposed to have something in m_lines
2157 // already if it's not empty
2158 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2160 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2161 wxListLineData
*line
= new wxListLineData(self
);
2162 self
->m_lines
.Add(line
);
2168 // ----------------------------------------------------------------------------
2169 // line geometry (report mode only)
2170 // ----------------------------------------------------------------------------
2172 wxCoord
wxListMainWindow::GetLineHeight() const
2174 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2176 // we cache the line height as calling GetTextExtent() is slow
2177 if ( !m_lineHeight
)
2179 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2181 wxClientDC
dc( self
);
2182 dc
.SetFont( GetFont() );
2185 dc
.GetTextExtent(_T("H"), NULL
, &y
);
2187 if ( y
< SCROLL_UNIT_Y
)
2191 self
->m_lineHeight
= y
+ LINE_SPACING
;
2194 return m_lineHeight
;
2197 wxCoord
wxListMainWindow::GetLineY(size_t line
) const
2199 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2201 return LINE_SPACING
+ line
*GetLineHeight();
2204 wxRect
wxListMainWindow::GetLineRect(size_t line
) const
2206 if ( !InReportView() )
2207 return GetLine(line
)->m_gi
->m_rectAll
;
2210 rect
.x
= HEADER_OFFSET_X
;
2211 rect
.y
= GetLineY(line
);
2212 rect
.width
= GetHeaderWidth();
2213 rect
.height
= GetLineHeight();
2218 wxRect
wxListMainWindow::GetLineLabelRect(size_t line
) const
2220 if ( !InReportView() )
2221 return GetLine(line
)->m_gi
->m_rectLabel
;
2224 rect
.x
= HEADER_OFFSET_X
;
2225 rect
.y
= GetLineY(line
);
2226 rect
.width
= GetColumnWidth(0);
2227 rect
.height
= GetLineHeight();
2232 wxRect
wxListMainWindow::GetLineIconRect(size_t line
) const
2234 if ( !InReportView() )
2235 return GetLine(line
)->m_gi
->m_rectIcon
;
2237 wxListLineData
*ld
= GetLine(line
);
2238 wxASSERT_MSG( ld
->HasImage(), _T("should have an image") );
2241 rect
.x
= HEADER_OFFSET_X
;
2242 rect
.y
= GetLineY(line
);
2243 GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
);
2248 wxRect
wxListMainWindow::GetLineHighlightRect(size_t line
) const
2250 return InReportView() ? GetLineRect(line
)
2251 : GetLine(line
)->m_gi
->m_rectHighlight
;
2254 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const
2256 wxListLineData
*ld
= GetLine(line
);
2258 if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) )
2259 return wxLIST_HITTEST_ONITEMICON
;
2261 if ( ld
->HasText() )
2263 wxRect rect
= InReportView() ? GetLineRect(line
)
2264 : GetLineLabelRect(line
);
2266 if ( rect
.Inside(x
, y
) )
2267 return wxLIST_HITTEST_ONITEMLABEL
;
2273 // ----------------------------------------------------------------------------
2274 // highlight (selection) handling
2275 // ----------------------------------------------------------------------------
2277 bool wxListMainWindow::IsHighlighted(size_t line
) const
2281 return m_selStore
.IsSelected(line
);
2285 wxListLineData
*ld
= GetLine(line
);
2286 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2288 return ld
->IsHighlighted();
2292 void wxListMainWindow::HighlightLines( size_t lineFrom
, size_t lineTo
, bool highlight
)
2296 m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
);
2297 RefreshLines(lineFrom
, lineTo
);
2301 // do it the dumb way
2302 bool needsRefresh
= FALSE
;
2303 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2305 if ( HighlightLine(line
, highlight
) )
2306 needsRefresh
= TRUE
;
2310 RefreshLines(lineFrom
, lineTo
);
2314 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight
)
2320 changed
= m_selStore
.SelectItem(line
, highlight
);
2324 wxListLineData
*ld
= GetLine(line
);
2325 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2327 changed
= ld
->Highlight(highlight
);
2332 SendNotify( line
, highlight
? wxEVT_COMMAND_LIST_ITEM_SELECTED
2333 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
);
2339 void wxListMainWindow::RefreshLine( size_t line
)
2341 wxRect rect
= GetLineRect(line
);
2343 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2344 RefreshRect( rect
);
2347 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo
)
2349 // we suppose that they are ordered by caller
2350 wxASSERT_MSG( lineFrom
<= lineTo
, _T("indices in disorder") );
2352 wxASSERT_MSG( lineTo
< GetItemCount(), _T("invalid line range") );
2354 if ( HasFlag(wxLC_REPORT
) )
2356 size_t visibleFrom
, visibleTo
;
2357 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2359 if ( lineFrom
< visibleFrom
)
2360 lineFrom
= visibleFrom
;
2361 if ( lineTo
> visibleTo
)
2366 rect
.y
= GetLineY(lineFrom
);
2367 rect
.width
= GetClientSize().x
;
2368 rect
.height
= GetLineY(lineTo
) - rect
.y
;
2370 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2371 RefreshRect( rect
);
2375 // TODO: this should be optimized...
2376 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2383 void wxListMainWindow::RefreshAfter( size_t lineFrom
)
2385 if ( HasFlag(wxLC_REPORT
) )
2388 GetVisibleLinesRange(&visibleFrom
, NULL
);
2390 if ( lineFrom
< visibleFrom
)
2391 lineFrom
= visibleFrom
;
2395 rect
.y
= GetLineY(lineFrom
);
2397 wxSize size
= GetClientSize();
2398 rect
.width
= size
.x
;
2399 // refresh till the bottom of the window
2400 rect
.height
= size
.y
- rect
.y
;
2402 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2403 RefreshRect( rect
);
2407 // TODO: how to do it more efficiently?
2412 void wxListMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2414 // Note: a wxPaintDC must be constructed even if no drawing is
2415 // done (a Windows requirement).
2416 wxPaintDC
dc( this );
2420 // empty control. nothing to draw
2426 // delay the repainting until we calculate all the items positions
2433 CalcScrolledPosition( 0, 0, &dev_x
, &dev_y
);
2437 dc
.SetFont( GetFont() );
2439 if ( HasFlag(wxLC_REPORT
) )
2441 int lineHeight
= GetLineHeight();
2443 size_t visibleFrom
, visibleTo
;
2444 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2447 wxCoord xOrig
, yOrig
;
2448 CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
);
2450 for ( size_t line
= visibleFrom
; line
<= visibleTo
; line
++ )
2452 rectLine
= GetLineRect(line
);
2454 if ( !IsExposed(rectLine
.x
- xOrig
, rectLine
.y
- yOrig
,
2455 rectLine
.width
, rectLine
.height
) )
2457 // don't redraw unaffected lines to avoid flicker
2461 GetLine(line
)->DrawInReportMode( &dc
,
2463 GetLineHighlightRect(line
),
2464 IsHighlighted(line
) );
2467 if ( HasFlag(wxLC_HRULES
) )
2469 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2470 wxSize clientSize
= GetClientSize();
2472 for ( size_t i
= visibleFrom
; i
<= visibleTo
; i
++ )
2475 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2476 dc
.DrawLine(0 - dev_x
, i
*lineHeight
,
2477 clientSize
.x
- dev_x
, i
*lineHeight
);
2480 // Draw last horizontal rule
2481 if ( visibleTo
> visibleFrom
)
2484 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2485 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
,
2486 clientSize
.x
- dev_x
, m_lineTo
*lineHeight
);
2490 // Draw vertical rules if required
2491 if ( HasFlag(wxLC_VRULES
) && !IsEmpty() )
2493 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2496 wxRect firstItemRect
;
2497 wxRect lastItemRect
;
2498 GetItemRect(0, firstItemRect
);
2499 GetItemRect(GetItemCount() - 1, lastItemRect
);
2500 int x
= firstItemRect
.GetX();
2502 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2503 for (col
= 0; col
< GetColumnCount(); col
++)
2505 int colWidth
= GetColumnWidth(col
);
2507 dc
.DrawLine(x
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
,
2508 x
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
);
2514 size_t count
= GetItemCount();
2515 for ( size_t i
= 0; i
< count
; i
++ )
2517 GetLine(i
)->Draw( &dc
);
2521 if ( HasCurrent() && m_hasFocus
)
2524 // no rect outline, we already have the background color
2526 dc
.SetPen( *wxBLACK_PEN
);
2527 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2528 dc
.DrawRectangle( GetLineHighlightRect(m_current
) );
2535 void wxListMainWindow::HighlightAll( bool on
)
2537 if ( IsSingleSel() )
2539 wxASSERT_MSG( !on
, _T("can't do this in a single sel control") );
2541 // we just have one item to turn off
2542 if ( HasCurrent() && IsHighlighted(m_current
) )
2544 HighlightLine(m_current
, FALSE
);
2545 RefreshLine(m_current
);
2550 HighlightLines(0, GetItemCount() - 1, on
);
2554 void wxListMainWindow::SendNotify( size_t line
,
2555 wxEventType command
,
2558 wxListEvent
le( command
, GetParent()->GetId() );
2559 le
.SetEventObject( GetParent() );
2560 le
.m_itemIndex
= line
;
2562 // set only for events which have position
2563 if ( point
!= wxDefaultPosition
)
2564 le
.m_pointDrag
= point
;
2566 GetLine(line
)->GetItem( 0, le
.m_item
);
2567 GetParent()->GetEventHandler()->ProcessEvent( le
);
2570 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) )
2572 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
2575 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) )
2577 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
2580 void wxListMainWindow::EditLabel( long item
)
2582 wxCHECK_RET( (item
>= 0) && ((size_t)item
< GetItemCount()),
2583 wxT("wrong index in wxListCtrl::EditLabel()") );
2585 m_currentEdit
= (size_t)item
;
2587 wxListEvent
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() );
2588 le
.SetEventObject( GetParent() );
2589 le
.m_itemIndex
= item
;
2590 wxListLineData
*data
= GetLine(m_currentEdit
);
2591 wxCHECK_RET( data
, _T("invalid index in EditLabel()") );
2592 data
->GetItem( 0, le
.m_item
);
2593 GetParent()->GetEventHandler()->ProcessEvent( le
);
2595 if (!le
.IsAllowed())
2598 // We have to call this here because the label in question might just have
2599 // been added and no screen update taken place.
2603 wxClientDC
dc(this);
2606 wxString s
= data
->GetText(0);
2607 wxRect rectLabel
= GetLineLabelRect(m_currentEdit
);
2609 rectLabel
.x
= dc
.LogicalToDeviceX( rectLabel
.x
);
2610 rectLabel
.y
= dc
.LogicalToDeviceY( rectLabel
.y
);
2612 wxListTextCtrl
*text
= new wxListTextCtrl
2619 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4),
2620 wxSize(rectLabel
.width
+11,rectLabel
.height
+8)
2625 void wxListMainWindow::OnRenameTimer()
2627 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2629 EditLabel( m_current
);
2632 void wxListMainWindow::OnRenameAccept()
2634 wxListEvent
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() );
2635 le
.SetEventObject( GetParent() );
2636 le
.m_itemIndex
= m_currentEdit
;
2638 wxListLineData
*data
= GetLine(m_currentEdit
);
2639 wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") );
2641 data
->GetItem( 0, le
.m_item
);
2642 le
.m_item
.m_text
= m_renameRes
;
2643 GetParent()->GetEventHandler()->ProcessEvent( le
);
2645 if (!le
.IsAllowed()) return;
2648 info
.m_mask
= wxLIST_MASK_TEXT
;
2649 info
.m_itemId
= le
.m_itemIndex
;
2650 info
.m_text
= m_renameRes
;
2651 info
.SetTextColour(le
.m_item
.GetTextColour());
2655 void wxListMainWindow::OnMouse( wxMouseEvent
&event
)
2657 event
.SetEventObject( GetParent() );
2658 if ( GetParent()->GetEventHandler()->ProcessEvent( event
) )
2661 if ( !HasCurrent() || IsEmpty() )
2667 if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() ||
2668 event
.ButtonDClick()) )
2671 int x
= event
.GetX();
2672 int y
= event
.GetY();
2673 CalcUnscrolledPosition( x
, y
, &x
, &y
);
2675 // where did we hit it (if we did)?
2678 size_t count
= GetItemCount(),
2681 if ( HasFlag(wxLC_REPORT
) )
2683 current
= y
/ GetLineHeight();
2684 if ( current
< count
)
2685 hitResult
= HitTestLine(current
, x
, y
);
2689 // TODO: optimize it too! this is less simple than for report view but
2690 // enumerating all items is still not a way to do it!!
2691 for ( current
= 0; current
< count
; current
++ )
2693 hitResult
= HitTestLine(current
, x
, y
);
2699 if (event
.Dragging())
2701 if (m_dragCount
== 0)
2702 m_dragStart
= wxPoint(x
,y
);
2706 if (m_dragCount
!= 3)
2709 int command
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2710 : wxEVT_COMMAND_LIST_BEGIN_DRAG
;
2712 wxListEvent
le( command
, GetParent()->GetId() );
2713 le
.SetEventObject( GetParent() );
2714 le
.m_pointDrag
= m_dragStart
;
2715 GetParent()->GetEventHandler()->ProcessEvent( le
);
2726 // outside of any item
2730 bool forceClick
= FALSE
;
2731 if (event
.ButtonDClick())
2733 m_renameTimer
->Stop();
2734 m_lastOnSame
= FALSE
;
2736 if ( current
== m_lineBeforeLastClicked
)
2738 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED
);
2744 // the first click was on another item, so don't interpret this as
2745 // a double click, but as a simple click instead
2750 if (event
.LeftUp() && m_lastOnSame
)
2752 if ((current
== m_current
) &&
2753 (hitResult
== wxLIST_HITTEST_ONITEMLABEL
) &&
2754 HasFlag(wxLC_EDIT_LABELS
) )
2756 m_renameTimer
->Start( 100, TRUE
);
2758 m_lastOnSame
= FALSE
;
2760 else if (event
.RightDown())
2762 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
,
2763 event
.GetPosition() );
2765 else if (event
.MiddleDown())
2767 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
);
2769 else if ( event
.LeftDown() || forceClick
)
2771 m_lineBeforeLastClicked
= m_lineLastClicked
;
2772 m_lineLastClicked
= current
;
2774 size_t oldCurrent
= m_current
;
2776 if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) )
2778 HighlightAll( FALSE
);
2779 m_current
= current
;
2781 ReverseHighlight(m_current
);
2783 else // multi sel & either ctrl or shift is down
2785 if (event
.ControlDown())
2787 m_current
= current
;
2789 ReverseHighlight(m_current
);
2791 else if (event
.ShiftDown())
2793 m_current
= current
;
2795 size_t lineFrom
= oldCurrent
,
2798 if ( lineTo
< lineFrom
)
2801 lineFrom
= m_current
;
2804 HighlightLines(lineFrom
, lineTo
);
2806 else // !ctrl, !shift
2808 // test in the enclosing if should make it impossible
2809 wxFAIL_MSG( _T("how did we get here?") );
2813 if (m_current
!= oldCurrent
)
2815 RefreshLine( oldCurrent
);
2816 OnUnfocusLine( oldCurrent
);
2817 OnFocusLine( m_current
);
2820 // forceClick is only set if the previous click was on another item
2821 m_lastOnSame
= !forceClick
&& (m_current
== oldCurrent
);
2825 void wxListMainWindow::MoveToFocus()
2827 if ( !HasCurrent() )
2830 wxRect rect
= GetLineRect(m_current
);
2832 int client_w
, client_h
;
2833 GetClientSize( &client_w
, &client_h
);
2835 int view_x
= m_xScroll
*GetScrollPos( wxHORIZONTAL
);
2836 int view_y
= m_yScroll
*GetScrollPos( wxVERTICAL
);
2838 if ( HasFlag(wxLC_REPORT
) )
2840 // the next we need the range of lines shown it might be different, so
2842 ResetVisibleLinesRange();
2844 if (rect
.y
< view_y
)
2845 Scroll( -1, rect
.y
/m_yScroll
);
2846 if (rect
.y
+rect
.height
+5 > view_y
+client_h
)
2847 Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll
);
2851 if (rect
.x
-view_x
< 5)
2852 Scroll( (rect
.x
-5)/m_xScroll
, -1 );
2853 if (rect
.x
+rect
.width
-5 > view_x
+client_w
)
2854 Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 );
2858 // ----------------------------------------------------------------------------
2859 // keyboard handling
2860 // ----------------------------------------------------------------------------
2862 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
2864 wxCHECK_RET( newCurrent
< (size_t)GetItemCount(),
2865 _T("invalid item index in OnArrowChar()") );
2867 size_t oldCurrent
= m_current
;
2869 // in single selection we just ignore Shift as we can't select several
2871 if ( event
.ShiftDown() && !IsSingleSel() )
2873 m_current
= newCurrent
;
2875 // select all the items between the old and the new one
2876 if ( oldCurrent
> newCurrent
)
2878 newCurrent
= oldCurrent
;
2879 oldCurrent
= m_current
;
2882 HighlightLines(oldCurrent
, newCurrent
);
2886 // all previously selected items are unselected unless ctrl is held
2887 if ( !event
.ControlDown() )
2888 HighlightAll(FALSE
);
2890 m_current
= newCurrent
;
2892 HighlightLine( oldCurrent
, FALSE
);
2893 RefreshLine( oldCurrent
);
2895 if ( !event
.ControlDown() )
2897 HighlightLine( m_current
, TRUE
);
2901 OnUnfocusLine( oldCurrent
);
2902 OnFocusLine( m_current
);
2903 RefreshLine( m_current
);
2908 void wxListMainWindow::OnKeyDown( wxKeyEvent
&event
)
2910 wxWindow
*parent
= GetParent();
2912 /* we propagate the key event up */
2913 wxKeyEvent
ke( wxEVT_KEY_DOWN
);
2914 ke
.m_shiftDown
= event
.m_shiftDown
;
2915 ke
.m_controlDown
= event
.m_controlDown
;
2916 ke
.m_altDown
= event
.m_altDown
;
2917 ke
.m_metaDown
= event
.m_metaDown
;
2918 ke
.m_keyCode
= event
.m_keyCode
;
2921 ke
.SetEventObject( parent
);
2922 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2927 void wxListMainWindow::OnChar( wxKeyEvent
&event
)
2929 wxWindow
*parent
= GetParent();
2931 /* we send a list_key event up */
2934 wxListEvent
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() );
2935 le
.m_itemIndex
= m_current
;
2936 GetLine(m_current
)->GetItem( 0, le
.m_item
);
2937 le
.m_code
= (int)event
.KeyCode();
2938 le
.SetEventObject( parent
);
2939 parent
->GetEventHandler()->ProcessEvent( le
);
2942 /* we propagate the char event up */
2943 wxKeyEvent
ke( wxEVT_CHAR
);
2944 ke
.m_shiftDown
= event
.m_shiftDown
;
2945 ke
.m_controlDown
= event
.m_controlDown
;
2946 ke
.m_altDown
= event
.m_altDown
;
2947 ke
.m_metaDown
= event
.m_metaDown
;
2948 ke
.m_keyCode
= event
.m_keyCode
;
2951 ke
.SetEventObject( parent
);
2952 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
2954 if (event
.KeyCode() == WXK_TAB
)
2956 wxNavigationKeyEvent nevent
;
2957 nevent
.SetWindowChange( event
.ControlDown() );
2958 nevent
.SetDirection( !event
.ShiftDown() );
2959 nevent
.SetEventObject( GetParent()->GetParent() );
2960 nevent
.SetCurrentFocus( m_parent
);
2961 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
)) return;
2964 /* no item -> nothing to do */
2971 switch (event
.KeyCode())
2974 if ( m_current
> 0 )
2975 OnArrowChar( m_current
- 1, event
);
2979 if ( m_current
< (size_t)GetItemCount() - 1 )
2980 OnArrowChar( m_current
+ 1, event
);
2985 OnArrowChar( GetItemCount() - 1, event
);
2990 OnArrowChar( 0, event
);
2996 if ( HasFlag(wxLC_REPORT
) )
2998 steps
= m_linesPerPage
- 1;
3002 steps
= m_current
% m_linesPerPage
;
3005 int index
= m_current
- steps
;
3009 OnArrowChar( index
, event
);
3016 if ( HasFlag(wxLC_REPORT
) )
3018 steps
= m_linesPerPage
- 1;
3022 steps
= m_linesPerPage
- (m_current
% m_linesPerPage
) - 1;
3025 size_t index
= m_current
+ steps
;
3026 size_t count
= GetItemCount();
3027 if ( index
>= count
)
3030 OnArrowChar( index
, event
);
3035 if ( !HasFlag(wxLC_REPORT
) )
3037 int index
= m_current
- m_linesPerPage
;
3041 OnArrowChar( index
, event
);
3046 if ( !HasFlag(wxLC_REPORT
) )
3048 size_t index
= m_current
+ m_linesPerPage
;
3050 size_t count
= GetItemCount();
3051 if ( index
>= count
)
3054 OnArrowChar( index
, event
);
3059 if ( IsSingleSel() )
3061 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3062 GetParent()->GetId() );
3063 le
.SetEventObject( GetParent() );
3064 le
.m_itemIndex
= m_current
;
3065 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3066 GetParent()->GetEventHandler()->ProcessEvent( le
);
3070 ReverseHighlight(m_current
);
3077 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3078 GetParent()->GetId() );
3079 le
.SetEventObject( GetParent() );
3080 le
.m_itemIndex
= m_current
;
3081 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3082 GetParent()->GetEventHandler()->ProcessEvent( le
);
3091 // ----------------------------------------------------------------------------
3093 // ----------------------------------------------------------------------------
3096 extern wxWindow
*g_focusWindow
;
3099 void wxListMainWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
3104 RefreshLine( m_current
);
3110 g_focusWindow
= GetParent();
3113 wxFocusEvent
event( wxEVT_SET_FOCUS
, GetParent()->GetId() );
3114 event
.SetEventObject( GetParent() );
3115 GetParent()->GetEventHandler()->ProcessEvent( event
);
3118 void wxListMainWindow::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
3123 RefreshLine( m_current
);
3126 void wxListMainWindow::DrawImage( int index
, wxDC
*dc
, int x
, int y
)
3128 if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
))
3130 m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3132 else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
))
3134 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3136 else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
))
3138 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3140 else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
))
3142 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3146 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height
) const
3148 if ( HasFlag(wxLC_ICON
) && m_normal_image_list
)
3150 m_normal_image_list
->GetSize( index
, width
, height
);
3152 else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list
)
3154 m_small_image_list
->GetSize( index
, width
, height
);
3156 else if ( HasFlag(wxLC_LIST
) && m_small_image_list
)
3158 m_small_image_list
->GetSize( index
, width
, height
);
3160 else if ( HasFlag(wxLC_REPORT
) && m_small_image_list
)
3162 m_small_image_list
->GetSize( index
, width
, height
);
3171 int wxListMainWindow::GetTextLength( const wxString
&s
) const
3173 wxClientDC
dc( wxConstCast(this, wxListMainWindow
) );
3174 dc
.SetFont( GetFont() );
3177 dc
.GetTextExtent( s
, &lw
, NULL
);
3179 return lw
+ AUTOSIZE_COL_MARGIN
;
3182 void wxListMainWindow::SetImageList( wxImageList
*imageList
, int which
)
3186 // calc the spacing from the icon size
3189 if ((imageList
) && (imageList
->GetImageCount()) )
3191 imageList
->GetSize(0, width
, height
);
3194 if (which
== wxIMAGE_LIST_NORMAL
)
3196 m_normal_image_list
= imageList
;
3197 m_normal_spacing
= width
+ 8;
3200 if (which
== wxIMAGE_LIST_SMALL
)
3202 m_small_image_list
= imageList
;
3203 m_small_spacing
= width
+ 14;
3207 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall
)
3212 m_small_spacing
= spacing
;
3216 m_normal_spacing
= spacing
;
3220 int wxListMainWindow::GetItemSpacing( bool isSmall
)
3222 return isSmall
? m_small_spacing
: m_normal_spacing
;
3225 // ----------------------------------------------------------------------------
3227 // ----------------------------------------------------------------------------
3229 void wxListMainWindow::SetColumn( int col
, wxListItem
&item
)
3231 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3233 wxCHECK_RET( node
, _T("invalid column index in SetColumn") );
3235 if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3236 item
.m_width
= GetTextLength( item
.m_text
);
3238 wxListHeaderData
*column
= node
->GetData();
3239 column
->SetItem( item
);
3241 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3243 headerWin
->m_dirty
= TRUE
;
3247 // invalidate it as it has to be recalculated
3251 void wxListMainWindow::SetColumnWidth( int col
, int width
)
3253 wxCHECK_RET( col
>= 0 && col
< GetColumnCount(),
3254 _T("invalid column index") );
3256 wxCHECK_RET( HasFlag(wxLC_REPORT
),
3257 _T("SetColumnWidth() can only be called in report mode.") );
3261 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3262 wxCHECK_RET( node
, _T("no column?") );
3264 wxListHeaderData
*column
= node
->GetData();
3266 size_t count
= GetItemCount();
3268 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
3270 width
= GetTextLength(column
->GetText());
3272 else if ( width
== wxLIST_AUTOSIZE
)
3276 // TODO: determine the max width somehow...
3277 width
= WIDTH_COL_DEFAULT
;
3281 wxClientDC
dc(this);
3282 dc
.SetFont( GetFont() );
3284 int max
= AUTOSIZE_COL_MARGIN
;
3286 for ( size_t i
= 0; i
< count
; i
++ )
3288 wxListLineData
*line
= GetLine(i
);
3289 wxListItemDataList::Node
*n
= line
->m_items
.Item( col
);
3291 wxCHECK_RET( n
, _T("no subitem?") );
3293 wxListItemData
*item
= n
->GetData();
3296 if (item
->HasImage())
3299 GetImageSize( item
->GetImage(), ix
, iy
);
3303 if (item
->HasText())
3306 dc
.GetTextExtent( item
->GetText(), &w
, NULL
);
3314 width
= max
+ AUTOSIZE_COL_MARGIN
;
3318 column
->SetWidth( width
);
3320 // invalidate it as it has to be recalculated
3324 int wxListMainWindow::GetHeaderWidth() const
3326 if ( !m_headerWidth
)
3328 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
3330 size_t count
= GetColumnCount();
3331 for ( size_t col
= 0; col
< count
; col
++ )
3333 self
->m_headerWidth
+= GetColumnWidth(col
);
3337 return m_headerWidth
;
3340 void wxListMainWindow::GetColumn( int col
, wxListItem
&item
) const
3342 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3343 wxCHECK_RET( node
, _T("invalid column index in GetColumn") );
3345 wxListHeaderData
*column
= node
->GetData();
3346 column
->GetItem( item
);
3349 int wxListMainWindow::GetColumnWidth( int col
) const
3351 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3352 wxCHECK_MSG( node
, 0, _T("invalid column index") );
3354 wxListHeaderData
*column
= node
->GetData();
3355 return column
->GetWidth();
3358 // ----------------------------------------------------------------------------
3360 // ----------------------------------------------------------------------------
3362 void wxListMainWindow::SetItem( wxListItem
&item
)
3364 long id
= item
.m_itemId
;
3365 wxCHECK_RET( id
>= 0 && (size_t)id
< GetItemCount(),
3366 _T("invalid item index in SetItem") );
3370 // just refresh the line to show the new value of the text/image
3371 RefreshLine((size_t)id
);
3377 wxListLineData
*line
= GetLine((size_t)id
);
3378 if ( HasFlag(wxLC_REPORT
) )
3379 item
.m_width
= GetColumnWidth( item
.m_col
);
3380 line
->SetItem( item
.m_col
, item
);
3384 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask
)
3386 wxCHECK_RET( litem
>= 0 && (size_t)litem
< GetItemCount(),
3387 _T("invalid list ctrl item index in SetItem") );
3389 size_t oldCurrent
= m_current
;
3390 size_t item
= (size_t)litem
; // sdafe because of the check above
3392 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3394 if ( state
& wxLIST_STATE_FOCUSED
)
3396 // don't do anything if this item is already focused
3397 if ( item
!= m_current
)
3399 OnUnfocusLine( m_current
);
3401 OnFocusLine( m_current
);
3403 if ( IsSingleSel() && (oldCurrent
!= (size_t)-1) )
3405 HighlightLine(oldCurrent
, FALSE
);
3406 RefreshLine(oldCurrent
);
3409 RefreshLine( m_current
);
3414 // don't do anything if this item is not focused
3415 if ( item
== m_current
)
3417 OnUnfocusLine( m_current
);
3418 m_current
= (size_t)-1;
3423 if ( stateMask
& wxLIST_STATE_SELECTED
)
3425 bool on
= (state
& wxLIST_STATE_SELECTED
) != 0;
3427 if ( IsSingleSel() )
3431 // selecting the item also makes it the focused one in the
3433 if ( m_current
!= item
)
3435 OnUnfocusLine( m_current
);
3437 OnFocusLine( m_current
);
3439 if ( oldCurrent
!= (size_t)-1 )
3441 HighlightLine( oldCurrent
, FALSE
);
3442 RefreshLine( oldCurrent
);
3448 // only the current item may be selected anyhow
3449 if ( item
!= m_current
)
3454 if ( HighlightLine(item
, on
) )
3461 int wxListMainWindow::GetItemState( long item
, long stateMask
)
3463 wxCHECK_MSG( item
>= 0 && (size_t)item
< GetItemCount(), 0,
3464 _T("invalid list ctrl item index in GetItemState()") );
3466 int ret
= wxLIST_STATE_DONTCARE
;
3468 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3470 if ( (size_t)item
== m_current
)
3471 ret
|= wxLIST_STATE_FOCUSED
;
3474 if ( stateMask
& wxLIST_STATE_SELECTED
)
3476 if ( IsHighlighted(item
) )
3477 ret
|= wxLIST_STATE_SELECTED
;
3483 void wxListMainWindow::GetItem( wxListItem
&item
)
3485 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
< GetItemCount(),
3486 _T("invalid item index in GetItem") );
3488 wxListLineData
*line
= GetLine((size_t)item
.m_itemId
);
3489 line
->GetItem( item
.m_col
, item
);
3492 // ----------------------------------------------------------------------------
3494 // ----------------------------------------------------------------------------
3496 size_t wxListMainWindow::GetItemCount() const
3498 return IsVirtual() ? m_countVirt
: m_lines
.GetCount();
3501 void wxListMainWindow::SetItemCount(long count
)
3503 m_selStore
.SetItemCount(count
);
3504 m_countVirt
= count
;
3509 int wxListMainWindow::GetSelectedItemCount()
3511 // deal with the quick case first
3512 if ( IsSingleSel() )
3514 return HasCurrent() ? IsHighlighted(m_current
) : FALSE
;
3517 // virtual controls remmebers all its selections itself
3519 return m_selStore
.GetSelectedCount();
3521 // TODO: we probably should maintain the number of items selected even for
3522 // non virtual controls as enumerating all lines is really slow...
3523 size_t countSel
= 0;
3524 size_t count
= GetItemCount();
3525 for ( size_t line
= 0; line
< count
; line
++ )
3527 if ( GetLine(line
)->IsHighlighted() )
3534 // ----------------------------------------------------------------------------
3535 // item position/size
3536 // ----------------------------------------------------------------------------
3538 void wxListMainWindow::GetItemRect( long index
, wxRect
&rect
)
3540 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3541 _T("invalid index in GetItemRect") );
3543 rect
= GetLineRect((size_t)index
);
3545 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
3548 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
)
3551 GetItemRect(item
, rect
);
3559 // ----------------------------------------------------------------------------
3560 // geometry calculation
3561 // ----------------------------------------------------------------------------
3563 void wxListMainWindow::RecalculatePositions()
3568 wxClientDC
dc( this );
3569 dc
.SetFont( GetFont() );
3572 if ( HasFlag(wxLC_ICON
) )
3573 iconSpacing
= m_normal_spacing
;
3574 else if ( HasFlag(wxLC_SMALL_ICON
) )
3575 iconSpacing
= m_small_spacing
;
3581 GetClientSize( &clientWidth
, &clientHeight
);
3583 if ( HasFlag(wxLC_REPORT
) )
3585 // all lines have the same height
3586 int lineHeight
= GetLineHeight();
3588 // scroll one line per step
3589 m_yScroll
= lineHeight
;
3591 size_t lineCount
= GetItemCount();
3592 int entireHeight
= lineCount
*lineHeight
+ LINE_SPACING
;
3594 m_linesPerPage
= clientHeight
/ lineHeight
;
3596 ResetVisibleLinesRange();
3598 SetScrollbars( m_xScroll
, m_yScroll
,
3599 (GetHeaderWidth() + m_xScroll
- 1)/m_xScroll
,
3600 (entireHeight
+ m_yScroll
- 1)/m_yScroll
,
3601 GetScrollPos(wxHORIZONTAL
),
3602 GetScrollPos(wxVERTICAL
),
3607 // at first we try without any scrollbar. if the items don't
3608 // fit into the window, we recalculate after subtracting an
3609 // approximated 15 pt for the horizontal scrollbar
3611 clientHeight
-= 4; // sunken frame
3613 int entireWidth
= 0;
3615 for (int tries
= 0; tries
< 2; tries
++)
3622 int currentlyVisibleLines
= 0;
3624 size_t count
= GetItemCount();
3625 for (size_t i
= 0; i
< count
; i
++)
3627 currentlyVisibleLines
++;
3628 wxListLineData
*line
= GetLine(i
);
3629 line
->CalculateSize( &dc
, iconSpacing
);
3630 line
->SetPosition( x
, y
, clientWidth
, iconSpacing
);
3632 wxSize sizeLine
= GetLineSize(i
);
3634 if ( maxWidth
< sizeLine
.x
)
3635 maxWidth
= sizeLine
.x
;
3638 if (currentlyVisibleLines
> m_linesPerPage
)
3639 m_linesPerPage
= currentlyVisibleLines
;
3641 // assume that the size of the next one is the same... (FIXME)
3642 if ( y
+ sizeLine
.y
- 6 >= clientHeight
)
3644 currentlyVisibleLines
= 0;
3647 entireWidth
+= maxWidth
+6;
3650 if ( i
== count
- 1 )
3651 entireWidth
+= maxWidth
;
3652 if ((tries
== 0) && (entireWidth
> clientWidth
))
3654 clientHeight
-= 15; // scrollbar height
3656 currentlyVisibleLines
= 0;
3659 if ( i
== count
- 1 )
3660 tries
= 1; // everything fits, no second try required
3664 int scroll_pos
= GetScrollPos( wxHORIZONTAL
);
3665 SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE
);
3668 // FIXME: why should we call it from here?
3674 void wxListMainWindow::RefreshAll()
3679 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3682 headerWin
->m_dirty
= FALSE
;
3683 headerWin
->Refresh();
3687 void wxListMainWindow::UpdateCurrent()
3689 if ( !HasCurrent() && !IsEmpty() )
3694 if ( m_current
!= (size_t)-1 )
3696 OnFocusLine( m_current
);
3700 long wxListMainWindow::GetNextItem( long item
,
3701 int WXUNUSED(geometry
),
3705 max
= GetItemCount();
3706 wxCHECK_MSG( (ret
== -1) || (ret
< max
), -1,
3707 _T("invalid listctrl index in GetNextItem()") );
3709 // notice that we start with the next item (or the first one if item == -1)
3710 // and this is intentional to allow writing a simple loop to iterate over
3711 // all selected items
3715 // this is not an error because the index was ok initially, just no
3726 size_t count
= GetItemCount();
3727 for ( size_t line
= (size_t)ret
; line
< count
; line
++ )
3729 if ( (state
& wxLIST_STATE_FOCUSED
) && (line
== m_current
) )
3732 if ( (state
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) )
3739 // ----------------------------------------------------------------------------
3741 // ----------------------------------------------------------------------------
3743 void wxListMainWindow::DeleteItem( long lindex
)
3745 size_t count
= GetItemCount();
3747 wxCHECK_RET( (lindex
>= 0) && ((size_t)lindex
< count
),
3748 _T("invalid item index in DeleteItem") );
3750 size_t index
= (size_t)lindex
;
3754 // select the next item when the selected one is deleted
3755 if ( m_current
== index
)
3757 // the last valid index after deleting the item will be count-2
3758 if ( m_current
== count
- 1 )
3764 SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
);
3766 if ( InReportView() )
3768 ResetVisibleLinesRange();
3775 m_selStore
.OnItemDelete(index
);
3779 m_lines
.RemoveAt( index
);
3783 RefreshAfter(index
);
3786 void wxListMainWindow::DeleteColumn( int col
)
3788 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3790 wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") );
3793 m_columns
.DeleteNode( node
);
3796 void wxListMainWindow::DeleteAllItems()
3800 // nothing to do - in particular, don't send the event
3808 // to make the deletion of all items faster, we don't send the
3809 // notifications for each item deletion in this case but only one event
3810 // for all of them: this is compatible with wxMSW and documented in
3811 // DeleteAllItems() description
3813 wxListEvent
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() );
3814 event
.SetEventObject( GetParent() );
3815 GetParent()->GetEventHandler()->ProcessEvent( event
);
3821 ResetVisibleLinesRange();
3824 if ( InReportView() )
3826 ResetVisibleLinesRange();
3834 void wxListMainWindow::DeleteEverything()
3841 // ----------------------------------------------------------------------------
3842 // scanning for an item
3843 // ----------------------------------------------------------------------------
3845 void wxListMainWindow::EnsureVisible( long index
)
3847 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3848 _T("invalid index in EnsureVisible") );
3850 // We have to call this here because the label in question might just have
3851 // been added and no screen update taken place.
3855 size_t oldCurrent
= m_current
;
3856 m_current
= (size_t)index
;
3858 m_current
= oldCurrent
;
3861 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) )
3868 size_t count
= GetItemCount();
3869 for ( size_t i
= (size_t)pos
; i
< count
; i
++ )
3871 wxListLineData
*line
= GetLine(i
);
3872 if ( line
->GetText(0) == tmp
)
3879 long wxListMainWindow::FindItem(long start
, long data
)
3885 size_t count
= GetItemCount();
3886 for (size_t i
= (size_t)pos
; i
< count
; i
++)
3888 wxListLineData
*line
= GetLine(i
);
3890 line
->GetItem( 0, item
);
3891 if (item
.m_data
== data
)
3898 long wxListMainWindow::HitTest( int x
, int y
, int &flags
)
3900 CalcUnscrolledPosition( x
, y
, &x
, &y
);
3902 if ( HasFlag(wxLC_REPORT
) )
3904 size_t current
= y
/ GetLineHeight();
3905 flags
= HitTestLine(current
, x
, y
);
3911 // TODO: optimize it too! this is less simple than for report view but
3912 // enumerating all items is still not a way to do it!!
3913 size_t count
= GetItemCount();
3914 for ( size_t current
= 0; current
< count
; current
++ )
3916 flags
= HitTestLine(current
, x
, y
);
3925 // ----------------------------------------------------------------------------
3927 // ----------------------------------------------------------------------------
3929 void wxListMainWindow::InsertItem( wxListItem
&item
)
3931 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
3933 size_t count
= GetItemCount();
3934 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
<= count
,
3935 _T("invalid item index") );
3937 size_t id
= item
.m_itemId
;
3942 if ( HasFlag(wxLC_REPORT
) )
3944 else if ( HasFlag(wxLC_LIST
) )
3946 else if ( HasFlag(wxLC_ICON
) )
3948 else if ( HasFlag(wxLC_SMALL_ICON
) )
3949 mode
= wxLC_ICON
; // no typo
3952 wxFAIL_MSG( _T("unknown mode") );
3955 wxListLineData
*line
= new wxListLineData(this);
3957 line
->SetItem( 0, item
);
3959 m_lines
.Insert( line
, id
);
3962 RefreshLines(id
, GetItemCount() - 1);
3965 void wxListMainWindow::InsertColumn( long col
, wxListItem
&item
)
3968 if ( HasFlag(wxLC_REPORT
) )
3970 if (item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3971 item
.m_width
= GetTextLength( item
.m_text
);
3972 wxListHeaderData
*column
= new wxListHeaderData( item
);
3973 if ((col
>= 0) && (col
< (int)m_columns
.GetCount()))
3975 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3976 m_columns
.Insert( node
, column
);
3980 m_columns
.Append( column
);
3985 // ----------------------------------------------------------------------------
3987 // ----------------------------------------------------------------------------
3989 wxListCtrlCompare list_ctrl_compare_func_2
;
3990 long list_ctrl_compare_data
;
3992 int LINKAGEMODE
list_ctrl_compare_func_1( wxListLineData
**arg1
, wxListLineData
**arg2
)
3994 wxListLineData
*line1
= *arg1
;
3995 wxListLineData
*line2
= *arg2
;
3997 line1
->GetItem( 0, item
);
3998 long data1
= item
.m_data
;
3999 line2
->GetItem( 0, item
);
4000 long data2
= item
.m_data
;
4001 return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data
);
4004 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data
)
4006 list_ctrl_compare_func_2
= fn
;
4007 list_ctrl_compare_data
= data
;
4008 m_lines
.Sort( list_ctrl_compare_func_1
);
4012 // ----------------------------------------------------------------------------
4014 // ----------------------------------------------------------------------------
4016 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
)
4018 // update our idea of which lines are shown when we redraw the window the
4020 ResetVisibleLinesRange();
4023 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4024 wxScrolledWindow::OnScroll(event
);
4026 HandleOnScroll( event
);
4029 if ( event
.GetOrientation() == wxHORIZONTAL
&& HasHeader() )
4031 wxListCtrl
* lc
= GetListCtrl();
4032 wxCHECK_RET( lc
, _T("no listctrl window?") );
4034 lc
->m_headerWin
->Refresh() ;
4036 lc
->m_headerWin
->MacUpdateImmediately() ;
4041 int wxListMainWindow::GetCountPerPage() const
4043 if ( !m_linesPerPage
)
4045 wxConstCast(this, wxListMainWindow
)->
4046 m_linesPerPage
= GetClientSize().y
/ GetLineHeight();
4049 return m_linesPerPage
;
4052 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
)
4054 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") );
4056 if ( m_lineFrom
== (size_t)-1 )
4058 size_t count
= GetItemCount();
4061 m_lineFrom
= GetScrollPos(wxVERTICAL
);
4063 // this may happen if SetScrollbars() hadn't been called yet
4064 if ( m_lineFrom
>= count
)
4065 m_lineFrom
= count
- 1;
4067 // we redraw one extra line but this is needed to make the redrawing
4068 // logic work when there is a fractional number of lines on screen
4069 m_lineTo
= m_lineFrom
+ m_linesPerPage
;
4070 if ( m_lineTo
>= count
)
4071 m_lineTo
= count
- 1;
4073 else // empty control
4076 m_lineTo
= (size_t)-1;
4080 wxASSERT_MSG( IsEmpty() ||
4081 (m_lineFrom
<= m_lineTo
&& m_lineTo
< GetItemCount()),
4082 _T("GetVisibleLinesRange() returns incorrect result") );
4090 // -------------------------------------------------------------------------------------
4092 // -------------------------------------------------------------------------------------
4094 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
4096 wxListItem::wxListItem()
4105 m_format
= wxLIST_FORMAT_CENTRE
;
4111 void wxListItem::Clear()
4120 m_format
= wxLIST_FORMAT_CENTRE
;
4127 void wxListItem::ClearAttributes()
4136 // -------------------------------------------------------------------------------------
4138 // -------------------------------------------------------------------------------------
4140 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
4142 wxListEvent::wxListEvent( wxEventType commandType
, int id
)
4143 : wxNotifyEvent( commandType
, id
)
4149 m_cancelled
= FALSE
;
4154 void wxListEvent::CopyObject(wxObject
& object_dest
) const
4156 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
4158 wxNotifyEvent::CopyObject(object_dest
);
4160 obj
->m_code
= m_code
;
4161 obj
->m_itemIndex
= m_itemIndex
;
4162 obj
->m_oldItemIndex
= m_oldItemIndex
;
4164 obj
->m_cancelled
= m_cancelled
;
4165 obj
->m_pointDrag
= m_pointDrag
;
4166 obj
->m_item
.m_mask
= m_item
.m_mask
;
4167 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
4168 obj
->m_item
.m_col
= m_item
.m_col
;
4169 obj
->m_item
.m_state
= m_item
.m_state
;
4170 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
4171 obj
->m_item
.m_text
= m_item
.m_text
;
4172 obj
->m_item
.m_image
= m_item
.m_image
;
4173 obj
->m_item
.m_data
= m_item
.m_data
;
4174 obj
->m_item
.m_format
= m_item
.m_format
;
4175 obj
->m_item
.m_width
= m_item
.m_width
;
4177 if ( m_item
.HasAttributes() )
4179 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
4183 // -------------------------------------------------------------------------------------
4185 // -------------------------------------------------------------------------------------
4187 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
4189 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
)
4190 EVT_SIZE(wxListCtrl::OnSize
)
4191 EVT_IDLE(wxListCtrl::OnIdle
)
4194 wxListCtrl::wxListCtrl()
4196 m_imageListNormal
= (wxImageList
*) NULL
;
4197 m_imageListSmall
= (wxImageList
*) NULL
;
4198 m_imageListState
= (wxImageList
*) NULL
;
4200 m_ownsImageListNormal
=
4201 m_ownsImageListSmall
=
4202 m_ownsImageListState
= FALSE
;
4204 m_mainWin
= (wxListMainWindow
*) NULL
;
4205 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4208 wxListCtrl::~wxListCtrl()
4211 m_mainWin
->ResetCurrent();
4213 if (m_ownsImageListNormal
)
4214 delete m_imageListNormal
;
4215 if (m_ownsImageListSmall
)
4216 delete m_imageListSmall
;
4217 if (m_ownsImageListState
)
4218 delete m_imageListState
;
4221 void wxListCtrl::CreateHeaderWindow()
4223 m_headerWin
= new wxListHeaderWindow
4225 this, -1, m_mainWin
,
4227 wxSize(GetClientSize().x
, HEADER_HEIGHT
),
4232 bool wxListCtrl::Create(wxWindow
*parent
,
4237 const wxValidator
&validator
,
4238 const wxString
&name
)
4242 m_imageListState
= (wxImageList
*) NULL
;
4243 m_ownsImageListNormal
=
4244 m_ownsImageListSmall
=
4245 m_ownsImageListState
= FALSE
;
4247 m_mainWin
= (wxListMainWindow
*) NULL
;
4248 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4250 if ( !(style
& wxLC_MASK_TYPE
) )
4252 style
= style
| wxLC_LIST
;
4255 if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name
) )
4258 // don't create the inner window with the border
4259 style
&= ~wxSUNKEN_BORDER
;
4261 m_mainWin
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style
);
4263 if ( HasFlag(wxLC_REPORT
) )
4265 CreateHeaderWindow();
4267 if ( HasFlag(wxLC_NO_HEADER
) )
4269 // VZ: why do we create it at all then?
4270 m_headerWin
->Show( FALSE
);
4277 void wxListCtrl::SetSingleStyle( long style
, bool add
)
4279 wxASSERT_MSG( !(style
& wxLC_VIRTUAL
),
4280 _T("wxLC_VIRTUAL can't be [un]set") );
4282 long flag
= GetWindowStyle();
4286 if (style
& wxLC_MASK_TYPE
)
4287 flag
&= ~(wxLC_MASK_TYPE
| wxLC_VIRTUAL
);
4288 if (style
& wxLC_MASK_ALIGN
)
4289 flag
&= ~wxLC_MASK_ALIGN
;
4290 if (style
& wxLC_MASK_SORT
)
4291 flag
&= ~wxLC_MASK_SORT
;
4303 SetWindowStyleFlag( flag
);
4306 void wxListCtrl::SetWindowStyleFlag( long flag
)
4310 m_mainWin
->DeleteEverything();
4314 GetClientSize( &width
, &height
);
4316 if (flag
& wxLC_REPORT
)
4318 if (!HasFlag(wxLC_REPORT
))
4322 CreateHeaderWindow();
4324 if (HasFlag(wxLC_NO_HEADER
))
4325 m_headerWin
->Show( FALSE
);
4329 if (flag
& wxLC_NO_HEADER
)
4330 m_headerWin
->Show( FALSE
);
4332 m_headerWin
->Show( TRUE
);
4338 if ( m_mainWin
->HasHeader() )
4340 m_headerWin
->Show( FALSE
);
4345 wxWindow::SetWindowStyleFlag( flag
);
4348 bool wxListCtrl::GetColumn(int col
, wxListItem
&item
) const
4350 m_mainWin
->GetColumn( col
, item
);
4354 bool wxListCtrl::SetColumn( int col
, wxListItem
& item
)
4356 m_mainWin
->SetColumn( col
, item
);
4360 int wxListCtrl::GetColumnWidth( int col
) const
4362 return m_mainWin
->GetColumnWidth( col
);
4365 bool wxListCtrl::SetColumnWidth( int col
, int width
)
4367 m_mainWin
->SetColumnWidth( col
, width
);
4371 int wxListCtrl::GetCountPerPage() const
4373 return m_mainWin
->GetCountPerPage(); // different from Windows ?
4376 bool wxListCtrl::GetItem( wxListItem
&info
) const
4378 m_mainWin
->GetItem( info
);
4382 bool wxListCtrl::SetItem( wxListItem
&info
)
4384 m_mainWin
->SetItem( info
);
4388 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId
)
4391 info
.m_text
= label
;
4392 info
.m_mask
= wxLIST_MASK_TEXT
;
4393 info
.m_itemId
= index
;
4397 info
.m_image
= imageId
;
4398 info
.m_mask
|= wxLIST_MASK_IMAGE
;
4400 m_mainWin
->SetItem(info
);
4404 int wxListCtrl::GetItemState( long item
, long stateMask
) const
4406 return m_mainWin
->GetItemState( item
, stateMask
);
4409 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask
)
4411 m_mainWin
->SetItemState( item
, state
, stateMask
);
4415 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) )
4418 info
.m_image
= image
;
4419 info
.m_mask
= wxLIST_MASK_IMAGE
;
4420 info
.m_itemId
= item
;
4421 m_mainWin
->SetItem( info
);
4425 wxString
wxListCtrl::GetItemText( long item
) const
4428 info
.m_itemId
= item
;
4429 m_mainWin
->GetItem( info
);
4433 void wxListCtrl::SetItemText( long item
, const wxString
&str
)
4436 info
.m_mask
= wxLIST_MASK_TEXT
;
4437 info
.m_itemId
= item
;
4439 m_mainWin
->SetItem( info
);
4442 long wxListCtrl::GetItemData( long item
) const
4445 info
.m_itemId
= item
;
4446 m_mainWin
->GetItem( info
);
4450 bool wxListCtrl::SetItemData( long item
, long data
)
4453 info
.m_mask
= wxLIST_MASK_DATA
;
4454 info
.m_itemId
= item
;
4456 m_mainWin
->SetItem( info
);
4460 bool wxListCtrl::GetItemRect( long item
, wxRect
&rect
, int WXUNUSED(code
) ) const
4462 m_mainWin
->GetItemRect( item
, rect
);
4466 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos
) const
4468 m_mainWin
->GetItemPosition( item
, pos
);
4472 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) )
4477 int wxListCtrl::GetItemCount() const
4479 return m_mainWin
->GetItemCount();
4482 int wxListCtrl::GetColumnCount() const
4484 return m_mainWin
->GetColumnCount();
4487 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall
)
4489 m_mainWin
->SetItemSpacing( spacing
, isSmall
);
4492 int wxListCtrl::GetItemSpacing( bool isSmall
) const
4494 return m_mainWin
->GetItemSpacing( isSmall
);
4497 int wxListCtrl::GetSelectedItemCount() const
4499 return m_mainWin
->GetSelectedItemCount();
4502 wxColour
wxListCtrl::GetTextColour() const
4504 return GetForegroundColour();
4507 void wxListCtrl::SetTextColour(const wxColour
& col
)
4509 SetForegroundColour(col
);
4512 long wxListCtrl::GetTopItem() const
4517 long wxListCtrl::GetNextItem( long item
, int geom
, int state
) const
4519 return m_mainWin
->GetNextItem( item
, geom
, state
);
4522 wxImageList
*wxListCtrl::GetImageList(int which
) const
4524 if (which
== wxIMAGE_LIST_NORMAL
)
4526 return m_imageListNormal
;
4528 else if (which
== wxIMAGE_LIST_SMALL
)
4530 return m_imageListSmall
;
4532 else if (which
== wxIMAGE_LIST_STATE
)
4534 return m_imageListState
;
4536 return (wxImageList
*) NULL
;
4539 void wxListCtrl::SetImageList( wxImageList
*imageList
, int which
)
4541 if ( which
== wxIMAGE_LIST_NORMAL
)
4543 if (m_ownsImageListNormal
) delete m_imageListNormal
;
4544 m_imageListNormal
= imageList
;
4545 m_ownsImageListNormal
= FALSE
;
4547 else if ( which
== wxIMAGE_LIST_SMALL
)
4549 if (m_ownsImageListSmall
) delete m_imageListSmall
;
4550 m_imageListSmall
= imageList
;
4551 m_ownsImageListSmall
= FALSE
;
4553 else if ( which
== wxIMAGE_LIST_STATE
)
4555 if (m_ownsImageListState
) delete m_imageListState
;
4556 m_imageListState
= imageList
;
4557 m_ownsImageListState
= FALSE
;
4560 m_mainWin
->SetImageList( imageList
, which
);
4563 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
4565 SetImageList(imageList
, which
);
4566 if ( which
== wxIMAGE_LIST_NORMAL
)
4567 m_ownsImageListNormal
= TRUE
;
4568 else if ( which
== wxIMAGE_LIST_SMALL
)
4569 m_ownsImageListSmall
= TRUE
;
4570 else if ( which
== wxIMAGE_LIST_STATE
)
4571 m_ownsImageListState
= TRUE
;
4574 bool wxListCtrl::Arrange( int WXUNUSED(flag
) )
4579 bool wxListCtrl::DeleteItem( long item
)
4581 m_mainWin
->DeleteItem( item
);
4585 bool wxListCtrl::DeleteAllItems()
4587 m_mainWin
->DeleteAllItems();
4591 bool wxListCtrl::DeleteAllColumns()
4593 size_t count
= m_mainWin
->m_columns
.GetCount();
4594 for ( size_t n
= 0; n
< count
; n
++ )
4600 void wxListCtrl::ClearAll()
4602 m_mainWin
->DeleteEverything();
4605 bool wxListCtrl::DeleteColumn( int col
)
4607 m_mainWin
->DeleteColumn( col
);
4611 void wxListCtrl::Edit( long item
)
4613 m_mainWin
->EditLabel( item
);
4616 bool wxListCtrl::EnsureVisible( long item
)
4618 m_mainWin
->EnsureVisible( item
);
4622 long wxListCtrl::FindItem( long start
, const wxString
& str
, bool partial
)
4624 return m_mainWin
->FindItem( start
, str
, partial
);
4627 long wxListCtrl::FindItem( long start
, long data
)
4629 return m_mainWin
->FindItem( start
, data
);
4632 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
),
4633 int WXUNUSED(direction
))
4638 long wxListCtrl::HitTest( const wxPoint
&point
, int &flags
)
4640 return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags
);
4643 long wxListCtrl::InsertItem( wxListItem
& info
)
4645 m_mainWin
->InsertItem( info
);
4646 return info
.m_itemId
;
4649 long wxListCtrl::InsertItem( long index
, const wxString
&label
)
4652 info
.m_text
= label
;
4653 info
.m_mask
= wxLIST_MASK_TEXT
;
4654 info
.m_itemId
= index
;
4655 return InsertItem( info
);
4658 long wxListCtrl::InsertItem( long index
, int imageIndex
)
4661 info
.m_mask
= wxLIST_MASK_IMAGE
;
4662 info
.m_image
= imageIndex
;
4663 info
.m_itemId
= index
;
4664 return InsertItem( info
);
4667 long wxListCtrl::InsertItem( long index
, const wxString
&label
, int imageIndex
)
4670 info
.m_text
= label
;
4671 info
.m_image
= imageIndex
;
4672 info
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_IMAGE
;
4673 info
.m_itemId
= index
;
4674 return InsertItem( info
);
4677 long wxListCtrl::InsertColumn( long col
, wxListItem
&item
)
4679 wxASSERT( m_headerWin
);
4680 m_mainWin
->InsertColumn( col
, item
);
4681 m_headerWin
->Refresh();
4686 long wxListCtrl::InsertColumn( long col
, const wxString
&heading
,
4687 int format
, int width
)
4690 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
4691 item
.m_text
= heading
;
4694 item
.m_mask
|= wxLIST_MASK_WIDTH
;
4695 item
.m_width
= width
;
4697 item
.m_format
= format
;
4699 return InsertColumn( col
, item
);
4702 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) )
4708 // fn is a function which takes 3 long arguments: item1, item2, data.
4709 // item1 is the long data associated with a first item (NOT the index).
4710 // item2 is the long data associated with a second item (NOT the index).
4711 // data is the same value as passed to SortItems.
4712 // The return value is a negative number if the first item should precede the second
4713 // item, a positive number of the second item should precede the first,
4714 // or zero if the two items are equivalent.
4715 // data is arbitrary data to be passed to the sort function.
4717 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data
)
4719 m_mainWin
->SortItems( fn
, data
);
4723 // ----------------------------------------------------------------------------
4725 // ----------------------------------------------------------------------------
4727 void wxListCtrl::OnSize(wxSizeEvent
& event
)
4733 GetClientSize( &cw
, &ch
);
4735 if ( m_mainWin
->HasHeader() )
4737 m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT
);
4738 m_mainWin
->SetSize( 0, HEADER_HEIGHT
+ 1, cw
, ch
- HEADER_HEIGHT
- 1 );
4740 else // no header window
4742 m_mainWin
->SetSize( 0, 0, cw
, ch
);
4745 m_mainWin
->RecalculatePositions();
4748 void wxListCtrl::OnIdle( wxIdleEvent
& event
)
4752 // do it only if needed
4753 if ( !m_mainWin
->m_dirty
)
4756 m_mainWin
->RecalculatePositions();
4759 // ----------------------------------------------------------------------------
4761 // ----------------------------------------------------------------------------
4763 bool wxListCtrl::SetBackgroundColour( const wxColour
&colour
)
4767 m_mainWin
->SetBackgroundColour( colour
);
4768 m_mainWin
->m_dirty
= TRUE
;
4774 bool wxListCtrl::SetForegroundColour( const wxColour
&colour
)
4776 if ( !wxWindow::SetForegroundColour( colour
) )
4781 m_mainWin
->SetForegroundColour( colour
);
4782 m_mainWin
->m_dirty
= TRUE
;
4787 m_headerWin
->SetForegroundColour( colour
);
4793 bool wxListCtrl::SetFont( const wxFont
&font
)
4795 if ( !wxWindow::SetFont( font
) )
4800 m_mainWin
->SetFont( font
);
4801 m_mainWin
->m_dirty
= TRUE
;
4806 m_headerWin
->SetFont( font
);
4812 // ----------------------------------------------------------------------------
4813 // methods forwarded to m_mainWin
4814 // ----------------------------------------------------------------------------
4816 #if wxUSE_DRAG_AND_DROP
4818 void wxListCtrl::SetDropTarget( wxDropTarget
*dropTarget
)
4820 m_mainWin
->SetDropTarget( dropTarget
);
4823 wxDropTarget
*wxListCtrl::GetDropTarget() const
4825 return m_mainWin
->GetDropTarget();
4828 #endif // wxUSE_DRAG_AND_DROP
4830 bool wxListCtrl::SetCursor( const wxCursor
&cursor
)
4832 return m_mainWin
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
;
4835 wxColour
wxListCtrl::GetBackgroundColour() const
4837 return m_mainWin
? m_mainWin
->GetBackgroundColour() : wxColour();
4840 wxColour
wxListCtrl::GetForegroundColour() const
4842 return m_mainWin
? m_mainWin
->GetForegroundColour() : wxColour();
4845 bool wxListCtrl::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4848 return m_mainWin
->PopupMenu( menu
, x
, y
);
4851 #endif // wxUSE_MENUS
4854 void wxListCtrl::SetFocus()
4856 /* The test in window.cpp fails as we are a composite
4857 window, so it checks against "this", but not m_mainWin. */
4858 if ( FindFocus() != this )
4859 m_mainWin
->SetFocus();
4862 // ----------------------------------------------------------------------------
4863 // virtual list control support
4864 // ----------------------------------------------------------------------------
4866 wxString
wxListCtrl::OnGetItemText(long item
, long col
) const
4868 // this is a pure virtual function, in fact - which is not really pure
4869 // because the controls which are not virtual don't need to implement it
4870 wxFAIL_MSG( _T("not supposed to be called") );
4872 return wxEmptyString
;
4875 int wxListCtrl::OnGetItemImage(long item
) const
4878 wxFAIL_MSG( _T("not supposed to be called") );
4883 void wxListCtrl::SetItemCount(long count
)
4885 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4887 m_mainWin
->SetItemCount(count
);
4890 #endif // wxUSE_LISTCTRL