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" 
  76     #include "wx/mac/private.h" 
  82 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
  83 // be removed, as well as the #else case below. 
  84 #define _USE_VISATTR 0 
  87 // ---------------------------------------------------------------------------- 
  89 // ---------------------------------------------------------------------------- 
  91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
) 
  92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
) 
  93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
) 
  94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
) 
  95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
) 
  96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
) 
  97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
) 
  98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
) 
  99 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
) 
 100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
) 
 101 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
) 
 102 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
) 
 103 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
) 
 104 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
) 
 105 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
) 
 106 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING
) 
 107 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG
) 
 108 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
) 
 109 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
) 
 110 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
) 
 111 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED
) 
 112 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
) 
 114 // ---------------------------------------------------------------------------- 
 116 // ---------------------------------------------------------------------------- 
 118 // // the height of the header window (FIXME: should depend on its font!) 
 119 // static const int HEADER_HEIGHT = 23; 
 121 static const int SCROLL_UNIT_X 
= 15; 
 123 // the spacing between the lines (in report mode) 
 124 static const int LINE_SPACING 
= 0; 
 126 // extra margins around the text label 
 127 static const int EXTRA_WIDTH 
= 4; 
 128 static const int EXTRA_HEIGHT 
= 4; 
 130 // margin between the window and the items 
 131 static const int EXTRA_BORDER_X 
= 2; 
 132 static const int EXTRA_BORDER_Y 
= 2; 
 134 // offset for the header window 
 135 static const int HEADER_OFFSET_X 
= 1; 
 136 static const int HEADER_OFFSET_Y 
= 1; 
 138 // margin between rows of icons in [small] icon view 
 139 static const int MARGIN_BETWEEN_ROWS 
= 6; 
 141 // when autosizing the columns, add some slack 
 142 static const int AUTOSIZE_COL_MARGIN 
= 10; 
 144 // default and minimal widths for the header columns 
 145 static const int WIDTH_COL_DEFAULT 
= 80; 
 146 static const int WIDTH_COL_MIN 
= 10; 
 148 // the space between the image and the text in the report mode 
 149 static const int IMAGE_MARGIN_IN_REPORT_MODE 
= 5; 
 151 // ============================================================================ 
 153 // ============================================================================ 
 155 //----------------------------------------------------------------------------- 
 156 //  wxListItemData (internal) 
 157 //----------------------------------------------------------------------------- 
 159 class WXDLLEXPORT wxListItemData
 
 162     wxListItemData(wxListMainWindow 
*owner
); 
 165     void SetItem( const wxListItem 
&info 
); 
 166     void SetImage( int image 
) { m_image 
= image
; } 
 167     void SetData( wxUIntPtr data 
) { m_data 
= data
; } 
 168     void SetPosition( int x
, int y 
); 
 169     void SetSize( int width
, int height 
); 
 171     bool HasText() const { return !m_text
.empty(); } 
 172     const wxString
& GetText() const { return m_text
; } 
 173     void SetText(const wxString
& text
) { m_text 
= text
; } 
 175     // we can't use empty string for measuring the string width/height, so 
 176     // always return something 
 177     wxString 
GetTextForMeasuring() const 
 179         wxString s 
= GetText(); 
 186     bool IsHit( int x
, int y 
) const; 
 190     int GetWidth() const; 
 191     int GetHeight() const; 
 193     int GetImage() const { return m_image
; } 
 194     bool HasImage() const { return GetImage() != -1; } 
 196     void GetItem( wxListItem 
&info 
) const; 
 198     void SetAttr(wxListItemAttr 
*attr
) { m_attr 
= attr
; } 
 199     wxListItemAttr 
*GetAttr() const { return m_attr
; } 
 202     // the item image or -1 
 205     // user data associated with the item 
 208     // the item coordinates are not used in report mode, instead this pointer 
 209     // is NULL and the owner window is used to retrieve the item position and 
 213     // the list ctrl we are in 
 214     wxListMainWindow 
*m_owner
; 
 216     // custom attributes or NULL 
 217     wxListItemAttr 
*m_attr
; 
 220     // common part of all ctors 
 226 //----------------------------------------------------------------------------- 
 227 //  wxListHeaderData (internal) 
 228 //----------------------------------------------------------------------------- 
 230 class WXDLLEXPORT wxListHeaderData 
: public wxObject
 
 234     wxListHeaderData( const wxListItem 
&info 
); 
 235     void SetItem( const wxListItem 
&item 
); 
 236     void SetPosition( int x
, int y 
); 
 237     void SetWidth( int w 
); 
 238     void SetFormat( int format 
); 
 239     void SetHeight( int h 
); 
 240     bool HasImage() const; 
 242     bool HasText() const { return !m_text
.empty(); } 
 243     const wxString
& GetText() const { return m_text
; } 
 244     void SetText(const wxString
& text
) { m_text 
= text
; } 
 246     void GetItem( wxListItem 
&item 
); 
 248     bool IsHit( int x
, int y 
) const; 
 249     int GetImage() const; 
 250     int GetWidth() const; 
 251     int GetFormat() const; 
 267 //----------------------------------------------------------------------------- 
 268 //  wxListLineData (internal) 
 269 //----------------------------------------------------------------------------- 
 271 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
); 
 272 #include "wx/listimpl.cpp" 
 273 WX_DEFINE_LIST(wxListItemDataList
); 
 278     // the list of subitems: only may have more than one item in report mode 
 279     wxListItemDataList m_items
; 
 281     // this is not used in report view 
 293         // the part to be highlighted 
 294         wxRect m_rectHighlight
; 
 296         // extend all our rects to be centered inside theo ne of given width 
 297         void ExtendWidth(wxCoord w
) 
 299             wxASSERT_MSG( m_rectAll
.width 
<= w
, 
 300                             _T("width can only be increased") ); 
 303             m_rectLabel
.x 
= m_rectAll
.x 
+ (w 
- m_rectLabel
.width
)/2; 
 304             m_rectIcon
.x 
= m_rectAll
.x 
+ (w 
- m_rectIcon
.width
)/2; 
 305             m_rectHighlight
.x 
= m_rectAll
.x 
+ (w 
- m_rectHighlight
.width
)/2; 
 309     // is this item selected? [NB: not used in virtual mode] 
 312     // back pointer to the list ctrl 
 313     wxListMainWindow 
*m_owner
; 
 316     wxListLineData(wxListMainWindow 
*owner
); 
 320         WX_CLEAR_LIST(wxListItemDataList
, m_items
); 
 324     // are we in report mode? 
 325     inline bool InReportView() const; 
 327     // are we in virtual report mode? 
 328     inline bool IsVirtual() const; 
 330     // these 2 methods shouldn't be called for report view controls, in that 
 331     // case we determine our position/size ourselves 
 333     // calculate the size of the line 
 334     void CalculateSize( wxDC 
*dc
, int spacing 
); 
 336     // remember the position this line appears at 
 337     void SetPosition( int x
, int y
, int spacing 
); 
 341     void SetImage( int image 
) { SetImage(0, image
); } 
 342     int GetImage() const { return GetImage(0); } 
 343     bool HasImage() const { return GetImage() != -1; } 
 344     bool HasText() const { return !GetText(0).empty(); } 
 346     void SetItem( int index
, const wxListItem 
&info 
); 
 347     void GetItem( int index
, wxListItem 
&info 
); 
 349     wxString 
GetText(int index
) const; 
 350     void SetText( int index
, const wxString s 
); 
 352     wxListItemAttr 
*GetAttr() const; 
 353     void SetAttr(wxListItemAttr 
*attr
); 
 355     // return true if the highlighting really changed 
 356     bool Highlight( bool on 
); 
 358     void ReverseHighlight(); 
 360     bool IsHighlighted() const 
 362         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); 
 364         return m_highlighted
; 
 367     // draw the line on the given DC in icon/list mode 
 368     void Draw( wxDC 
*dc 
); 
 370     // the same in report mode 
 371     void DrawInReportMode( wxDC 
*dc
, 
 373                            const wxRect
& rectHL
, 
 377     // set the line to contain num items (only can be > 1 in report mode) 
 378     void InitItems( int num 
); 
 380     // get the mode (i.e. style)  of the list control 
 381     inline int GetMode() const; 
 383     // prepare the DC for drawing with these item's attributes, return true if 
 384     // we need to draw the items background to highlight it, false otherwise 
 385     bool SetAttributes(wxDC 
*dc
, 
 386                        const wxListItemAttr 
*attr
, 
 389     // draw the text on the DC with the correct justification; also add an 
 390     // ellipsis if the text is too large to fit in the current width 
 391     void DrawTextFormatted(wxDC 
*dc
, const wxString 
&text
, int col
, int x
, int y
, int width
); 
 393     // these are only used by GetImage/SetImage above, we don't support images 
 394     // with subitems at the public API level yet 
 395     void SetImage( int index
, int image 
); 
 396     int GetImage( int index 
) const; 
 399 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
); 
 400 #include "wx/arrimpl.cpp" 
 401 WX_DEFINE_OBJARRAY(wxListLineDataArray
); 
 403 //----------------------------------------------------------------------------- 
 404 //  wxListHeaderWindow (internal) 
 405 //----------------------------------------------------------------------------- 
 407 class WXDLLEXPORT wxListHeaderWindow 
: public wxWindow
 
 410     wxListMainWindow  
*m_owner
; 
 411     wxCursor          
*m_currentCursor
; 
 412     wxCursor          
*m_resizeCursor
; 
 415     // column being resized or -1 
 418     // divider line position in logical (unscrolled) coords 
 421     // minimal position beyond which the divider line can't be dragged in 
 426     wxListHeaderWindow(); 
 428     wxListHeaderWindow( wxWindow 
*win
, 
 430                         wxListMainWindow 
*owner
, 
 431                         const wxPoint 
&pos 
= wxDefaultPosition
, 
 432                         const wxSize 
&size 
= wxDefaultSize
, 
 434                         const wxString 
&name 
= wxT("wxlistctrlcolumntitles") ); 
 436     virtual ~wxListHeaderWindow(); 
 439     void AdjustDC(wxDC
& dc
); 
 441     void OnPaint( wxPaintEvent 
&event 
); 
 442     void OnMouse( wxMouseEvent 
&event 
); 
 443     void OnSetFocus( wxFocusEvent 
&event 
); 
 449     // common part of all ctors 
 452     // generate and process the list event of the given type, return true if 
 453     // it wasn't vetoed, i.e. if we should proceed 
 454     bool SendListEvent(wxEventType type
, wxPoint pos
); 
 456     DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
) 
 457     DECLARE_EVENT_TABLE() 
 460 //----------------------------------------------------------------------------- 
 461 // wxListRenameTimer (internal) 
 462 //----------------------------------------------------------------------------- 
 464 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
 
 467     wxListMainWindow 
*m_owner
; 
 470     wxListRenameTimer( wxListMainWindow 
*owner 
); 
 474 //----------------------------------------------------------------------------- 
 475 //  wxListTextCtrl (internal) 
 476 //----------------------------------------------------------------------------- 
 478 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
 
 481     wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
); 
 484     void OnChar( wxKeyEvent 
&event 
); 
 485     void OnKeyUp( wxKeyEvent 
&event 
); 
 486     void OnKillFocus( wxFocusEvent 
&event 
); 
 488     bool AcceptChanges(); 
 492     wxListMainWindow   
*m_owner
; 
 493     wxString            m_startValue
; 
 497     DECLARE_EVENT_TABLE() 
 500 //----------------------------------------------------------------------------- 
 501 //  wxListMainWindow (internal) 
 502 //----------------------------------------------------------------------------- 
 504 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
); 
 505 #include "wx/listimpl.cpp" 
 506 WX_DEFINE_LIST(wxListHeaderDataList
); 
 508 class wxListMainWindow 
: public wxScrolledWindow
 
 512     wxListMainWindow( wxWindow 
*parent
, 
 514                       const wxPoint
& pos 
= wxDefaultPosition
, 
 515                       const wxSize
& size 
= wxDefaultSize
, 
 517                       const wxString 
&name 
= _T("listctrlmainwindow") ); 
 519     virtual ~wxListMainWindow(); 
 521     wxWindow 
*GetMainWindowOfCompositeControl() { return GetParent(); } 
 523     bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); } 
 525     // return true if this is a virtual list control 
 526     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); } 
 528     // return true if the control is in report mode 
 529     bool InReportView() const { return HasFlag(wxLC_REPORT
); } 
 531     // return true if we are in single selection mode, false if multi sel 
 532     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); } 
 534     // do we have a header window? 
 535     bool HasHeader() const 
 536         { return InReportView() && !HasFlag(wxLC_NO_HEADER
); } 
 538     void HighlightAll( bool on 
); 
 540     // all these functions only do something if the line is currently visible 
 542     // change the line "selected" state, return true if it really changed 
 543     bool HighlightLine( size_t line
, bool highlight 
= true); 
 545     // as HighlightLine() but do it for the range of lines: this is incredibly 
 546     // more efficient for virtual list controls! 
 548     // NB: unlike HighlightLine() this one does refresh the lines on screen 
 549     void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on 
= true ); 
 551     // toggle the line state and refresh it 
 552     void ReverseHighlight( size_t line 
) 
 553         { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); } 
 555     // return true if the line is highlighted 
 556     bool IsHighlighted(size_t line
) const; 
 558     // refresh one or several lines at once 
 559     void RefreshLine( size_t line 
); 
 560     void RefreshLines( size_t lineFrom
, size_t lineTo 
); 
 562     // refresh all selected items 
 563     void RefreshSelected(); 
 565     // refresh all lines below the given one: the difference with 
 566     // RefreshLines() is that the index here might not be a valid one (happens 
 567     // when the last line is deleted) 
 568     void RefreshAfter( size_t lineFrom 
); 
 570     // the methods which are forwarded to wxListLineData itself in list/icon 
 571     // modes but are here because the lines don't store their positions in the 
 574     // get the bound rect for the entire line 
 575     wxRect 
GetLineRect(size_t line
) const; 
 577     // get the bound rect of the label 
 578     wxRect 
GetLineLabelRect(size_t line
) const; 
 580     // get the bound rect of the items icon (only may be called if we do have 
 582     wxRect 
GetLineIconRect(size_t line
) const; 
 584     // get the rect to be highlighted when the item has focus 
 585     wxRect 
GetLineHighlightRect(size_t line
) const; 
 587     // get the size of the total line rect 
 588     wxSize 
GetLineSize(size_t line
) const 
 589         { return GetLineRect(line
).GetSize(); } 
 591     // return the hit code for the corresponding position (in this line) 
 592     long HitTestLine(size_t line
, int x
, int y
) const; 
 594     // bring the selected item into view, scrolling to it if necessary 
 595     void MoveToItem(size_t item
); 
 597     // bring the current item into view 
 598     void MoveToFocus() { MoveToItem(m_current
); } 
 600     // start editing the label of the given item 
 601     void EditLabel( long item 
); 
 603     // suspend/resume redrawing the control 
 609     void OnRenameTimer(); 
 610     bool OnRenameAccept(size_t itemEdit
, const wxString
& value
); 
 611     void OnRenameCancelled(size_t itemEdit
); 
 613     void OnMouse( wxMouseEvent 
&event 
); 
 615     // called to switch the selection from the current item to newCurrent, 
 616     void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event 
); 
 618     void OnChar( wxKeyEvent 
&event 
); 
 619     void OnKeyDown( wxKeyEvent 
&event 
); 
 620     void OnSetFocus( wxFocusEvent 
&event 
); 
 621     void OnKillFocus( wxFocusEvent 
&event 
); 
 622     void OnScroll(wxScrollWinEvent
& event
) ; 
 624     void OnPaint( wxPaintEvent 
&event 
); 
 626     void DrawImage( int index
, wxDC 
*dc
, int x
, int y 
); 
 627     void GetImageSize( int index
, int &width
, int &height 
) const; 
 628     int GetTextLength( const wxString 
&s 
) const; 
 630     void SetImageList( wxImageListType 
*imageList
, int which 
); 
 631     void SetItemSpacing( int spacing
, bool isSmall 
= false ); 
 632     int GetItemSpacing( bool isSmall 
= false ); 
 634     void SetColumn( int col
, wxListItem 
&item 
); 
 635     void SetColumnWidth( int col
, int width 
); 
 636     void GetColumn( int col
, wxListItem 
&item 
) const; 
 637     int GetColumnWidth( int col 
) const; 
 638     int GetColumnCount() const { return m_columns
.GetCount(); } 
 640     // returns the sum of the heights of all columns 
 641     int GetHeaderWidth() const; 
 643     int GetCountPerPage() const; 
 645     void SetItem( wxListItem 
&item 
); 
 646     void GetItem( wxListItem 
&item 
) const; 
 647     void SetItemState( long item
, long state
, long stateMask 
); 
 648     int GetItemState( long item
, long stateMask 
) const; 
 649     void GetItemRect( long index
, wxRect 
&rect 
) const; 
 650     wxRect 
GetViewRect() const; 
 651     bool GetItemPosition( long item
, wxPoint
& pos 
) const; 
 652     int GetSelectedItemCount() const; 
 654     wxString 
GetItemText(long item
) const 
 657         info
.m_itemId 
= item
; 
 662     void SetItemText(long item
, const wxString
& value
) 
 665         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 666         info
.m_itemId 
= item
; 
 671     // set the scrollbars and update the positions of the items 
 672     void RecalculatePositions(bool noRefresh 
= false); 
 674     // refresh the window and the header 
 677     long GetNextItem( long item
, int geometry
, int state 
) const; 
 678     void DeleteItem( long index 
); 
 679     void DeleteAllItems(); 
 680     void DeleteColumn( int col 
); 
 681     void DeleteEverything(); 
 682     void EnsureVisible( long index 
); 
 683     long FindItem( long start
, const wxString
& str
, bool partial 
= false ); 
 684     long FindItem( long start
, wxUIntPtr data
); 
 685     long FindItem( const wxPoint
& pt 
); 
 686     long HitTest( int x
, int y
, int &flags 
); 
 687     void InsertItem( wxListItem 
&item 
); 
 688     void InsertColumn( long col
, wxListItem 
&item 
); 
 689     void SortItems( wxListCtrlCompare fn
, long data 
); 
 691     size_t GetItemCount() const; 
 692     bool IsEmpty() const { return GetItemCount() == 0; } 
 693     void SetItemCount(long count
); 
 695     // change the current (== focused) item, send a notification event 
 696     void ChangeCurrent(size_t current
); 
 697     void ResetCurrent() { ChangeCurrent((size_t)-1); } 
 698     bool HasCurrent() const { return m_current 
!= (size_t)-1; } 
 700     // send out a wxListEvent 
 701     void SendNotify( size_t line
, 
 703                      wxPoint point 
= wxDefaultPosition 
); 
 705     // override base class virtual to reset m_lineHeight when the font changes 
 706     virtual bool SetFont(const wxFont
& font
) 
 708         if ( !wxScrolledWindow::SetFont(font
) ) 
 716     // these are for wxListLineData usage only 
 718     // get the backpointer to the list ctrl 
 719     wxGenericListCtrl 
*GetListCtrl() const 
 721         return wxStaticCast(GetParent(), wxGenericListCtrl
); 
 724     // get the height of all lines (assuming they all do have the same height) 
 725     wxCoord 
GetLineHeight() const; 
 727     // get the y position of the given line (only for report view) 
 728     wxCoord 
GetLineY(size_t line
) const; 
 730     // get the brush to use for the item highlighting 
 731     wxBrush 
*GetHighlightBrush() const 
 733         return m_hasFocus 
? m_highlightBrush 
: m_highlightUnfocusedBrush
; 
 737     // the array of all line objects for a non virtual list control (for the 
 738     // virtual list control we only ever use m_lines[0]) 
 739     wxListLineDataArray  m_lines
; 
 741     // the list of column objects 
 742     wxListHeaderDataList m_columns
; 
 744     // currently focused item or -1 
 747     // the number of lines per page 
 750     // this flag is set when something which should result in the window 
 751     // redrawing happens (i.e. an item was added or deleted, or its appearance 
 752     // changed) and OnPaint() doesn't redraw the window while it is set which 
 753     // allows to minimize the number of repaintings when a lot of items are 
 754     // being added. The real repainting occurs only after the next OnIdle() 
 758     wxColour            
*m_highlightColour
; 
 759     wxImageListType         
*m_small_image_list
; 
 760     wxImageListType         
*m_normal_image_list
; 
 762     int                  m_normal_spacing
; 
 766     wxTimer             
*m_renameTimer
; 
 771     // for double click logic 
 772     size_t m_lineLastClicked
, 
 773            m_lineBeforeLastClicked
; 
 776     // the total count of items in a virtual list control 
 779     // the object maintaining the items selection state, only used in virtual 
 781     wxSelectionStore m_selStore
; 
 783     // common part of all ctors 
 786     // get the line data for the given index 
 787     wxListLineData 
*GetLine(size_t n
) const 
 789         wxASSERT_MSG( n 
!= (size_t)-1, _T("invalid line index") ); 
 793             wxConstCast(this, wxListMainWindow
)->CacheLineData(n
); 
 801     // get a dummy line which can be used for geometry calculations and such: 
 802     // you must use GetLine() if you want to really draw the line 
 803     wxListLineData 
*GetDummyLine() const; 
 805     // cache the line data of the n-th line in m_lines[0] 
 806     void CacheLineData(size_t line
); 
 808     // get the range of visible lines 
 809     void GetVisibleLinesRange(size_t *from
, size_t *to
); 
 811     // force us to recalculate the range of visible lines 
 812     void ResetVisibleLinesRange() { m_lineFrom 
= (size_t)-1; } 
 814     // get the colour to be used for drawing the rules 
 815     wxColour 
GetRuleColour() const 
 820         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 825     // initialize the current item if needed 
 826     void UpdateCurrent(); 
 828     // delete all items but don't refresh: called from dtor 
 829     void DoDeleteAllItems(); 
 831     // the height of one line using the current font 
 832     wxCoord m_lineHeight
; 
 834     // the total header width or 0 if not calculated yet 
 835     wxCoord m_headerWidth
; 
 837     // the first and last lines being shown on screen right now (inclusive), 
 838     // both may be -1 if they must be calculated so never access them directly: 
 839     // use GetVisibleLinesRange() above instead 
 843     // the brushes to use for item highlighting when we do/don't have focus 
 844     wxBrush 
*m_highlightBrush
, 
 845             *m_highlightUnfocusedBrush
; 
 847     // if this is > 0, the control is frozen and doesn't redraw itself 
 848     size_t m_freezeCount
; 
 850     DECLARE_DYNAMIC_CLASS(wxListMainWindow
) 
 851     DECLARE_EVENT_TABLE() 
 853     friend class wxGenericListCtrl
; 
 856 // ============================================================================ 
 858 // ============================================================================ 
 860 //----------------------------------------------------------------------------- 
 862 //----------------------------------------------------------------------------- 
 864 wxListItemData::~wxListItemData() 
 866     // in the virtual list control the attributes are managed by the main 
 867     // program, so don't delete them 
 868     if ( !m_owner
->IsVirtual() ) 
 876 void wxListItemData::Init() 
 884 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
 890     if ( owner
->InReportView() ) 
 900 void wxListItemData::SetItem( const wxListItem 
&info 
) 
 902     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
 903         SetText(info
.m_text
); 
 904     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 905         m_image 
= info
.m_image
; 
 906     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
 907         m_data 
= info
.m_data
; 
 909     if ( info
.HasAttributes() ) 
 912             *m_attr 
= *info
.GetAttributes(); 
 914             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
 922         m_rect
->width 
= info
.m_width
; 
 926 void wxListItemData::SetPosition( int x
, int y 
) 
 928     wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") ); 
 934 void wxListItemData::SetSize( int width
, int height 
) 
 936     wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") ); 
 939         m_rect
->width 
= width
; 
 941         m_rect
->height 
= height
; 
 944 bool wxListItemData::IsHit( int x
, int y 
) const 
 946     wxCHECK_MSG( m_rect
, false, _T("can't be called in this mode") ); 
 948     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
); 
 951 int wxListItemData::GetX() const 
 953     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 958 int wxListItemData::GetY() const 
 960     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 965 int wxListItemData::GetWidth() const 
 967     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 969     return m_rect
->width
; 
 972 int wxListItemData::GetHeight() const 
 974     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 976     return m_rect
->height
; 
 979 void wxListItemData::GetItem( wxListItem 
&info 
) const 
 981     info
.m_text 
= m_text
; 
 982     info
.m_image 
= m_image
; 
 983     info
.m_data 
= m_data
; 
 987         if ( m_attr
->HasTextColour() ) 
 988             info
.SetTextColour(m_attr
->GetTextColour()); 
 989         if ( m_attr
->HasBackgroundColour() ) 
 990             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
 991         if ( m_attr
->HasFont() ) 
 992             info
.SetFont(m_attr
->GetFont()); 
 996 //----------------------------------------------------------------------------- 
 998 //----------------------------------------------------------------------------- 
1000 void wxListHeaderData::Init() 
1011 wxListHeaderData::wxListHeaderData() 
1016 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
1023 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
1025     m_mask 
= item
.m_mask
; 
1027     if ( m_mask 
& wxLIST_MASK_TEXT 
) 
1028         m_text 
= item
.m_text
; 
1030     if ( m_mask 
& wxLIST_MASK_IMAGE 
) 
1031         m_image 
= item
.m_image
; 
1033     if ( m_mask 
& wxLIST_MASK_FORMAT 
) 
1034         m_format 
= item
.m_format
; 
1036     if ( m_mask 
& wxLIST_MASK_WIDTH 
) 
1037         SetWidth(item
.m_width
); 
1040 void wxListHeaderData::SetPosition( int x
, int y 
) 
1046 void wxListHeaderData::SetHeight( int h 
) 
1051 void wxListHeaderData::SetWidth( int w 
) 
1055         m_width 
= WIDTH_COL_DEFAULT
; 
1056     else if (m_width 
< WIDTH_COL_MIN
) 
1057         m_width 
= WIDTH_COL_MIN
; 
1060 void wxListHeaderData::SetFormat( int format 
) 
1065 bool wxListHeaderData::HasImage() const 
1067     return m_image 
!= -1; 
1070 bool wxListHeaderData::IsHit( int x
, int y 
) const 
1072     return ((x 
>= m_xpos
) && (x 
<= m_xpos
+m_width
) && (y 
>= m_ypos
) && (y 
<= m_ypos
+m_height
)); 
1075 void wxListHeaderData::GetItem( wxListItem
& item 
) 
1077     item
.m_mask 
= m_mask
; 
1078     item
.m_text 
= m_text
; 
1079     item
.m_image 
= m_image
; 
1080     item
.m_format 
= m_format
; 
1081     item
.m_width 
= m_width
; 
1084 int wxListHeaderData::GetImage() const 
1089 int wxListHeaderData::GetWidth() const 
1094 int wxListHeaderData::GetFormat() const 
1099 //----------------------------------------------------------------------------- 
1101 //----------------------------------------------------------------------------- 
1103 inline int wxListLineData::GetMode() const 
1105     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
1108 inline bool wxListLineData::InReportView() const 
1110     return m_owner
->HasFlag(wxLC_REPORT
); 
1113 inline bool wxListLineData::IsVirtual() const 
1115     return m_owner
->IsVirtual(); 
1118 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
1122     if ( InReportView() ) 
1128         m_gi 
= new GeometryInfo
; 
1131     m_highlighted 
= false; 
1133     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
1136 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
1138     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1139     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1141     wxListItemData 
*item 
= node
->GetData(); 
1146     switch ( GetMode() ) 
1149         case wxLC_SMALL_ICON
: 
1150             m_gi
->m_rectAll
.width 
= spacing
; 
1152             s 
= item
->GetText(); 
1157                 m_gi
->m_rectLabel
.width 
= 
1158                 m_gi
->m_rectLabel
.height 
= 0; 
1162                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
1166                 m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
1168                     m_gi
->m_rectAll
.width 
= lw
; 
1170                 m_gi
->m_rectLabel
.width 
= lw
; 
1171                 m_gi
->m_rectLabel
.height 
= lh
; 
1174             if (item
->HasImage()) 
1177                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1178                 m_gi
->m_rectIcon
.width 
= w 
+ 8; 
1179                 m_gi
->m_rectIcon
.height 
= h 
+ 8; 
1181                 if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
1182                     m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
1183                 if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
1184                     m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
1187             if ( item
->HasText() ) 
1189                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
1190                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
1192             else // no text, highlight the icon 
1194                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
1195                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
1200             s 
= item
->GetTextForMeasuring(); 
1202             dc
->GetTextExtent( s
, &lw
, &lh 
); 
1206             m_gi
->m_rectLabel
.width 
= lw
; 
1207             m_gi
->m_rectLabel
.height 
= lh
; 
1209             m_gi
->m_rectAll
.width 
= lw
; 
1210             m_gi
->m_rectAll
.height 
= lh
; 
1212             if (item
->HasImage()) 
1215                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1216                 m_gi
->m_rectIcon
.width 
= w
; 
1217                 m_gi
->m_rectIcon
.height 
= h
; 
1219                 m_gi
->m_rectAll
.width 
+= 4 + w
; 
1220                 if (h 
> m_gi
->m_rectAll
.height
) 
1221                     m_gi
->m_rectAll
.height 
= h
; 
1224             m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
1225             m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
1229             wxFAIL_MSG( _T("unexpected call to SetSize") ); 
1233             wxFAIL_MSG( _T("unknown mode") ); 
1237 void wxListLineData::SetPosition( int x
, int y
, int spacing 
) 
1239     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1240     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1242     wxListItemData 
*item 
= node
->GetData(); 
1244     switch ( GetMode() ) 
1247         case wxLC_SMALL_ICON
: 
1248             m_gi
->m_rectAll
.x 
= x
; 
1249             m_gi
->m_rectAll
.y 
= y
; 
1251             if ( item
->HasImage() ) 
1253                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 + 
1254                     (m_gi
->m_rectAll
.width 
- m_gi
->m_rectIcon
.width
) / 2; 
1255                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
1258             if ( item
->HasText() ) 
1260                 if (m_gi
->m_rectAll
.width 
> spacing
) 
1261                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1263                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2); 
1264                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
1265                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
1266                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
1268             else // no text, highlight the icon 
1270                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
1271                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
1276             m_gi
->m_rectAll
.x 
= x
; 
1277             m_gi
->m_rectAll
.y 
= y
; 
1279             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
1280             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
1281             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1283             if (item
->HasImage()) 
1285                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1286                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1287                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 6 + m_gi
->m_rectIcon
.width
; 
1291                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1296             wxFAIL_MSG( _T("unexpected call to SetPosition") ); 
1300             wxFAIL_MSG( _T("unknown mode") ); 
1304 void wxListLineData::InitItems( int num 
) 
1306     for (int i 
= 0; i 
< num
; i
++) 
1307         m_items
.Append( new wxListItemData(m_owner
) ); 
1310 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
1312     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1313     wxCHECK_RET( node
, _T("invalid column index in SetItem") ); 
1315     wxListItemData 
*item 
= node
->GetData(); 
1316     item
->SetItem( info 
); 
1319 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
1321     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1324         wxListItemData 
*item 
= node
->GetData(); 
1325         item
->GetItem( info 
); 
1329 wxString 
wxListLineData::GetText(int index
) const 
1333     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1336         wxListItemData 
*item 
= node
->GetData(); 
1337         s 
= item
->GetText(); 
1343 void wxListLineData::SetText( int index
, const wxString s 
) 
1345     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1348         wxListItemData 
*item 
= node
->GetData(); 
1353 void wxListLineData::SetImage( int index
, int image 
) 
1355     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1356     wxCHECK_RET( node
, _T("invalid column index in SetImage()") ); 
1358     wxListItemData 
*item 
= node
->GetData(); 
1359     item
->SetImage(image
); 
1362 int wxListLineData::GetImage( int index 
) const 
1364     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1365     wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") ); 
1367     wxListItemData 
*item 
= node
->GetData(); 
1368     return item
->GetImage(); 
1371 wxListItemAttr 
*wxListLineData::GetAttr() const 
1373     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1374     wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") ); 
1376     wxListItemData 
*item 
= node
->GetData(); 
1377     return item
->GetAttr(); 
1380 void wxListLineData::SetAttr(wxListItemAttr 
*attr
) 
1382     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1383     wxCHECK_RET( node
, _T("invalid column index in SetAttr()") ); 
1385     wxListItemData 
*item 
= node
->GetData(); 
1386     item
->SetAttr(attr
); 
1389 bool wxListLineData::SetAttributes(wxDC 
*dc
, 
1390                                    const wxListItemAttr 
*attr
, 
1393     wxWindow 
*listctrl 
= m_owner
->GetParent(); 
1397     // don't use foreground colour for drawing highlighted items - this might 
1398     // make them completely invisible (and there is no way to do bit 
1399     // arithmetics on wxColour, unfortunately) 
1403         colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1407         if ( attr 
&& attr
->HasTextColour() ) 
1409             colText 
= attr
->GetTextColour(); 
1413             colText 
= listctrl
->GetForegroundColour(); 
1417     dc
->SetTextForeground(colText
); 
1421     if ( attr 
&& attr
->HasFont() ) 
1423         font 
= attr
->GetFont(); 
1427         font 
= listctrl
->GetFont(); 
1433     bool hasBgCol 
= attr 
&& attr
->HasBackgroundColour(); 
1434     if ( highlighted 
|| hasBgCol 
) 
1438             dc
->SetBrush( *m_owner
->GetHighlightBrush() ); 
1442             dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
)); 
1445         dc
->SetPen( *wxTRANSPARENT_PEN 
); 
1453 void wxListLineData::Draw( wxDC 
*dc 
) 
1455     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1456     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1458     bool highlighted 
= IsHighlighted(); 
1460     wxListItemAttr 
*attr 
= GetAttr(); 
1462     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1464         dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1467     // just for debugging to better see where the items are 
1469     dc
->SetPen(*wxRED_PEN
); 
1470     dc
->SetBrush(*wxTRANSPARENT_BRUSH
); 
1471     dc
->DrawRectangle( m_gi
->m_rectAll 
); 
1472     dc
->SetPen(*wxGREEN_PEN
); 
1473     dc
->DrawRectangle( m_gi
->m_rectIcon 
); 
1476     wxListItemData 
*item 
= node
->GetData(); 
1477     if (item
->HasImage()) 
1479         // centre the image inside our rectangle, this looks nicer when items 
1480         // ae aligned in a row 
1481         const wxRect
& rectIcon 
= m_gi
->m_rectIcon
; 
1483         m_owner
->DrawImage(item
->GetImage(), dc
, rectIcon
.x
, rectIcon
.y
); 
1486     if (item
->HasText()) 
1488         const wxRect
& rectLabel 
= m_gi
->m_rectLabel
; 
1490         wxDCClipper 
clipper(*dc
, rectLabel
); 
1491         dc
->DrawText(item
->GetText(), rectLabel
.x
, rectLabel
.y
); 
1495 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
1497                                        const wxRect
& rectHL
, 
1500     // TODO: later we should support setting different attributes for 
1501     //       different columns - to do it, just add "col" argument to 
1502     //       GetAttr() and move these lines into the loop below 
1503     wxListItemAttr 
*attr 
= GetAttr(); 
1504     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1506         dc
->DrawRectangle( rectHL 
); 
1509     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
1510             y 
= rect
.y 
+ (LINE_SPACING 
+ EXTRA_HEIGHT
) / 2; 
1513     for ( wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1515           node 
= node
->GetNext(), col
++ ) 
1517         wxListItemData 
*item 
= node
->GetData(); 
1519         int width 
= m_owner
->GetColumnWidth(col
); 
1523         if ( item
->HasImage() ) 
1526             m_owner
->DrawImage( item
->GetImage(), dc
, xOld
, y 
); 
1527             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
1529             ix 
+= IMAGE_MARGIN_IN_REPORT_MODE
; 
1535         wxDCClipper 
clipper(*dc
, xOld
, y
, width 
- 8, rect
.height
); 
1537         if ( item
->HasText() ) 
1539             DrawTextFormatted(dc
, item
->GetText(), col
, xOld
, y
, width 
- 8); 
1544 void wxListLineData::DrawTextFormatted(wxDC 
*dc
, 
1545                                        const wxString 
&text
, 
1551     wxString drawntext
, ellipsis
; 
1552     wxCoord w
, h
, base_w
; 
1555     // determine if the string can fit inside the current width 
1556     dc
->GetTextExtent(text
, &w
, &h
); 
1559         // it can, draw it using the items alignment 
1560         m_owner
->GetColumn(col
, item
); 
1561         switch ( item
.GetAlign() ) 
1564                 wxFAIL_MSG( _T("unknown list item format") ); 
1567             case wxLIST_FORMAT_LEFT
: 
1571             case wxLIST_FORMAT_RIGHT
: 
1575             case wxLIST_FORMAT_CENTER
: 
1576                 x 
+= (width 
- w
) / 2; 
1580         dc
->DrawText(text
, x
, y
); 
1582     else // otherwise, truncate and add an ellipsis if possible 
1584         // determine the base width 
1585         ellipsis 
= wxString(wxT("...")); 
1586         dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1588         // continue until we have enough space or only one character left 
1590         size_t len 
= text
.Length(); 
1591         drawntext 
= text
.Left(len
); 
1594             dc
->GetTextExtent(drawntext
.Last(), &w_c
, &h_c
); 
1595             drawntext
.RemoveLast(); 
1598             if (w 
+ base_w 
<= width
) 
1602         // if still not enough space, remove ellipsis characters 
1603         while (ellipsis
.Length() > 0 && w 
+ base_w 
> width
) 
1605             ellipsis 
= ellipsis
.Left(ellipsis
.Length() - 1); 
1606             dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1609         // now draw the text 
1610         dc
->DrawText(drawntext
, x
, y
); 
1611         dc
->DrawText(ellipsis
, x 
+ w
, y
); 
1615 bool wxListLineData::Highlight( bool on 
) 
1617     wxCHECK_MSG( !IsVirtual(), false, _T("unexpected call to Highlight") ); 
1619     if ( on 
== m_highlighted 
) 
1627 void wxListLineData::ReverseHighlight( void ) 
1629     Highlight(!IsHighlighted()); 
1632 //----------------------------------------------------------------------------- 
1633 //  wxListHeaderWindow 
1634 //----------------------------------------------------------------------------- 
1636 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
) 
1638 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
1639     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
1640     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
1641     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
1644 void wxListHeaderWindow::Init() 
1646     m_currentCursor 
= (wxCursor 
*) NULL
; 
1647     m_isDragging 
= false; 
1651 wxListHeaderWindow::wxListHeaderWindow() 
1655     m_owner 
= (wxListMainWindow 
*) NULL
; 
1656     m_resizeCursor 
= (wxCursor 
*) NULL
; 
1659 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, 
1661                                         wxListMainWindow 
*owner
, 
1665                                         const wxString 
&name 
) 
1666                   : wxWindow( win
, id
, pos
, size
, style
, name 
) 
1671     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
1674     wxVisualAttributes attr 
= wxPanel::GetClassDefaultAttributes(); 
1675     SetOwnForegroundColour( attr
.colFg 
); 
1676     SetOwnBackgroundColour( attr
.colBg 
); 
1678         SetOwnFont( attr
.font 
); 
1680     SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
1681     SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
1683         SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT 
)); 
1687 wxListHeaderWindow::~wxListHeaderWindow() 
1689     delete m_resizeCursor
; 
1692 #ifdef __WXUNIVERSAL__ 
1693 #include "wx/univ/renderer.h" 
1694 #include "wx/univ/theme.h" 
1697 // shift the DC origin to match the position of the main window horz 
1698 // scrollbar: this allows us to always use logical coords 
1699 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
1702     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1705     m_owner
->GetViewStart( &x
, NULL 
); 
1707     // account for the horz scrollbar offset 
1708     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1711 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1713     wxPaintDC 
dc( this ); 
1720     dc
.SetFont( GetFont() ); 
1722     // width and height of the entire header window 
1724     GetClientSize( &w
, &h 
); 
1725     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1727     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1729     dc
.SetTextForeground(GetForegroundColour()); 
1731     int x 
= HEADER_OFFSET_X
; 
1733     int numColumns 
= m_owner
->GetColumnCount(); 
1735     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1737         m_owner
->GetColumn( i
, item 
); 
1738         int wCol 
= item
.m_width
; 
1740         // the width of the rect to draw: make it smaller to fit entirely 
1741         // inside the column rect 
1744         wxRendererNative::Get().DrawHeaderButton
 
1748                                     wxRect(x
, HEADER_OFFSET_Y
, cw
, h 
- 2), 
1749                                     m_parent
->IsEnabled() ? 0 
1750                                                           : wxCONTROL_DISABLED
 
1753         // see if we have enough space for the column label 
1755         // for this we need the width of the text 
1758         dc
.GetTextExtent(item
.GetText(), &wLabel
, &hLabel
); 
1759         wLabel 
+= 2*EXTRA_WIDTH
; 
1761         // and the width of the icon, if any 
1762         static const int MARGIN_BETWEEN_TEXT_AND_ICON 
= 2; 
1763         int ix 
= 0,     // init them just to suppress the compiler warnings 
1765         const int image 
= item
.m_image
; 
1766         wxImageListType 
*imageList
; 
1769             imageList 
= m_owner
->m_small_image_list
; 
1772                 imageList
->GetSize(image
, ix
, iy
); 
1773                 wLabel 
+= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
1781         // ignore alignment if there is not enough space anyhow 
1783         switch ( wLabel 
< cw 
? item
.GetAlign() : wxLIST_FORMAT_LEFT 
) 
1786                 wxFAIL_MSG( _T("unknown list item format") ); 
1789             case wxLIST_FORMAT_LEFT
: 
1793             case wxLIST_FORMAT_RIGHT
: 
1794                 xAligned 
= x 
+ cw 
- wLabel
; 
1797             case wxLIST_FORMAT_CENTER
: 
1798                 xAligned 
= x 
+ (cw 
- wLabel
) / 2; 
1803         // if we have an image, draw it on the right of the label 
1810                         xAligned 
+ wLabel 
- ix 
- MARGIN_BETWEEN_TEXT_AND_ICON
, 
1811                         HEADER_OFFSET_Y 
+ (h 
- 4 - iy
)/2, 
1812                         wxIMAGELIST_DRAW_TRANSPARENT
 
1815             cw 
-= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
1818         // draw the text clipping it so that it doesn't overwrite the column 
1820         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h 
- 4 ); 
1822         dc
.DrawText( item
.GetText(), 
1823                      xAligned 
+ EXTRA_WIDTH
, h 
/ 2 - hLabel 
/ 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT ); 
1831 void wxListHeaderWindow::DrawCurrent() 
1833     int x1 
= m_currentX
; 
1835     m_owner
->ClientToScreen( &x1
, &y1 
); 
1837     int x2 
= m_currentX
; 
1839     m_owner
->GetClientSize( NULL
, &y2 
); 
1840     m_owner
->ClientToScreen( &x2
, &y2 
); 
1843     dc
.SetLogicalFunction( wxINVERT 
); 
1844     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
1845     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1849     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1851     dc
.SetLogicalFunction( wxCOPY 
); 
1853     dc
.SetPen( wxNullPen 
); 
1854     dc
.SetBrush( wxNullBrush 
); 
1857 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1859     // we want to work with logical coords 
1861     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1862     int y 
= event
.GetY(); 
1866         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1868         // we don't draw the line beyond our window, but we allow dragging it 
1871         GetClientSize( &w
, NULL 
); 
1872         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1875         // erase the line if it was drawn 
1876         if ( m_currentX 
< w 
) 
1879         if (event
.ButtonUp()) 
1882             m_isDragging 
= false; 
1884             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1885             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1892                 m_currentX 
= m_minX 
+ 7; 
1894             // draw in the new location 
1895             if ( m_currentX 
< w 
) 
1899     else // not dragging 
1902         bool hit_border 
= false; 
1904         // end of the current column 
1907         // find the column where this event occured 
1909             countCol 
= m_owner
->GetColumnCount(); 
1910         for (col 
= 0; col 
< countCol
; col
++) 
1912             xpos 
+= m_owner
->GetColumnWidth( col 
); 
1915             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
1917                 // near the column border 
1924                 // inside the column 
1931         if ( col 
== countCol 
) 
1934         if (event
.LeftDown() || event
.RightUp()) 
1936             if (hit_border 
&& event
.LeftDown()) 
1938                 if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
1939                                    event
.GetPosition()) ) 
1941                     m_isDragging 
= true; 
1946                 //else: column resizing was vetoed by the user code 
1948             else // click on a column 
1950                 SendListEvent( event
.LeftDown() 
1951                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
1952                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
1953                                 event
.GetPosition()); 
1956         else if (event
.Moving()) 
1961                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
1962                 m_currentCursor 
= m_resizeCursor
; 
1966                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
1967                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1971                 SetCursor(*m_currentCursor
); 
1976 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1978     m_owner
->SetFocus(); 
1982 bool wxListHeaderWindow::SendListEvent(wxEventType type
, wxPoint pos
) 
1984     wxWindow 
*parent 
= GetParent(); 
1985     wxListEvent 
le( type
, parent
->GetId() ); 
1986     le
.SetEventObject( parent 
); 
1987     le
.m_pointDrag 
= pos
; 
1989     // the position should be relative to the parent window, not 
1990     // this one for compatibility with MSW and common sense: the 
1991     // user code doesn't know anything at all about this header 
1992     // window, so why should it get positions relative to it? 
1993     le
.m_pointDrag
.y 
-= GetSize().y
; 
1995     le
.m_col 
= m_column
; 
1996     return !parent
->GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
1999 //----------------------------------------------------------------------------- 
2000 // wxListRenameTimer (internal) 
2001 //----------------------------------------------------------------------------- 
2003 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
2008 void wxListRenameTimer::Notify() 
2010     m_owner
->OnRenameTimer(); 
2013 //----------------------------------------------------------------------------- 
2014 // wxListTextCtrl (internal) 
2015 //----------------------------------------------------------------------------- 
2017 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
) 
2018     EVT_CHAR           (wxListTextCtrl::OnChar
) 
2019     EVT_KEY_UP         (wxListTextCtrl::OnKeyUp
) 
2020     EVT_KILL_FOCUS     (wxListTextCtrl::OnKillFocus
) 
2023 wxListTextCtrl::wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
) 
2024               : m_startValue(owner
->GetItemText(itemEdit
)), 
2025                 m_itemEdited(itemEdit
) 
2030     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
2032     m_owner
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
2033                                   &rectLabel
.x
, &rectLabel
.y
); 
2035     (void)Create(owner
, wxID_ANY
, m_startValue
, 
2036                  wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2037                  wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
2040 void wxListTextCtrl::Finish() 
2044         wxPendingDelete
.Append(this); 
2048         m_owner
->SetFocus(); 
2052 bool wxListTextCtrl::AcceptChanges() 
2054     const wxString value 
= GetValue(); 
2056     if ( value 
== m_startValue 
) 
2058         // nothing changed, always accept 
2062     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
2064         // vetoed by the user 
2068     // accepted, do rename the item 
2069     m_owner
->SetItemText(m_itemEdited
, value
); 
2074 void wxListTextCtrl::OnChar( wxKeyEvent 
&event 
) 
2076     switch ( event
.m_keyCode 
) 
2079             if ( AcceptChanges() ) 
2081                 // Close the text control, changes were accepted 
2084             // else do nothing, do not accept and do not close 
2090             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2098 void wxListTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
2106     // auto-grow the textctrl: 
2107     wxSize parentSize 
= m_owner
->GetSize(); 
2108     wxPoint myPos 
= GetPosition(); 
2109     wxSize mySize 
= GetSize(); 
2111     GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); 
2112     if (myPos
.x 
+ sx 
> parentSize
.x
) 
2113         sx 
= parentSize
.x 
- myPos
.x
; 
2116     SetSize(sx
, wxDefaultCoord
); 
2121 void wxListTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2125         // We must finish regardless of success, otherwise we'll get 
2129         if ( !AcceptChanges() ) 
2130             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2133     // We must let the native text control handle focus, too, otherwise 
2134     // it could have problems with the cursor (e.g., in wxGTK): 
2138 //----------------------------------------------------------------------------- 
2140 //----------------------------------------------------------------------------- 
2142 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
) 
2144 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
) 
2145   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2146   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2147   EVT_CHAR           (wxListMainWindow::OnChar
) 
2148   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2149   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2150   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2151   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2154 void wxListMainWindow::Init() 
2159     m_lineTo 
= (size_t)-1; 
2165     m_small_image_list 
= (wxImageListType 
*) NULL
; 
2166     m_normal_image_list 
= (wxImageListType 
*) NULL
; 
2168     m_small_spacing 
= 30; 
2169     m_normal_spacing 
= 40; 
2173     m_isCreated 
= false; 
2175     m_lastOnSame 
= false; 
2176     m_renameTimer 
= new wxListRenameTimer( this ); 
2180     m_lineBeforeLastClicked 
= (size_t)-1; 
2185 wxListMainWindow::wxListMainWindow() 
2190     m_highlightUnfocusedBrush 
= (wxBrush 
*) NULL
; 
2193 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2198                                     const wxString 
&name 
) 
2199                 : wxScrolledWindow( parent
, id
, pos
, size
, 
2200                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2204     m_highlightBrush 
= new wxBrush
 
2206                             wxSystemSettings::GetColour
 
2208                                 wxSYS_COLOUR_HIGHLIGHT
 
2213     m_highlightUnfocusedBrush 
= new wxBrush
 
2215                                        wxSystemSettings::GetColour
 
2217                                            wxSYS_COLOUR_BTNSHADOW
 
2225     SetScrollbars( 0, 0, 0, 0, 0, 0 ); 
2227     wxVisualAttributes attr 
= wxGenericListCtrl::GetClassDefaultAttributes(); 
2228     SetOwnForegroundColour( attr
.colFg 
); 
2229     SetOwnBackgroundColour( attr
.colBg 
); 
2231         SetOwnFont( attr
.font 
); 
2234 wxListMainWindow::~wxListMainWindow() 
2237     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
2239     delete m_highlightBrush
; 
2240     delete m_highlightUnfocusedBrush
; 
2242     delete m_renameTimer
; 
2245 void wxListMainWindow::CacheLineData(size_t line
) 
2247     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
2249     wxListLineData 
*ld 
= GetDummyLine(); 
2251     size_t countCol 
= GetColumnCount(); 
2252     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2254         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2257     ld
->SetImage(listctrl
->OnGetItemImage(line
)); 
2258     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
2261 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2263     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2265     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); 
2267     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2269     // we need to recreate the dummy line if the number of columns in the 
2270     // control changed as it would have the incorrect number of fields 
2272     if ( !m_lines
.IsEmpty() && 
2273             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
2275         self
->m_lines
.Clear(); 
2278     if ( m_lines
.IsEmpty() ) 
2280         wxListLineData 
*line 
= new wxListLineData(self
); 
2281         self
->m_lines
.Add(line
); 
2283         // don't waste extra memory -- there never going to be anything 
2284         // else/more in this array 
2285         self
->m_lines
.Shrink(); 
2291 // ---------------------------------------------------------------------------- 
2292 // line geometry (report mode only) 
2293 // ---------------------------------------------------------------------------- 
2295 wxCoord 
wxListMainWindow::GetLineHeight() const 
2297     // we cache the line height as calling GetTextExtent() is slow 
2298     if ( !m_lineHeight 
) 
2300         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2302         wxClientDC 
dc( self 
); 
2303         dc
.SetFont( GetFont() ); 
2306         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2308         if ( m_small_image_list 
&& m_small_image_list
->GetImageCount() ) 
2312             m_small_image_list
->GetSize(0, iw
, ih
); 
2317         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2320     return m_lineHeight
; 
2323 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2325     wxASSERT_MSG( InReportView(), _T("only works in report mode") ); 
2327     return LINE_SPACING 
+ line
*GetLineHeight(); 
2330 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2332     if ( !InReportView() ) 
2333         return GetLine(line
)->m_gi
->m_rectAll
; 
2336     rect
.x 
= HEADER_OFFSET_X
; 
2337     rect
.y 
= GetLineY(line
); 
2338     rect
.width 
= GetHeaderWidth(); 
2339     rect
.height 
= GetLineHeight(); 
2344 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2346     if ( !InReportView() ) 
2347         return GetLine(line
)->m_gi
->m_rectLabel
; 
2350     rect
.x 
= HEADER_OFFSET_X
; 
2351     rect
.y 
= GetLineY(line
); 
2352     rect
.width 
= GetColumnWidth(0); 
2353     rect
.height 
= GetLineHeight(); 
2358 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2360     if ( !InReportView() ) 
2361         return GetLine(line
)->m_gi
->m_rectIcon
; 
2363     wxListLineData 
*ld 
= GetLine(line
); 
2364     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2367     rect
.x 
= HEADER_OFFSET_X
; 
2368     rect
.y 
= GetLineY(line
); 
2369     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2374 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2376     return InReportView() ? GetLineRect(line
) 
2377                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2380 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2382     wxASSERT_MSG( line 
< GetItemCount(), _T("invalid line in HitTestLine") ); 
2384     wxListLineData 
*ld 
= GetLine(line
); 
2386     if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) ) 
2387         return wxLIST_HITTEST_ONITEMICON
; 
2389     // VS: Testing for "ld->HasText() || InReportView()" instead of 
2390     //     "ld->HasText()" is needed to make empty lines in report view 
2392     if ( ld
->HasText() || InReportView() ) 
2394         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2395                                      : GetLineLabelRect(line
); 
2397         if ( rect
.Inside(x
, y
) ) 
2398             return wxLIST_HITTEST_ONITEMLABEL
; 
2404 // ---------------------------------------------------------------------------- 
2405 // highlight (selection) handling 
2406 // ---------------------------------------------------------------------------- 
2408 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2412         return m_selStore
.IsSelected(line
); 
2416         wxListLineData 
*ld 
= GetLine(line
); 
2417         wxCHECK_MSG( ld
, false, _T("invalid index in IsHighlighted") ); 
2419         return ld
->IsHighlighted(); 
2423 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
2429         wxArrayInt linesChanged
; 
2430         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
2433             // meny items changed state, refresh everything 
2434             RefreshLines(lineFrom
, lineTo
); 
2436         else // only a few items changed state, refresh only them 
2438             size_t count 
= linesChanged
.GetCount(); 
2439             for ( size_t n 
= 0; n 
< count
; n
++ ) 
2441                 RefreshLine(linesChanged
[n
]); 
2445     else // iterate over all items in non report view 
2447         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2449             if ( HighlightLine(line
, highlight
) ) 
2457 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2463         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2467         wxListLineData 
*ld 
= GetLine(line
); 
2468         wxCHECK_MSG( ld
, false, _T("invalid index in HighlightLine") ); 
2470         changed 
= ld
->Highlight(highlight
); 
2475         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2476                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2482 void wxListMainWindow::RefreshLine( size_t line 
) 
2484     if ( InReportView() ) 
2486         size_t visibleFrom
, visibleTo
; 
2487         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2489         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
2493     wxRect rect 
= GetLineRect(line
); 
2495     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2496     RefreshRect( rect 
); 
2499 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2501     // we suppose that they are ordered by caller 
2502     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2504     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2506     if ( InReportView() ) 
2508         size_t visibleFrom
, visibleTo
; 
2509         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2511         if ( lineFrom 
< visibleFrom 
) 
2512             lineFrom 
= visibleFrom
; 
2513         if ( lineTo 
> visibleTo 
) 
2518         rect
.y 
= GetLineY(lineFrom
); 
2519         rect
.width 
= GetClientSize().x
; 
2520         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
2522         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2523         RefreshRect( rect 
); 
2527         // TODO: this should be optimized... 
2528         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2535 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2537     if ( InReportView() ) 
2539         size_t visibleFrom
, visibleTo
; 
2540         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2542         if ( lineFrom 
< visibleFrom 
) 
2543             lineFrom 
= visibleFrom
; 
2544         else if ( lineFrom 
> visibleTo 
) 
2549         rect
.y 
= GetLineY(lineFrom
); 
2550         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2552         wxSize size 
= GetClientSize(); 
2553         rect
.width 
= size
.x
; 
2554         // refresh till the bottom of the window 
2555         rect
.height 
= size
.y 
- rect
.y
; 
2557         RefreshRect( rect 
); 
2561         // TODO: how to do it more efficiently? 
2566 void wxListMainWindow::RefreshSelected() 
2572     if ( InReportView() ) 
2574         GetVisibleLinesRange(&from
, &to
); 
2579         to 
= GetItemCount() - 1; 
2582     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
2584         RefreshLine(m_current
); 
2587     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
2589         // NB: the test works as expected even if m_current == -1 
2590         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
2597 void wxListMainWindow::Freeze() 
2602 void wxListMainWindow::Thaw() 
2604     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen list control?") ); 
2606     if ( !--m_freezeCount 
) 
2612 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2614     // Note: a wxPaintDC must be constructed even if no drawing is 
2615     // done (a Windows requirement). 
2616     wxPaintDC 
dc( this ); 
2618     if ( IsEmpty() || m_freezeCount 
) 
2620         // nothing to draw or not the moment to draw it 
2626         // delay the repainting until we calculate all the items positions 
2633     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2637     dc
.SetFont( GetFont() ); 
2639     if ( InReportView() ) 
2641         int lineHeight 
= GetLineHeight(); 
2643         size_t visibleFrom
, visibleTo
; 
2644         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2647         wxCoord xOrig
, yOrig
; 
2648         CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
); 
2650         // tell the caller cache to cache the data 
2653             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2654                                 GetParent()->GetId()); 
2655             evCache
.SetEventObject( GetParent() ); 
2656             evCache
.m_oldItemIndex 
= visibleFrom
; 
2657             evCache
.m_itemIndex 
= visibleTo
; 
2658             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2661         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2663             rectLine 
= GetLineRect(line
); 
2665             if ( !IsExposed(rectLine
.x 
- xOrig
, rectLine
.y 
- yOrig
, 
2666                             rectLine
.width
, rectLine
.height
) ) 
2668                 // don't redraw unaffected lines to avoid flicker 
2672             GetLine(line
)->DrawInReportMode( &dc
, 
2674                                              GetLineHighlightRect(line
), 
2675                                              IsHighlighted(line
) ); 
2678         if ( HasFlag(wxLC_HRULES
) ) 
2680             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2681             wxSize clientSize 
= GetClientSize(); 
2683             // Don't draw the first one 
2684             for ( size_t i 
= visibleFrom
+1; i 
<= visibleTo
; i
++ ) 
2687                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2688                 dc
.DrawLine(0 - dev_x
, i
*lineHeight
, 
2689                             clientSize
.x 
- dev_x
, i
*lineHeight
); 
2692             // Draw last horizontal rule 
2693             if ( visibleTo 
== GetItemCount() - 1 ) 
2696                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2697                 dc
.DrawLine(0 - dev_x
, (m_lineTo
+1)*lineHeight
, 
2698                             clientSize
.x 
- dev_x 
, (m_lineTo
+1)*lineHeight 
); 
2702         // Draw vertical rules if required 
2703         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2705             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2707             wxRect firstItemRect
; 
2708             wxRect lastItemRect
; 
2709             GetItemRect(visibleFrom
, firstItemRect
); 
2710             GetItemRect(visibleTo
, lastItemRect
); 
2711             int x 
= firstItemRect
.GetX(); 
2713             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2714             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2716                 int colWidth 
= GetColumnWidth(col
); 
2718                 dc
.DrawLine(x 
- dev_x 
- 2, firstItemRect
.GetY() - 1 - dev_y
, 
2719                             x 
- dev_x 
- 2, lastItemRect
.GetBottom() + 1 - dev_y
); 
2725         size_t count 
= GetItemCount(); 
2726         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2728             GetLine(i
)->Draw( &dc 
); 
2733     // Don't draw rect outline under Mac at all. 
2738             dc
.SetPen( *wxBLACK_PEN 
); 
2739             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2740             dc
.DrawRectangle( GetLineHighlightRect(m_current
) ); 
2748 void wxListMainWindow::HighlightAll( bool on 
) 
2750     if ( IsSingleSel() ) 
2752         wxASSERT_MSG( !on
, _T("can't do this in a single sel control") ); 
2754         // we just have one item to turn off 
2755         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2757             HighlightLine(m_current
, false); 
2758             RefreshLine(m_current
); 
2763         HighlightLines(0, GetItemCount() - 1, on
); 
2767 void wxListMainWindow::SendNotify( size_t line
, 
2768                                    wxEventType command
, 
2771     wxListEvent 
le( command
, GetParent()->GetId() ); 
2772     le
.SetEventObject( GetParent() ); 
2773     le
.m_itemIndex 
= line
; 
2775     // set only for events which have position 
2776     if ( point 
!= wxDefaultPosition 
) 
2777         le
.m_pointDrag 
= point
; 
2779     // don't try to get the line info for virtual list controls: the main 
2780     // program has it anyhow and if we did it would result in accessing all 
2781     // the lines, even those which are not visible now and this is precisely 
2782     // what we're trying to avoid 
2783     if ( !IsVirtual() && (command 
!= wxEVT_COMMAND_LIST_DELETE_ITEM
) ) 
2785         if ( line 
!= (size_t)-1 ) 
2787             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2789         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2791     //else: there may be no more such item 
2793     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2796 void wxListMainWindow::ChangeCurrent(size_t current
) 
2798     m_current 
= current
; 
2800     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2803 void wxListMainWindow::EditLabel( long item 
) 
2805     wxCHECK_RET( (item 
>= 0) && ((size_t)item 
< GetItemCount()), 
2806                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2808     size_t itemEdit 
= (size_t)item
; 
2810     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2811     le
.SetEventObject( GetParent() ); 
2812     le
.m_itemIndex 
= item
; 
2813     wxListLineData 
*data 
= GetLine(itemEdit
); 
2814     wxCHECK_RET( data
, _T("invalid index in EditLabel()") ); 
2815     data
->GetItem( 0, le
.m_item 
); 
2816     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2818         // vetoed by user code 
2822     // We have to call this here because the label in question might just have 
2823     // been added and no screen update taken place. 
2827     wxListTextCtrl 
*text 
= new wxListTextCtrl(this, itemEdit
); 
2832 void wxListMainWindow::OnRenameTimer() 
2834     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2836     EditLabel( m_current 
); 
2839 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2841     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2842     le
.SetEventObject( GetParent() ); 
2843     le
.m_itemIndex 
= itemEdit
; 
2845     wxListLineData 
*data 
= GetLine(itemEdit
); 
2846     wxCHECK_MSG( data
, false, _T("invalid index in OnRenameAccept()") ); 
2848     data
->GetItem( 0, le
.m_item 
); 
2849     le
.m_item
.m_text 
= value
; 
2850     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2854 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2856     // let owner know that the edit was cancelled 
2857     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2859     le
.SetEditCanceled(true); 
2861     le
.SetEventObject( GetParent() ); 
2862     le
.m_itemIndex 
= itemEdit
; 
2864     wxListLineData 
*data 
= GetLine(itemEdit
); 
2865     wxCHECK_RET( data
, _T("invalid index in OnRenameCancelled()") ); 
2867     data
->GetItem( 0, le
.m_item 
); 
2869     GetEventHandler()->ProcessEvent( le 
); 
2872 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2874     event
.SetEventObject( GetParent() ); 
2875     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2878     if ( !HasCurrent() || IsEmpty() ) 
2884     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
2885         event
.ButtonDClick()) ) 
2888     int x 
= event
.GetX(); 
2889     int y 
= event
.GetY(); 
2890     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2892     // where did we hit it (if we did)? 
2895     size_t count 
= GetItemCount(), 
2898     if ( InReportView() ) 
2900         current 
= y 
/ GetLineHeight(); 
2901         if ( current 
< count 
) 
2902             hitResult 
= HitTestLine(current
, x
, y
); 
2906         // TODO: optimize it too! this is less simple than for report view but 
2907         //       enumerating all items is still not a way to do it!! 
2908         for ( current 
= 0; current 
< count
; current
++ ) 
2910             hitResult 
= HitTestLine(current
, x
, y
); 
2916     if (event
.Dragging()) 
2918         if (m_dragCount 
== 0) 
2920             // we have to report the raw, physical coords as we want to be 
2921             // able to call HitTest(event.m_pointDrag) from the user code to 
2922             // get the item being dragged 
2923             m_dragStart 
= event
.GetPosition(); 
2928         if (m_dragCount 
!= 3) 
2931         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
2932                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2934         wxListEvent 
le( command
, GetParent()->GetId() ); 
2935         le
.SetEventObject( GetParent() ); 
2936         le
.m_itemIndex 
= current
; 
2937         le
.m_pointDrag 
= m_dragStart
; 
2938         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2949         // outside of any item 
2953     bool forceClick 
= false; 
2954     if (event
.ButtonDClick()) 
2956         m_renameTimer
->Stop(); 
2957         m_lastOnSame 
= false; 
2959         if ( current 
== m_lineLastClicked 
) 
2961             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2967             // the first click was on another item, so don't interpret this as 
2968             // a double click, but as a simple click instead 
2973     if (event
.LeftUp() && m_lastOnSame
) 
2975         if ((current 
== m_current
) && 
2976             (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
2977             HasFlag(wxLC_EDIT_LABELS
)  ) 
2979             m_renameTimer
->Start( 100, true ); 
2981         m_lastOnSame 
= false; 
2983     else if (event
.RightDown()) 
2985         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, 
2986                     event
.GetPosition() ); 
2988     else if (event
.MiddleDown()) 
2990         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
2992     else if ( event
.LeftDown() || forceClick 
) 
2994         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2995         m_lineLastClicked 
= current
; 
2997         size_t oldCurrent 
= m_current
; 
2998         bool cmdModifierDown 
= event
.CmdDown(); 
2999         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
3001             HighlightAll( false ); 
3003             ChangeCurrent(current
); 
3005             ReverseHighlight(m_current
); 
3007         else // multi sel & either ctrl or shift is down 
3009             if (cmdModifierDown
) 
3011                 ChangeCurrent(current
); 
3013                 ReverseHighlight(m_current
); 
3015             else if (event
.ShiftDown()) 
3017                 ChangeCurrent(current
); 
3019                 size_t lineFrom 
= oldCurrent
, 
3022                 if ( lineTo 
< lineFrom 
) 
3025                     lineFrom 
= m_current
; 
3028                 HighlightLines(lineFrom
, lineTo
); 
3030             else // !ctrl, !shift 
3032                 // test in the enclosing if should make it impossible 
3033                 wxFAIL_MSG( _T("how did we get here?") ); 
3037         if (m_current 
!= oldCurrent
) 
3039             RefreshLine( oldCurrent 
); 
3042         // forceClick is only set if the previous click was on another item 
3043         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
); 
3047 void wxListMainWindow::MoveToItem(size_t item
) 
3049     if ( item 
== (size_t)-1 ) 
3052     wxRect rect 
= GetLineRect(item
); 
3054     int client_w
, client_h
; 
3055     GetClientSize( &client_w
, &client_h 
); 
3057     const int hLine 
= GetLineHeight(); 
3059     int view_x 
= SCROLL_UNIT_X
*GetScrollPos( wxHORIZONTAL 
); 
3060     int view_y 
= hLine
*GetScrollPos( wxVERTICAL 
); 
3062     if ( InReportView() ) 
3064         // the next we need the range of lines shown it might be different, so 
3066         ResetVisibleLinesRange(); 
3068         if (rect
.y 
< view_y 
) 
3069             Scroll( -1, rect
.y
/hLine 
); 
3070         if (rect
.y
+rect
.height
+5 > view_y
+client_h
) 
3071             Scroll( -1, (rect
.y
+rect
.height
-client_h
+hLine
)/hLine 
); 
3075         if (rect
.x
-view_x 
< 5) 
3076             Scroll( (rect
.x
-5)/SCROLL_UNIT_X
, -1 ); 
3077         if (rect
.x
+rect
.width
-5 > view_x
+client_w
) 
3078             Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/SCROLL_UNIT_X
, -1 ); 
3082 // ---------------------------------------------------------------------------- 
3083 // keyboard handling 
3084 // ---------------------------------------------------------------------------- 
3086 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
3088     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
3089                  _T("invalid item index in OnArrowChar()") ); 
3091     size_t oldCurrent 
= m_current
; 
3093     // in single selection we just ignore Shift as we can't select several 
3095     if ( event
.ShiftDown() && !IsSingleSel() ) 
3097         ChangeCurrent(newCurrent
); 
3099         // refresh the old focus to remove it 
3100         RefreshLine( oldCurrent 
); 
3102         // select all the items between the old and the new one 
3103         if ( oldCurrent 
> newCurrent 
) 
3105             newCurrent 
= oldCurrent
; 
3106             oldCurrent 
= m_current
; 
3109         HighlightLines(oldCurrent
, newCurrent
); 
3113         // all previously selected items are unselected unless ctrl is held 
3114         if ( !event
.ControlDown() ) 
3115             HighlightAll(false); 
3117         ChangeCurrent(newCurrent
); 
3119         // refresh the old focus to remove it 
3120         RefreshLine( oldCurrent 
); 
3122         if ( !event
.ControlDown() ) 
3124             HighlightLine( m_current
, true ); 
3128     RefreshLine( m_current 
); 
3133 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
3135     wxWindow 
*parent 
= GetParent(); 
3137     /* we propagate the key event up */ 
3138     wxKeyEvent 
ke( wxEVT_KEY_DOWN 
); 
3139     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3140     ke
.m_controlDown 
= event
.m_controlDown
; 
3141     ke
.m_altDown 
= event
.m_altDown
; 
3142     ke
.m_metaDown 
= event
.m_metaDown
; 
3143     ke
.m_keyCode 
= event
.m_keyCode
; 
3146     ke
.SetEventObject( parent 
); 
3147     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3152 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
3154     wxWindow 
*parent 
= GetParent(); 
3156     /* we send a list_key event up */ 
3159         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
3160         le
.m_itemIndex 
= m_current
; 
3161         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3162         le
.m_code 
= event
.GetKeyCode(); 
3163         le
.SetEventObject( parent 
); 
3164         parent
->GetEventHandler()->ProcessEvent( le 
); 
3167     /* we propagate the char event up */ 
3168     wxKeyEvent 
ke( wxEVT_CHAR 
); 
3169     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3170     ke
.m_controlDown 
= event
.m_controlDown
; 
3171     ke
.m_altDown 
= event
.m_altDown
; 
3172     ke
.m_metaDown 
= event
.m_metaDown
; 
3173     ke
.m_keyCode 
= event
.m_keyCode
; 
3176     ke
.SetEventObject( parent 
); 
3177     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3179     if (event
.GetKeyCode() == WXK_TAB
) 
3181         wxNavigationKeyEvent nevent
; 
3182         nevent
.SetWindowChange( event
.ControlDown() ); 
3183         nevent
.SetDirection( !event
.ShiftDown() ); 
3184         nevent
.SetEventObject( GetParent()->GetParent() ); 
3185         nevent
.SetCurrentFocus( m_parent 
); 
3186         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent 
)) 
3190     /* no item -> nothing to do */ 
3197     switch (event
.GetKeyCode()) 
3200             if ( m_current 
> 0 ) 
3201                 OnArrowChar( m_current 
- 1, event 
); 
3205             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
3206                 OnArrowChar( m_current 
+ 1, event 
); 
3211                 OnArrowChar( GetItemCount() - 1, event 
); 
3216                 OnArrowChar( 0, event 
); 
3221                 int steps 
= InReportView() ? m_linesPerPage 
- 1 : m_current 
% m_linesPerPage
; 
3223                 int index 
= m_current 
- steps
; 
3227                 OnArrowChar( index
, event 
); 
3233                 int steps 
= InReportView() 
3234                                ? m_linesPerPage 
- 1 
3235                                : m_linesPerPage 
- (m_current 
% m_linesPerPage
) - 1; 
3237                 size_t index 
= m_current 
+ steps
; 
3238                 size_t count 
= GetItemCount(); 
3239                 if ( index 
>= count 
) 
3242                 OnArrowChar( index
, event 
); 
3247             if ( !InReportView() ) 
3249                 int index 
= m_current 
- m_linesPerPage
; 
3253                 OnArrowChar( index
, event 
); 
3258             if ( !InReportView() ) 
3260                 size_t index 
= m_current 
+ m_linesPerPage
; 
3262                 size_t count 
= GetItemCount(); 
3263                 if ( index 
>= count 
) 
3266                 OnArrowChar( index
, event 
); 
3271             if ( IsSingleSel() ) 
3273                 SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3275                 if ( IsHighlighted(m_current
) ) 
3277                     // don't unselect the item in single selection mode 
3280                 //else: select it in ReverseHighlight() below if unselected 
3283             ReverseHighlight(m_current
); 
3288             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3296 // ---------------------------------------------------------------------------- 
3298 // ---------------------------------------------------------------------------- 
3300 void wxListMainWindow::SetFocus() 
3302     // VS: wxListMainWindow derives from wxPanel (via wxScrolledWindow) and wxPanel 
3303     //     overrides SetFocus in such way that it does never change focus from 
3304     //     panel's child to the panel itself. Unfortunately, we must be able to change 
3305     //     focus to the panel from wxListTextCtrl because the text control should 
3306     //     disappear when the user clicks outside it. 
3308     wxWindow 
*oldFocus 
= FindFocus(); 
3310     if ( oldFocus 
&& oldFocus
->GetParent() == this ) 
3312         wxWindow::SetFocus(); 
3316         wxScrolledWindow::SetFocus(); 
3320 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3324         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3325         event
.SetEventObject( GetParent() ); 
3326         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3330     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
3331     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
3332     // which are already drawn correctly resulting in horrible flicker - avoid 
3342 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3346         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
3347         event
.SetEventObject( GetParent() ); 
3348         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3355 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3357     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3359         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3361     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3363         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3365     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3367         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3369     else if ( InReportView() && (m_small_image_list
)) 
3371         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3375 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3377     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3379         m_normal_image_list
->GetSize( index
, width
, height 
); 
3381     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3383         m_small_image_list
->GetSize( index
, width
, height 
); 
3385     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3387         m_small_image_list
->GetSize( index
, width
, height 
); 
3389     else if ( InReportView() && m_small_image_list 
) 
3391         m_small_image_list
->GetSize( index
, width
, height 
); 
3400 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3402     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3403     dc
.SetFont( GetFont() ); 
3406     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3408     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3411 void wxListMainWindow::SetImageList( wxImageListType 
*imageList
, int which 
) 
3415     // calc the spacing from the icon size 
3418     if ((imageList
) && (imageList
->GetImageCount()) ) 
3420         imageList
->GetSize(0, width
, height
); 
3423     if (which 
== wxIMAGE_LIST_NORMAL
) 
3425         m_normal_image_list 
= imageList
; 
3426         m_normal_spacing 
= width 
+ 8; 
3429     if (which 
== wxIMAGE_LIST_SMALL
) 
3431         m_small_image_list 
= imageList
; 
3432         m_small_spacing 
= width 
+ 14; 
3433         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
3437 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3442         m_small_spacing 
= spacing
; 
3446         m_normal_spacing 
= spacing
; 
3450 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3452     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3455 // ---------------------------------------------------------------------------- 
3457 // ---------------------------------------------------------------------------- 
3459 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3461     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3463     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3465     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3466         item
.m_width 
= GetTextLength( item
.m_text 
); 
3468     wxListHeaderData 
*column 
= node
->GetData(); 
3469     column
->SetItem( item 
); 
3471     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3473         headerWin
->m_dirty 
= true; 
3477     // invalidate it as it has to be recalculated 
3481 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3483     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3484                  _T("invalid column index") ); 
3486     wxCHECK_RET( InReportView(), 
3487                  _T("SetColumnWidth() can only be called in report mode.") ); 
3490     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3492         headerWin
->m_dirty 
= true; 
3494     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3495     wxCHECK_RET( node
, _T("no column?") ); 
3497     wxListHeaderData 
*column 
= node
->GetData(); 
3499     size_t count 
= GetItemCount(); 
3501     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3503         width 
= GetTextLength(column
->GetText()); 
3505     else if ( width 
== wxLIST_AUTOSIZE 
) 
3509             // TODO: determine the max width somehow... 
3510             width 
= WIDTH_COL_DEFAULT
; 
3514             wxClientDC 
dc(this); 
3515             dc
.SetFont( GetFont() ); 
3517             int max 
= AUTOSIZE_COL_MARGIN
; 
3519             for ( size_t i 
= 0; i 
< count
; i
++ ) 
3521                 wxListLineData 
*line 
= GetLine(i
); 
3522                 wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3524                 wxCHECK_RET( n
, _T("no subitem?") ); 
3526                 wxListItemData 
*item 
= n
->GetData(); 
3529                 if (item
->HasImage()) 
3532                     GetImageSize( item
->GetImage(), ix
, iy 
); 
3536                 if (item
->HasText()) 
3539                     dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
3547             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3551     column
->SetWidth( width 
); 
3553     // invalidate it as it has to be recalculated 
3557 int wxListMainWindow::GetHeaderWidth() const 
3559     if ( !m_headerWidth 
) 
3561         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3563         size_t count 
= GetColumnCount(); 
3564         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3566             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3570     return m_headerWidth
; 
3573 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3575     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3576     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3578     wxListHeaderData 
*column 
= node
->GetData(); 
3579     column
->GetItem( item 
); 
3582 int wxListMainWindow::GetColumnWidth( int col 
) const 
3584     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3585     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3587     wxListHeaderData 
*column 
= node
->GetData(); 
3588     return column
->GetWidth(); 
3591 // ---------------------------------------------------------------------------- 
3593 // ---------------------------------------------------------------------------- 
3595 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3597     long id 
= item
.m_itemId
; 
3598     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3599                  _T("invalid item index in SetItem") ); 
3603         wxListLineData 
*line 
= GetLine((size_t)id
); 
3604         line
->SetItem( item
.m_col
, item 
); 
3607     // update the item on screen 
3609     GetItemRect(id
, rectItem
); 
3610     RefreshRect(rectItem
); 
3613 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3615      wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3616                   _T("invalid list ctrl item index in SetItem") ); 
3618     size_t oldCurrent 
= m_current
; 
3619     size_t item 
= (size_t)litem
;    // safe because of the check above 
3621     // do we need to change the focus? 
3622     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3624         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3626             // don't do anything if this item is already focused 
3627             if ( item 
!= m_current 
) 
3629                 ChangeCurrent(item
); 
3631                 if ( oldCurrent 
!= (size_t)-1 ) 
3633                     if ( IsSingleSel() ) 
3635                         HighlightLine(oldCurrent
, false); 
3638                     RefreshLine(oldCurrent
); 
3641                 RefreshLine( m_current 
); 
3646             // don't do anything if this item is not focused 
3647             if ( item 
== m_current 
) 
3651                 if ( IsSingleSel() ) 
3653                     // we must unselect the old current item as well or we 
3654                     // might end up with more than one selected item in a 
3655                     // single selection control 
3656                     HighlightLine(oldCurrent
, false); 
3659                 RefreshLine( oldCurrent 
); 
3664     // do we need to change the selection state? 
3665     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3667         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3669         if ( IsSingleSel() ) 
3673                 // selecting the item also makes it the focused one in the 
3675                 if ( m_current 
!= item 
) 
3677                     ChangeCurrent(item
); 
3679                     if ( oldCurrent 
!= (size_t)-1 ) 
3681                         HighlightLine( oldCurrent
, false ); 
3682                         RefreshLine( oldCurrent 
); 
3688                 // only the current item may be selected anyhow 
3689                 if ( item 
!= m_current 
) 
3694         if ( HighlightLine(item
, on
) ) 
3701 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
3703     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3704                  _T("invalid list ctrl item index in GetItemState()") ); 
3706     int ret 
= wxLIST_STATE_DONTCARE
; 
3708     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3710         if ( (size_t)item 
== m_current 
) 
3711             ret 
|= wxLIST_STATE_FOCUSED
; 
3714     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3716         if ( IsHighlighted(item
) ) 
3717             ret 
|= wxLIST_STATE_SELECTED
; 
3723 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
3725     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3726                  _T("invalid item index in GetItem") ); 
3728     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3729     line
->GetItem( item
.m_col
, item 
); 
3732 // ---------------------------------------------------------------------------- 
3734 // ---------------------------------------------------------------------------- 
3736 size_t wxListMainWindow::GetItemCount() const 
3738     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3741 void wxListMainWindow::SetItemCount(long count
) 
3743     m_selStore
.SetItemCount(count
); 
3744     m_countVirt 
= count
; 
3746     ResetVisibleLinesRange(); 
3748     // scrollbars must be reset 
3752 int wxListMainWindow::GetSelectedItemCount() const 
3754     // deal with the quick case first 
3755     if ( IsSingleSel() ) 
3757         return HasCurrent() ? IsHighlighted(m_current
) : false; 
3760     // virtual controls remmebers all its selections itself 
3762         return m_selStore
.GetSelectedCount(); 
3764     // TODO: we probably should maintain the number of items selected even for 
3765     //       non virtual controls as enumerating all lines is really slow... 
3766     size_t countSel 
= 0; 
3767     size_t count 
= GetItemCount(); 
3768     for ( size_t line 
= 0; line 
< count
; line
++ ) 
3770         if ( GetLine(line
)->IsHighlighted() ) 
3777 // ---------------------------------------------------------------------------- 
3778 // item position/size 
3779 // ---------------------------------------------------------------------------- 
3781 wxRect 
wxListMainWindow::GetViewRect() const 
3783     wxASSERT_MSG( !HasFlag(wxLC_REPORT 
| wxLC_LIST
), 
3784                     _T("wxListCtrl::GetViewRect() only works in icon mode") ); 
3786     // we need to find the longest/tallest label 
3789     const int count 
= GetItemCount(); 
3792         for ( int i 
= 0; i 
< count
; i
++ ) 
3797             wxCoord x 
= r
.GetRight(), 
3807     // some fudge needed to make it look prettier 
3808     xMax 
+= 2*EXTRA_BORDER_X
; 
3809     yMax 
+= 2*EXTRA_BORDER_Y
; 
3811     // account for the scrollbars if necessary 
3812     const wxSize sizeAll 
= GetClientSize(); 
3813     if ( xMax 
> sizeAll
.x 
) 
3814         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
3815     if ( yMax 
> sizeAll
.y 
) 
3816         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
3818     return wxRect(0, 0, xMax
, yMax
); 
3821 void wxListMainWindow::GetItemRect( long index
, wxRect 
&rect 
) const 
3823     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3824                  _T("invalid index in GetItemRect") ); 
3826     // ensure that we're laid out, otherwise we could return nonsense 
3829         wxConstCast(this, wxListMainWindow
)-> 
3830             RecalculatePositions(true /* no refresh */); 
3833     rect 
= GetLineRect((size_t)index
); 
3835     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
3838 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
3841     GetItemRect(item
, rect
); 
3849 // ---------------------------------------------------------------------------- 
3850 // geometry calculation 
3851 // ---------------------------------------------------------------------------- 
3853 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
3855     wxClientDC 
dc( this ); 
3856     dc
.SetFont( GetFont() ); 
3858     const size_t count 
= GetItemCount(); 
3861     if ( HasFlag(wxLC_ICON
) ) 
3862         iconSpacing 
= m_normal_spacing
; 
3863     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
3864         iconSpacing 
= m_small_spacing
; 
3868     // Note that we do not call GetClientSize() here but 
3869     // GetSize() and substract the border size for sunken 
3870     // borders manually. This is technically incorrect, 
3871     // but we need to know the client area's size WITHOUT 
3872     // scrollbars here. Since we don't know if there are 
3873     // any scrollbars, we use GetSize() instead. Another 
3874     // solution would be to call SetScrollbars() here to 
3875     // remove the scrollbars and call GetClientSize() then, 
3876     // but this might result in flicker and - worse - will 
3877     // reset the scrollbars to 0 which is not good at all 
3878     // if you resize a dialog/window, but don't want to 
3879     // reset the window scrolling. RR. 
3880     // Furthermore, we actually do NOT subtract the border 
3881     // width as 2 pixels is just the extra space which we 
3882     // need around the actual content in the window. Other- 
3883     // wise the text would e.g. touch the upper border. RR. 
3886     GetSize( &clientWidth
, &clientHeight 
); 
3888     const int lineHeight 
= GetLineHeight(); 
3890     if ( InReportView() ) 
3892         // all lines have the same height and we scroll one line per step 
3893         int entireHeight 
= count
*lineHeight 
+ LINE_SPACING
; 
3895         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
3897         ResetVisibleLinesRange(); 
3899         SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
3900                        GetHeaderWidth() / SCROLL_UNIT_X
, 
3901                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
3902                        GetScrollPos(wxHORIZONTAL
), 
3903                        GetScrollPos(wxVERTICAL
), 
3908         // we have 3 different layout strategies: either layout all items 
3909         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
3910         // to arrange them in top to bottom, left to right (don't ask me why 
3911         // not the other way round...) order 
3912         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
3914             int x 
= EXTRA_BORDER_X
; 
3915             int y 
= EXTRA_BORDER_Y
; 
3917             wxCoord widthMax 
= 0; 
3920             for ( i 
= 0; i 
< count
; i
++ ) 
3922                 wxListLineData 
*line 
= GetLine(i
); 
3923                 line
->CalculateSize( &dc
, iconSpacing 
); 
3924                 line
->SetPosition( x
, y
, iconSpacing 
); 
3926                 wxSize sizeLine 
= GetLineSize(i
); 
3928                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3930                     if ( sizeLine
.x 
> widthMax 
) 
3931                         widthMax 
= sizeLine
.x
; 
3935                 else // wxLC_ALIGN_LEFT 
3937                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
3941             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3943                 // traverse the items again and tweak their sizes so that they are 
3944                 // all the same in a row 
3945                 for ( i 
= 0; i 
< count
; i
++ ) 
3947                     wxListLineData 
*line 
= GetLine(i
); 
3948                     line
->m_gi
->ExtendWidth(widthMax
); 
3957                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3958                 (y 
+ lineHeight
) / lineHeight
, 
3959                 GetScrollPos( wxHORIZONTAL 
), 
3960                 GetScrollPos( wxVERTICAL 
), 
3964         else // "flowed" arrangement, the most complicated case 
3966             // at first we try without any scrollbars, if the items don't fit into 
3967             // the window, we recalculate after subtracting the space taken by the 
3970             int entireWidth 
= 0; 
3972             for (int tries 
= 0; tries 
< 2; tries
++) 
3974                 entireWidth 
= 2*EXTRA_BORDER_X
; 
3978                     // Now we have decided that the items do not fit into the 
3979                     // client area, so we need a scrollbar 
3980                     entireWidth 
+= SCROLL_UNIT_X
; 
3983                 int x 
= EXTRA_BORDER_X
; 
3984                 int y 
= EXTRA_BORDER_Y
; 
3985                 int maxWidthInThisRow 
= 0; 
3988                 int currentlyVisibleLines 
= 0; 
3990                 for (size_t i 
= 0; i 
< count
; i
++) 
3992                     currentlyVisibleLines
++; 
3993                     wxListLineData 
*line 
= GetLine(i
); 
3994                     line
->CalculateSize( &dc
, iconSpacing 
); 
3995                     line
->SetPosition( x
, y
, iconSpacing 
); 
3997                     wxSize sizeLine 
= GetLineSize(i
); 
3999                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
4000                         maxWidthInThisRow 
= sizeLine
.x
; 
4003                     if (currentlyVisibleLines 
> m_linesPerPage
) 
4004                         m_linesPerPage 
= currentlyVisibleLines
; 
4006                     if ( y 
+ sizeLine
.y 
>= clientHeight 
) 
4008                         currentlyVisibleLines 
= 0; 
4010                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
4011                         x 
+= maxWidthInThisRow
; 
4012                         entireWidth 
+= maxWidthInThisRow
; 
4013                         maxWidthInThisRow 
= 0; 
4016                     // We have reached the last item. 
4017                     if ( i 
== count 
- 1 ) 
4018                         entireWidth 
+= maxWidthInThisRow
; 
4020                     if ( (tries 
== 0) && 
4021                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
4023                         clientHeight 
-= wxSystemSettings:: 
4024                                             GetMetric(wxSYS_HSCROLL_Y
); 
4029                     if ( i 
== count 
- 1 ) 
4030                         tries 
= 1;  // Everything fits, no second try required. 
4038                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4040                 GetScrollPos( wxHORIZONTAL 
), 
4049         // FIXME: why should we call it from here? 
4056 void wxListMainWindow::RefreshAll() 
4061     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
4062     if ( headerWin 
&& headerWin
->m_dirty 
) 
4064         headerWin
->m_dirty 
= false; 
4065         headerWin
->Refresh(); 
4069 void wxListMainWindow::UpdateCurrent() 
4071     if ( !HasCurrent() && !IsEmpty() ) 
4077 long wxListMainWindow::GetNextItem( long item
, 
4078                                     int WXUNUSED(geometry
), 
4082          max 
= GetItemCount(); 
4083     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
4084                  _T("invalid listctrl index in GetNextItem()") ); 
4086     // notice that we start with the next item (or the first one if item == -1) 
4087     // and this is intentional to allow writing a simple loop to iterate over 
4088     // all selected items 
4092         // this is not an error because the index was ok initially, just no 
4103     size_t count 
= GetItemCount(); 
4104     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
4106         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
4109         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
4116 // ---------------------------------------------------------------------------- 
4118 // ---------------------------------------------------------------------------- 
4120 void wxListMainWindow::DeleteItem( long lindex 
) 
4122     size_t count 
= GetItemCount(); 
4124     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
4125                  _T("invalid item index in DeleteItem") ); 
4127     size_t index 
= (size_t)lindex
; 
4129     // we don't need to adjust the index for the previous items 
4130     if ( HasCurrent() && m_current 
>= index 
) 
4132         // if the current item is being deleted, we want the next one to 
4133         // become selected - unless there is no next one - so don't adjust 
4134         // m_current in this case 
4135         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
4141     if ( InReportView() ) 
4143         ResetVisibleLinesRange(); 
4150         m_selStore
.OnItemDelete(index
); 
4154         m_lines
.RemoveAt( index 
); 
4157     // we need to refresh the (vert) scrollbar as the number of items changed 
4160     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM 
); 
4162     RefreshAfter(index
); 
4165 void wxListMainWindow::DeleteColumn( int col 
) 
4167     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4169     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
4172     delete node
->GetData(); 
4173     m_columns
.Erase( node 
); 
4177         // update all the items 
4178         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4180             wxListLineData 
* const line 
= GetLine(i
); 
4181             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
4182             delete n
->GetData(); 
4183             line
->m_items
.Erase(n
); 
4187     // invalidate it as it has to be recalculated 
4191 void wxListMainWindow::DoDeleteAllItems() 
4195         // nothing to do - in particular, don't send the event 
4201     // to make the deletion of all items faster, we don't send the 
4202     // notifications for each item deletion in this case but only one event 
4203     // for all of them: this is compatible with wxMSW and documented in 
4204     // DeleteAllItems() description 
4206     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
4207     event
.SetEventObject( GetParent() ); 
4208     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
4217     if ( InReportView() ) 
4219         ResetVisibleLinesRange(); 
4225 void wxListMainWindow::DeleteAllItems() 
4229     RecalculatePositions(); 
4232 void wxListMainWindow::DeleteEverything() 
4234     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
4239 // ---------------------------------------------------------------------------- 
4240 // scanning for an item 
4241 // ---------------------------------------------------------------------------- 
4243 void wxListMainWindow::EnsureVisible( long index 
) 
4245     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4246                  _T("invalid index in EnsureVisible") ); 
4248     // We have to call this here because the label in question might just have 
4249     // been added and its position is not known yet 
4252         RecalculatePositions(true /* no refresh */); 
4255     MoveToItem((size_t)index
); 
4258 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) ) 
4265     size_t count 
= GetItemCount(); 
4266     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
4268         wxListLineData 
*line 
= GetLine(i
); 
4269         if ( line
->GetText(0) == tmp 
) 
4276 long wxListMainWindow::FindItem(long start
, wxUIntPtr data
) 
4282     size_t count 
= GetItemCount(); 
4283     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4285         wxListLineData 
*line 
= GetLine(i
); 
4287         line
->GetItem( 0, item 
); 
4288         if (item
.m_data 
== data
) 
4295 long wxListMainWindow::FindItem( const wxPoint
& pt 
) 
4298     GetVisibleLinesRange(&topItem
, NULL
); 
4301     GetItemPosition( GetItemCount()-1, p 
); 
4304     long id 
= (long) floor( pt
.y
*double(GetItemCount()-topItem
-1)/p
.y
+topItem 
); 
4305     if( id 
>= 0 && id 
< (long)GetItemCount() ) 
4311 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) 
4313     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4315     size_t count 
= GetItemCount(); 
4317     if ( InReportView() ) 
4319         size_t current 
= y 
/ GetLineHeight(); 
4320         if ( current 
< count 
) 
4322             flags 
= HitTestLine(current
, x
, y
); 
4329         // TODO: optimize it too! this is less simple than for report view but 
4330         //       enumerating all items is still not a way to do it!! 
4331         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4333             flags 
= HitTestLine(current
, x
, y
); 
4342 // ---------------------------------------------------------------------------- 
4344 // ---------------------------------------------------------------------------- 
4346 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4348     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
4350     int count 
= GetItemCount(); 
4351     wxCHECK_RET( item
.m_itemId 
>= 0, _T("invalid item index") ); 
4353     if (item
.m_itemId 
> count
) 
4354         item
.m_itemId 
= count
; 
4356     size_t id 
= item
.m_itemId
; 
4361     // this is unused variable 
4364     if ( InReportView() ) 
4367         // this is unused variable 
4370         ResetVisibleLinesRange(); 
4372     else if ( HasFlag(wxLC_LIST
) ) 
4374         // this is unused variable 
4379     else if ( HasFlag(wxLC_ICON
) ) 
4381         // this is unused variable 
4386     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
4388         // this is unused variable 
4389         mode 
= wxLC_ICON
;  // no typo 
4395         wxFAIL_MSG( _T("unknown mode") ); 
4398     wxListLineData 
*line 
= new wxListLineData(this); 
4400     line
->SetItem( 0, item 
); 
4402     m_lines
.Insert( line
, id 
); 
4406     // If an item is selected at or below the point of insertion, we need to 
4407     // increment the member variables because the current row's index has gone 
4409     if ( HasCurrent() && m_current 
>= id 
) 
4414     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4416     RefreshLines(id
, GetItemCount() - 1); 
4419 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4422     if ( InReportView() ) 
4424         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4425             item
.m_width 
= GetTextLength( item
.m_text 
); 
4427         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4428         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4431             wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4432             m_columns
.Insert( node
, column 
); 
4436             m_columns
.Append( column 
); 
4441             // update all the items 
4442             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4444                 wxListLineData 
* const line 
= GetLine(i
); 
4445                 wxListItemData 
* const data 
= new wxListItemData(this); 
4447                     line
->m_items
.Insert(col
, data
); 
4449                     line
->m_items
.Append(data
); 
4453         // invalidate it as it has to be recalculated 
4458 // ---------------------------------------------------------------------------- 
4460 // ---------------------------------------------------------------------------- 
4462 wxListCtrlCompare list_ctrl_compare_func_2
; 
4463 long              list_ctrl_compare_data
; 
4465 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4467     wxListLineData 
*line1 
= *arg1
; 
4468     wxListLineData 
*line2 
= *arg2
; 
4470     line1
->GetItem( 0, item 
); 
4471     wxUIntPtr data1 
= item
.m_data
; 
4472     line2
->GetItem( 0, item 
); 
4473     wxUIntPtr data2 
= item
.m_data
; 
4474     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4477 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
4479     list_ctrl_compare_func_2 
= fn
; 
4480     list_ctrl_compare_data 
= data
; 
4481     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4485 // ---------------------------------------------------------------------------- 
4487 // ---------------------------------------------------------------------------- 
4489 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4491     // update our idea of which lines are shown when we redraw the window the 
4493     ResetVisibleLinesRange(); 
4496 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
4497     wxScrolledWindow::OnScroll(event
); 
4499     HandleOnScroll( event 
); 
4502     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4504         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4505         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4507         lc
->m_headerWin
->Refresh(); 
4508         lc
->m_headerWin
->Update(); 
4512 int wxListMainWindow::GetCountPerPage() const 
4514     if ( !m_linesPerPage 
) 
4516         wxConstCast(this, wxListMainWindow
)-> 
4517             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4520     return m_linesPerPage
; 
4523 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4525     wxASSERT_MSG( InReportView(), _T("this is for report mode only") ); 
4527     if ( m_lineFrom 
== (size_t)-1 ) 
4529         size_t count 
= GetItemCount(); 
4532             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4534             // this may happen if SetScrollbars() hadn't been called yet 
4535             if ( m_lineFrom 
>= count 
) 
4536                 m_lineFrom 
= count 
- 1; 
4538             // we redraw one extra line but this is needed to make the redrawing 
4539             // logic work when there is a fractional number of lines on screen 
4540             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4541             if ( m_lineTo 
>= count 
) 
4542                 m_lineTo 
= count 
- 1; 
4544         else // empty control 
4547             m_lineTo 
= (size_t)-1; 
4551     wxASSERT_MSG( IsEmpty() || 
4552                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4553                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4561 // ------------------------------------------------------------------------------------- 
4562 // wxGenericListCtrl 
4563 // ------------------------------------------------------------------------------------- 
4565 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4567 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4568   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4571 wxGenericListCtrl::wxGenericListCtrl() 
4573     m_imageListNormal 
= (wxImageListType 
*) NULL
; 
4574     m_imageListSmall 
= (wxImageListType 
*) NULL
; 
4575     m_imageListState 
= (wxImageListType 
*) NULL
; 
4577     m_ownsImageListNormal 
= 
4578     m_ownsImageListSmall 
= 
4579     m_ownsImageListState 
= false; 
4581     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4582     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4586 wxGenericListCtrl::~wxGenericListCtrl() 
4588     if (m_ownsImageListNormal
) 
4589         delete m_imageListNormal
; 
4590     if (m_ownsImageListSmall
) 
4591         delete m_imageListSmall
; 
4592     if (m_ownsImageListState
) 
4593         delete m_imageListState
; 
4596 void wxGenericListCtrl::CalculateAndSetHeaderHeight() 
4600         // we use 'g' to get the descent, too 
4602         m_headerWin
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
); 
4603         h 
+= d 
+ 2 * HEADER_OFFSET_Y 
+ EXTRA_HEIGHT
; 
4605         // only update if changed 
4606         if ( h 
!= m_headerHeight 
) 
4610             m_headerWin
->SetSize(m_headerWin
->GetSize().x
, m_headerHeight
); 
4613                 ResizeReportView(true); 
4618 void wxGenericListCtrl::CreateHeaderWindow() 
4620     m_headerWin 
= new wxListHeaderWindow
 
4622                         this, wxID_ANY
, m_mainWin
, 
4624                         wxSize(GetClientSize().x
, m_headerHeight
), 
4627     CalculateAndSetHeaderHeight(); 
4630 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
4635                         const wxValidator 
&validator
, 
4636                         const wxString 
&name
) 
4640     m_imageListState 
= (wxImageListType 
*) NULL
; 
4641     m_ownsImageListNormal 
= 
4642     m_ownsImageListSmall 
= 
4643     m_ownsImageListState 
= false; 
4645     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4646     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4650     if ( !(style 
& wxLC_MASK_TYPE
) ) 
4652         style 
= style 
| wxLC_LIST
; 
4655     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
4658     // don't create the inner window with the border 
4659     style 
&= ~wxBORDER_MASK
; 
4661     m_mainWin 
= new wxListMainWindow( this, wxID_ANY
, wxPoint(0,0), size
, style 
); 
4663 #if defined( __WXMAC__ ) && __WXMAC_CARBON__ 
4664     // Human Interface Guidelines ask us for a special font in this case 
4665     if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL 
) 
4668         font
.MacCreateThemeFont( kThemeViewsFont 
) ; 
4672     if ( InReportView() ) 
4674         CreateHeaderWindow(); 
4676         if ( HasFlag(wxLC_NO_HEADER
) ) 
4678             // VZ: why do we create it at all then? 
4679             m_headerWin
->Show( false ); 
4688 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
4690     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4691                   _T("wxLC_VIRTUAL can't be [un]set") ); 
4693     long flag 
= GetWindowStyle(); 
4697         if (style 
& wxLC_MASK_TYPE
) 
4698             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4699         if (style 
& wxLC_MASK_ALIGN
) 
4700             flag 
&= ~wxLC_MASK_ALIGN
; 
4701         if (style 
& wxLC_MASK_SORT
) 
4702             flag 
&= ~wxLC_MASK_SORT
; 
4714     SetWindowStyleFlag( flag 
); 
4717 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
4721         m_mainWin
->DeleteEverything(); 
4723         // has the header visibility changed? 
4724         bool hasHeader 
= HasHeader(); 
4725         bool willHaveHeader 
= (flag 
& wxLC_REPORT
) && !(flag 
& wxLC_NO_HEADER
); 
4727         if ( hasHeader 
!= willHaveHeader 
) 
4734                     // don't delete, just hide, as we can reuse it later 
4735                     m_headerWin
->Show(false); 
4737                 //else: nothing to do 
4739             else // must show header 
4743                     CreateHeaderWindow(); 
4745                 else // already have it, just show 
4747                     m_headerWin
->Show( true ); 
4751             ResizeReportView(willHaveHeader
); 
4755     wxWindow::SetWindowStyleFlag( flag 
); 
4758 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4760     m_mainWin
->GetColumn( col
, item 
); 
4764 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
4766     m_mainWin
->SetColumn( col
, item 
); 
4770 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
4772     return m_mainWin
->GetColumnWidth( col 
); 
4775 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
4777     m_mainWin
->SetColumnWidth( col
, width 
); 
4781 int wxGenericListCtrl::GetCountPerPage() const 
4783   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4786 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
4788     m_mainWin
->GetItem( info 
); 
4792 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
4794     m_mainWin
->SetItem( info 
); 
4798 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4801     info
.m_text 
= label
; 
4802     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4803     info
.m_itemId 
= index
; 
4807         info
.m_image 
= imageId
; 
4808         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4810     m_mainWin
->SetItem(info
); 
4814 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
4816     return m_mainWin
->GetItemState( item
, stateMask 
); 
4819 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4821     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4825 bool wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4828     info
.m_image 
= image
; 
4829     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4830     info
.m_itemId 
= item
; 
4831     m_mainWin
->SetItem( info 
); 
4835 wxString 
wxGenericListCtrl::GetItemText( long item 
) const 
4837     return m_mainWin
->GetItemText(item
); 
4840 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
4842     m_mainWin
->SetItemText(item
, str
); 
4845 wxUIntPtr 
wxGenericListCtrl::GetItemData( long item 
) const 
4848     info
.m_itemId 
= item
; 
4849     m_mainWin
->GetItem( info 
); 
4853 bool wxGenericListCtrl::SetItemData( long item
, long data 
) 
4856     info
.m_mask 
= wxLIST_MASK_DATA
; 
4857     info
.m_itemId 
= item
; 
4859     m_mainWin
->SetItem( info 
); 
4863 wxRect 
wxGenericListCtrl::GetViewRect() const 
4865     return m_mainWin
->GetViewRect(); 
4868 bool wxGenericListCtrl::GetItemRect( long item
, wxRect 
&rect
,  int WXUNUSED(code
) ) const 
4870     m_mainWin
->GetItemRect( item
, rect 
); 
4871     if ( m_mainWin
->HasHeader() ) 
4872         rect
.y 
+= m_headerHeight 
+ 1; 
4876 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4878     m_mainWin
->GetItemPosition( item
, pos 
); 
4882 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4887 int wxGenericListCtrl::GetItemCount() const 
4889     return m_mainWin
->GetItemCount(); 
4892 int wxGenericListCtrl::GetColumnCount() const 
4894     return m_mainWin
->GetColumnCount(); 
4897 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4899     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4902 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
4904     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
4906     return wxSize(spacing
, spacing
); 
4909 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
4911     return m_mainWin
->GetItemSpacing( isSmall 
); 
4914 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
4917     info
.m_itemId 
= item
; 
4918     info
.SetTextColour( col 
); 
4919     m_mainWin
->SetItem( info 
); 
4922 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
4925     info
.m_itemId 
= item
; 
4926     m_mainWin
->GetItem( info 
); 
4927     return info
.GetTextColour(); 
4930 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
4933     info
.m_itemId 
= item
; 
4934     info
.SetBackgroundColour( col 
); 
4935     m_mainWin
->SetItem( info 
); 
4938 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
4941     info
.m_itemId 
= item
; 
4942     m_mainWin
->GetItem( info 
); 
4943     return info
.GetBackgroundColour(); 
4946 int wxGenericListCtrl::GetSelectedItemCount() const 
4948     return m_mainWin
->GetSelectedItemCount(); 
4951 wxColour 
wxGenericListCtrl::GetTextColour() const 
4953     return GetForegroundColour(); 
4956 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
4958     SetForegroundColour(col
); 
4961 long wxGenericListCtrl::GetTopItem() const 
4964     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
4968 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
4970     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
4973 wxImageListType 
*wxGenericListCtrl::GetImageList(int which
) const 
4975     if (which 
== wxIMAGE_LIST_NORMAL
) 
4977         return m_imageListNormal
; 
4979     else if (which 
== wxIMAGE_LIST_SMALL
) 
4981         return m_imageListSmall
; 
4983     else if (which 
== wxIMAGE_LIST_STATE
) 
4985         return m_imageListState
; 
4987     return (wxImageListType 
*) NULL
; 
4990 void wxGenericListCtrl::SetImageList( wxImageListType 
*imageList
, int which 
) 
4992     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4994         if (m_ownsImageListNormal
) delete m_imageListNormal
; 
4995         m_imageListNormal 
= imageList
; 
4996         m_ownsImageListNormal 
= false; 
4998     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5000         if (m_ownsImageListSmall
) delete m_imageListSmall
; 
5001         m_imageListSmall 
= imageList
; 
5002         m_ownsImageListSmall 
= false; 
5004     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5006         if (m_ownsImageListState
) delete m_imageListState
; 
5007         m_imageListState 
= imageList
; 
5008         m_ownsImageListState 
= false; 
5011     m_mainWin
->SetImageList( imageList
, which 
); 
5014 void wxGenericListCtrl::AssignImageList(wxImageListType 
*imageList
, int which
) 
5016     SetImageList(imageList
, which
); 
5017     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5018         m_ownsImageListNormal 
= true; 
5019     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5020         m_ownsImageListSmall 
= true; 
5021     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5022         m_ownsImageListState 
= true; 
5025 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
5030 bool wxGenericListCtrl::DeleteItem( long item 
) 
5032     m_mainWin
->DeleteItem( item 
); 
5036 bool wxGenericListCtrl::DeleteAllItems() 
5038     m_mainWin
->DeleteAllItems(); 
5042 bool wxGenericListCtrl::DeleteAllColumns() 
5044     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
5045     for ( size_t n 
= 0; n 
< count
; n
++ ) 
5051 void wxGenericListCtrl::ClearAll() 
5053     m_mainWin
->DeleteEverything(); 
5056 bool wxGenericListCtrl::DeleteColumn( int col 
) 
5058     m_mainWin
->DeleteColumn( col 
); 
5060     // if we don't have the header any longer, we need to relayout the window 
5061     if ( !GetColumnCount() ) 
5063         ResizeReportView(false /* no header */); 
5069 void wxGenericListCtrl::Edit( long item 
) 
5071     m_mainWin
->EditLabel( item 
); 
5074 bool wxGenericListCtrl::EnsureVisible( long item 
) 
5076     m_mainWin
->EnsureVisible( item 
); 
5080 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
,  bool partial 
) 
5082     return m_mainWin
->FindItem( start
, str
, partial 
); 
5085 long wxGenericListCtrl::FindItem( long start
, wxUIntPtr data 
) 
5087     return m_mainWin
->FindItem( start
, data 
); 
5090 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& pt
, 
5091                            int WXUNUSED(direction
)) 
5093     return m_mainWin
->FindItem( pt 
); 
5096 long wxGenericListCtrl::HitTest( const wxPoint 
&point
, int &flags 
) 
5098     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
5101 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
5103     m_mainWin
->InsertItem( info 
); 
5104     return info
.m_itemId
; 
5107 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
5110     info
.m_text 
= label
; 
5111     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5112     info
.m_itemId 
= index
; 
5113     return InsertItem( info 
); 
5116 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
5119     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5120     info
.m_image 
= imageIndex
; 
5121     info
.m_itemId 
= index
; 
5122     return InsertItem( info 
); 
5125 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
5128     info
.m_text 
= label
; 
5129     info
.m_image 
= imageIndex
; 
5130     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
5131     info
.m_itemId 
= index
; 
5132     return InsertItem( info 
); 
5135 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
5137     wxCHECK_MSG( m_headerWin
, -1, _T("can't add column in non report mode") ); 
5139     m_mainWin
->InsertColumn( col
, item 
); 
5141     // if we hadn't had header before and have it now we need to relayout the 
5143     if ( GetColumnCount() == 1 && m_mainWin
->HasHeader() ) 
5145         ResizeReportView(true /* have header */); 
5148     m_headerWin
->Refresh(); 
5153 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
5154                                int format
, int width 
) 
5157     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
5158     item
.m_text 
= heading
; 
5161         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
5162         item
.m_width 
= width
; 
5164     item
.m_format 
= format
; 
5166     return InsertColumn( col
, item 
); 
5169 bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) ) 
5175 // fn is a function which takes 3 long arguments: item1, item2, data. 
5176 // item1 is the long data associated with a first item (NOT the index). 
5177 // item2 is the long data associated with a second item (NOT the index). 
5178 // data is the same value as passed to SortItems. 
5179 // The return value is a negative number if the first item should precede the second 
5180 // item, a positive number of the second item should precede the first, 
5181 // or zero if the two items are equivalent. 
5182 // data is arbitrary data to be passed to the sort function. 
5184 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
5186     m_mainWin
->SortItems( fn
, data 
); 
5190 // ---------------------------------------------------------------------------- 
5192 // ---------------------------------------------------------------------------- 
5194 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
5199     ResizeReportView(m_mainWin
->HasHeader()); 
5201     m_mainWin
->RecalculatePositions(); 
5204 void wxGenericListCtrl::ResizeReportView(bool showHeader
) 
5207     GetClientSize( &cw
, &ch 
); 
5211         m_headerWin
->SetSize( 0, 0, cw
, m_headerHeight 
); 
5212         m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, cw
, ch 
- m_headerHeight 
- 1 ); 
5214     else // no header window 
5216         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
5220 void wxGenericListCtrl::OnInternalIdle() 
5222     wxWindow::OnInternalIdle(); 
5224     // do it only if needed 
5225     if ( !m_mainWin
->m_dirty 
) 
5228     m_mainWin
->RecalculatePositions(); 
5231 // ---------------------------------------------------------------------------- 
5233 // ---------------------------------------------------------------------------- 
5235 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5239         m_mainWin
->SetBackgroundColour( colour 
); 
5240         m_mainWin
->m_dirty 
= true; 
5246 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5248     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5253         m_mainWin
->SetForegroundColour( colour 
); 
5254         m_mainWin
->m_dirty 
= true; 
5259         m_headerWin
->SetForegroundColour( colour 
); 
5265 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5267     if ( !wxWindow::SetFont( font 
) ) 
5272         m_mainWin
->SetFont( font 
); 
5273         m_mainWin
->m_dirty 
= true; 
5278         m_headerWin
->SetFont( font 
); 
5279         CalculateAndSetHeaderHeight(); 
5290 #include "wx/listbox.h" 
5295 wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
5298     // Use the same color scheme as wxListBox 
5299     return wxListBox::GetClassDefaultAttributes(variant
); 
5301     wxUnusedVar(variant
); 
5302     wxVisualAttributes attr
; 
5303     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
5304     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
5305     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
5310 // ---------------------------------------------------------------------------- 
5311 // methods forwarded to m_mainWin 
5312 // ---------------------------------------------------------------------------- 
5314 #if wxUSE_DRAG_AND_DROP 
5316 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5318     m_mainWin
->SetDropTarget( dropTarget 
); 
5321 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5323     return m_mainWin
->GetDropTarget(); 
5326 #endif // wxUSE_DRAG_AND_DROP 
5328 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5330     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : false; 
5333 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5335     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5338 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5340     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5343 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5346     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5349 #endif // wxUSE_MENUS 
5352 void wxGenericListCtrl::SetFocus() 
5354     /* The test in window.cpp fails as we are a composite 
5355        window, so it checks against "this", but not m_mainWin. */ 
5356     if ( FindFocus() != this ) 
5357         m_mainWin
->SetFocus(); 
5360 wxSize 
wxGenericListCtrl::DoGetBestSize() const 
5362     // Something is better than nothing... 
5363     // 100x80 is what the MSW version will get from the default 
5364     // wxControl::DoGetBestSize 
5365     return wxSize(100,80); 
5368 // ---------------------------------------------------------------------------- 
5369 // virtual list control support 
5370 // ---------------------------------------------------------------------------- 
5372 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5374     // this is a pure virtual function, in fact - which is not really pure 
5375     // because the controls which are not virtual don't need to implement it 
5376     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5378     return wxEmptyString
; 
5381 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5384     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemImage not supposed to be called") ); 
5390 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5392     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5393                   _T("invalid item index in OnGetItemAttr()") ); 
5395     // no attributes by default 
5399 void wxGenericListCtrl::SetItemCount(long count
) 
5401     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
5403     m_mainWin
->SetItemCount(count
); 
5406 void wxGenericListCtrl::RefreshItem(long item
) 
5408     m_mainWin
->RefreshLine(item
); 
5411 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5413     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5417  * Generic wxListCtrl is more or less a container for two other 
5418  * windows which drawings are done upon. These are namely 
5419  * 'm_headerWin' and 'm_mainWin'. 
5420  * Here we override 'virtual wxWindow::Refresh()' to mimic the 
5421  * behaviour wxListCtrl has under wxMSW. 
5423 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5427         // The easy case, no rectangle specified. 
5429             m_headerWin
->Refresh(eraseBackground
); 
5432             m_mainWin
->Refresh(eraseBackground
); 
5436         // Refresh the header window 
5439             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5440             rectHeader
.Intersect(*rect
); 
5441             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5444                 m_headerWin
->GetPosition(&x
, &y
); 
5445                 rectHeader
.Offset(-x
, -y
); 
5446                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5451         // Refresh the main window 
5454             wxRect rectMain 
= m_mainWin
->GetRect(); 
5455             rectMain
.Intersect(*rect
); 
5456             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5459                 m_mainWin
->GetPosition(&x
, &y
); 
5460                 rectMain
.Offset(-x
, -y
); 
5461                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5467 void wxGenericListCtrl::Freeze() 
5469     m_mainWin
->Freeze(); 
5472 void wxGenericListCtrl::Thaw() 
5477 #endif // wxUSE_LISTCTRL