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() 
1813     int x1 
= m_currentX
; 
1815     m_owner
->ClientToScreen( &x1
, &y1 
); 
1817     int x2 
= m_currentX
; 
1819     m_owner
->GetClientSize( NULL
, &y2 
); 
1820     m_owner
->ClientToScreen( &x2
, &y2 
); 
1823     dc
.SetLogicalFunction( wxINVERT 
); 
1824     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
1825     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1829     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1831     dc
.SetLogicalFunction( wxCOPY 
); 
1833     dc
.SetPen( wxNullPen 
); 
1834     dc
.SetBrush( wxNullBrush 
); 
1837 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1839     // we want to work with logical coords 
1841     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1842     int y 
= event
.GetY(); 
1846         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1848         // we don't draw the line beyond our window, but we allow dragging it 
1851         GetClientSize( &w
, NULL 
); 
1852         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1855         // erase the line if it was drawn 
1856         if ( m_currentX 
< w 
) 
1859         if (event
.ButtonUp()) 
1862             m_isDragging 
= FALSE
; 
1864             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1865             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1872                 m_currentX 
= m_minX 
+ 7; 
1874             // draw in the new location 
1875             if ( m_currentX 
< w 
) 
1879     else // not dragging 
1882         bool hit_border 
= FALSE
; 
1884         // end of the current column 
1887         // find the column where this event occured 
1889             countCol 
= m_owner
->GetColumnCount(); 
1890         for (col 
= 0; col 
< countCol
; col
++) 
1892             xpos 
+= m_owner
->GetColumnWidth( col 
); 
1895             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
1897                 // near the column border 
1904                 // inside the column 
1911         if ( col 
== countCol 
) 
1914         if (event
.LeftDown() || event
.RightUp()) 
1916             if (hit_border 
&& event
.LeftDown()) 
1918                 if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
1919                                    event
.GetPosition()) ) 
1921                     m_isDragging 
= TRUE
; 
1926                 //else: column resizing was vetoed by the user code 
1928             else // click on a column 
1930                 SendListEvent( event
.LeftDown() 
1931                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
1932                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
1933                                 event
.GetPosition()); 
1936         else if (event
.Moving()) 
1941                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
1942                 m_currentCursor 
= m_resizeCursor
; 
1946                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
1947                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1951                 SetCursor(*m_currentCursor
); 
1956 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1958     m_owner
->SetFocus(); 
1961 bool wxListHeaderWindow::SendListEvent(wxEventType type
, wxPoint pos
) 
1963     wxWindow 
*parent 
= GetParent(); 
1964     wxListEvent 
le( type
, parent
->GetId() ); 
1965     le
.SetEventObject( parent 
); 
1966     le
.m_pointDrag 
= pos
; 
1968     // the position should be relative to the parent window, not 
1969     // this one for compatibility with MSW and common sense: the 
1970     // user code doesn't know anything at all about this header 
1971     // window, so why should it get positions relative to it? 
1972     le
.m_pointDrag
.y 
-= GetSize().y
; 
1974     le
.m_col 
= m_column
; 
1975     return !parent
->GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
1978 //----------------------------------------------------------------------------- 
1979 // wxListRenameTimer (internal) 
1980 //----------------------------------------------------------------------------- 
1982 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
1987 void wxListRenameTimer::Notify() 
1989     m_owner
->OnRenameTimer(); 
1992 //----------------------------------------------------------------------------- 
1993 // wxListTextCtrl (internal) 
1994 //----------------------------------------------------------------------------- 
1996 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
) 
1997     EVT_CHAR           (wxListTextCtrl::OnChar
) 
1998     EVT_KEY_UP         (wxListTextCtrl::OnKeyUp
) 
1999     EVT_KILL_FOCUS     (wxListTextCtrl::OnKillFocus
) 
2002 wxListTextCtrl::wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
) 
2003               : m_startValue(owner
->GetItemText(itemEdit
)), 
2004                 m_itemEdited(itemEdit
) 
2009     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
2011     m_owner
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
2012                                   &rectLabel
.x
, &rectLabel
.y
); 
2014     (void)Create(owner
, wxID_ANY
, m_startValue
, 
2015                  wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2016                  wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
2019 void wxListTextCtrl::Finish() 
2023         wxPendingDelete
.Append(this); 
2027         m_owner
->SetFocus(); 
2031 bool wxListTextCtrl::AcceptChanges() 
2033     const wxString value 
= GetValue(); 
2035     if ( value 
== m_startValue 
) 
2037         // nothing changed, always accept 
2041     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
2043         // vetoed by the user 
2047     // accepted, do rename the item 
2048     m_owner
->SetItemText(m_itemEdited
, value
); 
2053 void wxListTextCtrl::OnChar( wxKeyEvent 
&event 
) 
2055     switch ( event
.m_keyCode 
) 
2058             if ( !AcceptChanges() ) 
2060                 // vetoed by the user code 
2063             //else: fall through 
2067             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2075 void wxListTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
2083     // auto-grow the textctrl: 
2084     wxSize parentSize 
= m_owner
->GetSize(); 
2085     wxPoint myPos 
= GetPosition(); 
2086     wxSize mySize 
= GetSize(); 
2088     GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); 
2089     if (myPos
.x 
+ sx 
> parentSize
.x
) 
2090         sx 
= parentSize
.x 
- myPos
.x
; 
2098 void wxListTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2102         // We must finish regardless of success, otherwise we'll get focus problems 
2105         if ( !AcceptChanges() ) 
2106             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2112 //----------------------------------------------------------------------------- 
2114 //----------------------------------------------------------------------------- 
2116 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
) 
2118 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
) 
2119   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2120   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2121   EVT_CHAR           (wxListMainWindow::OnChar
) 
2122   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2123   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2124   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2125   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2128 void wxListMainWindow::Init() 
2133     m_lineTo 
= (size_t)-1; 
2139     m_small_image_list 
= (wxImageListType 
*) NULL
; 
2140     m_normal_image_list 
= (wxImageListType 
*) NULL
; 
2142     m_small_spacing 
= 30; 
2143     m_normal_spacing 
= 40; 
2147     m_isCreated 
= FALSE
; 
2149     m_lastOnSame 
= FALSE
; 
2150     m_renameTimer 
= new wxListRenameTimer( this ); 
2154     m_lineBeforeLastClicked 
= (size_t)-1; 
2159 wxListMainWindow::wxListMainWindow() 
2164     m_highlightUnfocusedBrush 
= (wxBrush 
*) NULL
; 
2167 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2172                                     const wxString 
&name 
) 
2173                 : wxScrolledWindow( parent
, id
, pos
, size
, 
2174                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2178     m_highlightBrush 
= new wxBrush
 
2180                             wxSystemSettings::GetColour
 
2182                                 wxSYS_COLOUR_HIGHLIGHT
 
2187     m_highlightUnfocusedBrush 
= new wxBrush
 
2189                                        wxSystemSettings::GetColour
 
2191                                            wxSYS_COLOUR_BTNSHADOW
 
2199     SetScrollbars( 0, 0, 0, 0, 0, 0 ); 
2201     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX 
) ); 
2204 wxListMainWindow::~wxListMainWindow() 
2207     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
2209     delete m_highlightBrush
; 
2210     delete m_highlightUnfocusedBrush
; 
2212     delete m_renameTimer
; 
2215 void wxListMainWindow::CacheLineData(size_t line
) 
2217     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
2219     wxListLineData 
*ld 
= GetDummyLine(); 
2221     size_t countCol 
= GetColumnCount(); 
2222     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2224         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2227     ld
->SetImage(listctrl
->OnGetItemImage(line
)); 
2228     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
2231 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2233     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2235     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); 
2237     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2239     // we need to recreate the dummy line if the number of columns in the 
2240     // control changed as it would have the incorrect number of fields 
2242     if ( !m_lines
.IsEmpty() && 
2243             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
2245         self
->m_lines
.Clear(); 
2248     if ( m_lines
.IsEmpty() ) 
2250         wxListLineData 
*line 
= new wxListLineData(self
); 
2251         self
->m_lines
.Add(line
); 
2253         // don't waste extra memory -- there never going to be anything 
2254         // else/more in this array 
2255         self
->m_lines
.Shrink(); 
2261 // ---------------------------------------------------------------------------- 
2262 // line geometry (report mode only) 
2263 // ---------------------------------------------------------------------------- 
2265 wxCoord 
wxListMainWindow::GetLineHeight() const 
2267     // we cache the line height as calling GetTextExtent() is slow 
2268     if ( !m_lineHeight 
) 
2270         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2272         wxClientDC 
dc( self 
); 
2273         dc
.SetFont( GetFont() ); 
2276         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2278         if ( m_small_image_list 
&& m_small_image_list
->GetImageCount() ) 
2282             m_small_image_list
->GetSize(0, iw
, ih
); 
2287         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2290     return m_lineHeight
; 
2293 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2295     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") ); 
2297     return LINE_SPACING 
+ line
*GetLineHeight(); 
2300 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2302     if ( !InReportView() ) 
2303         return GetLine(line
)->m_gi
->m_rectAll
; 
2306     rect
.x 
= HEADER_OFFSET_X
; 
2307     rect
.y 
= GetLineY(line
); 
2308     rect
.width 
= GetHeaderWidth(); 
2309     rect
.height 
= GetLineHeight(); 
2314 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2316     if ( !InReportView() ) 
2317         return GetLine(line
)->m_gi
->m_rectLabel
; 
2320     rect
.x 
= HEADER_OFFSET_X
; 
2321     rect
.y 
= GetLineY(line
); 
2322     rect
.width 
= GetColumnWidth(0); 
2323     rect
.height 
= GetLineHeight(); 
2328 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2330     if ( !InReportView() ) 
2331         return GetLine(line
)->m_gi
->m_rectIcon
; 
2333     wxListLineData 
*ld 
= GetLine(line
); 
2334     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2337     rect
.x 
= HEADER_OFFSET_X
; 
2338     rect
.y 
= GetLineY(line
); 
2339     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2344 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2346     return InReportView() ? GetLineRect(line
) 
2347                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2350 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2352     wxASSERT_MSG( line 
< GetItemCount(), _T("invalid line in HitTestLine") ); 
2354     wxListLineData 
*ld 
= GetLine(line
); 
2356     if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) ) 
2357         return wxLIST_HITTEST_ONITEMICON
; 
2359     // VS: Testing for "ld->HasText() || InReportView()" instead of 
2360     //     "ld->HasText()" is needed to make empty lines in report view 
2362     if ( ld
->HasText() || InReportView() ) 
2364         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2365                                      : GetLineLabelRect(line
); 
2367         if ( rect
.Inside(x
, y
) ) 
2368             return wxLIST_HITTEST_ONITEMLABEL
; 
2374 // ---------------------------------------------------------------------------- 
2375 // highlight (selection) handling 
2376 // ---------------------------------------------------------------------------- 
2378 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2382         return m_selStore
.IsSelected(line
); 
2386         wxListLineData 
*ld 
= GetLine(line
); 
2387         wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") ); 
2389         return ld
->IsHighlighted(); 
2393 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
2399         wxArrayInt linesChanged
; 
2400         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
2403             // meny items changed state, refresh everything 
2404             RefreshLines(lineFrom
, lineTo
); 
2406         else // only a few items changed state, refresh only them 
2408             size_t count 
= linesChanged
.GetCount(); 
2409             for ( size_t n 
= 0; n 
< count
; n
++ ) 
2411                 RefreshLine(linesChanged
[n
]); 
2415     else // iterate over all items in non report view 
2417         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2419             if ( HighlightLine(line
, highlight
) ) 
2427 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2433         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2437         wxListLineData 
*ld 
= GetLine(line
); 
2438         wxCHECK_MSG( ld
, FALSE
, _T("invalid index in HighlightLine") ); 
2440         changed 
= ld
->Highlight(highlight
); 
2445         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2446                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2452 void wxListMainWindow::RefreshLine( size_t line 
) 
2454     if ( HasFlag(wxLC_REPORT
) ) 
2456         size_t visibleFrom
, visibleTo
; 
2457         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2459         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
2463     wxRect rect 
= GetLineRect(line
); 
2465     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2466     RefreshRect( rect 
); 
2469 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2471     // we suppose that they are ordered by caller 
2472     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2474     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2476     if ( HasFlag(wxLC_REPORT
) ) 
2478         size_t visibleFrom
, visibleTo
; 
2479         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2481         if ( lineFrom 
< visibleFrom 
) 
2482             lineFrom 
= visibleFrom
; 
2483         if ( lineTo 
> visibleTo 
) 
2488         rect
.y 
= GetLineY(lineFrom
); 
2489         rect
.width 
= GetClientSize().x
; 
2490         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
2492         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2493         RefreshRect( rect 
); 
2497         // TODO: this should be optimized... 
2498         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2505 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2507     if ( HasFlag(wxLC_REPORT
) ) 
2509         size_t visibleFrom
, visibleTo
; 
2510         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2512         if ( lineFrom 
< visibleFrom 
) 
2513             lineFrom 
= visibleFrom
; 
2514         else if ( lineFrom 
> visibleTo 
) 
2519         rect
.y 
= GetLineY(lineFrom
); 
2520         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2522         wxSize size 
= GetClientSize(); 
2523         rect
.width 
= size
.x
; 
2524         // refresh till the bottom of the window 
2525         rect
.height 
= size
.y 
- rect
.y
; 
2527         RefreshRect( rect 
); 
2531         // TODO: how to do it more efficiently? 
2536 void wxListMainWindow::RefreshSelected() 
2542     if ( InReportView() ) 
2544         GetVisibleLinesRange(&from
, &to
); 
2549         to 
= GetItemCount() - 1; 
2552     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
2554         RefreshLine(m_current
); 
2557     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
2559         // NB: the test works as expected even if m_current == -1 
2560         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
2567 void wxListMainWindow::Freeze() 
2572 void wxListMainWindow::Thaw() 
2574     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen list control?") ); 
2576     if ( !--m_freezeCount 
) 
2582 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2584     // Note: a wxPaintDC must be constructed even if no drawing is 
2585     // done (a Windows requirement). 
2586     wxPaintDC 
dc( this ); 
2588     if ( IsEmpty() || m_freezeCount 
) 
2590         // nothing to draw or not the moment to draw it 
2596         // delay the repainting until we calculate all the items positions 
2603     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2607     dc
.SetFont( GetFont() ); 
2609     if ( HasFlag(wxLC_REPORT
) ) 
2611         int lineHeight 
= GetLineHeight(); 
2613         size_t visibleFrom
, visibleTo
; 
2614         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2617         wxCoord xOrig
, yOrig
; 
2618         CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
); 
2620         // tell the caller cache to cache the data 
2623             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2624                                 GetParent()->GetId()); 
2625             evCache
.SetEventObject( GetParent() ); 
2626             evCache
.m_oldItemIndex 
= visibleFrom
; 
2627             evCache
.m_itemIndex 
= visibleTo
; 
2628             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2631         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2633             rectLine 
= GetLineRect(line
); 
2635             if ( !IsExposed(rectLine
.x 
- xOrig
, rectLine
.y 
- yOrig
, 
2636                             rectLine
.width
, rectLine
.height
) ) 
2638                 // don't redraw unaffected lines to avoid flicker 
2642             GetLine(line
)->DrawInReportMode( &dc
, 
2644                                              GetLineHighlightRect(line
), 
2645                                              IsHighlighted(line
) ); 
2648         if ( HasFlag(wxLC_HRULES
) ) 
2650             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2651             wxSize clientSize 
= GetClientSize(); 
2653             // Don't draw the first one 
2654             for ( size_t i 
= visibleFrom
+1; i 
<= visibleTo
; i
++ ) 
2657                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2658                 dc
.DrawLine(0 - dev_x
, i
*lineHeight
, 
2659                             clientSize
.x 
- dev_x
, i
*lineHeight
); 
2662             // Draw last horizontal rule 
2663             if ( visibleTo 
== GetItemCount() - 1 ) 
2666                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2667                 dc
.DrawLine(0 - dev_x
, (m_lineTo
+1)*lineHeight
, 
2668                             clientSize
.x 
- dev_x 
, (m_lineTo
+1)*lineHeight 
); 
2672         // Draw vertical rules if required 
2673         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2675             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2677             wxRect firstItemRect
; 
2678             wxRect lastItemRect
; 
2679             GetItemRect(visibleFrom
, firstItemRect
); 
2680             GetItemRect(visibleTo
, lastItemRect
); 
2681             int x 
= firstItemRect
.GetX(); 
2683             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2684             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2686                 int colWidth 
= GetColumnWidth(col
); 
2688                 dc
.DrawLine(x 
- dev_x 
- 2, firstItemRect
.GetY() - 1 - dev_y
, 
2689                             x 
- dev_x 
- 2, lastItemRect
.GetBottom() + 1 - dev_y
); 
2695         size_t count 
= GetItemCount(); 
2696         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2698             GetLine(i
)->Draw( &dc 
); 
2704         // don't draw rect outline under Max if we already have the background 
2705         // color but under other platforms only draw it if we do: it is a bit 
2706         // silly to draw "focus rect" if we don't have focus! 
2711 #endif // __WXMAC__/!__WXMAC__ 
2713             dc
.SetPen( *wxBLACK_PEN 
); 
2714             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2715             dc
.DrawRectangle( GetLineHighlightRect(m_current
) ); 
2722 void wxListMainWindow::HighlightAll( bool on 
) 
2724     if ( IsSingleSel() ) 
2726         wxASSERT_MSG( !on
, _T("can't do this in a single sel control") ); 
2728         // we just have one item to turn off 
2729         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2731             HighlightLine(m_current
, FALSE
); 
2732             RefreshLine(m_current
); 
2737         HighlightLines(0, GetItemCount() - 1, on
); 
2741 void wxListMainWindow::SendNotify( size_t line
, 
2742                                    wxEventType command
, 
2745     wxListEvent 
le( command
, GetParent()->GetId() ); 
2746     le
.SetEventObject( GetParent() ); 
2747     le
.m_itemIndex 
= line
; 
2749     // set only for events which have position 
2750     if ( point 
!= wxDefaultPosition 
) 
2751         le
.m_pointDrag 
= point
; 
2753     // don't try to get the line info for virtual list controls: the main 
2754     // program has it anyhow and if we did it would result in accessing all 
2755     // the lines, even those which are not visible now and this is precisely 
2756     // what we're trying to avoid 
2757     if ( !IsVirtual() && (command 
!= wxEVT_COMMAND_LIST_DELETE_ITEM
) ) 
2759         if ( line 
!= (size_t)-1 ) 
2761             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2763         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2765     //else: there may be no more such item 
2767     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2770 void wxListMainWindow::ChangeCurrent(size_t current
) 
2772     m_current 
= current
; 
2774     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2777 void wxListMainWindow::EditLabel( long item 
) 
2779     wxCHECK_RET( (item 
>= 0) && ((size_t)item 
< GetItemCount()), 
2780                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2782     size_t itemEdit 
= (size_t)item
; 
2784     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2785     le
.SetEventObject( GetParent() ); 
2786     le
.m_itemIndex 
= item
; 
2787     wxListLineData 
*data 
= GetLine(itemEdit
); 
2788     wxCHECK_RET( data
, _T("invalid index in EditLabel()") ); 
2789     data
->GetItem( 0, le
.m_item 
); 
2790     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2792         // vetoed by user code 
2796     // We have to call this here because the label in question might just have 
2797     // been added and no screen update taken place. 
2801     wxListTextCtrl 
*text 
= new wxListTextCtrl(this, itemEdit
); 
2806 void wxListMainWindow::OnRenameTimer() 
2808     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2810     EditLabel( m_current 
); 
2813 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2815     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2816     le
.SetEventObject( GetParent() ); 
2817     le
.m_itemIndex 
= itemEdit
; 
2819     wxListLineData 
*data 
= GetLine(itemEdit
); 
2820     wxCHECK_MSG( data
, FALSE
, _T("invalid index in OnRenameAccept()") ); 
2822     data
->GetItem( 0, le
.m_item 
); 
2823     le
.m_item
.m_text 
= value
; 
2824     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2828 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2830     // let owner know that the edit was cancelled 
2831     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2833     le
.SetEditCanceled(TRUE
); 
2835     le
.SetEventObject( GetParent() ); 
2836     le
.m_itemIndex 
= itemEdit
; 
2838     wxListLineData 
*data 
= GetLine(itemEdit
); 
2839     wxCHECK_RET( data
, _T("invalid index in OnRenameCancelled()") ); 
2841     data
->GetItem( 0, le
.m_item 
); 
2843     GetEventHandler()->ProcessEvent( le 
); 
2846 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2848     event
.SetEventObject( GetParent() ); 
2849     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2852     if ( !HasCurrent() || IsEmpty() ) 
2858     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
2859         event
.ButtonDClick()) ) 
2862     int x 
= event
.GetX(); 
2863     int y 
= event
.GetY(); 
2864     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2866     // where did we hit it (if we did)? 
2869     size_t count 
= GetItemCount(), 
2872     if ( HasFlag(wxLC_REPORT
) ) 
2874         current 
= y 
/ GetLineHeight(); 
2875         if ( current 
< count 
) 
2876             hitResult 
= HitTestLine(current
, x
, y
); 
2880         // TODO: optimize it too! this is less simple than for report view but 
2881         //       enumerating all items is still not a way to do it!! 
2882         for ( current 
= 0; current 
< count
; current
++ ) 
2884             hitResult 
= HitTestLine(current
, x
, y
); 
2890     if (event
.Dragging()) 
2892         if (m_dragCount 
== 0) 
2894             // we have to report the raw, physical coords as we want to be 
2895             // able to call HitTest(event.m_pointDrag) from the user code to 
2896             // get the item being dragged 
2897             m_dragStart 
= event
.GetPosition(); 
2902         if (m_dragCount 
!= 3) 
2905         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
2906                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2908         wxListEvent 
le( command
, GetParent()->GetId() ); 
2909         le
.SetEventObject( GetParent() ); 
2910         le
.m_itemIndex 
= current
; 
2911         le
.m_pointDrag 
= m_dragStart
; 
2912         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2923         // outside of any item 
2927     bool forceClick 
= FALSE
; 
2928     if (event
.ButtonDClick()) 
2930         m_renameTimer
->Stop(); 
2931         m_lastOnSame 
= FALSE
; 
2933         if ( current 
== m_lineLastClicked 
) 
2935             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2941             // the first click was on another item, so don't interpret this as 
2942             // a double click, but as a simple click instead 
2947     if (event
.LeftUp() && m_lastOnSame
) 
2949         if ((current 
== m_current
) && 
2950             (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
2951             HasFlag(wxLC_EDIT_LABELS
)  ) 
2953             m_renameTimer
->Start( 100, TRUE 
); 
2955         m_lastOnSame 
= FALSE
; 
2957     else if (event
.RightDown()) 
2959         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, 
2960                     event
.GetPosition() ); 
2962     else if (event
.MiddleDown()) 
2964         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
2966     else if ( event
.LeftDown() || forceClick 
) 
2968         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2969         m_lineLastClicked 
= current
; 
2971         size_t oldCurrent 
= m_current
; 
2973         if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) ) 
2975             HighlightAll( FALSE 
); 
2977             ChangeCurrent(current
); 
2979             ReverseHighlight(m_current
); 
2981         else // multi sel & either ctrl or shift is down 
2983             if (event
.ControlDown()) 
2985                 ChangeCurrent(current
); 
2987                 ReverseHighlight(m_current
); 
2989             else if (event
.ShiftDown()) 
2991                 ChangeCurrent(current
); 
2993                 size_t lineFrom 
= oldCurrent
, 
2996                 if ( lineTo 
< lineFrom 
) 
2999                     lineFrom 
= m_current
; 
3002                 HighlightLines(lineFrom
, lineTo
); 
3004             else // !ctrl, !shift 
3006                 // test in the enclosing if should make it impossible 
3007                 wxFAIL_MSG( _T("how did we get here?") ); 
3011         if (m_current 
!= oldCurrent
) 
3013             RefreshLine( oldCurrent 
); 
3016         // forceClick is only set if the previous click was on another item 
3017         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
); 
3021 void wxListMainWindow::MoveToItem(size_t item
) 
3023     if ( item 
== (size_t)-1 ) 
3026     wxRect rect 
= GetLineRect(item
); 
3028     int client_w
, client_h
; 
3029     GetClientSize( &client_w
, &client_h 
); 
3031     const int hLine 
= GetLineHeight(); 
3033     int view_x 
= SCROLL_UNIT_X
*GetScrollPos( wxHORIZONTAL 
); 
3034     int view_y 
= hLine
*GetScrollPos( wxVERTICAL 
); 
3036     if ( HasFlag(wxLC_REPORT
) ) 
3038         // the next we need the range of lines shown it might be different, so 
3040         ResetVisibleLinesRange(); 
3042         if (rect
.y 
< view_y 
) 
3043             Scroll( -1, rect
.y
/hLine 
); 
3044         if (rect
.y
+rect
.height
+5 > view_y
+client_h
) 
3045             Scroll( -1, (rect
.y
+rect
.height
-client_h
+hLine
)/hLine 
); 
3049         if (rect
.x
-view_x 
< 5) 
3050             Scroll( (rect
.x
-5)/SCROLL_UNIT_X
, -1 ); 
3051         if (rect
.x
+rect
.width
-5 > view_x
+client_w
) 
3052             Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/SCROLL_UNIT_X
, -1 ); 
3056 // ---------------------------------------------------------------------------- 
3057 // keyboard handling 
3058 // ---------------------------------------------------------------------------- 
3060 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
3062     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
3063                  _T("invalid item index in OnArrowChar()") ); 
3065     size_t oldCurrent 
= m_current
; 
3067     // in single selection we just ignore Shift as we can't select several 
3069     if ( event
.ShiftDown() && !IsSingleSel() ) 
3071         ChangeCurrent(newCurrent
); 
3073         // select all the items between the old and the new one 
3074         if ( oldCurrent 
> newCurrent 
) 
3076             newCurrent 
= oldCurrent
; 
3077             oldCurrent 
= m_current
; 
3080         HighlightLines(oldCurrent
, newCurrent
); 
3084         // all previously selected items are unselected unless ctrl is held 
3085         if ( !event
.ControlDown() ) 
3086             HighlightAll(FALSE
); 
3088         ChangeCurrent(newCurrent
); 
3090         // refresh the old focus to remove it 
3091         RefreshLine( oldCurrent 
); 
3093         if ( !event
.ControlDown() ) 
3095             HighlightLine( m_current
, TRUE 
); 
3099     RefreshLine( m_current 
); 
3104 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
3106     wxWindow 
*parent 
= GetParent(); 
3108     /* we propagate the key event up */ 
3109     wxKeyEvent 
ke( wxEVT_KEY_DOWN 
); 
3110     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3111     ke
.m_controlDown 
= event
.m_controlDown
; 
3112     ke
.m_altDown 
= event
.m_altDown
; 
3113     ke
.m_metaDown 
= event
.m_metaDown
; 
3114     ke
.m_keyCode 
= event
.m_keyCode
; 
3117     ke
.SetEventObject( parent 
); 
3118     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3123 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
3125     wxWindow 
*parent 
= GetParent(); 
3127     /* we send a list_key event up */ 
3130         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
3131         le
.m_itemIndex 
= m_current
; 
3132         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3133         le
.m_code 
= event
.GetKeyCode(); 
3134         le
.SetEventObject( parent 
); 
3135         parent
->GetEventHandler()->ProcessEvent( le 
); 
3138     /* we propagate the char event up */ 
3139     wxKeyEvent 
ke( wxEVT_CHAR 
); 
3140     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3141     ke
.m_controlDown 
= event
.m_controlDown
; 
3142     ke
.m_altDown 
= event
.m_altDown
; 
3143     ke
.m_metaDown 
= event
.m_metaDown
; 
3144     ke
.m_keyCode 
= event
.m_keyCode
; 
3147     ke
.SetEventObject( parent 
); 
3148     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3150     if (event
.GetKeyCode() == WXK_TAB
) 
3152         wxNavigationKeyEvent nevent
; 
3153         nevent
.SetWindowChange( event
.ControlDown() ); 
3154         nevent
.SetDirection( !event
.ShiftDown() ); 
3155         nevent
.SetEventObject( GetParent()->GetParent() ); 
3156         nevent
.SetCurrentFocus( m_parent 
); 
3157         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent 
)) 
3161     /* no item -> nothing to do */ 
3168     switch (event
.GetKeyCode()) 
3171             if ( m_current 
> 0 ) 
3172                 OnArrowChar( m_current 
- 1, event 
); 
3176             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
3177                 OnArrowChar( m_current 
+ 1, event 
); 
3182                 OnArrowChar( GetItemCount() - 1, event 
); 
3187                 OnArrowChar( 0, event 
); 
3192                 int steps 
= HasFlag(wxLC_REPORT
) ? m_linesPerPage 
- 1 : m_current 
% m_linesPerPage
; 
3194                 int index 
= m_current 
- steps
; 
3198                 OnArrowChar( index
, event 
); 
3204                 int steps 
= HasFlag(wxLC_REPORT
) 
3205                                ? m_linesPerPage 
- 1 
3206                                : m_linesPerPage 
- (m_current 
% m_linesPerPage
) - 1; 
3208                 size_t index 
= m_current 
+ steps
; 
3209                 size_t count 
= GetItemCount(); 
3210                 if ( index 
>= count 
) 
3213                 OnArrowChar( index
, event 
); 
3218             if ( !HasFlag(wxLC_REPORT
) ) 
3220                 int index 
= m_current 
- m_linesPerPage
; 
3224                 OnArrowChar( index
, event 
); 
3229             if ( !HasFlag(wxLC_REPORT
) ) 
3231                 size_t index 
= m_current 
+ m_linesPerPage
; 
3233                 size_t count 
= GetItemCount(); 
3234                 if ( index 
>= count 
) 
3237                 OnArrowChar( index
, event 
); 
3242             if ( IsSingleSel() ) 
3244                 SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3246                 if ( IsHighlighted(m_current
) ) 
3248                     // don't unselect the item in single selection mode 
3251                 //else: select it in ReverseHighlight() below if unselected 
3254             ReverseHighlight(m_current
); 
3259             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3267 // ---------------------------------------------------------------------------- 
3269 // ---------------------------------------------------------------------------- 
3271 void wxListMainWindow::SetFocus() 
3273     // VS: wxListMainWindow derives from wxPanel (via wxScrolledWindow) and wxPanel 
3274     //     overrides SetFocus in such way that it does never change focus from 
3275     //     panel's child to the panel itself. Unfortunately, we must be able to change 
3276     //     focus to the panel from wxListTextCtrl because the text control should 
3277     //     disappear when the user clicks outside it. 
3279     wxWindow 
*oldFocus 
= FindFocus(); 
3281     if ( oldFocus 
&& oldFocus
->GetParent() == this ) 
3283         wxWindow::SetFocus(); 
3287         wxScrolledWindow::SetFocus(); 
3291 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3295         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3296         event
.SetEventObject( GetParent() ); 
3297         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3301     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
3302     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
3303     // which are already drawn correctly resulting in horrible flicker - avoid 
3313 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3317         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
3318         event
.SetEventObject( GetParent() ); 
3319         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3326 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3328     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3330         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3332     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3334         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3336     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3338         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3340     else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
)) 
3342         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3346 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3348     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3350         m_normal_image_list
->GetSize( index
, width
, height 
); 
3352     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3354         m_small_image_list
->GetSize( index
, width
, height 
); 
3356     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3358         m_small_image_list
->GetSize( index
, width
, height 
); 
3360     else if ( HasFlag(wxLC_REPORT
) && m_small_image_list 
) 
3362         m_small_image_list
->GetSize( index
, width
, height 
); 
3371 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3373     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3374     dc
.SetFont( GetFont() ); 
3377     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3379     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3382 void wxListMainWindow::SetImageList( wxImageListType 
*imageList
, int which 
) 
3386     // calc the spacing from the icon size 
3389     if ((imageList
) && (imageList
->GetImageCount()) ) 
3391         imageList
->GetSize(0, width
, height
); 
3394     if (which 
== wxIMAGE_LIST_NORMAL
) 
3396         m_normal_image_list 
= imageList
; 
3397         m_normal_spacing 
= width 
+ 8; 
3400     if (which 
== wxIMAGE_LIST_SMALL
) 
3402         m_small_image_list 
= imageList
; 
3403         m_small_spacing 
= width 
+ 14; 
3404         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
3408 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3413         m_small_spacing 
= spacing
; 
3417         m_normal_spacing 
= spacing
; 
3421 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3423     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3426 // ---------------------------------------------------------------------------- 
3428 // ---------------------------------------------------------------------------- 
3430 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3432     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3434     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3436     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3437         item
.m_width 
= GetTextLength( item
.m_text 
); 
3439     wxListHeaderData 
*column 
= node
->GetData(); 
3440     column
->SetItem( item 
); 
3442     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3444         headerWin
->m_dirty 
= TRUE
; 
3448     // invalidate it as it has to be recalculated 
3452 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3454     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3455                  _T("invalid column index") ); 
3457     wxCHECK_RET( HasFlag(wxLC_REPORT
), 
3458                  _T("SetColumnWidth() can only be called in report mode.") ); 
3461     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3463         headerWin
->m_dirty 
= TRUE
; 
3465     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3466     wxCHECK_RET( node
, _T("no column?") ); 
3468     wxListHeaderData 
*column 
= node
->GetData(); 
3470     size_t count 
= GetItemCount(); 
3472     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3474         width 
= GetTextLength(column
->GetText()); 
3476     else if ( width 
== wxLIST_AUTOSIZE 
) 
3480             // TODO: determine the max width somehow... 
3481             width 
= WIDTH_COL_DEFAULT
; 
3485             wxClientDC 
dc(this); 
3486             dc
.SetFont( GetFont() ); 
3488             int max 
= AUTOSIZE_COL_MARGIN
; 
3490             for ( size_t i 
= 0; i 
< count
; i
++ ) 
3492                 wxListLineData 
*line 
= GetLine(i
); 
3493                 wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3495                 wxCHECK_RET( n
, _T("no subitem?") ); 
3497                 wxListItemData 
*item 
= n
->GetData(); 
3500                 if (item
->HasImage()) 
3503                     GetImageSize( item
->GetImage(), ix
, iy 
); 
3507                 if (item
->HasText()) 
3510                     dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
3518             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3522     column
->SetWidth( width 
); 
3524     // invalidate it as it has to be recalculated 
3528 int wxListMainWindow::GetHeaderWidth() const 
3530     if ( !m_headerWidth 
) 
3532         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3534         size_t count 
= GetColumnCount(); 
3535         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3537             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3541     return m_headerWidth
; 
3544 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3546     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3547     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3549     wxListHeaderData 
*column 
= node
->GetData(); 
3550     column
->GetItem( item 
); 
3553 int wxListMainWindow::GetColumnWidth( int col 
) const 
3555     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3556     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3558     wxListHeaderData 
*column 
= node
->GetData(); 
3559     return column
->GetWidth(); 
3562 // ---------------------------------------------------------------------------- 
3564 // ---------------------------------------------------------------------------- 
3566 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3568     long id 
= item
.m_itemId
; 
3569     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3570                  _T("invalid item index in SetItem") ); 
3574         wxListLineData 
*line 
= GetLine((size_t)id
); 
3575         line
->SetItem( item
.m_col
, item 
); 
3578     // update the item on screen 
3580     GetItemRect(id
, rectItem
); 
3581     RefreshRect(rectItem
); 
3584 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3586      wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3587                   _T("invalid list ctrl item index in SetItem") ); 
3589     size_t oldCurrent 
= m_current
; 
3590     size_t item 
= (size_t)litem
;    // safe because of the check above 
3592     // do we need to change the focus? 
3593     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3595         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3597             // don't do anything if this item is already focused 
3598             if ( item 
!= m_current 
) 
3600                 ChangeCurrent(item
); 
3602                 if ( oldCurrent 
!= (size_t)-1 ) 
3604                     if ( IsSingleSel() ) 
3606                         HighlightLine(oldCurrent
, FALSE
); 
3609                     RefreshLine(oldCurrent
); 
3612                 RefreshLine( m_current 
); 
3617             // don't do anything if this item is not focused 
3618             if ( item 
== m_current 
) 
3622                 if ( IsSingleSel() ) 
3624                     // we must unselect the old current item as well or we 
3625                     // might end up with more than one selected item in a 
3626                     // single selection control 
3627                     HighlightLine(oldCurrent
, FALSE
); 
3630                 RefreshLine( oldCurrent 
); 
3635     // do we need to change the selection state? 
3636     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3638         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3640         if ( IsSingleSel() ) 
3644                 // selecting the item also makes it the focused one in the 
3646                 if ( m_current 
!= item 
) 
3648                     ChangeCurrent(item
); 
3650                     if ( oldCurrent 
!= (size_t)-1 ) 
3652                         HighlightLine( oldCurrent
, FALSE 
); 
3653                         RefreshLine( oldCurrent 
); 
3659                 // only the current item may be selected anyhow 
3660                 if ( item 
!= m_current 
) 
3665         if ( HighlightLine(item
, on
) ) 
3672 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
3674     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3675                  _T("invalid list ctrl item index in GetItemState()") ); 
3677     int ret 
= wxLIST_STATE_DONTCARE
; 
3679     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3681         if ( (size_t)item 
== m_current 
) 
3682             ret 
|= wxLIST_STATE_FOCUSED
; 
3685     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3687         if ( IsHighlighted(item
) ) 
3688             ret 
|= wxLIST_STATE_SELECTED
; 
3694 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
3696     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3697                  _T("invalid item index in GetItem") ); 
3699     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3700     line
->GetItem( item
.m_col
, item 
); 
3703 // ---------------------------------------------------------------------------- 
3705 // ---------------------------------------------------------------------------- 
3707 size_t wxListMainWindow::GetItemCount() const 
3709     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3712 void wxListMainWindow::SetItemCount(long count
) 
3714     m_selStore
.SetItemCount(count
); 
3715     m_countVirt 
= count
; 
3717     ResetVisibleLinesRange(); 
3719     // scrollbars must be reset 
3723 int wxListMainWindow::GetSelectedItemCount() const 
3725     // deal with the quick case first 
3726     if ( IsSingleSel() ) 
3728         return HasCurrent() ? IsHighlighted(m_current
) : FALSE
; 
3731     // virtual controls remmebers all its selections itself 
3733         return m_selStore
.GetSelectedCount(); 
3735     // TODO: we probably should maintain the number of items selected even for 
3736     //       non virtual controls as enumerating all lines is really slow... 
3737     size_t countSel 
= 0; 
3738     size_t count 
= GetItemCount(); 
3739     for ( size_t line 
= 0; line 
< count
; line
++ ) 
3741         if ( GetLine(line
)->IsHighlighted() ) 
3748 // ---------------------------------------------------------------------------- 
3749 // item position/size 
3750 // ---------------------------------------------------------------------------- 
3752 wxRect 
wxListMainWindow::GetViewRect() const 
3754     wxASSERT_MSG( !HasFlag(wxLC_REPORT 
| wxLC_LIST
), 
3755                     _T("wxListCtrl::GetViewRect() only works in icon mode") ); 
3757     // we need to find the longest/tallest label 
3760     const int count 
= GetItemCount(); 
3763         for ( int i 
= 0; i 
< count
; i
++ ) 
3768             wxCoord x 
= r
.GetRight(), 
3778     // some fudge needed to make it look prettier 
3779     xMax 
+= 2*EXTRA_BORDER_X
; 
3780     yMax 
+= 2*EXTRA_BORDER_Y
; 
3782     // account for the scrollbars if necessary 
3783     const wxSize sizeAll 
= GetClientSize(); 
3784     if ( xMax 
> sizeAll
.x 
) 
3785         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
3786     if ( yMax 
> sizeAll
.y 
) 
3787         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
3789     return wxRect(0, 0, xMax
, yMax
); 
3792 void wxListMainWindow::GetItemRect( long index
, wxRect 
&rect 
) const 
3794     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3795                  _T("invalid index in GetItemRect") ); 
3797     // ensure that we're laid out, otherwise we could return nonsense 
3800         wxConstCast(this, wxListMainWindow
)-> 
3801             RecalculatePositions(TRUE 
/* no refresh */); 
3804     rect 
= GetLineRect((size_t)index
); 
3806     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
3809 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
3812     GetItemRect(item
, rect
); 
3820 // ---------------------------------------------------------------------------- 
3821 // geometry calculation 
3822 // ---------------------------------------------------------------------------- 
3824 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
3826     wxClientDC 
dc( this ); 
3827     dc
.SetFont( GetFont() ); 
3829     const size_t count 
= GetItemCount(); 
3832     if ( HasFlag(wxLC_ICON
) ) 
3833         iconSpacing 
= m_normal_spacing
; 
3834     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
3835         iconSpacing 
= m_small_spacing
; 
3839     // Note that we do not call GetClientSize() here but 
3840     // GetSize() and substract the border size for sunken 
3841     // borders manually. This is technically incorrect, 
3842     // but we need to know the client area's size WITHOUT 
3843     // scrollbars here. Since we don't know if there are 
3844     // any scrollbars, we use GetSize() instead. Another 
3845     // solution would be to call SetScrollbars() here to 
3846     // remove the scrollbars and call GetClientSize() then, 
3847     // but this might result in flicker and - worse - will 
3848     // reset the scrollbars to 0 which is not good at all 
3849     // if you resize a dialog/window, but don't want to 
3850     // reset the window scrolling. RR. 
3851     // Furthermore, we actually do NOT subtract the border 
3852     // width as 2 pixels is just the extra space which we 
3853     // need around the actual content in the window. Other- 
3854     // wise the text would e.g. touch the upper border. RR. 
3857     GetSize( &clientWidth
, &clientHeight 
); 
3859     const int lineHeight 
= GetLineHeight(); 
3861     if ( HasFlag(wxLC_REPORT
) ) 
3863         // all lines have the same height and we scroll one line per step 
3864         int entireHeight 
= count
*lineHeight 
+ LINE_SPACING
; 
3866         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
3868         ResetVisibleLinesRange(); 
3870         SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
3871                        GetHeaderWidth() / SCROLL_UNIT_X
, 
3872                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
3873                        GetScrollPos(wxHORIZONTAL
), 
3874                        GetScrollPos(wxVERTICAL
), 
3879         // we have 3 different layout strategies: either layout all items 
3880         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
3881         // to arrange them in top to bottom, left to right (don't ask me why 
3882         // not the other way round...) order 
3883         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
3885             int x 
= EXTRA_BORDER_X
; 
3886             int y 
= EXTRA_BORDER_Y
; 
3888             wxCoord widthMax 
= 0; 
3891             for ( i 
= 0; i 
< count
; i
++ ) 
3893                 wxListLineData 
*line 
= GetLine(i
); 
3894                 line
->CalculateSize( &dc
, iconSpacing 
); 
3895                 line
->SetPosition( x
, y
, iconSpacing 
); 
3897                 wxSize sizeLine 
= GetLineSize(i
); 
3899                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3901                     if ( sizeLine
.x 
> widthMax 
) 
3902                         widthMax 
= sizeLine
.x
; 
3906                 else // wxLC_ALIGN_LEFT 
3908                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
3912             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3914                 // traverse the items again and tweak their sizes so that they are 
3915                 // all the same in a row 
3916                 for ( i 
= 0; i 
< count
; i
++ ) 
3918                     wxListLineData 
*line 
= GetLine(i
); 
3919                     line
->m_gi
->ExtendWidth(widthMax
); 
3928                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3929                 (y 
+ lineHeight
) / lineHeight
, 
3930                 GetScrollPos( wxHORIZONTAL 
), 
3931                 GetScrollPos( wxVERTICAL 
), 
3935         else // "flowed" arrangement, the most complicated case 
3937             // at first we try without any scrollbars, if the items don't fit into 
3938             // the window, we recalculate after subtracting the space taken by the 
3941             int entireWidth 
= 0; 
3943             for (int tries 
= 0; tries 
< 2; tries
++) 
3945                 entireWidth 
= 2*EXTRA_BORDER_X
; 
3949                     // Now we have decided that the items do not fit into the 
3950                     // client area, so we need a scrollbar 
3951                     entireWidth 
+= SCROLL_UNIT_X
; 
3954                 int x 
= EXTRA_BORDER_X
; 
3955                 int y 
= EXTRA_BORDER_Y
; 
3956                 int maxWidthInThisRow 
= 0; 
3959                 int currentlyVisibleLines 
= 0; 
3961                 for (size_t i 
= 0; i 
< count
; i
++) 
3963                     currentlyVisibleLines
++; 
3964                     wxListLineData 
*line 
= GetLine(i
); 
3965                     line
->CalculateSize( &dc
, iconSpacing 
); 
3966                     line
->SetPosition( x
, y
, iconSpacing 
); 
3968                     wxSize sizeLine 
= GetLineSize(i
); 
3970                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
3971                         maxWidthInThisRow 
= sizeLine
.x
; 
3974                     if (currentlyVisibleLines 
> m_linesPerPage
) 
3975                         m_linesPerPage 
= currentlyVisibleLines
; 
3977                     if ( y 
+ sizeLine
.y 
>= clientHeight 
) 
3979                         currentlyVisibleLines 
= 0; 
3981                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
3982                         x 
+= maxWidthInThisRow
; 
3983                         entireWidth 
+= maxWidthInThisRow
; 
3984                         maxWidthInThisRow 
= 0; 
3987                     // We have reached the last item. 
3988                     if ( i 
== count 
- 1 ) 
3989                         entireWidth 
+= maxWidthInThisRow
; 
3991                     if ( (tries 
== 0) && 
3992                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
3994                         clientHeight 
-= wxSystemSettings:: 
3995                                             GetMetric(wxSYS_HSCROLL_Y
); 
4000                     if ( i 
== count 
- 1 ) 
4001                         tries 
= 1;  // Everything fits, no second try required. 
4009                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4011                 GetScrollPos( wxHORIZONTAL 
), 
4020         // FIXME: why should we call it from here? 
4027 void wxListMainWindow::RefreshAll() 
4032     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
4033     if ( headerWin 
&& headerWin
->m_dirty 
) 
4035         headerWin
->m_dirty 
= FALSE
; 
4036         headerWin
->Refresh(); 
4040 void wxListMainWindow::UpdateCurrent() 
4042     if ( !HasCurrent() && !IsEmpty() ) 
4048 long wxListMainWindow::GetNextItem( long item
, 
4049                                     int WXUNUSED(geometry
), 
4053          max 
= GetItemCount(); 
4054     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
4055                  _T("invalid listctrl index in GetNextItem()") ); 
4057     // notice that we start with the next item (or the first one if item == -1) 
4058     // and this is intentional to allow writing a simple loop to iterate over 
4059     // all selected items 
4063         // this is not an error because the index was ok initially, just no 
4074     size_t count 
= GetItemCount(); 
4075     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
4077         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
4080         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
4087 // ---------------------------------------------------------------------------- 
4089 // ---------------------------------------------------------------------------- 
4091 void wxListMainWindow::DeleteItem( long lindex 
) 
4093     size_t count 
= GetItemCount(); 
4095     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
4096                  _T("invalid item index in DeleteItem") ); 
4098     size_t index 
= (size_t)lindex
; 
4100     // we don't need to adjust the index for the previous items 
4101     if ( HasCurrent() && m_current 
>= index 
) 
4103         // if the current item is being deleted, we want the next one to 
4104         // become selected - unless there is no next one - so don't adjust 
4105         // m_current in this case 
4106         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
4112     if ( InReportView() ) 
4114         ResetVisibleLinesRange(); 
4121         m_selStore
.OnItemDelete(index
); 
4125         m_lines
.RemoveAt( index 
); 
4128     // we need to refresh the (vert) scrollbar as the number of items changed 
4131     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM 
); 
4133     RefreshAfter(index
); 
4136 void wxListMainWindow::DeleteColumn( int col 
) 
4138     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4140     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
4143     delete node
->GetData(); 
4144     m_columns
.Erase( node 
); 
4148         // update all the items 
4149         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4151             wxListLineData 
* const line 
= GetLine(i
); 
4152             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
4153             delete n
->GetData(); 
4154             line
->m_items
.Erase(n
); 
4158     // invalidate it as it has to be recalculated 
4162 void wxListMainWindow::DoDeleteAllItems() 
4166         // nothing to do - in particular, don't send the event 
4172     // to make the deletion of all items faster, we don't send the 
4173     // notifications for each item deletion in this case but only one event 
4174     // for all of them: this is compatible with wxMSW and documented in 
4175     // DeleteAllItems() description 
4177     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
4178     event
.SetEventObject( GetParent() ); 
4179     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
4188     if ( InReportView() ) 
4190         ResetVisibleLinesRange(); 
4196 void wxListMainWindow::DeleteAllItems() 
4200     RecalculatePositions(); 
4203 void wxListMainWindow::DeleteEverything() 
4205     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
4210 // ---------------------------------------------------------------------------- 
4211 // scanning for an item 
4212 // ---------------------------------------------------------------------------- 
4214 void wxListMainWindow::EnsureVisible( long index 
) 
4216     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4217                  _T("invalid index in EnsureVisible") ); 
4219     // We have to call this here because the label in question might just have 
4220     // been added and its position is not known yet 
4223         RecalculatePositions(TRUE 
/* no refresh */); 
4226     MoveToItem((size_t)index
); 
4229 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) ) 
4236     size_t count 
= GetItemCount(); 
4237     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
4239         wxListLineData 
*line 
= GetLine(i
); 
4240         if ( line
->GetText(0) == tmp 
) 
4247 long wxListMainWindow::FindItem(long start
, long data
) 
4253     size_t count 
= GetItemCount(); 
4254     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4256         wxListLineData 
*line 
= GetLine(i
); 
4258         line
->GetItem( 0, item 
); 
4259         if (item
.m_data 
== data
) 
4266 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) 
4268     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4270     size_t count 
= GetItemCount(); 
4272     if ( HasFlag(wxLC_REPORT
) ) 
4274         size_t current 
= y 
/ GetLineHeight(); 
4275         if ( current 
< count 
) 
4277             flags 
= HitTestLine(current
, x
, y
); 
4284         // TODO: optimize it too! this is less simple than for report view but 
4285         //       enumerating all items is still not a way to do it!! 
4286         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4288             flags 
= HitTestLine(current
, x
, y
); 
4297 // ---------------------------------------------------------------------------- 
4299 // ---------------------------------------------------------------------------- 
4301 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4303     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
4305     size_t count 
= GetItemCount(); 
4306     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
<= count
, 
4307                  _T("invalid item index") ); 
4309     size_t id 
= item
.m_itemId
; 
4314     // this is unused variable 
4317     if ( HasFlag(wxLC_REPORT
) ) 
4320         // this is unused variable 
4323         ResetVisibleLinesRange(); 
4325     else if ( HasFlag(wxLC_LIST
) ) 
4327         // this is unused variable 
4332     else if ( HasFlag(wxLC_ICON
) ) 
4334         // this is unused variable 
4339     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
4341         // this is unused variable 
4342         mode 
= wxLC_ICON
;  // no typo 
4348         wxFAIL_MSG( _T("unknown mode") ); 
4351     wxListLineData 
*line 
= new wxListLineData(this); 
4353     line
->SetItem( 0, item 
); 
4355     m_lines
.Insert( line
, id 
); 
4359     // If an item is selected at or below the point of insertion, we need to 
4360     // increment the member variables because the current row's index has gone 
4362     if ( HasCurrent() && m_current 
>= id 
) 
4367     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4369     RefreshLines(id
, GetItemCount() - 1); 
4372 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4375     if ( HasFlag(wxLC_REPORT
) ) 
4377         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4378             item
.m_width 
= GetTextLength( item
.m_text 
); 
4380         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4381         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4384             wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4385             m_columns
.Insert( node
, column 
); 
4389             m_columns
.Append( column 
); 
4394             // update all the items 
4395             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4397                 wxListLineData 
* const line 
= GetLine(i
); 
4398                 wxListItemData 
* const data 
= new wxListItemData(this); 
4400                     line
->m_items
.Insert(col
, data
); 
4402                     line
->m_items
.Append(data
); 
4406         // invalidate it as it has to be recalculated 
4411 // ---------------------------------------------------------------------------- 
4413 // ---------------------------------------------------------------------------- 
4415 wxListCtrlCompare list_ctrl_compare_func_2
; 
4416 long              list_ctrl_compare_data
; 
4418 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4420     wxListLineData 
*line1 
= *arg1
; 
4421     wxListLineData 
*line2 
= *arg2
; 
4423     line1
->GetItem( 0, item 
); 
4424     long data1 
= item
.m_data
; 
4425     line2
->GetItem( 0, item 
); 
4426     long data2 
= item
.m_data
; 
4427     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4430 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
4432     list_ctrl_compare_func_2 
= fn
; 
4433     list_ctrl_compare_data 
= data
; 
4434     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4438 // ---------------------------------------------------------------------------- 
4440 // ---------------------------------------------------------------------------- 
4442 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4444     // update our idea of which lines are shown when we redraw the window the 
4446     ResetVisibleLinesRange(); 
4449 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
4450     wxScrolledWindow::OnScroll(event
); 
4452     HandleOnScroll( event 
); 
4455     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4457         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4458         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4460         lc
->m_headerWin
->Refresh(); 
4461         lc
->m_headerWin
->Update(); 
4465 int wxListMainWindow::GetCountPerPage() const 
4467     if ( !m_linesPerPage 
) 
4469         wxConstCast(this, wxListMainWindow
)-> 
4470             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4473     return m_linesPerPage
; 
4476 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4478     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") ); 
4480     if ( m_lineFrom 
== (size_t)-1 ) 
4482         size_t count 
= GetItemCount(); 
4485             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4487             // this may happen if SetScrollbars() hadn't been called yet 
4488             if ( m_lineFrom 
>= count 
) 
4489                 m_lineFrom 
= count 
- 1; 
4491             // we redraw one extra line but this is needed to make the redrawing 
4492             // logic work when there is a fractional number of lines on screen 
4493             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4494             if ( m_lineTo 
>= count 
) 
4495                 m_lineTo 
= count 
- 1; 
4497         else // empty control 
4500             m_lineTo 
= (size_t)-1; 
4504     wxASSERT_MSG( IsEmpty() || 
4505                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4506                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4514 // ------------------------------------------------------------------------------------- 
4515 // wxGenericListCtrl 
4516 // ------------------------------------------------------------------------------------- 
4518 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4520 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4521   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4524 wxGenericListCtrl::wxGenericListCtrl() 
4526     m_imageListNormal 
= (wxImageListType 
*) NULL
; 
4527     m_imageListSmall 
= (wxImageListType 
*) NULL
; 
4528     m_imageListState 
= (wxImageListType 
*) NULL
; 
4530     m_ownsImageListNormal 
= 
4531     m_ownsImageListSmall 
= 
4532     m_ownsImageListState 
= FALSE
; 
4534     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4535     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4539 wxGenericListCtrl::~wxGenericListCtrl() 
4541     if (m_ownsImageListNormal
) 
4542         delete m_imageListNormal
; 
4543     if (m_ownsImageListSmall
) 
4544         delete m_imageListSmall
; 
4545     if (m_ownsImageListState
) 
4546         delete m_imageListState
; 
4549 void wxGenericListCtrl::CalculateAndSetHeaderHeight() 
4553         // we use 'g' to get the descent, too 
4555         m_headerWin
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
); 
4556         h 
+= d 
+ 2 * HEADER_OFFSET_Y 
+ EXTRA_HEIGHT
; 
4558         // only update if changed 
4559         if ( h 
!= m_headerHeight 
) 
4563             m_headerWin
->SetSize(m_headerWin
->GetSize().x
, m_headerHeight
); 
4565             if ( HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
) ) 
4566                 ResizeReportView(TRUE
); 
4571 void wxGenericListCtrl::CreateHeaderWindow() 
4573     m_headerWin 
= new wxListHeaderWindow
 
4575                         this, -1, m_mainWin
, 
4577                         wxSize(GetClientSize().x
, m_headerHeight
), 
4580     CalculateAndSetHeaderHeight(); 
4583 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
4588                         const wxValidator 
&validator
, 
4589                         const wxString 
&name
) 
4593     m_imageListState 
= (wxImageListType 
*) NULL
; 
4594     m_ownsImageListNormal 
= 
4595     m_ownsImageListSmall 
= 
4596     m_ownsImageListState 
= FALSE
; 
4598     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4599     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4603     if ( !(style 
& wxLC_MASK_TYPE
) ) 
4605         style 
= style 
| wxLC_LIST
; 
4608     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
4611     // don't create the inner window with the border 
4612     style 
&= ~wxBORDER_MASK
; 
4614     m_mainWin 
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style 
); 
4616     if ( HasFlag(wxLC_REPORT
) ) 
4618         CreateHeaderWindow(); 
4620         if ( HasFlag(wxLC_NO_HEADER
) ) 
4622             // VZ: why do we create it at all then? 
4623             m_headerWin
->Show( FALSE 
); 
4630 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
4632     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4633                   _T("wxLC_VIRTUAL can't be [un]set") ); 
4635     long flag 
= GetWindowStyle(); 
4639         if (style 
& wxLC_MASK_TYPE
) 
4640             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4641         if (style 
& wxLC_MASK_ALIGN
) 
4642             flag 
&= ~wxLC_MASK_ALIGN
; 
4643         if (style 
& wxLC_MASK_SORT
) 
4644             flag 
&= ~wxLC_MASK_SORT
; 
4656     SetWindowStyleFlag( flag 
); 
4659 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
4663         m_mainWin
->DeleteEverything(); 
4665         // has the header visibility changed? 
4666         bool hasHeader 
= HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
), 
4667              willHaveHeader 
= (flag 
& wxLC_REPORT
) && !(flag 
& wxLC_NO_HEADER
); 
4669         if ( hasHeader 
!= willHaveHeader 
) 
4676                     // don't delete, just hide, as we can reuse it later 
4677                     m_headerWin
->Show(FALSE
); 
4679                 //else: nothing to do 
4681             else // must show header 
4685                     CreateHeaderWindow(); 
4687                 else // already have it, just show 
4689                     m_headerWin
->Show( TRUE 
); 
4693             ResizeReportView(willHaveHeader
); 
4697     wxWindow::SetWindowStyleFlag( flag 
); 
4700 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4702     m_mainWin
->GetColumn( col
, item 
); 
4706 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
4708     m_mainWin
->SetColumn( col
, item 
); 
4712 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
4714     return m_mainWin
->GetColumnWidth( col 
); 
4717 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
4719     m_mainWin
->SetColumnWidth( col
, width 
); 
4723 int wxGenericListCtrl::GetCountPerPage() const 
4725   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4728 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
4730     m_mainWin
->GetItem( info 
); 
4734 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
4736     m_mainWin
->SetItem( info 
); 
4740 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4743     info
.m_text 
= label
; 
4744     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4745     info
.m_itemId 
= index
; 
4749         info
.m_image 
= imageId
; 
4750         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4752     m_mainWin
->SetItem(info
); 
4756 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
4758     return m_mainWin
->GetItemState( item
, stateMask 
); 
4761 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4763     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4767 bool wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4770     info
.m_image 
= image
; 
4771     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4772     info
.m_itemId 
= item
; 
4773     m_mainWin
->SetItem( info 
); 
4777 wxString 
wxGenericListCtrl::GetItemText( long item 
) const 
4779     return m_mainWin
->GetItemText(item
); 
4782 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
4784     m_mainWin
->SetItemText(item
, str
); 
4787 long wxGenericListCtrl::GetItemData( long item 
) const 
4790     info
.m_itemId 
= item
; 
4791     m_mainWin
->GetItem( info 
); 
4795 bool wxGenericListCtrl::SetItemData( long item
, long data 
) 
4798     info
.m_mask 
= wxLIST_MASK_DATA
; 
4799     info
.m_itemId 
= item
; 
4801     m_mainWin
->SetItem( info 
); 
4805 wxRect 
wxGenericListCtrl::GetViewRect() const 
4807     return m_mainWin
->GetViewRect(); 
4810 bool wxGenericListCtrl::GetItemRect( long item
, wxRect 
&rect
,  int WXUNUSED(code
) ) const 
4812     m_mainWin
->GetItemRect( item
, rect 
); 
4813     if ( m_mainWin
->HasHeader() ) 
4814         rect
.y 
+= m_headerHeight 
+ 1; 
4818 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4820     m_mainWin
->GetItemPosition( item
, pos 
); 
4824 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4829 int wxGenericListCtrl::GetItemCount() const 
4831     return m_mainWin
->GetItemCount(); 
4834 int wxGenericListCtrl::GetColumnCount() const 
4836     return m_mainWin
->GetColumnCount(); 
4839 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4841     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4844 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
4846     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
4848     return wxSize(spacing
, spacing
); 
4851 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
4853     return m_mainWin
->GetItemSpacing( isSmall 
); 
4856 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
4859     info
.m_itemId 
= item
; 
4860     info
.SetTextColour( col 
); 
4861     m_mainWin
->SetItem( info 
); 
4864 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
4867     info
.m_itemId 
= item
; 
4868     m_mainWin
->GetItem( info 
); 
4869     return info
.GetTextColour(); 
4872 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
4875     info
.m_itemId 
= item
; 
4876     info
.SetBackgroundColour( col 
); 
4877     m_mainWin
->SetItem( info 
); 
4880 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
4883     info
.m_itemId 
= item
; 
4884     m_mainWin
->GetItem( info 
); 
4885     return info
.GetBackgroundColour(); 
4888 int wxGenericListCtrl::GetSelectedItemCount() const 
4890     return m_mainWin
->GetSelectedItemCount(); 
4893 wxColour 
wxGenericListCtrl::GetTextColour() const 
4895     return GetForegroundColour(); 
4898 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
4900     SetForegroundColour(col
); 
4903 long wxGenericListCtrl::GetTopItem() const 
4906     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
4910 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
4912     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
4915 wxImageListType 
*wxGenericListCtrl::GetImageList(int which
) const 
4917     if (which 
== wxIMAGE_LIST_NORMAL
) 
4919         return m_imageListNormal
; 
4921     else if (which 
== wxIMAGE_LIST_SMALL
) 
4923         return m_imageListSmall
; 
4925     else if (which 
== wxIMAGE_LIST_STATE
) 
4927         return m_imageListState
; 
4929     return (wxImageListType 
*) NULL
; 
4932 void wxGenericListCtrl::SetImageList( wxImageListType 
*imageList
, int which 
) 
4934     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4936         if (m_ownsImageListNormal
) delete m_imageListNormal
; 
4937         m_imageListNormal 
= imageList
; 
4938         m_ownsImageListNormal 
= FALSE
; 
4940     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4942         if (m_ownsImageListSmall
) delete m_imageListSmall
; 
4943         m_imageListSmall 
= imageList
; 
4944         m_ownsImageListSmall 
= FALSE
; 
4946     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4948         if (m_ownsImageListState
) delete m_imageListState
; 
4949         m_imageListState 
= imageList
; 
4950         m_ownsImageListState 
= FALSE
; 
4953     m_mainWin
->SetImageList( imageList
, which 
); 
4956 void wxGenericListCtrl::AssignImageList(wxImageListType 
*imageList
, int which
) 
4958     SetImageList(imageList
, which
); 
4959     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4960         m_ownsImageListNormal 
= TRUE
; 
4961     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4962         m_ownsImageListSmall 
= TRUE
; 
4963     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4964         m_ownsImageListState 
= TRUE
; 
4967 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
4972 bool wxGenericListCtrl::DeleteItem( long item 
) 
4974     m_mainWin
->DeleteItem( item 
); 
4978 bool wxGenericListCtrl::DeleteAllItems() 
4980     m_mainWin
->DeleteAllItems(); 
4984 bool wxGenericListCtrl::DeleteAllColumns() 
4986     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
4987     for ( size_t n 
= 0; n 
< count
; n
++ ) 
4993 void wxGenericListCtrl::ClearAll() 
4995     m_mainWin
->DeleteEverything(); 
4998 bool wxGenericListCtrl::DeleteColumn( int col 
) 
5000     m_mainWin
->DeleteColumn( col 
); 
5002     // if we don't have the header any longer, we need to relayout the window 
5003     if ( !GetColumnCount() ) 
5005         ResizeReportView(FALSE 
/* no header */); 
5011 void wxGenericListCtrl::Edit( long item 
) 
5013     m_mainWin
->EditLabel( item 
); 
5016 bool wxGenericListCtrl::EnsureVisible( long item 
) 
5018     m_mainWin
->EnsureVisible( item 
); 
5022 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
,  bool partial 
) 
5024     return m_mainWin
->FindItem( start
, str
, partial 
); 
5027 long wxGenericListCtrl::FindItem( long start
, long data 
) 
5029     return m_mainWin
->FindItem( start
, data 
); 
5032 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
), 
5033                            int WXUNUSED(direction
)) 
5038 long wxGenericListCtrl::HitTest( const wxPoint 
&point
, int &flags 
) 
5040     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
5043 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
5045     m_mainWin
->InsertItem( info 
); 
5046     return info
.m_itemId
; 
5049 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
5052     info
.m_text 
= label
; 
5053     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5054     info
.m_itemId 
= index
; 
5055     return InsertItem( info 
); 
5058 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
5061     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5062     info
.m_image 
= imageIndex
; 
5063     info
.m_itemId 
= index
; 
5064     return InsertItem( info 
); 
5067 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
5070     info
.m_text 
= label
; 
5071     info
.m_image 
= imageIndex
; 
5072     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
5073     info
.m_itemId 
= index
; 
5074     return InsertItem( info 
); 
5077 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
5079     wxCHECK_MSG( m_headerWin
, -1, _T("can't add column in non report mode") ); 
5081     m_mainWin
->InsertColumn( col
, item 
); 
5083     // if we hadn't had header before and have it now we need to relayout the 
5085     if ( GetColumnCount() == 1 && m_mainWin
->HasHeader() ) 
5087         ResizeReportView(TRUE 
/* have header */); 
5090     m_headerWin
->Refresh(); 
5095 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
5096                                int format
, int width 
) 
5099     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
5100     item
.m_text 
= heading
; 
5103         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
5104         item
.m_width 
= width
; 
5106     item
.m_format 
= format
; 
5108     return InsertColumn( col
, item 
); 
5111 bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) ) 
5117 // fn is a function which takes 3 long arguments: item1, item2, data. 
5118 // item1 is the long data associated with a first item (NOT the index). 
5119 // item2 is the long data associated with a second item (NOT the index). 
5120 // data is the same value as passed to SortItems. 
5121 // The return value is a negative number if the first item should precede the second 
5122 // item, a positive number of the second item should precede the first, 
5123 // or zero if the two items are equivalent. 
5124 // data is arbitrary data to be passed to the sort function. 
5126 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
5128     m_mainWin
->SortItems( fn
, data 
); 
5132 // ---------------------------------------------------------------------------- 
5134 // ---------------------------------------------------------------------------- 
5136 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
5141     ResizeReportView(m_mainWin
->HasHeader()); 
5143     m_mainWin
->RecalculatePositions(); 
5146 void wxGenericListCtrl::ResizeReportView(bool showHeader
) 
5149     GetClientSize( &cw
, &ch 
); 
5153         m_headerWin
->SetSize( 0, 0, cw
, m_headerHeight 
); 
5154         m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, cw
, ch 
- m_headerHeight 
- 1 ); 
5156     else // no header window 
5158         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
5162 void wxGenericListCtrl::OnInternalIdle() 
5164     wxWindow::OnInternalIdle(); 
5166     // do it only if needed 
5167     if ( !m_mainWin
->m_dirty 
) 
5170     m_mainWin
->RecalculatePositions(); 
5173 // ---------------------------------------------------------------------------- 
5175 // ---------------------------------------------------------------------------- 
5177 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5181         m_mainWin
->SetBackgroundColour( colour 
); 
5182         m_mainWin
->m_dirty 
= TRUE
; 
5188 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5190     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5195         m_mainWin
->SetForegroundColour( colour 
); 
5196         m_mainWin
->m_dirty 
= TRUE
; 
5201         m_headerWin
->SetForegroundColour( colour 
); 
5207 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5209     if ( !wxWindow::SetFont( font 
) ) 
5214         m_mainWin
->SetFont( font 
); 
5215         m_mainWin
->m_dirty 
= TRUE
; 
5220         m_headerWin
->SetFont( font 
); 
5221         CalculateAndSetHeaderHeight(); 
5229 // ---------------------------------------------------------------------------- 
5230 // methods forwarded to m_mainWin 
5231 // ---------------------------------------------------------------------------- 
5233 #if wxUSE_DRAG_AND_DROP 
5235 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5237     m_mainWin
->SetDropTarget( dropTarget 
); 
5240 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5242     return m_mainWin
->GetDropTarget(); 
5245 #endif // wxUSE_DRAG_AND_DROP 
5247 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5249     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
; 
5252 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5254     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5257 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5259     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5262 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5265     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5268 #endif // wxUSE_MENUS 
5271 void wxGenericListCtrl::SetFocus() 
5273     /* The test in window.cpp fails as we are a composite 
5274        window, so it checks against "this", but not m_mainWin. */ 
5275     if ( FindFocus() != this ) 
5276         m_mainWin
->SetFocus(); 
5279 // ---------------------------------------------------------------------------- 
5280 // virtual list control support 
5281 // ---------------------------------------------------------------------------- 
5283 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5285     // this is a pure virtual function, in fact - which is not really pure 
5286     // because the controls which are not virtual don't need to implement it 
5287     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5289     return wxEmptyString
; 
5292 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5295     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemImage not supposed to be called") ); 
5301 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5303     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5304                   _T("invalid item index in OnGetItemAttr()") ); 
5306     // no attributes by default 
5310 void wxGenericListCtrl::SetItemCount(long count
) 
5312     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
5314     m_mainWin
->SetItemCount(count
); 
5317 void wxGenericListCtrl::RefreshItem(long item
) 
5319     m_mainWin
->RefreshLine(item
); 
5322 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5324     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5328  * Generic wxListCtrl is more or less a container for two other 
5329  * windows which drawings are done upon. These are namely 
5330  * 'm_headerWin' and 'm_mainWin'. 
5331  * Here we override 'virtual wxWindow::Refresh()' to mimic the 
5332  * behaviour wxListCtrl has under wxMSW. 
5334 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5338         // The easy case, no rectangle specified. 
5340             m_headerWin
->Refresh(eraseBackground
); 
5343             m_mainWin
->Refresh(eraseBackground
); 
5347         // Refresh the header window 
5350             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5351             rectHeader
.Intersect(*rect
); 
5352             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5355                 m_headerWin
->GetPosition(&x
, &y
); 
5356                 rectHeader
.Offset(-x
, -y
); 
5357                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5362         // Refresh the main window 
5365             wxRect rectMain 
= m_mainWin
->GetRect(); 
5366             rectMain
.Intersect(*rect
); 
5367             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5370                 m_mainWin
->GetPosition(&x
, &y
); 
5371                 rectMain
.Offset(-x
, -y
); 
5372                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5378 void wxGenericListCtrl::Freeze() 
5380     m_mainWin
->Freeze(); 
5383 void wxGenericListCtrl::Thaw() 
5388 #endif // wxUSE_LISTCTRL