1 /////////////////////////////////////////////////////////////////////////////
2 // Name: generic/listctrl.cpp
3 // Purpose: generic implementation of wxListCtrl
4 // Author: Robert Roebling
5 // Vadim Zeitlin (virtual list control support)
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
12 FIXME for virtual list controls
14 +1. clicking on the item with a mouse is awfully slow, what is going on?
15 note that selecting with keyboard seems to be much faster
16 => fixed HighlightAll() - iterating over 1000000 items *is* slow
18 2. background colour is wrong?
22 TODO for better virtual list control support:
24 1. less dumb line caching, we should cache at least all those visible
25 in the control itself and probably twice as many (we might also need to
26 cache the first one always for geometry calculations?)
28 +2. storing selections: we can't use an array to store the selected indices
29 like right now as selecting all in a control with 1000000 items is not
30 doable like this - instead, store selections as collection of individual
35 3. we need to implement searching/sorting somehow
37 4. the idea of storing the line index in the line itself is really stupid,
38 we shouldn't need it - but for this we have to get rid of all calles to
39 wxListLineData::GetFoo() and replace them with something like
41 ... we have it ourselves ...
47 5. attributes support: we need OnGetItemAttr() as well!
50 // ============================================================================
52 // ============================================================================
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
59 #pragma implementation "listctrl.h"
60 #pragma implementation "listctrlbase.h"
63 // For compilers that support precompilation, includes "wx.h".
64 #include "wx/wxprec.h"
72 #include "wx/dcscreen.h"
74 #include "wx/listctrl.h"
75 #include "wx/imaglist.h"
76 #include "wx/dynarray.h"
80 #include "wx/gtk/win_gtk.h"
83 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
)
88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
)
89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
)
90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
)
91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
)
92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
)
93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
)
94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
)
95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
)
96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
)
97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
)
98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
)
99 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
)
100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
)
101 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
)
102 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
)
103 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
)
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 // the height of the header window (FIXME: should depend on its font!)
110 static const int HEADER_HEIGHT
= 23;
112 // the scrollbar units
113 static const int SCROLL_UNIT_X
= 15;
114 static const int SCROLL_UNIT_Y
= 15;
116 // the spacing between the lines (in report mode)
117 static const int LINE_SPACING
= 0;
119 // extra margins around the text label
120 static const int EXTRA_WIDTH
= 3;
121 static const int EXTRA_HEIGHT
= 4;
123 // offset for the header window
124 static const int HEADER_OFFSET_X
= 1;
125 static const int HEADER_OFFSET_Y
= 1;
127 // when autosizing the columns, add some slack
128 static const int AUTOSIZE_COL_MARGIN
= 10;
130 // default and minimal widths for the header columns
131 static const int WIDTH_COL_DEFAULT
= 80;
132 static const int WIDTH_COL_MIN
= 10;
134 // ============================================================================
136 // ============================================================================
138 // ----------------------------------------------------------------------------
140 // ----------------------------------------------------------------------------
142 int CMPFUNC_CONV
wxSizeTCmpFn(size_t n1
, size_t n2
) { return n1
- n2
; }
144 WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray
);
146 // this class is used to store the selected items in the virtual list control
147 // (but it is not tied to list control and so can be used with other controls
148 // such as wxListBox in wxUniv)
150 // the idea is to make it really smart later (i.e. store the selections as an
151 // array of ranes + individual items) but, as I don't have time to do it now
152 // (this would require writing code to merge/break ranges and much more) keep
153 // it simple but define a clean interface to it which allows it to be made
155 class WXDLLEXPORT wxSelectionStore
158 wxSelectionStore() : m_itemsSel(wxSizeTCmpFn
) { Init(); }
160 // set the total number of items we handle
161 void SetItemCount(size_t count
) { m_count
= count
; }
163 // special case of SetItemCount(0)
164 void Clear() { m_itemsSel
.Clear(); m_count
= 0; }
166 // must be called when a new item is inserted/added
167 void OnItemAdd(size_t item
) { wxFAIL_MSG( _T("TODO") ); }
169 // must be called when an item is deleted
170 void OnItemDelete(size_t item
);
172 // select one item, use SelectRange() insted if possible!
174 // returns true if the items selection really changed
175 bool SelectItem(size_t item
, bool select
= TRUE
);
177 // select the range of items
178 void SelectRange(size_t itemFrom
, size_t itemTo
, bool select
= TRUE
);
180 // return true if the given item is selected
181 bool IsSelected(size_t item
) const;
183 // return the total number of selected items
184 size_t GetSelectedCount() const
186 return m_defaultState
? m_count
- m_itemsSel
.GetCount()
187 : m_itemsSel
.GetCount();
192 void Init() { m_defaultState
= FALSE
; }
194 // the total number of items we handle
197 // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
198 // there are more selected items than non selected ones - this allows to
199 // handle selection of all items efficiently
202 // the array of items whose selection state is different from default
203 wxIndexArray m_itemsSel
;
205 DECLARE_NO_COPY_CLASS(wxSelectionStore
)
208 //-----------------------------------------------------------------------------
209 // wxListItemData (internal)
210 //-----------------------------------------------------------------------------
212 class WXDLLEXPORT wxListItemData
215 wxListItemData(wxListMainWindow
*owner
);
218 void SetItem( const wxListItem
&info
);
219 void SetImage( int image
) { m_image
= image
; }
220 void SetData( long data
) { m_data
= data
; }
221 void SetPosition( int x
, int y
);
222 void SetSize( int width
, int height
);
224 bool HasText() const { return !m_text
.empty(); }
225 const wxString
& GetText() const { return m_text
; }
226 void SetText(const wxString
& text
) { m_text
= text
; }
228 // we can't use empty string for measuring the string width/height, so
229 // always return something
230 wxString
GetTextForMeasuring() const
232 wxString s
= GetText();
239 bool IsHit( int x
, int y
) const;
243 int GetWidth() const;
244 int GetHeight() const;
246 int GetImage() const { return m_image
; }
247 bool HasImage() const { return GetImage() != -1; }
249 void GetItem( wxListItem
&info
) const;
251 void SetAttr(wxListItemAttr
*attr
) { m_attr
= attr
; }
252 wxListItemAttr
*GetAttr() const { return m_attr
; }
255 // the item image or -1
258 // user data associated with the item
261 // the item coordinates are not used in report mode, instead this pointer
262 // is NULL and the owner window is used to retrieve the item position and
266 // the list ctrl we are in
267 wxListMainWindow
*m_owner
;
269 // custom attributes or NULL
270 wxListItemAttr
*m_attr
;
273 // common part of all ctors
279 //-----------------------------------------------------------------------------
280 // wxListHeaderData (internal)
281 //-----------------------------------------------------------------------------
283 class WXDLLEXPORT wxListHeaderData
: public wxObject
297 wxListHeaderData( const wxListItem
&info
);
298 void SetItem( const wxListItem
&item
);
299 void SetPosition( int x
, int y
);
300 void SetWidth( int w
);
301 void SetFormat( int format
);
302 void SetHeight( int h
);
303 bool HasImage() const;
305 bool HasText() const { return !m_text
.empty(); }
306 const wxString
& GetText() const { return m_text
; }
307 void SetText(const wxString
& text
) { m_text
= text
; }
309 void GetItem( wxListItem
&item
);
311 bool IsHit( int x
, int y
) const;
312 int GetImage() const;
313 int GetWidth() const;
314 int GetFormat() const;
317 DECLARE_DYNAMIC_CLASS(wxListHeaderData
);
320 //-----------------------------------------------------------------------------
321 // wxListLineData (internal)
322 //-----------------------------------------------------------------------------
324 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
);
325 #include "wx/listimpl.cpp"
326 WX_DEFINE_LIST(wxListItemDataList
);
328 class WXDLLEXPORT wxListLineData
331 // the list of subitems: only may have more than one item in report mode
332 wxListItemDataList m_items
;
334 // this is not used in report view
346 // the part to be highlighted
347 wxRect m_rectHighlight
;
350 // is this item selected? [NB: not used in virtual mode]
353 // back pointer to the list ctrl
354 wxListMainWindow
*m_owner
;
357 wxListLineData(wxListMainWindow
*owner
);
359 ~wxListLineData() { delete m_gi
; }
361 // are we in report mode?
362 inline bool InReportView() const;
364 // are we in virtual report mode?
365 inline bool IsVirtual() const;
367 // these 2 methods shouldn't be called for report view controls, in that
368 // case we determine our position/size ourselves
370 // calculate the size of the line
371 void CalculateSize( wxDC
*dc
, int spacing
);
373 // remember the position this line appears at
374 void SetPosition( int x
, int y
, int window_width
, int spacing
);
378 void SetImage( int image
) { SetImage(0, image
); }
379 int GetImage() const { return GetImage(0); }
380 bool HasImage() const { return GetImage() != -1; }
381 bool HasText() const { return !GetText(0).empty(); }
383 void SetItem( int index
, const wxListItem
&info
);
384 void GetItem( int index
, wxListItem
&info
);
386 wxString
GetText(int index
) const;
387 void SetText( int index
, const wxString s
);
389 wxListItemAttr
*GetAttr() const;
390 void SetAttr(wxListItemAttr
*attr
);
392 // return true if the highlighting really changed
393 bool Highlight( bool on
);
395 void ReverseHighlight();
397 bool IsHighlighted() const
399 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
401 return m_highlighted
;
404 // draw the line on the given DC in icon/list mode
405 void Draw( wxDC
*dc
);
407 // the same in report mode
408 void DrawInReportMode( wxDC
*dc
,
410 const wxRect
& rectHL
,
414 // set the line to contain num items (only can be > 1 in report mode)
415 void InitItems( int num
);
417 // get the mode (i.e. style) of the list control
418 inline int GetMode() const;
420 // prepare the DC for drawing with these item's attributes, return true if
421 // we need to draw the items background to highlight it, false otherwise
422 bool SetAttributes(wxDC
*dc
,
423 const wxListItemAttr
*attr
,
426 // these are only used by GetImage/SetImage above, we don't support images
427 // with subitems at the public API level yet
428 void SetImage( int index
, int image
);
429 int GetImage( int index
) const;
432 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
);
433 #include "wx/arrimpl.cpp"
434 WX_DEFINE_OBJARRAY(wxListLineDataArray
);
436 //-----------------------------------------------------------------------------
437 // wxListHeaderWindow (internal)
438 //-----------------------------------------------------------------------------
440 class WXDLLEXPORT wxListHeaderWindow
: public wxWindow
443 wxListMainWindow
*m_owner
;
444 wxCursor
*m_currentCursor
;
445 wxCursor
*m_resizeCursor
;
448 // column being resized
451 // divider line position in logical (unscrolled) coords
454 // minimal position beyond which the divider line can't be dragged in
459 wxListHeaderWindow();
460 virtual ~wxListHeaderWindow();
462 wxListHeaderWindow( wxWindow
*win
,
464 wxListMainWindow
*owner
,
465 const wxPoint
&pos
= wxDefaultPosition
,
466 const wxSize
&size
= wxDefaultSize
,
468 const wxString
&name
= "wxlistctrlcolumntitles" );
470 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
472 void AdjustDC(wxDC
& dc
);
474 void OnPaint( wxPaintEvent
&event
);
475 void OnMouse( wxMouseEvent
&event
);
476 void OnSetFocus( wxFocusEvent
&event
);
482 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
)
483 DECLARE_EVENT_TABLE()
486 //-----------------------------------------------------------------------------
487 // wxListRenameTimer (internal)
488 //-----------------------------------------------------------------------------
490 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
493 wxListMainWindow
*m_owner
;
496 wxListRenameTimer( wxListMainWindow
*owner
);
500 //-----------------------------------------------------------------------------
501 // wxListTextCtrl (internal)
502 //-----------------------------------------------------------------------------
504 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
509 wxListMainWindow
*m_owner
;
510 wxString m_startValue
;
514 wxListTextCtrl( wxWindow
*parent
, const wxWindowID id
,
515 bool *accept
, wxString
*res
, wxListMainWindow
*owner
,
516 const wxString
&value
= "",
517 const wxPoint
&pos
= wxDefaultPosition
, const wxSize
&size
= wxDefaultSize
,
519 const wxValidator
& validator
= wxDefaultValidator
,
520 const wxString
&name
= "listctrltextctrl" );
521 void OnChar( wxKeyEvent
&event
);
522 void OnKeyUp( wxKeyEvent
&event
);
523 void OnKillFocus( wxFocusEvent
&event
);
526 DECLARE_DYNAMIC_CLASS(wxListTextCtrl
);
527 DECLARE_EVENT_TABLE()
530 //-----------------------------------------------------------------------------
531 // wxListMainWindow (internal)
532 //-----------------------------------------------------------------------------
534 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
);
535 #include "wx/listimpl.cpp"
536 WX_DEFINE_LIST(wxListHeaderDataList
);
538 class WXDLLEXPORT wxListMainWindow
: public wxScrolledWindow
542 wxListMainWindow( wxWindow
*parent
,
544 const wxPoint
& pos
= wxDefaultPosition
,
545 const wxSize
& size
= wxDefaultSize
,
547 const wxString
&name
= _T("listctrlmainwindow") );
549 virtual ~wxListMainWindow();
551 bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); }
553 // return true if this is a virtual list control
554 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); }
556 // return true if the control is in report mode
557 bool InReportView() const { return HasFlag(wxLC_REPORT
); }
559 // return true if we are in single selection mode, false if multi sel
560 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); }
562 // do we have a header window?
563 bool HasHeader() const
564 { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); }
566 void HighlightAll( bool on
);
568 // all these functions only do something if the line is currently visible
570 // change the line "selected" state, return TRUE if it really changed
571 bool HighlightLine( size_t line
, bool highlight
= TRUE
);
573 // as HighlightLine() but do it for the range of lines: this is incredibly
574 // more efficient for virtual list controls!
576 // NB: unlike HighlightLine() this one does refresh the lines on screen
577 void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on
= TRUE
);
579 // toggle the line state and refresh it
580 void ReverseHighlight( size_t line
)
581 { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); }
583 // return true if the line is highlighted
584 bool IsHighlighted(size_t line
) const;
586 // refresh one or several lines at once
587 void RefreshLine( size_t line
);
588 void RefreshLines( size_t lineFrom
, size_t lineTo
);
590 // refresh all lines below the given one: the difference with
591 // RefreshLines() is that the index here might not be a valid one (happens
592 // when the last line is deleted)
593 void RefreshAfter( size_t lineFrom
);
595 // the methods which are forwarded to wxListLineData itself in list/icon
596 // modes but are here because the lines don't store their positions in the
599 // get the bound rect for the entire line
600 wxRect
GetLineRect(size_t line
) const;
602 // get the bound rect of the label
603 wxRect
GetLineLabelRect(size_t line
) const;
605 // get the bound rect of the items icon (only may be called if we do have
607 wxRect
GetLineIconRect(size_t line
) const;
609 // get the rect to be highlighted when the item has focus
610 wxRect
GetLineHighlightRect(size_t line
) const;
612 // get the size of the total line rect
613 wxSize
GetLineSize(size_t line
) const
614 { return GetLineRect(line
).GetSize(); }
616 // return the hit code for the corresponding position (in this line)
617 long HitTestLine(size_t line
, int x
, int y
) const;
619 // bring the selected item into view, scrolling to it if necessary
620 void MoveToItem(size_t item
);
622 // bring the current item into view
623 void MoveToFocus() { MoveToItem(m_current
); }
625 void EditLabel( long item
);
626 void OnRenameTimer();
627 void OnRenameAccept();
629 void OnMouse( wxMouseEvent
&event
);
631 // called to switch the selection from the current item to newCurrent,
632 void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event
);
634 void OnChar( wxKeyEvent
&event
);
635 void OnKeyDown( wxKeyEvent
&event
);
636 void OnSetFocus( wxFocusEvent
&event
);
637 void OnKillFocus( wxFocusEvent
&event
);
638 void OnScroll(wxScrollWinEvent
& event
) ;
640 void OnPaint( wxPaintEvent
&event
);
642 void DrawImage( int index
, wxDC
*dc
, int x
, int y
);
643 void GetImageSize( int index
, int &width
, int &height
) const;
644 int GetTextLength( const wxString
&s
) const;
646 void SetImageList( wxImageList
*imageList
, int which
);
647 void SetItemSpacing( int spacing
, bool isSmall
= FALSE
);
648 int GetItemSpacing( bool isSmall
= FALSE
);
650 void SetColumn( int col
, wxListItem
&item
);
651 void SetColumnWidth( int col
, int width
);
652 void GetColumn( int col
, wxListItem
&item
) const;
653 int GetColumnWidth( int col
) const;
654 int GetColumnCount() const { return m_columns
.GetCount(); }
656 // returns the sum of the heights of all columns
657 int GetHeaderWidth() const;
659 int GetCountPerPage() const;
661 void SetItem( wxListItem
&item
);
662 void GetItem( wxListItem
&item
);
663 void SetItemState( long item
, long state
, long stateMask
);
664 int GetItemState( long item
, long stateMask
);
665 void GetItemRect( long index
, wxRect
&rect
);
666 bool GetItemPosition( long item
, wxPoint
& pos
);
667 int GetSelectedItemCount();
669 // set the scrollbars and update the positions of the items
670 void RecalculatePositions(bool noRefresh
= FALSE
);
672 // refresh the window and the header
675 long GetNextItem( long item
, int geometry
, int state
);
676 void DeleteItem( long index
);
677 void DeleteAllItems();
678 void DeleteColumn( int col
);
679 void DeleteEverything();
680 void EnsureVisible( long index
);
681 long FindItem( long start
, const wxString
& str
, bool partial
= FALSE
);
682 long FindItem( long start
, long data
);
683 long HitTest( int x
, int y
, int &flags
);
684 void InsertItem( wxListItem
&item
);
685 void InsertColumn( long col
, wxListItem
&item
);
686 void SortItems( wxListCtrlCompare fn
, long data
);
688 size_t GetItemCount() const;
689 bool IsEmpty() const { return GetItemCount() == 0; }
690 void SetItemCount(long count
);
692 void ResetCurrent() { m_current
= (size_t)-1; }
693 bool HasCurrent() const { return m_current
!= (size_t)-1; }
695 // send out a wxListEvent
696 void SendNotify( size_t line
,
698 wxPoint point
= wxDefaultPosition
);
700 // override base class virtual to reset m_lineHeight when the font changes
701 virtual bool SetFont(const wxFont
& font
)
703 if ( !wxScrolledWindow::SetFont(font
) )
711 // these are for wxListLineData usage only
713 // get the backpointer to the list ctrl
714 wxListCtrl
*GetListCtrl() const
716 return wxStaticCast(GetParent(), wxListCtrl
);
719 // get the height of all lines (assuming they all do have the same height)
720 wxCoord
GetLineHeight() const;
722 // get the y position of the given line (only for report view)
723 wxCoord
GetLineY(size_t line
) const;
726 // the array of all line objects for a non virtual list control
727 wxListLineDataArray m_lines
;
729 // the list of column objects
730 wxListHeaderDataList m_columns
;
732 // currently focused item or -1
735 // the item currently being edited or -1
736 size_t m_currentEdit
;
738 // the number of lines per page
741 // this flag is set when something which should result in the window
742 // redrawing happens (i.e. an item was added or deleted, or its appearance
743 // changed) and OnPaint() doesn't redraw the window while it is set which
744 // allows to minimize the number of repaintings when a lot of items are
745 // being added. The real repainting occurs only after the next OnIdle()
749 wxBrush
*m_highlightBrush
;
750 wxColour
*m_highlightColour
;
753 wxImageList
*m_small_image_list
;
754 wxImageList
*m_normal_image_list
;
756 int m_normal_spacing
;
760 wxTimer
*m_renameTimer
;
762 wxString m_renameRes
;
767 // for double click logic
768 size_t m_lineLastClicked
,
769 m_lineBeforeLastClicked
;
772 // the total count of items in a virtual list control
775 // the object maintaining the items selection state, only used in virtual
777 wxSelectionStore m_selStore
;
779 // common part of all ctors
782 // intiialize m_[xy]Scroll
783 void InitScrolling();
785 // get the line data for the given index
786 wxListLineData
*GetLine(size_t n
) const
788 wxASSERT_MSG( n
!= (size_t)-1, _T("invalid line index") );
792 wxConstCast(this, wxListMainWindow
)->CacheLineData(n
);
800 // get a dummy line which can be used for geometry calculations and such:
801 // you must use GetLine() if you want to really draw the line
802 wxListLineData
*GetDummyLine() const;
804 // cache the line data of the n-th line in m_lines[0]
805 void CacheLineData(size_t line
);
807 // get the range of visible lines
808 void GetVisibleLinesRange(size_t *from
, size_t *to
);
810 // force us to recalculate the range of visible lines
811 void ResetVisibleLinesRange() { m_lineFrom
= (size_t)-1; }
813 // get the colour to be used for drawing the rules
814 wxColour
GetRuleColour() const
819 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
);
824 // initialize the current item if needed
825 void UpdateCurrent();
827 // delete all items but don't refresh: called from dtor
828 void DoDeleteAllItems();
830 // called when an item is [un]focuded, i.e. becomes [not] current
833 void OnFocusLine( size_t line
);
834 void OnUnfocusLine( size_t line
);
836 // the height of one line using the current font
837 wxCoord m_lineHeight
;
839 // the total header width or 0 if not calculated yet
840 wxCoord m_headerWidth
;
842 // the first and last lines being shown on screen right now (inclusive),
843 // both may be -1 if they must be calculated so never access them directly:
844 // use GetVisibleLinesRange() above instead
848 DECLARE_DYNAMIC_CLASS(wxListMainWindow
);
849 DECLARE_EVENT_TABLE()
852 // ============================================================================
854 // ============================================================================
856 // ----------------------------------------------------------------------------
858 // ----------------------------------------------------------------------------
860 bool wxSelectionStore::IsSelected(size_t item
) const
862 bool isSel
= m_itemsSel
.Index(item
) != wxNOT_FOUND
;
864 // if the default state is to be selected, being in m_itemsSel means that
865 // the item is not selected, so we have to inverse the logic
866 return m_defaultState
? !isSel
: isSel
;
869 bool wxSelectionStore::SelectItem(size_t item
, bool select
)
871 // search for the item ourselves as like this we get the index where to
872 // insert it later if needed, so we do only one search in the array instead
873 // of two (adding item to a sorted array requires a search)
874 size_t index
= m_itemsSel
.IndexForInsert(item
);
875 bool isSel
= index
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
;
877 if ( select
!= m_defaultState
)
881 m_itemsSel
.AddAt(item
, index
);
886 else // reset to default state
890 m_itemsSel
.RemoveAt(index
);
898 void wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, bool select
)
900 wxASSERT_MSG( itemFrom
<= itemTo
, _T("should be in order") );
902 // are we going to have more [un]selected items than the other ones?
903 if ( itemTo
- itemFrom
> m_count
/ 2 )
905 if ( select
!= m_defaultState
)
907 // the default state now becomes the same as 'select'
908 m_defaultState
= select
;
910 // so all the old selections (which had state select) shouldn't be
911 // selected any more, but all the other ones should
912 wxIndexArray selOld
= m_itemsSel
;
915 // TODO: it should be possible to optimize the searches a bit
916 // knowing the possible range
919 for ( item
= 0; item
< itemFrom
; item
++ )
921 if ( selOld
.Index(item
) == wxNOT_FOUND
)
922 m_itemsSel
.Add(item
);
925 for ( item
= itemTo
+ 1; item
< m_count
; item
++ )
927 if ( selOld
.Index(item
) == wxNOT_FOUND
)
928 m_itemsSel
.Add(item
);
931 else // select == m_defaultState
933 // get the inclusive range of items between itemFrom and itemTo
934 size_t count
= m_itemsSel
.GetCount(),
935 start
= m_itemsSel
.IndexForInsert(itemFrom
),
936 end
= m_itemsSel
.IndexForInsert(itemTo
);
938 if ( start
== count
|| m_itemsSel
[start
] < itemFrom
)
943 if ( end
== count
|| m_itemsSel
[end
] > itemTo
)
950 // delete all of them (from end to avoid changing indices)
951 for ( int i
= end
; i
>= (int)start
; i
-- )
953 m_itemsSel
.RemoveAt(i
);
958 else // "few" items change state
960 // just add the items to the selection
961 for ( size_t item
= itemFrom
; item
<= itemTo
; item
++ )
963 SelectItem(item
, select
);
968 void wxSelectionStore::OnItemDelete(size_t item
)
970 size_t count
= m_itemsSel
.GetCount(),
971 i
= m_itemsSel
.IndexForInsert(item
);
973 if ( i
< count
&& m_itemsSel
[i
] == item
)
975 // this item itself was in m_itemsSel, remove it from there
976 m_itemsSel
.RemoveAt(i
);
981 // and adjust the index of all which follow it
984 // all following elements must be greater than the one we deleted
985 wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") );
991 //-----------------------------------------------------------------------------
993 //-----------------------------------------------------------------------------
995 wxListItemData::~wxListItemData()
997 // in the virtual list control the attributes are managed by the main
998 // program, so don't delete them
999 if ( !m_owner
->IsVirtual() )
1007 void wxListItemData::Init()
1015 wxListItemData::wxListItemData(wxListMainWindow
*owner
)
1021 if ( owner
->InReportView() )
1027 m_rect
= new wxRect
;
1031 void wxListItemData::SetItem( const wxListItem
&info
)
1033 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
1034 SetText(info
.m_text
);
1035 if ( info
.m_mask
& wxLIST_MASK_IMAGE
)
1036 m_image
= info
.m_image
;
1037 if ( info
.m_mask
& wxLIST_MASK_DATA
)
1038 m_data
= info
.m_data
;
1040 if ( info
.HasAttributes() )
1043 *m_attr
= *info
.GetAttributes();
1045 m_attr
= new wxListItemAttr(*info
.GetAttributes());
1053 m_rect
->width
= info
.m_width
;
1057 void wxListItemData::SetPosition( int x
, int y
)
1059 wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") );
1065 void wxListItemData::SetSize( int width
, int height
)
1067 wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") );
1070 m_rect
->width
= width
;
1072 m_rect
->height
= height
;
1075 bool wxListItemData::IsHit( int x
, int y
) const
1077 wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") );
1079 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
);
1082 int wxListItemData::GetX() const
1084 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1089 int wxListItemData::GetY() const
1091 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1096 int wxListItemData::GetWidth() const
1098 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1100 return m_rect
->width
;
1103 int wxListItemData::GetHeight() const
1105 wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") );
1107 return m_rect
->height
;
1110 void wxListItemData::GetItem( wxListItem
&info
) const
1112 info
.m_text
= m_text
;
1113 info
.m_image
= m_image
;
1114 info
.m_data
= m_data
;
1118 if ( m_attr
->HasTextColour() )
1119 info
.SetTextColour(m_attr
->GetTextColour());
1120 if ( m_attr
->HasBackgroundColour() )
1121 info
.SetBackgroundColour(m_attr
->GetBackgroundColour());
1122 if ( m_attr
->HasFont() )
1123 info
.SetFont(m_attr
->GetFont());
1127 //-----------------------------------------------------------------------------
1129 //-----------------------------------------------------------------------------
1131 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
);
1133 wxListHeaderData::wxListHeaderData()
1144 wxListHeaderData::wxListHeaderData( const wxListItem
&item
)
1152 void wxListHeaderData::SetItem( const wxListItem
&item
)
1154 m_mask
= item
.m_mask
;
1155 m_text
= item
.m_text
;
1156 m_image
= item
.m_image
;
1157 m_format
= item
.m_format
;
1159 SetWidth(item
.m_width
);
1162 void wxListHeaderData::SetPosition( int x
, int y
)
1168 void wxListHeaderData::SetHeight( int h
)
1173 void wxListHeaderData::SetWidth( int w
)
1177 m_width
= WIDTH_COL_DEFAULT
;
1178 if (m_width
< WIDTH_COL_MIN
)
1179 m_width
= WIDTH_COL_MIN
;
1182 void wxListHeaderData::SetFormat( int format
)
1187 bool wxListHeaderData::HasImage() const
1189 return (m_image
!= 0);
1192 bool wxListHeaderData::IsHit( int x
, int y
) const
1194 return ((x
>= m_xpos
) && (x
<= m_xpos
+m_width
) && (y
>= m_ypos
) && (y
<= m_ypos
+m_height
));
1197 void wxListHeaderData::GetItem( wxListItem
&item
)
1199 item
.m_mask
= m_mask
;
1200 item
.m_text
= m_text
;
1201 item
.m_image
= m_image
;
1202 item
.m_format
= m_format
;
1203 item
.m_width
= m_width
;
1206 int wxListHeaderData::GetImage() const
1211 int wxListHeaderData::GetWidth() const
1216 int wxListHeaderData::GetFormat() const
1221 //-----------------------------------------------------------------------------
1223 //-----------------------------------------------------------------------------
1225 inline int wxListLineData::GetMode() const
1227 return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
;
1230 inline bool wxListLineData::InReportView() const
1232 return m_owner
->HasFlag(wxLC_REPORT
);
1235 inline bool wxListLineData::IsVirtual() const
1237 return m_owner
->IsVirtual();
1240 wxListLineData::wxListLineData( wxListMainWindow
*owner
)
1243 m_items
.DeleteContents( TRUE
);
1245 if ( InReportView() )
1251 m_gi
= new GeometryInfo
;
1254 m_highlighted
= FALSE
;
1256 InitItems( GetMode() == wxLC_REPORT
? m_owner
->GetColumnCount() : 1 );
1259 void wxListLineData::CalculateSize( wxDC
*dc
, int spacing
)
1261 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1262 wxCHECK_RET( node
, _T("no subitems at all??") );
1264 wxListItemData
*item
= node
->GetData();
1266 switch ( GetMode() )
1269 case wxLC_SMALL_ICON
:
1271 m_gi
->m_rectAll
.width
= spacing
;
1273 wxString s
= item
->GetText();
1279 m_gi
->m_rectLabel
.width
=
1280 m_gi
->m_rectLabel
.height
= 0;
1284 dc
->GetTextExtent( s
, &lw
, &lh
);
1285 if (lh
< SCROLL_UNIT_Y
)
1290 m_gi
->m_rectAll
.height
= spacing
+ lh
;
1292 m_gi
->m_rectAll
.width
= lw
;
1294 m_gi
->m_rectLabel
.width
= lw
;
1295 m_gi
->m_rectLabel
.height
= lh
;
1298 if (item
->HasImage())
1301 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1302 m_gi
->m_rectIcon
.width
= w
+ 8;
1303 m_gi
->m_rectIcon
.height
= h
+ 8;
1305 if ( m_gi
->m_rectIcon
.width
> m_gi
->m_rectAll
.width
)
1306 m_gi
->m_rectAll
.width
= m_gi
->m_rectIcon
.width
;
1307 if ( m_gi
->m_rectIcon
.height
+ lh
> m_gi
->m_rectAll
.height
- 4 )
1308 m_gi
->m_rectAll
.height
= m_gi
->m_rectIcon
.height
+ lh
+ 4;
1311 if ( item
->HasText() )
1313 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectLabel
.width
;
1314 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectLabel
.height
;
1316 else // no text, highlight the icon
1318 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectIcon
.width
;
1319 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectIcon
.height
;
1326 wxString s
= item
->GetTextForMeasuring();
1329 dc
->GetTextExtent( s
, &lw
, &lh
);
1330 if (lh
< SCROLL_UNIT_Y
)
1335 m_gi
->m_rectLabel
.width
= lw
;
1336 m_gi
->m_rectLabel
.height
= lh
;
1338 m_gi
->m_rectAll
.width
= lw
;
1339 m_gi
->m_rectAll
.height
= lh
;
1341 if (item
->HasImage())
1344 m_owner
->GetImageSize( item
->GetImage(), w
, h
);
1345 m_gi
->m_rectIcon
.width
= w
;
1346 m_gi
->m_rectIcon
.height
= h
;
1348 m_gi
->m_rectAll
.width
+= 4 + w
;
1349 if (h
> m_gi
->m_rectAll
.height
)
1350 m_gi
->m_rectAll
.height
= h
;
1353 m_gi
->m_rectHighlight
.width
= m_gi
->m_rectAll
.width
;
1354 m_gi
->m_rectHighlight
.height
= m_gi
->m_rectAll
.height
;
1359 wxFAIL_MSG( _T("unexpected call to SetSize") );
1363 wxFAIL_MSG( _T("unknown mode") );
1367 void wxListLineData::SetPosition( int x
, int y
,
1371 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1372 wxCHECK_RET( node
, _T("no subitems at all??") );
1374 wxListItemData
*item
= node
->GetData();
1376 switch ( GetMode() )
1379 case wxLC_SMALL_ICON
:
1380 m_gi
->m_rectAll
.x
= x
;
1381 m_gi
->m_rectAll
.y
= y
;
1383 if ( item
->HasImage() )
1385 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 4
1386 + (spacing
- m_gi
->m_rectIcon
.width
)/2;
1387 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 4;
1390 if ( item
->HasText() )
1392 if (m_gi
->m_rectAll
.width
> spacing
)
1393 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1395 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2);
1396 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ m_gi
->m_rectAll
.height
+ 2 - m_gi
->m_rectLabel
.height
;
1397 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectLabel
.x
- 2;
1398 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectLabel
.y
- 2;
1400 else // no text, highlight the icon
1402 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectIcon
.x
- 4;
1403 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectIcon
.y
- 4;
1408 m_gi
->m_rectAll
.x
= x
;
1409 m_gi
->m_rectAll
.y
= y
;
1411 m_gi
->m_rectHighlight
.x
= m_gi
->m_rectAll
.x
;
1412 m_gi
->m_rectHighlight
.y
= m_gi
->m_rectAll
.y
;
1413 m_gi
->m_rectLabel
.y
= m_gi
->m_rectAll
.y
+ 2;
1415 if (item
->HasImage())
1417 m_gi
->m_rectIcon
.x
= m_gi
->m_rectAll
.x
+ 2;
1418 m_gi
->m_rectIcon
.y
= m_gi
->m_rectAll
.y
+ 2;
1419 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 6 + m_gi
->m_rectIcon
.width
;
1423 m_gi
->m_rectLabel
.x
= m_gi
->m_rectAll
.x
+ 2;
1428 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1432 wxFAIL_MSG( _T("unknown mode") );
1436 void wxListLineData::InitItems( int num
)
1438 for (int i
= 0; i
< num
; i
++)
1439 m_items
.Append( new wxListItemData(m_owner
) );
1442 void wxListLineData::SetItem( int index
, const wxListItem
&info
)
1444 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1445 wxCHECK_RET( node
, _T("invalid column index in SetItem") );
1447 wxListItemData
*item
= node
->GetData();
1448 item
->SetItem( info
);
1451 void wxListLineData::GetItem( int index
, wxListItem
&info
)
1453 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1456 wxListItemData
*item
= node
->GetData();
1457 item
->GetItem( info
);
1461 wxString
wxListLineData::GetText(int index
) const
1465 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1468 wxListItemData
*item
= node
->GetData();
1469 s
= item
->GetText();
1475 void wxListLineData::SetText( int index
, const wxString s
)
1477 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1480 wxListItemData
*item
= node
->GetData();
1485 void wxListLineData::SetImage( int index
, int image
)
1487 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1488 wxCHECK_RET( node
, _T("invalid column index in SetImage()") );
1490 wxListItemData
*item
= node
->GetData();
1491 item
->SetImage(image
);
1494 int wxListLineData::GetImage( int index
) const
1496 wxListItemDataList::Node
*node
= m_items
.Item( index
);
1497 wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") );
1499 wxListItemData
*item
= node
->GetData();
1500 return item
->GetImage();
1503 wxListItemAttr
*wxListLineData::GetAttr() const
1505 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1506 wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") );
1508 wxListItemData
*item
= node
->GetData();
1509 return item
->GetAttr();
1512 void wxListLineData::SetAttr(wxListItemAttr
*attr
)
1514 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1515 wxCHECK_RET( node
, _T("invalid column index in SetAttr()") );
1517 wxListItemData
*item
= node
->GetData();
1518 item
->SetAttr(attr
);
1521 bool wxListLineData::SetAttributes(wxDC
*dc
,
1522 const wxListItemAttr
*attr
,
1525 wxWindow
*listctrl
= m_owner
->GetParent();
1529 // don't use foreground colour for drawing highlighted items - this might
1530 // make them completely invisible (and there is no way to do bit
1531 // arithmetics on wxColour, unfortunately)
1535 colText
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
1539 if ( attr
&& attr
->HasTextColour() )
1541 colText
= attr
->GetTextColour();
1545 colText
= listctrl
->GetForegroundColour();
1549 dc
->SetTextForeground(colText
);
1553 if ( attr
&& attr
->HasFont() )
1555 font
= attr
->GetFont();
1559 font
= listctrl
->GetFont();
1565 bool hasBgCol
= attr
&& attr
->HasBackgroundColour();
1566 if ( highlighted
|| hasBgCol
)
1570 dc
->SetBrush( *m_owner
->m_highlightBrush
);
1574 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
1577 dc
->SetPen( *wxTRANSPARENT_PEN
);
1585 void wxListLineData::Draw( wxDC
*dc
)
1587 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1588 wxCHECK_RET( node
, _T("no subitems at all??") );
1590 bool highlighted
= IsHighlighted();
1592 wxListItemAttr
*attr
= GetAttr();
1594 if ( SetAttributes(dc
, attr
, highlighted
) )
1596 dc
->DrawRectangle( m_gi
->m_rectHighlight
);
1599 wxListItemData
*item
= node
->GetData();
1600 if (item
->HasImage())
1602 wxRect rectIcon
= m_gi
->m_rectIcon
;
1603 m_owner
->DrawImage( item
->GetImage(), dc
,
1604 rectIcon
.x
, rectIcon
.y
);
1607 if (item
->HasText())
1609 wxRect rectLabel
= m_gi
->m_rectLabel
;
1610 dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y
);
1614 void wxListLineData::DrawInReportMode( wxDC
*dc
,
1616 const wxRect
& rectHL
,
1619 // use our own flag if we maintain it
1621 highlighted
= m_highlighted
;
1623 // TODO: later we should support setting different attributes for
1624 // different columns - to do it, just add "col" argument to
1625 // GetAttr() and move these lines into the loop below
1626 wxListItemAttr
*attr
= GetAttr();
1627 if ( SetAttributes(dc
, attr
, highlighted
) )
1629 dc
->DrawRectangle( rectHL
);
1632 wxListItemDataList::Node
*node
= m_items
.GetFirst();
1633 wxCHECK_RET( node
, _T("no subitems at all??") );
1636 wxCoord x
= rect
.x
+ HEADER_OFFSET_X
,
1637 y
= rect
.y
+ (LINE_SPACING
+ EXTRA_HEIGHT
) / 2;
1641 wxListItemData
*item
= node
->GetData();
1645 if ( item
->HasImage() )
1648 m_owner
->DrawImage( item
->GetImage(), dc
, x
, y
);
1649 m_owner
->GetImageSize( item
->GetImage(), ix
, iy
);
1650 x
+= ix
+ 5; // FIXME: what is "5"?
1653 int width
= m_owner
->GetColumnWidth(col
++);
1655 wxDCClipper
clipper(*dc
, x
, y
, width
, rect
.height
);
1657 if ( item
->HasText() )
1659 dc
->DrawText( item
->GetText(), x
, y
);
1664 node
= node
->GetNext();
1668 bool wxListLineData::Highlight( bool on
)
1670 wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") );
1672 if ( on
== m_highlighted
)
1680 void wxListLineData::ReverseHighlight( void )
1682 Highlight(!IsHighlighted());
1685 //-----------------------------------------------------------------------------
1686 // wxListHeaderWindow
1687 //-----------------------------------------------------------------------------
1689 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
);
1691 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
)
1692 EVT_PAINT (wxListHeaderWindow::OnPaint
)
1693 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse
)
1694 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus
)
1697 wxListHeaderWindow::wxListHeaderWindow( void )
1699 m_owner
= (wxListMainWindow
*) NULL
;
1700 m_currentCursor
= (wxCursor
*) NULL
;
1701 m_resizeCursor
= (wxCursor
*) NULL
;
1702 m_isDragging
= FALSE
;
1705 wxListHeaderWindow::wxListHeaderWindow( wxWindow
*win
, wxWindowID id
, wxListMainWindow
*owner
,
1706 const wxPoint
&pos
, const wxSize
&size
,
1707 long style
, const wxString
&name
) :
1708 wxWindow( win
, id
, pos
, size
, style
, name
)
1711 // m_currentCursor = wxSTANDARD_CURSOR;
1712 m_currentCursor
= (wxCursor
*) NULL
;
1713 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
1714 m_isDragging
= FALSE
;
1717 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE
) );
1720 wxListHeaderWindow::~wxListHeaderWindow( void )
1722 delete m_resizeCursor
;
1725 void wxListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1728 GtkStateType state
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
1729 : GTK_STATE_INSENSITIVE
;
1731 x
= dc
->XLOG2DEV( x
);
1733 gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
,
1734 state
, GTK_SHADOW_OUT
,
1735 (GdkRectangle
*) NULL
, m_wxwindow
, "button",
1736 x
-1, y
-1, w
+2, h
+2);
1737 #elif defined( __WXMAC__ )
1738 const int m_corner
= 1;
1740 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1742 dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
) , 1 , wxSOLID
) );
1743 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1744 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1746 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1749 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1750 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1752 dc
->SetPen( *wxWHITE_PEN
);
1753 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1754 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1755 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1756 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1758 const int m_corner
= 1;
1760 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1762 dc
->SetPen( *wxBLACK_PEN
);
1763 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1764 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1766 wxPen
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1769 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1770 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1772 dc
->SetPen( *wxWHITE_PEN
);
1773 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1774 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1775 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1776 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1780 // shift the DC origin to match the position of the main window horz
1781 // scrollbar: this allows us to always use logical coords
1782 void wxListHeaderWindow::AdjustDC(wxDC
& dc
)
1785 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1788 m_owner
->GetViewStart( &x
, NULL
);
1790 // account for the horz scrollbar offset
1791 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1794 void wxListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1797 wxClientDC
dc( this );
1799 wxPaintDC
dc( this );
1807 dc
.SetFont( GetFont() );
1809 // width and height of the entire header window
1811 GetClientSize( &w
, &h
);
1812 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1814 dc
.SetBackgroundMode(wxTRANSPARENT
);
1816 // do *not* use the listctrl colour for headers - one day we will have a
1817 // function to set it separately
1818 //dc.SetTextForeground( *wxBLACK );
1819 dc
.SetTextForeground(wxSystemSettings::
1820 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1822 int x
= HEADER_OFFSET_X
;
1824 int numColumns
= m_owner
->GetColumnCount();
1826 for (int i
= 0; i
< numColumns
; i
++)
1828 m_owner
->GetColumn( i
, item
);
1829 int wCol
= item
.m_width
;
1830 int cw
= wCol
- 2; // the width of the rect to draw
1832 int xEnd
= x
+ wCol
;
1834 dc
.SetPen( *wxWHITE_PEN
);
1836 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1837 dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 );
1838 dc
.DrawText( item
.GetText(), x
+ EXTRA_WIDTH
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1839 dc
.DestroyClippingRegion();
1848 void wxListHeaderWindow::DrawCurrent()
1850 int x1
= m_currentX
;
1852 ClientToScreen( &x1
, &y1
);
1854 int x2
= m_currentX
-1;
1856 m_owner
->GetClientSize( NULL
, &y2
);
1857 m_owner
->ClientToScreen( &x2
, &y2
);
1860 dc
.SetLogicalFunction( wxINVERT
);
1861 dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID
) );
1862 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
1866 dc
.DrawLine( x1
, y1
, x2
, y2
);
1868 dc
.SetLogicalFunction( wxCOPY
);
1870 dc
.SetPen( wxNullPen
);
1871 dc
.SetBrush( wxNullBrush
);
1874 void wxListHeaderWindow::OnMouse( wxMouseEvent
&event
)
1876 // we want to work with logical coords
1878 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1879 int y
= event
.GetY();
1883 // we don't draw the line beyond our window, but we allow dragging it
1886 GetClientSize( &w
, NULL
);
1887 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1890 // erase the line if it was drawn
1891 if ( m_currentX
< w
)
1894 if (event
.ButtonUp())
1897 m_isDragging
= FALSE
;
1899 m_owner
->SetColumnWidth( m_column
, m_currentX
- m_minX
);
1906 m_currentX
= m_minX
+ 7;
1908 // draw in the new location
1909 if ( m_currentX
< w
)
1913 else // not dragging
1916 bool hit_border
= FALSE
;
1918 // end of the current column
1921 // find the column where this event occured
1922 int countCol
= m_owner
->GetColumnCount();
1923 for (int col
= 0; col
< countCol
; col
++)
1925 xpos
+= m_owner
->GetColumnWidth( col
);
1928 if ( (abs(x
-xpos
) < 3) && (y
< 22) )
1930 // near the column border
1937 // inside the column
1944 if (event
.LeftDown())
1948 m_isDragging
= TRUE
;
1955 wxWindow
*parent
= GetParent();
1956 wxListEvent
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() );
1957 le
.SetEventObject( parent
);
1958 le
.m_col
= m_column
;
1959 parent
->GetEventHandler()->ProcessEvent( le
);
1962 else if (event
.Moving())
1967 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1968 m_currentCursor
= m_resizeCursor
;
1972 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1973 m_currentCursor
= wxSTANDARD_CURSOR
;
1977 SetCursor(*m_currentCursor
);
1982 void wxListHeaderWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
1984 m_owner
->SetFocus();
1987 //-----------------------------------------------------------------------------
1988 // wxListRenameTimer (internal)
1989 //-----------------------------------------------------------------------------
1991 wxListRenameTimer::wxListRenameTimer( wxListMainWindow
*owner
)
1996 void wxListRenameTimer::Notify()
1998 m_owner
->OnRenameTimer();
2001 //-----------------------------------------------------------------------------
2002 // wxListTextCtrl (internal)
2003 //-----------------------------------------------------------------------------
2005 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
);
2007 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
)
2008 EVT_CHAR (wxListTextCtrl::OnChar
)
2009 EVT_KEY_UP (wxListTextCtrl::OnKeyUp
)
2010 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus
)
2013 wxListTextCtrl::wxListTextCtrl( wxWindow
*parent
,
2014 const wxWindowID id
,
2017 wxListMainWindow
*owner
,
2018 const wxString
&value
,
2022 const wxValidator
& validator
,
2023 const wxString
&name
)
2024 : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name
)
2029 (*m_accept
) = FALSE
;
2031 m_startValue
= value
;
2034 void wxListTextCtrl::OnChar( wxKeyEvent
&event
)
2036 if (event
.m_keyCode
== WXK_RETURN
)
2039 (*m_res
) = GetValue();
2041 if (!wxPendingDelete
.Member(this))
2042 wxPendingDelete
.Append(this);
2044 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2045 m_owner
->OnRenameAccept();
2049 if (event
.m_keyCode
== WXK_ESCAPE
)
2051 (*m_accept
) = FALSE
;
2054 if (!wxPendingDelete
.Member(this))
2055 wxPendingDelete
.Append(this);
2063 void wxListTextCtrl::OnKeyUp( wxKeyEvent
&event
)
2065 // auto-grow the textctrl:
2066 wxSize parentSize
= m_owner
->GetSize();
2067 wxPoint myPos
= GetPosition();
2068 wxSize mySize
= GetSize();
2070 GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM??
2071 if (myPos
.x
+ sx
> parentSize
.x
)
2072 sx
= parentSize
.x
- myPos
.x
;
2080 void wxListTextCtrl::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
2082 if (!wxPendingDelete
.Member(this))
2083 wxPendingDelete
.Append(this);
2085 if ((*m_accept
) && ((*m_res
) != m_startValue
))
2086 m_owner
->OnRenameAccept();
2089 //-----------------------------------------------------------------------------
2091 //-----------------------------------------------------------------------------
2093 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
);
2095 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
)
2096 EVT_PAINT (wxListMainWindow::OnPaint
)
2097 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse
)
2098 EVT_CHAR (wxListMainWindow::OnChar
)
2099 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown
)
2100 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus
)
2101 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus
)
2102 EVT_SCROLLWIN (wxListMainWindow::OnScroll
)
2105 void wxListMainWindow::Init()
2107 m_columns
.DeleteContents( TRUE
);
2111 m_lineTo
= (size_t)-1;
2117 m_small_image_list
= (wxImageList
*) NULL
;
2118 m_normal_image_list
= (wxImageList
*) NULL
;
2120 m_small_spacing
= 30;
2121 m_normal_spacing
= 40;
2125 m_isCreated
= FALSE
;
2127 m_lastOnSame
= FALSE
;
2128 m_renameTimer
= new wxListRenameTimer( this );
2129 m_renameAccept
= FALSE
;
2134 m_lineBeforeLastClicked
= (size_t)-1;
2137 void wxListMainWindow::InitScrolling()
2139 if ( HasFlag(wxLC_REPORT
) )
2141 m_xScroll
= SCROLL_UNIT_X
;
2142 m_yScroll
= SCROLL_UNIT_Y
;
2146 m_xScroll
= SCROLL_UNIT_Y
;
2151 wxListMainWindow::wxListMainWindow()
2155 m_highlightBrush
= (wxBrush
*) NULL
;
2161 wxListMainWindow::wxListMainWindow( wxWindow
*parent
,
2166 const wxString
&name
)
2167 : wxScrolledWindow( parent
, id
, pos
, size
,
2168 style
| wxHSCROLL
| wxVSCROLL
, name
)
2172 m_highlightBrush
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
2177 SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 );
2179 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX
) );
2182 wxListMainWindow::~wxListMainWindow()
2186 delete m_highlightBrush
;
2188 delete m_renameTimer
;
2191 void wxListMainWindow::CacheLineData(size_t line
)
2193 wxListCtrl
*listctrl
= GetListCtrl();
2195 wxListLineData
*ld
= GetDummyLine();
2197 size_t countCol
= GetColumnCount();
2198 for ( size_t col
= 0; col
< countCol
; col
++ )
2200 ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
));
2203 ld
->SetImage(listctrl
->OnGetItemImage(line
));
2204 ld
->SetAttr(listctrl
->OnGetItemAttr(line
));
2207 wxListLineData
*wxListMainWindow::GetDummyLine() const
2209 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2211 if ( m_lines
.IsEmpty() )
2213 // normal controls are supposed to have something in m_lines
2214 // already if it's not empty
2215 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2217 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2218 wxListLineData
*line
= new wxListLineData(self
);
2219 self
->m_lines
.Add(line
);
2225 // ----------------------------------------------------------------------------
2226 // line geometry (report mode only)
2227 // ----------------------------------------------------------------------------
2229 wxCoord
wxListMainWindow::GetLineHeight() const
2231 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2233 // we cache the line height as calling GetTextExtent() is slow
2234 if ( !m_lineHeight
)
2236 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
2238 wxClientDC
dc( self
);
2239 dc
.SetFont( GetFont() );
2242 dc
.GetTextExtent(_T("H"), NULL
, &y
);
2244 if ( y
< SCROLL_UNIT_Y
)
2248 self
->m_lineHeight
= y
+ LINE_SPACING
;
2251 return m_lineHeight
;
2254 wxCoord
wxListMainWindow::GetLineY(size_t line
) const
2256 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") );
2258 return LINE_SPACING
+ line
*GetLineHeight();
2261 wxRect
wxListMainWindow::GetLineRect(size_t line
) const
2263 if ( !InReportView() )
2264 return GetLine(line
)->m_gi
->m_rectAll
;
2267 rect
.x
= HEADER_OFFSET_X
;
2268 rect
.y
= GetLineY(line
);
2269 rect
.width
= GetHeaderWidth();
2270 rect
.height
= GetLineHeight();
2275 wxRect
wxListMainWindow::GetLineLabelRect(size_t line
) const
2277 if ( !InReportView() )
2278 return GetLine(line
)->m_gi
->m_rectLabel
;
2281 rect
.x
= HEADER_OFFSET_X
;
2282 rect
.y
= GetLineY(line
);
2283 rect
.width
= GetColumnWidth(0);
2284 rect
.height
= GetLineHeight();
2289 wxRect
wxListMainWindow::GetLineIconRect(size_t line
) const
2291 if ( !InReportView() )
2292 return GetLine(line
)->m_gi
->m_rectIcon
;
2294 wxListLineData
*ld
= GetLine(line
);
2295 wxASSERT_MSG( ld
->HasImage(), _T("should have an image") );
2298 rect
.x
= HEADER_OFFSET_X
;
2299 rect
.y
= GetLineY(line
);
2300 GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
);
2305 wxRect
wxListMainWindow::GetLineHighlightRect(size_t line
) const
2307 return InReportView() ? GetLineRect(line
)
2308 : GetLine(line
)->m_gi
->m_rectHighlight
;
2311 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const
2313 wxListLineData
*ld
= GetLine(line
);
2315 if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) )
2316 return wxLIST_HITTEST_ONITEMICON
;
2318 if ( ld
->HasText() )
2320 wxRect rect
= InReportView() ? GetLineRect(line
)
2321 : GetLineLabelRect(line
);
2323 if ( rect
.Inside(x
, y
) )
2324 return wxLIST_HITTEST_ONITEMLABEL
;
2330 // ----------------------------------------------------------------------------
2331 // highlight (selection) handling
2332 // ----------------------------------------------------------------------------
2334 bool wxListMainWindow::IsHighlighted(size_t line
) const
2338 return m_selStore
.IsSelected(line
);
2342 wxListLineData
*ld
= GetLine(line
);
2343 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2345 return ld
->IsHighlighted();
2349 void wxListMainWindow::HighlightLines( size_t lineFrom
, size_t lineTo
, bool highlight
)
2353 m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
);
2354 RefreshLines(lineFrom
, lineTo
);
2358 // do it the dumb way
2359 bool needsRefresh
= FALSE
;
2360 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2362 if ( HighlightLine(line
, highlight
) )
2363 needsRefresh
= TRUE
;
2367 RefreshLines(lineFrom
, lineTo
);
2371 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight
)
2377 changed
= m_selStore
.SelectItem(line
, highlight
);
2381 wxListLineData
*ld
= GetLine(line
);
2382 wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") );
2384 changed
= ld
->Highlight(highlight
);
2389 SendNotify( line
, highlight
? wxEVT_COMMAND_LIST_ITEM_SELECTED
2390 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
);
2396 void wxListMainWindow::RefreshLine( size_t line
)
2398 wxRect rect
= GetLineRect(line
);
2400 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2401 RefreshRect( rect
);
2404 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo
)
2406 // we suppose that they are ordered by caller
2407 wxASSERT_MSG( lineFrom
<= lineTo
, _T("indices in disorder") );
2409 wxASSERT_MSG( lineTo
< GetItemCount(), _T("invalid line range") );
2411 if ( HasFlag(wxLC_REPORT
) )
2413 size_t visibleFrom
, visibleTo
;
2414 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2416 if ( lineFrom
< visibleFrom
)
2417 lineFrom
= visibleFrom
;
2418 if ( lineTo
> visibleTo
)
2423 rect
.y
= GetLineY(lineFrom
);
2424 rect
.width
= GetClientSize().x
;
2425 rect
.height
= GetLineY(lineTo
) - rect
.y
+ GetLineHeight();
2427 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2428 RefreshRect( rect
);
2432 // TODO: this should be optimized...
2433 for ( size_t line
= lineFrom
; line
<= lineTo
; line
++ )
2440 void wxListMainWindow::RefreshAfter( size_t lineFrom
)
2442 if ( HasFlag(wxLC_REPORT
) )
2445 GetVisibleLinesRange(&visibleFrom
, NULL
);
2447 if ( lineFrom
< visibleFrom
)
2448 lineFrom
= visibleFrom
;
2452 rect
.y
= GetLineY(lineFrom
);
2454 wxSize size
= GetClientSize();
2455 rect
.width
= size
.x
;
2456 // refresh till the bottom of the window
2457 rect
.height
= size
.y
- rect
.y
;
2459 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2460 RefreshRect( rect
);
2464 // TODO: how to do it more efficiently?
2469 void wxListMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2471 // Note: a wxPaintDC must be constructed even if no drawing is
2472 // done (a Windows requirement).
2473 wxPaintDC
dc( this );
2477 // empty control. nothing to draw
2483 // delay the repainting until we calculate all the items positions
2490 CalcScrolledPosition( 0, 0, &dev_x
, &dev_y
);
2494 dc
.SetFont( GetFont() );
2496 if ( HasFlag(wxLC_REPORT
) )
2498 int lineHeight
= GetLineHeight();
2500 size_t visibleFrom
, visibleTo
;
2501 GetVisibleLinesRange(&visibleFrom
, &visibleTo
);
2504 wxCoord xOrig
, yOrig
;
2505 CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
);
2507 // tell the caller cache to cache the data
2510 wxListEvent
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
,
2511 GetParent()->GetId());
2512 evCache
.SetEventObject( GetParent() );
2513 evCache
.m_oldItemIndex
= visibleFrom
;
2514 evCache
.m_itemIndex
= visibleTo
;
2515 GetParent()->GetEventHandler()->ProcessEvent( evCache
);
2518 for ( size_t line
= visibleFrom
; line
<= visibleTo
; line
++ )
2520 rectLine
= GetLineRect(line
);
2522 if ( !IsExposed(rectLine
.x
- xOrig
, rectLine
.y
- yOrig
,
2523 rectLine
.width
, rectLine
.height
) )
2525 // don't redraw unaffected lines to avoid flicker
2529 GetLine(line
)->DrawInReportMode( &dc
,
2531 GetLineHighlightRect(line
),
2532 IsHighlighted(line
) );
2535 if ( HasFlag(wxLC_HRULES
) )
2537 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2538 wxSize clientSize
= GetClientSize();
2540 for ( size_t i
= visibleFrom
; i
<= visibleTo
; i
++ )
2543 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2544 dc
.DrawLine(0 - dev_x
, i
*lineHeight
,
2545 clientSize
.x
- dev_x
, i
*lineHeight
);
2548 // Draw last horizontal rule
2549 if ( visibleTo
> visibleFrom
)
2552 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2553 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
,
2554 clientSize
.x
- dev_x
, m_lineTo
*lineHeight
);
2558 // Draw vertical rules if required
2559 if ( HasFlag(wxLC_VRULES
) && !IsEmpty() )
2561 wxPen
pen(GetRuleColour(), 1, wxSOLID
);
2564 wxRect firstItemRect
;
2565 wxRect lastItemRect
;
2566 GetItemRect(0, firstItemRect
);
2567 GetItemRect(GetItemCount() - 1, lastItemRect
);
2568 int x
= firstItemRect
.GetX();
2570 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2571 for (col
= 0; col
< GetColumnCount(); col
++)
2573 int colWidth
= GetColumnWidth(col
);
2575 dc
.DrawLine(x
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
,
2576 x
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
);
2582 size_t count
= GetItemCount();
2583 for ( size_t i
= 0; i
< count
; i
++ )
2585 GetLine(i
)->Draw( &dc
);
2589 if ( HasCurrent() && m_hasFocus
)
2592 // no rect outline, we already have the background color
2594 dc
.SetPen( *wxBLACK_PEN
);
2595 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
2596 dc
.DrawRectangle( GetLineHighlightRect(m_current
) );
2603 void wxListMainWindow::HighlightAll( bool on
)
2605 if ( IsSingleSel() )
2607 wxASSERT_MSG( !on
, _T("can't do this in a single sel control") );
2609 // we just have one item to turn off
2610 if ( HasCurrent() && IsHighlighted(m_current
) )
2612 HighlightLine(m_current
, FALSE
);
2613 RefreshLine(m_current
);
2618 HighlightLines(0, GetItemCount() - 1, on
);
2622 void wxListMainWindow::SendNotify( size_t line
,
2623 wxEventType command
,
2626 wxListEvent
le( command
, GetParent()->GetId() );
2627 le
.SetEventObject( GetParent() );
2628 le
.m_itemIndex
= line
;
2630 // set only for events which have position
2631 if ( point
!= wxDefaultPosition
)
2632 le
.m_pointDrag
= point
;
2634 if ( command
!= wxEVT_COMMAND_LIST_DELETE_ITEM
)
2636 GetLine(line
)->GetItem( 0, le
.m_item
);
2638 //else: there may be no more such item
2640 GetParent()->GetEventHandler()->ProcessEvent( le
);
2643 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) )
2645 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
2648 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) )
2650 // SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
2653 void wxListMainWindow::EditLabel( long item
)
2655 wxCHECK_RET( (item
>= 0) && ((size_t)item
< GetItemCount()),
2656 wxT("wrong index in wxListCtrl::EditLabel()") );
2658 m_currentEdit
= (size_t)item
;
2660 wxListEvent
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() );
2661 le
.SetEventObject( GetParent() );
2662 le
.m_itemIndex
= item
;
2663 wxListLineData
*data
= GetLine(m_currentEdit
);
2664 wxCHECK_RET( data
, _T("invalid index in EditLabel()") );
2665 data
->GetItem( 0, le
.m_item
);
2666 GetParent()->GetEventHandler()->ProcessEvent( le
);
2668 if (!le
.IsAllowed())
2671 // We have to call this here because the label in question might just have
2672 // been added and no screen update taken place.
2676 wxClientDC
dc(this);
2679 wxString s
= data
->GetText(0);
2680 wxRect rectLabel
= GetLineLabelRect(m_currentEdit
);
2682 rectLabel
.x
= dc
.LogicalToDeviceX( rectLabel
.x
);
2683 rectLabel
.y
= dc
.LogicalToDeviceY( rectLabel
.y
);
2685 wxListTextCtrl
*text
= new wxListTextCtrl
2692 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4),
2693 wxSize(rectLabel
.width
+11,rectLabel
.height
+8)
2698 void wxListMainWindow::OnRenameTimer()
2700 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2702 EditLabel( m_current
);
2705 void wxListMainWindow::OnRenameAccept()
2707 wxListEvent
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() );
2708 le
.SetEventObject( GetParent() );
2709 le
.m_itemIndex
= m_currentEdit
;
2711 wxListLineData
*data
= GetLine(m_currentEdit
);
2712 wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") );
2714 data
->GetItem( 0, le
.m_item
);
2715 le
.m_item
.m_text
= m_renameRes
;
2716 GetParent()->GetEventHandler()->ProcessEvent( le
);
2718 if (!le
.IsAllowed()) return;
2721 info
.m_mask
= wxLIST_MASK_TEXT
;
2722 info
.m_itemId
= le
.m_itemIndex
;
2723 info
.m_text
= m_renameRes
;
2724 info
.SetTextColour(le
.m_item
.GetTextColour());
2728 void wxListMainWindow::OnMouse( wxMouseEvent
&event
)
2730 event
.SetEventObject( GetParent() );
2731 if ( GetParent()->GetEventHandler()->ProcessEvent( event
) )
2734 if ( !HasCurrent() || IsEmpty() )
2740 if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() ||
2741 event
.ButtonDClick()) )
2744 int x
= event
.GetX();
2745 int y
= event
.GetY();
2746 CalcUnscrolledPosition( x
, y
, &x
, &y
);
2748 // where did we hit it (if we did)?
2751 size_t count
= GetItemCount(),
2754 if ( HasFlag(wxLC_REPORT
) )
2756 current
= y
/ GetLineHeight();
2757 if ( current
< count
)
2758 hitResult
= HitTestLine(current
, x
, y
);
2762 // TODO: optimize it too! this is less simple than for report view but
2763 // enumerating all items is still not a way to do it!!
2764 for ( current
= 0; current
< count
; current
++ )
2766 hitResult
= HitTestLine(current
, x
, y
);
2772 if (event
.Dragging())
2774 if (m_dragCount
== 0)
2775 m_dragStart
= wxPoint(x
,y
);
2779 if (m_dragCount
!= 3)
2782 int command
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2783 : wxEVT_COMMAND_LIST_BEGIN_DRAG
;
2785 wxListEvent
le( command
, GetParent()->GetId() );
2786 le
.SetEventObject( GetParent() );
2787 le
.m_pointDrag
= m_dragStart
;
2788 GetParent()->GetEventHandler()->ProcessEvent( le
);
2799 // outside of any item
2803 bool forceClick
= FALSE
;
2804 if (event
.ButtonDClick())
2806 m_renameTimer
->Stop();
2807 m_lastOnSame
= FALSE
;
2809 if ( current
== m_lineBeforeLastClicked
)
2811 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED
);
2817 // the first click was on another item, so don't interpret this as
2818 // a double click, but as a simple click instead
2823 if (event
.LeftUp() && m_lastOnSame
)
2825 if ((current
== m_current
) &&
2826 (hitResult
== wxLIST_HITTEST_ONITEMLABEL
) &&
2827 HasFlag(wxLC_EDIT_LABELS
) )
2829 m_renameTimer
->Start( 100, TRUE
);
2831 m_lastOnSame
= FALSE
;
2833 else if (event
.RightDown())
2835 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
,
2836 event
.GetPosition() );
2838 else if (event
.MiddleDown())
2840 SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
);
2842 else if ( event
.LeftDown() || forceClick
)
2844 m_lineBeforeLastClicked
= m_lineLastClicked
;
2845 m_lineLastClicked
= current
;
2847 size_t oldCurrent
= m_current
;
2849 if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) )
2851 HighlightAll( FALSE
);
2852 m_current
= current
;
2854 ReverseHighlight(m_current
);
2856 else // multi sel & either ctrl or shift is down
2858 if (event
.ControlDown())
2860 m_current
= current
;
2862 ReverseHighlight(m_current
);
2864 else if (event
.ShiftDown())
2866 m_current
= current
;
2868 size_t lineFrom
= oldCurrent
,
2871 if ( lineTo
< lineFrom
)
2874 lineFrom
= m_current
;
2877 HighlightLines(lineFrom
, lineTo
);
2879 else // !ctrl, !shift
2881 // test in the enclosing if should make it impossible
2882 wxFAIL_MSG( _T("how did we get here?") );
2886 if (m_current
!= oldCurrent
)
2888 RefreshLine( oldCurrent
);
2889 OnUnfocusLine( oldCurrent
);
2890 OnFocusLine( m_current
);
2893 // forceClick is only set if the previous click was on another item
2894 m_lastOnSame
= !forceClick
&& (m_current
== oldCurrent
);
2898 void wxListMainWindow::MoveToItem(size_t item
)
2900 if ( item
== (size_t)-1 )
2903 wxRect rect
= GetLineRect(item
);
2905 int client_w
, client_h
;
2906 GetClientSize( &client_w
, &client_h
);
2908 int view_x
= m_xScroll
*GetScrollPos( wxHORIZONTAL
);
2909 int view_y
= m_yScroll
*GetScrollPos( wxVERTICAL
);
2911 if ( HasFlag(wxLC_REPORT
) )
2913 // the next we need the range of lines shown it might be different, so
2915 ResetVisibleLinesRange();
2917 if (rect
.y
< view_y
)
2918 Scroll( -1, rect
.y
/m_yScroll
);
2919 if (rect
.y
+rect
.height
+5 > view_y
+client_h
)
2920 Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll
);
2924 if (rect
.x
-view_x
< 5)
2925 Scroll( (rect
.x
-5)/m_xScroll
, -1 );
2926 if (rect
.x
+rect
.width
-5 > view_x
+client_w
)
2927 Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 );
2931 // ----------------------------------------------------------------------------
2932 // keyboard handling
2933 // ----------------------------------------------------------------------------
2935 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
)
2937 wxCHECK_RET( newCurrent
< (size_t)GetItemCount(),
2938 _T("invalid item index in OnArrowChar()") );
2940 size_t oldCurrent
= m_current
;
2942 // in single selection we just ignore Shift as we can't select several
2944 if ( event
.ShiftDown() && !IsSingleSel() )
2946 m_current
= newCurrent
;
2948 // select all the items between the old and the new one
2949 if ( oldCurrent
> newCurrent
)
2951 newCurrent
= oldCurrent
;
2952 oldCurrent
= m_current
;
2955 HighlightLines(oldCurrent
, newCurrent
);
2959 // all previously selected items are unselected unless ctrl is held
2960 if ( !event
.ControlDown() )
2961 HighlightAll(FALSE
);
2963 m_current
= newCurrent
;
2965 HighlightLine( oldCurrent
, FALSE
);
2966 RefreshLine( oldCurrent
);
2968 if ( !event
.ControlDown() )
2970 HighlightLine( m_current
, TRUE
);
2974 OnUnfocusLine( oldCurrent
);
2975 OnFocusLine( m_current
);
2976 RefreshLine( m_current
);
2981 void wxListMainWindow::OnKeyDown( wxKeyEvent
&event
)
2983 wxWindow
*parent
= GetParent();
2985 /* we propagate the key event up */
2986 wxKeyEvent
ke( wxEVT_KEY_DOWN
);
2987 ke
.m_shiftDown
= event
.m_shiftDown
;
2988 ke
.m_controlDown
= event
.m_controlDown
;
2989 ke
.m_altDown
= event
.m_altDown
;
2990 ke
.m_metaDown
= event
.m_metaDown
;
2991 ke
.m_keyCode
= event
.m_keyCode
;
2994 ke
.SetEventObject( parent
);
2995 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
3000 void wxListMainWindow::OnChar( wxKeyEvent
&event
)
3002 wxWindow
*parent
= GetParent();
3004 /* we send a list_key event up */
3007 wxListEvent
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() );
3008 le
.m_itemIndex
= m_current
;
3009 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3010 le
.m_code
= (int)event
.KeyCode();
3011 le
.SetEventObject( parent
);
3012 parent
->GetEventHandler()->ProcessEvent( le
);
3015 /* we propagate the char event up */
3016 wxKeyEvent
ke( wxEVT_CHAR
);
3017 ke
.m_shiftDown
= event
.m_shiftDown
;
3018 ke
.m_controlDown
= event
.m_controlDown
;
3019 ke
.m_altDown
= event
.m_altDown
;
3020 ke
.m_metaDown
= event
.m_metaDown
;
3021 ke
.m_keyCode
= event
.m_keyCode
;
3024 ke
.SetEventObject( parent
);
3025 if (parent
->GetEventHandler()->ProcessEvent( ke
)) return;
3027 if (event
.KeyCode() == WXK_TAB
)
3029 wxNavigationKeyEvent nevent
;
3030 nevent
.SetWindowChange( event
.ControlDown() );
3031 nevent
.SetDirection( !event
.ShiftDown() );
3032 nevent
.SetEventObject( GetParent()->GetParent() );
3033 nevent
.SetCurrentFocus( m_parent
);
3034 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent
)) return;
3037 /* no item -> nothing to do */
3044 switch (event
.KeyCode())
3047 if ( m_current
> 0 )
3048 OnArrowChar( m_current
- 1, event
);
3052 if ( m_current
< (size_t)GetItemCount() - 1 )
3053 OnArrowChar( m_current
+ 1, event
);
3058 OnArrowChar( GetItemCount() - 1, event
);
3063 OnArrowChar( 0, event
);
3069 if ( HasFlag(wxLC_REPORT
) )
3071 steps
= m_linesPerPage
- 1;
3075 steps
= m_current
% m_linesPerPage
;
3078 int index
= m_current
- steps
;
3082 OnArrowChar( index
, event
);
3089 if ( HasFlag(wxLC_REPORT
) )
3091 steps
= m_linesPerPage
- 1;
3095 steps
= m_linesPerPage
- (m_current
% m_linesPerPage
) - 1;
3098 size_t index
= m_current
+ steps
;
3099 size_t count
= GetItemCount();
3100 if ( index
>= count
)
3103 OnArrowChar( index
, event
);
3108 if ( !HasFlag(wxLC_REPORT
) )
3110 int index
= m_current
- m_linesPerPage
;
3114 OnArrowChar( index
, event
);
3119 if ( !HasFlag(wxLC_REPORT
) )
3121 size_t index
= m_current
+ m_linesPerPage
;
3123 size_t count
= GetItemCount();
3124 if ( index
>= count
)
3127 OnArrowChar( index
, event
);
3132 if ( IsSingleSel() )
3134 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3135 GetParent()->GetId() );
3136 le
.SetEventObject( GetParent() );
3137 le
.m_itemIndex
= m_current
;
3138 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3139 GetParent()->GetEventHandler()->ProcessEvent( le
);
3143 ReverseHighlight(m_current
);
3150 wxListEvent
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
,
3151 GetParent()->GetId() );
3152 le
.SetEventObject( GetParent() );
3153 le
.m_itemIndex
= m_current
;
3154 GetLine(m_current
)->GetItem( 0, le
.m_item
);
3155 GetParent()->GetEventHandler()->ProcessEvent( le
);
3164 // ----------------------------------------------------------------------------
3166 // ----------------------------------------------------------------------------
3169 extern wxWindow
*g_focusWindow
;
3172 void wxListMainWindow::OnSetFocus( wxFocusEvent
&WXUNUSED(event
) )
3177 RefreshLine( m_current
);
3183 g_focusWindow
= GetParent();
3186 wxFocusEvent
event( wxEVT_SET_FOCUS
, GetParent()->GetId() );
3187 event
.SetEventObject( GetParent() );
3188 GetParent()->GetEventHandler()->ProcessEvent( event
);
3191 void wxListMainWindow::OnKillFocus( wxFocusEvent
&WXUNUSED(event
) )
3196 RefreshLine( m_current
);
3199 void wxListMainWindow::DrawImage( int index
, wxDC
*dc
, int x
, int y
)
3201 if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
))
3203 m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3205 else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
))
3207 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3209 else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
))
3211 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3213 else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
))
3215 m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3219 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height
) const
3221 if ( HasFlag(wxLC_ICON
) && m_normal_image_list
)
3223 m_normal_image_list
->GetSize( index
, width
, height
);
3225 else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list
)
3227 m_small_image_list
->GetSize( index
, width
, height
);
3229 else if ( HasFlag(wxLC_LIST
) && m_small_image_list
)
3231 m_small_image_list
->GetSize( index
, width
, height
);
3233 else if ( HasFlag(wxLC_REPORT
) && m_small_image_list
)
3235 m_small_image_list
->GetSize( index
, width
, height
);
3244 int wxListMainWindow::GetTextLength( const wxString
&s
) const
3246 wxClientDC
dc( wxConstCast(this, wxListMainWindow
) );
3247 dc
.SetFont( GetFont() );
3250 dc
.GetTextExtent( s
, &lw
, NULL
);
3252 return lw
+ AUTOSIZE_COL_MARGIN
;
3255 void wxListMainWindow::SetImageList( wxImageList
*imageList
, int which
)
3259 // calc the spacing from the icon size
3262 if ((imageList
) && (imageList
->GetImageCount()) )
3264 imageList
->GetSize(0, width
, height
);
3267 if (which
== wxIMAGE_LIST_NORMAL
)
3269 m_normal_image_list
= imageList
;
3270 m_normal_spacing
= width
+ 8;
3273 if (which
== wxIMAGE_LIST_SMALL
)
3275 m_small_image_list
= imageList
;
3276 m_small_spacing
= width
+ 14;
3280 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall
)
3285 m_small_spacing
= spacing
;
3289 m_normal_spacing
= spacing
;
3293 int wxListMainWindow::GetItemSpacing( bool isSmall
)
3295 return isSmall
? m_small_spacing
: m_normal_spacing
;
3298 // ----------------------------------------------------------------------------
3300 // ----------------------------------------------------------------------------
3302 void wxListMainWindow::SetColumn( int col
, wxListItem
&item
)
3304 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3306 wxCHECK_RET( node
, _T("invalid column index in SetColumn") );
3308 if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
3309 item
.m_width
= GetTextLength( item
.m_text
);
3311 wxListHeaderData
*column
= node
->GetData();
3312 column
->SetItem( item
);
3314 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3316 headerWin
->m_dirty
= TRUE
;
3320 // invalidate it as it has to be recalculated
3324 void wxListMainWindow::SetColumnWidth( int col
, int width
)
3326 wxCHECK_RET( col
>= 0 && col
< GetColumnCount(),
3327 _T("invalid column index") );
3329 wxCHECK_RET( HasFlag(wxLC_REPORT
),
3330 _T("SetColumnWidth() can only be called in report mode.") );
3334 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3335 wxCHECK_RET( node
, _T("no column?") );
3337 wxListHeaderData
*column
= node
->GetData();
3339 size_t count
= GetItemCount();
3341 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
3343 width
= GetTextLength(column
->GetText());
3345 else if ( width
== wxLIST_AUTOSIZE
)
3349 // TODO: determine the max width somehow...
3350 width
= WIDTH_COL_DEFAULT
;
3354 wxClientDC
dc(this);
3355 dc
.SetFont( GetFont() );
3357 int max
= AUTOSIZE_COL_MARGIN
;
3359 for ( size_t i
= 0; i
< count
; i
++ )
3361 wxListLineData
*line
= GetLine(i
);
3362 wxListItemDataList::Node
*n
= line
->m_items
.Item( col
);
3364 wxCHECK_RET( n
, _T("no subitem?") );
3366 wxListItemData
*item
= n
->GetData();
3369 if (item
->HasImage())
3372 GetImageSize( item
->GetImage(), ix
, iy
);
3376 if (item
->HasText())
3379 dc
.GetTextExtent( item
->GetText(), &w
, NULL
);
3387 width
= max
+ AUTOSIZE_COL_MARGIN
;
3391 column
->SetWidth( width
);
3393 // invalidate it as it has to be recalculated
3397 int wxListMainWindow::GetHeaderWidth() const
3399 if ( !m_headerWidth
)
3401 wxListMainWindow
*self
= wxConstCast(this, wxListMainWindow
);
3403 size_t count
= GetColumnCount();
3404 for ( size_t col
= 0; col
< count
; col
++ )
3406 self
->m_headerWidth
+= GetColumnWidth(col
);
3410 return m_headerWidth
;
3413 void wxListMainWindow::GetColumn( int col
, wxListItem
&item
) const
3415 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3416 wxCHECK_RET( node
, _T("invalid column index in GetColumn") );
3418 wxListHeaderData
*column
= node
->GetData();
3419 column
->GetItem( item
);
3422 int wxListMainWindow::GetColumnWidth( int col
) const
3424 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3425 wxCHECK_MSG( node
, 0, _T("invalid column index") );
3427 wxListHeaderData
*column
= node
->GetData();
3428 return column
->GetWidth();
3431 // ----------------------------------------------------------------------------
3433 // ----------------------------------------------------------------------------
3435 void wxListMainWindow::SetItem( wxListItem
&item
)
3437 long id
= item
.m_itemId
;
3438 wxCHECK_RET( id
>= 0 && (size_t)id
< GetItemCount(),
3439 _T("invalid item index in SetItem") );
3443 wxListLineData
*line
= GetLine((size_t)id
);
3444 line
->SetItem( item
.m_col
, item
);
3447 if ( InReportView() )
3449 // just refresh the line to show the new value of the text/image
3450 RefreshLine((size_t)id
);
3454 // refresh everything (resulting in horrible flicker - FIXME!)
3459 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask
)
3461 wxCHECK_RET( litem
>= 0 && (size_t)litem
< GetItemCount(),
3462 _T("invalid list ctrl item index in SetItem") );
3464 size_t oldCurrent
= m_current
;
3465 size_t item
= (size_t)litem
; // sdafe because of the check above
3467 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3469 if ( state
& wxLIST_STATE_FOCUSED
)
3471 // don't do anything if this item is already focused
3472 if ( item
!= m_current
)
3474 OnUnfocusLine( m_current
);
3476 OnFocusLine( m_current
);
3478 if ( IsSingleSel() && (oldCurrent
!= (size_t)-1) )
3480 HighlightLine(oldCurrent
, FALSE
);
3481 RefreshLine(oldCurrent
);
3484 RefreshLine( m_current
);
3489 // don't do anything if this item is not focused
3490 if ( item
== m_current
)
3492 OnUnfocusLine( m_current
);
3493 m_current
= (size_t)-1;
3498 if ( stateMask
& wxLIST_STATE_SELECTED
)
3500 bool on
= (state
& wxLIST_STATE_SELECTED
) != 0;
3502 if ( IsSingleSel() )
3506 // selecting the item also makes it the focused one in the
3508 if ( m_current
!= item
)
3510 OnUnfocusLine( m_current
);
3512 OnFocusLine( m_current
);
3514 if ( oldCurrent
!= (size_t)-1 )
3516 HighlightLine( oldCurrent
, FALSE
);
3517 RefreshLine( oldCurrent
);
3523 // only the current item may be selected anyhow
3524 if ( item
!= m_current
)
3529 if ( HighlightLine(item
, on
) )
3536 int wxListMainWindow::GetItemState( long item
, long stateMask
)
3538 wxCHECK_MSG( item
>= 0 && (size_t)item
< GetItemCount(), 0,
3539 _T("invalid list ctrl item index in GetItemState()") );
3541 int ret
= wxLIST_STATE_DONTCARE
;
3543 if ( stateMask
& wxLIST_STATE_FOCUSED
)
3545 if ( (size_t)item
== m_current
)
3546 ret
|= wxLIST_STATE_FOCUSED
;
3549 if ( stateMask
& wxLIST_STATE_SELECTED
)
3551 if ( IsHighlighted(item
) )
3552 ret
|= wxLIST_STATE_SELECTED
;
3558 void wxListMainWindow::GetItem( wxListItem
&item
)
3560 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
< GetItemCount(),
3561 _T("invalid item index in GetItem") );
3563 wxListLineData
*line
= GetLine((size_t)item
.m_itemId
);
3564 line
->GetItem( item
.m_col
, item
);
3567 // ----------------------------------------------------------------------------
3569 // ----------------------------------------------------------------------------
3571 size_t wxListMainWindow::GetItemCount() const
3573 return IsVirtual() ? m_countVirt
: m_lines
.GetCount();
3576 void wxListMainWindow::SetItemCount(long count
)
3578 m_selStore
.SetItemCount(count
);
3579 m_countVirt
= count
;
3581 ResetVisibleLinesRange();
3583 // scrollbars must be reset
3587 int wxListMainWindow::GetSelectedItemCount()
3589 // deal with the quick case first
3590 if ( IsSingleSel() )
3592 return HasCurrent() ? IsHighlighted(m_current
) : FALSE
;
3595 // virtual controls remmebers all its selections itself
3597 return m_selStore
.GetSelectedCount();
3599 // TODO: we probably should maintain the number of items selected even for
3600 // non virtual controls as enumerating all lines is really slow...
3601 size_t countSel
= 0;
3602 size_t count
= GetItemCount();
3603 for ( size_t line
= 0; line
< count
; line
++ )
3605 if ( GetLine(line
)->IsHighlighted() )
3612 // ----------------------------------------------------------------------------
3613 // item position/size
3614 // ----------------------------------------------------------------------------
3616 void wxListMainWindow::GetItemRect( long index
, wxRect
&rect
)
3618 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3619 _T("invalid index in GetItemRect") );
3621 rect
= GetLineRect((size_t)index
);
3623 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
3626 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
)
3629 GetItemRect(item
, rect
);
3637 // ----------------------------------------------------------------------------
3638 // geometry calculation
3639 // ----------------------------------------------------------------------------
3641 void wxListMainWindow::RecalculatePositions(bool noRefresh
)
3643 wxClientDC
dc( this );
3644 dc
.SetFont( GetFont() );
3647 if ( HasFlag(wxLC_ICON
) )
3648 iconSpacing
= m_normal_spacing
;
3649 else if ( HasFlag(wxLC_SMALL_ICON
) )
3650 iconSpacing
= m_small_spacing
;
3656 GetClientSize( &clientWidth
, &clientHeight
);
3658 if ( HasFlag(wxLC_REPORT
) )
3660 // all lines have the same height
3661 int lineHeight
= GetLineHeight();
3663 // scroll one line per step
3664 m_yScroll
= lineHeight
;
3666 size_t lineCount
= GetItemCount();
3667 int entireHeight
= lineCount
*lineHeight
+ LINE_SPACING
;
3669 m_linesPerPage
= clientHeight
/ lineHeight
;
3671 ResetVisibleLinesRange();
3673 SetScrollbars( m_xScroll
, m_yScroll
,
3674 (GetHeaderWidth() + m_xScroll
- 1)/m_xScroll
,
3675 (entireHeight
+ m_yScroll
- 1)/m_yScroll
,
3676 GetScrollPos(wxHORIZONTAL
),
3677 GetScrollPos(wxVERTICAL
),
3682 // at first we try without any scrollbar. if the items don't
3683 // fit into the window, we recalculate after subtracting an
3684 // approximated 15 pt for the horizontal scrollbar
3686 clientHeight
-= 4; // sunken frame
3688 int entireWidth
= 0;
3690 for (int tries
= 0; tries
< 2; tries
++)
3697 int currentlyVisibleLines
= 0;
3699 size_t count
= GetItemCount();
3700 for (size_t i
= 0; i
< count
; i
++)
3702 currentlyVisibleLines
++;
3703 wxListLineData
*line
= GetLine(i
);
3704 line
->CalculateSize( &dc
, iconSpacing
);
3705 line
->SetPosition( x
, y
, clientWidth
, iconSpacing
);
3707 wxSize sizeLine
= GetLineSize(i
);
3709 if ( maxWidth
< sizeLine
.x
)
3710 maxWidth
= sizeLine
.x
;
3713 if (currentlyVisibleLines
> m_linesPerPage
)
3714 m_linesPerPage
= currentlyVisibleLines
;
3716 // assume that the size of the next one is the same... (FIXME)
3717 if ( y
+ sizeLine
.y
- 6 >= clientHeight
)
3719 currentlyVisibleLines
= 0;
3722 entireWidth
+= maxWidth
+6;
3725 if ( i
== count
- 1 )
3726 entireWidth
+= maxWidth
;
3727 if ((tries
== 0) && (entireWidth
> clientWidth
))
3729 clientHeight
-= 15; // scrollbar height
3731 currentlyVisibleLines
= 0;
3734 if ( i
== count
- 1 )
3735 tries
= 1; // everything fits, no second try required
3739 int scroll_pos
= GetScrollPos( wxHORIZONTAL
);
3740 SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE
);
3745 // FIXME: why should we call it from here?
3752 void wxListMainWindow::RefreshAll()
3757 wxListHeaderWindow
*headerWin
= GetListCtrl()->m_headerWin
;
3760 headerWin
->m_dirty
= FALSE
;
3761 headerWin
->Refresh();
3765 void wxListMainWindow::UpdateCurrent()
3767 if ( !HasCurrent() && !IsEmpty() )
3772 if ( m_current
!= (size_t)-1 )
3774 OnFocusLine( m_current
);
3778 long wxListMainWindow::GetNextItem( long item
,
3779 int WXUNUSED(geometry
),
3783 max
= GetItemCount();
3784 wxCHECK_MSG( (ret
== -1) || (ret
< max
), -1,
3785 _T("invalid listctrl index in GetNextItem()") );
3787 // notice that we start with the next item (or the first one if item == -1)
3788 // and this is intentional to allow writing a simple loop to iterate over
3789 // all selected items
3793 // this is not an error because the index was ok initially, just no
3804 size_t count
= GetItemCount();
3805 for ( size_t line
= (size_t)ret
; line
< count
; line
++ )
3807 if ( (state
& wxLIST_STATE_FOCUSED
) && (line
== m_current
) )
3810 if ( (state
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) )
3817 // ----------------------------------------------------------------------------
3819 // ----------------------------------------------------------------------------
3821 void wxListMainWindow::DeleteItem( long lindex
)
3823 size_t count
= GetItemCount();
3825 wxCHECK_RET( (lindex
>= 0) && ((size_t)lindex
< count
),
3826 _T("invalid item index in DeleteItem") );
3828 size_t index
= (size_t)lindex
;
3830 // we don't need to adjust the index for the previous items
3831 if ( HasCurrent() && m_current
>= index
)
3833 // if the current item is being deleted, we want the next one to
3834 // become selected - unless there is no next one - so don't adjust
3835 // m_current in this case
3836 if ( m_current
!= index
|| m_current
== count
- 1 )
3842 if ( InReportView() )
3844 ResetVisibleLinesRange();
3851 m_selStore
.OnItemDelete(index
);
3855 m_lines
.RemoveAt( index
);
3860 SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
);
3862 RefreshAfter(index
);
3865 void wxListMainWindow::DeleteColumn( int col
)
3867 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
3869 wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") );
3872 m_columns
.DeleteNode( node
);
3875 void wxListMainWindow::DoDeleteAllItems()
3879 // nothing to do - in particular, don't send the event
3885 // to make the deletion of all items faster, we don't send the
3886 // notifications for each item deletion in this case but only one event
3887 // for all of them: this is compatible with wxMSW and documented in
3888 // DeleteAllItems() description
3890 wxListEvent
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() );
3891 event
.SetEventObject( GetParent() );
3892 GetParent()->GetEventHandler()->ProcessEvent( event
);
3901 if ( InReportView() )
3903 ResetVisibleLinesRange();
3909 void wxListMainWindow::DeleteAllItems()
3913 RecalculatePositions();
3916 void wxListMainWindow::DeleteEverything()
3923 // ----------------------------------------------------------------------------
3924 // scanning for an item
3925 // ----------------------------------------------------------------------------
3927 void wxListMainWindow::EnsureVisible( long index
)
3929 wxCHECK_RET( index
>= 0 && (size_t)index
< GetItemCount(),
3930 _T("invalid index in EnsureVisible") );
3932 // We have to call this here because the label in question might just have
3933 // been added and its position is not known yet
3938 RecalculatePositions(TRUE
/* no refresh */);
3941 MoveToItem((size_t)index
);
3944 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) )
3951 size_t count
= GetItemCount();
3952 for ( size_t i
= (size_t)pos
; i
< count
; i
++ )
3954 wxListLineData
*line
= GetLine(i
);
3955 if ( line
->GetText(0) == tmp
)
3962 long wxListMainWindow::FindItem(long start
, long data
)
3968 size_t count
= GetItemCount();
3969 for (size_t i
= (size_t)pos
; i
< count
; i
++)
3971 wxListLineData
*line
= GetLine(i
);
3973 line
->GetItem( 0, item
);
3974 if (item
.m_data
== data
)
3981 long wxListMainWindow::HitTest( int x
, int y
, int &flags
)
3983 CalcUnscrolledPosition( x
, y
, &x
, &y
);
3985 if ( HasFlag(wxLC_REPORT
) )
3987 size_t current
= y
/ GetLineHeight();
3988 flags
= HitTestLine(current
, x
, y
);
3994 // TODO: optimize it too! this is less simple than for report view but
3995 // enumerating all items is still not a way to do it!!
3996 size_t count
= GetItemCount();
3997 for ( size_t current
= 0; current
< count
; current
++ )
3999 flags
= HitTestLine(current
, x
, y
);
4008 // ----------------------------------------------------------------------------
4010 // ----------------------------------------------------------------------------
4012 void wxListMainWindow::InsertItem( wxListItem
&item
)
4014 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
4016 size_t count
= GetItemCount();
4017 wxCHECK_RET( item
.m_itemId
>= 0 && (size_t)item
.m_itemId
<= count
,
4018 _T("invalid item index") );
4020 size_t id
= item
.m_itemId
;
4025 if ( HasFlag(wxLC_REPORT
) )
4027 else if ( HasFlag(wxLC_LIST
) )
4029 else if ( HasFlag(wxLC_ICON
) )
4031 else if ( HasFlag(wxLC_SMALL_ICON
) )
4032 mode
= wxLC_ICON
; // no typo
4035 wxFAIL_MSG( _T("unknown mode") );
4038 wxListLineData
*line
= new wxListLineData(this);
4040 line
->SetItem( 0, item
);
4042 m_lines
.Insert( line
, id
);
4045 RefreshLines(id
, GetItemCount() - 1);
4048 void wxListMainWindow::InsertColumn( long col
, wxListItem
&item
)
4051 if ( HasFlag(wxLC_REPORT
) )
4053 if (item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
4054 item
.m_width
= GetTextLength( item
.m_text
);
4055 wxListHeaderData
*column
= new wxListHeaderData( item
);
4056 if ((col
>= 0) && (col
< (int)m_columns
.GetCount()))
4058 wxListHeaderDataList::Node
*node
= m_columns
.Item( col
);
4059 m_columns
.Insert( node
, column
);
4063 m_columns
.Append( column
);
4068 // ----------------------------------------------------------------------------
4070 // ----------------------------------------------------------------------------
4072 wxListCtrlCompare list_ctrl_compare_func_2
;
4073 long list_ctrl_compare_data
;
4075 int LINKAGEMODE
list_ctrl_compare_func_1( wxListLineData
**arg1
, wxListLineData
**arg2
)
4077 wxListLineData
*line1
= *arg1
;
4078 wxListLineData
*line2
= *arg2
;
4080 line1
->GetItem( 0, item
);
4081 long data1
= item
.m_data
;
4082 line2
->GetItem( 0, item
);
4083 long data2
= item
.m_data
;
4084 return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data
);
4087 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data
)
4089 list_ctrl_compare_func_2
= fn
;
4090 list_ctrl_compare_data
= data
;
4091 m_lines
.Sort( list_ctrl_compare_func_1
);
4095 // ----------------------------------------------------------------------------
4097 // ----------------------------------------------------------------------------
4099 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
)
4101 // update our idea of which lines are shown when we redraw the window the
4103 ResetVisibleLinesRange();
4106 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4107 wxScrolledWindow::OnScroll(event
);
4109 HandleOnScroll( event
);
4112 if ( event
.GetOrientation() == wxHORIZONTAL
&& HasHeader() )
4114 wxListCtrl
* lc
= GetListCtrl();
4115 wxCHECK_RET( lc
, _T("no listctrl window?") );
4117 lc
->m_headerWin
->Refresh() ;
4119 lc
->m_headerWin
->MacUpdateImmediately() ;
4124 int wxListMainWindow::GetCountPerPage() const
4126 if ( !m_linesPerPage
)
4128 wxConstCast(this, wxListMainWindow
)->
4129 m_linesPerPage
= GetClientSize().y
/ GetLineHeight();
4132 return m_linesPerPage
;
4135 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
)
4137 wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") );
4139 if ( m_lineFrom
== (size_t)-1 )
4141 size_t count
= GetItemCount();
4144 m_lineFrom
= GetScrollPos(wxVERTICAL
);
4146 // this may happen if SetScrollbars() hadn't been called yet
4147 if ( m_lineFrom
>= count
)
4148 m_lineFrom
= count
- 1;
4150 // we redraw one extra line but this is needed to make the redrawing
4151 // logic work when there is a fractional number of lines on screen
4152 m_lineTo
= m_lineFrom
+ m_linesPerPage
;
4153 if ( m_lineTo
>= count
)
4154 m_lineTo
= count
- 1;
4156 else // empty control
4159 m_lineTo
= (size_t)-1;
4163 wxASSERT_MSG( IsEmpty() ||
4164 (m_lineFrom
<= m_lineTo
&& m_lineTo
< GetItemCount()),
4165 _T("GetVisibleLinesRange() returns incorrect result") );
4173 // -------------------------------------------------------------------------------------
4175 // -------------------------------------------------------------------------------------
4177 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
4179 wxListItem::wxListItem()
4188 m_format
= wxLIST_FORMAT_CENTRE
;
4194 void wxListItem::Clear()
4203 m_format
= wxLIST_FORMAT_CENTRE
;
4210 void wxListItem::ClearAttributes()
4219 // -------------------------------------------------------------------------------------
4221 // -------------------------------------------------------------------------------------
4223 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
4225 wxListEvent::wxListEvent( wxEventType commandType
, int id
)
4226 : wxNotifyEvent( commandType
, id
)
4232 m_cancelled
= FALSE
;
4237 void wxListEvent::CopyObject(wxObject
& object_dest
) const
4239 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
4241 wxNotifyEvent::CopyObject(object_dest
);
4243 obj
->m_code
= m_code
;
4244 obj
->m_itemIndex
= m_itemIndex
;
4245 obj
->m_oldItemIndex
= m_oldItemIndex
;
4247 obj
->m_cancelled
= m_cancelled
;
4248 obj
->m_pointDrag
= m_pointDrag
;
4249 obj
->m_item
.m_mask
= m_item
.m_mask
;
4250 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
4251 obj
->m_item
.m_col
= m_item
.m_col
;
4252 obj
->m_item
.m_state
= m_item
.m_state
;
4253 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
4254 obj
->m_item
.m_text
= m_item
.m_text
;
4255 obj
->m_item
.m_image
= m_item
.m_image
;
4256 obj
->m_item
.m_data
= m_item
.m_data
;
4257 obj
->m_item
.m_format
= m_item
.m_format
;
4258 obj
->m_item
.m_width
= m_item
.m_width
;
4260 if ( m_item
.HasAttributes() )
4262 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
4266 // -------------------------------------------------------------------------------------
4268 // -------------------------------------------------------------------------------------
4270 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
4272 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
)
4273 EVT_SIZE(wxListCtrl::OnSize
)
4274 EVT_IDLE(wxListCtrl::OnIdle
)
4277 wxListCtrl::wxListCtrl()
4279 m_imageListNormal
= (wxImageList
*) NULL
;
4280 m_imageListSmall
= (wxImageList
*) NULL
;
4281 m_imageListState
= (wxImageList
*) NULL
;
4283 m_ownsImageListNormal
=
4284 m_ownsImageListSmall
=
4285 m_ownsImageListState
= FALSE
;
4287 m_mainWin
= (wxListMainWindow
*) NULL
;
4288 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4291 wxListCtrl::~wxListCtrl()
4294 m_mainWin
->ResetCurrent();
4296 if (m_ownsImageListNormal
)
4297 delete m_imageListNormal
;
4298 if (m_ownsImageListSmall
)
4299 delete m_imageListSmall
;
4300 if (m_ownsImageListState
)
4301 delete m_imageListState
;
4304 void wxListCtrl::CreateHeaderWindow()
4306 m_headerWin
= new wxListHeaderWindow
4308 this, -1, m_mainWin
,
4310 wxSize(GetClientSize().x
, HEADER_HEIGHT
),
4315 bool wxListCtrl::Create(wxWindow
*parent
,
4320 const wxValidator
&validator
,
4321 const wxString
&name
)
4325 m_imageListState
= (wxImageList
*) NULL
;
4326 m_ownsImageListNormal
=
4327 m_ownsImageListSmall
=
4328 m_ownsImageListState
= FALSE
;
4330 m_mainWin
= (wxListMainWindow
*) NULL
;
4331 m_headerWin
= (wxListHeaderWindow
*) NULL
;
4333 if ( !(style
& wxLC_MASK_TYPE
) )
4335 style
= style
| wxLC_LIST
;
4338 if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name
) )
4341 // don't create the inner window with the border
4342 style
&= ~wxSUNKEN_BORDER
;
4344 m_mainWin
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style
);
4346 if ( HasFlag(wxLC_REPORT
) )
4348 CreateHeaderWindow();
4350 if ( HasFlag(wxLC_NO_HEADER
) )
4352 // VZ: why do we create it at all then?
4353 m_headerWin
->Show( FALSE
);
4360 void wxListCtrl::SetSingleStyle( long style
, bool add
)
4362 wxASSERT_MSG( !(style
& wxLC_VIRTUAL
),
4363 _T("wxLC_VIRTUAL can't be [un]set") );
4365 long flag
= GetWindowStyle();
4369 if (style
& wxLC_MASK_TYPE
)
4370 flag
&= ~(wxLC_MASK_TYPE
| wxLC_VIRTUAL
);
4371 if (style
& wxLC_MASK_ALIGN
)
4372 flag
&= ~wxLC_MASK_ALIGN
;
4373 if (style
& wxLC_MASK_SORT
)
4374 flag
&= ~wxLC_MASK_SORT
;
4386 SetWindowStyleFlag( flag
);
4389 void wxListCtrl::SetWindowStyleFlag( long flag
)
4393 m_mainWin
->DeleteEverything();
4395 // has the header visibility changed?
4396 bool hasHeader
= HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
),
4397 willHaveHeader
= (flag
& wxLC_REPORT
) && !(flag
& wxLC_NO_HEADER
);
4399 if ( hasHeader
!= willHaveHeader
)
4406 // don't delete, just hide, as we can reuse it later
4407 m_headerWin
->Show(FALSE
);
4409 //else: nothing to do
4411 else // must show header
4415 CreateHeaderWindow();
4417 else // already have it, just show
4419 m_headerWin
->Show( TRUE
);
4423 ResizeReportView(willHaveHeader
);
4427 wxWindow::SetWindowStyleFlag( flag
);
4430 bool wxListCtrl::GetColumn(int col
, wxListItem
&item
) const
4432 m_mainWin
->GetColumn( col
, item
);
4436 bool wxListCtrl::SetColumn( int col
, wxListItem
& item
)
4438 m_mainWin
->SetColumn( col
, item
);
4442 int wxListCtrl::GetColumnWidth( int col
) const
4444 return m_mainWin
->GetColumnWidth( col
);
4447 bool wxListCtrl::SetColumnWidth( int col
, int width
)
4449 m_mainWin
->SetColumnWidth( col
, width
);
4453 int wxListCtrl::GetCountPerPage() const
4455 return m_mainWin
->GetCountPerPage(); // different from Windows ?
4458 bool wxListCtrl::GetItem( wxListItem
&info
) const
4460 m_mainWin
->GetItem( info
);
4464 bool wxListCtrl::SetItem( wxListItem
&info
)
4466 m_mainWin
->SetItem( info
);
4470 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId
)
4473 info
.m_text
= label
;
4474 info
.m_mask
= wxLIST_MASK_TEXT
;
4475 info
.m_itemId
= index
;
4479 info
.m_image
= imageId
;
4480 info
.m_mask
|= wxLIST_MASK_IMAGE
;
4482 m_mainWin
->SetItem(info
);
4486 int wxListCtrl::GetItemState( long item
, long stateMask
) const
4488 return m_mainWin
->GetItemState( item
, stateMask
);
4491 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask
)
4493 m_mainWin
->SetItemState( item
, state
, stateMask
);
4497 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) )
4500 info
.m_image
= image
;
4501 info
.m_mask
= wxLIST_MASK_IMAGE
;
4502 info
.m_itemId
= item
;
4503 m_mainWin
->SetItem( info
);
4507 wxString
wxListCtrl::GetItemText( long item
) const
4510 info
.m_itemId
= item
;
4511 m_mainWin
->GetItem( info
);
4515 void wxListCtrl::SetItemText( long item
, const wxString
&str
)
4518 info
.m_mask
= wxLIST_MASK_TEXT
;
4519 info
.m_itemId
= item
;
4521 m_mainWin
->SetItem( info
);
4524 long wxListCtrl::GetItemData( long item
) const
4527 info
.m_itemId
= item
;
4528 m_mainWin
->GetItem( info
);
4532 bool wxListCtrl::SetItemData( long item
, long data
)
4535 info
.m_mask
= wxLIST_MASK_DATA
;
4536 info
.m_itemId
= item
;
4538 m_mainWin
->SetItem( info
);
4542 bool wxListCtrl::GetItemRect( long item
, wxRect
&rect
, int WXUNUSED(code
) ) const
4544 m_mainWin
->GetItemRect( item
, rect
);
4548 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos
) const
4550 m_mainWin
->GetItemPosition( item
, pos
);
4554 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) )
4559 int wxListCtrl::GetItemCount() const
4561 return m_mainWin
->GetItemCount();
4564 int wxListCtrl::GetColumnCount() const
4566 return m_mainWin
->GetColumnCount();
4569 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall
)
4571 m_mainWin
->SetItemSpacing( spacing
, isSmall
);
4574 int wxListCtrl::GetItemSpacing( bool isSmall
) const
4576 return m_mainWin
->GetItemSpacing( isSmall
);
4579 int wxListCtrl::GetSelectedItemCount() const
4581 return m_mainWin
->GetSelectedItemCount();
4584 wxColour
wxListCtrl::GetTextColour() const
4586 return GetForegroundColour();
4589 void wxListCtrl::SetTextColour(const wxColour
& col
)
4591 SetForegroundColour(col
);
4594 long wxListCtrl::GetTopItem() const
4599 long wxListCtrl::GetNextItem( long item
, int geom
, int state
) const
4601 return m_mainWin
->GetNextItem( item
, geom
, state
);
4604 wxImageList
*wxListCtrl::GetImageList(int which
) const
4606 if (which
== wxIMAGE_LIST_NORMAL
)
4608 return m_imageListNormal
;
4610 else if (which
== wxIMAGE_LIST_SMALL
)
4612 return m_imageListSmall
;
4614 else if (which
== wxIMAGE_LIST_STATE
)
4616 return m_imageListState
;
4618 return (wxImageList
*) NULL
;
4621 void wxListCtrl::SetImageList( wxImageList
*imageList
, int which
)
4623 if ( which
== wxIMAGE_LIST_NORMAL
)
4625 if (m_ownsImageListNormal
) delete m_imageListNormal
;
4626 m_imageListNormal
= imageList
;
4627 m_ownsImageListNormal
= FALSE
;
4629 else if ( which
== wxIMAGE_LIST_SMALL
)
4631 if (m_ownsImageListSmall
) delete m_imageListSmall
;
4632 m_imageListSmall
= imageList
;
4633 m_ownsImageListSmall
= FALSE
;
4635 else if ( which
== wxIMAGE_LIST_STATE
)
4637 if (m_ownsImageListState
) delete m_imageListState
;
4638 m_imageListState
= imageList
;
4639 m_ownsImageListState
= FALSE
;
4642 m_mainWin
->SetImageList( imageList
, which
);
4645 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
4647 SetImageList(imageList
, which
);
4648 if ( which
== wxIMAGE_LIST_NORMAL
)
4649 m_ownsImageListNormal
= TRUE
;
4650 else if ( which
== wxIMAGE_LIST_SMALL
)
4651 m_ownsImageListSmall
= TRUE
;
4652 else if ( which
== wxIMAGE_LIST_STATE
)
4653 m_ownsImageListState
= TRUE
;
4656 bool wxListCtrl::Arrange( int WXUNUSED(flag
) )
4661 bool wxListCtrl::DeleteItem( long item
)
4663 m_mainWin
->DeleteItem( item
);
4667 bool wxListCtrl::DeleteAllItems()
4669 m_mainWin
->DeleteAllItems();
4673 bool wxListCtrl::DeleteAllColumns()
4675 size_t count
= m_mainWin
->m_columns
.GetCount();
4676 for ( size_t n
= 0; n
< count
; n
++ )
4682 void wxListCtrl::ClearAll()
4684 m_mainWin
->DeleteEverything();
4687 bool wxListCtrl::DeleteColumn( int col
)
4689 m_mainWin
->DeleteColumn( col
);
4693 void wxListCtrl::Edit( long item
)
4695 m_mainWin
->EditLabel( item
);
4698 bool wxListCtrl::EnsureVisible( long item
)
4700 m_mainWin
->EnsureVisible( item
);
4704 long wxListCtrl::FindItem( long start
, const wxString
& str
, bool partial
)
4706 return m_mainWin
->FindItem( start
, str
, partial
);
4709 long wxListCtrl::FindItem( long start
, long data
)
4711 return m_mainWin
->FindItem( start
, data
);
4714 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
),
4715 int WXUNUSED(direction
))
4720 long wxListCtrl::HitTest( const wxPoint
&point
, int &flags
)
4722 return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags
);
4725 long wxListCtrl::InsertItem( wxListItem
& info
)
4727 m_mainWin
->InsertItem( info
);
4728 return info
.m_itemId
;
4731 long wxListCtrl::InsertItem( long index
, const wxString
&label
)
4734 info
.m_text
= label
;
4735 info
.m_mask
= wxLIST_MASK_TEXT
;
4736 info
.m_itemId
= index
;
4737 return InsertItem( info
);
4740 long wxListCtrl::InsertItem( long index
, int imageIndex
)
4743 info
.m_mask
= wxLIST_MASK_IMAGE
;
4744 info
.m_image
= imageIndex
;
4745 info
.m_itemId
= index
;
4746 return InsertItem( info
);
4749 long wxListCtrl::InsertItem( long index
, const wxString
&label
, int imageIndex
)
4752 info
.m_text
= label
;
4753 info
.m_image
= imageIndex
;
4754 info
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_IMAGE
;
4755 info
.m_itemId
= index
;
4756 return InsertItem( info
);
4759 long wxListCtrl::InsertColumn( long col
, wxListItem
&item
)
4761 wxASSERT( m_headerWin
);
4762 m_mainWin
->InsertColumn( col
, item
);
4763 m_headerWin
->Refresh();
4768 long wxListCtrl::InsertColumn( long col
, const wxString
&heading
,
4769 int format
, int width
)
4772 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
4773 item
.m_text
= heading
;
4776 item
.m_mask
|= wxLIST_MASK_WIDTH
;
4777 item
.m_width
= width
;
4779 item
.m_format
= format
;
4781 return InsertColumn( col
, item
);
4784 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) )
4790 // fn is a function which takes 3 long arguments: item1, item2, data.
4791 // item1 is the long data associated with a first item (NOT the index).
4792 // item2 is the long data associated with a second item (NOT the index).
4793 // data is the same value as passed to SortItems.
4794 // The return value is a negative number if the first item should precede the second
4795 // item, a positive number of the second item should precede the first,
4796 // or zero if the two items are equivalent.
4797 // data is arbitrary data to be passed to the sort function.
4799 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data
)
4801 m_mainWin
->SortItems( fn
, data
);
4805 // ----------------------------------------------------------------------------
4807 // ----------------------------------------------------------------------------
4809 void wxListCtrl::OnSize(wxSizeEvent
& event
)
4814 ResizeReportView(m_mainWin
->HasHeader());
4816 m_mainWin
->RecalculatePositions();
4819 void wxListCtrl::ResizeReportView(bool showHeader
)
4822 GetClientSize( &cw
, &ch
);
4826 m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT
);
4827 m_mainWin
->SetSize( 0, HEADER_HEIGHT
+ 1, cw
, ch
- HEADER_HEIGHT
- 1 );
4829 else // no header window
4831 m_mainWin
->SetSize( 0, 0, cw
, ch
);
4835 void wxListCtrl::OnIdle( wxIdleEvent
& event
)
4839 // do it only if needed
4840 if ( !m_mainWin
->m_dirty
)
4843 m_mainWin
->RecalculatePositions();
4846 // ----------------------------------------------------------------------------
4848 // ----------------------------------------------------------------------------
4850 bool wxListCtrl::SetBackgroundColour( const wxColour
&colour
)
4854 m_mainWin
->SetBackgroundColour( colour
);
4855 m_mainWin
->m_dirty
= TRUE
;
4861 bool wxListCtrl::SetForegroundColour( const wxColour
&colour
)
4863 if ( !wxWindow::SetForegroundColour( colour
) )
4868 m_mainWin
->SetForegroundColour( colour
);
4869 m_mainWin
->m_dirty
= TRUE
;
4874 m_headerWin
->SetForegroundColour( colour
);
4880 bool wxListCtrl::SetFont( const wxFont
&font
)
4882 if ( !wxWindow::SetFont( font
) )
4887 m_mainWin
->SetFont( font
);
4888 m_mainWin
->m_dirty
= TRUE
;
4893 m_headerWin
->SetFont( font
);
4899 // ----------------------------------------------------------------------------
4900 // methods forwarded to m_mainWin
4901 // ----------------------------------------------------------------------------
4903 #if wxUSE_DRAG_AND_DROP
4905 void wxListCtrl::SetDropTarget( wxDropTarget
*dropTarget
)
4907 m_mainWin
->SetDropTarget( dropTarget
);
4910 wxDropTarget
*wxListCtrl::GetDropTarget() const
4912 return m_mainWin
->GetDropTarget();
4915 #endif // wxUSE_DRAG_AND_DROP
4917 bool wxListCtrl::SetCursor( const wxCursor
&cursor
)
4919 return m_mainWin
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
;
4922 wxColour
wxListCtrl::GetBackgroundColour() const
4924 return m_mainWin
? m_mainWin
->GetBackgroundColour() : wxColour();
4927 wxColour
wxListCtrl::GetForegroundColour() const
4929 return m_mainWin
? m_mainWin
->GetForegroundColour() : wxColour();
4932 bool wxListCtrl::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4935 return m_mainWin
->PopupMenu( menu
, x
, y
);
4938 #endif // wxUSE_MENUS
4941 void wxListCtrl::SetFocus()
4943 /* The test in window.cpp fails as we are a composite
4944 window, so it checks against "this", but not m_mainWin. */
4945 if ( FindFocus() != this )
4946 m_mainWin
->SetFocus();
4949 // ----------------------------------------------------------------------------
4950 // virtual list control support
4951 // ----------------------------------------------------------------------------
4953 wxString
wxListCtrl::OnGetItemText(long item
, long col
) const
4955 // this is a pure virtual function, in fact - which is not really pure
4956 // because the controls which are not virtual don't need to implement it
4957 wxFAIL_MSG( _T("not supposed to be called") );
4959 return wxEmptyString
;
4962 int wxListCtrl::OnGetItemImage(long item
) const
4965 wxFAIL_MSG( _T("not supposed to be called") );
4970 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long item
) const
4972 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
4973 _T("invalid item index in OnGetItemAttr()") );
4975 // no attributes by default
4979 void wxListCtrl::SetItemCount(long count
)
4981 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4983 m_mainWin
->SetItemCount(count
);
4986 void wxListCtrl::RefreshItem(long item
)
4988 m_mainWin
->RefreshLine(item
);
4991 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
)
4993 m_mainWin
->RefreshLines(itemFrom
, itemTo
);
4996 #endif // wxUSE_LISTCTRL