1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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 ///////////////////////////////////////////////////////////////////////////// 
  13 //   1. we need to implement searching/sorting for virtual controls somehow 
  14 // 2. when changing selection the lines are refreshed twice 
  17 // For compilers that support precompilation, includes "wx.h". 
  18 #include "wx/wxprec.h" 
  26 #include "wx/listctrl.h" 
  28 #if ((!defined(__WXMSW__) && !(defined(__WXMAC__) && wxOSX_USE_CARBON)) || defined(__WXUNIVERSAL__)) 
  29     // if we have a native version, its implementation file does all this 
  30     IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
) 
  31     IMPLEMENT_DYNAMIC_CLASS(wxListView
, wxListCtrl
) 
  32     IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
) 
  34     IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxGenericListCtrl
) 
  38     #include "wx/scrolwin.h" 
  40     #include "wx/settings.h" 
  41     #include "wx/dynarray.h" 
  42     #include "wx/dcclient.h" 
  43     #include "wx/dcscreen.h" 
  45     #include "wx/settings.h" 
  48 #include "wx/imaglist.h" 
  49 #include "wx/selstore.h" 
  50 #include "wx/renderer.h" 
  53     #include "wx/osx/private.h" 
  54     // for themeing support 
  55     #include <Carbon/Carbon.h> 
  59 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
  60 // be removed, as well as the #else case below. 
  61 #define _USE_VISATTR 0 
  64 // ---------------------------------------------------------------------------- 
  66 // ---------------------------------------------------------------------------- 
  68 // // the height of the header window (FIXME: should depend on its font!) 
  69 // static const int HEADER_HEIGHT = 23; 
  71 static const int SCROLL_UNIT_X 
= 15; 
  73 // the spacing between the lines (in report mode) 
  74 static const int LINE_SPACING 
= 0; 
  76 // extra margins around the text label 
  78 static const int EXTRA_WIDTH 
= 6; 
  80 static const int EXTRA_WIDTH 
= 4; 
  82 static const int EXTRA_HEIGHT 
= 4; 
  84 // margin between the window and the items 
  85 static const int EXTRA_BORDER_X 
= 2; 
  86 static const int EXTRA_BORDER_Y 
= 2; 
  88 // offset for the header window 
  89 static const int HEADER_OFFSET_X 
= 0; 
  90 static const int HEADER_OFFSET_Y 
= 0; 
  92 // margin between rows of icons in [small] icon view 
  93 static const int MARGIN_BETWEEN_ROWS 
= 6; 
  95 // when autosizing the columns, add some slack 
  96 static const int AUTOSIZE_COL_MARGIN 
= 10; 
  98 // default width for the header columns 
  99 static const int WIDTH_COL_DEFAULT 
= 80; 
 101 // the space between the image and the text in the report mode 
 102 static const int IMAGE_MARGIN_IN_REPORT_MODE 
= 5; 
 104 // the space between the image and the text in the report mode in header 
 105 static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE 
= 2; 
 107 // ============================================================================ 
 109 // ============================================================================ 
 111 //----------------------------------------------------------------------------- 
 112 //  wxColWidthInfo (internal) 
 113 //----------------------------------------------------------------------------- 
 115 struct wxColWidthInfo
 
 118     bool    bNeedsUpdate
;   //  only set to true when an item whose 
 119                             //  width == nMaxWidth is removed 
 121     wxColWidthInfo(int w 
= 0, bool needsUpdate 
= false) 
 124         bNeedsUpdate 
= needsUpdate
; 
 128 WX_DEFINE_ARRAY_PTR(wxColWidthInfo 
*, ColWidthArray
); 
 130 //----------------------------------------------------------------------------- 
 131 //  wxListItemData (internal) 
 132 //----------------------------------------------------------------------------- 
 137     wxListItemData(wxListMainWindow 
*owner
); 
 140     void SetItem( const wxListItem 
&info 
); 
 141     void SetImage( int image 
) { m_image 
= image
; } 
 142     void SetData( wxUIntPtr data 
) { m_data 
= data
; } 
 143     void SetPosition( int x
, int y 
); 
 144     void SetSize( int width
, int height 
); 
 146     bool HasText() const { return !m_text
.empty(); } 
 147     const wxString
& GetText() const { return m_text
; } 
 148     void SetText(const wxString
& text
) { m_text 
= text
; } 
 150     // we can't use empty string for measuring the string width/height, so 
 151     // always return something 
 152     wxString 
GetTextForMeasuring() const 
 154         wxString s 
= GetText(); 
 161     bool IsHit( int x
, int y 
) const; 
 165     int GetWidth() const; 
 166     int GetHeight() const; 
 168     int GetImage() const { return m_image
; } 
 169     bool HasImage() const { return GetImage() != -1; } 
 171     void GetItem( wxListItem 
&info 
) const; 
 173     void SetAttr(wxListItemAttr 
*attr
) { m_attr 
= attr
; } 
 174     wxListItemAttr 
*GetAttr() const { return m_attr
; } 
 177     // the item image or -1 
 180     // user data associated with the item 
 183     // the item coordinates are not used in report mode; instead this pointer is 
 184     // NULL and the owner window is used to retrieve the item position and size 
 187     // the list ctrl we are in 
 188     wxListMainWindow 
*m_owner
; 
 190     // custom attributes or NULL 
 191     wxListItemAttr 
*m_attr
; 
 194     // common part of all ctors 
 200 //----------------------------------------------------------------------------- 
 201 //  wxListHeaderData (internal) 
 202 //----------------------------------------------------------------------------- 
 204 class wxListHeaderData 
: public wxObject
 
 208     wxListHeaderData( const wxListItem 
&info 
); 
 209     void SetItem( const wxListItem 
&item 
); 
 210     void SetPosition( int x
, int y 
); 
 211     void SetWidth( int w 
); 
 212     void SetState( int state 
); 
 213     void SetFormat( int format 
); 
 214     void SetHeight( int h 
); 
 215     bool HasImage() const; 
 217     bool HasText() const { return !m_text
.empty(); } 
 218     const wxString
& GetText() const { return m_text
; } 
 219     void SetText(const wxString
& text
) { m_text 
= text
; } 
 221     void GetItem( wxListItem 
&item 
); 
 223     bool IsHit( int x
, int y 
) const; 
 224     int GetImage() const; 
 225     int GetWidth() const; 
 226     int GetFormat() const; 
 227     int GetState() const; 
 244 //----------------------------------------------------------------------------- 
 245 //  wxListLineData (internal) 
 246 //----------------------------------------------------------------------------- 
 248 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
); 
 249 #include "wx/listimpl.cpp" 
 250 WX_DEFINE_LIST(wxListItemDataList
) 
 255     // the list of subitems: only may have more than one item in report mode 
 256     wxListItemDataList m_items
; 
 258     // this is not used in report view 
 270         // the part to be highlighted 
 271         wxRect m_rectHighlight
; 
 273         // extend all our rects to be centered inside the one of given width 
 274         void ExtendWidth(wxCoord w
) 
 276             wxASSERT_MSG( m_rectAll
.width 
<= w
, 
 277                             _T("width can only be increased") ); 
 280             m_rectLabel
.x 
= m_rectAll
.x 
+ (w 
- m_rectLabel
.width
) / 2; 
 281             m_rectIcon
.x 
= m_rectAll
.x 
+ (w 
- m_rectIcon
.width
) / 2; 
 282             m_rectHighlight
.x 
= m_rectAll
.x 
+ (w 
- m_rectHighlight
.width
) / 2; 
 287     // is this item selected? [NB: not used in virtual mode] 
 290     // back pointer to the list ctrl 
 291     wxListMainWindow 
*m_owner
; 
 294     wxListLineData(wxListMainWindow 
*owner
); 
 298         WX_CLEAR_LIST(wxListItemDataList
, m_items
); 
 302     // are we in report mode? 
 303     inline bool InReportView() const; 
 305     // are we in virtual report mode? 
 306     inline bool IsVirtual() const; 
 308     // these 2 methods shouldn't be called for report view controls, in that 
 309     // case we determine our position/size ourselves 
 311     // calculate the size of the line 
 312     void CalculateSize( wxDC 
*dc
, int spacing 
); 
 314     // remember the position this line appears at 
 315     void SetPosition( int x
, int y
, int spacing 
); 
 319     void SetImage( int image 
) { SetImage(0, image
); } 
 320     int GetImage() const { return GetImage(0); } 
 321     void SetImage( int index
, int image 
); 
 322     int GetImage( int index 
) const; 
 324     bool HasImage() const { return GetImage() != -1; } 
 325     bool HasText() const { return !GetText(0).empty(); } 
 327     void SetItem( int index
, const wxListItem 
&info 
); 
 328     void GetItem( int index
, wxListItem 
&info 
); 
 330     wxString 
GetText(int index
) const; 
 331     void SetText( int index
, const wxString
& s 
); 
 333     wxListItemAttr 
*GetAttr() const; 
 334     void SetAttr(wxListItemAttr 
*attr
); 
 336     // return true if the highlighting really changed 
 337     bool Highlight( bool on 
); 
 339     void ReverseHighlight(); 
 341     bool IsHighlighted() const 
 343         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); 
 345         return m_highlighted
; 
 348     // draw the line on the given DC in icon/list mode 
 349     void Draw( wxDC 
*dc 
); 
 351     // the same in report mode 
 352     void DrawInReportMode( wxDC 
*dc
, 
 354                            const wxRect
& rectHL
, 
 358     // set the line to contain num items (only can be > 1 in report mode) 
 359     void InitItems( int num 
); 
 361     // get the mode (i.e. style)  of the list control 
 362     inline int GetMode() const; 
 364     // prepare the DC for drawing with these item's attributes, return true if 
 365     // we need to draw the items background to highlight it, false otherwise 
 366     bool SetAttributes(wxDC 
*dc
, 
 367                        const wxListItemAttr 
*attr
, 
 370     // draw the text on the DC with the correct justification; also add an 
 371     // ellipsis if the text is too large to fit in the current width 
 372     void DrawTextFormatted(wxDC 
*dc
, 
 373                            const wxString 
&text
, 
 376                            int yMid
,    // this is middle, not top, of the text 
 380 WX_DECLARE_OBJARRAY(wxListLineData
, wxListLineDataArray
); 
 381 #include "wx/arrimpl.cpp" 
 382 WX_DEFINE_OBJARRAY(wxListLineDataArray
) 
 384 //----------------------------------------------------------------------------- 
 385 //  wxListHeaderWindow (internal) 
 386 //----------------------------------------------------------------------------- 
 388 class wxListHeaderWindow 
: public wxWindow
 
 391     wxListMainWindow  
*m_owner
; 
 392     const wxCursor    
*m_currentCursor
; 
 393     wxCursor          
*m_resizeCursor
; 
 396     // column being resized or -1 
 399     // divider line position in logical (unscrolled) coords 
 402     // minimal position beyond which the divider line 
 403     // can't be dragged in logical coords 
 407     wxListHeaderWindow(); 
 409     wxListHeaderWindow( wxWindow 
*win
, 
 411                         wxListMainWindow 
*owner
, 
 412                         const wxPoint 
&pos 
= wxDefaultPosition
, 
 413                         const wxSize 
&size 
= wxDefaultSize
, 
 415                         const wxString 
&name 
= wxT("wxlistctrlcolumntitles") ); 
 417     virtual ~wxListHeaderWindow(); 
 420     void AdjustDC( wxDC
& dc 
); 
 422     void OnPaint( wxPaintEvent 
&event 
); 
 423     void OnMouse( wxMouseEvent 
&event 
); 
 424     void OnSetFocus( wxFocusEvent 
&event 
); 
 430     // common part of all ctors 
 433     // generate and process the list event of the given type, return true if 
 434     // it wasn't vetoed, i.e. if we should proceed 
 435     bool SendListEvent(wxEventType type
, const wxPoint
& pos
); 
 437     DECLARE_EVENT_TABLE() 
 440 //----------------------------------------------------------------------------- 
 441 // wxListRenameTimer (internal) 
 442 //----------------------------------------------------------------------------- 
 444 class wxListRenameTimer
: public wxTimer
 
 447     wxListMainWindow 
*m_owner
; 
 450     wxListRenameTimer( wxListMainWindow 
*owner 
); 
 454 //----------------------------------------------------------------------------- 
 455 // wxListTextCtrlWrapper: wraps a wxTextCtrl to make it work for inline editing 
 456 //----------------------------------------------------------------------------- 
 458 class wxListTextCtrlWrapper 
: public wxEvtHandler
 
 461     // NB: text must be a valid object but not Create()d yet 
 462     wxListTextCtrlWrapper(wxListMainWindow 
*owner
, 
 466     wxTextCtrl 
*GetText() const { return m_text
; } 
 468     void EndEdit( bool discardChanges 
); 
 471     void OnChar( wxKeyEvent 
&event 
); 
 472     void OnKeyUp( wxKeyEvent 
&event 
); 
 473     void OnKillFocus( wxFocusEvent 
&event 
); 
 475     bool AcceptChanges(); 
 476     void Finish( bool setfocus 
); 
 479     wxListMainWindow   
*m_owner
; 
 481     wxString            m_startValue
; 
 483     bool                m_aboutToFinish
; 
 485     DECLARE_EVENT_TABLE() 
 488 //----------------------------------------------------------------------------- 
 489 //  wxListMainWindow (internal) 
 490 //----------------------------------------------------------------------------- 
 492 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
); 
 493 #include "wx/listimpl.cpp" 
 494 WX_DEFINE_LIST(wxListHeaderDataList
) 
 496 class wxListMainWindow 
: public wxScrolledCanvas
 
 500     wxListMainWindow( wxWindow 
*parent
, 
 502                       const wxPoint
& pos 
= wxDefaultPosition
, 
 503                       const wxSize
& size 
= wxDefaultSize
, 
 505                       const wxString 
&name 
= _T("listctrlmainwindow") ); 
 507     virtual ~wxListMainWindow(); 
 509     bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); } 
 511     // return true if this is a virtual list control 
 512     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); } 
 514     // return true if the control is in report mode 
 515     bool InReportView() const { return HasFlag(wxLC_REPORT
); } 
 517     // return true if we are in single selection mode, false if multi sel 
 518     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); } 
 520     // do we have a header window? 
 521     bool HasHeader() const 
 522         { return InReportView() && !HasFlag(wxLC_NO_HEADER
); } 
 524     void HighlightAll( bool on 
); 
 526     // all these functions only do something if the line is currently visible 
 528     // change the line "selected" state, return true if it really changed 
 529     bool HighlightLine( size_t line
, bool highlight 
= true); 
 531     // as HighlightLine() but do it for the range of lines: this is incredibly 
 532     // more efficient for virtual list controls! 
 534     // NB: unlike HighlightLine() this one does refresh the lines on screen 
 535     void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on 
= true ); 
 537     // toggle the line state and refresh it 
 538     void ReverseHighlight( size_t line 
) 
 539         { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); } 
 541     // return true if the line is highlighted 
 542     bool IsHighlighted(size_t line
) const; 
 544     // refresh one or several lines at once 
 545     void RefreshLine( size_t line 
); 
 546     void RefreshLines( size_t lineFrom
, size_t lineTo 
); 
 548     // refresh all selected items 
 549     void RefreshSelected(); 
 551     // refresh all lines below the given one: the difference with 
 552     // RefreshLines() is that the index here might not be a valid one (happens 
 553     // when the last line is deleted) 
 554     void RefreshAfter( size_t lineFrom 
); 
 556     // the methods which are forwarded to wxListLineData itself in list/icon 
 557     // modes but are here because the lines don't store their positions in the 
 560     // get the bound rect for the entire line 
 561     wxRect 
GetLineRect(size_t line
) const; 
 563     // get the bound rect of the label 
 564     wxRect 
GetLineLabelRect(size_t line
) const; 
 566     // get the bound rect of the items icon (only may be called if we do have 
 568     wxRect 
GetLineIconRect(size_t line
) const; 
 570     // get the rect to be highlighted when the item has focus 
 571     wxRect 
GetLineHighlightRect(size_t line
) const; 
 573     // get the size of the total line rect 
 574     wxSize 
GetLineSize(size_t line
) const 
 575         { return GetLineRect(line
).GetSize(); } 
 577     // return the hit code for the corresponding position (in this line) 
 578     long HitTestLine(size_t line
, int x
, int y
) const; 
 580     // bring the selected item into view, scrolling to it if necessary 
 581     void MoveToItem(size_t item
); 
 583     bool ScrollList( int WXUNUSED(dx
), int dy 
); 
 585     // bring the current item into view 
 586     void MoveToFocus() { MoveToItem(m_current
); } 
 588     // start editing the label of the given item 
 589     wxTextCtrl 
*EditLabel(long item
, 
 590                           wxClassInfo
* textControlClass 
= CLASSINFO(wxTextCtrl
)); 
 591     wxTextCtrl 
*GetEditControl() const 
 593         return m_textctrlWrapper 
? m_textctrlWrapper
->GetText() : NULL
; 
 596     void ResetTextControl(wxTextCtrl 
*text
) 
 599         m_textctrlWrapper 
= NULL
; 
 602     void OnRenameTimer(); 
 603     bool OnRenameAccept(size_t itemEdit
, const wxString
& value
); 
 604     void OnRenameCancelled(size_t itemEdit
); 
 606     void OnMouse( wxMouseEvent 
&event 
); 
 608     // called to switch the selection from the current item to newCurrent, 
 609     void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event 
); 
 611     void OnChar( wxKeyEvent 
&event 
); 
 612     void OnKeyDown( wxKeyEvent 
&event 
); 
 613     void OnKeyUp( wxKeyEvent 
&event 
); 
 614     void OnSetFocus( wxFocusEvent 
&event 
); 
 615     void OnKillFocus( wxFocusEvent 
&event 
); 
 616     void OnScroll( wxScrollWinEvent
& event 
); 
 618     void OnPaint( wxPaintEvent 
&event 
); 
 620     void OnChildFocus(wxChildFocusEvent
& event
); 
 622     void DrawImage( int index
, wxDC 
*dc
, int x
, int y 
); 
 623     void GetImageSize( int index
, int &width
, int &height 
) const; 
 624     int GetTextLength( const wxString 
&s 
) const; 
 626     void SetImageList( wxImageList 
*imageList
, int which 
); 
 627     void SetItemSpacing( int spacing
, bool isSmall 
= false ); 
 628     int GetItemSpacing( bool isSmall 
= false ); 
 630     void SetColumn( int col
, wxListItem 
&item 
); 
 631     void SetColumnWidth( int col
, int width 
); 
 632     void GetColumn( int col
, wxListItem 
&item 
) const; 
 633     int GetColumnWidth( int col 
) const; 
 634     int GetColumnCount() const { return m_columns
.GetCount(); } 
 636     // returns the sum of the heights of all columns 
 637     int GetHeaderWidth() const; 
 639     int GetCountPerPage() const; 
 641     void SetItem( wxListItem 
&item 
); 
 642     void GetItem( wxListItem 
&item 
) const; 
 643     void SetItemState( long item
, long state
, long stateMask 
); 
 644     void SetItemStateAll( long state
, long stateMask 
); 
 645     int GetItemState( long item
, long stateMask 
) const; 
 646     bool GetItemRect( long item
, wxRect 
&rect 
) const 
 648         return GetSubItemRect(item
, wxLIST_GETSUBITEMRECT_WHOLEITEM
, rect
); 
 650     bool GetSubItemRect( long item
, long subItem
, wxRect
& rect 
) const; 
 651     wxRect 
GetViewRect() const; 
 652     bool GetItemPosition( long item
, wxPoint
& pos 
) const; 
 653     int GetSelectedItemCount() const; 
 655     wxString 
GetItemText(long item
) const 
 658         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 659         info
.m_itemId 
= item
; 
 664     void SetItemText(long item
, const wxString
& value
) 
 667         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 668         info
.m_itemId 
= item
; 
 673     // set the scrollbars and update the positions of the items 
 674     void RecalculatePositions(bool noRefresh 
= false); 
 676     // refresh the window and the header 
 679     long GetNextItem( long item
, int geometry
, int state 
) const; 
 680     void DeleteItem( long index 
); 
 681     void DeleteAllItems(); 
 682     void DeleteColumn( int col 
); 
 683     void DeleteEverything(); 
 684     void EnsureVisible( long index 
); 
 685     long FindItem( long start
, const wxString
& str
, bool partial 
= false ); 
 686     long FindItem( long start
, wxUIntPtr data
); 
 687     long FindItem( const wxPoint
& pt 
); 
 688     long HitTest( int x
, int y
, int &flags 
) const; 
 689     void InsertItem( wxListItem 
&item 
); 
 690     void InsertColumn( long col
, wxListItem 
&item 
); 
 691     int GetItemWidthWithImage(wxListItem 
* item
); 
 692     void SortItems( wxListCtrlCompare fn
, long data 
); 
 694     size_t GetItemCount() const; 
 695     bool IsEmpty() const { return GetItemCount() == 0; } 
 696     void SetItemCount(long count
); 
 698     // change the current (== focused) item, send a notification event 
 699     void ChangeCurrent(size_t current
); 
 700     void ResetCurrent() { ChangeCurrent((size_t)-1); } 
 701     bool HasCurrent() const { return m_current 
!= (size_t)-1; } 
 703     // send out a wxListEvent 
 704     void SendNotify( size_t line
, 
 706                      const wxPoint
& point 
= wxDefaultPosition 
); 
 708     // override base class virtual to reset m_lineHeight when the font changes 
 709     virtual bool SetFont(const wxFont
& font
) 
 711         if ( !wxScrolledCanvas::SetFont(font
) ) 
 719     // these are for wxListLineData usage only 
 721     // get the backpointer to the list ctrl 
 722     wxGenericListCtrl 
*GetListCtrl() const 
 724         return wxStaticCast(GetParent(), wxGenericListCtrl
); 
 727     // get the height of all lines (assuming they all do have the same height) 
 728     wxCoord 
GetLineHeight() const; 
 730     // get the y position of the given line (only for report view) 
 731     wxCoord 
GetLineY(size_t line
) const; 
 733     // get the brush to use for the item highlighting 
 734     wxBrush 
*GetHighlightBrush() const 
 736         return m_hasFocus 
? m_highlightBrush 
: m_highlightUnfocusedBrush
; 
 739     bool HasFocus() const 
 745     // the array of all line objects for a non virtual list control (for the 
 746     // virtual list control we only ever use m_lines[0]) 
 747     wxListLineDataArray  m_lines
; 
 749     // the list of column objects 
 750     wxListHeaderDataList m_columns
; 
 752     // currently focused item or -1 
 755     // the number of lines per page 
 758     // this flag is set when something which should result in the window 
 759     // redrawing happens (i.e. an item was added or deleted, or its appearance 
 760     // changed) and OnPaint() doesn't redraw the window while it is set which 
 761     // allows to minimize the number of repaintings when a lot of items are 
 762     // being added. The real repainting occurs only after the next OnIdle() 
 766     wxColour            
*m_highlightColour
; 
 767     wxImageList         
*m_small_image_list
; 
 768     wxImageList         
*m_normal_image_list
; 
 770     int                  m_normal_spacing
; 
 774     wxTimer             
*m_renameTimer
; 
 778     ColWidthArray        m_aColWidths
; 
 780     // for double click logic 
 781     size_t m_lineLastClicked
, 
 782            m_lineBeforeLastClicked
, 
 783            m_lineSelectSingleOnUp
; 
 786     wxWindow 
*GetMainWindowOfCompositeControl() { return GetParent(); } 
 788     // the total count of items in a virtual list control 
 791     // the object maintaining the items selection state, only used in virtual 
 793     wxSelectionStore m_selStore
; 
 795     // common part of all ctors 
 798     // get the line data for the given index 
 799     wxListLineData 
*GetLine(size_t n
) const 
 801         wxASSERT_MSG( n 
!= (size_t)-1, _T("invalid line index") ); 
 805             wxConstCast(this, wxListMainWindow
)->CacheLineData(n
); 
 812     // get a dummy line which can be used for geometry calculations and such: 
 813     // you must use GetLine() if you want to really draw the line 
 814     wxListLineData 
*GetDummyLine() const; 
 816     // cache the line data of the n-th line in m_lines[0] 
 817     void CacheLineData(size_t line
); 
 819     // get the range of visible lines 
 820     void GetVisibleLinesRange(size_t *from
, size_t *to
); 
 822     // force us to recalculate the range of visible lines 
 823     void ResetVisibleLinesRange() { m_lineFrom 
= (size_t)-1; } 
 825     // get the colour to be used for drawing the rules 
 826     wxColour 
GetRuleColour() const 
 828         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 832     // initialize the current item if needed 
 833     void UpdateCurrent(); 
 835     // delete all items but don't refresh: called from dtor 
 836     void DoDeleteAllItems(); 
 838     // the height of one line using the current font 
 839     wxCoord m_lineHeight
; 
 841     // the total header width or 0 if not calculated yet 
 842     wxCoord m_headerWidth
; 
 844     // the first and last lines being shown on screen right now (inclusive), 
 845     // both may be -1 if they must be calculated so never access them directly: 
 846     // use GetVisibleLinesRange() above instead 
 850     // the brushes to use for item highlighting when we do/don't have focus 
 851     wxBrush 
*m_highlightBrush
, 
 852             *m_highlightUnfocusedBrush
; 
 854     // wrapper around the text control currently used for in place editing or 
 855     // NULL if no item is being edited 
 856     wxListTextCtrlWrapper 
*m_textctrlWrapper
; 
 859     DECLARE_EVENT_TABLE() 
 861     friend class wxGenericListCtrl
; 
 865 wxListItemData::~wxListItemData() 
 867     // in the virtual list control the attributes are managed by the main 
 868     // program, so don't delete them 
 869     if ( !m_owner
->IsVirtual() ) 
 875 void wxListItemData::Init() 
 883 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
 889     if ( owner
->InReportView() ) 
 895 void wxListItemData::SetItem( const wxListItem 
&info 
) 
 897     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
 898         SetText(info
.m_text
); 
 899     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 900         m_image 
= info
.m_image
; 
 901     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
 902         m_data 
= info
.m_data
; 
 904     if ( info
.HasAttributes() ) 
 907             m_attr
->AssignFrom(*info
.GetAttributes()); 
 909             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
 917         m_rect
->width 
= info
.m_width
; 
 921 void wxListItemData::SetPosition( int x
, int y 
) 
 923     wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") ); 
 929 void wxListItemData::SetSize( int width
, int height 
) 
 931     wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") ); 
 934         m_rect
->width 
= width
; 
 936         m_rect
->height 
= height
; 
 939 bool wxListItemData::IsHit( int x
, int y 
) const 
 941     wxCHECK_MSG( m_rect
, false, _T("can't be called in this mode") ); 
 943     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Contains(x
, y
); 
 946 int wxListItemData::GetX() const 
 948     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 953 int wxListItemData::GetY() const 
 955     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 960 int wxListItemData::GetWidth() const 
 962     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 964     return m_rect
->width
; 
 967 int wxListItemData::GetHeight() const 
 969     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 971     return m_rect
->height
; 
 974 void wxListItemData::GetItem( wxListItem 
&info 
) const 
 976     long mask 
= info
.m_mask
; 
 978         // by default, get everything for backwards compatibility 
 981     if ( mask 
& wxLIST_MASK_TEXT 
) 
 982         info
.m_text 
= m_text
; 
 983     if ( mask 
& wxLIST_MASK_IMAGE 
) 
 984         info
.m_image 
= m_image
; 
 985     if ( mask 
& wxLIST_MASK_DATA 
) 
 986         info
.m_data 
= m_data
; 
 990         if ( m_attr
->HasTextColour() ) 
 991             info
.SetTextColour(m_attr
->GetTextColour()); 
 992         if ( m_attr
->HasBackgroundColour() ) 
 993             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
 994         if ( m_attr
->HasFont() ) 
 995             info
.SetFont(m_attr
->GetFont()); 
 999 //----------------------------------------------------------------------------- 
1001 //----------------------------------------------------------------------------- 
1003 void wxListHeaderData::Init() 
1015 wxListHeaderData::wxListHeaderData() 
1020 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
1027 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
1029     m_mask 
= item
.m_mask
; 
1031     if ( m_mask 
& wxLIST_MASK_TEXT 
) 
1032         m_text 
= item
.m_text
; 
1034     if ( m_mask 
& wxLIST_MASK_IMAGE 
) 
1035         m_image 
= item
.m_image
; 
1037     if ( m_mask 
& wxLIST_MASK_FORMAT 
) 
1038         m_format 
= item
.m_format
; 
1040     if ( m_mask 
& wxLIST_MASK_WIDTH 
) 
1041         SetWidth(item
.m_width
); 
1043     if ( m_mask 
& wxLIST_MASK_STATE 
) 
1044         SetState(item
.m_state
); 
1047 void wxListHeaderData::SetPosition( int x
, int y 
) 
1053 void wxListHeaderData::SetHeight( int h 
) 
1058 void wxListHeaderData::SetWidth( int w 
) 
1060     m_width 
= w 
< 0 ? WIDTH_COL_DEFAULT 
: w
; 
1063 void wxListHeaderData::SetState( int flag 
) 
1068 void wxListHeaderData::SetFormat( int format 
) 
1073 bool wxListHeaderData::HasImage() const 
1075     return m_image 
!= -1; 
1078 bool wxListHeaderData::IsHit( int x
, int y 
) const 
1080     return ((x 
>= m_xpos
) && (x 
<= m_xpos
+m_width
) && (y 
>= m_ypos
) && (y 
<= m_ypos
+m_height
)); 
1083 void wxListHeaderData::GetItem( wxListItem
& item 
) 
1085     item
.m_mask 
= m_mask
; 
1086     item
.m_text 
= m_text
; 
1087     item
.m_image 
= m_image
; 
1088     item
.m_format 
= m_format
; 
1089     item
.m_width 
= m_width
; 
1090     item
.m_state 
= m_state
; 
1093 int wxListHeaderData::GetImage() const 
1098 int wxListHeaderData::GetWidth() const 
1103 int wxListHeaderData::GetFormat() const 
1108 int wxListHeaderData::GetState() const 
1113 //----------------------------------------------------------------------------- 
1115 //----------------------------------------------------------------------------- 
1117 inline int wxListLineData::GetMode() const 
1119     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
1122 inline bool wxListLineData::InReportView() const 
1124     return m_owner
->HasFlag(wxLC_REPORT
); 
1127 inline bool wxListLineData::IsVirtual() const 
1129     return m_owner
->IsVirtual(); 
1132 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
1136     if ( InReportView() ) 
1139         m_gi 
= new GeometryInfo
; 
1141     m_highlighted 
= false; 
1143     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
1146 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
1148     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1149     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1151     wxListItemData 
*item 
= node
->GetData(); 
1156     switch ( GetMode() ) 
1159         case wxLC_SMALL_ICON
: 
1160             m_gi
->m_rectAll
.width 
= spacing
; 
1162             s 
= item
->GetText(); 
1167                 m_gi
->m_rectLabel
.width 
= 
1168                 m_gi
->m_rectLabel
.height 
= 0; 
1172                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
1176                 m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
1178                     m_gi
->m_rectAll
.width 
= lw
; 
1180                 m_gi
->m_rectLabel
.width 
= lw
; 
1181                 m_gi
->m_rectLabel
.height 
= lh
; 
1184             if (item
->HasImage()) 
1187                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1188                 m_gi
->m_rectIcon
.width 
= w 
+ 8; 
1189                 m_gi
->m_rectIcon
.height 
= h 
+ 8; 
1191                 if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
1192                     m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
1193                 if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
1194                     m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
1197             if ( item
->HasText() ) 
1199                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
1200                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
1202             else // no text, highlight the icon 
1204                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
1205                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
1210             s 
= item
->GetTextForMeasuring(); 
1212             dc
->GetTextExtent( s
, &lw
, &lh 
); 
1216             m_gi
->m_rectLabel
.width 
= lw
; 
1217             m_gi
->m_rectLabel
.height 
= lh
; 
1219             m_gi
->m_rectAll
.width 
= lw
; 
1220             m_gi
->m_rectAll
.height 
= lh
; 
1222             if (item
->HasImage()) 
1225                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1226                 m_gi
->m_rectIcon
.width 
= w
; 
1227                 m_gi
->m_rectIcon
.height 
= h
; 
1229                 m_gi
->m_rectAll
.width 
+= 4 + w
; 
1230                 if (h 
> m_gi
->m_rectAll
.height
) 
1231                     m_gi
->m_rectAll
.height 
= h
; 
1234             m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
1235             m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
1239             wxFAIL_MSG( _T("unexpected call to SetSize") ); 
1243             wxFAIL_MSG( _T("unknown mode") ); 
1248 void wxListLineData::SetPosition( int x
, int y
, int spacing 
) 
1250     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1251     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1253     wxListItemData 
*item 
= node
->GetData(); 
1255     switch ( GetMode() ) 
1258         case wxLC_SMALL_ICON
: 
1259             m_gi
->m_rectAll
.x 
= x
; 
1260             m_gi
->m_rectAll
.y 
= y
; 
1262             if ( item
->HasImage() ) 
1264                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 + 
1265                     (m_gi
->m_rectAll
.width 
- m_gi
->m_rectIcon
.width
) / 2; 
1266                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
1269             if ( item
->HasText() ) 
1271                 if (m_gi
->m_rectAll
.width 
> spacing
) 
1272                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2); 
1274                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2) + (spacing 
/ 2) - (m_gi
->m_rectLabel
.width 
/ 2); 
1275                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
1276                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
1277                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
1279             else // no text, highlight the icon 
1281                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
1282                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
1287             m_gi
->m_rectAll
.x 
= x
; 
1288             m_gi
->m_rectAll
.y 
= y
; 
1290             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
1291             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
1292             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1294             if (item
->HasImage()) 
1296                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1297                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1298                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 4 + (EXTRA_WIDTH
/2) + m_gi
->m_rectIcon
.width
; 
1302                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2); 
1307             wxFAIL_MSG( _T("unexpected call to SetPosition") ); 
1311             wxFAIL_MSG( _T("unknown mode") ); 
1316 void wxListLineData::InitItems( int num 
) 
1318     for (int i 
= 0; i 
< num
; i
++) 
1319         m_items
.Append( new wxListItemData(m_owner
) ); 
1322 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
1324     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1325     wxCHECK_RET( node
, _T("invalid column index in SetItem") ); 
1327     wxListItemData 
*item 
= node
->GetData(); 
1328     item
->SetItem( info 
); 
1331 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
1333     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1336         wxListItemData 
*item 
= node
->GetData(); 
1337         item
->GetItem( info 
); 
1341 wxString 
wxListLineData::GetText(int index
) const 
1345     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1348         wxListItemData 
*item 
= node
->GetData(); 
1349         s 
= item
->GetText(); 
1355 void wxListLineData::SetText( int index
, const wxString
& s 
) 
1357     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1360         wxListItemData 
*item 
= node
->GetData(); 
1365 void wxListLineData::SetImage( int index
, int image 
) 
1367     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1368     wxCHECK_RET( node
, _T("invalid column index in SetImage()") ); 
1370     wxListItemData 
*item 
= node
->GetData(); 
1371     item
->SetImage(image
); 
1374 int wxListLineData::GetImage( int index 
) const 
1376     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1377     wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") ); 
1379     wxListItemData 
*item 
= node
->GetData(); 
1380     return item
->GetImage(); 
1383 wxListItemAttr 
*wxListLineData::GetAttr() const 
1385     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1386     wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") ); 
1388     wxListItemData 
*item 
= node
->GetData(); 
1389     return item
->GetAttr(); 
1392 void wxListLineData::SetAttr(wxListItemAttr 
*attr
) 
1394     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1395     wxCHECK_RET( node
, _T("invalid column index in SetAttr()") ); 
1397     wxListItemData 
*item 
= node
->GetData(); 
1398     item
->SetAttr(attr
); 
1401 bool wxListLineData::SetAttributes(wxDC 
*dc
, 
1402                                    const wxListItemAttr 
*attr
, 
1405     wxWindow 
*listctrl 
= m_owner
->GetParent(); 
1409     // don't use foreground colour for drawing highlighted items - this might 
1410     // make them completely invisible (and there is no way to do bit 
1411     // arithmetics on wxColour, unfortunately) 
1416         if (m_owner
->HasFocus() 
1417 #if !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON 
1418                 && IsControlActive( (ControlRef
)m_owner
->GetHandle() ) 
1426         colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1428     else if ( attr 
&& attr
->HasTextColour() ) 
1429         colText 
= attr
->GetTextColour(); 
1431         colText 
= listctrl
->GetForegroundColour(); 
1433     dc
->SetTextForeground(colText
); 
1437     if ( attr 
&& attr
->HasFont() ) 
1438         font 
= attr
->GetFont(); 
1440         font 
= listctrl
->GetFont(); 
1445     bool hasBgCol 
= attr 
&& attr
->HasBackgroundColour(); 
1446     if ( highlighted 
|| hasBgCol 
) 
1449             dc
->SetBrush( *m_owner
->GetHighlightBrush() ); 
1451             dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxBRUSHSTYLE_SOLID
)); 
1453         dc
->SetPen( *wxTRANSPARENT_PEN 
); 
1461 void wxListLineData::Draw( wxDC 
*dc 
) 
1463     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1464     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1466     bool highlighted 
= IsHighlighted(); 
1468     wxListItemAttr 
*attr 
= GetAttr(); 
1470     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1471 #if ( !defined(__WXGTK20__) && !defined(__WXMAC__) ) 
1473         dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1479             int flags 
= wxCONTROL_SELECTED
; 
1480             if (m_owner
->HasFocus() 
1481 #if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON 
1482                 && IsControlActive( (ControlRef
)m_owner
->GetHandle() ) 
1485                 flags 
|= wxCONTROL_FOCUSED
; 
1486             wxRendererNative::Get().DrawItemSelectionRect( m_owner
, *dc
, m_gi
->m_rectHighlight
, flags 
); 
1491             dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1496     // just for debugging to better see where the items are 
1498     dc
->SetPen(*wxRED_PEN
); 
1499     dc
->SetBrush(*wxTRANSPARENT_BRUSH
); 
1500     dc
->DrawRectangle( m_gi
->m_rectAll 
); 
1501     dc
->SetPen(*wxGREEN_PEN
); 
1502     dc
->DrawRectangle( m_gi
->m_rectIcon 
); 
1505     wxListItemData 
*item 
= node
->GetData(); 
1506     if (item
->HasImage()) 
1508         // centre the image inside our rectangle, this looks nicer when items 
1509         // ae aligned in a row 
1510         const wxRect
& rectIcon 
= m_gi
->m_rectIcon
; 
1512         m_owner
->DrawImage(item
->GetImage(), dc
, rectIcon
.x
, rectIcon
.y
); 
1515     if (item
->HasText()) 
1517         const wxRect
& rectLabel 
= m_gi
->m_rectLabel
; 
1519         wxDCClipper 
clipper(*dc
, rectLabel
); 
1520         dc
->DrawText(item
->GetText(), rectLabel
.x
, rectLabel
.y
); 
1524 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
1526                                        const wxRect
& rectHL
, 
1529     // TODO: later we should support setting different attributes for 
1530     //       different columns - to do it, just add "col" argument to 
1531     //       GetAttr() and move these lines into the loop below 
1532     wxListItemAttr 
*attr 
= GetAttr(); 
1533     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1534 #if ( !defined(__WXGTK20__) && !defined(__WXMAC__) ) 
1536         dc
->DrawRectangle( rectHL 
); 
1542             int flags 
= wxCONTROL_SELECTED
; 
1543             if (m_owner
->HasFocus()) 
1544                 flags 
|= wxCONTROL_FOCUSED
; 
1545             wxRendererNative::Get().DrawItemSelectionRect( m_owner
, *dc
, rectHL
, flags 
); 
1549             dc
->DrawRectangle( rectHL 
); 
1554     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
1555             yMid 
= rect
.y 
+ rect
.height
/2; 
1557     // This probably needs to be done 
1558     // on all platforms as the icons 
1559     // otherwise nearly touch the border 
1564     for ( wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1566           node 
= node
->GetNext(), col
++ ) 
1568         wxListItemData 
*item 
= node
->GetData(); 
1570         int width 
= m_owner
->GetColumnWidth(col
); 
1574         const int wText 
= width 
- 8; 
1575         wxDCClipper 
clipper(*dc
, xOld
, rect
.y
, wText
, rect
.height
); 
1577         if ( item
->HasImage() ) 
1580             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
1581             m_owner
->DrawImage( item
->GetImage(), dc
, xOld
, yMid 
- iy
/2 ); 
1583             ix 
+= IMAGE_MARGIN_IN_REPORT_MODE
; 
1589         if ( item
->HasText() ) 
1590             DrawTextFormatted(dc
, item
->GetText(), col
, xOld
, yMid
, wText
); 
1594 void wxListLineData::DrawTextFormatted(wxDC 
*dc
, 
1595                                        const wxString
& textOrig
, 
1601     // we don't support displaying multiple lines currently (and neither does 
1602     // wxMSW FWIW) so just merge all the lines 
1603     wxString 
text(textOrig
); 
1604     text
.Replace(_T("\n"), _T(" ")); 
1607     dc
->GetTextExtent(text
, &w
, &h
); 
1609     const wxCoord y 
= yMid 
- (h 
+ 1)/2; 
1611     wxDCClipper 
clipper(*dc
, x
, y
, width
, h
); 
1613     // determine if the string can fit inside the current width 
1616         // it can, draw it using the items alignment 
1618         m_owner
->GetColumn(col
, item
); 
1619         switch ( item
.GetAlign() ) 
1621             case wxLIST_FORMAT_LEFT
: 
1625             case wxLIST_FORMAT_RIGHT
: 
1629             case wxLIST_FORMAT_CENTER
: 
1630                 x 
+= (width 
- w
) / 2; 
1634                 wxFAIL_MSG( _T("unknown list item format") ); 
1638         dc
->DrawText(text
, x
, y
); 
1640     else // otherwise, truncate and add an ellipsis if possible 
1642         // determine the base width 
1643         wxString 
ellipsis(wxT("...")); 
1645         dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1647         // continue until we have enough space or only one character left 
1649         size_t len 
= text
.length(); 
1650         wxString drawntext 
= text
.Left(len
); 
1653             dc
->GetTextExtent(drawntext
.Last(), &w_c
, &h_c
); 
1654             drawntext
.RemoveLast(); 
1657             if (w 
+ base_w 
<= width
) 
1661         // if still not enough space, remove ellipsis characters 
1662         while (ellipsis
.length() > 0 && w 
+ base_w 
> width
) 
1664             ellipsis 
= ellipsis
.Left(ellipsis
.length() - 1); 
1665             dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1668         // now draw the text 
1669         dc
->DrawText(drawntext
, x
, y
); 
1670         dc
->DrawText(ellipsis
, x 
+ w
, y
); 
1674 bool wxListLineData::Highlight( bool on 
) 
1676     wxCHECK_MSG( !IsVirtual(), false, _T("unexpected call to Highlight") ); 
1678     if ( on 
== m_highlighted 
) 
1686 void wxListLineData::ReverseHighlight( void ) 
1688     Highlight(!IsHighlighted()); 
1691 //----------------------------------------------------------------------------- 
1692 //  wxListHeaderWindow 
1693 //----------------------------------------------------------------------------- 
1695 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
1696     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
1697     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
1698     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
1701 void wxListHeaderWindow::Init() 
1703     m_currentCursor 
= NULL
; 
1704     m_isDragging 
= false; 
1708 wxListHeaderWindow::wxListHeaderWindow() 
1713     m_resizeCursor 
= NULL
; 
1716 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, 
1718                                         wxListMainWindow 
*owner
, 
1722                                         const wxString 
&name 
) 
1723                   : wxWindow( win
, id
, pos
, size
, style
, name 
) 
1728     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
1731     wxVisualAttributes attr 
= wxPanel::GetClassDefaultAttributes(); 
1732     SetOwnForegroundColour( attr
.colFg 
); 
1733     SetOwnBackgroundColour( attr
.colBg 
); 
1735         SetOwnFont( attr
.font 
); 
1737     SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
1738     SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
1740         SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT 
)); 
1744 wxListHeaderWindow::~wxListHeaderWindow() 
1746     delete m_resizeCursor
; 
1749 #ifdef __WXUNIVERSAL__ 
1750 #include "wx/univ/renderer.h" 
1751 #include "wx/univ/theme.h" 
1754 // shift the DC origin to match the position of the main window horz 
1755 // scrollbar: this allows us to always use logical coords 
1756 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
1759     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1762     m_owner
->GetViewStart( &view_start
, NULL 
); 
1767     dc
.GetDeviceOrigin( &org_x
, &org_y 
); 
1769     // account for the horz scrollbar offset 
1771     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
1773         // Maybe we just have to check for m_signX 
1774         // in the DC, but I leave the #ifdef __WXGTK__ 
1776         dc
.SetDeviceOrigin( org_x 
+ (view_start 
* xpix
), org_y 
); 
1780         dc
.SetDeviceOrigin( org_x 
- (view_start 
* xpix
), org_y 
); 
1783 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1785     wxPaintDC 
dc( this ); 
1790     dc
.SetFont( GetFont() ); 
1792     // width and height of the entire header window 
1794     GetClientSize( &w
, &h 
); 
1795     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1797     dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
1798     dc
.SetTextForeground(GetForegroundColour()); 
1800     int x 
= HEADER_OFFSET_X
; 
1801     int numColumns 
= m_owner
->GetColumnCount(); 
1803     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1805         m_owner
->GetColumn( i
, item 
); 
1806         int wCol 
= item
.m_width
; 
1812         if (!m_parent
->IsEnabled()) 
1813             flags 
|= wxCONTROL_DISABLED
; 
1815 // NB: The code below is not really Mac-specific, but since we are close 
1816 // to 2.8 release and I don't have time to test on other platforms, I 
1817 // defined this only for wxMac. If this behavior is desired on 
1818 // other platforms, please go ahead and revise or remove the #ifdef. 
1820         if ( !m_owner
->IsVirtual() && (item
.m_mask 
& wxLIST_MASK_STATE
) && 
1821                 (item
.m_state 
& wxLIST_STATE_SELECTED
) ) 
1822             flags 
|= wxCONTROL_SELECTED
; 
1825         wxRendererNative::Get().DrawHeaderButton
 
1829                                     wxRect(x
, HEADER_OFFSET_Y
, cw
, ch
), 
1833         // see if we have enough space for the column label 
1835         // for this we need the width of the text 
1838         dc
.GetTextExtent(item
.GetText(), &wLabel
, &hLabel
); 
1839         wLabel 
+= 2 * EXTRA_WIDTH
; 
1841         // and the width of the icon, if any 
1842         int ix 
= 0, iy 
= 0;    // init them just to suppress the compiler warnings 
1843         const int image 
= item
.m_image
; 
1844         wxImageList 
*imageList
; 
1847             imageList 
= m_owner
->m_small_image_list
; 
1850                 imageList
->GetSize(image
, ix
, iy
); 
1851                 wLabel 
+= ix 
+ HEADER_IMAGE_MARGIN_IN_REPORT_MODE
; 
1859         // ignore alignment if there is not enough space anyhow 
1861         switch ( wLabel 
< cw 
? item
.GetAlign() : wxLIST_FORMAT_LEFT 
) 
1864                 wxFAIL_MSG( _T("unknown list item format") ); 
1867             case wxLIST_FORMAT_LEFT
: 
1871             case wxLIST_FORMAT_RIGHT
: 
1872                 xAligned 
= x 
+ cw 
- wLabel
; 
1875             case wxLIST_FORMAT_CENTER
: 
1876                 xAligned 
= x 
+ (cw 
- wLabel
) / 2; 
1880         // draw the text and image clipping them so that they 
1881         // don't overwrite the column boundary 
1882         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h 
- 4 ); 
1884         // if we have an image, draw it on the right of the label 
1891                         xAligned 
+ wLabel 
- ix 
- HEADER_IMAGE_MARGIN_IN_REPORT_MODE
, 
1892                         HEADER_OFFSET_Y 
+ (h 
- 4 - iy
)/2, 
1893                         wxIMAGELIST_DRAW_TRANSPARENT
 
1897         dc
.DrawText( item
.GetText(), 
1898                      xAligned 
+ EXTRA_WIDTH
, h 
/ 2 - hLabel 
/ 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT ); 
1903     // Fill in what's missing to the right of the columns, otherwise we will 
1904     // leave an unpainted area when columns are removed (and it looks better) 
1907         wxRendererNative::Get().DrawHeaderButton
 
1911                                     wxRect(x
, HEADER_OFFSET_Y
, w 
- x
, h
), 
1917 void wxListHeaderWindow::DrawCurrent() 
1920     m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1922     int x1 
= m_currentX
; 
1924     m_owner
->ClientToScreen( &x1
, &y1 
); 
1926     int x2 
= m_currentX
; 
1928     m_owner
->GetClientSize( NULL
, &y2 
); 
1929     m_owner
->ClientToScreen( &x2
, &y2 
); 
1932     dc
.SetLogicalFunction( wxINVERT 
); 
1933     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
1934     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1938     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1940     dc
.SetLogicalFunction( wxCOPY 
); 
1942     dc
.SetPen( wxNullPen 
); 
1943     dc
.SetBrush( wxNullBrush 
); 
1947 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1949     // we want to work with logical coords 
1951     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1952     int y 
= event
.GetY(); 
1956         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1958         // we don't draw the line beyond our window, but we allow dragging it 
1961         GetClientSize( &w
, NULL 
); 
1962         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1965         // erase the line if it was drawn 
1966         if ( m_currentX 
< w 
) 
1969         if (event
.ButtonUp()) 
1972             m_isDragging 
= false; 
1974             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1975             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1982                 m_currentX 
= m_minX 
+ 7; 
1984             // draw in the new location 
1985             if ( m_currentX 
< w 
) 
1989     else // not dragging 
1992         bool hit_border 
= false; 
1994         // end of the current column 
1997         // find the column where this event occurred 
1999             countCol 
= m_owner
->GetColumnCount(); 
2000         for (col 
= 0; col 
< countCol
; col
++) 
2002             xpos 
+= m_owner
->GetColumnWidth( col 
); 
2005             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
2007                 // near the column border 
2014                 // inside the column 
2021         if ( col 
== countCol 
) 
2024         if (event
.LeftDown() || event
.RightUp()) 
2026             if (hit_border 
&& event
.LeftDown()) 
2028                 if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
2029                                    event
.GetPosition()) ) 
2031                     m_isDragging 
= true; 
2036                 //else: column resizing was vetoed by the user code 
2038             else // click on a column 
2040                 // record the selected state of the columns 
2041                 if (event
.LeftDown()) 
2043                     for (int i
=0; i 
< m_owner
->GetColumnCount(); i
++) 
2046                         m_owner
->GetColumn(i
, colItem
); 
2047                         long state 
= colItem
.GetState(); 
2049                             colItem
.SetState(state 
| wxLIST_STATE_SELECTED
); 
2051                             colItem
.SetState(state 
& ~wxLIST_STATE_SELECTED
); 
2052                         m_owner
->SetColumn(i
, colItem
); 
2056                 SendListEvent( event
.LeftDown() 
2057                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
2058                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
2059                                 event
.GetPosition()); 
2062         else if (event
.Moving()) 
2067                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
2068                 m_currentCursor 
= m_resizeCursor
; 
2072                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
2073                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
2077                 SetCursor(*m_currentCursor
); 
2082 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
2084     m_owner
->SetFocus(); 
2088 bool wxListHeaderWindow::SendListEvent(wxEventType type
, const wxPoint
& pos
) 
2090     wxWindow 
*parent 
= GetParent(); 
2091     wxListEvent 
le( type
, parent
->GetId() ); 
2092     le
.SetEventObject( parent 
); 
2093     le
.m_pointDrag 
= pos
; 
2095     // the position should be relative to the parent window, not 
2096     // this one for compatibility with MSW and common sense: the 
2097     // user code doesn't know anything at all about this header 
2098     // window, so why should it get positions relative to it? 
2099     le
.m_pointDrag
.y 
-= GetSize().y
; 
2101     le
.m_col 
= m_column
; 
2102     return !parent
->GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
2105 //----------------------------------------------------------------------------- 
2106 // wxListRenameTimer (internal) 
2107 //----------------------------------------------------------------------------- 
2109 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
2114 void wxListRenameTimer::Notify() 
2116     m_owner
->OnRenameTimer(); 
2119 //----------------------------------------------------------------------------- 
2120 // wxListTextCtrlWrapper (internal) 
2121 //----------------------------------------------------------------------------- 
2123 BEGIN_EVENT_TABLE(wxListTextCtrlWrapper
, wxEvtHandler
) 
2124     EVT_CHAR           (wxListTextCtrlWrapper::OnChar
) 
2125     EVT_KEY_UP         (wxListTextCtrlWrapper::OnKeyUp
) 
2126     EVT_KILL_FOCUS     (wxListTextCtrlWrapper::OnKillFocus
) 
2129 wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow 
*owner
, 
2132               : m_startValue(owner
->GetItemText(itemEdit
)), 
2133                 m_itemEdited(itemEdit
) 
2137     m_aboutToFinish 
= false; 
2139     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
2141     m_owner
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
2142                                   &rectLabel
.x
, &rectLabel
.y
); 
2144     m_text
->Create(owner
, wxID_ANY
, m_startValue
, 
2145                    wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2146                    wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
2149     m_text
->PushEventHandler(this); 
2152 void wxListTextCtrlWrapper::EndEdit(bool discardChanges
) 
2154     m_aboutToFinish 
= true; 
2156     if ( discardChanges 
) 
2158         m_owner
->OnRenameCancelled(m_itemEdited
); 
2164         // Notify the owner about the changes 
2167         // Even if vetoed, close the control (consistent with MSW) 
2172 void wxListTextCtrlWrapper::Finish( bool setfocus 
) 
2174     m_text
->RemoveEventHandler(this); 
2175     m_owner
->ResetTextControl( m_text 
); 
2177     wxPendingDelete
.Append( this ); 
2180         m_owner
->SetFocus(); 
2183 bool wxListTextCtrlWrapper::AcceptChanges() 
2185     const wxString value 
= m_text
->GetValue(); 
2187     // notice that we should always call OnRenameAccept() to generate the "end 
2188     // label editing" event, even if the user hasn't really changed anything 
2189     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
2191         // vetoed by the user 
2195     // accepted, do rename the item (unless nothing changed) 
2196     if ( value 
!= m_startValue 
) 
2197         m_owner
->SetItemText(m_itemEdited
, value
); 
2202 void wxListTextCtrlWrapper::OnChar( wxKeyEvent 
&event 
) 
2204     switch ( event
.m_keyCode 
) 
2219 void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent 
&event 
) 
2221     if (m_aboutToFinish
) 
2223         // auto-grow the textctrl: 
2224         wxSize parentSize 
= m_owner
->GetSize(); 
2225         wxPoint myPos 
= m_text
->GetPosition(); 
2226         wxSize mySize 
= m_text
->GetSize(); 
2228         m_text
->GetTextExtent(m_text
->GetValue() + _T("MM"), &sx
, &sy
); 
2229         if (myPos
.x 
+ sx 
> parentSize
.x
) 
2230             sx 
= parentSize
.x 
- myPos
.x
; 
2233        m_text
->SetSize(sx
, wxDefaultCoord
); 
2239 void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent 
&event 
) 
2241     if ( !m_aboutToFinish 
) 
2243         if ( !AcceptChanges() ) 
2244             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2249     // We must let the native text control handle focus 
2253 //----------------------------------------------------------------------------- 
2255 //----------------------------------------------------------------------------- 
2257 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledCanvas
) 
2258   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2259   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2260   EVT_CHAR           (wxListMainWindow::OnChar
) 
2261   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2262   EVT_KEY_UP         (wxListMainWindow::OnKeyUp
) 
2263   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2264   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2265   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2266   EVT_CHILD_FOCUS    (wxListMainWindow::OnChildFocus
) 
2269 void wxListMainWindow::Init() 
2274     m_lineTo 
= (size_t)-1; 
2280     m_small_image_list 
= NULL
; 
2281     m_normal_image_list 
= NULL
; 
2283     m_small_spacing 
= 30; 
2284     m_normal_spacing 
= 40; 
2288     m_isCreated 
= false; 
2290     m_lastOnSame 
= false; 
2291     m_renameTimer 
= new wxListRenameTimer( this ); 
2292     m_textctrlWrapper 
= NULL
; 
2296     m_lineSelectSingleOnUp 
= 
2297     m_lineBeforeLastClicked 
= (size_t)-1; 
2300 wxListMainWindow::wxListMainWindow() 
2305     m_highlightUnfocusedBrush 
= NULL
; 
2308 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2313                                     const wxString 
&name 
) 
2314                 : wxScrolledCanvas( parent
, id
, pos
, size
, 
2315                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2319     m_highlightBrush 
= new wxBrush
 
2321                             wxSystemSettings::GetColour
 
2323                                 wxSYS_COLOUR_HIGHLIGHT
 
2328     m_highlightUnfocusedBrush 
= new wxBrush
 
2330                                  wxSystemSettings::GetColour
 
2332                                      wxSYS_COLOUR_BTNSHADOW
 
2337     SetScrollbars( 0, 0, 0, 0, 0, 0 ); 
2339     wxVisualAttributes attr 
= wxGenericListCtrl::GetClassDefaultAttributes(); 
2340     SetOwnForegroundColour( attr
.colFg 
); 
2341     SetOwnBackgroundColour( attr
.colBg 
); 
2343         SetOwnFont( attr
.font 
); 
2346 wxListMainWindow::~wxListMainWindow() 
2349     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
2350     WX_CLEAR_ARRAY(m_aColWidths
); 
2352     delete m_highlightBrush
; 
2353     delete m_highlightUnfocusedBrush
; 
2354     delete m_renameTimer
; 
2357 void wxListMainWindow::CacheLineData(size_t line
) 
2359     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
2361     wxListLineData 
*ld 
= GetDummyLine(); 
2363     size_t countCol 
= GetColumnCount(); 
2364     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2366         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2367         ld
->SetImage(col
, listctrl
->OnGetItemColumnImage(line
, col
)); 
2370     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
2373 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2375     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2376     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); 
2378     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2380     // we need to recreate the dummy line if the number of columns in the 
2381     // control changed as it would have the incorrect number of fields 
2383     if ( !m_lines
.IsEmpty() && 
2384             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
2386         self
->m_lines
.Clear(); 
2389     if ( m_lines
.IsEmpty() ) 
2391         wxListLineData 
*line 
= new wxListLineData(self
); 
2392         self
->m_lines
.Add(line
); 
2394         // don't waste extra memory -- there never going to be anything 
2395         // else/more in this array 
2396         self
->m_lines
.Shrink(); 
2402 // ---------------------------------------------------------------------------- 
2403 // line geometry (report mode only) 
2404 // ---------------------------------------------------------------------------- 
2406 wxCoord 
wxListMainWindow::GetLineHeight() const 
2408     // we cache the line height as calling GetTextExtent() is slow 
2409     if ( !m_lineHeight 
) 
2411         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2413         wxClientDC 
dc( self 
); 
2414         dc
.SetFont( GetFont() ); 
2417         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2419         if ( m_small_image_list 
&& m_small_image_list
->GetImageCount() ) 
2422             m_small_image_list
->GetSize(0, iw
, ih
); 
2427         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2430     return m_lineHeight
; 
2433 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2435     wxASSERT_MSG( InReportView(), _T("only works in report mode") ); 
2437     return LINE_SPACING 
+ line 
* GetLineHeight(); 
2440 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2442     if ( !InReportView() ) 
2443         return GetLine(line
)->m_gi
->m_rectAll
; 
2446     rect
.x 
= HEADER_OFFSET_X
; 
2447     rect
.y 
= GetLineY(line
); 
2448     rect
.width 
= GetHeaderWidth(); 
2449     rect
.height 
= GetLineHeight(); 
2454 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2456     if ( !InReportView() ) 
2457         return GetLine(line
)->m_gi
->m_rectLabel
; 
2460     wxListLineData 
*data 
= GetLine(line
); 
2461     wxListItemDataList::compatibility_iterator node 
= data
->m_items
.GetFirst(); 
2464         wxListItemData 
*item 
= node
->GetData(); 
2465         if ( item
->HasImage() ) 
2468             GetImageSize( item
->GetImage(), ix
, iy 
); 
2469             image_x 
= 3 + ix 
+ IMAGE_MARGIN_IN_REPORT_MODE
; 
2474     rect
.x 
= image_x 
+ HEADER_OFFSET_X
; 
2475     rect
.y 
= GetLineY(line
); 
2476     rect
.width 
= GetColumnWidth(0) - image_x
; 
2477     rect
.height 
= GetLineHeight(); 
2482 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2484     if ( !InReportView() ) 
2485         return GetLine(line
)->m_gi
->m_rectIcon
; 
2487     wxListLineData 
*ld 
= GetLine(line
); 
2488     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2491     rect
.x 
= HEADER_OFFSET_X
; 
2492     rect
.y 
= GetLineY(line
); 
2493     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2498 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2500     return InReportView() ? GetLineRect(line
) 
2501                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2504 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2506     wxASSERT_MSG( line 
< GetItemCount(), _T("invalid line in HitTestLine") ); 
2508     wxListLineData 
*ld 
= GetLine(line
); 
2510     if ( ld
->HasImage() && GetLineIconRect(line
).Contains(x
, y
) ) 
2511         return wxLIST_HITTEST_ONITEMICON
; 
2513     // VS: Testing for "ld->HasText() || InReportView()" instead of 
2514     //     "ld->HasText()" is needed to make empty lines in report view 
2516     if ( ld
->HasText() || InReportView() ) 
2518         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2519                                      : GetLineLabelRect(line
); 
2521         if ( rect
.Contains(x
, y
) ) 
2522             return wxLIST_HITTEST_ONITEMLABEL
; 
2528 // ---------------------------------------------------------------------------- 
2529 // highlight (selection) handling 
2530 // ---------------------------------------------------------------------------- 
2532 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2536         return m_selStore
.IsSelected(line
); 
2540         wxListLineData 
*ld 
= GetLine(line
); 
2541         wxCHECK_MSG( ld
, false, _T("invalid index in IsHighlighted") ); 
2543         return ld
->IsHighlighted(); 
2547 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
2553         wxArrayInt linesChanged
; 
2554         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
2557             // meny items changed state, refresh everything 
2558             RefreshLines(lineFrom
, lineTo
); 
2560         else // only a few items changed state, refresh only them 
2562             size_t count 
= linesChanged
.GetCount(); 
2563             for ( size_t n 
= 0; n 
< count
; n
++ ) 
2565                 RefreshLine(linesChanged
[n
]); 
2569     else // iterate over all items in non report view 
2571         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2573             if ( HighlightLine(line
, highlight
) ) 
2579 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2585         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2589         wxListLineData 
*ld 
= GetLine(line
); 
2590         wxCHECK_MSG( ld
, false, _T("invalid index in HighlightLine") ); 
2592         changed 
= ld
->Highlight(highlight
); 
2597         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2598                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2604 void wxListMainWindow::RefreshLine( size_t line 
) 
2606     if ( InReportView() ) 
2608         size_t visibleFrom
, visibleTo
; 
2609         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2611         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
2615     wxRect rect 
= GetLineRect(line
); 
2617     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2618     RefreshRect( rect 
); 
2621 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2623     // we suppose that they are ordered by caller 
2624     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2626     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2628     if ( InReportView() ) 
2630         size_t visibleFrom
, visibleTo
; 
2631         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2633         if ( lineFrom 
< visibleFrom 
) 
2634             lineFrom 
= visibleFrom
; 
2635         if ( lineTo 
> visibleTo 
) 
2640         rect
.y 
= GetLineY(lineFrom
); 
2641         rect
.width 
= GetClientSize().x
; 
2642         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
2644         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2645         RefreshRect( rect 
); 
2649         // TODO: this should be optimized... 
2650         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2657 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2659     if ( InReportView() ) 
2661         size_t visibleFrom
, visibleTo
; 
2662         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2664         if ( lineFrom 
< visibleFrom 
) 
2665             lineFrom 
= visibleFrom
; 
2666         else if ( lineFrom 
> visibleTo 
) 
2671         rect
.y 
= GetLineY(lineFrom
); 
2672         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2674         wxSize size 
= GetClientSize(); 
2675         rect
.width 
= size
.x
; 
2677         // refresh till the bottom of the window 
2678         rect
.height 
= size
.y 
- rect
.y
; 
2680         RefreshRect( rect 
); 
2684         // TODO: how to do it more efficiently? 
2689 void wxListMainWindow::RefreshSelected() 
2695     if ( InReportView() ) 
2697         GetVisibleLinesRange(&from
, &to
); 
2702         to 
= GetItemCount() - 1; 
2705     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
2706         RefreshLine(m_current
); 
2708     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
2710         // NB: the test works as expected even if m_current == -1 
2711         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
2716 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2718     // Note: a wxPaintDC must be constructed even if no drawing is 
2719     // done (a Windows requirement). 
2720     wxPaintDC 
dc( this ); 
2724         // nothing to draw or not the moment to draw it 
2730         // delay the repainting until we calculate all the items positions 
2737     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2739     dc
.SetFont( GetFont() ); 
2741     if ( InReportView() ) 
2743         int lineHeight 
= GetLineHeight(); 
2745         size_t visibleFrom
, visibleTo
; 
2746         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2749         int xOrig 
= dc
.LogicalToDeviceX( 0 ); 
2750         int yOrig 
= dc
.LogicalToDeviceY( 0 ); 
2752         // tell the caller cache to cache the data 
2755             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2756                                 GetParent()->GetId()); 
2757             evCache
.SetEventObject( GetParent() ); 
2758             evCache
.m_oldItemIndex 
= visibleFrom
; 
2759             evCache
.m_itemIndex 
= visibleTo
; 
2760             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2763         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2765             rectLine 
= GetLineRect(line
); 
2768             if ( !IsExposed(rectLine
.x 
+ xOrig
, rectLine
.y 
+ yOrig
, 
2769                             rectLine
.width
, rectLine
.height
) ) 
2771                 // don't redraw unaffected lines to avoid flicker 
2775             GetLine(line
)->DrawInReportMode( &dc
, 
2777                                              GetLineHighlightRect(line
), 
2778                                              IsHighlighted(line
) ); 
2781         if ( HasFlag(wxLC_HRULES
) ) 
2783             wxPen 
pen(GetRuleColour(), 1, wxPENSTYLE_SOLID
); 
2784             wxSize clientSize 
= GetClientSize(); 
2786             size_t i 
= visibleFrom
; 
2787             if (i 
== 0) i 
= 1; // Don't draw the first one 
2788             for ( ; i 
<= visibleTo
; i
++ ) 
2791                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2792                 dc
.DrawLine(0 - dev_x
, i 
* lineHeight
, 
2793                             clientSize
.x 
- dev_x
, i 
* lineHeight
); 
2796             // Draw last horizontal rule 
2797             if ( visibleTo 
== GetItemCount() - 1 ) 
2800                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2801                 dc
.DrawLine(0 - dev_x
, (m_lineTo 
+ 1) * lineHeight
, 
2802                             clientSize
.x 
- dev_x 
, (m_lineTo 
+ 1) * lineHeight 
); 
2806         // Draw vertical rules if required 
2807         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2809             wxPen 
pen(GetRuleColour(), 1, wxPENSTYLE_SOLID
); 
2810             wxRect firstItemRect
, lastItemRect
; 
2812             GetItemRect(visibleFrom
, firstItemRect
); 
2813             GetItemRect(visibleTo
, lastItemRect
); 
2814             int x 
= firstItemRect
.GetX(); 
2816             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2818             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2820                 int colWidth 
= GetColumnWidth(col
); 
2822                 int x_pos 
= x 
- dev_x
; 
2823                 if (col 
< GetColumnCount()-1) x_pos 
-= 2; 
2824                 dc
.DrawLine(x_pos
, firstItemRect
.GetY() - 1 - dev_y
, 
2825                             x_pos
, lastItemRect
.GetBottom() + 1 - dev_y
); 
2831         size_t count 
= GetItemCount(); 
2832         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2834             GetLine(i
)->Draw( &dc 
); 
2839     // Don't draw rect outline under Mac at all. 
2844             wxRect 
rect( GetLineHighlightRect( m_current 
) ); 
2846             dc
.SetPen( *wxBLACK_PEN 
); 
2847             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2848             dc
.DrawRectangle( rect 
); 
2850             wxRendererNative::Get().DrawItemSelectionRect( this, dc
, rect
, wxCONTROL_CURRENT
|wxCONTROL_FOCUSED 
); 
2858 void wxListMainWindow::HighlightAll( bool on 
) 
2860     if ( IsSingleSel() ) 
2862         wxASSERT_MSG( !on
, _T("can't do this in a single selection control") ); 
2864         // we just have one item to turn off 
2865         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2867             HighlightLine(m_current
, false); 
2868             RefreshLine(m_current
); 
2871     else // multi selection 
2874             HighlightLines(0, GetItemCount() - 1, on
); 
2878 void wxListMainWindow::OnChildFocus(wxChildFocusEvent
& WXUNUSED(event
)) 
2880     // Do nothing here.  This prevents the default handler in wxScrolledWindow 
2881     // from needlessly scrolling the window when the edit control is 
2882     // dismissed.  See ticket #9563. 
2885 void wxListMainWindow::SendNotify( size_t line
, 
2886                                    wxEventType command
, 
2887                                    const wxPoint
& point 
) 
2889     wxListEvent 
le( command
, GetParent()->GetId() ); 
2890     le
.SetEventObject( GetParent() ); 
2892     le
.m_itemIndex 
= line
; 
2894     // set only for events which have position 
2895     if ( point 
!= wxDefaultPosition 
) 
2896         le
.m_pointDrag 
= point
; 
2898     // don't try to get the line info for virtual list controls: the main 
2899     // program has it anyhow and if we did it would result in accessing all 
2900     // the lines, even those which are not visible now and this is precisely 
2901     // what we're trying to avoid 
2904         if ( line 
!= (size_t)-1 ) 
2906             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2908         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2910     //else: there may be no more such item 
2912     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2915 void wxListMainWindow::ChangeCurrent(size_t current
) 
2917     m_current 
= current
; 
2919     // as the current item changed, we shouldn't start editing it when the 
2920     // "slow click" timer expires as the click happened on another item 
2921     if ( m_renameTimer
->IsRunning() ) 
2922         m_renameTimer
->Stop(); 
2924     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2927 wxTextCtrl 
*wxListMainWindow::EditLabel(long item
, wxClassInfo
* textControlClass
) 
2929     wxCHECK_MSG( (item 
>= 0) && ((size_t)item 
< GetItemCount()), NULL
, 
2930                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2932     wxASSERT_MSG( textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
)), 
2933                  wxT("EditLabel() needs a text control") ); 
2935     size_t itemEdit 
= (size_t)item
; 
2937     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2938     le
.SetEventObject( GetParent() ); 
2939     le
.m_itemIndex 
= item
; 
2940     wxListLineData 
*data 
= GetLine(itemEdit
); 
2941     wxCHECK_MSG( data
, NULL
, _T("invalid index in EditLabel()") ); 
2942     data
->GetItem( 0, le
.m_item 
); 
2944     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2946         // vetoed by user code 
2950     // We have to call this here because the label in question might just have 
2951     // been added and no screen update taken place. 
2956         // Pending events dispatched by wxSafeYield might have changed the item 
2958         if ( (size_t)item 
>= GetItemCount() ) 
2962     wxTextCtrl 
* const text 
= (wxTextCtrl 
*)textControlClass
->CreateObject(); 
2963     m_textctrlWrapper 
= new wxListTextCtrlWrapper(this, text
, item
); 
2964     return m_textctrlWrapper
->GetText(); 
2967 void wxListMainWindow::OnRenameTimer() 
2969     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2971     EditLabel( m_current 
); 
2974 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2976     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2977     le
.SetEventObject( GetParent() ); 
2978     le
.m_itemIndex 
= itemEdit
; 
2980     wxListLineData 
*data 
= GetLine(itemEdit
); 
2982     wxCHECK_MSG( data
, false, _T("invalid index in OnRenameAccept()") ); 
2984     data
->GetItem( 0, le
.m_item 
); 
2985     le
.m_item
.m_text 
= value
; 
2986     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2990 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2992     // let owner know that the edit was cancelled 
2993     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2995     le
.SetEditCanceled(true); 
2997     le
.SetEventObject( GetParent() ); 
2998     le
.m_itemIndex 
= itemEdit
; 
3000     wxListLineData 
*data 
= GetLine(itemEdit
); 
3001     wxCHECK_RET( data
, _T("invalid index in OnRenameCancelled()") ); 
3003     data
->GetItem( 0, le
.m_item 
); 
3004     GetEventHandler()->ProcessEvent( le 
); 
3007 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
3011     // On wxMac we can't depend on the EVT_KILL_FOCUS event to properly 
3012     // shutdown the edit control when the mouse is clicked elsewhere on the 
3013     // listctrl because the order of events is different (or something like 
3014     // that), so explicitly end the edit if it is active. 
3015     if ( event
.LeftDown() && m_textctrlWrapper 
) 
3016         m_textctrlWrapper
->EndEdit( false ); 
3019     if ( event
.LeftDown() ) 
3022     event
.SetEventObject( GetParent() ); 
3023     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3026     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
3028         // let the base handle mouse wheel events. 
3033     if ( !HasCurrent() || IsEmpty() ) 
3035         if (event
.RightDown()) 
3037             SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
3039             wxContextMenuEvent 
evtCtx( 
3041                 GetParent()->GetId(), 
3042                 ClientToScreen(event
.GetPosition())); 
3043             evtCtx
.SetEventObject(GetParent()); 
3044             GetParent()->GetEventHandler()->ProcessEvent(evtCtx
); 
3052     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
3053         event
.ButtonDClick()) ) 
3056     int x 
= event
.GetX(); 
3057     int y 
= event
.GetY(); 
3058     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
3060     // where did we hit it (if we did)? 
3063     size_t count 
= GetItemCount(), 
3066     if ( InReportView() ) 
3068         current 
= y 
/ GetLineHeight(); 
3069         if ( current 
< count 
) 
3070             hitResult 
= HitTestLine(current
, x
, y
); 
3074         // TODO: optimize it too! this is less simple than for report view but 
3075         //       enumerating all items is still not a way to do it!! 
3076         for ( current 
= 0; current 
< count
; current
++ ) 
3078             hitResult 
= HitTestLine(current
, x
, y
); 
3084     if (event
.Dragging()) 
3086         if (m_dragCount 
== 0) 
3088             // we have to report the raw, physical coords as we want to be 
3089             // able to call HitTest(event.m_pointDrag) from the user code to 
3090             // get the item being dragged 
3091             m_dragStart 
= event
.GetPosition(); 
3096         if (m_dragCount 
!= 3) 
3099         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
3100                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
3102         wxListEvent 
le( command
, GetParent()->GetId() ); 
3103         le
.SetEventObject( GetParent() ); 
3104         le
.m_itemIndex 
= m_lineLastClicked
; 
3105         le
.m_pointDrag 
= m_dragStart
; 
3106         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
3117         // outside of any item 
3118         if (event
.RightDown()) 
3120             SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
3122             wxContextMenuEvent 
evtCtx( 
3124                 GetParent()->GetId(), 
3125                 ClientToScreen(event
.GetPosition())); 
3126             evtCtx
.SetEventObject(GetParent()); 
3127             GetParent()->GetEventHandler()->ProcessEvent(evtCtx
); 
3131             // reset the selection and bail out 
3132             HighlightAll(false); 
3138     bool forceClick 
= false; 
3139     if (event
.ButtonDClick()) 
3141         if ( m_renameTimer
->IsRunning() ) 
3142             m_renameTimer
->Stop(); 
3144         m_lastOnSame 
= false; 
3146         if ( current 
== m_lineLastClicked 
) 
3148             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3154             // The first click was on another item, so don't interpret this as 
3155             // a double click, but as a simple click instead 
3162         if (m_lineSelectSingleOnUp 
!= (size_t)-1) 
3164             // select single line 
3165             HighlightAll( false ); 
3166             ReverseHighlight(m_lineSelectSingleOnUp
); 
3171             if ((current 
== m_current
) && 
3172                 (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
3173                 HasFlag(wxLC_EDIT_LABELS
) ) 
3175                 if ( !InReportView() || 
3176                         GetLineLabelRect(current
).Contains(x
, y
) ) 
3178                     int dclick 
= wxSystemSettings::GetMetric(wxSYS_DCLICK_MSEC
); 
3179                     m_renameTimer
->Start(dclick 
> 0 ? dclick 
: 250, true); 
3184         m_lastOnSame 
= false; 
3185         m_lineSelectSingleOnUp 
= (size_t)-1; 
3189         // This is necessary, because after a DnD operation in 
3190         // from and to ourself, the up event is swallowed by the 
3191         // DnD code. So on next non-up event (which means here and 
3192         // now) m_lineSelectSingleOnUp should be reset. 
3193         m_lineSelectSingleOnUp 
= (size_t)-1; 
3195     if (event
.RightDown()) 
3197         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3198         m_lineLastClicked 
= current
; 
3200         // If the item is already selected, do not update the selection. 
3201         // Multi-selections should not be cleared if a selected item is clicked. 
3202         if (!IsHighlighted(current
)) 
3204             HighlightAll(false); 
3205             ChangeCurrent(current
); 
3206             ReverseHighlight(m_current
); 
3209         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
3211         // Allow generation of context menu event 
3214     else if (event
.MiddleDown()) 
3216         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
3218     else if ( event
.LeftDown() || forceClick 
) 
3220         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3221         m_lineLastClicked 
= current
; 
3223         size_t oldCurrent 
= m_current
; 
3224         bool oldWasSelected 
= IsHighlighted(m_current
); 
3226         bool cmdModifierDown 
= event
.CmdDown(); 
3227         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
3229             if ( IsSingleSel() || !IsHighlighted(current
) ) 
3231                 HighlightAll( false ); 
3233                 ChangeCurrent(current
); 
3235                 ReverseHighlight(m_current
); 
3237             else // multi sel & current is highlighted & no mod keys 
3239                 m_lineSelectSingleOnUp 
= current
; 
3240                 ChangeCurrent(current
); // change focus 
3243         else // multi sel & either ctrl or shift is down 
3245             if (cmdModifierDown
) 
3247                 ChangeCurrent(current
); 
3249                 ReverseHighlight(m_current
); 
3251             else if (event
.ShiftDown()) 
3253                 ChangeCurrent(current
); 
3255                 size_t lineFrom 
= oldCurrent
, 
3258                 if ( lineTo 
< lineFrom 
) 
3261                     lineFrom 
= m_current
; 
3264                 HighlightLines(lineFrom
, lineTo
); 
3266             else // !ctrl, !shift 
3268                 // test in the enclosing if should make it impossible 
3269                 wxFAIL_MSG( _T("how did we get here?") ); 
3273         if (m_current 
!= oldCurrent
) 
3274             RefreshLine( oldCurrent 
); 
3276         // forceClick is only set if the previous click was on another item 
3277         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
) && oldWasSelected
; 
3281 void wxListMainWindow::MoveToItem(size_t item
) 
3283     if ( item 
== (size_t)-1 ) 
3286     wxRect rect 
= GetLineRect(item
); 
3288     int client_w
, client_h
; 
3289     GetClientSize( &client_w
, &client_h 
); 
3291     const int hLine 
= GetLineHeight(); 
3293     int view_x 
= SCROLL_UNIT_X 
* GetScrollPos( wxHORIZONTAL 
); 
3294     int view_y 
= hLine 
* GetScrollPos( wxVERTICAL 
); 
3296     if ( InReportView() ) 
3298         // the next we need the range of lines shown it might be different, 
3299         // so recalculate it 
3300         ResetVisibleLinesRange(); 
3302         if (rect
.y 
< view_y
) 
3303             Scroll( -1, rect
.y 
/ hLine 
); 
3304         if (rect
.y 
+ rect
.height 
+ 5 > view_y 
+ client_h
) 
3305             Scroll( -1, (rect
.y 
+ rect
.height 
- client_h 
+ hLine
) / hLine 
); 
3308         // At least on Mac the visible lines value will get reset inside of 
3309         // Scroll *before* it actually scrolls the window because of the 
3310         // Update() that happens there, so it will still have the wrong value. 
3311         // So let's reset it again and wait for it to be recalculated in the 
3312         // next paint event.  I would expect this problem to show up in wxGTK 
3313         // too but couldn't duplicate it there.  Perhaps the order of events 
3314         // is different...  --Robin 
3315         ResetVisibleLinesRange(); 
3323         if (rect
.x
-view_x 
< 5) 
3324             sx 
= (rect
.x 
- 5) / SCROLL_UNIT_X
; 
3325         if (rect
.x 
+ rect
.width 
- 5 > view_x 
+ client_w
) 
3326             sx 
= (rect
.x 
+ rect
.width 
- client_w 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
; 
3328         if (rect
.y
-view_y 
< 5) 
3329             sy 
= (rect
.y 
- 5) / hLine
; 
3330         if (rect
.y 
+ rect
.height 
- 5 > view_y 
+ client_h
) 
3331             sy 
= (rect
.y 
+ rect
.height 
- client_h 
+ hLine
) / hLine
; 
3337 bool wxListMainWindow::ScrollList(int WXUNUSED(dx
), int dy
) 
3339     if ( !InReportView() ) 
3341         // TODO: this should work in all views but is not implemented now 
3346     GetVisibleLinesRange(&top
, &bottom
); 
3348     if ( bottom 
== (size_t)-1 ) 
3351     ResetVisibleLinesRange(); 
3353     int hLine 
= GetLineHeight(); 
3355     Scroll(-1, top 
+ dy 
/ hLine
); 
3358     // see comment in MoveToItem() for why we do this 
3359     ResetVisibleLinesRange(); 
3365 // ---------------------------------------------------------------------------- 
3366 // keyboard handling 
3367 // ---------------------------------------------------------------------------- 
3369 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
3371     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
3372                  _T("invalid item index in OnArrowChar()") ); 
3374     size_t oldCurrent 
= m_current
; 
3376     // in single selection we just ignore Shift as we can't select several 
3378     if ( event
.ShiftDown() && !IsSingleSel() ) 
3380         ChangeCurrent(newCurrent
); 
3382         // refresh the old focus to remove it 
3383         RefreshLine( oldCurrent 
); 
3385         // select all the items between the old and the new one 
3386         if ( oldCurrent 
> newCurrent 
) 
3388             newCurrent 
= oldCurrent
; 
3389             oldCurrent 
= m_current
; 
3392         HighlightLines(oldCurrent
, newCurrent
); 
3396         // all previously selected items are unselected unless ctrl is held 
3397         // in a multiselection control 
3398         if ( !event
.ControlDown() || IsSingleSel() ) 
3399             HighlightAll(false); 
3401         ChangeCurrent(newCurrent
); 
3403         // refresh the old focus to remove it 
3404         RefreshLine( oldCurrent 
); 
3406         // in single selection mode we must always have a selected item 
3407         if ( !event
.ControlDown() || IsSingleSel() ) 
3408             HighlightLine( m_current
, true ); 
3411     RefreshLine( m_current 
); 
3416 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
3418     wxWindow 
*parent 
= GetParent(); 
3420     // propagate the key event upwards 
3421     wxKeyEvent 
ke(event
); 
3422     ke
.SetEventObject( parent 
); 
3423     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
3429 void wxListMainWindow::OnKeyUp( wxKeyEvent 
&event 
) 
3431     wxWindow 
*parent 
= GetParent(); 
3433     // propagate the key event upwards 
3434     wxKeyEvent 
ke(event
); 
3435     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
3441 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
3443     wxWindow 
*parent 
= GetParent(); 
3445     // send a list_key event up 
3448         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
3449         le
.m_itemIndex 
= m_current
; 
3450         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3451         le
.m_code 
= event
.GetKeyCode(); 
3452         le
.SetEventObject( parent 
); 
3453         parent
->GetEventHandler()->ProcessEvent( le 
); 
3456     // propagate the char event upwards 
3457     wxKeyEvent 
ke(event
); 
3458     ke
.SetEventObject( parent 
); 
3459     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
3462     if ( HandleAsNavigationKey(event
) ) 
3465     // no item -> nothing to do 
3472     // don't use m_linesPerPage directly as it might not be computed yet 
3473     const int pageSize 
= GetCountPerPage(); 
3474     wxCHECK_RET( pageSize
, _T("should have non zero page size") ); 
3476     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3478         if (event
.GetKeyCode() == WXK_RIGHT
) 
3479             event
.m_keyCode 
= WXK_LEFT
; 
3480         else if (event
.GetKeyCode() == WXK_LEFT
) 
3481             event
.m_keyCode 
= WXK_RIGHT
; 
3484     switch ( event
.GetKeyCode() ) 
3487             if ( m_current 
> 0 ) 
3488                 OnArrowChar( m_current 
- 1, event 
); 
3492             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
3493                 OnArrowChar( m_current 
+ 1, event 
); 
3498                 OnArrowChar( GetItemCount() - 1, event 
); 
3503                 OnArrowChar( 0, event 
); 
3508                 int steps 
= InReportView() ? pageSize 
- 1 
3509                                            : m_current 
% pageSize
; 
3511                 int index 
= m_current 
- steps
; 
3515                 OnArrowChar( index
, event 
); 
3521                 int steps 
= InReportView() 
3523                                 : pageSize 
- (m_current 
% pageSize
) - 1; 
3525                 size_t index 
= m_current 
+ steps
; 
3526                 size_t count 
= GetItemCount(); 
3527                 if ( index 
>= count 
) 
3530                 OnArrowChar( index
, event 
); 
3535             if ( !InReportView() ) 
3537                 int index 
= m_current 
- pageSize
; 
3541                 OnArrowChar( index
, event 
); 
3546             if ( !InReportView() ) 
3548                 size_t index 
= m_current 
+ pageSize
; 
3550                 size_t count 
= GetItemCount(); 
3551                 if ( index 
>= count 
) 
3554                 OnArrowChar( index
, event 
); 
3559             if ( IsSingleSel() ) 
3561                 if ( event
.ControlDown() ) 
3563                     ReverseHighlight(m_current
); 
3565                 else // normal space press 
3567                     SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3570             else // multiple selection 
3572                 ReverseHighlight(m_current
); 
3578             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3586 // ---------------------------------------------------------------------------- 
3588 // ---------------------------------------------------------------------------- 
3590 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3594         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3595         event
.SetEventObject( GetParent() ); 
3596         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3600     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
3601     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
3602     // which are already drawn correctly resulting in horrible flicker - avoid 
3612 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3616         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
3617         event
.SetEventObject( GetParent() ); 
3618         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3626 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3628     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3630         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3632     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3634         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3636     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3638         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3640     else if ( InReportView() && (m_small_image_list
)) 
3642         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3646 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3648     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3650         m_normal_image_list
->GetSize( index
, width
, height 
); 
3652     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3654         m_small_image_list
->GetSize( index
, width
, height 
); 
3656     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3658         m_small_image_list
->GetSize( index
, width
, height 
); 
3660     else if ( InReportView() && m_small_image_list 
) 
3662         m_small_image_list
->GetSize( index
, width
, height 
); 
3671 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3673     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3674     dc
.SetFont( GetFont() ); 
3677     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3679     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3682 void wxListMainWindow::SetImageList( wxImageList 
*imageList
, int which 
) 
3686     // calc the spacing from the icon size 
3687     int width 
= 0, height 
= 0; 
3689     if ((imageList
) && (imageList
->GetImageCount()) ) 
3690         imageList
->GetSize(0, width
, height
); 
3692     if (which 
== wxIMAGE_LIST_NORMAL
) 
3694         m_normal_image_list 
= imageList
; 
3695         m_normal_spacing 
= width 
+ 8; 
3698     if (which 
== wxIMAGE_LIST_SMALL
) 
3700         m_small_image_list 
= imageList
; 
3701         m_small_spacing 
= width 
+ 14; 
3702         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
3706 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3710         m_small_spacing 
= spacing
; 
3712         m_normal_spacing 
= spacing
; 
3715 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3717     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3720 // ---------------------------------------------------------------------------- 
3722 // ---------------------------------------------------------------------------- 
3724 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3726     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3728     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3730     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3731         item
.m_width 
= GetTextLength( item
.m_text 
); 
3733     wxListHeaderData 
*column 
= node
->GetData(); 
3734     column
->SetItem( item 
); 
3736     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3738         headerWin
->m_dirty 
= true; 
3742     // invalidate it as it has to be recalculated 
3746 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3748     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3749                  _T("invalid column index") ); 
3751     wxCHECK_RET( InReportView(), 
3752                  _T("SetColumnWidth() can only be called in report mode.") ); 
3755     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3757         headerWin
->m_dirty 
= true; 
3759     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3760     wxCHECK_RET( node
, _T("no column?") ); 
3762     wxListHeaderData 
*column 
= node
->GetData(); 
3764     size_t count 
= GetItemCount(); 
3766     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3768         width 
= GetTextLength(column
->GetText()); 
3769         width 
+= 2*EXTRA_WIDTH
; 
3771         // check for column header's image availability 
3772         const int image 
= column
->GetImage(); 
3775             if ( m_small_image_list 
) 
3778                 m_small_image_list
->GetSize(image
, ix
, iy
); 
3779                 width 
+= ix 
+ HEADER_IMAGE_MARGIN_IN_REPORT_MODE
; 
3783     else if ( width 
== wxLIST_AUTOSIZE 
) 
3787             // TODO: determine the max width somehow... 
3788             width 
= WIDTH_COL_DEFAULT
; 
3792             wxClientDC 
dc(this); 
3793             dc
.SetFont( GetFont() ); 
3795             int max 
= AUTOSIZE_COL_MARGIN
; 
3797             //  if the cached column width isn't valid then recalculate it 
3798             if (m_aColWidths
.Item(col
)->bNeedsUpdate
) 
3800                 for (size_t i 
= 0; i 
< count
; i
++) 
3802                     wxListLineData 
*line 
= GetLine( i 
); 
3803                     wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3805                     wxCHECK_RET( n
, _T("no subitem?") ); 
3807                     wxListItemData 
*itemData 
= n
->GetData(); 
3810                     itemData
->GetItem(item
); 
3811                     int itemWidth 
= GetItemWidthWithImage(&item
); 
3812                     if (itemWidth 
> max
) 
3816                 m_aColWidths
.Item(col
)->bNeedsUpdate 
= false; 
3817                 m_aColWidths
.Item(col
)->nMaxWidth 
= max
; 
3820             max 
= m_aColWidths
.Item(col
)->nMaxWidth
; 
3821             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3825     column
->SetWidth( width 
); 
3827     // invalidate it as it has to be recalculated 
3831 int wxListMainWindow::GetHeaderWidth() const 
3833     if ( !m_headerWidth 
) 
3835         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3837         size_t count 
= GetColumnCount(); 
3838         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3840             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3844     return m_headerWidth
; 
3847 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3849     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3850     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3852     wxListHeaderData 
*column 
= node
->GetData(); 
3853     column
->GetItem( item 
); 
3856 int wxListMainWindow::GetColumnWidth( int col 
) const 
3858     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3859     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3861     wxListHeaderData 
*column 
= node
->GetData(); 
3862     return column
->GetWidth(); 
3865 // ---------------------------------------------------------------------------- 
3867 // ---------------------------------------------------------------------------- 
3869 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3871     long id 
= item
.m_itemId
; 
3872     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3873                  _T("invalid item index in SetItem") ); 
3877         wxListLineData 
*line 
= GetLine((size_t)id
); 
3878         line
->SetItem( item
.m_col
, item 
); 
3880         // Set item state if user wants 
3881         if ( item
.m_mask 
& wxLIST_MASK_STATE 
) 
3882             SetItemState( item
.m_itemId
, item
.m_state
, item
.m_state 
); 
3886             //  update the Max Width Cache if needed 
3887             int width 
= GetItemWidthWithImage(&item
); 
3889             if (width 
> m_aColWidths
.Item(item
.m_col
)->nMaxWidth
) 
3890                 m_aColWidths
.Item(item
.m_col
)->nMaxWidth 
= width
; 
3894     // update the item on screen 
3896     GetItemRect(id
, rectItem
); 
3897     RefreshRect(rectItem
); 
3900 void wxListMainWindow::SetItemStateAll(long state
, long stateMask
) 
3905     // first deal with selection 
3906     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3908         // set/clear select state 
3911             // optimized version for virtual listctrl. 
3912             m_selStore
.SelectRange(0, GetItemCount() - 1, state 
== wxLIST_STATE_SELECTED
); 
3915         else if ( state 
& wxLIST_STATE_SELECTED 
) 
3917             const long count 
= GetItemCount(); 
3918             for( long i 
= 0; i 
<  count
; i
++ ) 
3920                 SetItemState( i
, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED 
); 
3926             // clear for non virtual (somewhat optimized by using GetNextItem()) 
3928             while ( (i 
= GetNextItem(i
, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
)) != -1 ) 
3930                 SetItemState( i
, 0, wxLIST_STATE_SELECTED 
); 
3935     if ( HasCurrent() && (state 
== 0) && (stateMask 
& wxLIST_STATE_FOCUSED
) ) 
3937         // unfocus all: only one item can be focussed, so clearing focus for 
3938         // all items is simply clearing focus of the focussed item. 
3939         SetItemState(m_current
, state
, stateMask
); 
3941     //(setting focus to all items makes no sense, so it is not handled here.) 
3944 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3948         SetItemStateAll(state
, stateMask
); 
3952     wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3953                  _T("invalid list ctrl item index in SetItem") ); 
3955     size_t oldCurrent 
= m_current
; 
3956     size_t item 
= (size_t)litem
;    // safe because of the check above 
3958     // do we need to change the focus? 
3959     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3961         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3963             // don't do anything if this item is already focused 
3964             if ( item 
!= m_current 
) 
3966                 ChangeCurrent(item
); 
3968                 if ( oldCurrent 
!= (size_t)-1 ) 
3970                     if ( IsSingleSel() ) 
3972                         HighlightLine(oldCurrent
, false); 
3975                     RefreshLine(oldCurrent
); 
3978                 RefreshLine( m_current 
); 
3983             // don't do anything if this item is not focused 
3984             if ( item 
== m_current 
) 
3988                 if ( IsSingleSel() ) 
3990                     // we must unselect the old current item as well or we 
3991                     // might end up with more than one selected item in a 
3992                     // single selection control 
3993                     HighlightLine(oldCurrent
, false); 
3996                 RefreshLine( oldCurrent 
); 
4001     // do we need to change the selection state? 
4002     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
4004         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
4006         if ( IsSingleSel() ) 
4010                 // selecting the item also makes it the focused one in the 
4012                 if ( m_current 
!= item 
) 
4014                     ChangeCurrent(item
); 
4016                     if ( oldCurrent 
!= (size_t)-1 ) 
4018                         HighlightLine( oldCurrent
, false ); 
4019                         RefreshLine( oldCurrent 
); 
4025                 // only the current item may be selected anyhow 
4026                 if ( item 
!= m_current 
) 
4031         if ( HighlightLine(item
, on
) ) 
4038 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
4040     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
4041                  _T("invalid list ctrl item index in GetItemState()") ); 
4043     int ret 
= wxLIST_STATE_DONTCARE
; 
4045     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
4047         if ( (size_t)item 
== m_current 
) 
4048             ret 
|= wxLIST_STATE_FOCUSED
; 
4051     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
4053         if ( IsHighlighted(item
) ) 
4054             ret 
|= wxLIST_STATE_SELECTED
; 
4060 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
4062     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
4063                  _T("invalid item index in GetItem") ); 
4065     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
4066     line
->GetItem( item
.m_col
, item 
); 
4068     // Get item state if user wants it 
4069     if ( item
.m_mask 
& wxLIST_MASK_STATE 
) 
4070         item
.m_state 
= GetItemState( item
.m_itemId
, wxLIST_STATE_SELECTED 
| 
4071                                                  wxLIST_STATE_FOCUSED 
); 
4074 // ---------------------------------------------------------------------------- 
4076 // ---------------------------------------------------------------------------- 
4078 size_t wxListMainWindow::GetItemCount() const 
4080     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
4083 void wxListMainWindow::SetItemCount(long count
) 
4085     m_selStore
.SetItemCount(count
); 
4086     m_countVirt 
= count
; 
4088     ResetVisibleLinesRange(); 
4090     // scrollbars must be reset 
4094 int wxListMainWindow::GetSelectedItemCount() const 
4096     // deal with the quick case first 
4097     if ( IsSingleSel() ) 
4098         return HasCurrent() ? IsHighlighted(m_current
) : false; 
4100     // virtual controls remmebers all its selections itself 
4102         return m_selStore
.GetSelectedCount(); 
4104     // TODO: we probably should maintain the number of items selected even for 
4105     //       non virtual controls as enumerating all lines is really slow... 
4106     size_t countSel 
= 0; 
4107     size_t count 
= GetItemCount(); 
4108     for ( size_t line 
= 0; line 
< count
; line
++ ) 
4110         if ( GetLine(line
)->IsHighlighted() ) 
4117 // ---------------------------------------------------------------------------- 
4118 // item position/size 
4119 // ---------------------------------------------------------------------------- 
4121 wxRect 
wxListMainWindow::GetViewRect() const 
4123     wxASSERT_MSG( !HasFlag(wxLC_LIST
), "not implemented for list view" ); 
4125     // we need to find the longest/tallest label 
4126     wxCoord xMax 
= 0, yMax 
= 0; 
4127     const int count 
= GetItemCount(); 
4130         for ( int i 
= 0; i 
< count
; i
++ ) 
4132             // we need logical, not physical, coordinates here, so use 
4133             // GetLineRect() instead of GetItemRect() 
4134             wxRect r 
= GetLineRect(i
); 
4136             wxCoord x 
= r
.GetRight(), 
4146     // some fudge needed to make it look prettier 
4147     xMax 
+= 2 * EXTRA_BORDER_X
; 
4148     yMax 
+= 2 * EXTRA_BORDER_Y
; 
4150     // account for the scrollbars if necessary 
4151     const wxSize sizeAll 
= GetClientSize(); 
4152     if ( xMax 
> sizeAll
.x 
) 
4153         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
4154     if ( yMax 
> sizeAll
.y 
) 
4155         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
4157     return wxRect(0, 0, xMax
, yMax
); 
4161 wxListMainWindow::GetSubItemRect(long item
, long subItem
, wxRect
& rect
) const 
4163     wxCHECK_MSG( subItem 
== wxLIST_GETSUBITEMRECT_WHOLEITEM 
|| InReportView(), 
4165                  _T("GetSubItemRect only meaningful in report view") ); 
4166     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), false, 
4167                  _T("invalid item in GetSubItemRect") ); 
4169     // ensure that we're laid out, otherwise we could return nonsense 
4172         wxConstCast(this, wxListMainWindow
)-> 
4173             RecalculatePositions(true /* no refresh */); 
4176     rect 
= GetLineRect((size_t)item
); 
4178     // Adjust rect to specified column 
4179     if ( subItem 
!= wxLIST_GETSUBITEMRECT_WHOLEITEM 
) 
4181         wxCHECK_MSG( subItem 
>= 0 && subItem 
< GetColumnCount(), false, 
4182                      _T("invalid subItem in GetSubItemRect") ); 
4184         for (int i 
= 0; i 
< subItem
; i
++) 
4186             rect
.x 
+= GetColumnWidth(i
); 
4188         rect
.width 
= GetColumnWidth(subItem
); 
4191     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
4196 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
4199     GetItemRect(item
, rect
); 
4207 // ---------------------------------------------------------------------------- 
4208 // geometry calculation 
4209 // ---------------------------------------------------------------------------- 
4211 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
4213     const int lineHeight 
= GetLineHeight(); 
4215     wxClientDC 
dc( this ); 
4216     dc
.SetFont( GetFont() ); 
4218     const size_t count 
= GetItemCount(); 
4221     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
4222         iconSpacing 
= m_normal_spacing
; 
4223     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
4224         iconSpacing 
= m_small_spacing
; 
4228     // Note that we do not call GetClientSize() here but 
4229     // GetSize() and subtract the border size for sunken 
4230     // borders manually. This is technically incorrect, 
4231     // but we need to know the client area's size WITHOUT 
4232     // scrollbars here. Since we don't know if there are 
4233     // any scrollbars, we use GetSize() instead. Another 
4234     // solution would be to call SetScrollbars() here to 
4235     // remove the scrollbars and call GetClientSize() then, 
4236     // but this might result in flicker and - worse - will 
4237     // reset the scrollbars to 0 which is not good at all 
4238     // if you resize a dialog/window, but don't want to 
4239     // reset the window scrolling. RR. 
4240     // Furthermore, we actually do NOT subtract the border 
4241     // width as 2 pixels is just the extra space which we 
4242     // need around the actual content in the window. Other- 
4243     // wise the text would e.g. touch the upper border. RR. 
4246     GetSize( &clientWidth
, &clientHeight 
); 
4248     if ( InReportView() ) 
4250         // all lines have the same height and we scroll one line per step 
4251         int entireHeight 
= count 
* lineHeight 
+ LINE_SPACING
; 
4253         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
4255         ResetVisibleLinesRange(); 
4257         SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
4258                        GetHeaderWidth() / SCROLL_UNIT_X
, 
4259                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
4260                        GetScrollPos(wxHORIZONTAL
), 
4261                        GetScrollPos(wxVERTICAL
), 
4266         // we have 3 different layout strategies: either layout all items 
4267         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
4268         // to arrange them in top to bottom, left to right (don't ask me why 
4269         // not the other way round...) order 
4270         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
4272             int x 
= EXTRA_BORDER_X
; 
4273             int y 
= EXTRA_BORDER_Y
; 
4275             wxCoord widthMax 
= 0; 
4278             for ( i 
= 0; i 
< count
; i
++ ) 
4280                 wxListLineData 
*line 
= GetLine(i
); 
4281                 line
->CalculateSize( &dc
, iconSpacing 
); 
4282                 line
->SetPosition( x
, y
, iconSpacing 
); 
4284                 wxSize sizeLine 
= GetLineSize(i
); 
4286                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
4288                     if ( sizeLine
.x 
> widthMax 
) 
4289                         widthMax 
= sizeLine
.x
; 
4293                 else // wxLC_ALIGN_LEFT 
4295                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
4299             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
4301                 // traverse the items again and tweak their sizes so that they are 
4302                 // all the same in a row 
4303                 for ( i 
= 0; i 
< count
; i
++ ) 
4305                     wxListLineData 
*line 
= GetLine(i
); 
4306                     line
->m_gi
->ExtendWidth(widthMax
); 
4314                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4315                 (y 
+ lineHeight
) / lineHeight
, 
4316                 GetScrollPos( wxHORIZONTAL 
), 
4317                 GetScrollPos( wxVERTICAL 
), 
4321         else // "flowed" arrangement, the most complicated case 
4323             // at first we try without any scrollbars, if the items don't fit into 
4324             // the window, we recalculate after subtracting the space taken by the 
4327             int entireWidth 
= 0; 
4329             for (int tries 
= 0; tries 
< 2; tries
++) 
4331                 entireWidth 
= 2 * EXTRA_BORDER_X
; 
4335                     // Now we have decided that the items do not fit into the 
4336                     // client area, so we need a scrollbar 
4337                     entireWidth 
+= SCROLL_UNIT_X
; 
4340                 int x 
= EXTRA_BORDER_X
; 
4341                 int y 
= EXTRA_BORDER_Y
; 
4342                 int maxWidthInThisRow 
= 0; 
4345                 int currentlyVisibleLines 
= 0; 
4347                 for (size_t i 
= 0; i 
< count
; i
++) 
4349                     currentlyVisibleLines
++; 
4350                     wxListLineData 
*line 
= GetLine( i 
); 
4351                     line
->CalculateSize( &dc
, iconSpacing 
); 
4352                     line
->SetPosition( x
, y
, iconSpacing 
); 
4354                     wxSize sizeLine 
= GetLineSize( i 
); 
4356                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
4357                         maxWidthInThisRow 
= sizeLine
.x
; 
4360                     if (currentlyVisibleLines 
> m_linesPerPage
) 
4361                         m_linesPerPage 
= currentlyVisibleLines
; 
4363                     if ( y 
+ sizeLine
.y 
>= clientHeight 
) 
4365                         currentlyVisibleLines 
= 0; 
4367                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
4368                         x 
+= maxWidthInThisRow
; 
4369                         entireWidth 
+= maxWidthInThisRow
; 
4370                         maxWidthInThisRow 
= 0; 
4373                     // We have reached the last item. 
4374                     if ( i 
== count 
- 1 ) 
4375                         entireWidth 
+= maxWidthInThisRow
; 
4377                     if ( (tries 
== 0) && 
4378                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
4380                         clientHeight 
-= wxSystemSettings:: 
4381                                             GetMetric(wxSYS_HSCROLL_Y
); 
4386                     if ( i 
== count 
- 1 ) 
4387                         tries 
= 1;  // Everything fits, no second try required. 
4395                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4397                 GetScrollPos( wxHORIZONTAL 
), 
4406         // FIXME: why should we call it from here? 
4413 void wxListMainWindow::RefreshAll() 
4418     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
4419     if ( headerWin 
&& headerWin
->m_dirty 
) 
4421         headerWin
->m_dirty 
= false; 
4422         headerWin
->Refresh(); 
4426 void wxListMainWindow::UpdateCurrent() 
4428     if ( !HasCurrent() && !IsEmpty() ) 
4432 long wxListMainWindow::GetNextItem( long item
, 
4433                                     int WXUNUSED(geometry
), 
4437          max 
= GetItemCount(); 
4438     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
4439                  _T("invalid listctrl index in GetNextItem()") ); 
4441     // notice that we start with the next item (or the first one if item == -1) 
4442     // and this is intentional to allow writing a simple loop to iterate over 
4443     // all selected items 
4446         // this is not an error because the index was OK initially, 
4447         // just no such item 
4454     size_t count 
= GetItemCount(); 
4455     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
4457         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
4460         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
4467 // ---------------------------------------------------------------------------- 
4469 // ---------------------------------------------------------------------------- 
4471 void wxListMainWindow::DeleteItem( long lindex 
) 
4473     size_t count 
= GetItemCount(); 
4475     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
4476                  _T("invalid item index in DeleteItem") ); 
4478     size_t index 
= (size_t)lindex
; 
4480     // we don't need to adjust the index for the previous items 
4481     if ( HasCurrent() && m_current 
>= index 
) 
4483         // if the current item is being deleted, we want the next one to 
4484         // become selected - unless there is no next one - so don't adjust 
4485         // m_current in this case 
4486         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
4490     if ( InReportView() ) 
4492         //  mark the Column Max Width cache as dirty if the items in the line 
4493         //  we're deleting contain the Max Column Width 
4494         wxListLineData 
* const line 
= GetLine(index
); 
4495         wxListItemDataList::compatibility_iterator n
; 
4496         wxListItemData 
*itemData
; 
4500         for (size_t i 
= 0; i 
< m_columns
.GetCount(); i
++) 
4502             n 
= line
->m_items
.Item( i 
); 
4503             itemData 
= n
->GetData(); 
4504             itemData
->GetItem(item
); 
4506             itemWidth 
= GetItemWidthWithImage(&item
); 
4508             if (itemWidth 
>= m_aColWidths
.Item(i
)->nMaxWidth
) 
4509                 m_aColWidths
.Item(i
)->bNeedsUpdate 
= true; 
4512         ResetVisibleLinesRange(); 
4515     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
, wxDefaultPosition 
); 
4520         m_selStore
.OnItemDelete(index
); 
4524         m_lines
.RemoveAt( index 
); 
4527     // we need to refresh the (vert) scrollbar as the number of items changed 
4530     RefreshAfter(index
); 
4533 void wxListMainWindow::DeleteColumn( int col 
) 
4535     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4537     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
4540     delete node
->GetData(); 
4541     m_columns
.Erase( node 
); 
4545         // update all the items 
4546         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4548             wxListLineData 
* const line 
= GetLine(i
); 
4549             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
4550             delete n
->GetData(); 
4551             line
->m_items
.Erase(n
); 
4555     if ( InReportView() )   //  we only cache max widths when in Report View 
4557         delete m_aColWidths
.Item(col
); 
4558         m_aColWidths
.RemoveAt(col
); 
4561     // invalidate it as it has to be recalculated 
4565 void wxListMainWindow::DoDeleteAllItems() 
4568         // nothing to do - in particular, don't send the event 
4573     // to make the deletion of all items faster, we don't send the 
4574     // notifications for each item deletion in this case but only one event 
4575     // for all of them: this is compatible with wxMSW and documented in 
4576     // DeleteAllItems() description 
4578     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
4579     event
.SetEventObject( GetParent() ); 
4580     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
4588     if ( InReportView() ) 
4590         ResetVisibleLinesRange(); 
4591         for (size_t i 
= 0; i 
< m_aColWidths
.GetCount(); i
++) 
4593             m_aColWidths
.Item(i
)->bNeedsUpdate 
= true; 
4600 void wxListMainWindow::DeleteAllItems() 
4604     RecalculatePositions(); 
4607 void wxListMainWindow::DeleteEverything() 
4609     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
4610     WX_CLEAR_ARRAY(m_aColWidths
); 
4615 // ---------------------------------------------------------------------------- 
4616 // scanning for an item 
4617 // ---------------------------------------------------------------------------- 
4619 void wxListMainWindow::EnsureVisible( long index 
) 
4621     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4622                  _T("invalid index in EnsureVisible") ); 
4624     // We have to call this here because the label in question might just have 
4625     // been added and its position is not known yet 
4627         RecalculatePositions(true /* no refresh */); 
4629     MoveToItem((size_t)index
); 
4632 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool partial 
) 
4638     wxString str_upper 
= str
.Upper(); 
4642     size_t count 
= GetItemCount(); 
4643     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
4645         wxListLineData 
*line 
= GetLine(i
); 
4646         wxString line_upper 
= line
->GetText(0).Upper(); 
4649             if (line_upper 
== str_upper 
) 
4654             if (line_upper
.find(str_upper
) == 0) 
4662 long wxListMainWindow::FindItem(long start
, wxUIntPtr data
) 
4668     size_t count 
= GetItemCount(); 
4669     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4671         wxListLineData 
*line 
= GetLine(i
); 
4673         line
->GetItem( 0, item 
); 
4674         if (item
.m_data 
== data
) 
4681 long wxListMainWindow::FindItem( const wxPoint
& pt 
) 
4684     GetVisibleLinesRange( &topItem
, NULL 
); 
4687     GetItemPosition( GetItemCount() - 1, p 
); 
4691     long id 
= (long)floor( pt
.y 
* double(GetItemCount() - topItem 
- 1) / p
.y 
+ topItem 
); 
4692     if ( id 
>= 0 && id 
< (long)GetItemCount() ) 
4698 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) const 
4700     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4702     size_t count 
= GetItemCount(); 
4704     if ( InReportView() ) 
4706         size_t current 
= y 
/ GetLineHeight(); 
4707         if ( current 
< count 
) 
4709             flags 
= HitTestLine(current
, x
, y
); 
4716         // TODO: optimize it too! this is less simple than for report view but 
4717         //       enumerating all items is still not a way to do it!! 
4718         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4720             flags 
= HitTestLine(current
, x
, y
); 
4729 // ---------------------------------------------------------------------------- 
4731 // ---------------------------------------------------------------------------- 
4733 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4735     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
4737     int count 
= GetItemCount(); 
4738     wxCHECK_RET( item
.m_itemId 
>= 0, _T("invalid item index") ); 
4740     if (item
.m_itemId 
> count
) 
4741         item
.m_itemId 
= count
; 
4743     size_t id 
= item
.m_itemId
; 
4747     if ( InReportView() ) 
4749         ResetVisibleLinesRange(); 
4751         // calculate the width of the item and adjust the max column width 
4752         wxColWidthInfo 
*pWidthInfo 
= m_aColWidths
.Item(item
.GetColumn()); 
4753         int width 
= GetItemWidthWithImage(&item
); 
4754         item
.SetWidth(width
); 
4755         if (width 
> pWidthInfo
->nMaxWidth
) 
4756             pWidthInfo
->nMaxWidth 
= width
; 
4759     wxListLineData 
*line 
= new wxListLineData(this); 
4761     line
->SetItem( item
.m_col
, item 
); 
4763     m_lines
.Insert( line
, id 
); 
4767     // If an item is selected at or below the point of insertion, we need to 
4768     // increment the member variables because the current row's index has gone 
4770     if ( HasCurrent() && m_current 
>= id 
) 
4773     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4775     RefreshLines(id
, GetItemCount() - 1); 
4778 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4781     if ( InReportView() ) 
4783         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4784             item
.m_width 
= GetTextLength( item
.m_text 
); 
4786         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4787         wxColWidthInfo 
*colWidthInfo 
= new wxColWidthInfo(); 
4789         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4792             wxListHeaderDataList::compatibility_iterator
 
4793                 node 
= m_columns
.Item( col 
); 
4794             m_columns
.Insert( node
, column 
); 
4795             m_aColWidths
.Insert( colWidthInfo
, col 
); 
4799             m_columns
.Append( column 
); 
4800             m_aColWidths
.Add( colWidthInfo 
); 
4805             // update all the items 
4806             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4808                 wxListLineData 
* const line 
= GetLine(i
); 
4809                 wxListItemData 
* const data 
= new wxListItemData(this); 
4811                     line
->m_items
.Insert(col
, data
); 
4813                     line
->m_items
.Append(data
); 
4817         // invalidate it as it has to be recalculated 
4822 int wxListMainWindow::GetItemWidthWithImage(wxListItem 
* item
) 
4825     wxClientDC 
dc(this); 
4827     dc
.SetFont( GetFont() ); 
4829     if (item
->GetImage() != -1) 
4832         GetImageSize( item
->GetImage(), ix
, iy 
); 
4836     if (!item
->GetText().empty()) 
4839         dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
4846 // ---------------------------------------------------------------------------- 
4848 // ---------------------------------------------------------------------------- 
4850 wxListCtrlCompare list_ctrl_compare_func_2
; 
4851 long              list_ctrl_compare_data
; 
4853 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4855     wxListLineData 
*line1 
= *arg1
; 
4856     wxListLineData 
*line2 
= *arg2
; 
4858     line1
->GetItem( 0, item 
); 
4859     wxUIntPtr data1 
= item
.m_data
; 
4860     line2
->GetItem( 0, item 
); 
4861     wxUIntPtr data2 
= item
.m_data
; 
4862     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4865 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
4867     // selections won't make sense any more after sorting the items so reset 
4869     HighlightAll(false); 
4872     list_ctrl_compare_func_2 
= fn
; 
4873     list_ctrl_compare_data 
= data
; 
4874     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4878 // ---------------------------------------------------------------------------- 
4880 // ---------------------------------------------------------------------------- 
4882 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4884     HandleOnScroll( event 
); 
4886     // update our idea of which lines are shown when we redraw the window the 
4888     ResetVisibleLinesRange(); 
4890     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4892         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4893         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4895         lc
->m_headerWin
->Refresh(); 
4896         lc
->m_headerWin
->Update(); 
4900 int wxListMainWindow::GetCountPerPage() const 
4902     if ( !m_linesPerPage 
) 
4904         wxConstCast(this, wxListMainWindow
)-> 
4905             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4908     return m_linesPerPage
; 
4911 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4913     wxASSERT_MSG( InReportView(), _T("this is for report mode only") ); 
4915     if ( m_lineFrom 
== (size_t)-1 ) 
4917         size_t count 
= GetItemCount(); 
4920             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4922             // this may happen if SetScrollbars() hadn't been called yet 
4923             if ( m_lineFrom 
>= count 
) 
4924                 m_lineFrom 
= count 
- 1; 
4926             // we redraw one extra line but this is needed to make the redrawing 
4927             // logic work when there is a fractional number of lines on screen 
4928             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4929             if ( m_lineTo 
>= count 
) 
4930                 m_lineTo 
= count 
- 1; 
4932         else // empty control 
4935             m_lineTo 
= (size_t)-1; 
4939     wxASSERT_MSG( IsEmpty() || 
4940                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4941                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4949 // ------------------------------------------------------------------------------------- 
4950 // wxGenericListCtrl 
4951 // ------------------------------------------------------------------------------------- 
4953 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4955 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4956   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4959 wxGenericListCtrl::wxGenericListCtrl() 
4961     m_imageListNormal 
= NULL
; 
4962     m_imageListSmall 
= NULL
; 
4963     m_imageListState 
= NULL
; 
4965     m_ownsImageListNormal 
= 
4966     m_ownsImageListSmall 
= 
4967     m_ownsImageListState 
= false; 
4974 wxGenericListCtrl::~wxGenericListCtrl() 
4976     if (m_ownsImageListNormal
) 
4977         delete m_imageListNormal
; 
4978     if (m_ownsImageListSmall
) 
4979         delete m_imageListSmall
; 
4980     if (m_ownsImageListState
) 
4981         delete m_imageListState
; 
4984 void wxGenericListCtrl::CalculateAndSetHeaderHeight() 
4988 #if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON 
4990         GetThemeMetric( kThemeMetricListHeaderHeight
, &h 
); 
4992         // we use 'g' to get the descent, too 
4994         m_headerWin
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
); 
4995         h 
+= d 
+ 2 * HEADER_OFFSET_Y 
+ EXTRA_HEIGHT
; 
4998         // only update if changed 
4999         if ( h 
!= m_headerHeight 
) 
5004                 ResizeReportView(true); 
5005             else    //why is this needed if it doesn't have a header? 
5006                 m_headerWin
->SetSize(m_headerWin
->GetSize().x
, m_headerHeight
); 
5011 void wxGenericListCtrl::CreateHeaderWindow() 
5013     m_headerWin 
= new wxListHeaderWindow
 
5015                         this, wxID_ANY
, m_mainWin
, 
5017                         wxSize(GetClientSize().x
, m_headerHeight
), 
5020     CalculateAndSetHeaderHeight(); 
5023 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
5028                         const wxValidator 
&validator
, 
5029                         const wxString 
&name
) 
5033     m_imageListState 
= NULL
; 
5034     m_ownsImageListNormal 
= 
5035     m_ownsImageListSmall 
= 
5036     m_ownsImageListState 
= false; 
5043     // just like in other ports, an assert will fail if the user doesn't give any type style: 
5044     wxASSERT_MSG( (style 
& wxLC_MASK_TYPE
), 
5045                   _T("wxListCtrl style should have exactly one mode bit set") ); 
5047     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
5050     // this window itself shouldn't get the focus, only m_mainWin should 
5053     // don't create the inner window with the border 
5054     style 
&= ~wxBORDER_MASK
; 
5056     m_mainWin 
= new wxListMainWindow( this, wxID_ANY
, wxPoint(0, 0), size
, style 
); 
5058 #if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON 
5059     // Human Interface Guidelines ask us for a special font in this case 
5060     if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL 
) 
5063 #if wxOSX_USE_ATSU_TEXT 
5064         font
.MacCreateFromThemeFont( kThemeViewsFont 
); 
5066         font
.MacCreateFromUIFont( kCTFontViewsFontType 
); 
5072     if ( InReportView() ) 
5074         CreateHeaderWindow(); 
5076 #if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON 
5080 #if wxOSX_USE_ATSU_TEXT 
5081             font
.MacCreateFromThemeFont( kThemeSmallSystemFont 
); 
5083         font
.MacCreateFromUIFont( kCTFontSystemFontType 
); 
5085             m_headerWin
->SetFont( font 
); 
5086             CalculateAndSetHeaderHeight(); 
5090         if ( HasFlag(wxLC_NO_HEADER
) ) 
5091             // VZ: why do we create it at all then? 
5092             m_headerWin
->Show( false ); 
5095     SetInitialSize(size
); 
5100 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
5102     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
5103                   _T("wxLC_VIRTUAL can't be [un]set") ); 
5105     long flag 
= GetWindowStyle(); 
5109         if (style 
& wxLC_MASK_TYPE
) 
5110             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
5111         if (style 
& wxLC_MASK_ALIGN
) 
5112             flag 
&= ~wxLC_MASK_ALIGN
; 
5113         if (style 
& wxLC_MASK_SORT
) 
5114             flag 
&= ~wxLC_MASK_SORT
; 
5122     // some styles can be set without recreating everything (as happens in 
5123     // SetWindowStyleFlag() which calls wxListMainWindow::DeleteEverything()) 
5124     if ( !(style 
& ~(wxLC_HRULES 
| wxLC_VRULES
)) ) 
5127         wxWindow::SetWindowStyleFlag(flag
); 
5131         SetWindowStyleFlag( flag 
); 
5135 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
5139         m_mainWin
->DeleteEverything(); 
5141         // has the header visibility changed? 
5142         bool hasHeader 
= HasHeader(); 
5143         bool willHaveHeader 
= (flag 
& wxLC_REPORT
) && !(flag 
& wxLC_NO_HEADER
); 
5145         if ( hasHeader 
!= willHaveHeader 
) 
5152                     // don't delete, just hide, as we can reuse it later 
5153                     m_headerWin
->Show(false); 
5155                 //else: nothing to do 
5157             else // must show header 
5161                     CreateHeaderWindow(); 
5163                 else // already have it, just show 
5165                     m_headerWin
->Show( true ); 
5169             ResizeReportView(willHaveHeader
); 
5173     wxWindow::SetWindowStyleFlag( flag 
); 
5176 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
5178     m_mainWin
->GetColumn( col
, item 
); 
5182 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
5184     m_mainWin
->SetColumn( col
, item 
); 
5188 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
5190     return m_mainWin
->GetColumnWidth( col 
); 
5193 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
5195     m_mainWin
->SetColumnWidth( col
, width 
); 
5199 int wxGenericListCtrl::GetCountPerPage() const 
5201   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
5204 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
5206     m_mainWin
->GetItem( info 
); 
5210 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
5212     m_mainWin
->SetItem( info 
); 
5216 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
5219     info
.m_text 
= label
; 
5220     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5221     info
.m_itemId 
= index
; 
5225         info
.m_image 
= imageId
; 
5226         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
5229     m_mainWin
->SetItem(info
); 
5233 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
5235     return m_mainWin
->GetItemState( item
, stateMask 
); 
5238 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
5240     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
5245 wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
5247     return SetItemColumnImage(item
, 0, image
); 
5251 wxGenericListCtrl::SetItemColumnImage( long item
, long column
, int image 
) 
5254     info
.m_image 
= image
; 
5255     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5256     info
.m_itemId 
= item
; 
5257     info
.m_col 
= column
; 
5258     m_mainWin
->SetItem( info 
); 
5262 wxString 
wxGenericListCtrl::GetItemText( long item 
) const 
5264     return m_mainWin
->GetItemText(item
); 
5267 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
5269     m_mainWin
->SetItemText(item
, str
); 
5272 wxUIntPtr 
wxGenericListCtrl::GetItemData( long item 
) const 
5275     info
.m_mask 
= wxLIST_MASK_DATA
; 
5276     info
.m_itemId 
= item
; 
5277     m_mainWin
->GetItem( info 
); 
5281 bool wxGenericListCtrl::SetItemPtrData( long item
, wxUIntPtr data 
) 
5284     info
.m_mask 
= wxLIST_MASK_DATA
; 
5285     info
.m_itemId 
= item
; 
5287     m_mainWin
->SetItem( info 
); 
5291 wxRect 
wxGenericListCtrl::GetViewRect() const 
5293     return m_mainWin
->GetViewRect(); 
5296 bool wxGenericListCtrl::GetItemRect(long item
, wxRect
& rect
, int code
) const 
5298     return GetSubItemRect(item
, wxLIST_GETSUBITEMRECT_WHOLEITEM
, rect
, code
); 
5301 bool wxGenericListCtrl::GetSubItemRect(long item
, 
5304                                        int WXUNUSED(code
)) const 
5306     if ( !m_mainWin
->GetSubItemRect( item
, subItem
, rect 
) ) 
5309     if ( m_mainWin
->HasHeader() ) 
5310         rect
.y 
+= m_headerHeight 
+ 1; 
5315 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
5317     m_mainWin
->GetItemPosition( item
, pos 
); 
5321 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
5326 int wxGenericListCtrl::GetItemCount() const 
5328     return m_mainWin
->GetItemCount(); 
5331 int wxGenericListCtrl::GetColumnCount() const 
5333     return m_mainWin
->GetColumnCount(); 
5336 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
5338     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
5341 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
5343     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
5345     return wxSize(spacing
, spacing
); 
5348 #if WXWIN_COMPATIBILITY_2_6 
5349 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
5351     return m_mainWin
->GetItemSpacing( isSmall 
); 
5353 #endif // WXWIN_COMPATIBILITY_2_6 
5355 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
5358     info
.m_itemId 
= item
; 
5359     info
.SetTextColour( col 
); 
5360     m_mainWin
->SetItem( info 
); 
5363 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
5366     info
.m_itemId 
= item
; 
5367     m_mainWin
->GetItem( info 
); 
5368     return info
.GetTextColour(); 
5371 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
5374     info
.m_itemId 
= item
; 
5375     info
.SetBackgroundColour( col 
); 
5376     m_mainWin
->SetItem( info 
); 
5379 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
5382     info
.m_itemId 
= item
; 
5383     m_mainWin
->GetItem( info 
); 
5384     return info
.GetBackgroundColour(); 
5387 int wxGenericListCtrl::GetScrollPos( int orient 
) const 
5389     return m_mainWin
->GetScrollPos( orient 
); 
5392 void wxGenericListCtrl::SetScrollPos( int orient
, int pos
, bool refresh 
) 
5394     m_mainWin
->SetScrollPos( orient
, pos
, refresh 
); 
5397 void wxGenericListCtrl::SetItemFont( long item
, const wxFont 
&f 
) 
5400     info
.m_itemId 
= item
; 
5402     m_mainWin
->SetItem( info 
); 
5405 wxFont 
wxGenericListCtrl::GetItemFont( long item 
) const 
5408     info
.m_itemId 
= item
; 
5409     m_mainWin
->GetItem( info 
); 
5410     return info
.GetFont(); 
5413 int wxGenericListCtrl::GetSelectedItemCount() const 
5415     return m_mainWin
->GetSelectedItemCount(); 
5418 wxColour 
wxGenericListCtrl::GetTextColour() const 
5420     return GetForegroundColour(); 
5423 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
5425     SetForegroundColour(col
); 
5428 long wxGenericListCtrl::GetTopItem() const 
5431     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
5435 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
5437     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
5440 wxImageList 
*wxGenericListCtrl::GetImageList(int which
) const 
5442     if (which 
== wxIMAGE_LIST_NORMAL
) 
5443         return m_imageListNormal
; 
5444     else if (which 
== wxIMAGE_LIST_SMALL
) 
5445         return m_imageListSmall
; 
5446     else if (which 
== wxIMAGE_LIST_STATE
) 
5447         return m_imageListState
; 
5452 void wxGenericListCtrl::SetImageList( wxImageList 
*imageList
, int which 
) 
5454     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5456         if (m_ownsImageListNormal
) 
5457             delete m_imageListNormal
; 
5458         m_imageListNormal 
= imageList
; 
5459         m_ownsImageListNormal 
= false; 
5461     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5463         if (m_ownsImageListSmall
) 
5464             delete m_imageListSmall
; 
5465         m_imageListSmall 
= imageList
; 
5466         m_ownsImageListSmall 
= false; 
5468     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5470         if (m_ownsImageListState
) 
5471             delete m_imageListState
; 
5472         m_imageListState 
= imageList
; 
5473         m_ownsImageListState 
= false; 
5476     m_mainWin
->SetImageList( imageList
, which 
); 
5479 void wxGenericListCtrl::AssignImageList(wxImageList 
*imageList
, int which
) 
5481     SetImageList(imageList
, which
); 
5482     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5483         m_ownsImageListNormal 
= true; 
5484     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5485         m_ownsImageListSmall 
= true; 
5486     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5487         m_ownsImageListState 
= true; 
5490 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
5495 bool wxGenericListCtrl::DeleteItem( long item 
) 
5497     m_mainWin
->DeleteItem( item 
); 
5501 bool wxGenericListCtrl::DeleteAllItems() 
5503     m_mainWin
->DeleteAllItems(); 
5507 bool wxGenericListCtrl::DeleteAllColumns() 
5509     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
5510     for ( size_t n 
= 0; n 
< count
; n
++ ) 
5515 void wxGenericListCtrl::ClearAll() 
5517     m_mainWin
->DeleteEverything(); 
5520 bool wxGenericListCtrl::DeleteColumn( int col 
) 
5522     m_mainWin
->DeleteColumn( col 
); 
5524     // if we don't have the header any longer, we need to relayout the window 
5525     if ( !GetColumnCount() ) 
5526         ResizeReportView(false /* no header */); 
5530 wxTextCtrl 
*wxGenericListCtrl::EditLabel(long item
, 
5531                                          wxClassInfo
* textControlClass
) 
5533     return m_mainWin
->EditLabel( item
, textControlClass 
); 
5536 wxTextCtrl 
*wxGenericListCtrl::GetEditControl() const 
5538     return m_mainWin
->GetEditControl(); 
5541 bool wxGenericListCtrl::EnsureVisible( long item 
) 
5543     m_mainWin
->EnsureVisible( item 
); 
5547 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
, bool partial 
) 
5549     return m_mainWin
->FindItem( start
, str
, partial 
); 
5552 long wxGenericListCtrl::FindItem( long start
, wxUIntPtr data 
) 
5554     return m_mainWin
->FindItem( start
, data 
); 
5557 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& pt
, 
5558                            int WXUNUSED(direction
)) 
5560     return m_mainWin
->FindItem( pt 
); 
5563 // TODO: sub item hit testing 
5564 long wxGenericListCtrl::HitTest(const wxPoint
& point
, int& flags
, long *) const 
5566     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
5569 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
5571     m_mainWin
->InsertItem( info 
); 
5572     return info
.m_itemId
; 
5575 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
5578     info
.m_text 
= label
; 
5579     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5580     info
.m_itemId 
= index
; 
5581     return InsertItem( info 
); 
5584 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
5587     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5588     info
.m_image 
= imageIndex
; 
5589     info
.m_itemId 
= index
; 
5590     return InsertItem( info 
); 
5593 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
5596     info
.m_text 
= label
; 
5597     info
.m_image 
= imageIndex
; 
5598     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
5599     info
.m_itemId 
= index
; 
5600     return InsertItem( info 
); 
5603 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
5605     wxCHECK_MSG( m_headerWin
, -1, _T("can't add column in non report mode") ); 
5607     m_mainWin
->InsertColumn( col
, item 
); 
5609     // if we hadn't had a header before but have one now 
5610     // then we need to relayout the window 
5611     if ( GetColumnCount() == 1 && m_mainWin
->HasHeader() ) 
5612         ResizeReportView(true /* have header */); 
5614     m_headerWin
->Refresh(); 
5619 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
5620                                int format
, int width 
) 
5623     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
5624     item
.m_text 
= heading
; 
5627         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
5628         item
.m_width 
= width
; 
5631     item
.m_format 
= format
; 
5633     return InsertColumn( col
, item 
); 
5636 bool wxGenericListCtrl::ScrollList( int dx
, int dy 
) 
5638     return m_mainWin
->ScrollList(dx
, dy
); 
5642 // fn is a function which takes 3 long arguments: item1, item2, data. 
5643 // item1 is the long data associated with a first item (NOT the index). 
5644 // item2 is the long data associated with a second item (NOT the index). 
5645 // data is the same value as passed to SortItems. 
5646 // The return value is a negative number if the first item should precede the second 
5647 // item, a positive number of the second item should precede the first, 
5648 // or zero if the two items are equivalent. 
5649 // data is arbitrary data to be passed to the sort function. 
5651 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
5653     m_mainWin
->SortItems( fn
, data 
); 
5657 // ---------------------------------------------------------------------------- 
5659 // ---------------------------------------------------------------------------- 
5661 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
5666     ResizeReportView(m_mainWin
->HasHeader()); 
5667     m_mainWin
->RecalculatePositions(); 
5670 void wxGenericListCtrl::ResizeReportView(bool showHeader
) 
5673     GetClientSize( &cw
, &ch 
); 
5677         m_headerWin
->SetSize( 0, 0, cw
, m_headerHeight 
); 
5678         if(ch 
> m_headerHeight
) 
5679             m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, 
5680                                    cw
, ch 
- m_headerHeight 
- 1 ); 
5682             m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, 
5685     else // no header window 
5687         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
5691 void wxGenericListCtrl::OnInternalIdle() 
5693     wxWindow::OnInternalIdle(); 
5695     // do it only if needed 
5696     if ( !m_mainWin
->m_dirty 
) 
5699     m_mainWin
->RecalculatePositions(); 
5702 // ---------------------------------------------------------------------------- 
5704 // ---------------------------------------------------------------------------- 
5706 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5710         m_mainWin
->SetBackgroundColour( colour 
); 
5711         m_mainWin
->m_dirty 
= true; 
5717 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5719     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5724         m_mainWin
->SetForegroundColour( colour 
); 
5725         m_mainWin
->m_dirty 
= true; 
5729         m_headerWin
->SetForegroundColour( colour 
); 
5734 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5736     if ( !wxWindow::SetFont( font 
) ) 
5741         m_mainWin
->SetFont( font 
); 
5742         m_mainWin
->m_dirty 
= true; 
5747         m_headerWin
->SetFont( font 
); 
5748         CalculateAndSetHeaderHeight(); 
5758 wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
5761     // Use the same color scheme as wxListBox 
5762     return wxListBox::GetClassDefaultAttributes(variant
); 
5764     wxUnusedVar(variant
); 
5765     wxVisualAttributes attr
; 
5766     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT
); 
5767     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
5768     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
5773 // ---------------------------------------------------------------------------- 
5774 // methods forwarded to m_mainWin 
5775 // ---------------------------------------------------------------------------- 
5777 #if wxUSE_DRAG_AND_DROP 
5779 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5781     m_mainWin
->SetDropTarget( dropTarget 
); 
5784 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5786     return m_mainWin
->GetDropTarget(); 
5791 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5793     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : false; 
5796 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5798     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5801 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5803     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5806 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5809     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5815 void wxGenericListCtrl::DoClientToScreen( int *x
, int *y 
) const 
5817     m_mainWin
->DoClientToScreen(x
, y
); 
5820 void wxGenericListCtrl::DoScreenToClient( int *x
, int *y 
) const 
5822     m_mainWin
->DoScreenToClient(x
, y
); 
5825 void wxGenericListCtrl::SetFocus() 
5827     // The test in window.cpp fails as we are a composite 
5828     // window, so it checks against "this", but not m_mainWin. 
5829     if ( DoFindFocus() != this ) 
5830         m_mainWin
->SetFocus(); 
5833 wxSize 
wxGenericListCtrl::DoGetBestSize() const 
5835     // Something is better than nothing... 
5836     // 100x80 is what the MSW version will get from the default 
5837     // wxControl::DoGetBestSize 
5838     return wxSize(100, 80); 
5841 // ---------------------------------------------------------------------------- 
5842 // virtual list control support 
5843 // ---------------------------------------------------------------------------- 
5845 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5847     // this is a pure virtual function, in fact - which is not really pure 
5848     // because the controls which are not virtual don't need to implement it 
5849     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5851     return wxEmptyString
; 
5854 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5856     wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL
), 
5858                 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden.")); 
5862 int wxGenericListCtrl::OnGetItemColumnImage(long item
, long column
) const 
5865         return OnGetItemImage(item
); 
5871 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5873     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5874                   _T("invalid item index in OnGetItemAttr()") ); 
5876     // no attributes by default 
5880 void wxGenericListCtrl::SetItemCount(long count
) 
5882     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
5884     m_mainWin
->SetItemCount(count
); 
5887 void wxGenericListCtrl::RefreshItem(long item
) 
5889     m_mainWin
->RefreshLine(item
); 
5892 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5894     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5897 // Generic wxListCtrl is more or less a container for two other 
5898 // windows which drawings are done upon. These are namely 
5899 // 'm_headerWin' and 'm_mainWin'. 
5900 // Here we override 'virtual wxWindow::Refresh()' to mimic the 
5901 // behaviour wxListCtrl has under wxMSW. 
5903 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5907         // The easy case, no rectangle specified. 
5909             m_headerWin
->Refresh(eraseBackground
); 
5912             m_mainWin
->Refresh(eraseBackground
); 
5916         // Refresh the header window 
5919             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5920             rectHeader
.Intersect(*rect
); 
5921             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5924                 m_headerWin
->GetPosition(&x
, &y
); 
5925                 rectHeader
.Offset(-x
, -y
); 
5926                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5930         // Refresh the main window 
5933             wxRect rectMain 
= m_mainWin
->GetRect(); 
5934             rectMain
.Intersect(*rect
); 
5935             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5938                 m_mainWin
->GetPosition(&x
, &y
); 
5939                 rectMain
.Offset(-x
, -y
); 
5940                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5946 #endif // wxUSE_LISTCTRL