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(__WXUNIVERSAL__)) && !defined(__WXMAC__) 
  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" 
  57 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
  58 // be removed, as well as the #else case below. 
  59 #define _USE_VISATTR 0 
  62 // ---------------------------------------------------------------------------- 
  64 // ---------------------------------------------------------------------------- 
  66 // // the height of the header window (FIXME: should depend on its font!) 
  67 // static const int HEADER_HEIGHT = 23; 
  69 static const int SCROLL_UNIT_X 
= 15; 
  71 // the spacing between the lines (in report mode) 
  72 static const int LINE_SPACING 
= 0; 
  74 // extra margins around the text label 
  76 static const int EXTRA_WIDTH 
= 6; 
  78 static const int EXTRA_WIDTH 
= 4; 
  80 static const int EXTRA_HEIGHT 
= 4; 
  82 // margin between the window and the items 
  83 static const int EXTRA_BORDER_X 
= 2; 
  84 static const int EXTRA_BORDER_Y 
= 2; 
  86 // offset for the header window 
  87 static const int HEADER_OFFSET_X 
= 0; 
  88 static const int HEADER_OFFSET_Y 
= 0; 
  90 // margin between rows of icons in [small] icon view 
  91 static const int MARGIN_BETWEEN_ROWS 
= 6; 
  93 // when autosizing the columns, add some slack 
  94 static const int AUTOSIZE_COL_MARGIN 
= 10; 
  96 // default width for the header columns 
  97 static const int WIDTH_COL_DEFAULT 
= 80; 
  99 // the space between the image and the text in the report mode 
 100 static const int IMAGE_MARGIN_IN_REPORT_MODE 
= 5; 
 102 // the space between the image and the text in the report mode in header 
 103 static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE 
= 2; 
 105 // ============================================================================ 
 107 // ============================================================================ 
 109 //----------------------------------------------------------------------------- 
 110 //  wxColWidthInfo (internal) 
 111 //----------------------------------------------------------------------------- 
 113 struct wxColWidthInfo
 
 116     bool    bNeedsUpdate
;   //  only set to true when an item whose 
 117                             //  width == nMaxWidth is removed 
 119     wxColWidthInfo(int w 
= 0, bool needsUpdate 
= false) 
 122         bNeedsUpdate 
= needsUpdate
; 
 126 WX_DEFINE_ARRAY_PTR(wxColWidthInfo 
*, ColWidthArray
); 
 128 //----------------------------------------------------------------------------- 
 129 //  wxListItemData (internal) 
 130 //----------------------------------------------------------------------------- 
 135     wxListItemData(wxListMainWindow 
*owner
); 
 138     void SetItem( const wxListItem 
&info 
); 
 139     void SetImage( int image 
) { m_image 
= image
; } 
 140     void SetData( wxUIntPtr data 
) { m_data 
= data
; } 
 141     void SetPosition( int x
, int y 
); 
 142     void SetSize( int width
, int height 
); 
 144     bool HasText() const { return !m_text
.empty(); } 
 145     const wxString
& GetText() const { return m_text
; } 
 146     void SetText(const wxString
& text
) { m_text 
= text
; } 
 148     // we can't use empty string for measuring the string width/height, so 
 149     // always return something 
 150     wxString 
GetTextForMeasuring() const 
 152         wxString s 
= GetText(); 
 159     bool IsHit( int x
, int y 
) const; 
 163     int GetWidth() const; 
 164     int GetHeight() const; 
 166     int GetImage() const { return m_image
; } 
 167     bool HasImage() const { return GetImage() != -1; } 
 169     void GetItem( wxListItem 
&info 
) const; 
 171     void SetAttr(wxListItemAttr 
*attr
) { m_attr 
= attr
; } 
 172     wxListItemAttr 
*GetAttr() const { return m_attr
; } 
 175     // the item image or -1 
 178     // user data associated with the item 
 181     // the item coordinates are not used in report mode; instead this pointer is 
 182     // NULL and the owner window is used to retrieve the item position and size 
 185     // the list ctrl we are in 
 186     wxListMainWindow 
*m_owner
; 
 188     // custom attributes or NULL 
 189     wxListItemAttr 
*m_attr
; 
 192     // common part of all ctors 
 198 //----------------------------------------------------------------------------- 
 199 //  wxListHeaderData (internal) 
 200 //----------------------------------------------------------------------------- 
 202 class wxListHeaderData 
: public wxObject
 
 206     wxListHeaderData( const wxListItem 
&info 
); 
 207     void SetItem( const wxListItem 
&item 
); 
 208     void SetPosition( int x
, int y 
); 
 209     void SetWidth( int w 
); 
 210     void SetState( int state 
); 
 211     void SetFormat( int format 
); 
 212     void SetHeight( int h 
); 
 213     bool HasImage() const; 
 215     bool HasText() const { return !m_text
.empty(); } 
 216     const wxString
& GetText() const { return m_text
; } 
 217     void SetText(const wxString
& text
) { m_text 
= text
; } 
 219     void GetItem( wxListItem 
&item 
); 
 221     bool IsHit( int x
, int y 
) const; 
 222     int GetImage() const; 
 223     int GetWidth() const; 
 224     int GetFormat() const; 
 225     int GetState() const; 
 242 //----------------------------------------------------------------------------- 
 243 //  wxListLineData (internal) 
 244 //----------------------------------------------------------------------------- 
 246 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
); 
 247 #include "wx/listimpl.cpp" 
 248 WX_DEFINE_LIST(wxListItemDataList
) 
 253     // the list of subitems: only may have more than one item in report mode 
 254     wxListItemDataList m_items
; 
 256     // this is not used in report view 
 268         // the part to be highlighted 
 269         wxRect m_rectHighlight
; 
 271         // extend all our rects to be centered inside the one of given width 
 272         void ExtendWidth(wxCoord w
) 
 274             wxASSERT_MSG( m_rectAll
.width 
<= w
, 
 275                             _T("width can only be increased") ); 
 278             m_rectLabel
.x 
= m_rectAll
.x 
+ (w 
- m_rectLabel
.width
) / 2; 
 279             m_rectIcon
.x 
= m_rectAll
.x 
+ (w 
- m_rectIcon
.width
) / 2; 
 280             m_rectHighlight
.x 
= m_rectAll
.x 
+ (w 
- m_rectHighlight
.width
) / 2; 
 285     // is this item selected? [NB: not used in virtual mode] 
 288     // back pointer to the list ctrl 
 289     wxListMainWindow 
*m_owner
; 
 292     wxListLineData(wxListMainWindow 
*owner
); 
 296         WX_CLEAR_LIST(wxListItemDataList
, m_items
); 
 300     // are we in report mode? 
 301     inline bool InReportView() const; 
 303     // are we in virtual report mode? 
 304     inline bool IsVirtual() const; 
 306     // these 2 methods shouldn't be called for report view controls, in that 
 307     // case we determine our position/size ourselves 
 309     // calculate the size of the line 
 310     void CalculateSize( wxDC 
*dc
, int spacing 
); 
 312     // remember the position this line appears at 
 313     void SetPosition( int x
, int y
, int spacing 
); 
 317     void SetImage( int image 
) { SetImage(0, image
); } 
 318     int GetImage() const { return GetImage(0); } 
 319     void SetImage( int index
, int image 
); 
 320     int GetImage( int index 
) const; 
 322     bool HasImage() const { return GetImage() != -1; } 
 323     bool HasText() const { return !GetText(0).empty(); } 
 325     void SetItem( int index
, const wxListItem 
&info 
); 
 326     void GetItem( int index
, wxListItem 
&info 
); 
 328     wxString 
GetText(int index
) const; 
 329     void SetText( int index
, const wxString
& s 
); 
 331     wxListItemAttr 
*GetAttr() const; 
 332     void SetAttr(wxListItemAttr 
*attr
); 
 334     // return true if the highlighting really changed 
 335     bool Highlight( bool on 
); 
 337     void ReverseHighlight(); 
 339     bool IsHighlighted() const 
 341         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); 
 343         return m_highlighted
; 
 346     // draw the line on the given DC in icon/list mode 
 347     void Draw( wxDC 
*dc 
); 
 349     // the same in report mode 
 350     void DrawInReportMode( wxDC 
*dc
, 
 352                            const wxRect
& rectHL
, 
 356     // set the line to contain num items (only can be > 1 in report mode) 
 357     void InitItems( int num 
); 
 359     // get the mode (i.e. style)  of the list control 
 360     inline int GetMode() const; 
 362     // prepare the DC for drawing with these item's attributes, return true if 
 363     // we need to draw the items background to highlight it, false otherwise 
 364     bool SetAttributes(wxDC 
*dc
, 
 365                        const wxListItemAttr 
*attr
, 
 368     // draw the text on the DC with the correct justification; also add an 
 369     // ellipsis if the text is too large to fit in the current width 
 370     void DrawTextFormatted(wxDC 
*dc
, 
 371                            const wxString 
&text
, 
 374                            int yMid
,    // this is middle, not top, of the text 
 378 WX_DECLARE_OBJARRAY(wxListLineData
, wxListLineDataArray
); 
 379 #include "wx/arrimpl.cpp" 
 380 WX_DEFINE_OBJARRAY(wxListLineDataArray
) 
 382 //----------------------------------------------------------------------------- 
 383 //  wxListHeaderWindow (internal) 
 384 //----------------------------------------------------------------------------- 
 386 class wxListHeaderWindow 
: public wxWindow
 
 389     wxListMainWindow  
*m_owner
; 
 390     const wxCursor    
*m_currentCursor
; 
 391     wxCursor          
*m_resizeCursor
; 
 394     // column being resized or -1 
 397     // divider line position in logical (unscrolled) coords 
 400     // minimal position beyond which the divider line 
 401     // can't be dragged in logical coords 
 405     wxListHeaderWindow(); 
 407     wxListHeaderWindow( wxWindow 
*win
, 
 409                         wxListMainWindow 
*owner
, 
 410                         const wxPoint 
&pos 
= wxDefaultPosition
, 
 411                         const wxSize 
&size 
= wxDefaultSize
, 
 413                         const wxString 
&name 
= wxT("wxlistctrlcolumntitles") ); 
 415     virtual ~wxListHeaderWindow(); 
 418     void AdjustDC( wxDC
& dc 
); 
 420     void OnPaint( wxPaintEvent 
&event 
); 
 421     void OnMouse( wxMouseEvent 
&event 
); 
 422     void OnSetFocus( wxFocusEvent 
&event 
); 
 428     // common part of all ctors 
 431     // generate and process the list event of the given type, return true if 
 432     // it wasn't vetoed, i.e. if we should proceed 
 433     bool SendListEvent(wxEventType type
, const wxPoint
& pos
); 
 435     DECLARE_EVENT_TABLE() 
 438 //----------------------------------------------------------------------------- 
 439 // wxListRenameTimer (internal) 
 440 //----------------------------------------------------------------------------- 
 442 class wxListRenameTimer
: public wxTimer
 
 445     wxListMainWindow 
*m_owner
; 
 448     wxListRenameTimer( wxListMainWindow 
*owner 
); 
 452 //----------------------------------------------------------------------------- 
 453 // wxListTextCtrlWrapper: wraps a wxTextCtrl to make it work for inline editing 
 454 //----------------------------------------------------------------------------- 
 456 class wxListTextCtrlWrapper 
: public wxEvtHandler
 
 459     // NB: text must be a valid object but not Create()d yet 
 460     wxListTextCtrlWrapper(wxListMainWindow 
*owner
, 
 464     wxTextCtrl 
*GetText() const { return m_text
; } 
 466     void EndEdit( bool discardChanges 
); 
 469     void OnChar( wxKeyEvent 
&event 
); 
 470     void OnKeyUp( wxKeyEvent 
&event 
); 
 471     void OnKillFocus( wxFocusEvent 
&event 
); 
 473     bool AcceptChanges(); 
 474     void Finish( bool setfocus 
); 
 477     wxListMainWindow   
*m_owner
; 
 479     wxString            m_startValue
; 
 481     bool                m_aboutToFinish
; 
 483     DECLARE_EVENT_TABLE() 
 486 //----------------------------------------------------------------------------- 
 487 //  wxListMainWindow (internal) 
 488 //----------------------------------------------------------------------------- 
 490 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
); 
 491 #include "wx/listimpl.cpp" 
 492 WX_DEFINE_LIST(wxListHeaderDataList
) 
 494 class wxListMainWindow 
: public wxScrolledCanvas
 
 498     wxListMainWindow( wxWindow 
*parent
, 
 500                       const wxPoint
& pos 
= wxDefaultPosition
, 
 501                       const wxSize
& size 
= wxDefaultSize
, 
 503                       const wxString 
&name 
= _T("listctrlmainwindow") ); 
 505     virtual ~wxListMainWindow(); 
 507     bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); } 
 509     // return true if this is a virtual list control 
 510     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); } 
 512     // return true if the control is in report mode 
 513     bool InReportView() const { return HasFlag(wxLC_REPORT
); } 
 515     // return true if we are in single selection mode, false if multi sel 
 516     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); } 
 518     // do we have a header window? 
 519     bool HasHeader() const 
 520         { return InReportView() && !HasFlag(wxLC_NO_HEADER
); } 
 522     void HighlightAll( bool on 
); 
 524     // all these functions only do something if the line is currently visible 
 526     // change the line "selected" state, return true if it really changed 
 527     bool HighlightLine( size_t line
, bool highlight 
= true); 
 529     // as HighlightLine() but do it for the range of lines: this is incredibly 
 530     // more efficient for virtual list controls! 
 532     // NB: unlike HighlightLine() this one does refresh the lines on screen 
 533     void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on 
= true ); 
 535     // toggle the line state and refresh it 
 536     void ReverseHighlight( size_t line 
) 
 537         { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); } 
 539     // return true if the line is highlighted 
 540     bool IsHighlighted(size_t line
) const; 
 542     // refresh one or several lines at once 
 543     void RefreshLine( size_t line 
); 
 544     void RefreshLines( size_t lineFrom
, size_t lineTo 
); 
 546     // refresh all selected items 
 547     void RefreshSelected(); 
 549     // refresh all lines below the given one: the difference with 
 550     // RefreshLines() is that the index here might not be a valid one (happens 
 551     // when the last line is deleted) 
 552     void RefreshAfter( size_t lineFrom 
); 
 554     // the methods which are forwarded to wxListLineData itself in list/icon 
 555     // modes but are here because the lines don't store their positions in the 
 558     // get the bound rect for the entire line 
 559     wxRect 
GetLineRect(size_t line
) const; 
 561     // get the bound rect of the label 
 562     wxRect 
GetLineLabelRect(size_t line
) const; 
 564     // get the bound rect of the items icon (only may be called if we do have 
 566     wxRect 
GetLineIconRect(size_t line
) const; 
 568     // get the rect to be highlighted when the item has focus 
 569     wxRect 
GetLineHighlightRect(size_t line
) const; 
 571     // get the size of the total line rect 
 572     wxSize 
GetLineSize(size_t line
) const 
 573         { return GetLineRect(line
).GetSize(); } 
 575     // return the hit code for the corresponding position (in this line) 
 576     long HitTestLine(size_t line
, int x
, int y
) const; 
 578     // bring the selected item into view, scrolling to it if necessary 
 579     void MoveToItem(size_t item
); 
 581     bool ScrollList( int WXUNUSED(dx
), int dy 
); 
 583     // bring the current item into view 
 584     void MoveToFocus() { MoveToItem(m_current
); } 
 586     // start editing the label of the given item 
 587     wxTextCtrl 
*EditLabel(long item
, 
 588                           wxClassInfo
* textControlClass 
= CLASSINFO(wxTextCtrl
)); 
 589     wxTextCtrl 
*GetEditControl() const 
 591         return m_textctrlWrapper 
? m_textctrlWrapper
->GetText() : NULL
; 
 594     void ResetTextControl(wxTextCtrl 
*text
) 
 597         m_textctrlWrapper 
= NULL
; 
 600     void OnRenameTimer(); 
 601     bool OnRenameAccept(size_t itemEdit
, const wxString
& value
); 
 602     void OnRenameCancelled(size_t itemEdit
); 
 604     void OnMouse( wxMouseEvent 
&event 
); 
 606     // called to switch the selection from the current item to newCurrent, 
 607     void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event 
); 
 609     void OnChar( wxKeyEvent 
&event 
); 
 610     void OnKeyDown( wxKeyEvent 
&event 
); 
 611     void OnKeyUp( wxKeyEvent 
&event 
); 
 612     void OnSetFocus( wxFocusEvent 
&event 
); 
 613     void OnKillFocus( wxFocusEvent 
&event 
); 
 614     void OnScroll( wxScrollWinEvent
& event 
); 
 616     void OnPaint( wxPaintEvent 
&event 
); 
 618     void DrawImage( int index
, wxDC 
*dc
, int x
, int y 
); 
 619     void GetImageSize( int index
, int &width
, int &height 
) const; 
 620     int GetTextLength( const wxString 
&s 
) const; 
 622     void SetImageList( wxImageList 
*imageList
, int which 
); 
 623     void SetItemSpacing( int spacing
, bool isSmall 
= false ); 
 624     int GetItemSpacing( bool isSmall 
= false ); 
 626     void SetColumn( int col
, wxListItem 
&item 
); 
 627     void SetColumnWidth( int col
, int width 
); 
 628     void GetColumn( int col
, wxListItem 
&item 
) const; 
 629     int GetColumnWidth( int col 
) const; 
 630     int GetColumnCount() const { return m_columns
.GetCount(); } 
 632     // returns the sum of the heights of all columns 
 633     int GetHeaderWidth() const; 
 635     int GetCountPerPage() const; 
 637     void SetItem( wxListItem 
&item 
); 
 638     void GetItem( wxListItem 
&item 
) const; 
 639     void SetItemState( long item
, long state
, long stateMask 
); 
 640     void SetItemStateAll( long state
, long stateMask 
); 
 641     int GetItemState( long item
, long stateMask 
) const; 
 642     void GetItemRect( long index
, wxRect 
&rect 
) const; 
 643     wxRect 
GetViewRect() const; 
 644     bool GetItemPosition( long item
, wxPoint
& pos 
) const; 
 645     int GetSelectedItemCount() const; 
 647     wxString 
GetItemText(long item
) const 
 650         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 651         info
.m_itemId 
= item
; 
 656     void SetItemText(long item
, const wxString
& value
) 
 659         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 660         info
.m_itemId 
= item
; 
 665     // set the scrollbars and update the positions of the items 
 666     void RecalculatePositions(bool noRefresh 
= false); 
 668     // refresh the window and the header 
 671     long GetNextItem( long item
, int geometry
, int state 
) const; 
 672     void DeleteItem( long index 
); 
 673     void DeleteAllItems(); 
 674     void DeleteColumn( int col 
); 
 675     void DeleteEverything(); 
 676     void EnsureVisible( long index 
); 
 677     long FindItem( long start
, const wxString
& str
, bool partial 
= false ); 
 678     long FindItem( long start
, wxUIntPtr data
); 
 679     long FindItem( const wxPoint
& pt 
); 
 680     long HitTest( int x
, int y
, int &flags 
) const; 
 681     void InsertItem( wxListItem 
&item 
); 
 682     void InsertColumn( long col
, wxListItem 
&item 
); 
 683     int GetItemWidthWithImage(wxListItem 
* item
); 
 684     void SortItems( wxListCtrlCompare fn
, long data 
); 
 686     size_t GetItemCount() const; 
 687     bool IsEmpty() const { return GetItemCount() == 0; } 
 688     void SetItemCount(long count
); 
 690     // change the current (== focused) item, send a notification event 
 691     void ChangeCurrent(size_t current
); 
 692     void ResetCurrent() { ChangeCurrent((size_t)-1); } 
 693     bool HasCurrent() const { return m_current 
!= (size_t)-1; } 
 695     // send out a wxListEvent 
 696     void SendNotify( size_t line
, 
 698                      const wxPoint
& point 
= wxDefaultPosition 
); 
 700     // override base class virtual to reset m_lineHeight when the font changes 
 701     virtual bool SetFont(const wxFont
& font
) 
 703         if ( !wxScrolledCanvas::SetFont(font
) ) 
 711     // these are for wxListLineData usage only 
 713     // get the backpointer to the list ctrl 
 714     wxGenericListCtrl 
*GetListCtrl() const 
 716         return wxStaticCast(GetParent(), wxGenericListCtrl
); 
 719     // get the height of all lines (assuming they all do have the same height) 
 720     wxCoord 
GetLineHeight() const; 
 722     // get the y position of the given line (only for report view) 
 723     wxCoord 
GetLineY(size_t line
) const; 
 725     // get the brush to use for the item highlighting 
 726     wxBrush 
*GetHighlightBrush() const 
 728         return m_hasFocus 
? m_highlightBrush 
: m_highlightUnfocusedBrush
; 
 731     bool HasFocus() const 
 737     // the array of all line objects for a non virtual list control (for the 
 738     // virtual list control we only ever use m_lines[0]) 
 739     wxListLineDataArray  m_lines
; 
 741     // the list of column objects 
 742     wxListHeaderDataList m_columns
; 
 744     // currently focused item or -1 
 747     // the number of lines per page 
 750     // this flag is set when something which should result in the window 
 751     // redrawing happens (i.e. an item was added or deleted, or its appearance 
 752     // changed) and OnPaint() doesn't redraw the window while it is set which 
 753     // allows to minimize the number of repaintings when a lot of items are 
 754     // being added. The real repainting occurs only after the next OnIdle() 
 758     wxColour            
*m_highlightColour
; 
 759     wxImageList         
*m_small_image_list
; 
 760     wxImageList         
*m_normal_image_list
; 
 762     int                  m_normal_spacing
; 
 766     wxTimer             
*m_renameTimer
; 
 770     ColWidthArray        m_aColWidths
; 
 772     // for double click logic 
 773     size_t m_lineLastClicked
, 
 774            m_lineBeforeLastClicked
, 
 775            m_lineSelectSingleOnUp
; 
 778     wxWindow 
*GetMainWindowOfCompositeControl() { return GetParent(); } 
 780     // the total count of items in a virtual list control 
 783     // the object maintaining the items selection state, only used in virtual 
 785     wxSelectionStore m_selStore
; 
 787     // common part of all ctors 
 790     // get the line data for the given index 
 791     wxListLineData 
*GetLine(size_t n
) const 
 793         wxASSERT_MSG( n 
!= (size_t)-1, _T("invalid line index") ); 
 797             wxConstCast(this, wxListMainWindow
)->CacheLineData(n
); 
 804     // get a dummy line which can be used for geometry calculations and such: 
 805     // you must use GetLine() if you want to really draw the line 
 806     wxListLineData 
*GetDummyLine() const; 
 808     // cache the line data of the n-th line in m_lines[0] 
 809     void CacheLineData(size_t line
); 
 811     // get the range of visible lines 
 812     void GetVisibleLinesRange(size_t *from
, size_t *to
); 
 814     // force us to recalculate the range of visible lines 
 815     void ResetVisibleLinesRange() { m_lineFrom 
= (size_t)-1; } 
 817     // get the colour to be used for drawing the rules 
 818     wxColour 
GetRuleColour() const 
 820         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 824     // initialize the current item if needed 
 825     void UpdateCurrent(); 
 827     // delete all items but don't refresh: called from dtor 
 828     void DoDeleteAllItems(); 
 830     // the height of one line using the current font 
 831     wxCoord m_lineHeight
; 
 833     // the total header width or 0 if not calculated yet 
 834     wxCoord m_headerWidth
; 
 836     // the first and last lines being shown on screen right now (inclusive), 
 837     // both may be -1 if they must be calculated so never access them directly: 
 838     // use GetVisibleLinesRange() above instead 
 842     // the brushes to use for item highlighting when we do/don't have focus 
 843     wxBrush 
*m_highlightBrush
, 
 844             *m_highlightUnfocusedBrush
; 
 846     // wrapper around the text control currently used for in place editing or 
 847     // NULL if no item is being edited 
 848     wxListTextCtrlWrapper 
*m_textctrlWrapper
; 
 851     DECLARE_EVENT_TABLE() 
 853     friend class wxGenericListCtrl
; 
 857 wxListItemData::~wxListItemData() 
 859     // in the virtual list control the attributes are managed by the main 
 860     // program, so don't delete them 
 861     if ( !m_owner
->IsVirtual() ) 
 867 void wxListItemData::Init() 
 875 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
 881     if ( owner
->InReportView() ) 
 887 void wxListItemData::SetItem( const wxListItem 
&info 
) 
 889     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
 890         SetText(info
.m_text
); 
 891     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 892         m_image 
= info
.m_image
; 
 893     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
 894         m_data 
= info
.m_data
; 
 896     if ( info
.HasAttributes() ) 
 899             m_attr
->AssignFrom(*info
.GetAttributes()); 
 901             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
 909         m_rect
->width 
= info
.m_width
; 
 913 void wxListItemData::SetPosition( int x
, int y 
) 
 915     wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") ); 
 921 void wxListItemData::SetSize( int width
, int height 
) 
 923     wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") ); 
 926         m_rect
->width 
= width
; 
 928         m_rect
->height 
= height
; 
 931 bool wxListItemData::IsHit( int x
, int y 
) const 
 933     wxCHECK_MSG( m_rect
, false, _T("can't be called in this mode") ); 
 935     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Contains(x
, y
); 
 938 int wxListItemData::GetX() const 
 940     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 945 int wxListItemData::GetY() const 
 947     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 952 int wxListItemData::GetWidth() const 
 954     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 956     return m_rect
->width
; 
 959 int wxListItemData::GetHeight() const 
 961     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 963     return m_rect
->height
; 
 966 void wxListItemData::GetItem( wxListItem 
&info 
) const 
 968     long mask 
= info
.m_mask
; 
 970         // by default, get everything for backwards compatibility 
 973     if ( mask 
& wxLIST_MASK_TEXT 
) 
 974         info
.m_text 
= m_text
; 
 975     if ( mask 
& wxLIST_MASK_IMAGE 
) 
 976         info
.m_image 
= m_image
; 
 977     if ( mask 
& wxLIST_MASK_DATA 
) 
 978         info
.m_data 
= m_data
; 
 982         if ( m_attr
->HasTextColour() ) 
 983             info
.SetTextColour(m_attr
->GetTextColour()); 
 984         if ( m_attr
->HasBackgroundColour() ) 
 985             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
 986         if ( m_attr
->HasFont() ) 
 987             info
.SetFont(m_attr
->GetFont()); 
 991 //----------------------------------------------------------------------------- 
 993 //----------------------------------------------------------------------------- 
 995 void wxListHeaderData::Init() 
1007 wxListHeaderData::wxListHeaderData() 
1012 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
1019 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
1021     m_mask 
= item
.m_mask
; 
1023     if ( m_mask 
& wxLIST_MASK_TEXT 
) 
1024         m_text 
= item
.m_text
; 
1026     if ( m_mask 
& wxLIST_MASK_IMAGE 
) 
1027         m_image 
= item
.m_image
; 
1029     if ( m_mask 
& wxLIST_MASK_FORMAT 
) 
1030         m_format 
= item
.m_format
; 
1032     if ( m_mask 
& wxLIST_MASK_WIDTH 
) 
1033         SetWidth(item
.m_width
); 
1035     if ( m_mask 
& wxLIST_MASK_STATE 
) 
1036         SetState(item
.m_state
); 
1039 void wxListHeaderData::SetPosition( int x
, int y 
) 
1045 void wxListHeaderData::SetHeight( int h 
) 
1050 void wxListHeaderData::SetWidth( int w 
) 
1052     m_width 
= w 
< 0 ? WIDTH_COL_DEFAULT 
: w
; 
1055 void wxListHeaderData::SetState( int flag 
) 
1060 void wxListHeaderData::SetFormat( int format 
) 
1065 bool wxListHeaderData::HasImage() const 
1067     return m_image 
!= -1; 
1070 bool wxListHeaderData::IsHit( int x
, int y 
) const 
1072     return ((x 
>= m_xpos
) && (x 
<= m_xpos
+m_width
) && (y 
>= m_ypos
) && (y 
<= m_ypos
+m_height
)); 
1075 void wxListHeaderData::GetItem( wxListItem
& item 
) 
1077     item
.m_mask 
= m_mask
; 
1078     item
.m_text 
= m_text
; 
1079     item
.m_image 
= m_image
; 
1080     item
.m_format 
= m_format
; 
1081     item
.m_width 
= m_width
; 
1082     item
.m_state 
= m_state
; 
1085 int wxListHeaderData::GetImage() const 
1090 int wxListHeaderData::GetWidth() const 
1095 int wxListHeaderData::GetFormat() const 
1100 int wxListHeaderData::GetState() const 
1105 //----------------------------------------------------------------------------- 
1107 //----------------------------------------------------------------------------- 
1109 inline int wxListLineData::GetMode() const 
1111     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
1114 inline bool wxListLineData::InReportView() const 
1116     return m_owner
->HasFlag(wxLC_REPORT
); 
1119 inline bool wxListLineData::IsVirtual() const 
1121     return m_owner
->IsVirtual(); 
1124 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
1128     if ( InReportView() ) 
1131         m_gi 
= new GeometryInfo
; 
1133     m_highlighted 
= false; 
1135     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
1138 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
1140     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1141     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1143     wxListItemData 
*item 
= node
->GetData(); 
1148     switch ( GetMode() ) 
1151         case wxLC_SMALL_ICON
: 
1152             m_gi
->m_rectAll
.width 
= spacing
; 
1154             s 
= item
->GetText(); 
1159                 m_gi
->m_rectLabel
.width 
= 
1160                 m_gi
->m_rectLabel
.height 
= 0; 
1164                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
1168                 m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
1170                     m_gi
->m_rectAll
.width 
= lw
; 
1172                 m_gi
->m_rectLabel
.width 
= lw
; 
1173                 m_gi
->m_rectLabel
.height 
= lh
; 
1176             if (item
->HasImage()) 
1179                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1180                 m_gi
->m_rectIcon
.width 
= w 
+ 8; 
1181                 m_gi
->m_rectIcon
.height 
= h 
+ 8; 
1183                 if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
1184                     m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
1185                 if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
1186                     m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
1189             if ( item
->HasText() ) 
1191                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
1192                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
1194             else // no text, highlight the icon 
1196                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
1197                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
1202             s 
= item
->GetTextForMeasuring(); 
1204             dc
->GetTextExtent( s
, &lw
, &lh 
); 
1208             m_gi
->m_rectLabel
.width 
= lw
; 
1209             m_gi
->m_rectLabel
.height 
= lh
; 
1211             m_gi
->m_rectAll
.width 
= lw
; 
1212             m_gi
->m_rectAll
.height 
= lh
; 
1214             if (item
->HasImage()) 
1217                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1218                 m_gi
->m_rectIcon
.width 
= w
; 
1219                 m_gi
->m_rectIcon
.height 
= h
; 
1221                 m_gi
->m_rectAll
.width 
+= 4 + w
; 
1222                 if (h 
> m_gi
->m_rectAll
.height
) 
1223                     m_gi
->m_rectAll
.height 
= h
; 
1226             m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
1227             m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
1231             wxFAIL_MSG( _T("unexpected call to SetSize") ); 
1235             wxFAIL_MSG( _T("unknown mode") ); 
1240 void wxListLineData::SetPosition( int x
, int y
, int spacing 
) 
1242     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1243     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1245     wxListItemData 
*item 
= node
->GetData(); 
1247     switch ( GetMode() ) 
1250         case wxLC_SMALL_ICON
: 
1251             m_gi
->m_rectAll
.x 
= x
; 
1252             m_gi
->m_rectAll
.y 
= y
; 
1254             if ( item
->HasImage() ) 
1256                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 + 
1257                     (m_gi
->m_rectAll
.width 
- m_gi
->m_rectIcon
.width
) / 2; 
1258                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
1261             if ( item
->HasText() ) 
1263                 if (m_gi
->m_rectAll
.width 
> spacing
) 
1264                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2); 
1266                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2) + (spacing 
/ 2) - (m_gi
->m_rectLabel
.width 
/ 2); 
1267                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
1268                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
1269                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
1271             else // no text, highlight the icon 
1273                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
1274                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
1279             m_gi
->m_rectAll
.x 
= x
; 
1280             m_gi
->m_rectAll
.y 
= y
; 
1282             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
1283             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
1284             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1286             if (item
->HasImage()) 
1288                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1289                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1290                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 4 + (EXTRA_WIDTH
/2) + m_gi
->m_rectIcon
.width
; 
1294                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2); 
1299             wxFAIL_MSG( _T("unexpected call to SetPosition") ); 
1303             wxFAIL_MSG( _T("unknown mode") ); 
1308 void wxListLineData::InitItems( int num 
) 
1310     for (int i 
= 0; i 
< num
; i
++) 
1311         m_items
.Append( new wxListItemData(m_owner
) ); 
1314 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
1316     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1317     wxCHECK_RET( node
, _T("invalid column index in SetItem") ); 
1319     wxListItemData 
*item 
= node
->GetData(); 
1320     item
->SetItem( info 
); 
1323 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
1325     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1328         wxListItemData 
*item 
= node
->GetData(); 
1329         item
->GetItem( info 
); 
1333 wxString 
wxListLineData::GetText(int index
) const 
1337     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1340         wxListItemData 
*item 
= node
->GetData(); 
1341         s 
= item
->GetText(); 
1347 void wxListLineData::SetText( int index
, const wxString
& s 
) 
1349     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1352         wxListItemData 
*item 
= node
->GetData(); 
1357 void wxListLineData::SetImage( int index
, int image 
) 
1359     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1360     wxCHECK_RET( node
, _T("invalid column index in SetImage()") ); 
1362     wxListItemData 
*item 
= node
->GetData(); 
1363     item
->SetImage(image
); 
1366 int wxListLineData::GetImage( int index 
) const 
1368     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1369     wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") ); 
1371     wxListItemData 
*item 
= node
->GetData(); 
1372     return item
->GetImage(); 
1375 wxListItemAttr 
*wxListLineData::GetAttr() const 
1377     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1378     wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") ); 
1380     wxListItemData 
*item 
= node
->GetData(); 
1381     return item
->GetAttr(); 
1384 void wxListLineData::SetAttr(wxListItemAttr 
*attr
) 
1386     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1387     wxCHECK_RET( node
, _T("invalid column index in SetAttr()") ); 
1389     wxListItemData 
*item 
= node
->GetData(); 
1390     item
->SetAttr(attr
); 
1393 bool wxListLineData::SetAttributes(wxDC 
*dc
, 
1394                                    const wxListItemAttr 
*attr
, 
1397     wxWindow 
*listctrl 
= m_owner
->GetParent(); 
1401     // don't use foreground colour for drawing highlighted items - this might 
1402     // make them completely invisible (and there is no way to do bit 
1403     // arithmetics on wxColour, unfortunately) 
1408         if (m_owner
->HasFocus() 
1409 #if !defined(__WXUNIVERSAL__) 
1410                 && IsControlActive( (ControlRef
)m_owner
->GetHandle() ) 
1418         colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1420     else if ( attr 
&& attr
->HasTextColour() ) 
1421         colText 
= attr
->GetTextColour(); 
1423         colText 
= listctrl
->GetForegroundColour(); 
1425     dc
->SetTextForeground(colText
); 
1429     if ( attr 
&& attr
->HasFont() ) 
1430         font 
= attr
->GetFont(); 
1432         font 
= listctrl
->GetFont(); 
1437     bool hasBgCol 
= attr 
&& attr
->HasBackgroundColour(); 
1438     if ( highlighted 
|| hasBgCol 
) 
1441             dc
->SetBrush( *m_owner
->GetHighlightBrush() ); 
1443             dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxBRUSHSTYLE_SOLID
)); 
1445         dc
->SetPen( *wxTRANSPARENT_PEN 
); 
1453 void wxListLineData::Draw( wxDC 
*dc 
) 
1455     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1456     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1458     bool highlighted 
= IsHighlighted(); 
1460     wxListItemAttr 
*attr 
= GetAttr(); 
1462     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1463 #if ( !defined(__WXGTK20__) && !defined(__WXMAC__) ) 
1465         dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1471             int flags 
= wxCONTROL_SELECTED
; 
1472             if (m_owner
->HasFocus() 
1473 #if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) 
1474                 && IsControlActive( (ControlRef
)m_owner
->GetHandle() ) 
1477                 flags 
|= wxCONTROL_FOCUSED
; 
1478             wxRendererNative::Get().DrawItemSelectionRect( m_owner
, *dc
, m_gi
->m_rectHighlight
, flags 
); 
1483             dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1488     // just for debugging to better see where the items are 
1490     dc
->SetPen(*wxRED_PEN
); 
1491     dc
->SetBrush(*wxTRANSPARENT_BRUSH
); 
1492     dc
->DrawRectangle( m_gi
->m_rectAll 
); 
1493     dc
->SetPen(*wxGREEN_PEN
); 
1494     dc
->DrawRectangle( m_gi
->m_rectIcon 
); 
1497     wxListItemData 
*item 
= node
->GetData(); 
1498     if (item
->HasImage()) 
1500         // centre the image inside our rectangle, this looks nicer when items 
1501         // ae aligned in a row 
1502         const wxRect
& rectIcon 
= m_gi
->m_rectIcon
; 
1504         m_owner
->DrawImage(item
->GetImage(), dc
, rectIcon
.x
, rectIcon
.y
); 
1507     if (item
->HasText()) 
1509         const wxRect
& rectLabel 
= m_gi
->m_rectLabel
; 
1511         wxDCClipper 
clipper(*dc
, rectLabel
); 
1512         dc
->DrawText(item
->GetText(), rectLabel
.x
, rectLabel
.y
); 
1516 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
1518                                        const wxRect
& rectHL
, 
1521     // TODO: later we should support setting different attributes for 
1522     //       different columns - to do it, just add "col" argument to 
1523     //       GetAttr() and move these lines into the loop below 
1524     wxListItemAttr 
*attr 
= GetAttr(); 
1525     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1526 #if ( !defined(__WXGTK20__) && !defined(__WXMAC__) ) 
1528         dc
->DrawRectangle( rectHL 
); 
1534             int flags 
= wxCONTROL_SELECTED
; 
1535             if (m_owner
->HasFocus()) 
1536                 flags 
|= wxCONTROL_FOCUSED
; 
1537             wxRendererNative::Get().DrawItemSelectionRect( m_owner
, *dc
, rectHL
, flags 
); 
1541             dc
->DrawRectangle( rectHL 
); 
1546     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
1547             yMid 
= rect
.y 
+ rect
.height
/2; 
1549     // This probably needs to be done 
1550     // on all platforms as the icons 
1551     // otherwise nearly touch the border 
1556     for ( wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1558           node 
= node
->GetNext(), col
++ ) 
1560         wxListItemData 
*item 
= node
->GetData(); 
1562         int width 
= m_owner
->GetColumnWidth(col
); 
1566         const int wText 
= width 
- 8; 
1567         wxDCClipper 
clipper(*dc
, xOld
, rect
.y
, wText
, rect
.height
); 
1569         if ( item
->HasImage() ) 
1572             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
1573             m_owner
->DrawImage( item
->GetImage(), dc
, xOld
, yMid 
- iy
/2 ); 
1575             ix 
+= IMAGE_MARGIN_IN_REPORT_MODE
; 
1581         if ( item
->HasText() ) 
1582             DrawTextFormatted(dc
, item
->GetText(), col
, xOld
, yMid
, wText
); 
1586 void wxListLineData::DrawTextFormatted(wxDC 
*dc
, 
1587                                        const wxString
& textOrig
, 
1593     // we don't support displaying multiple lines currently (and neither does 
1594     // wxMSW FWIW) so just merge all the lines 
1595     wxString 
text(textOrig
); 
1596     text
.Replace(_T("\n"), _T(" ")); 
1599     dc
->GetTextExtent(text
, &w
, &h
); 
1601     const wxCoord y 
= yMid 
- (h 
+ 1)/2; 
1603     wxDCClipper 
clipper(*dc
, x
, y
, width
, h
); 
1605     // determine if the string can fit inside the current width 
1608         // it can, draw it using the items alignment 
1610         m_owner
->GetColumn(col
, item
); 
1611         switch ( item
.GetAlign() ) 
1613             case wxLIST_FORMAT_LEFT
: 
1617             case wxLIST_FORMAT_RIGHT
: 
1621             case wxLIST_FORMAT_CENTER
: 
1622                 x 
+= (width 
- w
) / 2; 
1626                 wxFAIL_MSG( _T("unknown list item format") ); 
1630         dc
->DrawText(text
, x
, y
); 
1632     else // otherwise, truncate and add an ellipsis if possible 
1634         // determine the base width 
1635         wxString 
ellipsis(wxT("...")); 
1637         dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1639         // continue until we have enough space or only one character left 
1641         size_t len 
= text
.length(); 
1642         wxString drawntext 
= text
.Left(len
); 
1645             dc
->GetTextExtent(drawntext
.Last(), &w_c
, &h_c
); 
1646             drawntext
.RemoveLast(); 
1649             if (w 
+ base_w 
<= width
) 
1653         // if still not enough space, remove ellipsis characters 
1654         while (ellipsis
.length() > 0 && w 
+ base_w 
> width
) 
1656             ellipsis 
= ellipsis
.Left(ellipsis
.length() - 1); 
1657             dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1660         // now draw the text 
1661         dc
->DrawText(drawntext
, x
, y
); 
1662         dc
->DrawText(ellipsis
, x 
+ w
, y
); 
1666 bool wxListLineData::Highlight( bool on 
) 
1668     wxCHECK_MSG( !IsVirtual(), false, _T("unexpected call to Highlight") ); 
1670     if ( on 
== m_highlighted 
) 
1678 void wxListLineData::ReverseHighlight( void ) 
1680     Highlight(!IsHighlighted()); 
1683 //----------------------------------------------------------------------------- 
1684 //  wxListHeaderWindow 
1685 //----------------------------------------------------------------------------- 
1687 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
1688     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
1689     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
1690     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
1693 void wxListHeaderWindow::Init() 
1695     m_currentCursor 
= (wxCursor 
*) NULL
; 
1696     m_isDragging 
= false; 
1700 wxListHeaderWindow::wxListHeaderWindow() 
1704     m_owner 
= (wxListMainWindow 
*) NULL
; 
1705     m_resizeCursor 
= (wxCursor 
*) NULL
; 
1708 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, 
1710                                         wxListMainWindow 
*owner
, 
1714                                         const wxString 
&name 
) 
1715                   : wxWindow( win
, id
, pos
, size
, style
, name 
) 
1720     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
1723     wxVisualAttributes attr 
= wxPanel::GetClassDefaultAttributes(); 
1724     SetOwnForegroundColour( attr
.colFg 
); 
1725     SetOwnBackgroundColour( attr
.colBg 
); 
1727         SetOwnFont( attr
.font 
); 
1729     SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
1730     SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
1732         SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT 
)); 
1736 wxListHeaderWindow::~wxListHeaderWindow() 
1738     delete m_resizeCursor
; 
1741 #ifdef __WXUNIVERSAL__ 
1742 #include "wx/univ/renderer.h" 
1743 #include "wx/univ/theme.h" 
1746 // shift the DC origin to match the position of the main window horz 
1747 // scrollbar: this allows us to always use logical coords 
1748 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
1751     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1754     m_owner
->GetViewStart( &view_start
, NULL 
); 
1759     dc
.GetDeviceOrigin( &org_x
, &org_y 
); 
1761     // account for the horz scrollbar offset 
1763     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
1765         // Maybe we just have to check for m_signX 
1766         // in the DC, but I leave the #ifdef __WXGTK__ 
1768         dc
.SetDeviceOrigin( org_x 
+ (view_start 
* xpix
), org_y 
); 
1772         dc
.SetDeviceOrigin( org_x 
- (view_start 
* xpix
), org_y 
); 
1775 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1777     wxPaintDC 
dc( this ); 
1782     dc
.SetFont( GetFont() ); 
1784     // width and height of the entire header window 
1786     GetClientSize( &w
, &h 
); 
1787     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1789     dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
1790     dc
.SetTextForeground(GetForegroundColour()); 
1792     int x 
= HEADER_OFFSET_X
; 
1793     int numColumns 
= m_owner
->GetColumnCount(); 
1795     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1797         m_owner
->GetColumn( i
, item 
); 
1798         int wCol 
= item
.m_width
; 
1804         if (!m_parent
->IsEnabled()) 
1805             flags 
|= wxCONTROL_DISABLED
; 
1807 // NB: The code below is not really Mac-specific, but since we are close 
1808 // to 2.8 release and I don't have time to test on other platforms, I 
1809 // defined this only for wxMac. If this behavior is desired on 
1810 // other platforms, please go ahead and revise or remove the #ifdef. 
1812         if ( !m_owner
->IsVirtual() && (item
.m_mask 
& wxLIST_MASK_STATE
) && 
1813                 (item
.m_state 
& wxLIST_STATE_SELECTED
) ) 
1814             flags 
|= wxCONTROL_SELECTED
; 
1817         wxRendererNative::Get().DrawHeaderButton
 
1821                                     wxRect(x
, HEADER_OFFSET_Y
, cw
, ch
), 
1825         // see if we have enough space for the column label 
1827         // for this we need the width of the text 
1830         dc
.GetTextExtent(item
.GetText(), &wLabel
, &hLabel
); 
1831         wLabel 
+= 2 * EXTRA_WIDTH
; 
1833         // and the width of the icon, if any 
1834         int ix 
= 0, iy 
= 0;    // init them just to suppress the compiler warnings 
1835         const int image 
= item
.m_image
; 
1836         wxImageList 
*imageList
; 
1839             imageList 
= m_owner
->m_small_image_list
; 
1842                 imageList
->GetSize(image
, ix
, iy
); 
1843                 wLabel 
+= ix 
+ HEADER_IMAGE_MARGIN_IN_REPORT_MODE
; 
1851         // ignore alignment if there is not enough space anyhow 
1853         switch ( wLabel 
< cw 
? item
.GetAlign() : wxLIST_FORMAT_LEFT 
) 
1856                 wxFAIL_MSG( _T("unknown list item format") ); 
1859             case wxLIST_FORMAT_LEFT
: 
1863             case wxLIST_FORMAT_RIGHT
: 
1864                 xAligned 
= x 
+ cw 
- wLabel
; 
1867             case wxLIST_FORMAT_CENTER
: 
1868                 xAligned 
= x 
+ (cw 
- wLabel
) / 2; 
1872         // draw the text and image clipping them so that they 
1873         // don't overwrite the column boundary 
1874         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h 
- 4 ); 
1876         // if we have an image, draw it on the right of the label 
1883                         xAligned 
+ wLabel 
- ix 
- HEADER_IMAGE_MARGIN_IN_REPORT_MODE
, 
1884                         HEADER_OFFSET_Y 
+ (h 
- 4 - iy
)/2, 
1885                         wxIMAGELIST_DRAW_TRANSPARENT
 
1889         dc
.DrawText( item
.GetText(), 
1890                      xAligned 
+ EXTRA_WIDTH
, h 
/ 2 - hLabel 
/ 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT ); 
1896 void wxListHeaderWindow::DrawCurrent() 
1899     m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1901     int x1 
= m_currentX
; 
1903     m_owner
->ClientToScreen( &x1
, &y1 
); 
1905     int x2 
= m_currentX
; 
1907     m_owner
->GetClientSize( NULL
, &y2 
); 
1908     m_owner
->ClientToScreen( &x2
, &y2 
); 
1911     dc
.SetLogicalFunction( wxINVERT 
); 
1912     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
1913     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1917     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1919     dc
.SetLogicalFunction( wxCOPY 
); 
1921     dc
.SetPen( wxNullPen 
); 
1922     dc
.SetBrush( wxNullBrush 
); 
1926 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1928     // we want to work with logical coords 
1930     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1931     int y 
= event
.GetY(); 
1935         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1937         // we don't draw the line beyond our window, but we allow dragging it 
1940         GetClientSize( &w
, NULL 
); 
1941         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1944         // erase the line if it was drawn 
1945         if ( m_currentX 
< w 
) 
1948         if (event
.ButtonUp()) 
1951             m_isDragging 
= false; 
1953             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1954             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1961                 m_currentX 
= m_minX 
+ 7; 
1963             // draw in the new location 
1964             if ( m_currentX 
< w 
) 
1968     else // not dragging 
1971         bool hit_border 
= false; 
1973         // end of the current column 
1976         // find the column where this event occurred 
1978             countCol 
= m_owner
->GetColumnCount(); 
1979         for (col 
= 0; col 
< countCol
; col
++) 
1981             xpos 
+= m_owner
->GetColumnWidth( col 
); 
1984             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
1986                 // near the column border 
1993                 // inside the column 
2000         if ( col 
== countCol 
) 
2003         if (event
.LeftDown() || event
.RightUp()) 
2005             if (hit_border 
&& event
.LeftDown()) 
2007                 if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
2008                                    event
.GetPosition()) ) 
2010                     m_isDragging 
= true; 
2015                 //else: column resizing was vetoed by the user code 
2017             else // click on a column 
2019                 // record the selected state of the columns 
2020                 if (event
.LeftDown()) 
2022                     for (int i
=0; i 
< m_owner
->GetColumnCount(); i
++) 
2025                         m_owner
->GetColumn(i
, colItem
); 
2026                         long state 
= colItem
.GetState(); 
2028                             colItem
.SetState(state 
| wxLIST_STATE_SELECTED
); 
2030                             colItem
.SetState(state 
& ~wxLIST_STATE_SELECTED
); 
2031                         m_owner
->SetColumn(i
, colItem
); 
2035                 SendListEvent( event
.LeftDown() 
2036                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
2037                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
2038                                 event
.GetPosition()); 
2041         else if (event
.Moving()) 
2046                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
2047                 m_currentCursor 
= m_resizeCursor
; 
2051                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
2052                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
2056                 SetCursor(*m_currentCursor
); 
2061 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
2063     m_owner
->SetFocus(); 
2067 bool wxListHeaderWindow::SendListEvent(wxEventType type
, const wxPoint
& pos
) 
2069     wxWindow 
*parent 
= GetParent(); 
2070     wxListEvent 
le( type
, parent
->GetId() ); 
2071     le
.SetEventObject( parent 
); 
2072     le
.m_pointDrag 
= pos
; 
2074     // the position should be relative to the parent window, not 
2075     // this one for compatibility with MSW and common sense: the 
2076     // user code doesn't know anything at all about this header 
2077     // window, so why should it get positions relative to it? 
2078     le
.m_pointDrag
.y 
-= GetSize().y
; 
2080     le
.m_col 
= m_column
; 
2081     return !parent
->GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
2084 //----------------------------------------------------------------------------- 
2085 // wxListRenameTimer (internal) 
2086 //----------------------------------------------------------------------------- 
2088 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
2093 void wxListRenameTimer::Notify() 
2095     m_owner
->OnRenameTimer(); 
2098 //----------------------------------------------------------------------------- 
2099 // wxListTextCtrlWrapper (internal) 
2100 //----------------------------------------------------------------------------- 
2102 BEGIN_EVENT_TABLE(wxListTextCtrlWrapper
, wxEvtHandler
) 
2103     EVT_CHAR           (wxListTextCtrlWrapper::OnChar
) 
2104     EVT_KEY_UP         (wxListTextCtrlWrapper::OnKeyUp
) 
2105     EVT_KILL_FOCUS     (wxListTextCtrlWrapper::OnKillFocus
) 
2108 wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow 
*owner
, 
2111               : m_startValue(owner
->GetItemText(itemEdit
)), 
2112                 m_itemEdited(itemEdit
) 
2116     m_aboutToFinish 
= false; 
2118     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
2120     m_owner
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
2121                                   &rectLabel
.x
, &rectLabel
.y
); 
2123     m_text
->Create(owner
, wxID_ANY
, m_startValue
, 
2124                    wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2125                    wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
2128     m_text
->PushEventHandler(this); 
2131 void wxListTextCtrlWrapper::EndEdit(bool discardChanges
) 
2133     m_aboutToFinish 
= true; 
2135     if ( discardChanges 
) 
2137         m_owner
->OnRenameCancelled(m_itemEdited
); 
2143         // Notify the owner about the changes 
2146         // Even if vetoed, close the control (consistent with MSW) 
2151 void wxListTextCtrlWrapper::Finish( bool setfocus 
) 
2153     m_text
->RemoveEventHandler(this); 
2154     m_owner
->ResetTextControl( m_text 
); 
2156     wxPendingDelete
.Append( this ); 
2159         m_owner
->SetFocus(); 
2162 bool wxListTextCtrlWrapper::AcceptChanges() 
2164     const wxString value 
= m_text
->GetValue(); 
2166     // notice that we should always call OnRenameAccept() to generate the "end 
2167     // label editing" event, even if the user hasn't really changed anything 
2168     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
2170         // vetoed by the user 
2174     // accepted, do rename the item (unless nothing changed) 
2175     if ( value 
!= m_startValue 
) 
2176         m_owner
->SetItemText(m_itemEdited
, value
); 
2181 void wxListTextCtrlWrapper::OnChar( wxKeyEvent 
&event 
) 
2183     switch ( event
.m_keyCode 
) 
2198 void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent 
&event 
) 
2200     if (m_aboutToFinish
) 
2202         // auto-grow the textctrl: 
2203         wxSize parentSize 
= m_owner
->GetSize(); 
2204         wxPoint myPos 
= m_text
->GetPosition(); 
2205         wxSize mySize 
= m_text
->GetSize(); 
2207         m_text
->GetTextExtent(m_text
->GetValue() + _T("MM"), &sx
, &sy
); 
2208         if (myPos
.x 
+ sx 
> parentSize
.x
) 
2209             sx 
= parentSize
.x 
- myPos
.x
; 
2212        m_text
->SetSize(sx
, wxDefaultCoord
); 
2218 void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent 
&event 
) 
2220     if ( !m_aboutToFinish 
) 
2222         if ( !AcceptChanges() ) 
2223             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2228     // We must let the native text control handle focus 
2232 //----------------------------------------------------------------------------- 
2234 //----------------------------------------------------------------------------- 
2236 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledCanvas
) 
2237   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2238   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2239   EVT_CHAR           (wxListMainWindow::OnChar
) 
2240   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2241   EVT_KEY_UP         (wxListMainWindow::OnKeyUp
) 
2242   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2243   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2244   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2247 void wxListMainWindow::Init() 
2252     m_lineTo 
= (size_t)-1; 
2258     m_small_image_list 
= (wxImageList 
*) NULL
; 
2259     m_normal_image_list 
= (wxImageList 
*) NULL
; 
2261     m_small_spacing 
= 30; 
2262     m_normal_spacing 
= 40; 
2266     m_isCreated 
= false; 
2268     m_lastOnSame 
= false; 
2269     m_renameTimer 
= new wxListRenameTimer( this ); 
2270     m_textctrlWrapper 
= NULL
; 
2274     m_lineSelectSingleOnUp 
= 
2275     m_lineBeforeLastClicked 
= (size_t)-1; 
2278 wxListMainWindow::wxListMainWindow() 
2283     m_highlightUnfocusedBrush 
= (wxBrush 
*) NULL
; 
2286 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2291                                     const wxString 
&name 
) 
2292                 : wxScrolledCanvas( parent
, id
, pos
, size
, 
2293                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2297     m_highlightBrush 
= new wxBrush
 
2299                             wxSystemSettings::GetColour
 
2301                                 wxSYS_COLOUR_HIGHLIGHT
 
2306     m_highlightUnfocusedBrush 
= new wxBrush
 
2308                                  wxSystemSettings::GetColour
 
2310                                      wxSYS_COLOUR_BTNSHADOW
 
2315     SetScrollbars( 0, 0, 0, 0, 0, 0 ); 
2317     wxVisualAttributes attr 
= wxGenericListCtrl::GetClassDefaultAttributes(); 
2318     SetOwnForegroundColour( attr
.colFg 
); 
2319     SetOwnBackgroundColour( attr
.colBg 
); 
2321         SetOwnFont( attr
.font 
); 
2324 wxListMainWindow::~wxListMainWindow() 
2327     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
2328     WX_CLEAR_ARRAY(m_aColWidths
); 
2330     delete m_highlightBrush
; 
2331     delete m_highlightUnfocusedBrush
; 
2332     delete m_renameTimer
; 
2335 void wxListMainWindow::CacheLineData(size_t line
) 
2337     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
2339     wxListLineData 
*ld 
= GetDummyLine(); 
2341     size_t countCol 
= GetColumnCount(); 
2342     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2344         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2345         ld
->SetImage(col
, listctrl
->OnGetItemColumnImage(line
, col
)); 
2348     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
2351 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2353     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2354     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); 
2356     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2358     // we need to recreate the dummy line if the number of columns in the 
2359     // control changed as it would have the incorrect number of fields 
2361     if ( !m_lines
.IsEmpty() && 
2362             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
2364         self
->m_lines
.Clear(); 
2367     if ( m_lines
.IsEmpty() ) 
2369         wxListLineData 
*line 
= new wxListLineData(self
); 
2370         self
->m_lines
.Add(line
); 
2372         // don't waste extra memory -- there never going to be anything 
2373         // else/more in this array 
2374         self
->m_lines
.Shrink(); 
2380 // ---------------------------------------------------------------------------- 
2381 // line geometry (report mode only) 
2382 // ---------------------------------------------------------------------------- 
2384 wxCoord 
wxListMainWindow::GetLineHeight() const 
2386     // we cache the line height as calling GetTextExtent() is slow 
2387     if ( !m_lineHeight 
) 
2389         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2391         wxClientDC 
dc( self 
); 
2392         dc
.SetFont( GetFont() ); 
2395         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2397         if ( m_small_image_list 
&& m_small_image_list
->GetImageCount() ) 
2400             m_small_image_list
->GetSize(0, iw
, ih
); 
2405         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2408     return m_lineHeight
; 
2411 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2413     wxASSERT_MSG( InReportView(), _T("only works in report mode") ); 
2415     return LINE_SPACING 
+ line 
* GetLineHeight(); 
2418 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2420     if ( !InReportView() ) 
2421         return GetLine(line
)->m_gi
->m_rectAll
; 
2424     rect
.x 
= HEADER_OFFSET_X
; 
2425     rect
.y 
= GetLineY(line
); 
2426     rect
.width 
= GetHeaderWidth(); 
2427     rect
.height 
= GetLineHeight(); 
2432 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2434     if ( !InReportView() ) 
2435         return GetLine(line
)->m_gi
->m_rectLabel
; 
2438     wxListLineData 
*data 
= GetLine(line
); 
2439     wxListItemDataList::compatibility_iterator node 
= data
->m_items
.GetFirst(); 
2442         wxListItemData 
*item 
= node
->GetData(); 
2443         if ( item
->HasImage() ) 
2446             GetImageSize( item
->GetImage(), ix
, iy 
); 
2447             image_x 
= 3 + ix 
+ IMAGE_MARGIN_IN_REPORT_MODE
; 
2452     rect
.x 
= image_x 
+ HEADER_OFFSET_X
; 
2453     rect
.y 
= GetLineY(line
); 
2454     rect
.width 
= GetColumnWidth(0) - image_x
; 
2455     rect
.height 
= GetLineHeight(); 
2460 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2462     if ( !InReportView() ) 
2463         return GetLine(line
)->m_gi
->m_rectIcon
; 
2465     wxListLineData 
*ld 
= GetLine(line
); 
2466     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2469     rect
.x 
= HEADER_OFFSET_X
; 
2470     rect
.y 
= GetLineY(line
); 
2471     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2476 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2478     return InReportView() ? GetLineRect(line
) 
2479                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2482 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2484     wxASSERT_MSG( line 
< GetItemCount(), _T("invalid line in HitTestLine") ); 
2486     wxListLineData 
*ld 
= GetLine(line
); 
2488     if ( ld
->HasImage() && GetLineIconRect(line
).Contains(x
, y
) ) 
2489         return wxLIST_HITTEST_ONITEMICON
; 
2491     // VS: Testing for "ld->HasText() || InReportView()" instead of 
2492     //     "ld->HasText()" is needed to make empty lines in report view 
2494     if ( ld
->HasText() || InReportView() ) 
2496         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2497                                      : GetLineLabelRect(line
); 
2499         if ( rect
.Contains(x
, y
) ) 
2500             return wxLIST_HITTEST_ONITEMLABEL
; 
2506 // ---------------------------------------------------------------------------- 
2507 // highlight (selection) handling 
2508 // ---------------------------------------------------------------------------- 
2510 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2514         return m_selStore
.IsSelected(line
); 
2518         wxListLineData 
*ld 
= GetLine(line
); 
2519         wxCHECK_MSG( ld
, false, _T("invalid index in IsHighlighted") ); 
2521         return ld
->IsHighlighted(); 
2525 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
2531         wxArrayInt linesChanged
; 
2532         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
2535             // meny items changed state, refresh everything 
2536             RefreshLines(lineFrom
, lineTo
); 
2538         else // only a few items changed state, refresh only them 
2540             size_t count 
= linesChanged
.GetCount(); 
2541             for ( size_t n 
= 0; n 
< count
; n
++ ) 
2543                 RefreshLine(linesChanged
[n
]); 
2547     else // iterate over all items in non report view 
2549         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2551             if ( HighlightLine(line
, highlight
) ) 
2557 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2563         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2567         wxListLineData 
*ld 
= GetLine(line
); 
2568         wxCHECK_MSG( ld
, false, _T("invalid index in HighlightLine") ); 
2570         changed 
= ld
->Highlight(highlight
); 
2575         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2576                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2582 void wxListMainWindow::RefreshLine( size_t line 
) 
2584     if ( InReportView() ) 
2586         size_t visibleFrom
, visibleTo
; 
2587         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2589         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
2593     wxRect rect 
= GetLineRect(line
); 
2595     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2596     RefreshRect( rect 
); 
2599 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2601     // we suppose that they are ordered by caller 
2602     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2604     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2606     if ( InReportView() ) 
2608         size_t visibleFrom
, visibleTo
; 
2609         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2611         if ( lineFrom 
< visibleFrom 
) 
2612             lineFrom 
= visibleFrom
; 
2613         if ( lineTo 
> visibleTo 
) 
2618         rect
.y 
= GetLineY(lineFrom
); 
2619         rect
.width 
= GetClientSize().x
; 
2620         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
2622         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2623         RefreshRect( rect 
); 
2627         // TODO: this should be optimized... 
2628         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2635 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2637     if ( InReportView() ) 
2639         size_t visibleFrom
, visibleTo
; 
2640         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2642         if ( lineFrom 
< visibleFrom 
) 
2643             lineFrom 
= visibleFrom
; 
2644         else if ( lineFrom 
> visibleTo 
) 
2649         rect
.y 
= GetLineY(lineFrom
); 
2650         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2652         wxSize size 
= GetClientSize(); 
2653         rect
.width 
= size
.x
; 
2655         // refresh till the bottom of the window 
2656         rect
.height 
= size
.y 
- rect
.y
; 
2658         RefreshRect( rect 
); 
2662         // TODO: how to do it more efficiently? 
2667 void wxListMainWindow::RefreshSelected() 
2673     if ( InReportView() ) 
2675         GetVisibleLinesRange(&from
, &to
); 
2680         to 
= GetItemCount() - 1; 
2683     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
2684         RefreshLine(m_current
); 
2686     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
2688         // NB: the test works as expected even if m_current == -1 
2689         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
2694 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2696     // Note: a wxPaintDC must be constructed even if no drawing is 
2697     // done (a Windows requirement). 
2698     wxPaintDC 
dc( this ); 
2702         // nothing to draw or not the moment to draw it 
2708         // delay the repainting until we calculate all the items positions 
2715     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2717     dc
.SetFont( GetFont() ); 
2719     if ( InReportView() ) 
2721         int lineHeight 
= GetLineHeight(); 
2723         size_t visibleFrom
, visibleTo
; 
2724         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2727         int xOrig 
= dc
.LogicalToDeviceX( 0 ); 
2728         int yOrig 
= dc
.LogicalToDeviceY( 0 ); 
2730         // tell the caller cache to cache the data 
2733             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2734                                 GetParent()->GetId()); 
2735             evCache
.SetEventObject( GetParent() ); 
2736             evCache
.m_oldItemIndex 
= visibleFrom
; 
2737             evCache
.m_itemIndex 
= visibleTo
; 
2738             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2741         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2743             rectLine 
= GetLineRect(line
); 
2746             if ( !IsExposed(rectLine
.x 
+ xOrig
, rectLine
.y 
+ yOrig
, 
2747                             rectLine
.width
, rectLine
.height
) ) 
2749                 // don't redraw unaffected lines to avoid flicker 
2753             GetLine(line
)->DrawInReportMode( &dc
, 
2755                                              GetLineHighlightRect(line
), 
2756                                              IsHighlighted(line
) ); 
2759         if ( HasFlag(wxLC_HRULES
) ) 
2761             wxPen 
pen(GetRuleColour(), 1, wxPENSTYLE_SOLID
); 
2762             wxSize clientSize 
= GetClientSize(); 
2764             size_t i 
= visibleFrom
; 
2765             if (i 
== 0) i 
= 1; // Don't draw the first one 
2766             for ( ; i 
<= visibleTo
; i
++ ) 
2769                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2770                 dc
.DrawLine(0 - dev_x
, i 
* lineHeight
, 
2771                             clientSize
.x 
- dev_x
, i 
* lineHeight
); 
2774             // Draw last horizontal rule 
2775             if ( visibleTo 
== GetItemCount() - 1 ) 
2778                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2779                 dc
.DrawLine(0 - dev_x
, (m_lineTo 
+ 1) * lineHeight
, 
2780                             clientSize
.x 
- dev_x 
, (m_lineTo 
+ 1) * lineHeight 
); 
2784         // Draw vertical rules if required 
2785         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2787             wxPen 
pen(GetRuleColour(), 1, wxPENSTYLE_SOLID
); 
2788             wxRect firstItemRect
, lastItemRect
; 
2790             GetItemRect(visibleFrom
, firstItemRect
); 
2791             GetItemRect(visibleTo
, lastItemRect
); 
2792             int x 
= firstItemRect
.GetX(); 
2794             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2796             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2798                 int colWidth 
= GetColumnWidth(col
); 
2800                 int x_pos 
= x 
- dev_x
; 
2801                 if (col 
< GetColumnCount()-1) x_pos 
-= 2; 
2802                 dc
.DrawLine(x_pos
, firstItemRect
.GetY() - 1 - dev_y
, 
2803                             x_pos
, lastItemRect
.GetBottom() + 1 - dev_y
); 
2809         size_t count 
= GetItemCount(); 
2810         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2812             GetLine(i
)->Draw( &dc 
); 
2817     // Don't draw rect outline under Mac at all. 
2822             wxRect 
rect( GetLineHighlightRect( m_current 
) ); 
2824             dc
.SetPen( *wxBLACK_PEN 
); 
2825             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2826             dc
.DrawRectangle( rect 
); 
2828             wxRendererNative::Get().DrawItemSelectionRect( this, dc
, rect
, wxCONTROL_CURRENT
|wxCONTROL_FOCUSED 
); 
2836 void wxListMainWindow::HighlightAll( bool on 
) 
2838     if ( IsSingleSel() ) 
2840         wxASSERT_MSG( !on
, _T("can't do this in a single selection control") ); 
2842         // we just have one item to turn off 
2843         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2845             HighlightLine(m_current
, false); 
2846             RefreshLine(m_current
); 
2849     else // multi selection 
2852             HighlightLines(0, GetItemCount() - 1, on
); 
2856 void wxListMainWindow::SendNotify( size_t line
, 
2857                                    wxEventType command
, 
2858                                    const wxPoint
& point 
) 
2860     wxListEvent 
le( command
, GetParent()->GetId() ); 
2861     le
.SetEventObject( GetParent() ); 
2863     le
.m_itemIndex 
= line
; 
2865     // set only for events which have position 
2866     if ( point 
!= wxDefaultPosition 
) 
2867         le
.m_pointDrag 
= point
; 
2869     // don't try to get the line info for virtual list controls: the main 
2870     // program has it anyhow and if we did it would result in accessing all 
2871     // the lines, even those which are not visible now and this is precisely 
2872     // what we're trying to avoid 
2875         if ( line 
!= (size_t)-1 ) 
2877             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2879         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2881     //else: there may be no more such item 
2883     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2886 void wxListMainWindow::ChangeCurrent(size_t current
) 
2888     m_current 
= current
; 
2890     // as the current item changed, we shouldn't start editing it when the 
2891     // "slow click" timer expires as the click happened on another item 
2892     if ( m_renameTimer
->IsRunning() ) 
2893         m_renameTimer
->Stop(); 
2895     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2898 wxTextCtrl 
*wxListMainWindow::EditLabel(long item
, wxClassInfo
* textControlClass
) 
2900     wxCHECK_MSG( (item 
>= 0) && ((size_t)item 
< GetItemCount()), NULL
, 
2901                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2903     wxASSERT_MSG( textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
)), 
2904                  wxT("EditLabel() needs a text control") ); 
2906     size_t itemEdit 
= (size_t)item
; 
2908     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2909     le
.SetEventObject( GetParent() ); 
2910     le
.m_itemIndex 
= item
; 
2911     wxListLineData 
*data 
= GetLine(itemEdit
); 
2912     wxCHECK_MSG( data
, NULL
, _T("invalid index in EditLabel()") ); 
2913     data
->GetItem( 0, le
.m_item 
); 
2915     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2917         // vetoed by user code 
2921     // We have to call this here because the label in question might just have 
2922     // been added and no screen update taken place. 
2927         // Pending events dispatched by wxSafeYield might have changed the item 
2929         if ( (size_t)item 
>= GetItemCount() ) 
2933     wxTextCtrl 
* const text 
= (wxTextCtrl 
*)textControlClass
->CreateObject(); 
2934     m_textctrlWrapper 
= new wxListTextCtrlWrapper(this, text
, item
); 
2935     return m_textctrlWrapper
->GetText(); 
2938 void wxListMainWindow::OnRenameTimer() 
2940     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2942     EditLabel( m_current 
); 
2945 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2947     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2948     le
.SetEventObject( GetParent() ); 
2949     le
.m_itemIndex 
= itemEdit
; 
2951     wxListLineData 
*data 
= GetLine(itemEdit
); 
2953     wxCHECK_MSG( data
, false, _T("invalid index in OnRenameAccept()") ); 
2955     data
->GetItem( 0, le
.m_item 
); 
2956     le
.m_item
.m_text 
= value
; 
2957     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2961 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2963     // let owner know that the edit was cancelled 
2964     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2966     le
.SetEditCanceled(true); 
2968     le
.SetEventObject( GetParent() ); 
2969     le
.m_itemIndex 
= itemEdit
; 
2971     wxListLineData 
*data 
= GetLine(itemEdit
); 
2972     wxCHECK_RET( data
, _T("invalid index in OnRenameCancelled()") ); 
2974     data
->GetItem( 0, le
.m_item 
); 
2975     GetEventHandler()->ProcessEvent( le 
); 
2978 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2982     // On wxMac we can't depend on the EVT_KILL_FOCUS event to properly 
2983     // shutdown the edit control when the mouse is clicked elsewhere on the 
2984     // listctrl because the order of events is different (or something like 
2985     // that), so explicitly end the edit if it is active. 
2986     if ( event
.LeftDown() && m_textctrlWrapper 
) 
2987         m_textctrlWrapper
->EndEdit( false ); 
2990     if ( event
.LeftDown() ) 
2993     event
.SetEventObject( GetParent() ); 
2994     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2997     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
2999         // let the base handle mouse wheel events. 
3004     if ( !HasCurrent() || IsEmpty() ) 
3006         if (event
.RightDown()) 
3008             SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
3010             wxContextMenuEvent 
evtCtx( 
3012                 GetParent()->GetId(), 
3013                 ClientToScreen(event
.GetPosition())); 
3014             evtCtx
.SetEventObject(GetParent()); 
3015             GetParent()->GetEventHandler()->ProcessEvent(evtCtx
); 
3023     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
3024         event
.ButtonDClick()) ) 
3027     int x 
= event
.GetX(); 
3028     int y 
= event
.GetY(); 
3029     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
3031     // where did we hit it (if we did)? 
3034     size_t count 
= GetItemCount(), 
3037     if ( InReportView() ) 
3039         current 
= y 
/ GetLineHeight(); 
3040         if ( current 
< count 
) 
3041             hitResult 
= HitTestLine(current
, x
, y
); 
3045         // TODO: optimize it too! this is less simple than for report view but 
3046         //       enumerating all items is still not a way to do it!! 
3047         for ( current 
= 0; current 
< count
; current
++ ) 
3049             hitResult 
= HitTestLine(current
, x
, y
); 
3055     if (event
.Dragging()) 
3057         if (m_dragCount 
== 0) 
3059             // we have to report the raw, physical coords as we want to be 
3060             // able to call HitTest(event.m_pointDrag) from the user code to 
3061             // get the item being dragged 
3062             m_dragStart 
= event
.GetPosition(); 
3067         if (m_dragCount 
!= 3) 
3070         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
3071                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
3073         wxListEvent 
le( command
, GetParent()->GetId() ); 
3074         le
.SetEventObject( GetParent() ); 
3075         le
.m_itemIndex 
= m_lineLastClicked
; 
3076         le
.m_pointDrag 
= m_dragStart
; 
3077         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
3088         // outside of any item 
3089         if (event
.RightDown()) 
3091             SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
3093             wxContextMenuEvent 
evtCtx( 
3095                 GetParent()->GetId(), 
3096                 ClientToScreen(event
.GetPosition())); 
3097             evtCtx
.SetEventObject(GetParent()); 
3098             GetParent()->GetEventHandler()->ProcessEvent(evtCtx
); 
3102             // reset the selection and bail out 
3103             HighlightAll(false); 
3109     bool forceClick 
= false; 
3110     if (event
.ButtonDClick()) 
3112         if ( m_renameTimer
->IsRunning() ) 
3113             m_renameTimer
->Stop(); 
3115         m_lastOnSame 
= false; 
3117         if ( current 
== m_lineLastClicked 
) 
3119             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3125             // The first click was on another item, so don't interpret this as 
3126             // a double click, but as a simple click instead 
3133         if (m_lineSelectSingleOnUp 
!= (size_t)-1) 
3135             // select single line 
3136             HighlightAll( false ); 
3137             ReverseHighlight(m_lineSelectSingleOnUp
); 
3142             if ((current 
== m_current
) && 
3143                 (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
3144                 HasFlag(wxLC_EDIT_LABELS
) ) 
3146                 if ( !InReportView() || 
3147                         GetLineLabelRect(current
).Contains(x
, y
) ) 
3149                     int dclick 
= wxSystemSettings::GetMetric(wxSYS_DCLICK_MSEC
); 
3150                     m_renameTimer
->Start(dclick 
> 0 ? dclick 
: 250, true); 
3155         m_lastOnSame 
= false; 
3156         m_lineSelectSingleOnUp 
= (size_t)-1; 
3160         // This is necessary, because after a DnD operation in 
3161         // from and to ourself, the up event is swallowed by the 
3162         // DnD code. So on next non-up event (which means here and 
3163         // now) m_lineSelectSingleOnUp should be reset. 
3164         m_lineSelectSingleOnUp 
= (size_t)-1; 
3166     if (event
.RightDown()) 
3168         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3169         m_lineLastClicked 
= current
; 
3171         // If the item is already selected, do not update the selection. 
3172         // Multi-selections should not be cleared if a selected item is clicked. 
3173         if (!IsHighlighted(current
)) 
3175             HighlightAll(false); 
3176             ChangeCurrent(current
); 
3177             ReverseHighlight(m_current
); 
3180         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
3182         // Allow generation of context menu event 
3185     else if (event
.MiddleDown()) 
3187         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
3189     else if ( event
.LeftDown() || forceClick 
) 
3191         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3192         m_lineLastClicked 
= current
; 
3194         size_t oldCurrent 
= m_current
; 
3195         bool oldWasSelected 
= IsHighlighted(m_current
); 
3197         bool cmdModifierDown 
= event
.CmdDown(); 
3198         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
3200             if ( IsSingleSel() || !IsHighlighted(current
) ) 
3202                 HighlightAll( false ); 
3204                 ChangeCurrent(current
); 
3206                 ReverseHighlight(m_current
); 
3208             else // multi sel & current is highlighted & no mod keys 
3210                 m_lineSelectSingleOnUp 
= current
; 
3211                 ChangeCurrent(current
); // change focus 
3214         else // multi sel & either ctrl or shift is down 
3216             if (cmdModifierDown
) 
3218                 ChangeCurrent(current
); 
3220                 ReverseHighlight(m_current
); 
3222             else if (event
.ShiftDown()) 
3224                 ChangeCurrent(current
); 
3226                 size_t lineFrom 
= oldCurrent
, 
3229                 if ( lineTo 
< lineFrom 
) 
3232                     lineFrom 
= m_current
; 
3235                 HighlightLines(lineFrom
, lineTo
); 
3237             else // !ctrl, !shift 
3239                 // test in the enclosing if should make it impossible 
3240                 wxFAIL_MSG( _T("how did we get here?") ); 
3244         if (m_current 
!= oldCurrent
) 
3245             RefreshLine( oldCurrent 
); 
3247         // forceClick is only set if the previous click was on another item 
3248         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
) && oldWasSelected
; 
3252 void wxListMainWindow::MoveToItem(size_t item
) 
3254     if ( item 
== (size_t)-1 ) 
3257     wxRect rect 
= GetLineRect(item
); 
3259     int client_w
, client_h
; 
3260     GetClientSize( &client_w
, &client_h 
); 
3262     const int hLine 
= GetLineHeight(); 
3264     int view_x 
= SCROLL_UNIT_X 
* GetScrollPos( wxHORIZONTAL 
); 
3265     int view_y 
= hLine 
* GetScrollPos( wxVERTICAL 
); 
3267     if ( InReportView() ) 
3269         // the next we need the range of lines shown it might be different, 
3270         // so recalculate it 
3271         ResetVisibleLinesRange(); 
3273         if (rect
.y 
< view_y
) 
3274             Scroll( -1, rect
.y 
/ hLine 
); 
3275         if (rect
.y 
+ rect
.height 
+ 5 > view_y 
+ client_h
) 
3276             Scroll( -1, (rect
.y 
+ rect
.height 
- client_h 
+ hLine
) / hLine 
); 
3279         // At least on Mac the visible lines value will get reset inside of 
3280         // Scroll *before* it actually scrolls the window because of the 
3281         // Update() that happens there, so it will still have the wrong value. 
3282         // So let's reset it again and wait for it to be recalculated in the 
3283         // next paint event.  I would expect this problem to show up in wxGTK 
3284         // too but couldn't duplicate it there.  Perhaps the order of events 
3285         // is different...  --Robin 
3286         ResetVisibleLinesRange(); 
3294         if (rect
.x
-view_x 
< 5) 
3295             sx 
= (rect
.x 
- 5) / SCROLL_UNIT_X
; 
3296         if (rect
.x 
+ rect
.width 
- 5 > view_x 
+ client_w
) 
3297             sx 
= (rect
.x 
+ rect
.width 
- client_w 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
; 
3299         if (rect
.y
-view_y 
< 5) 
3300             sy 
= (rect
.y 
- 5) / hLine
; 
3301         if (rect
.y 
+ rect
.height 
- 5 > view_y 
+ client_h
) 
3302             sy 
= (rect
.y 
+ rect
.height 
- client_h 
+ hLine
) / hLine
; 
3308 bool wxListMainWindow::ScrollList(int WXUNUSED(dx
), int dy
) 
3310     if ( !InReportView() ) 
3312         // TODO: this should work in all views but is not implemented now 
3317     GetVisibleLinesRange(&top
, &bottom
); 
3319     if ( bottom 
== (size_t)-1 ) 
3322     ResetVisibleLinesRange(); 
3324     int hLine 
= GetLineHeight(); 
3326     Scroll(-1, top 
+ dy 
/ hLine
); 
3329     // see comment in MoveToItem() for why we do this 
3330     ResetVisibleLinesRange(); 
3336 // ---------------------------------------------------------------------------- 
3337 // keyboard handling 
3338 // ---------------------------------------------------------------------------- 
3340 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
3342     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
3343                  _T("invalid item index in OnArrowChar()") ); 
3345     size_t oldCurrent 
= m_current
; 
3347     // in single selection we just ignore Shift as we can't select several 
3349     if ( event
.ShiftDown() && !IsSingleSel() ) 
3351         ChangeCurrent(newCurrent
); 
3353         // refresh the old focus to remove it 
3354         RefreshLine( oldCurrent 
); 
3356         // select all the items between the old and the new one 
3357         if ( oldCurrent 
> newCurrent 
) 
3359             newCurrent 
= oldCurrent
; 
3360             oldCurrent 
= m_current
; 
3363         HighlightLines(oldCurrent
, newCurrent
); 
3367         // all previously selected items are unselected unless ctrl is held 
3368         // in a multiselection control 
3369         if ( !event
.ControlDown() || IsSingleSel() ) 
3370             HighlightAll(false); 
3372         ChangeCurrent(newCurrent
); 
3374         // refresh the old focus to remove it 
3375         RefreshLine( oldCurrent 
); 
3377         // in single selection mode we must always have a selected item 
3378         if ( !event
.ControlDown() || IsSingleSel() ) 
3379             HighlightLine( m_current
, true ); 
3382     RefreshLine( m_current 
); 
3387 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
3389     wxWindow 
*parent 
= GetParent(); 
3391     // propagate the key event upwards 
3392     wxKeyEvent 
ke( wxEVT_KEY_DOWN 
); 
3393     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3394     ke
.m_controlDown 
= event
.m_controlDown
; 
3395     ke
.m_altDown 
= event
.m_altDown
; 
3396     ke
.m_metaDown 
= event
.m_metaDown
; 
3397     ke
.m_keyCode 
= event
.m_keyCode
; 
3400     ke
.SetEventObject( parent 
); 
3401     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3406 void wxListMainWindow::OnKeyUp( wxKeyEvent 
&event 
) 
3408     wxWindow 
*parent 
= GetParent(); 
3410     // propagate the key event upwards 
3411     wxKeyEvent 
ke( wxEVT_KEY_UP 
); 
3412     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3413     ke
.m_controlDown 
= event
.m_controlDown
; 
3414     ke
.m_altDown 
= event
.m_altDown
; 
3415     ke
.m_metaDown 
= event
.m_metaDown
; 
3416     ke
.m_keyCode 
= event
.m_keyCode
; 
3419     ke
.SetEventObject( parent 
); 
3420     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3425 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
3427     wxWindow 
*parent 
= GetParent(); 
3429     // send a list_key event up 
3432         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
3433         le
.m_itemIndex 
= m_current
; 
3434         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3435         le
.m_code 
= event
.GetKeyCode(); 
3436         le
.SetEventObject( parent 
); 
3437         parent
->GetEventHandler()->ProcessEvent( le 
); 
3440     // propagate the char event upwards 
3441     wxKeyEvent 
ke( wxEVT_CHAR 
); 
3442     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3443     ke
.m_controlDown 
= event
.m_controlDown
; 
3444     ke
.m_altDown 
= event
.m_altDown
; 
3445     ke
.m_metaDown 
= event
.m_metaDown
; 
3446     ke
.m_keyCode 
= event
.m_keyCode
; 
3449     ke
.SetEventObject( parent 
); 
3450     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3452     if ( HandleAsNavigationKey(event
) ) 
3455     // no item -> nothing to do 
3462     // don't use m_linesPerPage directly as it might not be computed yet 
3463     const int pageSize 
= GetCountPerPage(); 
3464     wxCHECK_RET( pageSize
, _T("should have non zero page size") ); 
3466     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3468         if (event
.GetKeyCode() == WXK_RIGHT
) 
3469             event
.m_keyCode 
= WXK_LEFT
; 
3470         else if (event
.GetKeyCode() == WXK_LEFT
) 
3471             event
.m_keyCode 
= WXK_RIGHT
; 
3474     switch ( event
.GetKeyCode() ) 
3477             if ( m_current 
> 0 ) 
3478                 OnArrowChar( m_current 
- 1, event 
); 
3482             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
3483                 OnArrowChar( m_current 
+ 1, event 
); 
3488                 OnArrowChar( GetItemCount() - 1, event 
); 
3493                 OnArrowChar( 0, event 
); 
3498                 int steps 
= InReportView() ? pageSize 
- 1 
3499                                            : m_current 
% pageSize
; 
3501                 int index 
= m_current 
- steps
; 
3505                 OnArrowChar( index
, event 
); 
3511                 int steps 
= InReportView() 
3513                                 : pageSize 
- (m_current 
% pageSize
) - 1; 
3515                 size_t index 
= m_current 
+ steps
; 
3516                 size_t count 
= GetItemCount(); 
3517                 if ( index 
>= count 
) 
3520                 OnArrowChar( index
, event 
); 
3525             if ( !InReportView() ) 
3527                 int index 
= m_current 
- pageSize
; 
3531                 OnArrowChar( index
, event 
); 
3536             if ( !InReportView() ) 
3538                 size_t index 
= m_current 
+ pageSize
; 
3540                 size_t count 
= GetItemCount(); 
3541                 if ( index 
>= count 
) 
3544                 OnArrowChar( index
, event 
); 
3549             if ( IsSingleSel() ) 
3551                 if ( event
.ControlDown() ) 
3553                     ReverseHighlight(m_current
); 
3555                 else // normal space press 
3557                     SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3560             else // multiple selection 
3562                 ReverseHighlight(m_current
); 
3568             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3576 // ---------------------------------------------------------------------------- 
3578 // ---------------------------------------------------------------------------- 
3580 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3584         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3585         event
.SetEventObject( GetParent() ); 
3586         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3590     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
3591     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
3592     // which are already drawn correctly resulting in horrible flicker - avoid 
3602 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3606         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
3607         event
.SetEventObject( GetParent() ); 
3608         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3616 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3618     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3620         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3622     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3624         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3626     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3628         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3630     else if ( InReportView() && (m_small_image_list
)) 
3632         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3636 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3638     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3640         m_normal_image_list
->GetSize( index
, width
, height 
); 
3642     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3644         m_small_image_list
->GetSize( index
, width
, height 
); 
3646     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3648         m_small_image_list
->GetSize( index
, width
, height 
); 
3650     else if ( InReportView() && m_small_image_list 
) 
3652         m_small_image_list
->GetSize( index
, width
, height 
); 
3661 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3663     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3664     dc
.SetFont( GetFont() ); 
3667     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3669     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3672 void wxListMainWindow::SetImageList( wxImageList 
*imageList
, int which 
) 
3676     // calc the spacing from the icon size 
3677     int width 
= 0, height 
= 0; 
3679     if ((imageList
) && (imageList
->GetImageCount()) ) 
3680         imageList
->GetSize(0, width
, height
); 
3682     if (which 
== wxIMAGE_LIST_NORMAL
) 
3684         m_normal_image_list 
= imageList
; 
3685         m_normal_spacing 
= width 
+ 8; 
3688     if (which 
== wxIMAGE_LIST_SMALL
) 
3690         m_small_image_list 
= imageList
; 
3691         m_small_spacing 
= width 
+ 14; 
3692         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
3696 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3700         m_small_spacing 
= spacing
; 
3702         m_normal_spacing 
= spacing
; 
3705 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3707     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3710 // ---------------------------------------------------------------------------- 
3712 // ---------------------------------------------------------------------------- 
3714 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3716     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3718     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3720     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3721         item
.m_width 
= GetTextLength( item
.m_text 
); 
3723     wxListHeaderData 
*column 
= node
->GetData(); 
3724     column
->SetItem( item 
); 
3726     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3728         headerWin
->m_dirty 
= true; 
3732     // invalidate it as it has to be recalculated 
3736 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3738     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3739                  _T("invalid column index") ); 
3741     wxCHECK_RET( InReportView(), 
3742                  _T("SetColumnWidth() can only be called in report mode.") ); 
3745     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3747         headerWin
->m_dirty 
= true; 
3749     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3750     wxCHECK_RET( node
, _T("no column?") ); 
3752     wxListHeaderData 
*column 
= node
->GetData(); 
3754     size_t count 
= GetItemCount(); 
3756     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3758         width 
= GetTextLength(column
->GetText()); 
3759         width 
+= 2*EXTRA_WIDTH
; 
3761         // check for column header's image availability 
3762         const int image 
= column
->GetImage(); 
3765             if ( m_small_image_list 
) 
3768                 m_small_image_list
->GetSize(image
, ix
, iy
); 
3769                 width 
+= ix 
+ HEADER_IMAGE_MARGIN_IN_REPORT_MODE
; 
3773     else if ( width 
== wxLIST_AUTOSIZE 
) 
3777             // TODO: determine the max width somehow... 
3778             width 
= WIDTH_COL_DEFAULT
; 
3782             wxClientDC 
dc(this); 
3783             dc
.SetFont( GetFont() ); 
3785             int max 
= AUTOSIZE_COL_MARGIN
; 
3787             //  if the cached column width isn't valid then recalculate it 
3788             if (m_aColWidths
.Item(col
)->bNeedsUpdate
) 
3790                 for (size_t i 
= 0; i 
< count
; i
++) 
3792                     wxListLineData 
*line 
= GetLine( i 
); 
3793                     wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3795                     wxCHECK_RET( n
, _T("no subitem?") ); 
3797                     wxListItemData 
*itemData 
= n
->GetData(); 
3800                     itemData
->GetItem(item
); 
3801                     int itemWidth 
= GetItemWidthWithImage(&item
); 
3802                     if (itemWidth 
> max
) 
3806                 m_aColWidths
.Item(col
)->bNeedsUpdate 
= false; 
3807                 m_aColWidths
.Item(col
)->nMaxWidth 
= max
; 
3810             max 
= m_aColWidths
.Item(col
)->nMaxWidth
; 
3811             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3815     column
->SetWidth( width 
); 
3817     // invalidate it as it has to be recalculated 
3821 int wxListMainWindow::GetHeaderWidth() const 
3823     if ( !m_headerWidth 
) 
3825         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3827         size_t count 
= GetColumnCount(); 
3828         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3830             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3834     return m_headerWidth
; 
3837 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3839     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3840     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3842     wxListHeaderData 
*column 
= node
->GetData(); 
3843     column
->GetItem( item 
); 
3846 int wxListMainWindow::GetColumnWidth( int col 
) const 
3848     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3849     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3851     wxListHeaderData 
*column 
= node
->GetData(); 
3852     return column
->GetWidth(); 
3855 // ---------------------------------------------------------------------------- 
3857 // ---------------------------------------------------------------------------- 
3859 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3861     long id 
= item
.m_itemId
; 
3862     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3863                  _T("invalid item index in SetItem") ); 
3867         wxListLineData 
*line 
= GetLine((size_t)id
); 
3868         line
->SetItem( item
.m_col
, item 
); 
3870         // Set item state if user wants 
3871         if ( item
.m_mask 
& wxLIST_MASK_STATE 
) 
3872             SetItemState( item
.m_itemId
, item
.m_state
, item
.m_state 
); 
3876             //  update the Max Width Cache if needed 
3877             int width 
= GetItemWidthWithImage(&item
); 
3879             if (width 
> m_aColWidths
.Item(item
.m_col
)->nMaxWidth
) 
3880                 m_aColWidths
.Item(item
.m_col
)->nMaxWidth 
= width
; 
3884     // update the item on screen 
3886     GetItemRect(id
, rectItem
); 
3887     RefreshRect(rectItem
); 
3890 void wxListMainWindow::SetItemStateAll(long state
, long stateMask
) 
3895     // first deal with selection 
3896     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3898         // set/clear select state 
3901             // optimized version for virtual listctrl. 
3902             m_selStore
.SelectRange(0, GetItemCount() - 1, state 
== wxLIST_STATE_SELECTED
); 
3905         else if ( state 
& wxLIST_STATE_SELECTED 
) 
3907             const long count 
= GetItemCount(); 
3908             for( long i 
= 0; i 
<  count
; i
++ ) 
3910                 SetItemState( i
, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED 
); 
3916             // clear for non virtual (somewhat optimized by using GetNextItem()) 
3918             while ( (i 
= GetNextItem(i
, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
)) != -1 ) 
3920                 SetItemState( i
, 0, wxLIST_STATE_SELECTED 
); 
3925     if ( HasCurrent() && (state 
== 0) && (stateMask 
& wxLIST_STATE_FOCUSED
) ) 
3927         // unfocus all: only one item can be focussed, so clearing focus for 
3928         // all items is simply clearing focus of the focussed item. 
3929         SetItemState(m_current
, state
, stateMask
); 
3931     //(setting focus to all items makes no sense, so it is not handled here.) 
3934 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3938         SetItemStateAll(state
, stateMask
); 
3942     wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3943                  _T("invalid list ctrl item index in SetItem") ); 
3945     size_t oldCurrent 
= m_current
; 
3946     size_t item 
= (size_t)litem
;    // safe because of the check above 
3948     // do we need to change the focus? 
3949     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3951         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3953             // don't do anything if this item is already focused 
3954             if ( item 
!= m_current 
) 
3956                 ChangeCurrent(item
); 
3958                 if ( oldCurrent 
!= (size_t)-1 ) 
3960                     if ( IsSingleSel() ) 
3962                         HighlightLine(oldCurrent
, false); 
3965                     RefreshLine(oldCurrent
); 
3968                 RefreshLine( m_current 
); 
3973             // don't do anything if this item is not focused 
3974             if ( item 
== m_current 
) 
3978                 if ( IsSingleSel() ) 
3980                     // we must unselect the old current item as well or we 
3981                     // might end up with more than one selected item in a 
3982                     // single selection control 
3983                     HighlightLine(oldCurrent
, false); 
3986                 RefreshLine( oldCurrent 
); 
3991     // do we need to change the selection state? 
3992     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3994         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3996         if ( IsSingleSel() ) 
4000                 // selecting the item also makes it the focused one in the 
4002                 if ( m_current 
!= item 
) 
4004                     ChangeCurrent(item
); 
4006                     if ( oldCurrent 
!= (size_t)-1 ) 
4008                         HighlightLine( oldCurrent
, false ); 
4009                         RefreshLine( oldCurrent 
); 
4015                 // only the current item may be selected anyhow 
4016                 if ( item 
!= m_current 
) 
4021         if ( HighlightLine(item
, on
) ) 
4028 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
4030     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
4031                  _T("invalid list ctrl item index in GetItemState()") ); 
4033     int ret 
= wxLIST_STATE_DONTCARE
; 
4035     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
4037         if ( (size_t)item 
== m_current 
) 
4038             ret 
|= wxLIST_STATE_FOCUSED
; 
4041     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
4043         if ( IsHighlighted(item
) ) 
4044             ret 
|= wxLIST_STATE_SELECTED
; 
4050 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
4052     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
4053                  _T("invalid item index in GetItem") ); 
4055     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
4056     line
->GetItem( item
.m_col
, item 
); 
4058     // Get item state if user wants it 
4059     if ( item
.m_mask 
& wxLIST_MASK_STATE 
) 
4060         item
.m_state 
= GetItemState( item
.m_itemId
, wxLIST_STATE_SELECTED 
| 
4061                                                  wxLIST_STATE_FOCUSED 
); 
4064 // ---------------------------------------------------------------------------- 
4066 // ---------------------------------------------------------------------------- 
4068 size_t wxListMainWindow::GetItemCount() const 
4070     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
4073 void wxListMainWindow::SetItemCount(long count
) 
4075     m_selStore
.SetItemCount(count
); 
4076     m_countVirt 
= count
; 
4078     ResetVisibleLinesRange(); 
4080     // scrollbars must be reset 
4084 int wxListMainWindow::GetSelectedItemCount() const 
4086     // deal with the quick case first 
4087     if ( IsSingleSel() ) 
4088         return HasCurrent() ? IsHighlighted(m_current
) : false; 
4090     // virtual controls remmebers all its selections itself 
4092         return m_selStore
.GetSelectedCount(); 
4094     // TODO: we probably should maintain the number of items selected even for 
4095     //       non virtual controls as enumerating all lines is really slow... 
4096     size_t countSel 
= 0; 
4097     size_t count 
= GetItemCount(); 
4098     for ( size_t line 
= 0; line 
< count
; line
++ ) 
4100         if ( GetLine(line
)->IsHighlighted() ) 
4107 // ---------------------------------------------------------------------------- 
4108 // item position/size 
4109 // ---------------------------------------------------------------------------- 
4111 wxRect 
wxListMainWindow::GetViewRect() const 
4113     wxASSERT_MSG( !HasFlag(wxLC_REPORT 
| wxLC_LIST
), 
4114                     _T("wxListCtrl::GetViewRect() only works in icon mode") ); 
4116     // we need to find the longest/tallest label 
4117     wxCoord xMax 
= 0, yMax 
= 0; 
4118     const int count 
= GetItemCount(); 
4121         for ( int i 
= 0; i 
< count
; i
++ ) 
4126             wxCoord x 
= r
.GetRight(), 
4136     // some fudge needed to make it look prettier 
4137     xMax 
+= 2 * EXTRA_BORDER_X
; 
4138     yMax 
+= 2 * EXTRA_BORDER_Y
; 
4140     // account for the scrollbars if necessary 
4141     const wxSize sizeAll 
= GetClientSize(); 
4142     if ( xMax 
> sizeAll
.x 
) 
4143         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
4144     if ( yMax 
> sizeAll
.y 
) 
4145         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
4147     return wxRect(0, 0, xMax
, yMax
); 
4150 void wxListMainWindow::GetItemRect( long index
, wxRect 
&rect 
) const 
4152     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4153                  _T("invalid index in GetItemRect") ); 
4155     // ensure that we're laid out, otherwise we could return nonsense 
4158         wxConstCast(this, wxListMainWindow
)-> 
4159             RecalculatePositions(true /* no refresh */); 
4162     rect 
= GetLineRect((size_t)index
); 
4164     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
4167 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
4170     GetItemRect(item
, rect
); 
4178 // ---------------------------------------------------------------------------- 
4179 // geometry calculation 
4180 // ---------------------------------------------------------------------------- 
4182 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
4184     const int lineHeight 
= GetLineHeight(); 
4186     wxClientDC 
dc( this ); 
4187     dc
.SetFont( GetFont() ); 
4189     const size_t count 
= GetItemCount(); 
4192     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
4193         iconSpacing 
= m_normal_spacing
; 
4194     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
4195         iconSpacing 
= m_small_spacing
; 
4199     // Note that we do not call GetClientSize() here but 
4200     // GetSize() and subtract the border size for sunken 
4201     // borders manually. This is technically incorrect, 
4202     // but we need to know the client area's size WITHOUT 
4203     // scrollbars here. Since we don't know if there are 
4204     // any scrollbars, we use GetSize() instead. Another 
4205     // solution would be to call SetScrollbars() here to 
4206     // remove the scrollbars and call GetClientSize() then, 
4207     // but this might result in flicker and - worse - will 
4208     // reset the scrollbars to 0 which is not good at all 
4209     // if you resize a dialog/window, but don't want to 
4210     // reset the window scrolling. RR. 
4211     // Furthermore, we actually do NOT subtract the border 
4212     // width as 2 pixels is just the extra space which we 
4213     // need around the actual content in the window. Other- 
4214     // wise the text would e.g. touch the upper border. RR. 
4217     GetSize( &clientWidth
, &clientHeight 
); 
4219     if ( InReportView() ) 
4221         // all lines have the same height and we scroll one line per step 
4222         int entireHeight 
= count 
* lineHeight 
+ LINE_SPACING
; 
4224         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
4226         ResetVisibleLinesRange(); 
4228         SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
4229                        GetHeaderWidth() / SCROLL_UNIT_X
, 
4230                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
4231                        GetScrollPos(wxHORIZONTAL
), 
4232                        GetScrollPos(wxVERTICAL
), 
4237         // we have 3 different layout strategies: either layout all items 
4238         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
4239         // to arrange them in top to bottom, left to right (don't ask me why 
4240         // not the other way round...) order 
4241         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
4243             int x 
= EXTRA_BORDER_X
; 
4244             int y 
= EXTRA_BORDER_Y
; 
4246             wxCoord widthMax 
= 0; 
4249             for ( i 
= 0; i 
< count
; i
++ ) 
4251                 wxListLineData 
*line 
= GetLine(i
); 
4252                 line
->CalculateSize( &dc
, iconSpacing 
); 
4253                 line
->SetPosition( x
, y
, iconSpacing 
); 
4255                 wxSize sizeLine 
= GetLineSize(i
); 
4257                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
4259                     if ( sizeLine
.x 
> widthMax 
) 
4260                         widthMax 
= sizeLine
.x
; 
4264                 else // wxLC_ALIGN_LEFT 
4266                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
4270             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
4272                 // traverse the items again and tweak their sizes so that they are 
4273                 // all the same in a row 
4274                 for ( i 
= 0; i 
< count
; i
++ ) 
4276                     wxListLineData 
*line 
= GetLine(i
); 
4277                     line
->m_gi
->ExtendWidth(widthMax
); 
4285                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4286                 (y 
+ lineHeight
) / lineHeight
, 
4287                 GetScrollPos( wxHORIZONTAL 
), 
4288                 GetScrollPos( wxVERTICAL 
), 
4292         else // "flowed" arrangement, the most complicated case 
4294             // at first we try without any scrollbars, if the items don't fit into 
4295             // the window, we recalculate after subtracting the space taken by the 
4298             int entireWidth 
= 0; 
4300             for (int tries 
= 0; tries 
< 2; tries
++) 
4302                 entireWidth 
= 2 * EXTRA_BORDER_X
; 
4306                     // Now we have decided that the items do not fit into the 
4307                     // client area, so we need a scrollbar 
4308                     entireWidth 
+= SCROLL_UNIT_X
; 
4311                 int x 
= EXTRA_BORDER_X
; 
4312                 int y 
= EXTRA_BORDER_Y
; 
4313                 int maxWidthInThisRow 
= 0; 
4316                 int currentlyVisibleLines 
= 0; 
4318                 for (size_t i 
= 0; i 
< count
; i
++) 
4320                     currentlyVisibleLines
++; 
4321                     wxListLineData 
*line 
= GetLine( i 
); 
4322                     line
->CalculateSize( &dc
, iconSpacing 
); 
4323                     line
->SetPosition( x
, y
, iconSpacing 
); 
4325                     wxSize sizeLine 
= GetLineSize( i 
); 
4327                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
4328                         maxWidthInThisRow 
= sizeLine
.x
; 
4331                     if (currentlyVisibleLines 
> m_linesPerPage
) 
4332                         m_linesPerPage 
= currentlyVisibleLines
; 
4334                     if ( y 
+ sizeLine
.y 
>= clientHeight 
) 
4336                         currentlyVisibleLines 
= 0; 
4338                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
4339                         x 
+= maxWidthInThisRow
; 
4340                         entireWidth 
+= maxWidthInThisRow
; 
4341                         maxWidthInThisRow 
= 0; 
4344                     // We have reached the last item. 
4345                     if ( i 
== count 
- 1 ) 
4346                         entireWidth 
+= maxWidthInThisRow
; 
4348                     if ( (tries 
== 0) && 
4349                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
4351                         clientHeight 
-= wxSystemSettings:: 
4352                                             GetMetric(wxSYS_HSCROLL_Y
); 
4357                     if ( i 
== count 
- 1 ) 
4358                         tries 
= 1;  // Everything fits, no second try required. 
4366                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4368                 GetScrollPos( wxHORIZONTAL 
), 
4377         // FIXME: why should we call it from here? 
4384 void wxListMainWindow::RefreshAll() 
4389     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
4390     if ( headerWin 
&& headerWin
->m_dirty 
) 
4392         headerWin
->m_dirty 
= false; 
4393         headerWin
->Refresh(); 
4397 void wxListMainWindow::UpdateCurrent() 
4399     if ( !HasCurrent() && !IsEmpty() ) 
4403 long wxListMainWindow::GetNextItem( long item
, 
4404                                     int WXUNUSED(geometry
), 
4408          max 
= GetItemCount(); 
4409     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
4410                  _T("invalid listctrl index in GetNextItem()") ); 
4412     // notice that we start with the next item (or the first one if item == -1) 
4413     // and this is intentional to allow writing a simple loop to iterate over 
4414     // all selected items 
4417         // this is not an error because the index was OK initially, 
4418         // just no such item 
4425     size_t count 
= GetItemCount(); 
4426     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
4428         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
4431         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
4438 // ---------------------------------------------------------------------------- 
4440 // ---------------------------------------------------------------------------- 
4442 void wxListMainWindow::DeleteItem( long lindex 
) 
4444     size_t count 
= GetItemCount(); 
4446     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
4447                  _T("invalid item index in DeleteItem") ); 
4449     size_t index 
= (size_t)lindex
; 
4451     // we don't need to adjust the index for the previous items 
4452     if ( HasCurrent() && m_current 
>= index 
) 
4454         // if the current item is being deleted, we want the next one to 
4455         // become selected - unless there is no next one - so don't adjust 
4456         // m_current in this case 
4457         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
4461     if ( InReportView() ) 
4463         //  mark the Column Max Width cache as dirty if the items in the line 
4464         //  we're deleting contain the Max Column Width 
4465         wxListLineData 
* const line 
= GetLine(index
); 
4466         wxListItemDataList::compatibility_iterator n
; 
4467         wxListItemData 
*itemData
; 
4471         for (size_t i 
= 0; i 
< m_columns
.GetCount(); i
++) 
4473             n 
= line
->m_items
.Item( i 
); 
4474             itemData 
= n
->GetData(); 
4475             itemData
->GetItem(item
); 
4477             itemWidth 
= GetItemWidthWithImage(&item
); 
4479             if (itemWidth 
>= m_aColWidths
.Item(i
)->nMaxWidth
) 
4480                 m_aColWidths
.Item(i
)->bNeedsUpdate 
= true; 
4483         ResetVisibleLinesRange(); 
4486     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
, wxDefaultPosition 
); 
4491         m_selStore
.OnItemDelete(index
); 
4495         m_lines
.RemoveAt( index 
); 
4498     // we need to refresh the (vert) scrollbar as the number of items changed 
4501     RefreshAfter(index
); 
4504 void wxListMainWindow::DeleteColumn( int col 
) 
4506     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4508     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
4511     delete node
->GetData(); 
4512     m_columns
.Erase( node 
); 
4516         // update all the items 
4517         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4519             wxListLineData 
* const line 
= GetLine(i
); 
4520             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
4521             delete n
->GetData(); 
4522             line
->m_items
.Erase(n
); 
4526     if ( InReportView() )   //  we only cache max widths when in Report View 
4528         delete m_aColWidths
.Item(col
); 
4529         m_aColWidths
.RemoveAt(col
); 
4532     // invalidate it as it has to be recalculated 
4536 void wxListMainWindow::DoDeleteAllItems() 
4539         // nothing to do - in particular, don't send the event 
4544     // to make the deletion of all items faster, we don't send the 
4545     // notifications for each item deletion in this case but only one event 
4546     // for all of them: this is compatible with wxMSW and documented in 
4547     // DeleteAllItems() description 
4549     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
4550     event
.SetEventObject( GetParent() ); 
4551     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
4559     if ( InReportView() ) 
4561         ResetVisibleLinesRange(); 
4562         for (size_t i 
= 0; i 
< m_aColWidths
.GetCount(); i
++) 
4564             m_aColWidths
.Item(i
)->bNeedsUpdate 
= true; 
4571 void wxListMainWindow::DeleteAllItems() 
4575     RecalculatePositions(); 
4578 void wxListMainWindow::DeleteEverything() 
4580     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
4581     WX_CLEAR_ARRAY(m_aColWidths
); 
4586 // ---------------------------------------------------------------------------- 
4587 // scanning for an item 
4588 // ---------------------------------------------------------------------------- 
4590 void wxListMainWindow::EnsureVisible( long index 
) 
4592     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4593                  _T("invalid index in EnsureVisible") ); 
4595     // We have to call this here because the label in question might just have 
4596     // been added and its position is not known yet 
4598         RecalculatePositions(true /* no refresh */); 
4600     MoveToItem((size_t)index
); 
4603 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool partial 
) 
4609     wxString str_upper 
= str
.Upper(); 
4613     size_t count 
= GetItemCount(); 
4614     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
4616         wxListLineData 
*line 
= GetLine(i
); 
4617         wxString line_upper 
= line
->GetText(0).Upper(); 
4620             if (line_upper 
== str_upper 
) 
4625             if (line_upper
.find(str_upper
) == 0) 
4633 long wxListMainWindow::FindItem(long start
, wxUIntPtr data
) 
4639     size_t count 
= GetItemCount(); 
4640     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4642         wxListLineData 
*line 
= GetLine(i
); 
4644         line
->GetItem( 0, item 
); 
4645         if (item
.m_data 
== data
) 
4652 long wxListMainWindow::FindItem( const wxPoint
& pt 
) 
4655     GetVisibleLinesRange( &topItem
, NULL 
); 
4658     GetItemPosition( GetItemCount() - 1, p 
); 
4662     long id 
= (long)floor( pt
.y 
* double(GetItemCount() - topItem 
- 1) / p
.y 
+ topItem 
); 
4663     if ( id 
>= 0 && id 
< (long)GetItemCount() ) 
4669 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) const 
4671     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4673     size_t count 
= GetItemCount(); 
4675     if ( InReportView() ) 
4677         size_t current 
= y 
/ GetLineHeight(); 
4678         if ( current 
< count 
) 
4680             flags 
= HitTestLine(current
, x
, y
); 
4687         // TODO: optimize it too! this is less simple than for report view but 
4688         //       enumerating all items is still not a way to do it!! 
4689         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4691             flags 
= HitTestLine(current
, x
, y
); 
4700 // ---------------------------------------------------------------------------- 
4702 // ---------------------------------------------------------------------------- 
4704 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4706     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
4708     int count 
= GetItemCount(); 
4709     wxCHECK_RET( item
.m_itemId 
>= 0, _T("invalid item index") ); 
4711     if (item
.m_itemId 
> count
) 
4712         item
.m_itemId 
= count
; 
4714     size_t id 
= item
.m_itemId
; 
4718     if ( InReportView() ) 
4720         ResetVisibleLinesRange(); 
4722         // calculate the width of the item and adjust the max column width 
4723         wxColWidthInfo 
*pWidthInfo 
= m_aColWidths
.Item(item
.GetColumn()); 
4724         int width 
= GetItemWidthWithImage(&item
); 
4725         item
.SetWidth(width
); 
4726         if (width 
> pWidthInfo
->nMaxWidth
) 
4727             pWidthInfo
->nMaxWidth 
= width
; 
4730     wxListLineData 
*line 
= new wxListLineData(this); 
4732     line
->SetItem( item
.m_col
, item 
); 
4734     m_lines
.Insert( line
, id 
); 
4738     // If an item is selected at or below the point of insertion, we need to 
4739     // increment the member variables because the current row's index has gone 
4741     if ( HasCurrent() && m_current 
>= id 
) 
4744     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4746     RefreshLines(id
, GetItemCount() - 1); 
4749 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4752     if ( InReportView() ) 
4754         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4755             item
.m_width 
= GetTextLength( item
.m_text 
); 
4757         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4758         wxColWidthInfo 
*colWidthInfo 
= new wxColWidthInfo(); 
4760         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4763             wxListHeaderDataList::compatibility_iterator
 
4764                 node 
= m_columns
.Item( col 
); 
4765             m_columns
.Insert( node
, column 
); 
4766             m_aColWidths
.Insert( colWidthInfo
, col 
); 
4770             m_columns
.Append( column 
); 
4771             m_aColWidths
.Add( colWidthInfo 
); 
4776             // update all the items 
4777             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4779                 wxListLineData 
* const line 
= GetLine(i
); 
4780                 wxListItemData 
* const data 
= new wxListItemData(this); 
4782                     line
->m_items
.Insert(col
, data
); 
4784                     line
->m_items
.Append(data
); 
4788         // invalidate it as it has to be recalculated 
4793 int wxListMainWindow::GetItemWidthWithImage(wxListItem 
* item
) 
4796     wxClientDC 
dc(this); 
4798     dc
.SetFont( GetFont() ); 
4800     if (item
->GetImage() != -1) 
4803         GetImageSize( item
->GetImage(), ix
, iy 
); 
4807     if (!item
->GetText().empty()) 
4810         dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
4817 // ---------------------------------------------------------------------------- 
4819 // ---------------------------------------------------------------------------- 
4821 wxListCtrlCompare list_ctrl_compare_func_2
; 
4822 long              list_ctrl_compare_data
; 
4824 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4826     wxListLineData 
*line1 
= *arg1
; 
4827     wxListLineData 
*line2 
= *arg2
; 
4829     line1
->GetItem( 0, item 
); 
4830     wxUIntPtr data1 
= item
.m_data
; 
4831     line2
->GetItem( 0, item 
); 
4832     wxUIntPtr data2 
= item
.m_data
; 
4833     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4836 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
4838     // selections won't make sense any more after sorting the items so reset 
4840     HighlightAll(false); 
4843     list_ctrl_compare_func_2 
= fn
; 
4844     list_ctrl_compare_data 
= data
; 
4845     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4849 // ---------------------------------------------------------------------------- 
4851 // ---------------------------------------------------------------------------- 
4853 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4856 #if ( defined(__WXGTK__) || defined(__WXMAC__) ) && !defined(__WXUNIVERSAL__) 
4857     wxScrolledCanvas::OnScroll(event
); 
4859     HandleOnScroll( event 
); 
4862     // update our idea of which lines are shown when we redraw the window the 
4864     ResetVisibleLinesRange(); 
4866     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4868         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4869         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4871         lc
->m_headerWin
->Refresh(); 
4872         lc
->m_headerWin
->Update(); 
4876 int wxListMainWindow::GetCountPerPage() const 
4878     if ( !m_linesPerPage 
) 
4880         wxConstCast(this, wxListMainWindow
)-> 
4881             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4884     return m_linesPerPage
; 
4887 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4889     wxASSERT_MSG( InReportView(), _T("this is for report mode only") ); 
4891     if ( m_lineFrom 
== (size_t)-1 ) 
4893         size_t count 
= GetItemCount(); 
4896             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4898             // this may happen if SetScrollbars() hadn't been called yet 
4899             if ( m_lineFrom 
>= count 
) 
4900                 m_lineFrom 
= count 
- 1; 
4902             // we redraw one extra line but this is needed to make the redrawing 
4903             // logic work when there is a fractional number of lines on screen 
4904             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4905             if ( m_lineTo 
>= count 
) 
4906                 m_lineTo 
= count 
- 1; 
4908         else // empty control 
4911             m_lineTo 
= (size_t)-1; 
4915     wxASSERT_MSG( IsEmpty() || 
4916                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4917                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4925 // ------------------------------------------------------------------------------------- 
4926 // wxGenericListCtrl 
4927 // ------------------------------------------------------------------------------------- 
4929 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4931 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4932   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4935 wxGenericListCtrl::wxGenericListCtrl() 
4937     m_imageListNormal 
= (wxImageList 
*) NULL
; 
4938     m_imageListSmall 
= (wxImageList 
*) NULL
; 
4939     m_imageListState 
= (wxImageList 
*) NULL
; 
4941     m_ownsImageListNormal 
= 
4942     m_ownsImageListSmall 
= 
4943     m_ownsImageListState 
= false; 
4945     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4946     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4950 wxGenericListCtrl::~wxGenericListCtrl() 
4952     if (m_ownsImageListNormal
) 
4953         delete m_imageListNormal
; 
4954     if (m_ownsImageListSmall
) 
4955         delete m_imageListSmall
; 
4956     if (m_ownsImageListState
) 
4957         delete m_imageListState
; 
4960 void wxGenericListCtrl::CalculateAndSetHeaderHeight() 
4966         GetThemeMetric( kThemeMetricListHeaderHeight
, &h 
); 
4968         // we use 'g' to get the descent, too 
4970         m_headerWin
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
); 
4971         h 
+= d 
+ 2 * HEADER_OFFSET_Y 
+ EXTRA_HEIGHT
; 
4974         // only update if changed 
4975         if ( h 
!= m_headerHeight 
) 
4980                 ResizeReportView(true); 
4981             else    //why is this needed if it doesn't have a header? 
4982                 m_headerWin
->SetSize(m_headerWin
->GetSize().x
, m_headerHeight
); 
4987 void wxGenericListCtrl::CreateHeaderWindow() 
4989     m_headerWin 
= new wxListHeaderWindow
 
4991                         this, wxID_ANY
, m_mainWin
, 
4993                         wxSize(GetClientSize().x
, m_headerHeight
), 
4996     CalculateAndSetHeaderHeight(); 
4999 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
5004                         const wxValidator 
&validator
, 
5005                         const wxString 
&name
) 
5009     m_imageListState 
= (wxImageList 
*) NULL
; 
5010     m_ownsImageListNormal 
= 
5011     m_ownsImageListSmall 
= 
5012     m_ownsImageListState 
= false; 
5014     m_mainWin 
= (wxListMainWindow
*) NULL
; 
5015     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
5019     if ( !(style 
& wxLC_MASK_TYPE
) ) 
5021         style 
= style 
| wxLC_LIST
; 
5024     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
5027     // this window itself shouldn't get the focus, only m_mainWin should 
5030     // don't create the inner window with the border 
5031     style 
&= ~wxBORDER_MASK
; 
5033     m_mainWin 
= new wxListMainWindow( this, wxID_ANY
, wxPoint(0, 0), size
, style 
); 
5036     // Human Interface Guidelines ask us for a special font in this case 
5037     if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL 
) 
5040         font
.MacCreateFromThemeFont( kThemeViewsFont 
); 
5045     if ( InReportView() ) 
5047         CreateHeaderWindow(); 
5053             font
.MacCreateFromThemeFont( kThemeSmallSystemFont 
); 
5054             m_headerWin
->SetFont( font 
); 
5055             CalculateAndSetHeaderHeight(); 
5059         if ( HasFlag(wxLC_NO_HEADER
) ) 
5060             // VZ: why do we create it at all then? 
5061             m_headerWin
->Show( false ); 
5064     SetInitialSize(size
); 
5069 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
5071     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
5072                   _T("wxLC_VIRTUAL can't be [un]set") ); 
5074     long flag 
= GetWindowStyle(); 
5078         if (style 
& wxLC_MASK_TYPE
) 
5079             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
5080         if (style 
& wxLC_MASK_ALIGN
) 
5081             flag 
&= ~wxLC_MASK_ALIGN
; 
5082         if (style 
& wxLC_MASK_SORT
) 
5083             flag 
&= ~wxLC_MASK_SORT
; 
5091     SetWindowStyleFlag( flag 
); 
5094 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
5098         m_mainWin
->DeleteEverything(); 
5100         // has the header visibility changed? 
5101         bool hasHeader 
= HasHeader(); 
5102         bool willHaveHeader 
= (flag 
& wxLC_REPORT
) && !(flag 
& wxLC_NO_HEADER
); 
5104         if ( hasHeader 
!= willHaveHeader 
) 
5111                     // don't delete, just hide, as we can reuse it later 
5112                     m_headerWin
->Show(false); 
5114                 //else: nothing to do 
5116             else // must show header 
5120                     CreateHeaderWindow(); 
5122                 else // already have it, just show 
5124                     m_headerWin
->Show( true ); 
5128             ResizeReportView(willHaveHeader
); 
5132     wxWindow::SetWindowStyleFlag( flag 
); 
5135 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
5137     m_mainWin
->GetColumn( col
, item 
); 
5141 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
5143     m_mainWin
->SetColumn( col
, item 
); 
5147 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
5149     return m_mainWin
->GetColumnWidth( col 
); 
5152 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
5154     m_mainWin
->SetColumnWidth( col
, width 
); 
5158 int wxGenericListCtrl::GetCountPerPage() const 
5160   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
5163 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
5165     m_mainWin
->GetItem( info 
); 
5169 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
5171     m_mainWin
->SetItem( info 
); 
5175 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
5178     info
.m_text 
= label
; 
5179     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5180     info
.m_itemId 
= index
; 
5184         info
.m_image 
= imageId
; 
5185         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
5188     m_mainWin
->SetItem(info
); 
5192 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
5194     return m_mainWin
->GetItemState( item
, stateMask 
); 
5197 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
5199     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
5204 wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
5206     return SetItemColumnImage(item
, 0, image
); 
5210 wxGenericListCtrl::SetItemColumnImage( long item
, long column
, int image 
) 
5213     info
.m_image 
= image
; 
5214     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5215     info
.m_itemId 
= item
; 
5216     info
.m_col 
= column
; 
5217     m_mainWin
->SetItem( info 
); 
5221 wxString 
wxGenericListCtrl::GetItemText( long item 
) const 
5223     return m_mainWin
->GetItemText(item
); 
5226 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
5228     m_mainWin
->SetItemText(item
, str
); 
5231 wxUIntPtr 
wxGenericListCtrl::GetItemData( long item 
) const 
5234     info
.m_mask 
= wxLIST_MASK_DATA
; 
5235     info
.m_itemId 
= item
; 
5236     m_mainWin
->GetItem( info 
); 
5240 bool wxGenericListCtrl::SetItemPtrData( long item
, wxUIntPtr data 
) 
5243     info
.m_mask 
= wxLIST_MASK_DATA
; 
5244     info
.m_itemId 
= item
; 
5246     m_mainWin
->SetItem( info 
); 
5250 wxRect 
wxGenericListCtrl::GetViewRect() const 
5252     return m_mainWin
->GetViewRect(); 
5255 bool wxGenericListCtrl::GetItemRect( long item
, wxRect 
&rect
, int WXUNUSED(code
) ) const 
5257     m_mainWin
->GetItemRect( item
, rect 
); 
5258     if ( m_mainWin
->HasHeader() ) 
5259         rect
.y 
+= m_headerHeight 
+ 1; 
5263 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
5265     m_mainWin
->GetItemPosition( item
, pos 
); 
5269 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
5274 int wxGenericListCtrl::GetItemCount() const 
5276     return m_mainWin
->GetItemCount(); 
5279 int wxGenericListCtrl::GetColumnCount() const 
5281     return m_mainWin
->GetColumnCount(); 
5284 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
5286     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
5289 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
5291     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
5293     return wxSize(spacing
, spacing
); 
5296 #if WXWIN_COMPATIBILITY_2_6 
5297 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
5299     return m_mainWin
->GetItemSpacing( isSmall 
); 
5301 #endif // WXWIN_COMPATIBILITY_2_6 
5303 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
5306     info
.m_itemId 
= item
; 
5307     info
.SetTextColour( col 
); 
5308     m_mainWin
->SetItem( info 
); 
5311 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
5314     info
.m_itemId 
= item
; 
5315     m_mainWin
->GetItem( info 
); 
5316     return info
.GetTextColour(); 
5319 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
5322     info
.m_itemId 
= item
; 
5323     info
.SetBackgroundColour( col 
); 
5324     m_mainWin
->SetItem( info 
); 
5327 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
5330     info
.m_itemId 
= item
; 
5331     m_mainWin
->GetItem( info 
); 
5332     return info
.GetBackgroundColour(); 
5335 int wxGenericListCtrl::GetScrollPos( int orient 
) const 
5337     return m_mainWin
->GetScrollPos( orient 
); 
5340 void wxGenericListCtrl::SetScrollPos( int orient
, int pos
, bool refresh 
) 
5342     m_mainWin
->SetScrollPos( orient
, pos
, refresh 
); 
5345 void wxGenericListCtrl::SetItemFont( long item
, const wxFont 
&f 
) 
5348     info
.m_itemId 
= item
; 
5350     m_mainWin
->SetItem( info 
); 
5353 wxFont 
wxGenericListCtrl::GetItemFont( long item 
) const 
5356     info
.m_itemId 
= item
; 
5357     m_mainWin
->GetItem( info 
); 
5358     return info
.GetFont(); 
5361 int wxGenericListCtrl::GetSelectedItemCount() const 
5363     return m_mainWin
->GetSelectedItemCount(); 
5366 wxColour 
wxGenericListCtrl::GetTextColour() const 
5368     return GetForegroundColour(); 
5371 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
5373     SetForegroundColour(col
); 
5376 long wxGenericListCtrl::GetTopItem() const 
5379     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
5383 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
5385     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
5388 wxImageList 
*wxGenericListCtrl::GetImageList(int which
) const 
5390     if (which 
== wxIMAGE_LIST_NORMAL
) 
5391         return m_imageListNormal
; 
5392     else if (which 
== wxIMAGE_LIST_SMALL
) 
5393         return m_imageListSmall
; 
5394     else if (which 
== wxIMAGE_LIST_STATE
) 
5395         return m_imageListState
; 
5397     return (wxImageList 
*) NULL
; 
5400 void wxGenericListCtrl::SetImageList( wxImageList 
*imageList
, int which 
) 
5402     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5404         if (m_ownsImageListNormal
) 
5405             delete m_imageListNormal
; 
5406         m_imageListNormal 
= imageList
; 
5407         m_ownsImageListNormal 
= false; 
5409     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5411         if (m_ownsImageListSmall
) 
5412             delete m_imageListSmall
; 
5413         m_imageListSmall 
= imageList
; 
5414         m_ownsImageListSmall 
= false; 
5416     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5418         if (m_ownsImageListState
) 
5419             delete m_imageListState
; 
5420         m_imageListState 
= imageList
; 
5421         m_ownsImageListState 
= false; 
5424     m_mainWin
->SetImageList( imageList
, which 
); 
5427 void wxGenericListCtrl::AssignImageList(wxImageList 
*imageList
, int which
) 
5429     SetImageList(imageList
, which
); 
5430     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5431         m_ownsImageListNormal 
= true; 
5432     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5433         m_ownsImageListSmall 
= true; 
5434     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5435         m_ownsImageListState 
= true; 
5438 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
5443 bool wxGenericListCtrl::DeleteItem( long item 
) 
5445     m_mainWin
->DeleteItem( item 
); 
5449 bool wxGenericListCtrl::DeleteAllItems() 
5451     m_mainWin
->DeleteAllItems(); 
5455 bool wxGenericListCtrl::DeleteAllColumns() 
5457     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
5458     for ( size_t n 
= 0; n 
< count
; n
++ ) 
5463 void wxGenericListCtrl::ClearAll() 
5465     m_mainWin
->DeleteEverything(); 
5468 bool wxGenericListCtrl::DeleteColumn( int col 
) 
5470     m_mainWin
->DeleteColumn( col 
); 
5472     // if we don't have the header any longer, we need to relayout the window 
5473     if ( !GetColumnCount() ) 
5474         ResizeReportView(false /* no header */); 
5478 wxTextCtrl 
*wxGenericListCtrl::EditLabel(long item
, 
5479                                          wxClassInfo
* textControlClass
) 
5481     return m_mainWin
->EditLabel( item
, textControlClass 
); 
5484 wxTextCtrl 
*wxGenericListCtrl::GetEditControl() const 
5486     return m_mainWin
->GetEditControl(); 
5489 bool wxGenericListCtrl::EnsureVisible( long item 
) 
5491     m_mainWin
->EnsureVisible( item 
); 
5495 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
, bool partial 
) 
5497     return m_mainWin
->FindItem( start
, str
, partial 
); 
5500 long wxGenericListCtrl::FindItem( long start
, wxUIntPtr data 
) 
5502     return m_mainWin
->FindItem( start
, data 
); 
5505 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& pt
, 
5506                            int WXUNUSED(direction
)) 
5508     return m_mainWin
->FindItem( pt 
); 
5511 // TODO: sub item hit testing 
5512 long wxGenericListCtrl::HitTest(const wxPoint
& point
, int& flags
, long *) const 
5514     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
5517 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
5519     m_mainWin
->InsertItem( info 
); 
5520     return info
.m_itemId
; 
5523 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
5526     info
.m_text 
= label
; 
5527     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5528     info
.m_itemId 
= index
; 
5529     return InsertItem( info 
); 
5532 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
5535     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5536     info
.m_image 
= imageIndex
; 
5537     info
.m_itemId 
= index
; 
5538     return InsertItem( info 
); 
5541 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
5544     info
.m_text 
= label
; 
5545     info
.m_image 
= imageIndex
; 
5546     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
5547     info
.m_itemId 
= index
; 
5548     return InsertItem( info 
); 
5551 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
5553     wxCHECK_MSG( m_headerWin
, -1, _T("can't add column in non report mode") ); 
5555     m_mainWin
->InsertColumn( col
, item 
); 
5557     // if we hadn't had a header before but have one now 
5558     // then we need to relayout the window 
5559     if ( GetColumnCount() == 1 && m_mainWin
->HasHeader() ) 
5560         ResizeReportView(true /* have header */); 
5562     m_headerWin
->Refresh(); 
5567 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
5568                                int format
, int width 
) 
5571     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
5572     item
.m_text 
= heading
; 
5575         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
5576         item
.m_width 
= width
; 
5579     item
.m_format 
= format
; 
5581     return InsertColumn( col
, item 
); 
5584 bool wxGenericListCtrl::ScrollList( int dx
, int dy 
) 
5586     return m_mainWin
->ScrollList(dx
, dy
); 
5590 // fn is a function which takes 3 long arguments: item1, item2, data. 
5591 // item1 is the long data associated with a first item (NOT the index). 
5592 // item2 is the long data associated with a second item (NOT the index). 
5593 // data is the same value as passed to SortItems. 
5594 // The return value is a negative number if the first item should precede the second 
5595 // item, a positive number of the second item should precede the first, 
5596 // or zero if the two items are equivalent. 
5597 // data is arbitrary data to be passed to the sort function. 
5599 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
5601     m_mainWin
->SortItems( fn
, data 
); 
5605 // ---------------------------------------------------------------------------- 
5607 // ---------------------------------------------------------------------------- 
5609 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
5614     ResizeReportView(m_mainWin
->HasHeader()); 
5615     m_mainWin
->RecalculatePositions(); 
5618 void wxGenericListCtrl::ResizeReportView(bool showHeader
) 
5621     GetClientSize( &cw
, &ch 
); 
5625         m_headerWin
->SetSize( 0, 0, cw
, m_headerHeight 
); 
5626         if(ch 
> m_headerHeight
) 
5627             m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, 
5628                                    cw
, ch 
- m_headerHeight 
- 1 ); 
5630             m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, 
5633     else // no header window 
5635         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
5639 void wxGenericListCtrl::OnInternalIdle() 
5641     wxWindow::OnInternalIdle(); 
5643     // do it only if needed 
5644     if ( !m_mainWin
->m_dirty 
) 
5647     m_mainWin
->RecalculatePositions(); 
5650 // ---------------------------------------------------------------------------- 
5652 // ---------------------------------------------------------------------------- 
5654 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5658         m_mainWin
->SetBackgroundColour( colour 
); 
5659         m_mainWin
->m_dirty 
= true; 
5665 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5667     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5672         m_mainWin
->SetForegroundColour( colour 
); 
5673         m_mainWin
->m_dirty 
= true; 
5677         m_headerWin
->SetForegroundColour( colour 
); 
5682 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5684     if ( !wxWindow::SetFont( font 
) ) 
5689         m_mainWin
->SetFont( font 
); 
5690         m_mainWin
->m_dirty 
= true; 
5695         m_headerWin
->SetFont( font 
); 
5696         CalculateAndSetHeaderHeight(); 
5706 wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
5709     // Use the same color scheme as wxListBox 
5710     return wxListBox::GetClassDefaultAttributes(variant
); 
5712     wxUnusedVar(variant
); 
5713     wxVisualAttributes attr
; 
5714     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
5715     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
5716     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
5721 // ---------------------------------------------------------------------------- 
5722 // methods forwarded to m_mainWin 
5723 // ---------------------------------------------------------------------------- 
5725 #if wxUSE_DRAG_AND_DROP 
5727 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5729     m_mainWin
->SetDropTarget( dropTarget 
); 
5732 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5734     return m_mainWin
->GetDropTarget(); 
5739 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5741     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : false; 
5744 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5746     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5749 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5751     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5754 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5757     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5763 void wxGenericListCtrl::DoClientToScreen( int *x
, int *y 
) const 
5765     m_mainWin
->DoClientToScreen(x
, y
); 
5768 void wxGenericListCtrl::DoScreenToClient( int *x
, int *y 
) const 
5770     m_mainWin
->DoScreenToClient(x
, y
); 
5773 void wxGenericListCtrl::SetFocus() 
5775     // The test in window.cpp fails as we are a composite 
5776     // window, so it checks against "this", but not m_mainWin. 
5777     if ( DoFindFocus() != this ) 
5778         m_mainWin
->SetFocus(); 
5781 wxSize 
wxGenericListCtrl::DoGetBestSize() const 
5783     // Something is better than nothing... 
5784     // 100x80 is what the MSW version will get from the default 
5785     // wxControl::DoGetBestSize 
5786     return wxSize(100, 80); 
5789 // ---------------------------------------------------------------------------- 
5790 // virtual list control support 
5791 // ---------------------------------------------------------------------------- 
5793 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5795     // this is a pure virtual function, in fact - which is not really pure 
5796     // because the controls which are not virtual don't need to implement it 
5797     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5799     return wxEmptyString
; 
5802 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5804     wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL
), 
5806                 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden.")); 
5810 int wxGenericListCtrl::OnGetItemColumnImage(long item
, long column
) const 
5813         return OnGetItemImage(item
); 
5819 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5821     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5822                   _T("invalid item index in OnGetItemAttr()") ); 
5824     // no attributes by default 
5828 void wxGenericListCtrl::SetItemCount(long count
) 
5830     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
5832     m_mainWin
->SetItemCount(count
); 
5835 void wxGenericListCtrl::RefreshItem(long item
) 
5837     m_mainWin
->RefreshLine(item
); 
5840 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5842     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5845 // Generic wxListCtrl is more or less a container for two other 
5846 // windows which drawings are done upon. These are namely 
5847 // 'm_headerWin' and 'm_mainWin'. 
5848 // Here we override 'virtual wxWindow::Refresh()' to mimic the 
5849 // behaviour wxListCtrl has under wxMSW. 
5851 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5855         // The easy case, no rectangle specified. 
5857             m_headerWin
->Refresh(eraseBackground
); 
5860             m_mainWin
->Refresh(eraseBackground
); 
5864         // Refresh the header window 
5867             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5868             rectHeader
.Intersect(*rect
); 
5869             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5872                 m_headerWin
->GetPosition(&x
, &y
); 
5873                 rectHeader
.Offset(-x
, -y
); 
5874                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5878         // Refresh the main window 
5881             wxRect rectMain 
= m_mainWin
->GetRect(); 
5882             rectMain
.Intersect(*rect
); 
5883             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5886                 m_mainWin
->GetPosition(&x
, &y
); 
5887                 rectMain
.Offset(-x
, -y
); 
5888                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5894 #endif // wxUSE_LISTCTRL