1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        generic/listctrl.cpp 
   3 // Purpose:     generic implementation of wxListCtrl 
   4 // Author:      Robert Roebling 
   5 //              Vadim Zeitlin (virtual list control support) 
   7 // Copyright:   (c) 1998 Robert Roebling 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  14    1. we need to implement searching/sorting for virtual controls somehow 
  15   ?2. when changing selection the lines are refreshed twice 
  18 // ============================================================================ 
  20 // ============================================================================ 
  22 // ---------------------------------------------------------------------------- 
  24 // ---------------------------------------------------------------------------- 
  26 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  27     #pragma implementation "listctrl.h" 
  28     #pragma implementation "listctrlbase.h" 
  31 // For compilers that support precompilation, includes "wx.h". 
  32 #include "wx/wxprec.h" 
  43     #include "wx/dynarray.h" 
  45     #include "wx/dcscreen.h" 
  47     #include "wx/textctrl.h" 
  50 // under Win32 we always use the native version and also may use the generic 
  51 // one, however some things should be done only if we use only the generic 
  53 #if defined(__WIN32__) && !defined(__WXUNIVERSAL__) 
  54     #define HAVE_NATIVE_LISTCTRL 
  57 // if we have the native control, wx/listctrl.h declares it and not this one 
  58 #ifdef HAVE_NATIVE_LISTCTRL 
  59     #include "wx/generic/listctrl.h" 
  60 #else // !HAVE_NATIVE_LISTCTRL 
  61     #include "wx/listctrl.h" 
  63     // if we have a native version, its implementation file does all this 
  64     IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
) 
  65     IMPLEMENT_DYNAMIC_CLASS(wxListView
, wxListCtrl
) 
  66     IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
) 
  68     IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxGenericListCtrl
) 
  69 #endif // HAVE_NATIVE_LISTCTRL/!HAVE_NATIVE_LISTCTRL 
  71 #include "wx/selstore.h" 
  72 #include "wx/renderer.h" 
  76     #include "wx/mac/private.h" 
  81 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
  82 // be removed, as well as the #else case below. 
  83 #define _USE_VISATTR 0 
  86 // ---------------------------------------------------------------------------- 
  88 // ---------------------------------------------------------------------------- 
  90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
) 
  91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
) 
  92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
) 
  93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
) 
  94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
) 
  95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
) 
  96 #if WXWIN_COMPATIBILITY_2_4 
  97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
) 
  98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
) 
 100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
) 
 101 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
) 
 102 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
) 
 103 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
) 
 104 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
) 
 105 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
) 
 106 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
) 
 107 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING
) 
 108 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG
) 
 109 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
) 
 110 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
) 
 111 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
) 
 112 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED
) 
 113 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
) 
 115 // ---------------------------------------------------------------------------- 
 117 // ---------------------------------------------------------------------------- 
 119 // // the height of the header window (FIXME: should depend on its font!) 
 120 // static const int HEADER_HEIGHT = 23; 
 122 static const int SCROLL_UNIT_X 
= 15; 
 124 // the spacing between the lines (in report mode) 
 125 static const int LINE_SPACING 
= 0; 
 127 // extra margins around the text label 
 128 static const int EXTRA_WIDTH 
= 4; 
 129 static const int EXTRA_HEIGHT 
= 4; 
 131 // margin between the window and the items 
 132 static const int EXTRA_BORDER_X 
= 2; 
 133 static const int EXTRA_BORDER_Y 
= 2; 
 135 // offset for the header window 
 136 static const int HEADER_OFFSET_X 
= 1; 
 137 static const int HEADER_OFFSET_Y 
= 1; 
 139 // margin between rows of icons in [small] icon view 
 140 static const int MARGIN_BETWEEN_ROWS 
= 6; 
 142 // when autosizing the columns, add some slack 
 143 static const int AUTOSIZE_COL_MARGIN 
= 10; 
 145 // default and minimal widths for the header columns 
 146 static const int WIDTH_COL_DEFAULT 
= 80; 
 147 static const int WIDTH_COL_MIN 
= 10; 
 149 // the space between the image and the text in the report mode 
 150 static const int IMAGE_MARGIN_IN_REPORT_MODE 
= 5; 
 152 // ============================================================================ 
 154 // ============================================================================ 
 156 //----------------------------------------------------------------------------- 
 157 //  wxListItemData (internal) 
 158 //----------------------------------------------------------------------------- 
 160 class WXDLLEXPORT wxListItemData
 
 163     wxListItemData(wxListMainWindow 
*owner
); 
 166     void SetItem( const wxListItem 
&info 
); 
 167     void SetImage( int image 
) { m_image 
= image
; } 
 168     void SetData( wxUIntPtr data 
) { m_data 
= data
; } 
 169     void SetPosition( int x
, int y 
); 
 170     void SetSize( int width
, int height 
); 
 172     bool HasText() const { return !m_text
.empty(); } 
 173     const wxString
& GetText() const { return m_text
; } 
 174     void SetText(const wxString
& text
) { m_text 
= text
; } 
 176     // we can't use empty string for measuring the string width/height, so 
 177     // always return something 
 178     wxString 
GetTextForMeasuring() const 
 180         wxString s 
= GetText(); 
 187     bool IsHit( int x
, int y 
) const; 
 191     int GetWidth() const; 
 192     int GetHeight() const; 
 194     int GetImage() const { return m_image
; } 
 195     bool HasImage() const { return GetImage() != -1; } 
 197     void GetItem( wxListItem 
&info 
) const; 
 199     void SetAttr(wxListItemAttr 
*attr
) { m_attr 
= attr
; } 
 200     wxListItemAttr 
*GetAttr() const { return m_attr
; } 
 203     // the item image or -1 
 206     // user data associated with the item 
 209     // the item coordinates are not used in report mode, instead this pointer 
 210     // is NULL and the owner window is used to retrieve the item position and 
 214     // the list ctrl we are in 
 215     wxListMainWindow 
*m_owner
; 
 217     // custom attributes or NULL 
 218     wxListItemAttr 
*m_attr
; 
 221     // common part of all ctors 
 227 //----------------------------------------------------------------------------- 
 228 //  wxListHeaderData (internal) 
 229 //----------------------------------------------------------------------------- 
 231 class WXDLLEXPORT wxListHeaderData 
: public wxObject
 
 235     wxListHeaderData( const wxListItem 
&info 
); 
 236     void SetItem( const wxListItem 
&item 
); 
 237     void SetPosition( int x
, int y 
); 
 238     void SetWidth( int w 
); 
 239     void SetFormat( int format 
); 
 240     void SetHeight( int h 
); 
 241     bool HasImage() const; 
 243     bool HasText() const { return !m_text
.empty(); } 
 244     const wxString
& GetText() const { return m_text
; } 
 245     void SetText(const wxString
& text
) { m_text 
= text
; } 
 247     void GetItem( wxListItem 
&item 
); 
 249     bool IsHit( int x
, int y 
) const; 
 250     int GetImage() const; 
 251     int GetWidth() const; 
 252     int GetFormat() const; 
 268 //----------------------------------------------------------------------------- 
 269 //  wxListLineData (internal) 
 270 //----------------------------------------------------------------------------- 
 272 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
); 
 273 #include "wx/listimpl.cpp" 
 274 WX_DEFINE_LIST(wxListItemDataList
); 
 279     // the list of subitems: only may have more than one item in report mode 
 280     wxListItemDataList m_items
; 
 282     // this is not used in report view 
 294         // the part to be highlighted 
 295         wxRect m_rectHighlight
; 
 297         // extend all our rects to be centered inside theo ne of given width 
 298         void ExtendWidth(wxCoord w
) 
 300             wxASSERT_MSG( m_rectAll
.width 
<= w
, 
 301                             _T("width can only be increased") ); 
 304             m_rectLabel
.x 
= m_rectAll
.x 
+ (w 
- m_rectLabel
.width
)/2; 
 305             m_rectIcon
.x 
= m_rectAll
.x 
+ (w 
- m_rectIcon
.width
)/2; 
 306             m_rectHighlight
.x 
= m_rectAll
.x 
+ (w 
- m_rectHighlight
.width
)/2; 
 310     // is this item selected? [NB: not used in virtual mode] 
 313     // back pointer to the list ctrl 
 314     wxListMainWindow 
*m_owner
; 
 317     wxListLineData(wxListMainWindow 
*owner
); 
 321         WX_CLEAR_LIST(wxListItemDataList
, m_items
); 
 325     // are we in report mode? 
 326     inline bool InReportView() const; 
 328     // are we in virtual report mode? 
 329     inline bool IsVirtual() const; 
 331     // these 2 methods shouldn't be called for report view controls, in that 
 332     // case we determine our position/size ourselves 
 334     // calculate the size of the line 
 335     void CalculateSize( wxDC 
*dc
, int spacing 
); 
 337     // remember the position this line appears at 
 338     void SetPosition( int x
, int y
, int spacing 
); 
 342     void SetImage( int image 
) { SetImage(0, image
); } 
 343     int GetImage() const { return GetImage(0); } 
 344     bool HasImage() const { return GetImage() != -1; } 
 345     bool HasText() const { return !GetText(0).empty(); } 
 347     void SetItem( int index
, const wxListItem 
&info 
); 
 348     void GetItem( int index
, wxListItem 
&info 
); 
 350     wxString 
GetText(int index
) const; 
 351     void SetText( int index
, const wxString s 
); 
 353     wxListItemAttr 
*GetAttr() const; 
 354     void SetAttr(wxListItemAttr 
*attr
); 
 356     // return true if the highlighting really changed 
 357     bool Highlight( bool on 
); 
 359     void ReverseHighlight(); 
 361     bool IsHighlighted() const 
 363         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); 
 365         return m_highlighted
; 
 368     // draw the line on the given DC in icon/list mode 
 369     void Draw( wxDC 
*dc 
); 
 371     // the same in report mode 
 372     void DrawInReportMode( wxDC 
*dc
, 
 374                            const wxRect
& rectHL
, 
 378     // set the line to contain num items (only can be > 1 in report mode) 
 379     void InitItems( int num 
); 
 381     // get the mode (i.e. style)  of the list control 
 382     inline int GetMode() const; 
 384     // prepare the DC for drawing with these item's attributes, return true if 
 385     // we need to draw the items background to highlight it, false otherwise 
 386     bool SetAttributes(wxDC 
*dc
, 
 387                        const wxListItemAttr 
*attr
, 
 390     // draw the text on the DC with the correct justification; also add an 
 391     // ellipsis if the text is too large to fit in the current width 
 392     void DrawTextFormatted(wxDC 
*dc
, const wxString 
&text
, int col
, int x
, int y
, int width
); 
 394     // these are only used by GetImage/SetImage above, we don't support images 
 395     // with subitems at the public API level yet 
 396     void SetImage( int index
, int image 
); 
 397     int GetImage( int index 
) const; 
 400 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
); 
 401 #include "wx/arrimpl.cpp" 
 402 WX_DEFINE_OBJARRAY(wxListLineDataArray
); 
 404 //----------------------------------------------------------------------------- 
 405 //  wxListHeaderWindow (internal) 
 406 //----------------------------------------------------------------------------- 
 408 class WXDLLEXPORT wxListHeaderWindow 
: public wxWindow
 
 411     wxListMainWindow  
*m_owner
; 
 412     wxCursor          
*m_currentCursor
; 
 413     wxCursor          
*m_resizeCursor
; 
 416     // column being resized or -1 
 419     // divider line position in logical (unscrolled) coords 
 422     // minimal position beyond which the divider line can't be dragged in 
 427     wxListHeaderWindow(); 
 429     wxListHeaderWindow( wxWindow 
*win
, 
 431                         wxListMainWindow 
*owner
, 
 432                         const wxPoint 
&pos 
= wxDefaultPosition
, 
 433                         const wxSize 
&size 
= wxDefaultSize
, 
 435                         const wxString 
&name 
= wxT("wxlistctrlcolumntitles") ); 
 437     virtual ~wxListHeaderWindow(); 
 440     void AdjustDC(wxDC
& dc
); 
 442     void OnPaint( wxPaintEvent 
&event 
); 
 443     void OnMouse( wxMouseEvent 
&event 
); 
 444     void OnSetFocus( wxFocusEvent 
&event 
); 
 450     // common part of all ctors 
 453     // generate and process the list event of the given type, return true if 
 454     // it wasn't vetoed, i.e. if we should proceed 
 455     bool SendListEvent(wxEventType type
, wxPoint pos
); 
 457     DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
) 
 458     DECLARE_EVENT_TABLE() 
 461 //----------------------------------------------------------------------------- 
 462 // wxListRenameTimer (internal) 
 463 //----------------------------------------------------------------------------- 
 465 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
 
 468     wxListMainWindow 
*m_owner
; 
 471     wxListRenameTimer( wxListMainWindow 
*owner 
); 
 475 //----------------------------------------------------------------------------- 
 476 //  wxListTextCtrl (internal) 
 477 //----------------------------------------------------------------------------- 
 479 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
 
 482     wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
); 
 485     void OnChar( wxKeyEvent 
&event 
); 
 486     void OnKeyUp( wxKeyEvent 
&event 
); 
 487     void OnKillFocus( wxFocusEvent 
&event 
); 
 489     bool AcceptChanges(); 
 493     wxListMainWindow   
*m_owner
; 
 494     wxString            m_startValue
; 
 498     DECLARE_EVENT_TABLE() 
 501 //----------------------------------------------------------------------------- 
 502 //  wxListMainWindow (internal) 
 503 //----------------------------------------------------------------------------- 
 505 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
); 
 506 #include "wx/listimpl.cpp" 
 507 WX_DEFINE_LIST(wxListHeaderDataList
); 
 509 class wxListMainWindow 
: public wxScrolledWindow
 
 513     wxListMainWindow( wxWindow 
*parent
, 
 515                       const wxPoint
& pos 
= wxDefaultPosition
, 
 516                       const wxSize
& size 
= wxDefaultSize
, 
 518                       const wxString 
&name 
= _T("listctrlmainwindow") ); 
 520     virtual ~wxListMainWindow(); 
 522     wxWindow 
*GetMainWindowOfCompositeControl() { return GetParent(); } 
 524     bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); } 
 526     // return true if this is a virtual list control 
 527     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); } 
 529     // return true if the control is in report mode 
 530     bool InReportView() const { return HasFlag(wxLC_REPORT
); } 
 532     // return true if we are in single selection mode, false if multi sel 
 533     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); } 
 535     // do we have a header window? 
 536     bool HasHeader() const 
 537         { return InReportView() && !HasFlag(wxLC_NO_HEADER
); } 
 539     void HighlightAll( bool on 
); 
 541     // all these functions only do something if the line is currently visible 
 543     // change the line "selected" state, return true if it really changed 
 544     bool HighlightLine( size_t line
, bool highlight 
= true); 
 546     // as HighlightLine() but do it for the range of lines: this is incredibly 
 547     // more efficient for virtual list controls! 
 549     // NB: unlike HighlightLine() this one does refresh the lines on screen 
 550     void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on 
= true ); 
 552     // toggle the line state and refresh it 
 553     void ReverseHighlight( size_t line 
) 
 554         { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); } 
 556     // return true if the line is highlighted 
 557     bool IsHighlighted(size_t line
) const; 
 559     // refresh one or several lines at once 
 560     void RefreshLine( size_t line 
); 
 561     void RefreshLines( size_t lineFrom
, size_t lineTo 
); 
 563     // refresh all selected items 
 564     void RefreshSelected(); 
 566     // refresh all lines below the given one: the difference with 
 567     // RefreshLines() is that the index here might not be a valid one (happens 
 568     // when the last line is deleted) 
 569     void RefreshAfter( size_t lineFrom 
); 
 571     // the methods which are forwarded to wxListLineData itself in list/icon 
 572     // modes but are here because the lines don't store their positions in the 
 575     // get the bound rect for the entire line 
 576     wxRect 
GetLineRect(size_t line
) const; 
 578     // get the bound rect of the label 
 579     wxRect 
GetLineLabelRect(size_t line
) const; 
 581     // get the bound rect of the items icon (only may be called if we do have 
 583     wxRect 
GetLineIconRect(size_t line
) const; 
 585     // get the rect to be highlighted when the item has focus 
 586     wxRect 
GetLineHighlightRect(size_t line
) const; 
 588     // get the size of the total line rect 
 589     wxSize 
GetLineSize(size_t line
) const 
 590         { return GetLineRect(line
).GetSize(); } 
 592     // return the hit code for the corresponding position (in this line) 
 593     long HitTestLine(size_t line
, int x
, int y
) const; 
 595     // bring the selected item into view, scrolling to it if necessary 
 596     void MoveToItem(size_t item
); 
 598     // bring the current item into view 
 599     void MoveToFocus() { MoveToItem(m_current
); } 
 601     // start editing the label of the given item 
 602     void EditLabel( long item 
); 
 604     // suspend/resume redrawing the control 
 608     void OnRenameTimer(); 
 609     bool OnRenameAccept(size_t itemEdit
, const wxString
& value
); 
 610     void OnRenameCancelled(size_t itemEdit
); 
 612     void OnMouse( wxMouseEvent 
&event 
); 
 614     // called to switch the selection from the current item to newCurrent, 
 615     void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event 
); 
 617     void OnChar( wxKeyEvent 
&event 
); 
 618     void OnKeyDown( wxKeyEvent 
&event 
); 
 619     void OnSetFocus( wxFocusEvent 
&event 
); 
 620     void OnKillFocus( wxFocusEvent 
&event 
); 
 621     void OnScroll(wxScrollWinEvent
& event
) ; 
 623     void OnPaint( wxPaintEvent 
&event 
); 
 625     void DrawImage( int index
, wxDC 
*dc
, int x
, int y 
); 
 626     void GetImageSize( int index
, int &width
, int &height 
) const; 
 627     int GetTextLength( const wxString 
&s 
) const; 
 629     void SetImageList( wxImageListType 
*imageList
, int which 
); 
 630     void SetItemSpacing( int spacing
, bool isSmall 
= false ); 
 631     int GetItemSpacing( bool isSmall 
= false ); 
 633     void SetColumn( int col
, wxListItem 
&item 
); 
 634     void SetColumnWidth( int col
, int width 
); 
 635     void GetColumn( int col
, wxListItem 
&item 
) const; 
 636     int GetColumnWidth( int col 
) const; 
 637     int GetColumnCount() const { return m_columns
.GetCount(); } 
 639     // returns the sum of the heights of all columns 
 640     int GetHeaderWidth() const; 
 642     int GetCountPerPage() const; 
 644     void SetItem( wxListItem 
&item 
); 
 645     void GetItem( wxListItem 
&item 
) const; 
 646     void SetItemState( long item
, long state
, long stateMask 
); 
 647     int GetItemState( long item
, long stateMask 
) const; 
 648     void GetItemRect( long index
, wxRect 
&rect 
) const; 
 649     wxRect 
GetViewRect() const; 
 650     bool GetItemPosition( long item
, wxPoint
& pos 
) const; 
 651     int GetSelectedItemCount() const; 
 653     wxString 
GetItemText(long item
) const 
 656         info
.m_itemId 
= item
; 
 661     void SetItemText(long item
, const wxString
& value
) 
 664         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 665         info
.m_itemId 
= item
; 
 670     // set the scrollbars and update the positions of the items 
 671     void RecalculatePositions(bool noRefresh 
= false); 
 673     // refresh the window and the header 
 676     long GetNextItem( long item
, int geometry
, int state 
) const; 
 677     void DeleteItem( long index 
); 
 678     void DeleteAllItems(); 
 679     void DeleteColumn( int col 
); 
 680     void DeleteEverything(); 
 681     void EnsureVisible( long index 
); 
 682     long FindItem( long start
, const wxString
& str
, bool partial 
= false ); 
 683     long FindItem( long start
, wxUIntPtr data
); 
 684     long FindItem( const wxPoint
& pt 
); 
 685     long HitTest( int x
, int y
, int &flags 
); 
 686     void InsertItem( wxListItem 
&item 
); 
 687     void InsertColumn( long col
, wxListItem 
&item 
); 
 688     void SortItems( wxListCtrlCompare fn
, long data 
); 
 690     size_t GetItemCount() const; 
 691     bool IsEmpty() const { return GetItemCount() == 0; } 
 692     void SetItemCount(long count
); 
 694     // change the current (== focused) item, send a notification event 
 695     void ChangeCurrent(size_t current
); 
 696     void ResetCurrent() { ChangeCurrent((size_t)-1); } 
 697     bool HasCurrent() const { return m_current 
!= (size_t)-1; } 
 699     // send out a wxListEvent 
 700     void SendNotify( size_t line
, 
 702                      wxPoint point 
= wxDefaultPosition 
); 
 704     // override base class virtual to reset m_lineHeight when the font changes 
 705     virtual bool SetFont(const wxFont
& font
) 
 707         if ( !wxScrolledWindow::SetFont(font
) ) 
 715     // these are for wxListLineData usage only 
 717     // get the backpointer to the list ctrl 
 718     wxGenericListCtrl 
*GetListCtrl() const 
 720         return wxStaticCast(GetParent(), wxGenericListCtrl
); 
 723     // get the height of all lines (assuming they all do have the same height) 
 724     wxCoord 
GetLineHeight() const; 
 726     // get the y position of the given line (only for report view) 
 727     wxCoord 
GetLineY(size_t line
) const; 
 729     // get the brush to use for the item highlighting 
 730     wxBrush 
*GetHighlightBrush() const 
 732         return m_hasFocus 
? m_highlightBrush 
: m_highlightUnfocusedBrush
; 
 736     // the array of all line objects for a non virtual list control (for the 
 737     // virtual list control we only ever use m_lines[0]) 
 738     wxListLineDataArray  m_lines
; 
 740     // the list of column objects 
 741     wxListHeaderDataList m_columns
; 
 743     // currently focused item or -1 
 746     // the number of lines per page 
 749     // this flag is set when something which should result in the window 
 750     // redrawing happens (i.e. an item was added or deleted, or its appearance 
 751     // changed) and OnPaint() doesn't redraw the window while it is set which 
 752     // allows to minimize the number of repaintings when a lot of items are 
 753     // being added. The real repainting occurs only after the next OnIdle() 
 757     wxColour            
*m_highlightColour
; 
 758     wxImageListType         
*m_small_image_list
; 
 759     wxImageListType         
*m_normal_image_list
; 
 761     int                  m_normal_spacing
; 
 765     wxTimer             
*m_renameTimer
; 
 770     // for double click logic 
 771     size_t m_lineLastClicked
, 
 772            m_lineBeforeLastClicked
, 
 773            m_lineSelectSingleOnUp
; 
 776     // the total count of items in a virtual list control 
 779     // the object maintaining the items selection state, only used in virtual 
 781     wxSelectionStore m_selStore
; 
 783     // common part of all ctors 
 786     // get the line data for the given index 
 787     wxListLineData 
*GetLine(size_t n
) const 
 789         wxASSERT_MSG( n 
!= (size_t)-1, _T("invalid line index") ); 
 793             wxConstCast(this, wxListMainWindow
)->CacheLineData(n
); 
 801     // get a dummy line which can be used for geometry calculations and such: 
 802     // you must use GetLine() if you want to really draw the line 
 803     wxListLineData 
*GetDummyLine() const; 
 805     // cache the line data of the n-th line in m_lines[0] 
 806     void CacheLineData(size_t line
); 
 808     // get the range of visible lines 
 809     void GetVisibleLinesRange(size_t *from
, size_t *to
); 
 811     // force us to recalculate the range of visible lines 
 812     void ResetVisibleLinesRange() { m_lineFrom 
= (size_t)-1; } 
 814     // get the colour to be used for drawing the rules 
 815     wxColour 
GetRuleColour() const 
 820         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 825     // initialize the current item if needed 
 826     void UpdateCurrent(); 
 828     // delete all items but don't refresh: called from dtor 
 829     void DoDeleteAllItems(); 
 831     // the height of one line using the current font 
 832     wxCoord m_lineHeight
; 
 834     // the total header width or 0 if not calculated yet 
 835     wxCoord m_headerWidth
; 
 837     // the first and last lines being shown on screen right now (inclusive), 
 838     // both may be -1 if they must be calculated so never access them directly: 
 839     // use GetVisibleLinesRange() above instead 
 843     // the brushes to use for item highlighting when we do/don't have focus 
 844     wxBrush 
*m_highlightBrush
, 
 845             *m_highlightUnfocusedBrush
; 
 847     // if this is > 0, the control is frozen and doesn't redraw itself 
 848     size_t m_freezeCount
; 
 850     DECLARE_DYNAMIC_CLASS(wxListMainWindow
) 
 851     DECLARE_EVENT_TABLE() 
 853     friend class wxGenericListCtrl
; 
 856 // ============================================================================ 
 858 // ============================================================================ 
 860 //----------------------------------------------------------------------------- 
 862 //----------------------------------------------------------------------------- 
 864 wxListItemData::~wxListItemData() 
 866     // in the virtual list control the attributes are managed by the main 
 867     // program, so don't delete them 
 868     if ( !m_owner
->IsVirtual() ) 
 876 void wxListItemData::Init() 
 884 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
 890     if ( owner
->InReportView() ) 
 900 void wxListItemData::SetItem( const wxListItem 
&info 
) 
 902     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
 903         SetText(info
.m_text
); 
 904     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 905         m_image 
= info
.m_image
; 
 906     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
 907         m_data 
= info
.m_data
; 
 909     if ( info
.HasAttributes() ) 
 912             *m_attr 
= *info
.GetAttributes(); 
 914             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
 922         m_rect
->width 
= info
.m_width
; 
 926 void wxListItemData::SetPosition( int x
, int y 
) 
 928     wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") ); 
 934 void wxListItemData::SetSize( int width
, int height 
) 
 936     wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") ); 
 939         m_rect
->width 
= width
; 
 941         m_rect
->height 
= height
; 
 944 bool wxListItemData::IsHit( int x
, int y 
) const 
 946     wxCHECK_MSG( m_rect
, false, _T("can't be called in this mode") ); 
 948     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
); 
 951 int wxListItemData::GetX() const 
 953     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 958 int wxListItemData::GetY() const 
 960     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 965 int wxListItemData::GetWidth() const 
 967     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 969     return m_rect
->width
; 
 972 int wxListItemData::GetHeight() const 
 974     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 976     return m_rect
->height
; 
 979 void wxListItemData::GetItem( wxListItem 
&info 
) const 
 981     info
.m_text 
= m_text
; 
 982     info
.m_image 
= m_image
; 
 983     info
.m_data 
= m_data
; 
 987         if ( m_attr
->HasTextColour() ) 
 988             info
.SetTextColour(m_attr
->GetTextColour()); 
 989         if ( m_attr
->HasBackgroundColour() ) 
 990             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
 991         if ( m_attr
->HasFont() ) 
 992             info
.SetFont(m_attr
->GetFont()); 
 996 //----------------------------------------------------------------------------- 
 998 //----------------------------------------------------------------------------- 
1000 void wxListHeaderData::Init() 
1011 wxListHeaderData::wxListHeaderData() 
1016 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
1023 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
1025     m_mask 
= item
.m_mask
; 
1027     if ( m_mask 
& wxLIST_MASK_TEXT 
) 
1028         m_text 
= item
.m_text
; 
1030     if ( m_mask 
& wxLIST_MASK_IMAGE 
) 
1031         m_image 
= item
.m_image
; 
1033     if ( m_mask 
& wxLIST_MASK_FORMAT 
) 
1034         m_format 
= item
.m_format
; 
1036     if ( m_mask 
& wxLIST_MASK_WIDTH 
) 
1037         SetWidth(item
.m_width
); 
1040 void wxListHeaderData::SetPosition( int x
, int y 
) 
1046 void wxListHeaderData::SetHeight( int h 
) 
1051 void wxListHeaderData::SetWidth( int w 
) 
1055         m_width 
= WIDTH_COL_DEFAULT
; 
1056     else if (m_width 
< WIDTH_COL_MIN
) 
1057         m_width 
= WIDTH_COL_MIN
; 
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
; 
1084 int wxListHeaderData::GetImage() const 
1089 int wxListHeaderData::GetWidth() const 
1094 int wxListHeaderData::GetFormat() const 
1099 //----------------------------------------------------------------------------- 
1101 //----------------------------------------------------------------------------- 
1103 inline int wxListLineData::GetMode() const 
1105     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
1108 inline bool wxListLineData::InReportView() const 
1110     return m_owner
->HasFlag(wxLC_REPORT
); 
1113 inline bool wxListLineData::IsVirtual() const 
1115     return m_owner
->IsVirtual(); 
1118 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
1122     if ( InReportView() ) 
1128         m_gi 
= new GeometryInfo
; 
1131     m_highlighted 
= false; 
1133     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
1136 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
1138     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1139     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1141     wxListItemData 
*item 
= node
->GetData(); 
1146     switch ( GetMode() ) 
1149         case wxLC_SMALL_ICON
: 
1150             m_gi
->m_rectAll
.width 
= spacing
; 
1152             s 
= item
->GetText(); 
1157                 m_gi
->m_rectLabel
.width 
= 
1158                 m_gi
->m_rectLabel
.height 
= 0; 
1162                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
1166                 m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
1168                     m_gi
->m_rectAll
.width 
= lw
; 
1170                 m_gi
->m_rectLabel
.width 
= lw
; 
1171                 m_gi
->m_rectLabel
.height 
= lh
; 
1174             if (item
->HasImage()) 
1177                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1178                 m_gi
->m_rectIcon
.width 
= w 
+ 8; 
1179                 m_gi
->m_rectIcon
.height 
= h 
+ 8; 
1181                 if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
1182                     m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
1183                 if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
1184                     m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
1187             if ( item
->HasText() ) 
1189                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
1190                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
1192             else // no text, highlight the icon 
1194                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
1195                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
1200             s 
= item
->GetTextForMeasuring(); 
1202             dc
->GetTextExtent( s
, &lw
, &lh 
); 
1206             m_gi
->m_rectLabel
.width 
= lw
; 
1207             m_gi
->m_rectLabel
.height 
= lh
; 
1209             m_gi
->m_rectAll
.width 
= lw
; 
1210             m_gi
->m_rectAll
.height 
= lh
; 
1212             if (item
->HasImage()) 
1215                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1216                 m_gi
->m_rectIcon
.width 
= w
; 
1217                 m_gi
->m_rectIcon
.height 
= h
; 
1219                 m_gi
->m_rectAll
.width 
+= 4 + w
; 
1220                 if (h 
> m_gi
->m_rectAll
.height
) 
1221                     m_gi
->m_rectAll
.height 
= h
; 
1224             m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
1225             m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
1229             wxFAIL_MSG( _T("unexpected call to SetSize") ); 
1233             wxFAIL_MSG( _T("unknown mode") ); 
1237 void wxListLineData::SetPosition( int x
, int y
, int spacing 
) 
1239     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1240     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1242     wxListItemData 
*item 
= node
->GetData(); 
1244     switch ( GetMode() ) 
1247         case wxLC_SMALL_ICON
: 
1248             m_gi
->m_rectAll
.x 
= x
; 
1249             m_gi
->m_rectAll
.y 
= y
; 
1251             if ( item
->HasImage() ) 
1253                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 + 
1254                     (m_gi
->m_rectAll
.width 
- m_gi
->m_rectIcon
.width
) / 2; 
1255                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
1258             if ( item
->HasText() ) 
1260                 if (m_gi
->m_rectAll
.width 
> spacing
) 
1261                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1263                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2); 
1264                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
1265                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
1266                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
1268             else // no text, highlight the icon 
1270                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
1271                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
1276             m_gi
->m_rectAll
.x 
= x
; 
1277             m_gi
->m_rectAll
.y 
= y
; 
1279             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
1280             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
1281             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1283             if (item
->HasImage()) 
1285                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1286                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1287                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 6 + m_gi
->m_rectIcon
.width
; 
1291                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1296             wxFAIL_MSG( _T("unexpected call to SetPosition") ); 
1300             wxFAIL_MSG( _T("unknown mode") ); 
1304 void wxListLineData::InitItems( int num 
) 
1306     for (int i 
= 0; i 
< num
; i
++) 
1307         m_items
.Append( new wxListItemData(m_owner
) ); 
1310 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
1312     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1313     wxCHECK_RET( node
, _T("invalid column index in SetItem") ); 
1315     wxListItemData 
*item 
= node
->GetData(); 
1316     item
->SetItem( info 
); 
1319 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
1321     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1324         wxListItemData 
*item 
= node
->GetData(); 
1325         item
->GetItem( info 
); 
1329 wxString 
wxListLineData::GetText(int index
) const 
1333     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1336         wxListItemData 
*item 
= node
->GetData(); 
1337         s 
= item
->GetText(); 
1343 void wxListLineData::SetText( int index
, const wxString s 
) 
1345     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1348         wxListItemData 
*item 
= node
->GetData(); 
1353 void wxListLineData::SetImage( int index
, int image 
) 
1355     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1356     wxCHECK_RET( node
, _T("invalid column index in SetImage()") ); 
1358     wxListItemData 
*item 
= node
->GetData(); 
1359     item
->SetImage(image
); 
1362 int wxListLineData::GetImage( int index 
) const 
1364     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1365     wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") ); 
1367     wxListItemData 
*item 
= node
->GetData(); 
1368     return item
->GetImage(); 
1371 wxListItemAttr 
*wxListLineData::GetAttr() const 
1373     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1374     wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") ); 
1376     wxListItemData 
*item 
= node
->GetData(); 
1377     return item
->GetAttr(); 
1380 void wxListLineData::SetAttr(wxListItemAttr 
*attr
) 
1382     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1383     wxCHECK_RET( node
, _T("invalid column index in SetAttr()") ); 
1385     wxListItemData 
*item 
= node
->GetData(); 
1386     item
->SetAttr(attr
); 
1389 bool wxListLineData::SetAttributes(wxDC 
*dc
, 
1390                                    const wxListItemAttr 
*attr
, 
1393     wxWindow 
*listctrl 
= m_owner
->GetParent(); 
1397     // don't use foreground colour for drawing highlighted items - this might 
1398     // make them completely invisible (and there is no way to do bit 
1399     // arithmetics on wxColour, unfortunately) 
1403         colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1407         if ( attr 
&& attr
->HasTextColour() ) 
1409             colText 
= attr
->GetTextColour(); 
1413             colText 
= listctrl
->GetForegroundColour(); 
1417     dc
->SetTextForeground(colText
); 
1421     if ( attr 
&& attr
->HasFont() ) 
1423         font 
= attr
->GetFont(); 
1427         font 
= listctrl
->GetFont(); 
1433     bool hasBgCol 
= attr 
&& attr
->HasBackgroundColour(); 
1434     if ( highlighted 
|| hasBgCol 
) 
1438             dc
->SetBrush( *m_owner
->GetHighlightBrush() ); 
1442             dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
)); 
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
) ) 
1464         dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1467     // just for debugging to better see where the items are 
1469     dc
->SetPen(*wxRED_PEN
); 
1470     dc
->SetBrush(*wxTRANSPARENT_BRUSH
); 
1471     dc
->DrawRectangle( m_gi
->m_rectAll 
); 
1472     dc
->SetPen(*wxGREEN_PEN
); 
1473     dc
->DrawRectangle( m_gi
->m_rectIcon 
); 
1476     wxListItemData 
*item 
= node
->GetData(); 
1477     if (item
->HasImage()) 
1479         // centre the image inside our rectangle, this looks nicer when items 
1480         // ae aligned in a row 
1481         const wxRect
& rectIcon 
= m_gi
->m_rectIcon
; 
1483         m_owner
->DrawImage(item
->GetImage(), dc
, rectIcon
.x
, rectIcon
.y
); 
1486     if (item
->HasText()) 
1488         const wxRect
& rectLabel 
= m_gi
->m_rectLabel
; 
1490         wxDCClipper 
clipper(*dc
, rectLabel
); 
1491         dc
->DrawText(item
->GetText(), rectLabel
.x
, rectLabel
.y
); 
1495 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
1497                                        const wxRect
& rectHL
, 
1500     // TODO: later we should support setting different attributes for 
1501     //       different columns - to do it, just add "col" argument to 
1502     //       GetAttr() and move these lines into the loop below 
1503     wxListItemAttr 
*attr 
= GetAttr(); 
1504     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1506         dc
->DrawRectangle( rectHL 
); 
1509     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
1510             y 
= rect
.y 
+ (LINE_SPACING 
+ EXTRA_HEIGHT
) / 2; 
1513     for ( wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1515           node 
= node
->GetNext(), col
++ ) 
1517         wxListItemData 
*item 
= node
->GetData(); 
1519         int width 
= m_owner
->GetColumnWidth(col
); 
1523         if ( item
->HasImage() ) 
1526             m_owner
->DrawImage( item
->GetImage(), dc
, xOld
, y 
); 
1527             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
1529             ix 
+= IMAGE_MARGIN_IN_REPORT_MODE
; 
1535         wxDCClipper 
clipper(*dc
, xOld
, y
, width 
- 8, rect
.height
); 
1537         if ( item
->HasText() ) 
1539             DrawTextFormatted(dc
, item
->GetText(), col
, xOld
, y
, width 
- 8); 
1544 void wxListLineData::DrawTextFormatted(wxDC 
*dc
, 
1545                                        const wxString 
&text
, 
1551     wxString drawntext
, ellipsis
; 
1552     wxCoord w
, h
, base_w
; 
1555     // determine if the string can fit inside the current width 
1556     dc
->GetTextExtent(text
, &w
, &h
); 
1559         // it can, draw it using the items alignment 
1560         m_owner
->GetColumn(col
, item
); 
1561         switch ( item
.GetAlign() ) 
1564                 wxFAIL_MSG( _T("unknown list item format") ); 
1567             case wxLIST_FORMAT_LEFT
: 
1571             case wxLIST_FORMAT_RIGHT
: 
1575             case wxLIST_FORMAT_CENTER
: 
1576                 x 
+= (width 
- w
) / 2; 
1580         dc
->DrawText(text
, x
, y
); 
1582     else // otherwise, truncate and add an ellipsis if possible 
1584         // determine the base width 
1585         ellipsis 
= wxString(wxT("...")); 
1586         dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1588         // continue until we have enough space or only one character left 
1590         size_t len 
= text
.Length(); 
1591         drawntext 
= text
.Left(len
); 
1594             dc
->GetTextExtent(drawntext
.Last(), &w_c
, &h_c
); 
1595             drawntext
.RemoveLast(); 
1598             if (w 
+ base_w 
<= width
) 
1602         // if still not enough space, remove ellipsis characters 
1603         while (ellipsis
.Length() > 0 && w 
+ base_w 
> width
) 
1605             ellipsis 
= ellipsis
.Left(ellipsis
.Length() - 1); 
1606             dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1609         // now draw the text 
1610         dc
->DrawText(drawntext
, x
, y
); 
1611         dc
->DrawText(ellipsis
, x 
+ w
, y
); 
1615 bool wxListLineData::Highlight( bool on 
) 
1617     wxCHECK_MSG( !IsVirtual(), false, _T("unexpected call to Highlight") ); 
1619     if ( on 
== m_highlighted 
) 
1627 void wxListLineData::ReverseHighlight( void ) 
1629     Highlight(!IsHighlighted()); 
1632 //----------------------------------------------------------------------------- 
1633 //  wxListHeaderWindow 
1634 //----------------------------------------------------------------------------- 
1636 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
) 
1638 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
1639     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
1640     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
1641     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
1644 void wxListHeaderWindow::Init() 
1646     m_currentCursor 
= (wxCursor 
*) NULL
; 
1647     m_isDragging 
= false; 
1651 wxListHeaderWindow::wxListHeaderWindow() 
1655     m_owner 
= (wxListMainWindow 
*) NULL
; 
1656     m_resizeCursor 
= (wxCursor 
*) NULL
; 
1659 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, 
1661                                         wxListMainWindow 
*owner
, 
1665                                         const wxString 
&name 
) 
1666                   : wxWindow( win
, id
, pos
, size
, style
, name 
) 
1671     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
1674     wxVisualAttributes attr 
= wxPanel::GetClassDefaultAttributes(); 
1675     SetOwnForegroundColour( attr
.colFg 
); 
1676     SetOwnBackgroundColour( attr
.colBg 
); 
1678         SetOwnFont( attr
.font 
); 
1680     SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
1681     SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
1683         SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT 
)); 
1687 wxListHeaderWindow::~wxListHeaderWindow() 
1689     delete m_resizeCursor
; 
1692 #ifdef __WXUNIVERSAL__ 
1693 #include "wx/univ/renderer.h" 
1694 #include "wx/univ/theme.h" 
1697 // shift the DC origin to match the position of the main window horz 
1698 // scrollbar: this allows us to always use logical coords 
1699 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
1702     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1705     m_owner
->GetViewStart( &x
, NULL 
); 
1707     // account for the horz scrollbar offset 
1708     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1711 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1713     wxPaintDC 
dc( this ); 
1720     dc
.SetFont( GetFont() ); 
1722     // width and height of the entire header window 
1724     GetClientSize( &w
, &h 
); 
1725     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1727     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1729     dc
.SetTextForeground(GetForegroundColour()); 
1731     int x 
= HEADER_OFFSET_X
; 
1733     int numColumns 
= m_owner
->GetColumnCount(); 
1735     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1737         m_owner
->GetColumn( i
, item 
); 
1738         int wCol 
= item
.m_width
; 
1740         // the width of the rect to draw: make it smaller to fit entirely 
1741         // inside the column rect 
1744         wxRendererNative::Get().DrawHeaderButton
 
1748                                     wxRect(x
, HEADER_OFFSET_Y
, cw
, h 
- 2), 
1749                                     m_parent
->IsEnabled() ? 0 
1750                                                           : (int)wxCONTROL_DISABLED
 
1753         // see if we have enough space for the column label 
1755         // for this we need the width of the text 
1758         dc
.GetTextExtent(item
.GetText(), &wLabel
, &hLabel
); 
1759         wLabel 
+= 2*EXTRA_WIDTH
; 
1761         // and the width of the icon, if any 
1762         static const int MARGIN_BETWEEN_TEXT_AND_ICON 
= 2; 
1763         int ix 
= 0,     // init them just to suppress the compiler warnings 
1765         const int image 
= item
.m_image
; 
1766         wxImageListType 
*imageList
; 
1769             imageList 
= m_owner
->m_small_image_list
; 
1772                 imageList
->GetSize(image
, ix
, iy
); 
1773                 wLabel 
+= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
1781         // ignore alignment if there is not enough space anyhow 
1783         switch ( wLabel 
< cw 
? item
.GetAlign() : wxLIST_FORMAT_LEFT 
) 
1786                 wxFAIL_MSG( _T("unknown list item format") ); 
1789             case wxLIST_FORMAT_LEFT
: 
1793             case wxLIST_FORMAT_RIGHT
: 
1794                 xAligned 
= x 
+ cw 
- wLabel
; 
1797             case wxLIST_FORMAT_CENTER
: 
1798                 xAligned 
= x 
+ (cw 
- wLabel
) / 2; 
1803         // if we have an image, draw it on the right of the label 
1810                         xAligned 
+ wLabel 
- ix 
- MARGIN_BETWEEN_TEXT_AND_ICON
, 
1811                         HEADER_OFFSET_Y 
+ (h 
- 4 - iy
)/2, 
1812                         wxIMAGELIST_DRAW_TRANSPARENT
 
1815             cw 
-= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
1818         // draw the text clipping it so that it doesn't overwrite the column 
1820         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h 
- 4 ); 
1822         dc
.DrawText( item
.GetText(), 
1823                      xAligned 
+ EXTRA_WIDTH
, h 
/ 2 - hLabel 
/ 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT ); 
1831 void wxListHeaderWindow::DrawCurrent() 
1833     int x1 
= m_currentX
; 
1835     m_owner
->ClientToScreen( &x1
, &y1 
); 
1837     int x2 
= m_currentX
; 
1839     m_owner
->GetClientSize( NULL
, &y2 
); 
1840     m_owner
->ClientToScreen( &x2
, &y2 
); 
1843     dc
.SetLogicalFunction( wxINVERT 
); 
1844     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
1845     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1849     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1851     dc
.SetLogicalFunction( wxCOPY 
); 
1853     dc
.SetPen( wxNullPen 
); 
1854     dc
.SetBrush( wxNullBrush 
); 
1857 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1859     // we want to work with logical coords 
1861     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1862     int y 
= event
.GetY(); 
1866         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1868         // we don't draw the line beyond our window, but we allow dragging it 
1871         GetClientSize( &w
, NULL 
); 
1872         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1875         // erase the line if it was drawn 
1876         if ( m_currentX 
< w 
) 
1879         if (event
.ButtonUp()) 
1882             m_isDragging 
= false; 
1884             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1885             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1892                 m_currentX 
= m_minX 
+ 7; 
1894             // draw in the new location 
1895             if ( m_currentX 
< w 
) 
1899     else // not dragging 
1902         bool hit_border 
= false; 
1904         // end of the current column 
1907         // find the column where this event occured 
1909             countCol 
= m_owner
->GetColumnCount(); 
1910         for (col 
= 0; col 
< countCol
; col
++) 
1912             xpos 
+= m_owner
->GetColumnWidth( col 
); 
1915             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
1917                 // near the column border 
1924                 // inside the column 
1931         if ( col 
== countCol 
) 
1934         if (event
.LeftDown() || event
.RightUp()) 
1936             if (hit_border 
&& event
.LeftDown()) 
1938                 if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
1939                                    event
.GetPosition()) ) 
1941                     m_isDragging 
= true; 
1946                 //else: column resizing was vetoed by the user code 
1948             else // click on a column 
1950                 SendListEvent( event
.LeftDown() 
1951                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
1952                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
1953                                 event
.GetPosition()); 
1956         else if (event
.Moving()) 
1961                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
1962                 m_currentCursor 
= m_resizeCursor
; 
1966                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
1967                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1971                 SetCursor(*m_currentCursor
); 
1976 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1978     m_owner
->SetFocus(); 
1982 bool wxListHeaderWindow::SendListEvent(wxEventType type
, wxPoint pos
) 
1984     wxWindow 
*parent 
= GetParent(); 
1985     wxListEvent 
le( type
, parent
->GetId() ); 
1986     le
.SetEventObject( parent 
); 
1987     le
.m_pointDrag 
= pos
; 
1989     // the position should be relative to the parent window, not 
1990     // this one for compatibility with MSW and common sense: the 
1991     // user code doesn't know anything at all about this header 
1992     // window, so why should it get positions relative to it? 
1993     le
.m_pointDrag
.y 
-= GetSize().y
; 
1995     le
.m_col 
= m_column
; 
1996     return !parent
->GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
1999 //----------------------------------------------------------------------------- 
2000 // wxListRenameTimer (internal) 
2001 //----------------------------------------------------------------------------- 
2003 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
2008 void wxListRenameTimer::Notify() 
2010     m_owner
->OnRenameTimer(); 
2013 //----------------------------------------------------------------------------- 
2014 // wxListTextCtrl (internal) 
2015 //----------------------------------------------------------------------------- 
2017 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
) 
2018     EVT_CHAR           (wxListTextCtrl::OnChar
) 
2019     EVT_KEY_UP         (wxListTextCtrl::OnKeyUp
) 
2020     EVT_KILL_FOCUS     (wxListTextCtrl::OnKillFocus
) 
2023 wxListTextCtrl::wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
) 
2024               : m_startValue(owner
->GetItemText(itemEdit
)), 
2025                 m_itemEdited(itemEdit
) 
2030     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
2032     m_owner
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
2033                                   &rectLabel
.x
, &rectLabel
.y
); 
2035     (void)Create(owner
, wxID_ANY
, m_startValue
, 
2036                  wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2037                  wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
2040 void wxListTextCtrl::Finish() 
2044         wxPendingDelete
.Append(this); 
2048         m_owner
->SetFocusIgnoringChildren(); 
2052 bool wxListTextCtrl::AcceptChanges() 
2054     const wxString value 
= GetValue(); 
2056     if ( value 
== m_startValue 
) 
2058         // nothing changed, always accept 
2062     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
2064         // vetoed by the user 
2068     // accepted, do rename the item 
2069     m_owner
->SetItemText(m_itemEdited
, value
); 
2074 void wxListTextCtrl::OnChar( wxKeyEvent 
&event 
) 
2076     switch ( event
.m_keyCode 
) 
2079             // Notify the owner about the changes 
2082             // Even if vetoed, close the control (consistent with MSW) 
2089             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2097 void wxListTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
2105     // auto-grow the textctrl: 
2106     wxSize parentSize 
= m_owner
->GetSize(); 
2107     wxPoint myPos 
= GetPosition(); 
2108     wxSize mySize 
= GetSize(); 
2110     GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); 
2111     if (myPos
.x 
+ sx 
> parentSize
.x
) 
2112         sx 
= parentSize
.x 
- myPos
.x
; 
2115     SetSize(sx
, wxDefaultCoord
); 
2120 void wxListTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2124         // We must finish regardless of success, otherwise we'll get 
2128         if ( !AcceptChanges() ) 
2129             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2132     // We must let the native text control handle focus, too, otherwise 
2133     // it could have problems with the cursor (e.g., in wxGTK): 
2137 //----------------------------------------------------------------------------- 
2139 //----------------------------------------------------------------------------- 
2141 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
) 
2143 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
) 
2144   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2145   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2146   EVT_CHAR           (wxListMainWindow::OnChar
) 
2147   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2148   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2149   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2150   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2153 void wxListMainWindow::Init() 
2158     m_lineTo 
= (size_t)-1; 
2164     m_small_image_list 
= (wxImageListType 
*) NULL
; 
2165     m_normal_image_list 
= (wxImageListType 
*) NULL
; 
2167     m_small_spacing 
= 30; 
2168     m_normal_spacing 
= 40; 
2172     m_isCreated 
= false; 
2174     m_lastOnSame 
= false; 
2175     m_renameTimer 
= new wxListRenameTimer( this ); 
2179     m_lineSelectSingleOnUp 
= 
2180     m_lineBeforeLastClicked 
= (size_t)-1; 
2185 wxListMainWindow::wxListMainWindow() 
2190     m_highlightUnfocusedBrush 
= (wxBrush 
*) NULL
; 
2193 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2198                                     const wxString 
&name 
) 
2199                 : wxScrolledWindow( parent
, id
, pos
, size
, 
2200                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2204     m_highlightBrush 
= new wxBrush
 
2206                             wxSystemSettings::GetColour
 
2208                                 wxSYS_COLOUR_HIGHLIGHT
 
2213     m_highlightUnfocusedBrush 
= new wxBrush
 
2215                                        wxSystemSettings::GetColour
 
2217                                            wxSYS_COLOUR_BTNSHADOW
 
2225     SetScrollbars( 0, 0, 0, 0, 0, 0 ); 
2227     wxVisualAttributes attr 
= wxGenericListCtrl::GetClassDefaultAttributes(); 
2228     SetOwnForegroundColour( attr
.colFg 
); 
2229     SetOwnBackgroundColour( attr
.colBg 
); 
2231         SetOwnFont( attr
.font 
); 
2234 wxListMainWindow::~wxListMainWindow() 
2237     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
2239     delete m_highlightBrush
; 
2240     delete m_highlightUnfocusedBrush
; 
2242     delete m_renameTimer
; 
2245 void wxListMainWindow::CacheLineData(size_t line
) 
2247     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
2249     wxListLineData 
*ld 
= GetDummyLine(); 
2251     size_t countCol 
= GetColumnCount(); 
2252     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2254         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2257     ld
->SetImage(listctrl
->OnGetItemImage(line
)); 
2258     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
2261 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2263     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2265     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); 
2267     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2269     // we need to recreate the dummy line if the number of columns in the 
2270     // control changed as it would have the incorrect number of fields 
2272     if ( !m_lines
.IsEmpty() && 
2273             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
2275         self
->m_lines
.Clear(); 
2278     if ( m_lines
.IsEmpty() ) 
2280         wxListLineData 
*line 
= new wxListLineData(self
); 
2281         self
->m_lines
.Add(line
); 
2283         // don't waste extra memory -- there never going to be anything 
2284         // else/more in this array 
2285         self
->m_lines
.Shrink(); 
2291 // ---------------------------------------------------------------------------- 
2292 // line geometry (report mode only) 
2293 // ---------------------------------------------------------------------------- 
2295 wxCoord 
wxListMainWindow::GetLineHeight() const 
2297     // we cache the line height as calling GetTextExtent() is slow 
2298     if ( !m_lineHeight 
) 
2300         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2302         wxClientDC 
dc( self 
); 
2303         dc
.SetFont( GetFont() ); 
2306         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2308         if ( m_small_image_list 
&& m_small_image_list
->GetImageCount() ) 
2312             m_small_image_list
->GetSize(0, iw
, ih
); 
2317         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2320     return m_lineHeight
; 
2323 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2325     wxASSERT_MSG( InReportView(), _T("only works in report mode") ); 
2327     return LINE_SPACING 
+ line
*GetLineHeight(); 
2330 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2332     if ( !InReportView() ) 
2333         return GetLine(line
)->m_gi
->m_rectAll
; 
2336     rect
.x 
= HEADER_OFFSET_X
; 
2337     rect
.y 
= GetLineY(line
); 
2338     rect
.width 
= GetHeaderWidth(); 
2339     rect
.height 
= GetLineHeight(); 
2344 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2346     if ( !InReportView() ) 
2347         return GetLine(line
)->m_gi
->m_rectLabel
; 
2350     rect
.x 
= HEADER_OFFSET_X
; 
2351     rect
.y 
= GetLineY(line
); 
2352     rect
.width 
= GetColumnWidth(0); 
2353     rect
.height 
= GetLineHeight(); 
2358 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2360     if ( !InReportView() ) 
2361         return GetLine(line
)->m_gi
->m_rectIcon
; 
2363     wxListLineData 
*ld 
= GetLine(line
); 
2364     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2367     rect
.x 
= HEADER_OFFSET_X
; 
2368     rect
.y 
= GetLineY(line
); 
2369     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2374 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2376     return InReportView() ? GetLineRect(line
) 
2377                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2380 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2382     wxASSERT_MSG( line 
< GetItemCount(), _T("invalid line in HitTestLine") ); 
2384     wxListLineData 
*ld 
= GetLine(line
); 
2386     if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) ) 
2387         return wxLIST_HITTEST_ONITEMICON
; 
2389     // VS: Testing for "ld->HasText() || InReportView()" instead of 
2390     //     "ld->HasText()" is needed to make empty lines in report view 
2392     if ( ld
->HasText() || InReportView() ) 
2394         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2395                                      : GetLineLabelRect(line
); 
2397         if ( rect
.Inside(x
, y
) ) 
2398             return wxLIST_HITTEST_ONITEMLABEL
; 
2404 // ---------------------------------------------------------------------------- 
2405 // highlight (selection) handling 
2406 // ---------------------------------------------------------------------------- 
2408 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2412         return m_selStore
.IsSelected(line
); 
2416         wxListLineData 
*ld 
= GetLine(line
); 
2417         wxCHECK_MSG( ld
, false, _T("invalid index in IsHighlighted") ); 
2419         return ld
->IsHighlighted(); 
2423 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
2429         wxArrayInt linesChanged
; 
2430         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
2433             // meny items changed state, refresh everything 
2434             RefreshLines(lineFrom
, lineTo
); 
2436         else // only a few items changed state, refresh only them 
2438             size_t count 
= linesChanged
.GetCount(); 
2439             for ( size_t n 
= 0; n 
< count
; n
++ ) 
2441                 RefreshLine(linesChanged
[n
]); 
2445     else // iterate over all items in non report view 
2447         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2449             if ( HighlightLine(line
, highlight
) ) 
2457 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2463         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2467         wxListLineData 
*ld 
= GetLine(line
); 
2468         wxCHECK_MSG( ld
, false, _T("invalid index in HighlightLine") ); 
2470         changed 
= ld
->Highlight(highlight
); 
2475         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2476                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2482 void wxListMainWindow::RefreshLine( size_t line 
) 
2484     if ( InReportView() ) 
2486         size_t visibleFrom
, visibleTo
; 
2487         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2489         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
2493     wxRect rect 
= GetLineRect(line
); 
2495     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2496     RefreshRect( rect 
); 
2499 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2501     // we suppose that they are ordered by caller 
2502     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2504     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2506     if ( InReportView() ) 
2508         size_t visibleFrom
, visibleTo
; 
2509         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2511         if ( lineFrom 
< visibleFrom 
) 
2512             lineFrom 
= visibleFrom
; 
2513         if ( lineTo 
> visibleTo 
) 
2518         rect
.y 
= GetLineY(lineFrom
); 
2519         rect
.width 
= GetClientSize().x
; 
2520         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
2522         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2523         RefreshRect( rect 
); 
2527         // TODO: this should be optimized... 
2528         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2535 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2537     if ( InReportView() ) 
2539         size_t visibleFrom
, visibleTo
; 
2540         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2542         if ( lineFrom 
< visibleFrom 
) 
2543             lineFrom 
= visibleFrom
; 
2544         else if ( lineFrom 
> visibleTo 
) 
2549         rect
.y 
= GetLineY(lineFrom
); 
2550         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2552         wxSize size 
= GetClientSize(); 
2553         rect
.width 
= size
.x
; 
2554         // refresh till the bottom of the window 
2555         rect
.height 
= size
.y 
- rect
.y
; 
2557         RefreshRect( rect 
); 
2561         // TODO: how to do it more efficiently? 
2566 void wxListMainWindow::RefreshSelected() 
2572     if ( InReportView() ) 
2574         GetVisibleLinesRange(&from
, &to
); 
2579         to 
= GetItemCount() - 1; 
2582     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
2584         RefreshLine(m_current
); 
2587     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
2589         // NB: the test works as expected even if m_current == -1 
2590         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
2597 void wxListMainWindow::Freeze() 
2602 void wxListMainWindow::Thaw() 
2604     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen list control?") ); 
2606     if ( !--m_freezeCount 
) 
2612 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2614     // Note: a wxPaintDC must be constructed even if no drawing is 
2615     // done (a Windows requirement). 
2616     wxPaintDC 
dc( this ); 
2618     if ( IsEmpty() || m_freezeCount 
) 
2620         // nothing to draw or not the moment to draw it 
2626         // delay the repainting until we calculate all the items positions 
2633     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2637     dc
.SetFont( GetFont() ); 
2639     if ( InReportView() ) 
2641         int lineHeight 
= GetLineHeight(); 
2643         size_t visibleFrom
, visibleTo
; 
2644         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2647         wxCoord xOrig
, yOrig
; 
2648         CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
); 
2650         // tell the caller cache to cache the data 
2653             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2654                                 GetParent()->GetId()); 
2655             evCache
.SetEventObject( GetParent() ); 
2656             evCache
.m_oldItemIndex 
= visibleFrom
; 
2657             evCache
.m_itemIndex 
= visibleTo
; 
2658             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2661         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2663             rectLine 
= GetLineRect(line
); 
2665             if ( !IsExposed(rectLine
.x 
- xOrig
, rectLine
.y 
- yOrig
, 
2666                             rectLine
.width
, rectLine
.height
) ) 
2668                 // don't redraw unaffected lines to avoid flicker 
2672             GetLine(line
)->DrawInReportMode( &dc
, 
2674                                              GetLineHighlightRect(line
), 
2675                                              IsHighlighted(line
) ); 
2678         if ( HasFlag(wxLC_HRULES
) ) 
2680             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2681             wxSize clientSize 
= GetClientSize(); 
2683             // Don't draw the first one 
2684             for ( size_t i 
= visibleFrom
+1; i 
<= visibleTo
; i
++ ) 
2687                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2688                 dc
.DrawLine(0 - dev_x
, i
*lineHeight
, 
2689                             clientSize
.x 
- dev_x
, i
*lineHeight
); 
2692             // Draw last horizontal rule 
2693             if ( visibleTo 
== GetItemCount() - 1 ) 
2696                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2697                 dc
.DrawLine(0 - dev_x
, (m_lineTo
+1)*lineHeight
, 
2698                             clientSize
.x 
- dev_x 
, (m_lineTo
+1)*lineHeight 
); 
2702         // Draw vertical rules if required 
2703         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2705             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2707             wxRect firstItemRect
; 
2708             wxRect lastItemRect
; 
2709             GetItemRect(visibleFrom
, firstItemRect
); 
2710             GetItemRect(visibleTo
, lastItemRect
); 
2711             int x 
= firstItemRect
.GetX(); 
2713             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2714             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2716                 int colWidth 
= GetColumnWidth(col
); 
2718                 dc
.DrawLine(x 
- dev_x 
- 2, firstItemRect
.GetY() - 1 - dev_y
, 
2719                             x 
- dev_x 
- 2, lastItemRect
.GetBottom() + 1 - dev_y
); 
2725         size_t count 
= GetItemCount(); 
2726         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2728             GetLine(i
)->Draw( &dc 
); 
2733     // Don't draw rect outline under Mac at all. 
2738             dc
.SetPen( *wxBLACK_PEN 
); 
2739             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2740             dc
.DrawRectangle( GetLineHighlightRect(m_current
) ); 
2748 void wxListMainWindow::HighlightAll( bool on 
) 
2750     if ( IsSingleSel() ) 
2752         wxASSERT_MSG( !on
, _T("can't do this in a single sel control") ); 
2754         // we just have one item to turn off 
2755         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2757             HighlightLine(m_current
, false); 
2758             RefreshLine(m_current
); 
2763         HighlightLines(0, GetItemCount() - 1, on
); 
2767 void wxListMainWindow::SendNotify( size_t line
, 
2768                                    wxEventType command
, 
2771     wxListEvent 
le( command
, GetParent()->GetId() ); 
2772     le
.SetEventObject( GetParent() ); 
2773     le
.m_itemIndex 
= line
; 
2775     // set only for events which have position 
2776     if ( point 
!= wxDefaultPosition 
) 
2777         le
.m_pointDrag 
= point
; 
2779     // don't try to get the line info for virtual list controls: the main 
2780     // program has it anyhow and if we did it would result in accessing all 
2781     // the lines, even those which are not visible now and this is precisely 
2782     // what we're trying to avoid 
2783     if ( !IsVirtual() && (command 
!= wxEVT_COMMAND_LIST_DELETE_ITEM
) ) 
2785         if ( line 
!= (size_t)-1 ) 
2787             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2789         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2791     //else: there may be no more such item 
2793     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2796 void wxListMainWindow::ChangeCurrent(size_t current
) 
2798     m_current 
= current
; 
2800     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2803 void wxListMainWindow::EditLabel( long item 
) 
2805     wxCHECK_RET( (item 
>= 0) && ((size_t)item 
< GetItemCount()), 
2806                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2808     size_t itemEdit 
= (size_t)item
; 
2810     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2811     le
.SetEventObject( GetParent() ); 
2812     le
.m_itemIndex 
= item
; 
2813     wxListLineData 
*data 
= GetLine(itemEdit
); 
2814     wxCHECK_RET( data
, _T("invalid index in EditLabel()") ); 
2815     data
->GetItem( 0, le
.m_item 
); 
2816     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2818         // vetoed by user code 
2822     // We have to call this here because the label in question might just have 
2823     // been added and no screen update taken place. 
2827     wxListTextCtrl 
*text 
= new wxListTextCtrl(this, itemEdit
); 
2832 void wxListMainWindow::OnRenameTimer() 
2834     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2836     EditLabel( m_current 
); 
2839 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2841     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2842     le
.SetEventObject( GetParent() ); 
2843     le
.m_itemIndex 
= itemEdit
; 
2845     wxListLineData 
*data 
= GetLine(itemEdit
); 
2846     wxCHECK_MSG( data
, false, _T("invalid index in OnRenameAccept()") ); 
2848     data
->GetItem( 0, le
.m_item 
); 
2849     le
.m_item
.m_text 
= value
; 
2850     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2854 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2856     // let owner know that the edit was cancelled 
2857     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2859     le
.SetEditCanceled(true); 
2861     le
.SetEventObject( GetParent() ); 
2862     le
.m_itemIndex 
= itemEdit
; 
2864     wxListLineData 
*data 
= GetLine(itemEdit
); 
2865     wxCHECK_RET( data
, _T("invalid index in OnRenameCancelled()") ); 
2867     data
->GetItem( 0, le
.m_item 
); 
2869     GetEventHandler()->ProcessEvent( le 
); 
2872 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2874     event
.SetEventObject( GetParent() ); 
2875     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2878     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
2880         // let the base handle mouse wheel events. 
2885     if ( !HasCurrent() || IsEmpty() ) 
2891     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
2892         event
.ButtonDClick()) ) 
2895     int x 
= event
.GetX(); 
2896     int y 
= event
.GetY(); 
2897     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2899     // where did we hit it (if we did)? 
2902     size_t count 
= GetItemCount(), 
2905     if ( InReportView() ) 
2907         current 
= y 
/ GetLineHeight(); 
2908         if ( current 
< count 
) 
2909             hitResult 
= HitTestLine(current
, x
, y
); 
2913         // TODO: optimize it too! this is less simple than for report view but 
2914         //       enumerating all items is still not a way to do it!! 
2915         for ( current 
= 0; current 
< count
; current
++ ) 
2917             hitResult 
= HitTestLine(current
, x
, y
); 
2923     if (event
.Dragging()) 
2925         if (m_dragCount 
== 0) 
2927             // we have to report the raw, physical coords as we want to be 
2928             // able to call HitTest(event.m_pointDrag) from the user code to 
2929             // get the item being dragged 
2930             m_dragStart 
= event
.GetPosition(); 
2935         if (m_dragCount 
!= 3) 
2938         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
2939                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2941         wxListEvent 
le( command
, GetParent()->GetId() ); 
2942         le
.SetEventObject( GetParent() ); 
2943         le
.m_itemIndex 
= m_lineLastClicked
; 
2944         le
.m_pointDrag 
= m_dragStart
; 
2945         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2956         // outside of any item 
2960     bool forceClick 
= false; 
2961     if (event
.ButtonDClick()) 
2963         m_renameTimer
->Stop(); 
2964         m_lastOnSame 
= false; 
2966         if ( current 
== m_lineLastClicked 
) 
2968             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2974             // The first click was on another item, so don't interpret this as 
2975             // a double click, but as a simple click instead 
2982         if(m_lineSelectSingleOnUp 
!= (size_t) -1) 
2984             // select single line 
2985             HighlightAll( false ); 
2986             ReverseHighlight(m_lineSelectSingleOnUp
); 
2988         else if (m_lastOnSame
) 
2990             if ((current 
== m_current
) && 
2991                 (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
2992                 HasFlag(wxLC_EDIT_LABELS
)  ) 
2994                 m_renameTimer
->Start( 100, true ); 
2997         m_lastOnSame 
= false; 
2998         m_lineSelectSingleOnUp 
= (size_t) -1; 
3002         // This is neccessary , because after a DnD operation in 
3003         // from and to ourself, the up event is swallowed by the 
3004         // DnD code. So on next non-up event (which means here and 
3005         // now) m_lineSelectSingleOnUp should be reset. 
3006         m_lineSelectSingleOnUp 
= (size_t) -1; 
3008     if (event
.RightDown()) 
3010         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3011         m_lineLastClicked 
= current
; 
3012         // If the item is already selected, do not update the selection. 
3013         // Multi-selections should not be cleared if a selected item is clicked. 
3014         if (!IsHighlighted(current
)) 
3016             HighlightAll(false); 
3017             ChangeCurrent(current
); 
3018             ReverseHighlight(m_current
); 
3020         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, 
3021                     event
.GetPosition() ); 
3022         // Allow generation of context menu event 
3025     else if (event
.MiddleDown()) 
3027         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
3029     else if ( event
.LeftDown() || forceClick 
) 
3031         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3032         m_lineLastClicked 
= current
; 
3034         size_t oldCurrent 
= m_current
; 
3035         bool cmdModifierDown 
= event
.CmdDown(); 
3036         if ( !(cmdModifierDown 
|| event
.ShiftDown()) ) 
3038             if( IsSingleSel() || !IsHighlighted(current
) ) 
3040                 HighlightAll( false ); 
3042                 ChangeCurrent(current
); 
3044                 ReverseHighlight(m_current
); 
3046             else // multi sel & current is highlighted & no mod keys 
3048                 m_lineSelectSingleOnUp 
= current
; 
3049                 ChangeCurrent(current
); // change focus 
3052         else // multi sel & either ctrl or shift is down 
3054             if (cmdModifierDown
) 
3056                 ChangeCurrent(current
); 
3058                 ReverseHighlight(m_current
); 
3060             else if (event
.ShiftDown()) 
3062                 ChangeCurrent(current
); 
3064                 size_t lineFrom 
= oldCurrent
, 
3067                 if ( lineTo 
< lineFrom 
) 
3070                     lineFrom 
= m_current
; 
3073                 HighlightLines(lineFrom
, lineTo
); 
3075             else // !ctrl, !shift 
3077                 // test in the enclosing if should make it impossible 
3078                 wxFAIL_MSG( _T("how did we get here?") ); 
3082         if (m_current 
!= oldCurrent
) 
3084             RefreshLine( oldCurrent 
); 
3087         // forceClick is only set if the previous click was on another item 
3088         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
); 
3092 void wxListMainWindow::MoveToItem(size_t item
) 
3094     if ( item 
== (size_t)-1 ) 
3097     wxRect rect 
= GetLineRect(item
); 
3099     int client_w
, client_h
; 
3100     GetClientSize( &client_w
, &client_h 
); 
3102     const int hLine 
= GetLineHeight(); 
3104     int view_x 
= SCROLL_UNIT_X
*GetScrollPos( wxHORIZONTAL 
); 
3105     int view_y 
= hLine
*GetScrollPos( wxVERTICAL 
); 
3107     if ( InReportView() ) 
3109         // the next we need the range of lines shown it might be different, so 
3111         ResetVisibleLinesRange(); 
3113         if (rect
.y 
< view_y 
) 
3114             Scroll( -1, rect
.y
/hLine 
); 
3115         if (rect
.y
+rect
.height
+5 > view_y
+client_h
) 
3116             Scroll( -1, (rect
.y
+rect
.height
-client_h
+hLine
)/hLine 
); 
3120         if (rect
.x
-view_x 
< 5) 
3121             Scroll( (rect
.x
-5)/SCROLL_UNIT_X
, -1 ); 
3122         if (rect
.x
+rect
.width
-5 > view_x
+client_w
) 
3123             Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/SCROLL_UNIT_X
, -1 ); 
3127 // ---------------------------------------------------------------------------- 
3128 // keyboard handling 
3129 // ---------------------------------------------------------------------------- 
3131 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
3133     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
3134                  _T("invalid item index in OnArrowChar()") ); 
3136     size_t oldCurrent 
= m_current
; 
3138     // in single selection we just ignore Shift as we can't select several 
3140     if ( event
.ShiftDown() && !IsSingleSel() ) 
3142         ChangeCurrent(newCurrent
); 
3144         // refresh the old focus to remove it 
3145         RefreshLine( oldCurrent 
); 
3147         // select all the items between the old and the new one 
3148         if ( oldCurrent 
> newCurrent 
) 
3150             newCurrent 
= oldCurrent
; 
3151             oldCurrent 
= m_current
; 
3154         HighlightLines(oldCurrent
, newCurrent
); 
3158         // all previously selected items are unselected unless ctrl is held 
3159         if ( !event
.ControlDown() ) 
3160             HighlightAll(false); 
3162         ChangeCurrent(newCurrent
); 
3164         // refresh the old focus to remove it 
3165         RefreshLine( oldCurrent 
); 
3167         if ( !event
.ControlDown() ) 
3169             HighlightLine( m_current
, true ); 
3173     RefreshLine( m_current 
); 
3178 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
3180     wxWindow 
*parent 
= GetParent(); 
3182     /* we propagate the key event up */ 
3183     wxKeyEvent 
ke( wxEVT_KEY_DOWN 
); 
3184     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3185     ke
.m_controlDown 
= event
.m_controlDown
; 
3186     ke
.m_altDown 
= event
.m_altDown
; 
3187     ke
.m_metaDown 
= event
.m_metaDown
; 
3188     ke
.m_keyCode 
= event
.m_keyCode
; 
3191     ke
.SetEventObject( parent 
); 
3192     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3197 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
3199     wxWindow 
*parent 
= GetParent(); 
3201     /* we send a list_key event up */ 
3204         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
3205         le
.m_itemIndex 
= m_current
; 
3206         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3207         le
.m_code 
= event
.GetKeyCode(); 
3208         le
.SetEventObject( parent 
); 
3209         parent
->GetEventHandler()->ProcessEvent( le 
); 
3212     /* we propagate the char event up */ 
3213     wxKeyEvent 
ke( wxEVT_CHAR 
); 
3214     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3215     ke
.m_controlDown 
= event
.m_controlDown
; 
3216     ke
.m_altDown 
= event
.m_altDown
; 
3217     ke
.m_metaDown 
= event
.m_metaDown
; 
3218     ke
.m_keyCode 
= event
.m_keyCode
; 
3221     ke
.SetEventObject( parent 
); 
3222     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3224     if (event
.GetKeyCode() == WXK_TAB
) 
3226         wxNavigationKeyEvent nevent
; 
3227         nevent
.SetWindowChange( event
.ControlDown() ); 
3228         nevent
.SetDirection( !event
.ShiftDown() ); 
3229         nevent
.SetEventObject( GetParent()->GetParent() ); 
3230         nevent
.SetCurrentFocus( m_parent 
); 
3231         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent 
)) 
3235     /* no item -> nothing to do */ 
3242     switch (event
.GetKeyCode()) 
3245             if ( m_current 
> 0 ) 
3246                 OnArrowChar( m_current 
- 1, event 
); 
3250             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
3251                 OnArrowChar( m_current 
+ 1, event 
); 
3256                 OnArrowChar( GetItemCount() - 1, event 
); 
3261                 OnArrowChar( 0, event 
); 
3266                 int steps 
= InReportView() ? m_linesPerPage 
- 1 : m_current 
% m_linesPerPage
; 
3268                 int index 
= m_current 
- steps
; 
3272                 OnArrowChar( index
, event 
); 
3278                 int steps 
= InReportView() 
3279                                ? m_linesPerPage 
- 1 
3280                                : m_linesPerPage 
- (m_current 
% m_linesPerPage
) - 1; 
3282                 size_t index 
= m_current 
+ steps
; 
3283                 size_t count 
= GetItemCount(); 
3284                 if ( index 
>= count 
) 
3287                 OnArrowChar( index
, event 
); 
3292             if ( !InReportView() ) 
3294                 int index 
= m_current 
- m_linesPerPage
; 
3298                 OnArrowChar( index
, event 
); 
3303             if ( !InReportView() ) 
3305                 size_t index 
= m_current 
+ m_linesPerPage
; 
3307                 size_t count 
= GetItemCount(); 
3308                 if ( index 
>= count 
) 
3311                 OnArrowChar( index
, event 
); 
3316             if ( IsSingleSel() ) 
3318                 SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3320                 if ( IsHighlighted(m_current
) ) 
3322                     // don't unselect the item in single selection mode 
3325                 //else: select it in ReverseHighlight() below if unselected 
3328             ReverseHighlight(m_current
); 
3333             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3341 // ---------------------------------------------------------------------------- 
3343 // ---------------------------------------------------------------------------- 
3345 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3349         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3350         event
.SetEventObject( GetParent() ); 
3351         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3355     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
3356     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
3357     // which are already drawn correctly resulting in horrible flicker - avoid 
3367 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3371         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
3372         event
.SetEventObject( GetParent() ); 
3373         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3380 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3382     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3384         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3386     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3388         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3390     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3392         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3394     else if ( InReportView() && (m_small_image_list
)) 
3396         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3400 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3402     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3404         m_normal_image_list
->GetSize( index
, width
, height 
); 
3406     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3408         m_small_image_list
->GetSize( index
, width
, height 
); 
3410     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3412         m_small_image_list
->GetSize( index
, width
, height 
); 
3414     else if ( InReportView() && m_small_image_list 
) 
3416         m_small_image_list
->GetSize( index
, width
, height 
); 
3425 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3427     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3428     dc
.SetFont( GetFont() ); 
3431     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3433     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3436 void wxListMainWindow::SetImageList( wxImageListType 
*imageList
, int which 
) 
3440     // calc the spacing from the icon size 
3443     if ((imageList
) && (imageList
->GetImageCount()) ) 
3445         imageList
->GetSize(0, width
, height
); 
3448     if (which 
== wxIMAGE_LIST_NORMAL
) 
3450         m_normal_image_list 
= imageList
; 
3451         m_normal_spacing 
= width 
+ 8; 
3454     if (which 
== wxIMAGE_LIST_SMALL
) 
3456         m_small_image_list 
= imageList
; 
3457         m_small_spacing 
= width 
+ 14; 
3458         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
3462 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3467         m_small_spacing 
= spacing
; 
3471         m_normal_spacing 
= spacing
; 
3475 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3477     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3480 // ---------------------------------------------------------------------------- 
3482 // ---------------------------------------------------------------------------- 
3484 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3486     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3488     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3490     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3491         item
.m_width 
= GetTextLength( item
.m_text 
); 
3493     wxListHeaderData 
*column 
= node
->GetData(); 
3494     column
->SetItem( item 
); 
3496     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3498         headerWin
->m_dirty 
= true; 
3502     // invalidate it as it has to be recalculated 
3506 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3508     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3509                  _T("invalid column index") ); 
3511     wxCHECK_RET( InReportView(), 
3512                  _T("SetColumnWidth() can only be called in report mode.") ); 
3515     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3517         headerWin
->m_dirty 
= true; 
3519     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3520     wxCHECK_RET( node
, _T("no column?") ); 
3522     wxListHeaderData 
*column 
= node
->GetData(); 
3524     size_t count 
= GetItemCount(); 
3526     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3528         width 
= GetTextLength(column
->GetText()); 
3530     else if ( width 
== wxLIST_AUTOSIZE 
) 
3534             // TODO: determine the max width somehow... 
3535             width 
= WIDTH_COL_DEFAULT
; 
3539             wxClientDC 
dc(this); 
3540             dc
.SetFont( GetFont() ); 
3542             int max 
= AUTOSIZE_COL_MARGIN
; 
3544             for ( size_t i 
= 0; i 
< count
; i
++ ) 
3546                 wxListLineData 
*line 
= GetLine(i
); 
3547                 wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3549                 wxCHECK_RET( n
, _T("no subitem?") ); 
3551                 wxListItemData 
*item 
= n
->GetData(); 
3554                 if (item
->HasImage()) 
3557                     GetImageSize( item
->GetImage(), ix
, iy 
); 
3561                 if (item
->HasText()) 
3564                     dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
3572             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3576     column
->SetWidth( width 
); 
3578     // invalidate it as it has to be recalculated 
3582 int wxListMainWindow::GetHeaderWidth() const 
3584     if ( !m_headerWidth 
) 
3586         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3588         size_t count 
= GetColumnCount(); 
3589         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3591             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3595     return m_headerWidth
; 
3598 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3600     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3601     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3603     wxListHeaderData 
*column 
= node
->GetData(); 
3604     column
->GetItem( item 
); 
3607 int wxListMainWindow::GetColumnWidth( int col 
) const 
3609     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3610     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3612     wxListHeaderData 
*column 
= node
->GetData(); 
3613     return column
->GetWidth(); 
3616 // ---------------------------------------------------------------------------- 
3618 // ---------------------------------------------------------------------------- 
3620 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3622     long id 
= item
.m_itemId
; 
3623     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3624                  _T("invalid item index in SetItem") ); 
3628         wxListLineData 
*line 
= GetLine((size_t)id
); 
3629         line
->SetItem( item
.m_col
, item 
); 
3632     // update the item on screen 
3634     GetItemRect(id
, rectItem
); 
3635     RefreshRect(rectItem
); 
3638 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3640      wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3641                   _T("invalid list ctrl item index in SetItem") ); 
3643     size_t oldCurrent 
= m_current
; 
3644     size_t item 
= (size_t)litem
;    // safe because of the check above 
3646     // do we need to change the focus? 
3647     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3649         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3651             // don't do anything if this item is already focused 
3652             if ( item 
!= m_current 
) 
3654                 ChangeCurrent(item
); 
3656                 if ( oldCurrent 
!= (size_t)-1 ) 
3658                     if ( IsSingleSel() ) 
3660                         HighlightLine(oldCurrent
, false); 
3663                     RefreshLine(oldCurrent
); 
3666                 RefreshLine( m_current 
); 
3671             // don't do anything if this item is not focused 
3672             if ( item 
== m_current 
) 
3676                 if ( IsSingleSel() ) 
3678                     // we must unselect the old current item as well or we 
3679                     // might end up with more than one selected item in a 
3680                     // single selection control 
3681                     HighlightLine(oldCurrent
, false); 
3684                 RefreshLine( oldCurrent 
); 
3689     // do we need to change the selection state? 
3690     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3692         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3694         if ( IsSingleSel() ) 
3698                 // selecting the item also makes it the focused one in the 
3700                 if ( m_current 
!= item 
) 
3702                     ChangeCurrent(item
); 
3704                     if ( oldCurrent 
!= (size_t)-1 ) 
3706                         HighlightLine( oldCurrent
, false ); 
3707                         RefreshLine( oldCurrent 
); 
3713                 // only the current item may be selected anyhow 
3714                 if ( item 
!= m_current 
) 
3719         if ( HighlightLine(item
, on
) ) 
3726 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
3728     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3729                  _T("invalid list ctrl item index in GetItemState()") ); 
3731     int ret 
= wxLIST_STATE_DONTCARE
; 
3733     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3735         if ( (size_t)item 
== m_current 
) 
3736             ret 
|= wxLIST_STATE_FOCUSED
; 
3739     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3741         if ( IsHighlighted(item
) ) 
3742             ret 
|= wxLIST_STATE_SELECTED
; 
3748 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
3750     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3751                  _T("invalid item index in GetItem") ); 
3753     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3754     line
->GetItem( item
.m_col
, item 
); 
3757 // ---------------------------------------------------------------------------- 
3759 // ---------------------------------------------------------------------------- 
3761 size_t wxListMainWindow::GetItemCount() const 
3763     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3766 void wxListMainWindow::SetItemCount(long count
) 
3768     m_selStore
.SetItemCount(count
); 
3769     m_countVirt 
= count
; 
3771     ResetVisibleLinesRange(); 
3773     // scrollbars must be reset 
3777 int wxListMainWindow::GetSelectedItemCount() const 
3779     // deal with the quick case first 
3780     if ( IsSingleSel() ) 
3782         return HasCurrent() ? IsHighlighted(m_current
) : false; 
3785     // virtual controls remmebers all its selections itself 
3787         return m_selStore
.GetSelectedCount(); 
3789     // TODO: we probably should maintain the number of items selected even for 
3790     //       non virtual controls as enumerating all lines is really slow... 
3791     size_t countSel 
= 0; 
3792     size_t count 
= GetItemCount(); 
3793     for ( size_t line 
= 0; line 
< count
; line
++ ) 
3795         if ( GetLine(line
)->IsHighlighted() ) 
3802 // ---------------------------------------------------------------------------- 
3803 // item position/size 
3804 // ---------------------------------------------------------------------------- 
3806 wxRect 
wxListMainWindow::GetViewRect() const 
3808     wxASSERT_MSG( !HasFlag(wxLC_REPORT 
| wxLC_LIST
), 
3809                     _T("wxListCtrl::GetViewRect() only works in icon mode") ); 
3811     // we need to find the longest/tallest label 
3814     const int count 
= GetItemCount(); 
3817         for ( int i 
= 0; i 
< count
; i
++ ) 
3822             wxCoord x 
= r
.GetRight(), 
3832     // some fudge needed to make it look prettier 
3833     xMax 
+= 2*EXTRA_BORDER_X
; 
3834     yMax 
+= 2*EXTRA_BORDER_Y
; 
3836     // account for the scrollbars if necessary 
3837     const wxSize sizeAll 
= GetClientSize(); 
3838     if ( xMax 
> sizeAll
.x 
) 
3839         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
3840     if ( yMax 
> sizeAll
.y 
) 
3841         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
3843     return wxRect(0, 0, xMax
, yMax
); 
3846 void wxListMainWindow::GetItemRect( long index
, wxRect 
&rect 
) const 
3848     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3849                  _T("invalid index in GetItemRect") ); 
3851     // ensure that we're laid out, otherwise we could return nonsense 
3854         wxConstCast(this, wxListMainWindow
)-> 
3855             RecalculatePositions(true /* no refresh */); 
3858     rect 
= GetLineRect((size_t)index
); 
3860     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
3863 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
3866     GetItemRect(item
, rect
); 
3874 // ---------------------------------------------------------------------------- 
3875 // geometry calculation 
3876 // ---------------------------------------------------------------------------- 
3878 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
3880     wxClientDC 
dc( this ); 
3881     dc
.SetFont( GetFont() ); 
3883     const size_t count 
= GetItemCount(); 
3886     if ( HasFlag(wxLC_ICON
) ) 
3887         iconSpacing 
= m_normal_spacing
; 
3888     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
3889         iconSpacing 
= m_small_spacing
; 
3893     // Note that we do not call GetClientSize() here but 
3894     // GetSize() and subtract the border size for sunken 
3895     // borders manually. This is technically incorrect, 
3896     // but we need to know the client area's size WITHOUT 
3897     // scrollbars here. Since we don't know if there are 
3898     // any scrollbars, we use GetSize() instead. Another 
3899     // solution would be to call SetScrollbars() here to 
3900     // remove the scrollbars and call GetClientSize() then, 
3901     // but this might result in flicker and - worse - will 
3902     // reset the scrollbars to 0 which is not good at all 
3903     // if you resize a dialog/window, but don't want to 
3904     // reset the window scrolling. RR. 
3905     // Furthermore, we actually do NOT subtract the border 
3906     // width as 2 pixels is just the extra space which we 
3907     // need around the actual content in the window. Other- 
3908     // wise the text would e.g. touch the upper border. RR. 
3911     GetSize( &clientWidth
, &clientHeight 
); 
3913     const int lineHeight 
= GetLineHeight(); 
3915     if ( InReportView() ) 
3917         // all lines have the same height and we scroll one line per step 
3918         int entireHeight 
= count
*lineHeight 
+ LINE_SPACING
; 
3920         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
3922         ResetVisibleLinesRange(); 
3924         SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
3925                        GetHeaderWidth() / SCROLL_UNIT_X
, 
3926                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
3927                        GetScrollPos(wxHORIZONTAL
), 
3928                        GetScrollPos(wxVERTICAL
), 
3933         // we have 3 different layout strategies: either layout all items 
3934         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
3935         // to arrange them in top to bottom, left to right (don't ask me why 
3936         // not the other way round...) order 
3937         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
3939             int x 
= EXTRA_BORDER_X
; 
3940             int y 
= EXTRA_BORDER_Y
; 
3942             wxCoord widthMax 
= 0; 
3945             for ( i 
= 0; i 
< count
; i
++ ) 
3947                 wxListLineData 
*line 
= GetLine(i
); 
3948                 line
->CalculateSize( &dc
, iconSpacing 
); 
3949                 line
->SetPosition( x
, y
, iconSpacing 
); 
3951                 wxSize sizeLine 
= GetLineSize(i
); 
3953                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3955                     if ( sizeLine
.x 
> widthMax 
) 
3956                         widthMax 
= sizeLine
.x
; 
3960                 else // wxLC_ALIGN_LEFT 
3962                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
3966             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3968                 // traverse the items again and tweak their sizes so that they are 
3969                 // all the same in a row 
3970                 for ( i 
= 0; i 
< count
; i
++ ) 
3972                     wxListLineData 
*line 
= GetLine(i
); 
3973                     line
->m_gi
->ExtendWidth(widthMax
); 
3982                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3983                 (y 
+ lineHeight
) / lineHeight
, 
3984                 GetScrollPos( wxHORIZONTAL 
), 
3985                 GetScrollPos( wxVERTICAL 
), 
3989         else // "flowed" arrangement, the most complicated case 
3991             // at first we try without any scrollbars, if the items don't fit into 
3992             // the window, we recalculate after subtracting the space taken by the 
3995             int entireWidth 
= 0; 
3997             for (int tries 
= 0; tries 
< 2; tries
++) 
3999                 entireWidth 
= 2*EXTRA_BORDER_X
; 
4003                     // Now we have decided that the items do not fit into the 
4004                     // client area, so we need a scrollbar 
4005                     entireWidth 
+= SCROLL_UNIT_X
; 
4008                 int x 
= EXTRA_BORDER_X
; 
4009                 int y 
= EXTRA_BORDER_Y
; 
4010                 int maxWidthInThisRow 
= 0; 
4013                 int currentlyVisibleLines 
= 0; 
4015                 for (size_t i 
= 0; i 
< count
; i
++) 
4017                     currentlyVisibleLines
++; 
4018                     wxListLineData 
*line 
= GetLine(i
); 
4019                     line
->CalculateSize( &dc
, iconSpacing 
); 
4020                     line
->SetPosition( x
, y
, iconSpacing 
); 
4022                     wxSize sizeLine 
= GetLineSize(i
); 
4024                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
4025                         maxWidthInThisRow 
= sizeLine
.x
; 
4028                     if (currentlyVisibleLines 
> m_linesPerPage
) 
4029                         m_linesPerPage 
= currentlyVisibleLines
; 
4031                     if ( y 
+ sizeLine
.y 
>= clientHeight 
) 
4033                         currentlyVisibleLines 
= 0; 
4035                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
4036                         x 
+= maxWidthInThisRow
; 
4037                         entireWidth 
+= maxWidthInThisRow
; 
4038                         maxWidthInThisRow 
= 0; 
4041                     // We have reached the last item. 
4042                     if ( i 
== count 
- 1 ) 
4043                         entireWidth 
+= maxWidthInThisRow
; 
4045                     if ( (tries 
== 0) && 
4046                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
4048                         clientHeight 
-= wxSystemSettings:: 
4049                                             GetMetric(wxSYS_HSCROLL_Y
); 
4054                     if ( i 
== count 
- 1 ) 
4055                         tries 
= 1;  // Everything fits, no second try required. 
4063                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4065                 GetScrollPos( wxHORIZONTAL 
), 
4074         // FIXME: why should we call it from here? 
4081 void wxListMainWindow::RefreshAll() 
4086     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
4087     if ( headerWin 
&& headerWin
->m_dirty 
) 
4089         headerWin
->m_dirty 
= false; 
4090         headerWin
->Refresh(); 
4094 void wxListMainWindow::UpdateCurrent() 
4096     if ( !HasCurrent() && !IsEmpty() ) 
4102 long wxListMainWindow::GetNextItem( long item
, 
4103                                     int WXUNUSED(geometry
), 
4107          max 
= GetItemCount(); 
4108     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
4109                  _T("invalid listctrl index in GetNextItem()") ); 
4111     // notice that we start with the next item (or the first one if item == -1) 
4112     // and this is intentional to allow writing a simple loop to iterate over 
4113     // all selected items 
4117         // this is not an error because the index was ok initially, just no 
4128     size_t count 
= GetItemCount(); 
4129     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
4131         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
4134         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
4141 // ---------------------------------------------------------------------------- 
4143 // ---------------------------------------------------------------------------- 
4145 void wxListMainWindow::DeleteItem( long lindex 
) 
4147     size_t count 
= GetItemCount(); 
4149     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
4150                  _T("invalid item index in DeleteItem") ); 
4152     size_t index 
= (size_t)lindex
; 
4154     // we don't need to adjust the index for the previous items 
4155     if ( HasCurrent() && m_current 
>= index 
) 
4157         // if the current item is being deleted, we want the next one to 
4158         // become selected - unless there is no next one - so don't adjust 
4159         // m_current in this case 
4160         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
4166     if ( InReportView() ) 
4168         ResetVisibleLinesRange(); 
4175         m_selStore
.OnItemDelete(index
); 
4179         m_lines
.RemoveAt( index 
); 
4182     // we need to refresh the (vert) scrollbar as the number of items changed 
4185     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM 
); 
4187     RefreshAfter(index
); 
4190 void wxListMainWindow::DeleteColumn( int col 
) 
4192     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4194     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
4197     delete node
->GetData(); 
4198     m_columns
.Erase( node 
); 
4202         // update all the items 
4203         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4205             wxListLineData 
* const line 
= GetLine(i
); 
4206             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
4207             delete n
->GetData(); 
4208             line
->m_items
.Erase(n
); 
4212     // invalidate it as it has to be recalculated 
4216 void wxListMainWindow::DoDeleteAllItems() 
4220         // nothing to do - in particular, don't send the event 
4226     // to make the deletion of all items faster, we don't send the 
4227     // notifications for each item deletion in this case but only one event 
4228     // for all of them: this is compatible with wxMSW and documented in 
4229     // DeleteAllItems() description 
4231     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
4232     event
.SetEventObject( GetParent() ); 
4233     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
4242     if ( InReportView() ) 
4244         ResetVisibleLinesRange(); 
4250 void wxListMainWindow::DeleteAllItems() 
4254     RecalculatePositions(); 
4257 void wxListMainWindow::DeleteEverything() 
4259     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
4264 // ---------------------------------------------------------------------------- 
4265 // scanning for an item 
4266 // ---------------------------------------------------------------------------- 
4268 void wxListMainWindow::EnsureVisible( long index 
) 
4270     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4271                  _T("invalid index in EnsureVisible") ); 
4273     // We have to call this here because the label in question might just have 
4274     // been added and its position is not known yet 
4277         RecalculatePositions(true /* no refresh */); 
4280     MoveToItem((size_t)index
); 
4283 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) ) 
4290     size_t count 
= GetItemCount(); 
4291     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
4293         wxListLineData 
*line 
= GetLine(i
); 
4294         if ( line
->GetText(0) == tmp 
) 
4301 long wxListMainWindow::FindItem(long start
, wxUIntPtr data
) 
4307     size_t count 
= GetItemCount(); 
4308     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4310         wxListLineData 
*line 
= GetLine(i
); 
4312         line
->GetItem( 0, item 
); 
4313         if (item
.m_data 
== data
) 
4320 long wxListMainWindow::FindItem( const wxPoint
& pt 
) 
4323     GetVisibleLinesRange(&topItem
, NULL
); 
4326     GetItemPosition( GetItemCount()-1, p 
); 
4329     long id 
= (long) floor( pt
.y
*double(GetItemCount()-topItem
-1)/p
.y
+topItem 
); 
4330     if( id 
>= 0 && id 
< (long)GetItemCount() ) 
4336 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) 
4338     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4340     size_t count 
= GetItemCount(); 
4342     if ( InReportView() ) 
4344         size_t current 
= y 
/ GetLineHeight(); 
4345         if ( current 
< count 
) 
4347             flags 
= HitTestLine(current
, x
, y
); 
4354         // TODO: optimize it too! this is less simple than for report view but 
4355         //       enumerating all items is still not a way to do it!! 
4356         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4358             flags 
= HitTestLine(current
, x
, y
); 
4367 // ---------------------------------------------------------------------------- 
4369 // ---------------------------------------------------------------------------- 
4371 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4373     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
4375     int count 
= GetItemCount(); 
4376     wxCHECK_RET( item
.m_itemId 
>= 0, _T("invalid item index") ); 
4378     if (item
.m_itemId 
> count
) 
4379         item
.m_itemId 
= count
; 
4381     size_t id 
= item
.m_itemId
; 
4386     // this is unused variable 
4389     if ( InReportView() ) 
4392         // this is unused variable 
4395         ResetVisibleLinesRange(); 
4397     else if ( HasFlag(wxLC_LIST
) ) 
4399         // this is unused variable 
4404     else if ( HasFlag(wxLC_ICON
) ) 
4406         // this is unused variable 
4411     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
4413         // this is unused variable 
4414         mode 
= wxLC_ICON
;  // no typo 
4420         wxFAIL_MSG( _T("unknown mode") ); 
4423     wxListLineData 
*line 
= new wxListLineData(this); 
4425     line
->SetItem( item
.m_col
, item 
); 
4427     m_lines
.Insert( line
, id 
); 
4431     // If an item is selected at or below the point of insertion, we need to 
4432     // increment the member variables because the current row's index has gone 
4434     if ( HasCurrent() && m_current 
>= id 
) 
4439     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4441     RefreshLines(id
, GetItemCount() - 1); 
4444 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4447     if ( InReportView() ) 
4449         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4450             item
.m_width 
= GetTextLength( item
.m_text 
); 
4452         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4453         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4456             wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4457             m_columns
.Insert( node
, column 
); 
4461             m_columns
.Append( column 
); 
4466             // update all the items 
4467             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4469                 wxListLineData 
* const line 
= GetLine(i
); 
4470                 wxListItemData 
* const data 
= new wxListItemData(this); 
4472                     line
->m_items
.Insert(col
, data
); 
4474                     line
->m_items
.Append(data
); 
4478         // invalidate it as it has to be recalculated 
4483 // ---------------------------------------------------------------------------- 
4485 // ---------------------------------------------------------------------------- 
4487 wxListCtrlCompare list_ctrl_compare_func_2
; 
4488 long              list_ctrl_compare_data
; 
4490 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4492     wxListLineData 
*line1 
= *arg1
; 
4493     wxListLineData 
*line2 
= *arg2
; 
4495     line1
->GetItem( 0, item 
); 
4496     wxUIntPtr data1 
= item
.m_data
; 
4497     line2
->GetItem( 0, item 
); 
4498     wxUIntPtr data2 
= item
.m_data
; 
4499     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4502 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
4504     list_ctrl_compare_func_2 
= fn
; 
4505     list_ctrl_compare_data 
= data
; 
4506     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4510 // ---------------------------------------------------------------------------- 
4512 // ---------------------------------------------------------------------------- 
4514 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4516     // update our idea of which lines are shown when we redraw the window the 
4518     ResetVisibleLinesRange(); 
4521 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
4522     wxScrolledWindow::OnScroll(event
); 
4524     HandleOnScroll( event 
); 
4527     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4529         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4530         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4532         lc
->m_headerWin
->Refresh(); 
4533         lc
->m_headerWin
->Update(); 
4537 int wxListMainWindow::GetCountPerPage() const 
4539     if ( !m_linesPerPage 
) 
4541         wxConstCast(this, wxListMainWindow
)-> 
4542             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4545     return m_linesPerPage
; 
4548 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4550     wxASSERT_MSG( InReportView(), _T("this is for report mode only") ); 
4552     if ( m_lineFrom 
== (size_t)-1 ) 
4554         size_t count 
= GetItemCount(); 
4557             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4559             // this may happen if SetScrollbars() hadn't been called yet 
4560             if ( m_lineFrom 
>= count 
) 
4561                 m_lineFrom 
= count 
- 1; 
4563             // we redraw one extra line but this is needed to make the redrawing 
4564             // logic work when there is a fractional number of lines on screen 
4565             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4566             if ( m_lineTo 
>= count 
) 
4567                 m_lineTo 
= count 
- 1; 
4569         else // empty control 
4572             m_lineTo 
= (size_t)-1; 
4576     wxASSERT_MSG( IsEmpty() || 
4577                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4578                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4586 // ------------------------------------------------------------------------------------- 
4587 // wxGenericListCtrl 
4588 // ------------------------------------------------------------------------------------- 
4590 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4592 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4593   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4596 wxGenericListCtrl::wxGenericListCtrl() 
4598     m_imageListNormal 
= (wxImageListType 
*) NULL
; 
4599     m_imageListSmall 
= (wxImageListType 
*) NULL
; 
4600     m_imageListState 
= (wxImageListType 
*) NULL
; 
4602     m_ownsImageListNormal 
= 
4603     m_ownsImageListSmall 
= 
4604     m_ownsImageListState 
= false; 
4606     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4607     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4611 wxGenericListCtrl::~wxGenericListCtrl() 
4613     if (m_ownsImageListNormal
) 
4614         delete m_imageListNormal
; 
4615     if (m_ownsImageListSmall
) 
4616         delete m_imageListSmall
; 
4617     if (m_ownsImageListState
) 
4618         delete m_imageListState
; 
4621 void wxGenericListCtrl::CalculateAndSetHeaderHeight() 
4627         GetThemeMetric( kThemeMetricListHeaderHeight
, &h 
);     
4629         // we use 'g' to get the descent, too 
4631         m_headerWin
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
); 
4632         h 
+= d 
+ 2 * HEADER_OFFSET_Y 
+ EXTRA_HEIGHT
; 
4634         // only update if changed 
4635         if ( h 
!= m_headerHeight 
) 
4639             m_headerWin
->SetSize(m_headerWin
->GetSize().x
, m_headerHeight
); 
4642                 ResizeReportView(true); 
4647 void wxGenericListCtrl::CreateHeaderWindow() 
4649     m_headerWin 
= new wxListHeaderWindow
 
4651                         this, wxID_ANY
, m_mainWin
, 
4653                         wxSize(GetClientSize().x
, m_headerHeight
), 
4656     CalculateAndSetHeaderHeight(); 
4659 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
4664                         const wxValidator 
&validator
, 
4665                         const wxString 
&name
) 
4669     m_imageListState 
= (wxImageListType 
*) NULL
; 
4670     m_ownsImageListNormal 
= 
4671     m_ownsImageListSmall 
= 
4672     m_ownsImageListState 
= false; 
4674     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4675     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4679     if ( !(style 
& wxLC_MASK_TYPE
) ) 
4681         style 
= style 
| wxLC_LIST
; 
4684     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
4687     // don't create the inner window with the border 
4688     style 
&= ~wxBORDER_MASK
; 
4690     m_mainWin 
= new wxListMainWindow( this, wxID_ANY
, wxPoint(0,0), size
, style 
); 
4692 #ifdef  __WXMAC_CARBON__ 
4693     // Human Interface Guidelines ask us for a special font in this case 
4694     if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL 
) 
4697         font
.MacCreateThemeFont( kThemeViewsFont 
) ; 
4701     if ( InReportView() ) 
4703         CreateHeaderWindow(); 
4705         if ( HasFlag(wxLC_NO_HEADER
) ) 
4707             // VZ: why do we create it at all then? 
4708             m_headerWin
->Show( false ); 
4717 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
4719     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4720                   _T("wxLC_VIRTUAL can't be [un]set") ); 
4722     long flag 
= GetWindowStyle(); 
4726         if (style 
& wxLC_MASK_TYPE
) 
4727             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4728         if (style 
& wxLC_MASK_ALIGN
) 
4729             flag 
&= ~wxLC_MASK_ALIGN
; 
4730         if (style 
& wxLC_MASK_SORT
) 
4731             flag 
&= ~wxLC_MASK_SORT
; 
4743     SetWindowStyleFlag( flag 
); 
4746 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
4750         m_mainWin
->DeleteEverything(); 
4752         // has the header visibility changed? 
4753         bool hasHeader 
= HasHeader(); 
4754         bool willHaveHeader 
= (flag 
& wxLC_REPORT
) && !(flag 
& wxLC_NO_HEADER
); 
4756         if ( hasHeader 
!= willHaveHeader 
) 
4763                     // don't delete, just hide, as we can reuse it later 
4764                     m_headerWin
->Show(false); 
4766                 //else: nothing to do 
4768             else // must show header 
4772                     CreateHeaderWindow(); 
4774                 else // already have it, just show 
4776                     m_headerWin
->Show( true ); 
4780             ResizeReportView(willHaveHeader
); 
4784     wxWindow::SetWindowStyleFlag( flag 
); 
4787 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4789     m_mainWin
->GetColumn( col
, item 
); 
4793 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
4795     m_mainWin
->SetColumn( col
, item 
); 
4799 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
4801     return m_mainWin
->GetColumnWidth( col 
); 
4804 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
4806     m_mainWin
->SetColumnWidth( col
, width 
); 
4810 int wxGenericListCtrl::GetCountPerPage() const 
4812   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4815 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
4817     m_mainWin
->GetItem( info 
); 
4821 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
4823     m_mainWin
->SetItem( info 
); 
4827 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4830     info
.m_text 
= label
; 
4831     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4832     info
.m_itemId 
= index
; 
4836         info
.m_image 
= imageId
; 
4837         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4839     m_mainWin
->SetItem(info
); 
4843 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
4845     return m_mainWin
->GetItemState( item
, stateMask 
); 
4848 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4850     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4855 wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4858     info
.m_image 
= image
; 
4859     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4860     info
.m_itemId 
= item
; 
4861     m_mainWin
->SetItem( info 
); 
4865 wxString 
wxGenericListCtrl::GetItemText( long item 
) const 
4867     return m_mainWin
->GetItemText(item
); 
4870 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
4872     m_mainWin
->SetItemText(item
, str
); 
4875 wxUIntPtr 
wxGenericListCtrl::GetItemData( long item 
) const 
4878     info
.m_itemId 
= item
; 
4879     m_mainWin
->GetItem( info 
); 
4883 bool wxGenericListCtrl::SetItemData( long item
, long data 
) 
4886     info
.m_mask 
= wxLIST_MASK_DATA
; 
4887     info
.m_itemId 
= item
; 
4889     m_mainWin
->SetItem( info 
); 
4893 wxRect 
wxGenericListCtrl::GetViewRect() const 
4895     return m_mainWin
->GetViewRect(); 
4898 bool wxGenericListCtrl::GetItemRect( long item
, wxRect 
&rect
,  int WXUNUSED(code
) ) const 
4900     m_mainWin
->GetItemRect( item
, rect 
); 
4901     if ( m_mainWin
->HasHeader() ) 
4902         rect
.y 
+= m_headerHeight 
+ 1; 
4906 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4908     m_mainWin
->GetItemPosition( item
, pos 
); 
4912 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4917 int wxGenericListCtrl::GetItemCount() const 
4919     return m_mainWin
->GetItemCount(); 
4922 int wxGenericListCtrl::GetColumnCount() const 
4924     return m_mainWin
->GetColumnCount(); 
4927 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4929     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4932 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
4934     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
4936     return wxSize(spacing
, spacing
); 
4939 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
4941     return m_mainWin
->GetItemSpacing( isSmall 
); 
4944 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
4947     info
.m_itemId 
= item
; 
4948     info
.SetTextColour( col 
); 
4949     m_mainWin
->SetItem( info 
); 
4952 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
4955     info
.m_itemId 
= item
; 
4956     m_mainWin
->GetItem( info 
); 
4957     return info
.GetTextColour(); 
4960 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
4963     info
.m_itemId 
= item
; 
4964     info
.SetBackgroundColour( col 
); 
4965     m_mainWin
->SetItem( info 
); 
4968 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
4971     info
.m_itemId 
= item
; 
4972     m_mainWin
->GetItem( info 
); 
4973     return info
.GetBackgroundColour(); 
4976 int wxGenericListCtrl::GetSelectedItemCount() const 
4978     return m_mainWin
->GetSelectedItemCount(); 
4981 wxColour 
wxGenericListCtrl::GetTextColour() const 
4983     return GetForegroundColour(); 
4986 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
4988     SetForegroundColour(col
); 
4991 long wxGenericListCtrl::GetTopItem() const 
4994     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
4998 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
5000     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
5003 wxImageListType 
*wxGenericListCtrl::GetImageList(int which
) const 
5005     if (which 
== wxIMAGE_LIST_NORMAL
) 
5007         return m_imageListNormal
; 
5009     else if (which 
== wxIMAGE_LIST_SMALL
) 
5011         return m_imageListSmall
; 
5013     else if (which 
== wxIMAGE_LIST_STATE
) 
5015         return m_imageListState
; 
5017     return (wxImageListType 
*) NULL
; 
5020 void wxGenericListCtrl::SetImageList( wxImageListType 
*imageList
, int which 
) 
5022     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5024         if (m_ownsImageListNormal
) delete m_imageListNormal
; 
5025         m_imageListNormal 
= imageList
; 
5026         m_ownsImageListNormal 
= false; 
5028     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5030         if (m_ownsImageListSmall
) delete m_imageListSmall
; 
5031         m_imageListSmall 
= imageList
; 
5032         m_ownsImageListSmall 
= false; 
5034     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5036         if (m_ownsImageListState
) delete m_imageListState
; 
5037         m_imageListState 
= imageList
; 
5038         m_ownsImageListState 
= false; 
5041     m_mainWin
->SetImageList( imageList
, which 
); 
5044 void wxGenericListCtrl::AssignImageList(wxImageListType 
*imageList
, int which
) 
5046     SetImageList(imageList
, which
); 
5047     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5048         m_ownsImageListNormal 
= true; 
5049     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5050         m_ownsImageListSmall 
= true; 
5051     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5052         m_ownsImageListState 
= true; 
5055 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
5060 bool wxGenericListCtrl::DeleteItem( long item 
) 
5062     m_mainWin
->DeleteItem( item 
); 
5066 bool wxGenericListCtrl::DeleteAllItems() 
5068     m_mainWin
->DeleteAllItems(); 
5072 bool wxGenericListCtrl::DeleteAllColumns() 
5074     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
5075     for ( size_t n 
= 0; n 
< count
; n
++ ) 
5081 void wxGenericListCtrl::ClearAll() 
5083     m_mainWin
->DeleteEverything(); 
5086 bool wxGenericListCtrl::DeleteColumn( int col 
) 
5088     m_mainWin
->DeleteColumn( col 
); 
5090     // if we don't have the header any longer, we need to relayout the window 
5091     if ( !GetColumnCount() ) 
5093         ResizeReportView(false /* no header */); 
5099 void wxGenericListCtrl::Edit( long item 
) 
5101     m_mainWin
->EditLabel( item 
); 
5104 bool wxGenericListCtrl::EnsureVisible( long item 
) 
5106     m_mainWin
->EnsureVisible( item 
); 
5110 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
,  bool partial 
) 
5112     return m_mainWin
->FindItem( start
, str
, partial 
); 
5115 long wxGenericListCtrl::FindItem( long start
, wxUIntPtr data 
) 
5117     return m_mainWin
->FindItem( start
, data 
); 
5120 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& pt
, 
5121                            int WXUNUSED(direction
)) 
5123     return m_mainWin
->FindItem( pt 
); 
5126 long wxGenericListCtrl::HitTest( const wxPoint 
&point
, int &flags 
) 
5128     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
5131 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
5133     m_mainWin
->InsertItem( info 
); 
5134     return info
.m_itemId
; 
5137 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
5140     info
.m_text 
= label
; 
5141     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5142     info
.m_itemId 
= index
; 
5143     return InsertItem( info 
); 
5146 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
5149     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5150     info
.m_image 
= imageIndex
; 
5151     info
.m_itemId 
= index
; 
5152     return InsertItem( info 
); 
5155 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
5158     info
.m_text 
= label
; 
5159     info
.m_image 
= imageIndex
; 
5160     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
5161     info
.m_itemId 
= index
; 
5162     return InsertItem( info 
); 
5165 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
5167     wxCHECK_MSG( m_headerWin
, -1, _T("can't add column in non report mode") ); 
5169     m_mainWin
->InsertColumn( col
, item 
); 
5171     // if we hadn't had header before and have it now we need to relayout the 
5173     if ( GetColumnCount() == 1 && m_mainWin
->HasHeader() ) 
5175         ResizeReportView(true /* have header */); 
5178     m_headerWin
->Refresh(); 
5183 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
5184                                int format
, int width 
) 
5187     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
5188     item
.m_text 
= heading
; 
5191         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
5192         item
.m_width 
= width
; 
5194     item
.m_format 
= format
; 
5196     return InsertColumn( col
, item 
); 
5199 bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) ) 
5205 // fn is a function which takes 3 long arguments: item1, item2, data. 
5206 // item1 is the long data associated with a first item (NOT the index). 
5207 // item2 is the long data associated with a second item (NOT the index). 
5208 // data is the same value as passed to SortItems. 
5209 // The return value is a negative number if the first item should precede the second 
5210 // item, a positive number of the second item should precede the first, 
5211 // or zero if the two items are equivalent. 
5212 // data is arbitrary data to be passed to the sort function. 
5214 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
5216     m_mainWin
->SortItems( fn
, data 
); 
5220 // ---------------------------------------------------------------------------- 
5222 // ---------------------------------------------------------------------------- 
5224 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
5229     ResizeReportView(m_mainWin
->HasHeader()); 
5231     m_mainWin
->RecalculatePositions(); 
5234 void wxGenericListCtrl::ResizeReportView(bool showHeader
) 
5237     GetClientSize( &cw
, &ch 
); 
5241         m_headerWin
->SetSize( 0, 0, cw
, m_headerHeight 
); 
5242         m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, cw
, ch 
- m_headerHeight 
- 1 ); 
5244     else // no header window 
5246         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
5250 void wxGenericListCtrl::OnInternalIdle() 
5252     wxWindow::OnInternalIdle(); 
5254     // do it only if needed 
5255     if ( !m_mainWin
->m_dirty 
) 
5258     m_mainWin
->RecalculatePositions(); 
5261 // ---------------------------------------------------------------------------- 
5263 // ---------------------------------------------------------------------------- 
5265 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5269         m_mainWin
->SetBackgroundColour( colour 
); 
5270         m_mainWin
->m_dirty 
= true; 
5276 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5278     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5283         m_mainWin
->SetForegroundColour( colour 
); 
5284         m_mainWin
->m_dirty 
= true; 
5289         m_headerWin
->SetForegroundColour( colour 
); 
5295 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5297     if ( !wxWindow::SetFont( font 
) ) 
5302         m_mainWin
->SetFont( font 
); 
5303         m_mainWin
->m_dirty 
= true; 
5308         m_headerWin
->SetFont( font 
); 
5309         CalculateAndSetHeaderHeight(); 
5320 #include "wx/listbox.h" 
5325 wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
5328     // Use the same color scheme as wxListBox 
5329     return wxListBox::GetClassDefaultAttributes(variant
); 
5331     wxUnusedVar(variant
); 
5332     wxVisualAttributes attr
; 
5333     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
5334     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
5335     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
5340 // ---------------------------------------------------------------------------- 
5341 // methods forwarded to m_mainWin 
5342 // ---------------------------------------------------------------------------- 
5344 #if wxUSE_DRAG_AND_DROP 
5346 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5348     m_mainWin
->SetDropTarget( dropTarget 
); 
5351 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5353     return m_mainWin
->GetDropTarget(); 
5356 #endif // wxUSE_DRAG_AND_DROP 
5358 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5360     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : false; 
5363 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5365     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5368 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5370     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5373 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5376     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5379 #endif // wxUSE_MENUS 
5382 void wxGenericListCtrl::SetFocus() 
5384     /* The test in window.cpp fails as we are a composite 
5385        window, so it checks against "this", but not m_mainWin. */ 
5386     if ( DoFindFocus() != this ) 
5387         m_mainWin
->SetFocus(); 
5390 wxSize 
wxGenericListCtrl::DoGetBestSize() const 
5392     // Something is better than nothing... 
5393     // 100x80 is what the MSW version will get from the default 
5394     // wxControl::DoGetBestSize 
5395     return wxSize(100,80); 
5398 // ---------------------------------------------------------------------------- 
5399 // virtual list control support 
5400 // ---------------------------------------------------------------------------- 
5402 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5404     // this is a pure virtual function, in fact - which is not really pure 
5405     // because the controls which are not virtual don't need to implement it 
5406     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5408     return wxEmptyString
; 
5411 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5413     wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL
), 
5415                 wxT("List control has an image list, OnGetItemImage should be overridden.")); 
5420 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5422     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5423                   _T("invalid item index in OnGetItemAttr()") ); 
5425     // no attributes by default 
5429 void wxGenericListCtrl::SetItemCount(long count
) 
5431     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
5433     m_mainWin
->SetItemCount(count
); 
5436 void wxGenericListCtrl::RefreshItem(long item
) 
5438     m_mainWin
->RefreshLine(item
); 
5441 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5443     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5447  * Generic wxListCtrl is more or less a container for two other 
5448  * windows which drawings are done upon. These are namely 
5449  * 'm_headerWin' and 'm_mainWin'. 
5450  * Here we override 'virtual wxWindow::Refresh()' to mimic the 
5451  * behaviour wxListCtrl has under wxMSW. 
5453 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5457         // The easy case, no rectangle specified. 
5459             m_headerWin
->Refresh(eraseBackground
); 
5462             m_mainWin
->Refresh(eraseBackground
); 
5466         // Refresh the header window 
5469             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5470             rectHeader
.Intersect(*rect
); 
5471             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5474                 m_headerWin
->GetPosition(&x
, &y
); 
5475                 rectHeader
.Offset(-x
, -y
); 
5476                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5481         // Refresh the main window 
5484             wxRect rectMain 
= m_mainWin
->GetRect(); 
5485             rectMain
.Intersect(*rect
); 
5486             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5489                 m_mainWin
->GetPosition(&x
, &y
); 
5490                 rectMain
.Offset(-x
, -y
); 
5491                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5497 void wxGenericListCtrl::Freeze() 
5499     m_mainWin
->Freeze(); 
5502 void wxGenericListCtrl::Thaw() 
5507 #endif // wxUSE_LISTCTRL