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" 
  73 #include "wx/renderer.h" 
  75 // ---------------------------------------------------------------------------- 
  77 // ---------------------------------------------------------------------------- 
  79 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
) 
  80 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
) 
  81 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
) 
  82 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
) 
  83 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
) 
  84 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
) 
  85 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
) 
  86 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
) 
  87 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
) 
  88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
) 
  89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
) 
  90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
) 
  91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
) 
  92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
) 
  93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
) 
  94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING
) 
  95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG
) 
  96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
) 
  97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
) 
  98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
) 
  99 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED
) 
 100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
) 
 102 // ---------------------------------------------------------------------------- 
 104 // ---------------------------------------------------------------------------- 
 106 // // the height of the header window (FIXME: should depend on its font!) 
 107 // static const int HEADER_HEIGHT = 23; 
 109 static const int SCROLL_UNIT_X 
= 15; 
 111 // the spacing between the lines (in report mode) 
 112 static const int LINE_SPACING 
= 0; 
 114 // extra margins around the text label 
 115 static const int EXTRA_WIDTH 
= 3; 
 116 static const int EXTRA_HEIGHT 
= 4; 
 118 // margin between the window and the items 
 119 static const int EXTRA_BORDER_X 
= 2; 
 120 static const int EXTRA_BORDER_Y 
= 2; 
 122 // offset for the header window 
 123 static const int HEADER_OFFSET_X 
= 1; 
 124 static const int HEADER_OFFSET_Y 
= 1; 
 126 // margin between rows of icons in [small] icon view 
 127 static const int MARGIN_BETWEEN_ROWS 
= 6; 
 129 // when autosizing the columns, add some slack 
 130 static const int AUTOSIZE_COL_MARGIN 
= 10; 
 132 // default and minimal widths for the header columns 
 133 static const int WIDTH_COL_DEFAULT 
= 80; 
 134 static const int WIDTH_COL_MIN 
= 10; 
 136 // the space between the image and the text in the report mode 
 137 static const int IMAGE_MARGIN_IN_REPORT_MODE 
= 5; 
 139 // ============================================================================ 
 141 // ============================================================================ 
 143 //----------------------------------------------------------------------------- 
 144 //  wxListItemData (internal) 
 145 //----------------------------------------------------------------------------- 
 147 class WXDLLEXPORT wxListItemData
 
 150     wxListItemData(wxListMainWindow 
*owner
); 
 153     void SetItem( const wxListItem 
&info 
); 
 154     void SetImage( int image 
) { m_image 
= image
; } 
 155     void SetData( long data 
) { m_data 
= data
; } 
 156     void SetPosition( int x
, int y 
); 
 157     void SetSize( int width
, int height 
); 
 159     bool HasText() const { return !m_text
.empty(); } 
 160     const wxString
& GetText() const { return m_text
; } 
 161     void SetText(const wxString
& text
) { m_text 
= text
; } 
 163     // we can't use empty string for measuring the string width/height, so 
 164     // always return something 
 165     wxString 
GetTextForMeasuring() const 
 167         wxString s 
= GetText(); 
 174     bool IsHit( int x
, int y 
) const; 
 178     int GetWidth() const; 
 179     int GetHeight() const; 
 181     int GetImage() const { return m_image
; } 
 182     bool HasImage() const { return GetImage() != -1; } 
 184     void GetItem( wxListItem 
&info 
) const; 
 186     void SetAttr(wxListItemAttr 
*attr
) { m_attr 
= attr
; } 
 187     wxListItemAttr 
*GetAttr() const { return m_attr
; } 
 190     // the item image or -1 
 193     // user data associated with the item 
 196     // the item coordinates are not used in report mode, instead this pointer 
 197     // is NULL and the owner window is used to retrieve the item position and 
 201     // the list ctrl we are in 
 202     wxListMainWindow 
*m_owner
; 
 204     // custom attributes or NULL 
 205     wxListItemAttr 
*m_attr
; 
 208     // common part of all ctors 
 214 //----------------------------------------------------------------------------- 
 215 //  wxListHeaderData (internal) 
 216 //----------------------------------------------------------------------------- 
 218 class WXDLLEXPORT wxListHeaderData 
: public wxObject
 
 222     wxListHeaderData( const wxListItem 
&info 
); 
 223     void SetItem( const wxListItem 
&item 
); 
 224     void SetPosition( int x
, int y 
); 
 225     void SetWidth( int w 
); 
 226     void SetFormat( int format 
); 
 227     void SetHeight( int h 
); 
 228     bool HasImage() const; 
 230     bool HasText() const { return !m_text
.empty(); } 
 231     const wxString
& GetText() const { return m_text
; } 
 232     void SetText(const wxString
& text
) { m_text 
= text
; } 
 234     void GetItem( wxListItem 
&item 
); 
 236     bool IsHit( int x
, int y 
) const; 
 237     int GetImage() const; 
 238     int GetWidth() const; 
 239     int GetFormat() const; 
 255 //----------------------------------------------------------------------------- 
 256 //  wxListLineData (internal) 
 257 //----------------------------------------------------------------------------- 
 259 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
); 
 260 #include "wx/listimpl.cpp" 
 261 WX_DEFINE_LIST(wxListItemDataList
); 
 266     // the list of subitems: only may have more than one item in report mode 
 267     wxListItemDataList m_items
; 
 269     // this is not used in report view 
 281         // the part to be highlighted 
 282         wxRect m_rectHighlight
; 
 284         // extend all our rects to be centered inside theo ne of given width 
 285         void ExtendWidth(wxCoord w
) 
 287             wxASSERT_MSG( m_rectAll
.width 
<= w
, 
 288                             _T("width can only be increased") ); 
 291             m_rectLabel
.x 
= m_rectAll
.x 
+ (w 
- m_rectLabel
.width
)/2; 
 292             m_rectIcon
.x 
= m_rectAll
.x 
+ (w 
- m_rectIcon
.width
)/2; 
 293             m_rectHighlight
.x 
= m_rectAll
.x 
+ (w 
- m_rectHighlight
.width
)/2; 
 297     // is this item selected? [NB: not used in virtual mode] 
 300     // back pointer to the list ctrl 
 301     wxListMainWindow 
*m_owner
; 
 304     wxListLineData(wxListMainWindow 
*owner
); 
 308         WX_CLEAR_LIST(wxListItemDataList
, m_items
); 
 312     // are we in report mode? 
 313     inline bool InReportView() const; 
 315     // are we in virtual report mode? 
 316     inline bool IsVirtual() const; 
 318     // these 2 methods shouldn't be called for report view controls, in that 
 319     // case we determine our position/size ourselves 
 321     // calculate the size of the line 
 322     void CalculateSize( wxDC 
*dc
, int spacing 
); 
 324     // remember the position this line appears at 
 325     void SetPosition( int x
, int y
, int spacing 
); 
 329     void SetImage( int image 
) { SetImage(0, image
); } 
 330     int GetImage() const { return GetImage(0); } 
 331     bool HasImage() const { return GetImage() != -1; } 
 332     bool HasText() const { return !GetText(0).empty(); } 
 334     void SetItem( int index
, const wxListItem 
&info 
); 
 335     void GetItem( int index
, wxListItem 
&info 
); 
 337     wxString 
GetText(int index
) const; 
 338     void SetText( int index
, const wxString s 
); 
 340     wxListItemAttr 
*GetAttr() const; 
 341     void SetAttr(wxListItemAttr 
*attr
); 
 343     // return true if the highlighting really changed 
 344     bool Highlight( bool on 
); 
 346     void ReverseHighlight(); 
 348     bool IsHighlighted() const 
 350         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); 
 352         return m_highlighted
; 
 355     // draw the line on the given DC in icon/list mode 
 356     void Draw( wxDC 
*dc 
); 
 358     // the same in report mode 
 359     void DrawInReportMode( wxDC 
*dc
, 
 361                            const wxRect
& rectHL
, 
 365     // set the line to contain num items (only can be > 1 in report mode) 
 366     void InitItems( int num 
); 
 368     // get the mode (i.e. style)  of the list control 
 369     inline int GetMode() const; 
 371     // prepare the DC for drawing with these item's attributes, return true if 
 372     // we need to draw the items background to highlight it, false otherwise 
 373     bool SetAttributes(wxDC 
*dc
, 
 374                        const wxListItemAttr 
*attr
, 
 377     // draw the text on the DC with the correct justification; also add an 
 378     // ellipsis if the text is too large to fit in the current width 
 379     void DrawTextFormatted(wxDC 
*dc
, const wxString 
&text
, int col
, int x
, int y
, int width
); 
 381     // these are only used by GetImage/SetImage above, we don't support images 
 382     // with subitems at the public API level yet 
 383     void SetImage( int index
, int image 
); 
 384     int GetImage( int index 
) const; 
 387 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
); 
 388 #include "wx/arrimpl.cpp" 
 389 WX_DEFINE_OBJARRAY(wxListLineDataArray
); 
 391 //----------------------------------------------------------------------------- 
 392 //  wxListHeaderWindow (internal) 
 393 //----------------------------------------------------------------------------- 
 395 class WXDLLEXPORT wxListHeaderWindow 
: public wxWindow
 
 398     wxListMainWindow  
*m_owner
; 
 399     wxCursor          
*m_currentCursor
; 
 400     wxCursor          
*m_resizeCursor
; 
 403     // column being resized or -1 
 406     // divider line position in logical (unscrolled) coords 
 409     // minimal position beyond which the divider line can't be dragged in 
 414     wxListHeaderWindow(); 
 416     wxListHeaderWindow( wxWindow 
*win
, 
 418                         wxListMainWindow 
*owner
, 
 419                         const wxPoint 
&pos 
= wxDefaultPosition
, 
 420                         const wxSize 
&size 
= wxDefaultSize
, 
 422                         const wxString 
&name 
= wxT("wxlistctrlcolumntitles") ); 
 424     virtual ~wxListHeaderWindow(); 
 427     void AdjustDC(wxDC
& dc
); 
 429     void OnPaint( wxPaintEvent 
&event 
); 
 430     void OnMouse( wxMouseEvent 
&event 
); 
 431     void OnSetFocus( wxFocusEvent 
&event 
); 
 437     // common part of all ctors 
 440     // generate and process the list event of the given type, return true if 
 441     // it wasn't vetoed, i.e. if we should proceed 
 442     bool SendListEvent(wxEventType type
, wxPoint pos
); 
 444     DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
) 
 445     DECLARE_EVENT_TABLE() 
 448 //----------------------------------------------------------------------------- 
 449 // wxListRenameTimer (internal) 
 450 //----------------------------------------------------------------------------- 
 452 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
 
 455     wxListMainWindow 
*m_owner
; 
 458     wxListRenameTimer( wxListMainWindow 
*owner 
); 
 462 //----------------------------------------------------------------------------- 
 463 //  wxListTextCtrl (internal) 
 464 //----------------------------------------------------------------------------- 
 466 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
 
 469     wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
); 
 472     void OnChar( wxKeyEvent 
&event 
); 
 473     void OnKeyUp( wxKeyEvent 
&event 
); 
 474     void OnKillFocus( wxFocusEvent 
&event 
); 
 476     bool AcceptChanges(); 
 480     wxListMainWindow   
*m_owner
; 
 481     wxString            m_startValue
; 
 485     DECLARE_EVENT_TABLE() 
 488 //----------------------------------------------------------------------------- 
 489 //  wxListMainWindow (internal) 
 490 //----------------------------------------------------------------------------- 
 492 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
); 
 493 #include "wx/listimpl.cpp" 
 494 WX_DEFINE_LIST(wxListHeaderDataList
); 
 496 class wxListMainWindow 
: public wxScrolledWindow
 
 500     wxListMainWindow( wxWindow 
*parent
, 
 502                       const wxPoint
& pos 
= wxDefaultPosition
, 
 503                       const wxSize
& size 
= wxDefaultSize
, 
 505                       const wxString 
&name 
= _T("listctrlmainwindow") ); 
 507     virtual ~wxListMainWindow(); 
 509     bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); } 
 511     // return true if this is a virtual list control 
 512     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); } 
 514     // return true if the control is in report mode 
 515     bool InReportView() const { return HasFlag(wxLC_REPORT
); } 
 517     // return true if we are in single selection mode, false if multi sel 
 518     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); } 
 520     // do we have a header window? 
 521     bool HasHeader() const 
 522         { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); } 
 524     void HighlightAll( bool on 
); 
 526     // all these functions only do something if the line is currently visible 
 528     // change the line "selected" state, return TRUE if it really changed 
 529     bool HighlightLine( size_t line
, bool highlight 
= TRUE
); 
 531     // as HighlightLine() but do it for the range of lines: this is incredibly 
 532     // more efficient for virtual list controls! 
 534     // NB: unlike HighlightLine() this one does refresh the lines on screen 
 535     void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on 
= TRUE 
); 
 537     // toggle the line state and refresh it 
 538     void ReverseHighlight( size_t line 
) 
 539         { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); } 
 541     // return true if the line is highlighted 
 542     bool IsHighlighted(size_t line
) const; 
 544     // refresh one or several lines at once 
 545     void RefreshLine( size_t line 
); 
 546     void RefreshLines( size_t lineFrom
, size_t lineTo 
); 
 548     // refresh all selected items 
 549     void RefreshSelected(); 
 551     // refresh all lines below the given one: the difference with 
 552     // RefreshLines() is that the index here might not be a valid one (happens 
 553     // when the last line is deleted) 
 554     void RefreshAfter( size_t lineFrom 
); 
 556     // the methods which are forwarded to wxListLineData itself in list/icon 
 557     // modes but are here because the lines don't store their positions in the 
 560     // get the bound rect for the entire line 
 561     wxRect 
GetLineRect(size_t line
) const; 
 563     // get the bound rect of the label 
 564     wxRect 
GetLineLabelRect(size_t line
) const; 
 566     // get the bound rect of the items icon (only may be called if we do have 
 568     wxRect 
GetLineIconRect(size_t line
) const; 
 570     // get the rect to be highlighted when the item has focus 
 571     wxRect 
GetLineHighlightRect(size_t line
) const; 
 573     // get the size of the total line rect 
 574     wxSize 
GetLineSize(size_t line
) const 
 575         { return GetLineRect(line
).GetSize(); } 
 577     // return the hit code for the corresponding position (in this line) 
 578     long HitTestLine(size_t line
, int x
, int y
) const; 
 580     // bring the selected item into view, scrolling to it if necessary 
 581     void MoveToItem(size_t item
); 
 583     // bring the current item into view 
 584     void MoveToFocus() { MoveToItem(m_current
); } 
 586     // start editing the label of the given item 
 587     void EditLabel( long item 
); 
 589     // suspend/resume redrawing the control 
 595     void OnRenameTimer(); 
 596     bool OnRenameAccept(size_t itemEdit
, const wxString
& value
); 
 597     void OnRenameCancelled(size_t itemEdit
); 
 599     void OnMouse( wxMouseEvent 
&event 
); 
 601     // called to switch the selection from the current item to newCurrent, 
 602     void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event 
); 
 604     void OnChar( wxKeyEvent 
&event 
); 
 605     void OnKeyDown( wxKeyEvent 
&event 
); 
 606     void OnSetFocus( wxFocusEvent 
&event 
); 
 607     void OnKillFocus( wxFocusEvent 
&event 
); 
 608     void OnScroll(wxScrollWinEvent
& event
) ; 
 610     void OnPaint( wxPaintEvent 
&event 
); 
 612     void DrawImage( int index
, wxDC 
*dc
, int x
, int y 
); 
 613     void GetImageSize( int index
, int &width
, int &height 
) const; 
 614     int GetTextLength( const wxString 
&s 
) const; 
 616     void SetImageList( wxImageListType 
*imageList
, int which 
); 
 617     void SetItemSpacing( int spacing
, bool isSmall 
= FALSE 
); 
 618     int GetItemSpacing( bool isSmall 
= FALSE 
); 
 620     void SetColumn( int col
, wxListItem 
&item 
); 
 621     void SetColumnWidth( int col
, int width 
); 
 622     void GetColumn( int col
, wxListItem 
&item 
) const; 
 623     int GetColumnWidth( int col 
) const; 
 624     int GetColumnCount() const { return m_columns
.GetCount(); } 
 626     // returns the sum of the heights of all columns 
 627     int GetHeaderWidth() const; 
 629     int GetCountPerPage() const; 
 631     void SetItem( wxListItem 
&item 
); 
 632     void GetItem( wxListItem 
&item 
) const; 
 633     void SetItemState( long item
, long state
, long stateMask 
); 
 634     int GetItemState( long item
, long stateMask 
) const; 
 635     void GetItemRect( long index
, wxRect 
&rect 
) const; 
 636     wxRect 
GetViewRect() const; 
 637     bool GetItemPosition( long item
, wxPoint
& pos 
) const; 
 638     int GetSelectedItemCount() const; 
 640     wxString 
GetItemText(long item
) const 
 643         info
.m_itemId 
= item
; 
 648     void SetItemText(long item
, const wxString
& value
) 
 651         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 652         info
.m_itemId 
= item
; 
 657     // set the scrollbars and update the positions of the items 
 658     void RecalculatePositions(bool noRefresh 
= FALSE
); 
 660     // refresh the window and the header 
 663     long GetNextItem( long item
, int geometry
, int state 
) const; 
 664     void DeleteItem( long index 
); 
 665     void DeleteAllItems(); 
 666     void DeleteColumn( int col 
); 
 667     void DeleteEverything(); 
 668     void EnsureVisible( long index 
); 
 669     long FindItem( long start
, const wxString
& str
, bool partial 
= FALSE 
); 
 670     long FindItem( long start
, long data
); 
 671     long HitTest( int x
, int y
, int &flags 
); 
 672     void InsertItem( wxListItem 
&item 
); 
 673     void InsertColumn( long col
, wxListItem 
&item 
); 
 674     void SortItems( wxListCtrlCompare fn
, long data 
); 
 676     size_t GetItemCount() const; 
 677     bool IsEmpty() const { return GetItemCount() == 0; } 
 678     void SetItemCount(long count
); 
 680     // change the current (== focused) item, send a notification event 
 681     void ChangeCurrent(size_t current
); 
 682     void ResetCurrent() { ChangeCurrent((size_t)-1); } 
 683     bool HasCurrent() const { return m_current 
!= (size_t)-1; } 
 685     // send out a wxListEvent 
 686     void SendNotify( size_t line
, 
 688                      wxPoint point 
= wxDefaultPosition 
); 
 690     // override base class virtual to reset m_lineHeight when the font changes 
 691     virtual bool SetFont(const wxFont
& font
) 
 693         if ( !wxScrolledWindow::SetFont(font
) ) 
 701     // these are for wxListLineData usage only 
 703     // get the backpointer to the list ctrl 
 704     wxGenericListCtrl 
*GetListCtrl() const 
 706         return wxStaticCast(GetParent(), wxGenericListCtrl
); 
 709     // get the height of all lines (assuming they all do have the same height) 
 710     wxCoord 
GetLineHeight() const; 
 712     // get the y position of the given line (only for report view) 
 713     wxCoord 
GetLineY(size_t line
) const; 
 715     // get the brush to use for the item highlighting 
 716     wxBrush 
*GetHighlightBrush() const 
 718         return m_hasFocus 
? m_highlightBrush 
: m_highlightUnfocusedBrush
; 
 722     // the array of all line objects for a non virtual list control (for the 
 723     // virtual list control we only ever use m_lines[0]) 
 724     wxListLineDataArray  m_lines
; 
 726     // the list of column objects 
 727     wxListHeaderDataList m_columns
; 
 729     // currently focused item or -1 
 732     // the number of lines per page 
 735     // this flag is set when something which should result in the window 
 736     // redrawing happens (i.e. an item was added or deleted, or its appearance 
 737     // changed) and OnPaint() doesn't redraw the window while it is set which 
 738     // allows to minimize the number of repaintings when a lot of items are 
 739     // being added. The real repainting occurs only after the next OnIdle() 
 743     wxColour            
*m_highlightColour
; 
 744     wxImageListType         
*m_small_image_list
; 
 745     wxImageListType         
*m_normal_image_list
; 
 747     int                  m_normal_spacing
; 
 751     wxTimer             
*m_renameTimer
; 
 756     // for double click logic 
 757     size_t m_lineLastClicked
, 
 758            m_lineBeforeLastClicked
; 
 761     // the total count of items in a virtual list control 
 764     // the object maintaining the items selection state, only used in virtual 
 766     wxSelectionStore m_selStore
; 
 768     // common part of all ctors 
 771     // get the line data for the given index 
 772     wxListLineData 
*GetLine(size_t n
) const 
 774         wxASSERT_MSG( n 
!= (size_t)-1, _T("invalid line index") ); 
 778             wxConstCast(this, wxListMainWindow
)->CacheLineData(n
); 
 786     // get a dummy line which can be used for geometry calculations and such: 
 787     // you must use GetLine() if you want to really draw the line 
 788     wxListLineData 
*GetDummyLine() const; 
 790     // cache the line data of the n-th line in m_lines[0] 
 791     void CacheLineData(size_t line
); 
 793     // get the range of visible lines 
 794     void GetVisibleLinesRange(size_t *from
, size_t *to
); 
 796     // force us to recalculate the range of visible lines 
 797     void ResetVisibleLinesRange() { m_lineFrom 
= (size_t)-1; } 
 799     // get the colour to be used for drawing the rules 
 800     wxColour 
GetRuleColour() const 
 805         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 810     // initialize the current item if needed 
 811     void UpdateCurrent(); 
 813     // delete all items but don't refresh: called from dtor 
 814     void DoDeleteAllItems(); 
 816     // the height of one line using the current font 
 817     wxCoord m_lineHeight
; 
 819     // the total header width or 0 if not calculated yet 
 820     wxCoord m_headerWidth
; 
 822     // the first and last lines being shown on screen right now (inclusive), 
 823     // both may be -1 if they must be calculated so never access them directly: 
 824     // use GetVisibleLinesRange() above instead 
 828     // the brushes to use for item highlighting when we do/don't have focus 
 829     wxBrush 
*m_highlightBrush
, 
 830             *m_highlightUnfocusedBrush
; 
 832     // if this is > 0, the control is frozen and doesn't redraw itself 
 833     size_t m_freezeCount
; 
 835     DECLARE_DYNAMIC_CLASS(wxListMainWindow
) 
 836     DECLARE_EVENT_TABLE() 
 838     friend class wxGenericListCtrl
; 
 841 // ============================================================================ 
 843 // ============================================================================ 
 845 //----------------------------------------------------------------------------- 
 847 //----------------------------------------------------------------------------- 
 849 wxListItemData::~wxListItemData() 
 851     // in the virtual list control the attributes are managed by the main 
 852     // program, so don't delete them 
 853     if ( !m_owner
->IsVirtual() ) 
 861 void wxListItemData::Init() 
 869 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
 875     if ( owner
->InReportView() ) 
 885 void wxListItemData::SetItem( const wxListItem 
&info 
) 
 887     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
 888         SetText(info
.m_text
); 
 889     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 890         m_image 
= info
.m_image
; 
 891     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
 892         m_data 
= info
.m_data
; 
 894     if ( info
.HasAttributes() ) 
 897             *m_attr 
= *info
.GetAttributes(); 
 899             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
 907         m_rect
->width 
= info
.m_width
; 
 911 void wxListItemData::SetPosition( int x
, int y 
) 
 913     wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") ); 
 919 void wxListItemData::SetSize( int width
, int height 
) 
 921     wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") ); 
 924         m_rect
->width 
= width
; 
 926         m_rect
->height 
= height
; 
 929 bool wxListItemData::IsHit( int x
, int y 
) const 
 931     wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") ); 
 933     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
); 
 936 int wxListItemData::GetX() const 
 938     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 943 int wxListItemData::GetY() const 
 945     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 950 int wxListItemData::GetWidth() const 
 952     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 954     return m_rect
->width
; 
 957 int wxListItemData::GetHeight() const 
 959     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 961     return m_rect
->height
; 
 964 void wxListItemData::GetItem( wxListItem 
&info 
) const 
 966     info
.m_text 
= m_text
; 
 967     info
.m_image 
= m_image
; 
 968     info
.m_data 
= m_data
; 
 972         if ( m_attr
->HasTextColour() ) 
 973             info
.SetTextColour(m_attr
->GetTextColour()); 
 974         if ( m_attr
->HasBackgroundColour() ) 
 975             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
 976         if ( m_attr
->HasFont() ) 
 977             info
.SetFont(m_attr
->GetFont()); 
 981 //----------------------------------------------------------------------------- 
 983 //----------------------------------------------------------------------------- 
 985 void wxListHeaderData::Init() 
 996 wxListHeaderData::wxListHeaderData() 
1001 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
1008 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
1010     m_mask 
= item
.m_mask
; 
1012     if ( m_mask 
& wxLIST_MASK_TEXT 
) 
1013         m_text 
= item
.m_text
; 
1015     if ( m_mask 
& wxLIST_MASK_IMAGE 
) 
1016         m_image 
= item
.m_image
; 
1018     if ( m_mask 
& wxLIST_MASK_FORMAT 
) 
1019         m_format 
= item
.m_format
; 
1021     if ( m_mask 
& wxLIST_MASK_WIDTH 
) 
1022         SetWidth(item
.m_width
); 
1025 void wxListHeaderData::SetPosition( int x
, int y 
) 
1031 void wxListHeaderData::SetHeight( int h 
) 
1036 void wxListHeaderData::SetWidth( int w 
) 
1040         m_width 
= WIDTH_COL_DEFAULT
; 
1041     else if (m_width 
< WIDTH_COL_MIN
) 
1042         m_width 
= WIDTH_COL_MIN
; 
1045 void wxListHeaderData::SetFormat( int format 
) 
1050 bool wxListHeaderData::HasImage() const 
1052     return m_image 
!= -1; 
1055 bool wxListHeaderData::IsHit( int x
, int y 
) const 
1057     return ((x 
>= m_xpos
) && (x 
<= m_xpos
+m_width
) && (y 
>= m_ypos
) && (y 
<= m_ypos
+m_height
)); 
1060 void wxListHeaderData::GetItem( wxListItem
& item 
) 
1062     item
.m_mask 
= m_mask
; 
1063     item
.m_text 
= m_text
; 
1064     item
.m_image 
= m_image
; 
1065     item
.m_format 
= m_format
; 
1066     item
.m_width 
= m_width
; 
1069 int wxListHeaderData::GetImage() const 
1074 int wxListHeaderData::GetWidth() const 
1079 int wxListHeaderData::GetFormat() const 
1084 //----------------------------------------------------------------------------- 
1086 //----------------------------------------------------------------------------- 
1088 inline int wxListLineData::GetMode() const 
1090     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
1093 inline bool wxListLineData::InReportView() const 
1095     return m_owner
->HasFlag(wxLC_REPORT
); 
1098 inline bool wxListLineData::IsVirtual() const 
1100     return m_owner
->IsVirtual(); 
1103 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
1107     if ( InReportView() ) 
1113         m_gi 
= new GeometryInfo
; 
1116     m_highlighted 
= FALSE
; 
1118     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
1121 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
1123     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1124     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1126     wxListItemData 
*item 
= node
->GetData(); 
1131     switch ( GetMode() ) 
1134         case wxLC_SMALL_ICON
: 
1135             m_gi
->m_rectAll
.width 
= spacing
; 
1137             s 
= item
->GetText(); 
1142                 m_gi
->m_rectLabel
.width 
= 
1143                 m_gi
->m_rectLabel
.height 
= 0; 
1147                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
1151                 m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
1153                     m_gi
->m_rectAll
.width 
= lw
; 
1155                 m_gi
->m_rectLabel
.width 
= lw
; 
1156                 m_gi
->m_rectLabel
.height 
= lh
; 
1159             if (item
->HasImage()) 
1162                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1163                 m_gi
->m_rectIcon
.width 
= w 
+ 8; 
1164                 m_gi
->m_rectIcon
.height 
= h 
+ 8; 
1166                 if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
1167                     m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
1168                 if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
1169                     m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
1172             if ( item
->HasText() ) 
1174                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
1175                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
1177             else // no text, highlight the icon 
1179                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
1180                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
1185             s 
= item
->GetTextForMeasuring(); 
1187             dc
->GetTextExtent( s
, &lw
, &lh 
); 
1191             m_gi
->m_rectLabel
.width 
= lw
; 
1192             m_gi
->m_rectLabel
.height 
= lh
; 
1194             m_gi
->m_rectAll
.width 
= lw
; 
1195             m_gi
->m_rectAll
.height 
= lh
; 
1197             if (item
->HasImage()) 
1200                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1201                 m_gi
->m_rectIcon
.width 
= w
; 
1202                 m_gi
->m_rectIcon
.height 
= h
; 
1204                 m_gi
->m_rectAll
.width 
+= 4 + w
; 
1205                 if (h 
> m_gi
->m_rectAll
.height
) 
1206                     m_gi
->m_rectAll
.height 
= h
; 
1209             m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
1210             m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
1214             wxFAIL_MSG( _T("unexpected call to SetSize") ); 
1218             wxFAIL_MSG( _T("unknown mode") ); 
1222 void wxListLineData::SetPosition( int x
, int y
, int spacing 
) 
1224     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1225     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1227     wxListItemData 
*item 
= node
->GetData(); 
1229     switch ( GetMode() ) 
1232         case wxLC_SMALL_ICON
: 
1233             m_gi
->m_rectAll
.x 
= x
; 
1234             m_gi
->m_rectAll
.y 
= y
; 
1236             if ( item
->HasImage() ) 
1238                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 + 
1239                     (m_gi
->m_rectAll
.width 
- m_gi
->m_rectIcon
.width
) / 2; 
1240                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
1243             if ( item
->HasText() ) 
1245                 if (m_gi
->m_rectAll
.width 
> spacing
) 
1246                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1248                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2); 
1249                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
1250                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
1251                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
1253             else // no text, highlight the icon 
1255                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
1256                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
1261             m_gi
->m_rectAll
.x 
= x
; 
1262             m_gi
->m_rectAll
.y 
= y
; 
1264             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
1265             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
1266             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1268             if (item
->HasImage()) 
1270                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1271                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1272                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 6 + m_gi
->m_rectIcon
.width
; 
1276                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1281             wxFAIL_MSG( _T("unexpected call to SetPosition") ); 
1285             wxFAIL_MSG( _T("unknown mode") ); 
1289 void wxListLineData::InitItems( int num 
) 
1291     for (int i 
= 0; i 
< num
; i
++) 
1292         m_items
.Append( new wxListItemData(m_owner
) ); 
1295 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
1297     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1298     wxCHECK_RET( node
, _T("invalid column index in SetItem") ); 
1300     wxListItemData 
*item 
= node
->GetData(); 
1301     item
->SetItem( info 
); 
1304 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
1306     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1309         wxListItemData 
*item 
= node
->GetData(); 
1310         item
->GetItem( info 
); 
1314 wxString 
wxListLineData::GetText(int index
) const 
1318     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1321         wxListItemData 
*item 
= node
->GetData(); 
1322         s 
= item
->GetText(); 
1328 void wxListLineData::SetText( int index
, const wxString s 
) 
1330     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1333         wxListItemData 
*item 
= node
->GetData(); 
1338 void wxListLineData::SetImage( int index
, int image 
) 
1340     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1341     wxCHECK_RET( node
, _T("invalid column index in SetImage()") ); 
1343     wxListItemData 
*item 
= node
->GetData(); 
1344     item
->SetImage(image
); 
1347 int wxListLineData::GetImage( int index 
) const 
1349     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1350     wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") ); 
1352     wxListItemData 
*item 
= node
->GetData(); 
1353     return item
->GetImage(); 
1356 wxListItemAttr 
*wxListLineData::GetAttr() const 
1358     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1359     wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") ); 
1361     wxListItemData 
*item 
= node
->GetData(); 
1362     return item
->GetAttr(); 
1365 void wxListLineData::SetAttr(wxListItemAttr 
*attr
) 
1367     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1368     wxCHECK_RET( node
, _T("invalid column index in SetAttr()") ); 
1370     wxListItemData 
*item 
= node
->GetData(); 
1371     item
->SetAttr(attr
); 
1374 bool wxListLineData::SetAttributes(wxDC 
*dc
, 
1375                                    const wxListItemAttr 
*attr
, 
1378     wxWindow 
*listctrl 
= m_owner
->GetParent(); 
1382     // don't use foreground colour for drawing highlighted items - this might 
1383     // make them completely invisible (and there is no way to do bit 
1384     // arithmetics on wxColour, unfortunately) 
1388         colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1392         if ( attr 
&& attr
->HasTextColour() ) 
1394             colText 
= attr
->GetTextColour(); 
1398             colText 
= listctrl
->GetForegroundColour(); 
1402     dc
->SetTextForeground(colText
); 
1406     if ( attr 
&& attr
->HasFont() ) 
1408         font 
= attr
->GetFont(); 
1412         font 
= listctrl
->GetFont(); 
1418     bool hasBgCol 
= attr 
&& attr
->HasBackgroundColour(); 
1419     if ( highlighted 
|| hasBgCol 
) 
1423             dc
->SetBrush( *m_owner
->GetHighlightBrush() ); 
1427             dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
)); 
1430         dc
->SetPen( *wxTRANSPARENT_PEN 
); 
1438 void wxListLineData::Draw( wxDC 
*dc 
) 
1440     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1441     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1443     bool highlighted 
= IsHighlighted(); 
1445     wxListItemAttr 
*attr 
= GetAttr(); 
1447     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1449         dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1452     // just for debugging to better see where the items are 
1454     dc
->SetPen(*wxRED_PEN
); 
1455     dc
->SetBrush(*wxTRANSPARENT_BRUSH
); 
1456     dc
->DrawRectangle( m_gi
->m_rectAll 
); 
1457     dc
->SetPen(*wxGREEN_PEN
); 
1458     dc
->DrawRectangle( m_gi
->m_rectIcon 
); 
1461     wxListItemData 
*item 
= node
->GetData(); 
1462     if (item
->HasImage()) 
1464         // centre the image inside our rectangle, this looks nicer when items 
1465         // ae aligned in a row 
1466         const wxRect
& rectIcon 
= m_gi
->m_rectIcon
; 
1468         m_owner
->DrawImage(item
->GetImage(), dc
, rectIcon
.x
, rectIcon
.y
); 
1471     if (item
->HasText()) 
1473         const wxRect
& rectLabel 
= m_gi
->m_rectLabel
; 
1475         wxDCClipper 
clipper(*dc
, rectLabel
); 
1476         dc
->DrawText(item
->GetText(), rectLabel
.x
, rectLabel
.y
); 
1480 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
1482                                        const wxRect
& rectHL
, 
1485     // TODO: later we should support setting different attributes for 
1486     //       different columns - to do it, just add "col" argument to 
1487     //       GetAttr() and move these lines into the loop below 
1488     wxListItemAttr 
*attr 
= GetAttr(); 
1489     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1491         dc
->DrawRectangle( rectHL 
); 
1494     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
1495             y 
= rect
.y 
+ (LINE_SPACING 
+ EXTRA_HEIGHT
) / 2; 
1498     for ( wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1500           node 
= node
->GetNext(), col
++ ) 
1502         wxListItemData 
*item 
= node
->GetData(); 
1504         int width 
= m_owner
->GetColumnWidth(col
); 
1508         if ( item
->HasImage() ) 
1511             m_owner
->DrawImage( item
->GetImage(), dc
, xOld
, y 
); 
1512             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
1514             ix 
+= IMAGE_MARGIN_IN_REPORT_MODE
; 
1520         wxDCClipper 
clipper(*dc
, xOld
, y
, width 
- 8, rect
.height
); 
1522         if ( item
->HasText() ) 
1524             DrawTextFormatted(dc
, item
->GetText(), col
, xOld
, y
, width 
- 8); 
1529 void wxListLineData::DrawTextFormatted(wxDC 
*dc
, 
1530                                        const wxString 
&text
, 
1536     wxString drawntext
, ellipsis
; 
1537     wxCoord w
, h
, base_w
; 
1540     // determine if the string can fit inside the current width 
1541     dc
->GetTextExtent(text
, &w
, &h
); 
1544         // it can, draw it using the items alignment 
1545         m_owner
->GetColumn(col
, item
); 
1546         switch ( item
.GetAlign() ) 
1549                 wxFAIL_MSG( _T("unknown list item format") ); 
1552             case wxLIST_FORMAT_LEFT
: 
1556             case wxLIST_FORMAT_RIGHT
: 
1560             case wxLIST_FORMAT_CENTER
: 
1561                 x 
+= (width 
- w
) / 2; 
1565         dc
->DrawText(text
, x
, y
); 
1567     else // otherwise, truncate and add an ellipsis if possible 
1569         // determine the base width 
1570         ellipsis 
= wxString(wxT("...")); 
1571         dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1573         // continue until we have enough space or only one character left 
1575         size_t len 
= text
.Length(); 
1576         drawntext 
= text
.Left(len
); 
1579             dc
->GetTextExtent(drawntext
.Last(), &w_c
, &h_c
); 
1580             drawntext
.RemoveLast(); 
1583             if (w 
+ base_w 
<= width
) 
1587         // if still not enough space, remove ellipsis characters 
1588         while (ellipsis
.Length() > 0 && w 
+ base_w 
> width
) 
1590             ellipsis 
= ellipsis
.Left(ellipsis
.Length() - 1); 
1591             dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1594         // now draw the text 
1595         dc
->DrawText(drawntext
, x
, y
); 
1596         dc
->DrawText(ellipsis
, x 
+ w
, y
); 
1600 bool wxListLineData::Highlight( bool on 
) 
1602     wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") ); 
1604     if ( on 
== m_highlighted 
) 
1612 void wxListLineData::ReverseHighlight( void ) 
1614     Highlight(!IsHighlighted()); 
1617 //----------------------------------------------------------------------------- 
1618 //  wxListHeaderWindow 
1619 //----------------------------------------------------------------------------- 
1621 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
) 
1623 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
1624     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
1625     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
1626     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
1629 void wxListHeaderWindow::Init() 
1631     m_currentCursor 
= (wxCursor 
*) NULL
; 
1632     m_isDragging 
= FALSE
; 
1636 wxListHeaderWindow::wxListHeaderWindow() 
1640     m_owner 
= (wxListMainWindow 
*) NULL
; 
1641     m_resizeCursor 
= (wxCursor 
*) NULL
; 
1644 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, 
1646                                         wxListMainWindow 
*owner
, 
1650                                         const wxString 
&name 
) 
1651                   : wxWindow( win
, id
, pos
, size
, style
, name 
) 
1656     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
1658     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
) ); 
1661 wxListHeaderWindow::~wxListHeaderWindow() 
1663     delete m_resizeCursor
; 
1666 #ifdef __WXUNIVERSAL__ 
1667 #include "wx/univ/renderer.h" 
1668 #include "wx/univ/theme.h" 
1671 // shift the DC origin to match the position of the main window horz 
1672 // scrollbar: this allows us to always use logical coords 
1673 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
1676     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1679     m_owner
->GetViewStart( &x
, NULL 
); 
1681     // account for the horz scrollbar offset 
1682     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1685 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1687     wxPaintDC 
dc( this ); 
1694     dc
.SetFont( GetFont() ); 
1696     // width and height of the entire header window 
1698     GetClientSize( &w
, &h 
); 
1699     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1701     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1703     // do *not* use the listctrl colour for headers - one day we will have a 
1704     // function to set it separately 
1705     //dc.SetTextForeground( *wxBLACK ); 
1706     dc
.SetTextForeground(wxSystemSettings:: 
1707                             GetSystemColour( wxSYS_COLOUR_WINDOWTEXT 
)); 
1709     int x 
= HEADER_OFFSET_X
; 
1711     int numColumns 
= m_owner
->GetColumnCount(); 
1713     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1715         m_owner
->GetColumn( i
, item 
); 
1716         int wCol 
= item
.m_width
; 
1718         // the width of the rect to draw: make it smaller to fit entirely 
1719         // inside the column rect 
1722         wxRendererNative::Get().DrawHeaderButton
 
1726                                     wxRect(x
, HEADER_OFFSET_Y
, cw
, h 
- 2), 
1727                                     m_parent
->IsEnabled() ? 0 
1728                                                           : wxCONTROL_DISABLED
 
1731         // see if we have enough space for the column label 
1733         // for this we need the width of the text 
1736         dc
.GetTextExtent(item
.GetText(), &wLabel
, &hLabel
); 
1737         wLabel 
+= 2*EXTRA_WIDTH
; 
1739         // and the width of the icon, if any 
1740         static const int MARGIN_BETWEEN_TEXT_AND_ICON 
= 2; 
1741         int ix 
= 0,     // init them just to suppress the compiler warnings 
1743         const int image 
= item
.m_image
; 
1744         wxImageListType 
*imageList
; 
1747             imageList 
= m_owner
->m_small_image_list
; 
1750                 imageList
->GetSize(image
, ix
, iy
); 
1751                 wLabel 
+= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
1759         // ignore alignment if there is not enough space anyhow 
1761         switch ( wLabel 
< cw 
? item
.GetAlign() : wxLIST_FORMAT_LEFT 
) 
1764                 wxFAIL_MSG( _T("unknown list item format") ); 
1767             case wxLIST_FORMAT_LEFT
: 
1771             case wxLIST_FORMAT_RIGHT
: 
1772                 xAligned 
= x 
+ cw 
- wLabel
; 
1775             case wxLIST_FORMAT_CENTER
: 
1776                 xAligned 
= x 
+ (cw 
- wLabel
) / 2; 
1781         // if we have an image, draw it on the right of the label 
1788                         xAligned 
+ wLabel 
- ix 
- MARGIN_BETWEEN_TEXT_AND_ICON
, 
1789                         HEADER_OFFSET_Y 
+ (h 
- 4 - iy
)/2, 
1790                         wxIMAGELIST_DRAW_TRANSPARENT
 
1793             cw 
-= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
1796         // draw the text clipping it so that it doesn't overwrite the column 
1798         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h 
- 4 ); 
1800         dc
.DrawText( item
.GetText(), 
1801                      xAligned 
+ EXTRA_WIDTH
, h 
/ 2 - hLabel 
/ 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT ); 
1809 void wxListHeaderWindow::DrawCurrent() 
1811     int x1 
= m_currentX
; 
1813     m_owner
->ClientToScreen( &x1
, &y1 
); 
1815     int x2 
= m_currentX
; 
1817     m_owner
->GetClientSize( NULL
, &y2 
); 
1818     m_owner
->ClientToScreen( &x2
, &y2 
); 
1821     dc
.SetLogicalFunction( wxINVERT 
); 
1822     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
1823     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1827     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1829     dc
.SetLogicalFunction( wxCOPY 
); 
1831     dc
.SetPen( wxNullPen 
); 
1832     dc
.SetBrush( wxNullBrush 
); 
1835 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1837     // we want to work with logical coords 
1839     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1840     int y 
= event
.GetY(); 
1844         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1846         // we don't draw the line beyond our window, but we allow dragging it 
1849         GetClientSize( &w
, NULL 
); 
1850         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1853         // erase the line if it was drawn 
1854         if ( m_currentX 
< w 
) 
1857         if (event
.ButtonUp()) 
1860             m_isDragging 
= FALSE
; 
1862             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1863             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1870                 m_currentX 
= m_minX 
+ 7; 
1872             // draw in the new location 
1873             if ( m_currentX 
< w 
) 
1877     else // not dragging 
1880         bool hit_border 
= FALSE
; 
1882         // end of the current column 
1885         // find the column where this event occured 
1887             countCol 
= m_owner
->GetColumnCount(); 
1888         for (col 
= 0; col 
< countCol
; col
++) 
1890             xpos 
+= m_owner
->GetColumnWidth( col 
); 
1893             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
1895                 // near the column border 
1902                 // inside the column 
1909         if ( col 
== countCol 
) 
1912         if (event
.LeftDown() || event
.RightUp()) 
1914             if (hit_border 
&& event
.LeftDown()) 
1916                 if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
1917                                    event
.GetPosition()) ) 
1919                     m_isDragging 
= TRUE
; 
1924                 //else: column resizing was vetoed by the user code 
1926             else // click on a column 
1928                 SendListEvent( event
.LeftDown() 
1929                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
1930                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
1931                                 event
.GetPosition()); 
1934         else if (event
.Moving()) 
1939                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
1940                 m_currentCursor 
= m_resizeCursor
; 
1944                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
1945                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1949                 SetCursor(*m_currentCursor
); 
1954 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1956     m_owner
->SetFocus(); 
1960 bool wxListHeaderWindow::SendListEvent(wxEventType type
, wxPoint pos
) 
1962     wxWindow 
*parent 
= GetParent(); 
1963     wxListEvent 
le( type
, parent
->GetId() ); 
1964     le
.SetEventObject( parent 
); 
1965     le
.m_pointDrag 
= pos
; 
1967     // the position should be relative to the parent window, not 
1968     // this one for compatibility with MSW and common sense: the 
1969     // user code doesn't know anything at all about this header 
1970     // window, so why should it get positions relative to it? 
1971     le
.m_pointDrag
.y 
-= GetSize().y
; 
1973     le
.m_col 
= m_column
; 
1974     return !parent
->GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
1977 //----------------------------------------------------------------------------- 
1978 // wxListRenameTimer (internal) 
1979 //----------------------------------------------------------------------------- 
1981 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
1986 void wxListRenameTimer::Notify() 
1988     m_owner
->OnRenameTimer(); 
1991 //----------------------------------------------------------------------------- 
1992 // wxListTextCtrl (internal) 
1993 //----------------------------------------------------------------------------- 
1995 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
) 
1996     EVT_CHAR           (wxListTextCtrl::OnChar
) 
1997     EVT_KEY_UP         (wxListTextCtrl::OnKeyUp
) 
1998     EVT_KILL_FOCUS     (wxListTextCtrl::OnKillFocus
) 
2001 wxListTextCtrl::wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
) 
2002               : m_startValue(owner
->GetItemText(itemEdit
)), 
2003                 m_itemEdited(itemEdit
) 
2008     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
2010     m_owner
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
2011                                   &rectLabel
.x
, &rectLabel
.y
); 
2013     (void)Create(owner
, wxID_ANY
, m_startValue
, 
2014                  wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2015                  wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
2018 void wxListTextCtrl::Finish() 
2022         wxPendingDelete
.Append(this); 
2026         m_owner
->SetFocus(); 
2030 bool wxListTextCtrl::AcceptChanges() 
2032     const wxString value 
= GetValue(); 
2034     if ( value 
== m_startValue 
) 
2036         // nothing changed, always accept 
2040     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
2042         // vetoed by the user 
2046     // accepted, do rename the item 
2047     m_owner
->SetItemText(m_itemEdited
, value
); 
2052 void wxListTextCtrl::OnChar( wxKeyEvent 
&event 
) 
2054     switch ( event
.m_keyCode 
) 
2057             if ( !AcceptChanges() ) 
2059                 // vetoed by the user code 
2062             //else: fall through 
2066             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2074 void wxListTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
2082     // auto-grow the textctrl: 
2083     wxSize parentSize 
= m_owner
->GetSize(); 
2084     wxPoint myPos 
= GetPosition(); 
2085     wxSize mySize 
= GetSize(); 
2087     GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); 
2088     if (myPos
.x 
+ sx 
> parentSize
.x
) 
2089         sx 
= parentSize
.x 
- myPos
.x
; 
2097 void wxListTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2101         // We must finish regardless of success, otherwise we'll get focus problems 
2104         if ( !AcceptChanges() ) 
2105             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2111 //----------------------------------------------------------------------------- 
2113 //----------------------------------------------------------------------------- 
2115 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
) 
2117 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
) 
2118   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2119   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2120   EVT_CHAR           (wxListMainWindow::OnChar
) 
2121   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2122   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2123   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2124   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2127 void wxListMainWindow::Init() 
2132     m_lineTo 
= (size_t)-1; 
2138     m_small_image_list 
= (wxImageListType 
*) NULL
; 
2139     m_normal_image_list 
= (wxImageListType 
*) NULL
; 
2141     m_small_spacing 
= 30; 
2142     m_normal_spacing 
= 40; 
2146     m_isCreated 
= FALSE
; 
2148     m_lastOnSame 
= FALSE
; 
2149     m_renameTimer 
= new wxListRenameTimer( this ); 
2153     m_lineBeforeLastClicked 
= (size_t)-1; 
2158 wxListMainWindow::wxListMainWindow() 
2163     m_highlightUnfocusedBrush 
= (wxBrush 
*) NULL
; 
2166 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2171                                     const wxString 
&name 
) 
2172                 : wxScrolledWindow( parent
, id
, pos
, size
, 
2173                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2177     m_highlightBrush 
= new wxBrush
 
2179                             wxSystemSettings::GetColour
 
2181                                 wxSYS_COLOUR_HIGHLIGHT
 
2186     m_highlightUnfocusedBrush 
= new wxBrush
 
2188                                        wxSystemSettings::GetColour
 
2190                                            wxSYS_COLOUR_BTNSHADOW
 
2198     SetScrollbars( 0, 0, 0, 0, 0, 0 ); 
2200     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX 
) ); 
2203 wxListMainWindow::~wxListMainWindow() 
2206     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
2208     delete m_highlightBrush
; 
2209     delete m_highlightUnfocusedBrush
; 
2211     delete m_renameTimer
; 
2214 void wxListMainWindow::CacheLineData(size_t line
) 
2216     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
2218     wxListLineData 
*ld 
= GetDummyLine(); 
2220     size_t countCol 
= GetColumnCount(); 
2221     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2223         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2226     ld
->SetImage(listctrl
->OnGetItemImage(line
)); 
2227     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
2230 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2232     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2234     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); 
2236     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2238     // we need to recreate the dummy line if the number of columns in the 
2239     // control changed as it would have the incorrect number of fields 
2241     if ( !m_lines
.IsEmpty() && 
2242             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
2244         self
->m_lines
.Clear(); 
2247     if ( m_lines
.IsEmpty() ) 
2249         wxListLineData 
*line 
= new wxListLineData(self
); 
2250         self
->m_lines
.Add(line
); 
2252         // don't waste extra memory -- there never going to be anything 
2253         // else/more in this array 
2254         self
->m_lines
.Shrink(); 
2260 // ---------------------------------------------------------------------------- 
2261 // line geometry (report mode only) 
2262 // ---------------------------------------------------------------------------- 
2264 wxCoord 
wxListMainWindow::GetLineHeight() const 
2266     // we cache the line height as calling GetTextExtent() is slow 
2267     if ( !m_lineHeight 
) 
2269         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2271         wxClientDC 
dc( self 
); 
2272         dc
.SetFont( GetFont() ); 
2275         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2277         if ( m_small_image_list 
&& m_small_image_list
->GetImageCount() ) 
2281             m_small_image_list
->GetSize(0, iw
, ih
); 
2286         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2289     return m_lineHeight
; 
2292 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2294     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") ); 
2296     return LINE_SPACING 
+ line
*GetLineHeight(); 
2299 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2301     if ( !InReportView() ) 
2302         return GetLine(line
)->m_gi
->m_rectAll
; 
2305     rect
.x 
= HEADER_OFFSET_X
; 
2306     rect
.y 
= GetLineY(line
); 
2307     rect
.width 
= GetHeaderWidth(); 
2308     rect
.height 
= GetLineHeight(); 
2313 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2315     if ( !InReportView() ) 
2316         return GetLine(line
)->m_gi
->m_rectLabel
; 
2319     rect
.x 
= HEADER_OFFSET_X
; 
2320     rect
.y 
= GetLineY(line
); 
2321     rect
.width 
= GetColumnWidth(0); 
2322     rect
.height 
= GetLineHeight(); 
2327 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2329     if ( !InReportView() ) 
2330         return GetLine(line
)->m_gi
->m_rectIcon
; 
2332     wxListLineData 
*ld 
= GetLine(line
); 
2333     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2336     rect
.x 
= HEADER_OFFSET_X
; 
2337     rect
.y 
= GetLineY(line
); 
2338     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2343 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2345     return InReportView() ? GetLineRect(line
) 
2346                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2349 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2351     wxASSERT_MSG( line 
< GetItemCount(), _T("invalid line in HitTestLine") ); 
2353     wxListLineData 
*ld 
= GetLine(line
); 
2355     if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) ) 
2356         return wxLIST_HITTEST_ONITEMICON
; 
2358     // VS: Testing for "ld->HasText() || InReportView()" instead of 
2359     //     "ld->HasText()" is needed to make empty lines in report view 
2361     if ( ld
->HasText() || InReportView() ) 
2363         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2364                                      : GetLineLabelRect(line
); 
2366         if ( rect
.Inside(x
, y
) ) 
2367             return wxLIST_HITTEST_ONITEMLABEL
; 
2373 // ---------------------------------------------------------------------------- 
2374 // highlight (selection) handling 
2375 // ---------------------------------------------------------------------------- 
2377 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2381         return m_selStore
.IsSelected(line
); 
2385         wxListLineData 
*ld 
= GetLine(line
); 
2386         wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") ); 
2388         return ld
->IsHighlighted(); 
2392 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
2398         wxArrayInt linesChanged
; 
2399         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
2402             // meny items changed state, refresh everything 
2403             RefreshLines(lineFrom
, lineTo
); 
2405         else // only a few items changed state, refresh only them 
2407             size_t count 
= linesChanged
.GetCount(); 
2408             for ( size_t n 
= 0; n 
< count
; n
++ ) 
2410                 RefreshLine(linesChanged
[n
]); 
2414     else // iterate over all items in non report view 
2416         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2418             if ( HighlightLine(line
, highlight
) ) 
2426 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2432         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2436         wxListLineData 
*ld 
= GetLine(line
); 
2437         wxCHECK_MSG( ld
, FALSE
, _T("invalid index in HighlightLine") ); 
2439         changed 
= ld
->Highlight(highlight
); 
2444         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2445                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2451 void wxListMainWindow::RefreshLine( size_t line 
) 
2453     if ( HasFlag(wxLC_REPORT
) ) 
2455         size_t visibleFrom
, visibleTo
; 
2456         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2458         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
2462     wxRect rect 
= GetLineRect(line
); 
2464     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2465     RefreshRect( rect 
); 
2468 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2470     // we suppose that they are ordered by caller 
2471     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2473     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2475     if ( HasFlag(wxLC_REPORT
) ) 
2477         size_t visibleFrom
, visibleTo
; 
2478         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2480         if ( lineFrom 
< visibleFrom 
) 
2481             lineFrom 
= visibleFrom
; 
2482         if ( lineTo 
> visibleTo 
) 
2487         rect
.y 
= GetLineY(lineFrom
); 
2488         rect
.width 
= GetClientSize().x
; 
2489         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
2491         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2492         RefreshRect( rect 
); 
2496         // TODO: this should be optimized... 
2497         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2504 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2506     if ( HasFlag(wxLC_REPORT
) ) 
2508         size_t visibleFrom
, visibleTo
; 
2509         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2511         if ( lineFrom 
< visibleFrom 
) 
2512             lineFrom 
= visibleFrom
; 
2513         else if ( lineFrom 
> visibleTo 
) 
2518         rect
.y 
= GetLineY(lineFrom
); 
2519         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2521         wxSize size 
= GetClientSize(); 
2522         rect
.width 
= size
.x
; 
2523         // refresh till the bottom of the window 
2524         rect
.height 
= size
.y 
- rect
.y
; 
2526         RefreshRect( rect 
); 
2530         // TODO: how to do it more efficiently? 
2535 void wxListMainWindow::RefreshSelected() 
2541     if ( InReportView() ) 
2543         GetVisibleLinesRange(&from
, &to
); 
2548         to 
= GetItemCount() - 1; 
2551     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
2553         RefreshLine(m_current
); 
2556     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
2558         // NB: the test works as expected even if m_current == -1 
2559         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
2566 void wxListMainWindow::Freeze() 
2571 void wxListMainWindow::Thaw() 
2573     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen list control?") ); 
2575     if ( !--m_freezeCount 
) 
2581 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2583     // Note: a wxPaintDC must be constructed even if no drawing is 
2584     // done (a Windows requirement). 
2585     wxPaintDC 
dc( this ); 
2587     if ( IsEmpty() || m_freezeCount 
) 
2589         // nothing to draw or not the moment to draw it 
2595         // delay the repainting until we calculate all the items positions 
2602     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2606     dc
.SetFont( GetFont() ); 
2608     if ( HasFlag(wxLC_REPORT
) ) 
2610         int lineHeight 
= GetLineHeight(); 
2612         size_t visibleFrom
, visibleTo
; 
2613         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2616         wxCoord xOrig
, yOrig
; 
2617         CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
); 
2619         // tell the caller cache to cache the data 
2622             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2623                                 GetParent()->GetId()); 
2624             evCache
.SetEventObject( GetParent() ); 
2625             evCache
.m_oldItemIndex 
= visibleFrom
; 
2626             evCache
.m_itemIndex 
= visibleTo
; 
2627             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2630         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2632             rectLine 
= GetLineRect(line
); 
2634             if ( !IsExposed(rectLine
.x 
- xOrig
, rectLine
.y 
- yOrig
, 
2635                             rectLine
.width
, rectLine
.height
) ) 
2637                 // don't redraw unaffected lines to avoid flicker 
2641             GetLine(line
)->DrawInReportMode( &dc
, 
2643                                              GetLineHighlightRect(line
), 
2644                                              IsHighlighted(line
) ); 
2647         if ( HasFlag(wxLC_HRULES
) ) 
2649             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2650             wxSize clientSize 
= GetClientSize(); 
2652             // Don't draw the first one 
2653             for ( size_t i 
= visibleFrom
+1; i 
<= visibleTo
; i
++ ) 
2656                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2657                 dc
.DrawLine(0 - dev_x
, i
*lineHeight
, 
2658                             clientSize
.x 
- dev_x
, i
*lineHeight
); 
2661             // Draw last horizontal rule 
2662             if ( visibleTo 
== GetItemCount() - 1 ) 
2665                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2666                 dc
.DrawLine(0 - dev_x
, (m_lineTo
+1)*lineHeight
, 
2667                             clientSize
.x 
- dev_x 
, (m_lineTo
+1)*lineHeight 
); 
2671         // Draw vertical rules if required 
2672         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2674             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2676             wxRect firstItemRect
; 
2677             wxRect lastItemRect
; 
2678             GetItemRect(visibleFrom
, firstItemRect
); 
2679             GetItemRect(visibleTo
, lastItemRect
); 
2680             int x 
= firstItemRect
.GetX(); 
2682             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2683             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2685                 int colWidth 
= GetColumnWidth(col
); 
2687                 dc
.DrawLine(x 
- dev_x 
- 2, firstItemRect
.GetY() - 1 - dev_y
, 
2688                             x 
- dev_x 
- 2, lastItemRect
.GetBottom() + 1 - dev_y
); 
2694         size_t count 
= GetItemCount(); 
2695         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2697             GetLine(i
)->Draw( &dc 
); 
2702     // Don't draw rect outline under Mac at all. 
2707             dc
.SetPen( *wxBLACK_PEN 
); 
2708             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2709             dc
.DrawRectangle( GetLineHighlightRect(m_current
) ); 
2717 void wxListMainWindow::HighlightAll( bool on 
) 
2719     if ( IsSingleSel() ) 
2721         wxASSERT_MSG( !on
, _T("can't do this in a single sel control") ); 
2723         // we just have one item to turn off 
2724         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2726             HighlightLine(m_current
, FALSE
); 
2727             RefreshLine(m_current
); 
2732         HighlightLines(0, GetItemCount() - 1, on
); 
2736 void wxListMainWindow::SendNotify( size_t line
, 
2737                                    wxEventType command
, 
2740     wxListEvent 
le( command
, GetParent()->GetId() ); 
2741     le
.SetEventObject( GetParent() ); 
2742     le
.m_itemIndex 
= line
; 
2744     // set only for events which have position 
2745     if ( point 
!= wxDefaultPosition 
) 
2746         le
.m_pointDrag 
= point
; 
2748     // don't try to get the line info for virtual list controls: the main 
2749     // program has it anyhow and if we did it would result in accessing all 
2750     // the lines, even those which are not visible now and this is precisely 
2751     // what we're trying to avoid 
2752     if ( !IsVirtual() && (command 
!= wxEVT_COMMAND_LIST_DELETE_ITEM
) ) 
2754         if ( line 
!= (size_t)-1 ) 
2756             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2758         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2760     //else: there may be no more such item 
2762     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2765 void wxListMainWindow::ChangeCurrent(size_t current
) 
2767     m_current 
= current
; 
2769     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2772 void wxListMainWindow::EditLabel( long item 
) 
2774     wxCHECK_RET( (item 
>= 0) && ((size_t)item 
< GetItemCount()), 
2775                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2777     size_t itemEdit 
= (size_t)item
; 
2779     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2780     le
.SetEventObject( GetParent() ); 
2781     le
.m_itemIndex 
= item
; 
2782     wxListLineData 
*data 
= GetLine(itemEdit
); 
2783     wxCHECK_RET( data
, _T("invalid index in EditLabel()") ); 
2784     data
->GetItem( 0, le
.m_item 
); 
2785     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2787         // vetoed by user code 
2791     // We have to call this here because the label in question might just have 
2792     // been added and no screen update taken place. 
2796     wxListTextCtrl 
*text 
= new wxListTextCtrl(this, itemEdit
); 
2801 void wxListMainWindow::OnRenameTimer() 
2803     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2805     EditLabel( m_current 
); 
2808 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2810     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2811     le
.SetEventObject( GetParent() ); 
2812     le
.m_itemIndex 
= itemEdit
; 
2814     wxListLineData 
*data 
= GetLine(itemEdit
); 
2815     wxCHECK_MSG( data
, FALSE
, _T("invalid index in OnRenameAccept()") ); 
2817     data
->GetItem( 0, le
.m_item 
); 
2818     le
.m_item
.m_text 
= value
; 
2819     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2823 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2825     // let owner know that the edit was cancelled 
2826     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2828     le
.SetEditCanceled(TRUE
); 
2830     le
.SetEventObject( GetParent() ); 
2831     le
.m_itemIndex 
= itemEdit
; 
2833     wxListLineData 
*data 
= GetLine(itemEdit
); 
2834     wxCHECK_RET( data
, _T("invalid index in OnRenameCancelled()") ); 
2836     data
->GetItem( 0, le
.m_item 
); 
2838     GetEventHandler()->ProcessEvent( le 
); 
2841 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2843     event
.SetEventObject( GetParent() ); 
2844     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2847     if ( !HasCurrent() || IsEmpty() ) 
2853     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
2854         event
.ButtonDClick()) ) 
2857     int x 
= event
.GetX(); 
2858     int y 
= event
.GetY(); 
2859     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2861     // where did we hit it (if we did)? 
2864     size_t count 
= GetItemCount(), 
2867     if ( HasFlag(wxLC_REPORT
) ) 
2869         current 
= y 
/ GetLineHeight(); 
2870         if ( current 
< count 
) 
2871             hitResult 
= HitTestLine(current
, x
, y
); 
2875         // TODO: optimize it too! this is less simple than for report view but 
2876         //       enumerating all items is still not a way to do it!! 
2877         for ( current 
= 0; current 
< count
; current
++ ) 
2879             hitResult 
= HitTestLine(current
, x
, y
); 
2885     if (event
.Dragging()) 
2887         if (m_dragCount 
== 0) 
2889             // we have to report the raw, physical coords as we want to be 
2890             // able to call HitTest(event.m_pointDrag) from the user code to 
2891             // get the item being dragged 
2892             m_dragStart 
= event
.GetPosition(); 
2897         if (m_dragCount 
!= 3) 
2900         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
2901                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2903         wxListEvent 
le( command
, GetParent()->GetId() ); 
2904         le
.SetEventObject( GetParent() ); 
2905         le
.m_itemIndex 
= current
; 
2906         le
.m_pointDrag 
= m_dragStart
; 
2907         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2918         // outside of any item 
2922     bool forceClick 
= FALSE
; 
2923     if (event
.ButtonDClick()) 
2925         m_renameTimer
->Stop(); 
2926         m_lastOnSame 
= FALSE
; 
2928         if ( current 
== m_lineLastClicked 
) 
2930             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2936             // the first click was on another item, so don't interpret this as 
2937             // a double click, but as a simple click instead 
2942     if (event
.LeftUp() && m_lastOnSame
) 
2944         if ((current 
== m_current
) && 
2945             (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
2946             HasFlag(wxLC_EDIT_LABELS
)  ) 
2948             m_renameTimer
->Start( 100, TRUE 
); 
2950         m_lastOnSame 
= FALSE
; 
2952     else if (event
.RightDown()) 
2954         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, 
2955                     event
.GetPosition() ); 
2957     else if (event
.MiddleDown()) 
2959         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
2961     else if ( event
.LeftDown() || forceClick 
) 
2963         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2964         m_lineLastClicked 
= current
; 
2966         size_t oldCurrent 
= m_current
; 
2968         if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) ) 
2970             HighlightAll( FALSE 
); 
2972             ChangeCurrent(current
); 
2974             ReverseHighlight(m_current
); 
2976         else // multi sel & either ctrl or shift is down 
2978             if (event
.ControlDown()) 
2980                 ChangeCurrent(current
); 
2982                 ReverseHighlight(m_current
); 
2984             else if (event
.ShiftDown()) 
2986                 ChangeCurrent(current
); 
2988                 size_t lineFrom 
= oldCurrent
, 
2991                 if ( lineTo 
< lineFrom 
) 
2994                     lineFrom 
= m_current
; 
2997                 HighlightLines(lineFrom
, lineTo
); 
2999             else // !ctrl, !shift 
3001                 // test in the enclosing if should make it impossible 
3002                 wxFAIL_MSG( _T("how did we get here?") ); 
3006         if (m_current 
!= oldCurrent
) 
3008             RefreshLine( oldCurrent 
); 
3011         // forceClick is only set if the previous click was on another item 
3012         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
); 
3016 void wxListMainWindow::MoveToItem(size_t item
) 
3018     if ( item 
== (size_t)-1 ) 
3021     wxRect rect 
= GetLineRect(item
); 
3023     int client_w
, client_h
; 
3024     GetClientSize( &client_w
, &client_h 
); 
3026     const int hLine 
= GetLineHeight(); 
3028     int view_x 
= SCROLL_UNIT_X
*GetScrollPos( wxHORIZONTAL 
); 
3029     int view_y 
= hLine
*GetScrollPos( wxVERTICAL 
); 
3031     if ( HasFlag(wxLC_REPORT
) ) 
3033         // the next we need the range of lines shown it might be different, so 
3035         ResetVisibleLinesRange(); 
3037         if (rect
.y 
< view_y 
) 
3038             Scroll( -1, rect
.y
/hLine 
); 
3039         if (rect
.y
+rect
.height
+5 > view_y
+client_h
) 
3040             Scroll( -1, (rect
.y
+rect
.height
-client_h
+hLine
)/hLine 
); 
3044         if (rect
.x
-view_x 
< 5) 
3045             Scroll( (rect
.x
-5)/SCROLL_UNIT_X
, -1 ); 
3046         if (rect
.x
+rect
.width
-5 > view_x
+client_w
) 
3047             Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/SCROLL_UNIT_X
, -1 ); 
3051 // ---------------------------------------------------------------------------- 
3052 // keyboard handling 
3053 // ---------------------------------------------------------------------------- 
3055 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
3057     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
3058                  _T("invalid item index in OnArrowChar()") ); 
3060     size_t oldCurrent 
= m_current
; 
3062     // in single selection we just ignore Shift as we can't select several 
3064     if ( event
.ShiftDown() && !IsSingleSel() ) 
3066         ChangeCurrent(newCurrent
); 
3068         // refresh the old focus to remove it 
3069         RefreshLine( oldCurrent 
); 
3071         // select all the items between the old and the new one 
3072         if ( oldCurrent 
> newCurrent 
) 
3074             newCurrent 
= oldCurrent
; 
3075             oldCurrent 
= m_current
; 
3078         HighlightLines(oldCurrent
, newCurrent
); 
3082         // all previously selected items are unselected unless ctrl is held 
3083         if ( !event
.ControlDown() ) 
3084             HighlightAll(FALSE
); 
3086         ChangeCurrent(newCurrent
); 
3088         // refresh the old focus to remove it 
3089         RefreshLine( oldCurrent 
); 
3091         if ( !event
.ControlDown() ) 
3093             HighlightLine( m_current
, TRUE 
); 
3097     RefreshLine( m_current 
); 
3102 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
3104     wxWindow 
*parent 
= GetParent(); 
3106     /* we propagate the key event up */ 
3107     wxKeyEvent 
ke( wxEVT_KEY_DOWN 
); 
3108     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3109     ke
.m_controlDown 
= event
.m_controlDown
; 
3110     ke
.m_altDown 
= event
.m_altDown
; 
3111     ke
.m_metaDown 
= event
.m_metaDown
; 
3112     ke
.m_keyCode 
= event
.m_keyCode
; 
3115     ke
.SetEventObject( parent 
); 
3116     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3121 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
3123     wxWindow 
*parent 
= GetParent(); 
3125     /* we send a list_key event up */ 
3128         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
3129         le
.m_itemIndex 
= m_current
; 
3130         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3131         le
.m_code 
= event
.GetKeyCode(); 
3132         le
.SetEventObject( parent 
); 
3133         parent
->GetEventHandler()->ProcessEvent( le 
); 
3136     /* we propagate the char event up */ 
3137     wxKeyEvent 
ke( wxEVT_CHAR 
); 
3138     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3139     ke
.m_controlDown 
= event
.m_controlDown
; 
3140     ke
.m_altDown 
= event
.m_altDown
; 
3141     ke
.m_metaDown 
= event
.m_metaDown
; 
3142     ke
.m_keyCode 
= event
.m_keyCode
; 
3145     ke
.SetEventObject( parent 
); 
3146     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3148     if (event
.GetKeyCode() == WXK_TAB
) 
3150         wxNavigationKeyEvent nevent
; 
3151         nevent
.SetWindowChange( event
.ControlDown() ); 
3152         nevent
.SetDirection( !event
.ShiftDown() ); 
3153         nevent
.SetEventObject( GetParent()->GetParent() ); 
3154         nevent
.SetCurrentFocus( m_parent 
); 
3155         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent 
)) 
3159     /* no item -> nothing to do */ 
3166     switch (event
.GetKeyCode()) 
3169             if ( m_current 
> 0 ) 
3170                 OnArrowChar( m_current 
- 1, event 
); 
3174             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
3175                 OnArrowChar( m_current 
+ 1, event 
); 
3180                 OnArrowChar( GetItemCount() - 1, event 
); 
3185                 OnArrowChar( 0, event 
); 
3190                 int steps 
= HasFlag(wxLC_REPORT
) ? m_linesPerPage 
- 1 : m_current 
% m_linesPerPage
; 
3192                 int index 
= m_current 
- steps
; 
3196                 OnArrowChar( index
, event 
); 
3202                 int steps 
= HasFlag(wxLC_REPORT
) 
3203                                ? m_linesPerPage 
- 1 
3204                                : m_linesPerPage 
- (m_current 
% m_linesPerPage
) - 1; 
3206                 size_t index 
= m_current 
+ steps
; 
3207                 size_t count 
= GetItemCount(); 
3208                 if ( index 
>= count 
) 
3211                 OnArrowChar( index
, event 
); 
3216             if ( !HasFlag(wxLC_REPORT
) ) 
3218                 int index 
= m_current 
- m_linesPerPage
; 
3222                 OnArrowChar( index
, event 
); 
3227             if ( !HasFlag(wxLC_REPORT
) ) 
3229                 size_t index 
= m_current 
+ m_linesPerPage
; 
3231                 size_t count 
= GetItemCount(); 
3232                 if ( index 
>= count 
) 
3235                 OnArrowChar( index
, event 
); 
3240             if ( IsSingleSel() ) 
3242                 SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3244                 if ( IsHighlighted(m_current
) ) 
3246                     // don't unselect the item in single selection mode 
3249                 //else: select it in ReverseHighlight() below if unselected 
3252             ReverseHighlight(m_current
); 
3257             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3265 // ---------------------------------------------------------------------------- 
3267 // ---------------------------------------------------------------------------- 
3269 void wxListMainWindow::SetFocus() 
3271     // VS: wxListMainWindow derives from wxPanel (via wxScrolledWindow) and wxPanel 
3272     //     overrides SetFocus in such way that it does never change focus from 
3273     //     panel's child to the panel itself. Unfortunately, we must be able to change 
3274     //     focus to the panel from wxListTextCtrl because the text control should 
3275     //     disappear when the user clicks outside it. 
3277     wxWindow 
*oldFocus 
= FindFocus(); 
3279     if ( oldFocus 
&& oldFocus
->GetParent() == this ) 
3281         wxWindow::SetFocus(); 
3285         wxScrolledWindow::SetFocus(); 
3289 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3293         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3294         event
.SetEventObject( GetParent() ); 
3295         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3299     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
3300     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
3301     // which are already drawn correctly resulting in horrible flicker - avoid 
3311 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3315         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
3316         event
.SetEventObject( GetParent() ); 
3317         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3324 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3326     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3328         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3330     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3332         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3334     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3336         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3338     else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
)) 
3340         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3344 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3346     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3348         m_normal_image_list
->GetSize( index
, width
, height 
); 
3350     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3352         m_small_image_list
->GetSize( index
, width
, height 
); 
3354     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3356         m_small_image_list
->GetSize( index
, width
, height 
); 
3358     else if ( HasFlag(wxLC_REPORT
) && m_small_image_list 
) 
3360         m_small_image_list
->GetSize( index
, width
, height 
); 
3369 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3371     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3372     dc
.SetFont( GetFont() ); 
3375     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3377     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3380 void wxListMainWindow::SetImageList( wxImageListType 
*imageList
, int which 
) 
3384     // calc the spacing from the icon size 
3387     if ((imageList
) && (imageList
->GetImageCount()) ) 
3389         imageList
->GetSize(0, width
, height
); 
3392     if (which 
== wxIMAGE_LIST_NORMAL
) 
3394         m_normal_image_list 
= imageList
; 
3395         m_normal_spacing 
= width 
+ 8; 
3398     if (which 
== wxIMAGE_LIST_SMALL
) 
3400         m_small_image_list 
= imageList
; 
3401         m_small_spacing 
= width 
+ 14; 
3402         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
3406 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3411         m_small_spacing 
= spacing
; 
3415         m_normal_spacing 
= spacing
; 
3419 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3421     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3424 // ---------------------------------------------------------------------------- 
3426 // ---------------------------------------------------------------------------- 
3428 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3430     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3432     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3434     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3435         item
.m_width 
= GetTextLength( item
.m_text 
); 
3437     wxListHeaderData 
*column 
= node
->GetData(); 
3438     column
->SetItem( item 
); 
3440     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3442         headerWin
->m_dirty 
= TRUE
; 
3446     // invalidate it as it has to be recalculated 
3450 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3452     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3453                  _T("invalid column index") ); 
3455     wxCHECK_RET( HasFlag(wxLC_REPORT
), 
3456                  _T("SetColumnWidth() can only be called in report mode.") ); 
3459     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3461         headerWin
->m_dirty 
= TRUE
; 
3463     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3464     wxCHECK_RET( node
, _T("no column?") ); 
3466     wxListHeaderData 
*column 
= node
->GetData(); 
3468     size_t count 
= GetItemCount(); 
3470     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3472         width 
= GetTextLength(column
->GetText()); 
3474     else if ( width 
== wxLIST_AUTOSIZE 
) 
3478             // TODO: determine the max width somehow... 
3479             width 
= WIDTH_COL_DEFAULT
; 
3483             wxClientDC 
dc(this); 
3484             dc
.SetFont( GetFont() ); 
3486             int max 
= AUTOSIZE_COL_MARGIN
; 
3488             for ( size_t i 
= 0; i 
< count
; i
++ ) 
3490                 wxListLineData 
*line 
= GetLine(i
); 
3491                 wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3493                 wxCHECK_RET( n
, _T("no subitem?") ); 
3495                 wxListItemData 
*item 
= n
->GetData(); 
3498                 if (item
->HasImage()) 
3501                     GetImageSize( item
->GetImage(), ix
, iy 
); 
3505                 if (item
->HasText()) 
3508                     dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
3516             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3520     column
->SetWidth( width 
); 
3522     // invalidate it as it has to be recalculated 
3526 int wxListMainWindow::GetHeaderWidth() const 
3528     if ( !m_headerWidth 
) 
3530         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3532         size_t count 
= GetColumnCount(); 
3533         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3535             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3539     return m_headerWidth
; 
3542 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3544     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3545     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3547     wxListHeaderData 
*column 
= node
->GetData(); 
3548     column
->GetItem( item 
); 
3551 int wxListMainWindow::GetColumnWidth( int col 
) const 
3553     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3554     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3556     wxListHeaderData 
*column 
= node
->GetData(); 
3557     return column
->GetWidth(); 
3560 // ---------------------------------------------------------------------------- 
3562 // ---------------------------------------------------------------------------- 
3564 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3566     long id 
= item
.m_itemId
; 
3567     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3568                  _T("invalid item index in SetItem") ); 
3572         wxListLineData 
*line 
= GetLine((size_t)id
); 
3573         line
->SetItem( item
.m_col
, item 
); 
3576     // update the item on screen 
3578     GetItemRect(id
, rectItem
); 
3579     RefreshRect(rectItem
); 
3582 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3584      wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3585                   _T("invalid list ctrl item index in SetItem") ); 
3587     size_t oldCurrent 
= m_current
; 
3588     size_t item 
= (size_t)litem
;    // safe because of the check above 
3590     // do we need to change the focus? 
3591     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3593         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3595             // don't do anything if this item is already focused 
3596             if ( item 
!= m_current 
) 
3598                 ChangeCurrent(item
); 
3600                 if ( oldCurrent 
!= (size_t)-1 ) 
3602                     if ( IsSingleSel() ) 
3604                         HighlightLine(oldCurrent
, FALSE
); 
3607                     RefreshLine(oldCurrent
); 
3610                 RefreshLine( m_current 
); 
3615             // don't do anything if this item is not focused 
3616             if ( item 
== m_current 
) 
3620                 if ( IsSingleSel() ) 
3622                     // we must unselect the old current item as well or we 
3623                     // might end up with more than one selected item in a 
3624                     // single selection control 
3625                     HighlightLine(oldCurrent
, FALSE
); 
3628                 RefreshLine( oldCurrent 
); 
3633     // do we need to change the selection state? 
3634     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3636         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3638         if ( IsSingleSel() ) 
3642                 // selecting the item also makes it the focused one in the 
3644                 if ( m_current 
!= item 
) 
3646                     ChangeCurrent(item
); 
3648                     if ( oldCurrent 
!= (size_t)-1 ) 
3650                         HighlightLine( oldCurrent
, FALSE 
); 
3651                         RefreshLine( oldCurrent 
); 
3657                 // only the current item may be selected anyhow 
3658                 if ( item 
!= m_current 
) 
3663         if ( HighlightLine(item
, on
) ) 
3670 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
3672     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3673                  _T("invalid list ctrl item index in GetItemState()") ); 
3675     int ret 
= wxLIST_STATE_DONTCARE
; 
3677     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3679         if ( (size_t)item 
== m_current 
) 
3680             ret 
|= wxLIST_STATE_FOCUSED
; 
3683     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3685         if ( IsHighlighted(item
) ) 
3686             ret 
|= wxLIST_STATE_SELECTED
; 
3692 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
3694     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3695                  _T("invalid item index in GetItem") ); 
3697     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3698     line
->GetItem( item
.m_col
, item 
); 
3701 // ---------------------------------------------------------------------------- 
3703 // ---------------------------------------------------------------------------- 
3705 size_t wxListMainWindow::GetItemCount() const 
3707     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3710 void wxListMainWindow::SetItemCount(long count
) 
3712     m_selStore
.SetItemCount(count
); 
3713     m_countVirt 
= count
; 
3715     ResetVisibleLinesRange(); 
3717     // scrollbars must be reset 
3721 int wxListMainWindow::GetSelectedItemCount() const 
3723     // deal with the quick case first 
3724     if ( IsSingleSel() ) 
3726         return HasCurrent() ? IsHighlighted(m_current
) : FALSE
; 
3729     // virtual controls remmebers all its selections itself 
3731         return m_selStore
.GetSelectedCount(); 
3733     // TODO: we probably should maintain the number of items selected even for 
3734     //       non virtual controls as enumerating all lines is really slow... 
3735     size_t countSel 
= 0; 
3736     size_t count 
= GetItemCount(); 
3737     for ( size_t line 
= 0; line 
< count
; line
++ ) 
3739         if ( GetLine(line
)->IsHighlighted() ) 
3746 // ---------------------------------------------------------------------------- 
3747 // item position/size 
3748 // ---------------------------------------------------------------------------- 
3750 wxRect 
wxListMainWindow::GetViewRect() const 
3752     wxASSERT_MSG( !HasFlag(wxLC_REPORT 
| wxLC_LIST
), 
3753                     _T("wxListCtrl::GetViewRect() only works in icon mode") ); 
3755     // we need to find the longest/tallest label 
3758     const int count 
= GetItemCount(); 
3761         for ( int i 
= 0; i 
< count
; i
++ ) 
3766             wxCoord x 
= r
.GetRight(), 
3776     // some fudge needed to make it look prettier 
3777     xMax 
+= 2*EXTRA_BORDER_X
; 
3778     yMax 
+= 2*EXTRA_BORDER_Y
; 
3780     // account for the scrollbars if necessary 
3781     const wxSize sizeAll 
= GetClientSize(); 
3782     if ( xMax 
> sizeAll
.x 
) 
3783         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
3784     if ( yMax 
> sizeAll
.y 
) 
3785         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
3787     return wxRect(0, 0, xMax
, yMax
); 
3790 void wxListMainWindow::GetItemRect( long index
, wxRect 
&rect 
) const 
3792     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3793                  _T("invalid index in GetItemRect") ); 
3795     // ensure that we're laid out, otherwise we could return nonsense 
3798         wxConstCast(this, wxListMainWindow
)-> 
3799             RecalculatePositions(TRUE 
/* no refresh */); 
3802     rect 
= GetLineRect((size_t)index
); 
3804     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
3807 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
3810     GetItemRect(item
, rect
); 
3818 // ---------------------------------------------------------------------------- 
3819 // geometry calculation 
3820 // ---------------------------------------------------------------------------- 
3822 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
3824     wxClientDC 
dc( this ); 
3825     dc
.SetFont( GetFont() ); 
3827     const size_t count 
= GetItemCount(); 
3830     if ( HasFlag(wxLC_ICON
) ) 
3831         iconSpacing 
= m_normal_spacing
; 
3832     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
3833         iconSpacing 
= m_small_spacing
; 
3837     // Note that we do not call GetClientSize() here but 
3838     // GetSize() and substract the border size for sunken 
3839     // borders manually. This is technically incorrect, 
3840     // but we need to know the client area's size WITHOUT 
3841     // scrollbars here. Since we don't know if there are 
3842     // any scrollbars, we use GetSize() instead. Another 
3843     // solution would be to call SetScrollbars() here to 
3844     // remove the scrollbars and call GetClientSize() then, 
3845     // but this might result in flicker and - worse - will 
3846     // reset the scrollbars to 0 which is not good at all 
3847     // if you resize a dialog/window, but don't want to 
3848     // reset the window scrolling. RR. 
3849     // Furthermore, we actually do NOT subtract the border 
3850     // width as 2 pixels is just the extra space which we 
3851     // need around the actual content in the window. Other- 
3852     // wise the text would e.g. touch the upper border. RR. 
3855     GetSize( &clientWidth
, &clientHeight 
); 
3857     const int lineHeight 
= GetLineHeight(); 
3859     if ( HasFlag(wxLC_REPORT
) ) 
3861         // all lines have the same height and we scroll one line per step 
3862         int entireHeight 
= count
*lineHeight 
+ LINE_SPACING
; 
3864         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
3866         ResetVisibleLinesRange(); 
3868         SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
3869                        GetHeaderWidth() / SCROLL_UNIT_X
, 
3870                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
3871                        GetScrollPos(wxHORIZONTAL
), 
3872                        GetScrollPos(wxVERTICAL
), 
3877         // we have 3 different layout strategies: either layout all items 
3878         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
3879         // to arrange them in top to bottom, left to right (don't ask me why 
3880         // not the other way round...) order 
3881         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
3883             int x 
= EXTRA_BORDER_X
; 
3884             int y 
= EXTRA_BORDER_Y
; 
3886             wxCoord widthMax 
= 0; 
3889             for ( i 
= 0; i 
< count
; i
++ ) 
3891                 wxListLineData 
*line 
= GetLine(i
); 
3892                 line
->CalculateSize( &dc
, iconSpacing 
); 
3893                 line
->SetPosition( x
, y
, iconSpacing 
); 
3895                 wxSize sizeLine 
= GetLineSize(i
); 
3897                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3899                     if ( sizeLine
.x 
> widthMax 
) 
3900                         widthMax 
= sizeLine
.x
; 
3904                 else // wxLC_ALIGN_LEFT 
3906                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
3910             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3912                 // traverse the items again and tweak their sizes so that they are 
3913                 // all the same in a row 
3914                 for ( i 
= 0; i 
< count
; i
++ ) 
3916                     wxListLineData 
*line 
= GetLine(i
); 
3917                     line
->m_gi
->ExtendWidth(widthMax
); 
3926                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3927                 (y 
+ lineHeight
) / lineHeight
, 
3928                 GetScrollPos( wxHORIZONTAL 
), 
3929                 GetScrollPos( wxVERTICAL 
), 
3933         else // "flowed" arrangement, the most complicated case 
3935             // at first we try without any scrollbars, if the items don't fit into 
3936             // the window, we recalculate after subtracting the space taken by the 
3939             int entireWidth 
= 0; 
3941             for (int tries 
= 0; tries 
< 2; tries
++) 
3943                 entireWidth 
= 2*EXTRA_BORDER_X
; 
3947                     // Now we have decided that the items do not fit into the 
3948                     // client area, so we need a scrollbar 
3949                     entireWidth 
+= SCROLL_UNIT_X
; 
3952                 int x 
= EXTRA_BORDER_X
; 
3953                 int y 
= EXTRA_BORDER_Y
; 
3954                 int maxWidthInThisRow 
= 0; 
3957                 int currentlyVisibleLines 
= 0; 
3959                 for (size_t i 
= 0; i 
< count
; i
++) 
3961                     currentlyVisibleLines
++; 
3962                     wxListLineData 
*line 
= GetLine(i
); 
3963                     line
->CalculateSize( &dc
, iconSpacing 
); 
3964                     line
->SetPosition( x
, y
, iconSpacing 
); 
3966                     wxSize sizeLine 
= GetLineSize(i
); 
3968                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
3969                         maxWidthInThisRow 
= sizeLine
.x
; 
3972                     if (currentlyVisibleLines 
> m_linesPerPage
) 
3973                         m_linesPerPage 
= currentlyVisibleLines
; 
3975                     if ( y 
+ sizeLine
.y 
>= clientHeight 
) 
3977                         currentlyVisibleLines 
= 0; 
3979                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
3980                         x 
+= maxWidthInThisRow
; 
3981                         entireWidth 
+= maxWidthInThisRow
; 
3982                         maxWidthInThisRow 
= 0; 
3985                     // We have reached the last item. 
3986                     if ( i 
== count 
- 1 ) 
3987                         entireWidth 
+= maxWidthInThisRow
; 
3989                     if ( (tries 
== 0) && 
3990                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
3992                         clientHeight 
-= wxSystemSettings:: 
3993                                             GetMetric(wxSYS_HSCROLL_Y
); 
3998                     if ( i 
== count 
- 1 ) 
3999                         tries 
= 1;  // Everything fits, no second try required. 
4007                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4009                 GetScrollPos( wxHORIZONTAL 
), 
4018         // FIXME: why should we call it from here? 
4025 void wxListMainWindow::RefreshAll() 
4030     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
4031     if ( headerWin 
&& headerWin
->m_dirty 
) 
4033         headerWin
->m_dirty 
= FALSE
; 
4034         headerWin
->Refresh(); 
4038 void wxListMainWindow::UpdateCurrent() 
4040     if ( !HasCurrent() && !IsEmpty() ) 
4046 long wxListMainWindow::GetNextItem( long item
, 
4047                                     int WXUNUSED(geometry
), 
4051          max 
= GetItemCount(); 
4052     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
4053                  _T("invalid listctrl index in GetNextItem()") ); 
4055     // notice that we start with the next item (or the first one if item == -1) 
4056     // and this is intentional to allow writing a simple loop to iterate over 
4057     // all selected items 
4061         // this is not an error because the index was ok initially, just no 
4072     size_t count 
= GetItemCount(); 
4073     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
4075         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
4078         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
4085 // ---------------------------------------------------------------------------- 
4087 // ---------------------------------------------------------------------------- 
4089 void wxListMainWindow::DeleteItem( long lindex 
) 
4091     size_t count 
= GetItemCount(); 
4093     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
4094                  _T("invalid item index in DeleteItem") ); 
4096     size_t index 
= (size_t)lindex
; 
4098     // we don't need to adjust the index for the previous items 
4099     if ( HasCurrent() && m_current 
>= index 
) 
4101         // if the current item is being deleted, we want the next one to 
4102         // become selected - unless there is no next one - so don't adjust 
4103         // m_current in this case 
4104         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
4110     if ( InReportView() ) 
4112         ResetVisibleLinesRange(); 
4119         m_selStore
.OnItemDelete(index
); 
4123         m_lines
.RemoveAt( index 
); 
4126     // we need to refresh the (vert) scrollbar as the number of items changed 
4129     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM 
); 
4131     RefreshAfter(index
); 
4134 void wxListMainWindow::DeleteColumn( int col 
) 
4136     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4138     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
4141     delete node
->GetData(); 
4142     m_columns
.Erase( node 
); 
4146         // update all the items 
4147         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4149             wxListLineData 
* const line 
= GetLine(i
); 
4150             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
4151             delete n
->GetData(); 
4152             line
->m_items
.Erase(n
); 
4156     // invalidate it as it has to be recalculated 
4160 void wxListMainWindow::DoDeleteAllItems() 
4164         // nothing to do - in particular, don't send the event 
4170     // to make the deletion of all items faster, we don't send the 
4171     // notifications for each item deletion in this case but only one event 
4172     // for all of them: this is compatible with wxMSW and documented in 
4173     // DeleteAllItems() description 
4175     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
4176     event
.SetEventObject( GetParent() ); 
4177     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
4186     if ( InReportView() ) 
4188         ResetVisibleLinesRange(); 
4194 void wxListMainWindow::DeleteAllItems() 
4198     RecalculatePositions(); 
4201 void wxListMainWindow::DeleteEverything() 
4203     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
4208 // ---------------------------------------------------------------------------- 
4209 // scanning for an item 
4210 // ---------------------------------------------------------------------------- 
4212 void wxListMainWindow::EnsureVisible( long index 
) 
4214     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4215                  _T("invalid index in EnsureVisible") ); 
4217     // We have to call this here because the label in question might just have 
4218     // been added and its position is not known yet 
4221         RecalculatePositions(TRUE 
/* no refresh */); 
4224     MoveToItem((size_t)index
); 
4227 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) ) 
4234     size_t count 
= GetItemCount(); 
4235     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
4237         wxListLineData 
*line 
= GetLine(i
); 
4238         if ( line
->GetText(0) == tmp 
) 
4245 long wxListMainWindow::FindItem(long start
, long data
) 
4251     size_t count 
= GetItemCount(); 
4252     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4254         wxListLineData 
*line 
= GetLine(i
); 
4256         line
->GetItem( 0, item 
); 
4257         if (item
.m_data 
== data
) 
4264 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) 
4266     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4268     size_t count 
= GetItemCount(); 
4270     if ( HasFlag(wxLC_REPORT
) ) 
4272         size_t current 
= y 
/ GetLineHeight(); 
4273         if ( current 
< count 
) 
4275             flags 
= HitTestLine(current
, x
, y
); 
4282         // TODO: optimize it too! this is less simple than for report view but 
4283         //       enumerating all items is still not a way to do it!! 
4284         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4286             flags 
= HitTestLine(current
, x
, y
); 
4295 // ---------------------------------------------------------------------------- 
4297 // ---------------------------------------------------------------------------- 
4299 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4301     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
4303     size_t count 
= GetItemCount(); 
4304     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
<= count
, 
4305                  _T("invalid item index") ); 
4307     size_t id 
= item
.m_itemId
; 
4312     // this is unused variable 
4315     if ( HasFlag(wxLC_REPORT
) ) 
4318         // this is unused variable 
4321         ResetVisibleLinesRange(); 
4323     else if ( HasFlag(wxLC_LIST
) ) 
4325         // this is unused variable 
4330     else if ( HasFlag(wxLC_ICON
) ) 
4332         // this is unused variable 
4337     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
4339         // this is unused variable 
4340         mode 
= wxLC_ICON
;  // no typo 
4346         wxFAIL_MSG( _T("unknown mode") ); 
4349     wxListLineData 
*line 
= new wxListLineData(this); 
4351     line
->SetItem( 0, item 
); 
4353     m_lines
.Insert( line
, id 
); 
4357     // If an item is selected at or below the point of insertion, we need to 
4358     // increment the member variables because the current row's index has gone 
4360     if ( HasCurrent() && m_current 
>= id 
) 
4365     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4367     RefreshLines(id
, GetItemCount() - 1); 
4370 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4373     if ( HasFlag(wxLC_REPORT
) ) 
4375         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4376             item
.m_width 
= GetTextLength( item
.m_text 
); 
4378         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4379         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4382             wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4383             m_columns
.Insert( node
, column 
); 
4387             m_columns
.Append( column 
); 
4392             // update all the items 
4393             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4395                 wxListLineData 
* const line 
= GetLine(i
); 
4396                 wxListItemData 
* const data 
= new wxListItemData(this); 
4398                     line
->m_items
.Insert(col
, data
); 
4400                     line
->m_items
.Append(data
); 
4404         // invalidate it as it has to be recalculated 
4409 // ---------------------------------------------------------------------------- 
4411 // ---------------------------------------------------------------------------- 
4413 wxListCtrlCompare list_ctrl_compare_func_2
; 
4414 long              list_ctrl_compare_data
; 
4416 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4418     wxListLineData 
*line1 
= *arg1
; 
4419     wxListLineData 
*line2 
= *arg2
; 
4421     line1
->GetItem( 0, item 
); 
4422     long data1 
= item
.m_data
; 
4423     line2
->GetItem( 0, item 
); 
4424     long data2 
= item
.m_data
; 
4425     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4428 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
4430     list_ctrl_compare_func_2 
= fn
; 
4431     list_ctrl_compare_data 
= data
; 
4432     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4436 // ---------------------------------------------------------------------------- 
4438 // ---------------------------------------------------------------------------- 
4440 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4442     // update our idea of which lines are shown when we redraw the window the 
4444     ResetVisibleLinesRange(); 
4447 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
4448     wxScrolledWindow::OnScroll(event
); 
4450     HandleOnScroll( event 
); 
4453     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4455         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4456         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4458         lc
->m_headerWin
->Refresh(); 
4459         lc
->m_headerWin
->Update(); 
4463 int wxListMainWindow::GetCountPerPage() const 
4465     if ( !m_linesPerPage 
) 
4467         wxConstCast(this, wxListMainWindow
)-> 
4468             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4471     return m_linesPerPage
; 
4474 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4476     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") ); 
4478     if ( m_lineFrom 
== (size_t)-1 ) 
4480         size_t count 
= GetItemCount(); 
4483             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4485             // this may happen if SetScrollbars() hadn't been called yet 
4486             if ( m_lineFrom 
>= count 
) 
4487                 m_lineFrom 
= count 
- 1; 
4489             // we redraw one extra line but this is needed to make the redrawing 
4490             // logic work when there is a fractional number of lines on screen 
4491             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4492             if ( m_lineTo 
>= count 
) 
4493                 m_lineTo 
= count 
- 1; 
4495         else // empty control 
4498             m_lineTo 
= (size_t)-1; 
4502     wxASSERT_MSG( IsEmpty() || 
4503                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4504                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4512 // ------------------------------------------------------------------------------------- 
4513 // wxGenericListCtrl 
4514 // ------------------------------------------------------------------------------------- 
4516 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4518 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4519   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4522 wxGenericListCtrl::wxGenericListCtrl() 
4524     m_imageListNormal 
= (wxImageListType 
*) NULL
; 
4525     m_imageListSmall 
= (wxImageListType 
*) NULL
; 
4526     m_imageListState 
= (wxImageListType 
*) NULL
; 
4528     m_ownsImageListNormal 
= 
4529     m_ownsImageListSmall 
= 
4530     m_ownsImageListState 
= FALSE
; 
4532     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4533     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4537 wxGenericListCtrl::~wxGenericListCtrl() 
4539     if (m_ownsImageListNormal
) 
4540         delete m_imageListNormal
; 
4541     if (m_ownsImageListSmall
) 
4542         delete m_imageListSmall
; 
4543     if (m_ownsImageListState
) 
4544         delete m_imageListState
; 
4547 void wxGenericListCtrl::CalculateAndSetHeaderHeight() 
4551         // we use 'g' to get the descent, too 
4553         m_headerWin
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
); 
4554         h 
+= d 
+ 2 * HEADER_OFFSET_Y 
+ EXTRA_HEIGHT
; 
4556         // only update if changed 
4557         if ( h 
!= m_headerHeight 
) 
4561             m_headerWin
->SetSize(m_headerWin
->GetSize().x
, m_headerHeight
); 
4563             if ( HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
) ) 
4564                 ResizeReportView(TRUE
); 
4569 void wxGenericListCtrl::CreateHeaderWindow() 
4571     m_headerWin 
= new wxListHeaderWindow
 
4573                         this, -1, m_mainWin
, 
4575                         wxSize(GetClientSize().x
, m_headerHeight
), 
4578     CalculateAndSetHeaderHeight(); 
4581 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
4586                         const wxValidator 
&validator
, 
4587                         const wxString 
&name
) 
4591     m_imageListState 
= (wxImageListType 
*) NULL
; 
4592     m_ownsImageListNormal 
= 
4593     m_ownsImageListSmall 
= 
4594     m_ownsImageListState 
= FALSE
; 
4596     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4597     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4601     if ( !(style 
& wxLC_MASK_TYPE
) ) 
4603         style 
= style 
| wxLC_LIST
; 
4606     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
4609     // don't create the inner window with the border 
4610     style 
&= ~wxBORDER_MASK
; 
4612     m_mainWin 
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style 
); 
4614     if ( HasFlag(wxLC_REPORT
) ) 
4616         CreateHeaderWindow(); 
4618         if ( HasFlag(wxLC_NO_HEADER
) ) 
4620             // VZ: why do we create it at all then? 
4621             m_headerWin
->Show( FALSE 
); 
4628 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
4630     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4631                   _T("wxLC_VIRTUAL can't be [un]set") ); 
4633     long flag 
= GetWindowStyle(); 
4637         if (style 
& wxLC_MASK_TYPE
) 
4638             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4639         if (style 
& wxLC_MASK_ALIGN
) 
4640             flag 
&= ~wxLC_MASK_ALIGN
; 
4641         if (style 
& wxLC_MASK_SORT
) 
4642             flag 
&= ~wxLC_MASK_SORT
; 
4654     SetWindowStyleFlag( flag 
); 
4657 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
4661         m_mainWin
->DeleteEverything(); 
4663         // has the header visibility changed? 
4664         bool hasHeader 
= HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
), 
4665              willHaveHeader 
= (flag 
& wxLC_REPORT
) && !(flag 
& wxLC_NO_HEADER
); 
4667         if ( hasHeader 
!= willHaveHeader 
) 
4674                     // don't delete, just hide, as we can reuse it later 
4675                     m_headerWin
->Show(FALSE
); 
4677                 //else: nothing to do 
4679             else // must show header 
4683                     CreateHeaderWindow(); 
4685                 else // already have it, just show 
4687                     m_headerWin
->Show( TRUE 
); 
4691             ResizeReportView(willHaveHeader
); 
4695     wxWindow::SetWindowStyleFlag( flag 
); 
4698 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4700     m_mainWin
->GetColumn( col
, item 
); 
4704 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
4706     m_mainWin
->SetColumn( col
, item 
); 
4710 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
4712     return m_mainWin
->GetColumnWidth( col 
); 
4715 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
4717     m_mainWin
->SetColumnWidth( col
, width 
); 
4721 int wxGenericListCtrl::GetCountPerPage() const 
4723   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4726 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
4728     m_mainWin
->GetItem( info 
); 
4732 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
4734     m_mainWin
->SetItem( info 
); 
4738 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4741     info
.m_text 
= label
; 
4742     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4743     info
.m_itemId 
= index
; 
4747         info
.m_image 
= imageId
; 
4748         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4750     m_mainWin
->SetItem(info
); 
4754 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
4756     return m_mainWin
->GetItemState( item
, stateMask 
); 
4759 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4761     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4765 bool wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4768     info
.m_image 
= image
; 
4769     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4770     info
.m_itemId 
= item
; 
4771     m_mainWin
->SetItem( info 
); 
4775 wxString 
wxGenericListCtrl::GetItemText( long item 
) const 
4777     return m_mainWin
->GetItemText(item
); 
4780 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
4782     m_mainWin
->SetItemText(item
, str
); 
4785 long wxGenericListCtrl::GetItemData( long item 
) const 
4788     info
.m_itemId 
= item
; 
4789     m_mainWin
->GetItem( info 
); 
4793 bool wxGenericListCtrl::SetItemData( long item
, long data 
) 
4796     info
.m_mask 
= wxLIST_MASK_DATA
; 
4797     info
.m_itemId 
= item
; 
4799     m_mainWin
->SetItem( info 
); 
4803 wxRect 
wxGenericListCtrl::GetViewRect() const 
4805     return m_mainWin
->GetViewRect(); 
4808 bool wxGenericListCtrl::GetItemRect( long item
, wxRect 
&rect
,  int WXUNUSED(code
) ) const 
4810     m_mainWin
->GetItemRect( item
, rect 
); 
4811     if ( m_mainWin
->HasHeader() ) 
4812         rect
.y 
+= m_headerHeight 
+ 1; 
4816 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4818     m_mainWin
->GetItemPosition( item
, pos 
); 
4822 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4827 int wxGenericListCtrl::GetItemCount() const 
4829     return m_mainWin
->GetItemCount(); 
4832 int wxGenericListCtrl::GetColumnCount() const 
4834     return m_mainWin
->GetColumnCount(); 
4837 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4839     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4842 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
4844     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
4846     return wxSize(spacing
, spacing
); 
4849 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
4851     return m_mainWin
->GetItemSpacing( isSmall 
); 
4854 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
4857     info
.m_itemId 
= item
; 
4858     info
.SetTextColour( col 
); 
4859     m_mainWin
->SetItem( info 
); 
4862 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
4865     info
.m_itemId 
= item
; 
4866     m_mainWin
->GetItem( info 
); 
4867     return info
.GetTextColour(); 
4870 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
4873     info
.m_itemId 
= item
; 
4874     info
.SetBackgroundColour( col 
); 
4875     m_mainWin
->SetItem( info 
); 
4878 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
4881     info
.m_itemId 
= item
; 
4882     m_mainWin
->GetItem( info 
); 
4883     return info
.GetBackgroundColour(); 
4886 int wxGenericListCtrl::GetSelectedItemCount() const 
4888     return m_mainWin
->GetSelectedItemCount(); 
4891 wxColour 
wxGenericListCtrl::GetTextColour() const 
4893     return GetForegroundColour(); 
4896 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
4898     SetForegroundColour(col
); 
4901 long wxGenericListCtrl::GetTopItem() const 
4904     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
4908 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
4910     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
4913 wxImageListType 
*wxGenericListCtrl::GetImageList(int which
) const 
4915     if (which 
== wxIMAGE_LIST_NORMAL
) 
4917         return m_imageListNormal
; 
4919     else if (which 
== wxIMAGE_LIST_SMALL
) 
4921         return m_imageListSmall
; 
4923     else if (which 
== wxIMAGE_LIST_STATE
) 
4925         return m_imageListState
; 
4927     return (wxImageListType 
*) NULL
; 
4930 void wxGenericListCtrl::SetImageList( wxImageListType 
*imageList
, int which 
) 
4932     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4934         if (m_ownsImageListNormal
) delete m_imageListNormal
; 
4935         m_imageListNormal 
= imageList
; 
4936         m_ownsImageListNormal 
= FALSE
; 
4938     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4940         if (m_ownsImageListSmall
) delete m_imageListSmall
; 
4941         m_imageListSmall 
= imageList
; 
4942         m_ownsImageListSmall 
= FALSE
; 
4944     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4946         if (m_ownsImageListState
) delete m_imageListState
; 
4947         m_imageListState 
= imageList
; 
4948         m_ownsImageListState 
= FALSE
; 
4951     m_mainWin
->SetImageList( imageList
, which 
); 
4954 void wxGenericListCtrl::AssignImageList(wxImageListType 
*imageList
, int which
) 
4956     SetImageList(imageList
, which
); 
4957     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4958         m_ownsImageListNormal 
= TRUE
; 
4959     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4960         m_ownsImageListSmall 
= TRUE
; 
4961     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4962         m_ownsImageListState 
= TRUE
; 
4965 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
4970 bool wxGenericListCtrl::DeleteItem( long item 
) 
4972     m_mainWin
->DeleteItem( item 
); 
4976 bool wxGenericListCtrl::DeleteAllItems() 
4978     m_mainWin
->DeleteAllItems(); 
4982 bool wxGenericListCtrl::DeleteAllColumns() 
4984     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
4985     for ( size_t n 
= 0; n 
< count
; n
++ ) 
4991 void wxGenericListCtrl::ClearAll() 
4993     m_mainWin
->DeleteEverything(); 
4996 bool wxGenericListCtrl::DeleteColumn( int col 
) 
4998     m_mainWin
->DeleteColumn( col 
); 
5000     // if we don't have the header any longer, we need to relayout the window 
5001     if ( !GetColumnCount() ) 
5003         ResizeReportView(FALSE 
/* no header */); 
5009 void wxGenericListCtrl::Edit( long item 
) 
5011     m_mainWin
->EditLabel( item 
); 
5014 bool wxGenericListCtrl::EnsureVisible( long item 
) 
5016     m_mainWin
->EnsureVisible( item 
); 
5020 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
,  bool partial 
) 
5022     return m_mainWin
->FindItem( start
, str
, partial 
); 
5025 long wxGenericListCtrl::FindItem( long start
, long data 
) 
5027     return m_mainWin
->FindItem( start
, data 
); 
5030 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
), 
5031                            int WXUNUSED(direction
)) 
5036 long wxGenericListCtrl::HitTest( const wxPoint 
&point
, int &flags 
) 
5038     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
5041 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
5043     m_mainWin
->InsertItem( info 
); 
5044     return info
.m_itemId
; 
5047 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
5050     info
.m_text 
= label
; 
5051     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5052     info
.m_itemId 
= index
; 
5053     return InsertItem( info 
); 
5056 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
5059     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5060     info
.m_image 
= imageIndex
; 
5061     info
.m_itemId 
= index
; 
5062     return InsertItem( info 
); 
5065 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
5068     info
.m_text 
= label
; 
5069     info
.m_image 
= imageIndex
; 
5070     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
5071     info
.m_itemId 
= index
; 
5072     return InsertItem( info 
); 
5075 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
5077     wxCHECK_MSG( m_headerWin
, -1, _T("can't add column in non report mode") ); 
5079     m_mainWin
->InsertColumn( col
, item 
); 
5081     // if we hadn't had header before and have it now we need to relayout the 
5083     if ( GetColumnCount() == 1 && m_mainWin
->HasHeader() ) 
5085         ResizeReportView(TRUE 
/* have header */); 
5088     m_headerWin
->Refresh(); 
5093 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
5094                                int format
, int width 
) 
5097     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
5098     item
.m_text 
= heading
; 
5101         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
5102         item
.m_width 
= width
; 
5104     item
.m_format 
= format
; 
5106     return InsertColumn( col
, item 
); 
5109 bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) ) 
5115 // fn is a function which takes 3 long arguments: item1, item2, data. 
5116 // item1 is the long data associated with a first item (NOT the index). 
5117 // item2 is the long data associated with a second item (NOT the index). 
5118 // data is the same value as passed to SortItems. 
5119 // The return value is a negative number if the first item should precede the second 
5120 // item, a positive number of the second item should precede the first, 
5121 // or zero if the two items are equivalent. 
5122 // data is arbitrary data to be passed to the sort function. 
5124 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
5126     m_mainWin
->SortItems( fn
, data 
); 
5130 // ---------------------------------------------------------------------------- 
5132 // ---------------------------------------------------------------------------- 
5134 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
5139     ResizeReportView(m_mainWin
->HasHeader()); 
5141     m_mainWin
->RecalculatePositions(); 
5144 void wxGenericListCtrl::ResizeReportView(bool showHeader
) 
5147     GetClientSize( &cw
, &ch 
); 
5151         m_headerWin
->SetSize( 0, 0, cw
, m_headerHeight 
); 
5152         m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, cw
, ch 
- m_headerHeight 
- 1 ); 
5154     else // no header window 
5156         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
5160 void wxGenericListCtrl::OnInternalIdle() 
5162     wxWindow::OnInternalIdle(); 
5164     // do it only if needed 
5165     if ( !m_mainWin
->m_dirty 
) 
5168     m_mainWin
->RecalculatePositions(); 
5171 // ---------------------------------------------------------------------------- 
5173 // ---------------------------------------------------------------------------- 
5175 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5179         m_mainWin
->SetBackgroundColour( colour 
); 
5180         m_mainWin
->m_dirty 
= TRUE
; 
5186 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5188     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5193         m_mainWin
->SetForegroundColour( colour 
); 
5194         m_mainWin
->m_dirty 
= TRUE
; 
5199         m_headerWin
->SetForegroundColour( colour 
); 
5205 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5207     if ( !wxWindow::SetFont( font 
) ) 
5212         m_mainWin
->SetFont( font 
); 
5213         m_mainWin
->m_dirty 
= TRUE
; 
5218         m_headerWin
->SetFont( font 
); 
5219         CalculateAndSetHeaderHeight(); 
5227 // ---------------------------------------------------------------------------- 
5228 // methods forwarded to m_mainWin 
5229 // ---------------------------------------------------------------------------- 
5231 #if wxUSE_DRAG_AND_DROP 
5233 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5235     m_mainWin
->SetDropTarget( dropTarget 
); 
5238 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5240     return m_mainWin
->GetDropTarget(); 
5243 #endif // wxUSE_DRAG_AND_DROP 
5245 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5247     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
; 
5250 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5252     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5255 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5257     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5260 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5263     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5266 #endif // wxUSE_MENUS 
5269 void wxGenericListCtrl::SetFocus() 
5271     /* The test in window.cpp fails as we are a composite 
5272        window, so it checks against "this", but not m_mainWin. */ 
5273     if ( FindFocus() != this ) 
5274         m_mainWin
->SetFocus(); 
5277 // ---------------------------------------------------------------------------- 
5278 // virtual list control support 
5279 // ---------------------------------------------------------------------------- 
5281 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5283     // this is a pure virtual function, in fact - which is not really pure 
5284     // because the controls which are not virtual don't need to implement it 
5285     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5287     return wxEmptyString
; 
5290 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5293     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemImage not supposed to be called") ); 
5299 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5301     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5302                   _T("invalid item index in OnGetItemAttr()") ); 
5304     // no attributes by default 
5308 void wxGenericListCtrl::SetItemCount(long count
) 
5310     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
5312     m_mainWin
->SetItemCount(count
); 
5315 void wxGenericListCtrl::RefreshItem(long item
) 
5317     m_mainWin
->RefreshLine(item
); 
5320 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5322     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5326  * Generic wxListCtrl is more or less a container for two other 
5327  * windows which drawings are done upon. These are namely 
5328  * 'm_headerWin' and 'm_mainWin'. 
5329  * Here we override 'virtual wxWindow::Refresh()' to mimic the 
5330  * behaviour wxListCtrl has under wxMSW. 
5332 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5336         // The easy case, no rectangle specified. 
5338             m_headerWin
->Refresh(eraseBackground
); 
5341             m_mainWin
->Refresh(eraseBackground
); 
5345         // Refresh the header window 
5348             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5349             rectHeader
.Intersect(*rect
); 
5350             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5353                 m_headerWin
->GetPosition(&x
, &y
); 
5354                 rectHeader
.Offset(-x
, -y
); 
5355                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5360         // Refresh the main window 
5363             wxRect rectMain 
= m_mainWin
->GetRect(); 
5364             rectMain
.Intersect(*rect
); 
5365             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5368                 m_mainWin
->GetPosition(&x
, &y
); 
5369                 rectMain
.Offset(-x
, -y
); 
5370                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5376 void wxGenericListCtrl::Freeze() 
5378     m_mainWin
->Freeze(); 
5381 void wxGenericListCtrl::Thaw() 
5386 #endif // wxUSE_LISTCTRL