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" 
  79 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
  80 // be removed, as well as the #else case below. 
  81 #define _USE_VISATTR 0 
  84 // ---------------------------------------------------------------------------- 
  86 // ---------------------------------------------------------------------------- 
  88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
) 
  89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
) 
  90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
) 
  91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
) 
  92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
) 
  93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
) 
  94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
) 
  95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
) 
  96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
) 
  97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
) 
  98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
) 
  99 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
) 
 100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
) 
 101 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
) 
 102 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
) 
 103 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING
) 
 104 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG
) 
 105 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
) 
 106 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
) 
 107 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
) 
 108 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED
) 
 109 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
) 
 111 // ---------------------------------------------------------------------------- 
 113 // ---------------------------------------------------------------------------- 
 115 // // the height of the header window (FIXME: should depend on its font!) 
 116 // static const int HEADER_HEIGHT = 23; 
 118 static const int SCROLL_UNIT_X 
= 15; 
 120 // the spacing between the lines (in report mode) 
 121 static const int LINE_SPACING 
= 0; 
 123 // extra margins around the text label 
 124 static const int EXTRA_WIDTH 
= 4; 
 125 static const int EXTRA_HEIGHT 
= 4; 
 127 // margin between the window and the items 
 128 static const int EXTRA_BORDER_X 
= 2; 
 129 static const int EXTRA_BORDER_Y 
= 2; 
 131 // offset for the header window 
 132 static const int HEADER_OFFSET_X 
= 1; 
 133 static const int HEADER_OFFSET_Y 
= 1; 
 135 // margin between rows of icons in [small] icon view 
 136 static const int MARGIN_BETWEEN_ROWS 
= 6; 
 138 // when autosizing the columns, add some slack 
 139 static const int AUTOSIZE_COL_MARGIN 
= 10; 
 141 // default and minimal widths for the header columns 
 142 static const int WIDTH_COL_DEFAULT 
= 80; 
 143 static const int WIDTH_COL_MIN 
= 10; 
 145 // the space between the image and the text in the report mode 
 146 static const int IMAGE_MARGIN_IN_REPORT_MODE 
= 5; 
 148 // ============================================================================ 
 150 // ============================================================================ 
 152 //----------------------------------------------------------------------------- 
 153 //  wxListItemData (internal) 
 154 //----------------------------------------------------------------------------- 
 156 class WXDLLEXPORT wxListItemData
 
 159     wxListItemData(wxListMainWindow 
*owner
); 
 162     void SetItem( const wxListItem 
&info 
); 
 163     void SetImage( int image 
) { m_image 
= image
; } 
 164     void SetData( long data 
) { m_data 
= data
; } 
 165     void SetPosition( int x
, int y 
); 
 166     void SetSize( int width
, int height 
); 
 168     bool HasText() const { return !m_text
.empty(); } 
 169     const wxString
& GetText() const { return m_text
; } 
 170     void SetText(const wxString
& text
) { m_text 
= text
; } 
 172     // we can't use empty string for measuring the string width/height, so 
 173     // always return something 
 174     wxString 
GetTextForMeasuring() const 
 176         wxString s 
= GetText(); 
 183     bool IsHit( int x
, int y 
) const; 
 187     int GetWidth() const; 
 188     int GetHeight() const; 
 190     int GetImage() const { return m_image
; } 
 191     bool HasImage() const { return GetImage() != -1; } 
 193     void GetItem( wxListItem 
&info 
) const; 
 195     void SetAttr(wxListItemAttr 
*attr
) { m_attr 
= attr
; } 
 196     wxListItemAttr 
*GetAttr() const { return m_attr
; } 
 199     // the item image or -1 
 202     // user data associated with the item 
 205     // the item coordinates are not used in report mode, instead this pointer 
 206     // is NULL and the owner window is used to retrieve the item position and 
 210     // the list ctrl we are in 
 211     wxListMainWindow 
*m_owner
; 
 213     // custom attributes or NULL 
 214     wxListItemAttr 
*m_attr
; 
 217     // common part of all ctors 
 223 //----------------------------------------------------------------------------- 
 224 //  wxListHeaderData (internal) 
 225 //----------------------------------------------------------------------------- 
 227 class WXDLLEXPORT wxListHeaderData 
: public wxObject
 
 231     wxListHeaderData( const wxListItem 
&info 
); 
 232     void SetItem( const wxListItem 
&item 
); 
 233     void SetPosition( int x
, int y 
); 
 234     void SetWidth( int w 
); 
 235     void SetFormat( int format 
); 
 236     void SetHeight( int h 
); 
 237     bool HasImage() const; 
 239     bool HasText() const { return !m_text
.empty(); } 
 240     const wxString
& GetText() const { return m_text
; } 
 241     void SetText(const wxString
& text
) { m_text 
= text
; } 
 243     void GetItem( wxListItem 
&item 
); 
 245     bool IsHit( int x
, int y 
) const; 
 246     int GetImage() const; 
 247     int GetWidth() const; 
 248     int GetFormat() const; 
 264 //----------------------------------------------------------------------------- 
 265 //  wxListLineData (internal) 
 266 //----------------------------------------------------------------------------- 
 268 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
); 
 269 #include "wx/listimpl.cpp" 
 270 WX_DEFINE_LIST(wxListItemDataList
); 
 275     // the list of subitems: only may have more than one item in report mode 
 276     wxListItemDataList m_items
; 
 278     // this is not used in report view 
 290         // the part to be highlighted 
 291         wxRect m_rectHighlight
; 
 293         // extend all our rects to be centered inside theo ne of given width 
 294         void ExtendWidth(wxCoord w
) 
 296             wxASSERT_MSG( m_rectAll
.width 
<= w
, 
 297                             _T("width can only be increased") ); 
 300             m_rectLabel
.x 
= m_rectAll
.x 
+ (w 
- m_rectLabel
.width
)/2; 
 301             m_rectIcon
.x 
= m_rectAll
.x 
+ (w 
- m_rectIcon
.width
)/2; 
 302             m_rectHighlight
.x 
= m_rectAll
.x 
+ (w 
- m_rectHighlight
.width
)/2; 
 306     // is this item selected? [NB: not used in virtual mode] 
 309     // back pointer to the list ctrl 
 310     wxListMainWindow 
*m_owner
; 
 313     wxListLineData(wxListMainWindow 
*owner
); 
 317         WX_CLEAR_LIST(wxListItemDataList
, m_items
); 
 321     // are we in report mode? 
 322     inline bool InReportView() const; 
 324     // are we in virtual report mode? 
 325     inline bool IsVirtual() const; 
 327     // these 2 methods shouldn't be called for report view controls, in that 
 328     // case we determine our position/size ourselves 
 330     // calculate the size of the line 
 331     void CalculateSize( wxDC 
*dc
, int spacing 
); 
 333     // remember the position this line appears at 
 334     void SetPosition( int x
, int y
, int spacing 
); 
 338     void SetImage( int image 
) { SetImage(0, image
); } 
 339     int GetImage() const { return GetImage(0); } 
 340     bool HasImage() const { return GetImage() != -1; } 
 341     bool HasText() const { return !GetText(0).empty(); } 
 343     void SetItem( int index
, const wxListItem 
&info 
); 
 344     void GetItem( int index
, wxListItem 
&info 
); 
 346     wxString 
GetText(int index
) const; 
 347     void SetText( int index
, const wxString s 
); 
 349     wxListItemAttr 
*GetAttr() const; 
 350     void SetAttr(wxListItemAttr 
*attr
); 
 352     // return true if the highlighting really changed 
 353     bool Highlight( bool on 
); 
 355     void ReverseHighlight(); 
 357     bool IsHighlighted() const 
 359         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); 
 361         return m_highlighted
; 
 364     // draw the line on the given DC in icon/list mode 
 365     void Draw( wxDC 
*dc 
); 
 367     // the same in report mode 
 368     void DrawInReportMode( wxDC 
*dc
, 
 370                            const wxRect
& rectHL
, 
 374     // set the line to contain num items (only can be > 1 in report mode) 
 375     void InitItems( int num 
); 
 377     // get the mode (i.e. style)  of the list control 
 378     inline int GetMode() const; 
 380     // prepare the DC for drawing with these item's attributes, return true if 
 381     // we need to draw the items background to highlight it, false otherwise 
 382     bool SetAttributes(wxDC 
*dc
, 
 383                        const wxListItemAttr 
*attr
, 
 386     // draw the text on the DC with the correct justification; also add an 
 387     // ellipsis if the text is too large to fit in the current width 
 388     void DrawTextFormatted(wxDC 
*dc
, const wxString 
&text
, int col
, int x
, int y
, int width
); 
 390     // these are only used by GetImage/SetImage above, we don't support images 
 391     // with subitems at the public API level yet 
 392     void SetImage( int index
, int image 
); 
 393     int GetImage( int index 
) const; 
 396 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
); 
 397 #include "wx/arrimpl.cpp" 
 398 WX_DEFINE_OBJARRAY(wxListLineDataArray
); 
 400 //----------------------------------------------------------------------------- 
 401 //  wxListHeaderWindow (internal) 
 402 //----------------------------------------------------------------------------- 
 404 class WXDLLEXPORT wxListHeaderWindow 
: public wxWindow
 
 407     wxListMainWindow  
*m_owner
; 
 408     wxCursor          
*m_currentCursor
; 
 409     wxCursor          
*m_resizeCursor
; 
 412     // column being resized or -1 
 415     // divider line position in logical (unscrolled) coords 
 418     // minimal position beyond which the divider line can't be dragged in 
 423     wxListHeaderWindow(); 
 425     wxListHeaderWindow( wxWindow 
*win
, 
 427                         wxListMainWindow 
*owner
, 
 428                         const wxPoint 
&pos 
= wxDefaultPosition
, 
 429                         const wxSize 
&size 
= wxDefaultSize
, 
 431                         const wxString 
&name 
= wxT("wxlistctrlcolumntitles") ); 
 433     virtual ~wxListHeaderWindow(); 
 436     void AdjustDC(wxDC
& dc
); 
 438     void OnPaint( wxPaintEvent 
&event 
); 
 439     void OnMouse( wxMouseEvent 
&event 
); 
 440     void OnSetFocus( wxFocusEvent 
&event 
); 
 446     // common part of all ctors 
 449     // generate and process the list event of the given type, return true if 
 450     // it wasn't vetoed, i.e. if we should proceed 
 451     bool SendListEvent(wxEventType type
, wxPoint pos
); 
 453     DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
) 
 454     DECLARE_EVENT_TABLE() 
 457 //----------------------------------------------------------------------------- 
 458 // wxListRenameTimer (internal) 
 459 //----------------------------------------------------------------------------- 
 461 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
 
 464     wxListMainWindow 
*m_owner
; 
 467     wxListRenameTimer( wxListMainWindow 
*owner 
); 
 471 //----------------------------------------------------------------------------- 
 472 //  wxListTextCtrl (internal) 
 473 //----------------------------------------------------------------------------- 
 475 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
 
 478     wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
); 
 481     void OnChar( wxKeyEvent 
&event 
); 
 482     void OnKeyUp( wxKeyEvent 
&event 
); 
 483     void OnKillFocus( wxFocusEvent 
&event 
); 
 485     bool AcceptChanges(); 
 489     wxListMainWindow   
*m_owner
; 
 490     wxString            m_startValue
; 
 494     DECLARE_EVENT_TABLE() 
 497 //----------------------------------------------------------------------------- 
 498 //  wxListMainWindow (internal) 
 499 //----------------------------------------------------------------------------- 
 501 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
); 
 502 #include "wx/listimpl.cpp" 
 503 WX_DEFINE_LIST(wxListHeaderDataList
); 
 505 class wxListMainWindow 
: public wxScrolledWindow
 
 509     wxListMainWindow( wxWindow 
*parent
, 
 511                       const wxPoint
& pos 
= wxDefaultPosition
, 
 512                       const wxSize
& size 
= wxDefaultSize
, 
 514                       const wxString 
&name 
= _T("listctrlmainwindow") ); 
 516     virtual ~wxListMainWindow(); 
 518     bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); } 
 520     // return true if this is a virtual list control 
 521     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); } 
 523     // return true if the control is in report mode 
 524     bool InReportView() const { return HasFlag(wxLC_REPORT
); } 
 526     // return true if we are in single selection mode, false if multi sel 
 527     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); } 
 529     // do we have a header window? 
 530     bool HasHeader() const 
 531         { return InReportView() && !HasFlag(wxLC_NO_HEADER
); } 
 533     void HighlightAll( bool on 
); 
 535     // all these functions only do something if the line is currently visible 
 537     // change the line "selected" state, return true if it really changed 
 538     bool HighlightLine( size_t line
, bool highlight 
= true); 
 540     // as HighlightLine() but do it for the range of lines: this is incredibly 
 541     // more efficient for virtual list controls! 
 543     // NB: unlike HighlightLine() this one does refresh the lines on screen 
 544     void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on 
= true ); 
 546     // toggle the line state and refresh it 
 547     void ReverseHighlight( size_t line 
) 
 548         { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); } 
 550     // return true if the line is highlighted 
 551     bool IsHighlighted(size_t line
) const; 
 553     // refresh one or several lines at once 
 554     void RefreshLine( size_t line 
); 
 555     void RefreshLines( size_t lineFrom
, size_t lineTo 
); 
 557     // refresh all selected items 
 558     void RefreshSelected(); 
 560     // refresh all lines below the given one: the difference with 
 561     // RefreshLines() is that the index here might not be a valid one (happens 
 562     // when the last line is deleted) 
 563     void RefreshAfter( size_t lineFrom 
); 
 565     // the methods which are forwarded to wxListLineData itself in list/icon 
 566     // modes but are here because the lines don't store their positions in the 
 569     // get the bound rect for the entire line 
 570     wxRect 
GetLineRect(size_t line
) const; 
 572     // get the bound rect of the label 
 573     wxRect 
GetLineLabelRect(size_t line
) const; 
 575     // get the bound rect of the items icon (only may be called if we do have 
 577     wxRect 
GetLineIconRect(size_t line
) const; 
 579     // get the rect to be highlighted when the item has focus 
 580     wxRect 
GetLineHighlightRect(size_t line
) const; 
 582     // get the size of the total line rect 
 583     wxSize 
GetLineSize(size_t line
) const 
 584         { return GetLineRect(line
).GetSize(); } 
 586     // return the hit code for the corresponding position (in this line) 
 587     long HitTestLine(size_t line
, int x
, int y
) const; 
 589     // bring the selected item into view, scrolling to it if necessary 
 590     void MoveToItem(size_t item
); 
 592     // bring the current item into view 
 593     void MoveToFocus() { MoveToItem(m_current
); } 
 595     // start editing the label of the given item 
 596     void EditLabel( long item 
); 
 598     // suspend/resume redrawing the control 
 604     void OnRenameTimer(); 
 605     bool OnRenameAccept(size_t itemEdit
, const wxString
& value
); 
 606     void OnRenameCancelled(size_t itemEdit
); 
 608     void OnMouse( wxMouseEvent 
&event 
); 
 610     // called to switch the selection from the current item to newCurrent, 
 611     void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event 
); 
 613     void OnChar( wxKeyEvent 
&event 
); 
 614     void OnKeyDown( wxKeyEvent 
&event 
); 
 615     void OnSetFocus( wxFocusEvent 
&event 
); 
 616     void OnKillFocus( wxFocusEvent 
&event 
); 
 617     void OnScroll(wxScrollWinEvent
& event
) ; 
 619     void OnPaint( wxPaintEvent 
&event 
); 
 621     void DrawImage( int index
, wxDC 
*dc
, int x
, int y 
); 
 622     void GetImageSize( int index
, int &width
, int &height 
) const; 
 623     int GetTextLength( const wxString 
&s 
) const; 
 625     void SetImageList( wxImageListType 
*imageList
, int which 
); 
 626     void SetItemSpacing( int spacing
, bool isSmall 
= false ); 
 627     int GetItemSpacing( bool isSmall 
= false ); 
 629     void SetColumn( int col
, wxListItem 
&item 
); 
 630     void SetColumnWidth( int col
, int width 
); 
 631     void GetColumn( int col
, wxListItem 
&item 
) const; 
 632     int GetColumnWidth( int col 
) const; 
 633     int GetColumnCount() const { return m_columns
.GetCount(); } 
 635     // returns the sum of the heights of all columns 
 636     int GetHeaderWidth() const; 
 638     int GetCountPerPage() const; 
 640     void SetItem( wxListItem 
&item 
); 
 641     void GetItem( wxListItem 
&item 
) const; 
 642     void SetItemState( long item
, long state
, long stateMask 
); 
 643     int GetItemState( long item
, long stateMask 
) const; 
 644     void GetItemRect( long index
, wxRect 
&rect 
) const; 
 645     wxRect 
GetViewRect() const; 
 646     bool GetItemPosition( long item
, wxPoint
& pos 
) const; 
 647     int GetSelectedItemCount() const; 
 649     wxString 
GetItemText(long item
) const 
 652         info
.m_itemId 
= item
; 
 657     void SetItemText(long item
, const wxString
& value
) 
 660         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 661         info
.m_itemId 
= item
; 
 666     // set the scrollbars and update the positions of the items 
 667     void RecalculatePositions(bool noRefresh 
= false); 
 669     // refresh the window and the header 
 672     long GetNextItem( long item
, int geometry
, int state 
) const; 
 673     void DeleteItem( long index 
); 
 674     void DeleteAllItems(); 
 675     void DeleteColumn( int col 
); 
 676     void DeleteEverything(); 
 677     void EnsureVisible( long index 
); 
 678     long FindItem( long start
, const wxString
& str
, bool partial 
= false ); 
 679     long FindItem( long start
, long data
); 
 680     long HitTest( int x
, int y
, int &flags 
); 
 681     void InsertItem( wxListItem 
&item 
); 
 682     void InsertColumn( long col
, wxListItem 
&item 
); 
 683     void SortItems( wxListCtrlCompare fn
, long data 
); 
 685     size_t GetItemCount() const; 
 686     bool IsEmpty() const { return GetItemCount() == 0; } 
 687     void SetItemCount(long count
); 
 689     // change the current (== focused) item, send a notification event 
 690     void ChangeCurrent(size_t current
); 
 691     void ResetCurrent() { ChangeCurrent((size_t)-1); } 
 692     bool HasCurrent() const { return m_current 
!= (size_t)-1; } 
 694     // send out a wxListEvent 
 695     void SendNotify( size_t line
, 
 697                      wxPoint point 
= wxDefaultPosition 
); 
 699     // override base class virtual to reset m_lineHeight when the font changes 
 700     virtual bool SetFont(const wxFont
& font
) 
 702         if ( !wxScrolledWindow::SetFont(font
) ) 
 710     // these are for wxListLineData usage only 
 712     // get the backpointer to the list ctrl 
 713     wxGenericListCtrl 
*GetListCtrl() const 
 715         return wxStaticCast(GetParent(), wxGenericListCtrl
); 
 718     // get the height of all lines (assuming they all do have the same height) 
 719     wxCoord 
GetLineHeight() const; 
 721     // get the y position of the given line (only for report view) 
 722     wxCoord 
GetLineY(size_t line
) const; 
 724     // get the brush to use for the item highlighting 
 725     wxBrush 
*GetHighlightBrush() const 
 727         return m_hasFocus 
? m_highlightBrush 
: m_highlightUnfocusedBrush
; 
 731     // the array of all line objects for a non virtual list control (for the 
 732     // virtual list control we only ever use m_lines[0]) 
 733     wxListLineDataArray  m_lines
; 
 735     // the list of column objects 
 736     wxListHeaderDataList m_columns
; 
 738     // currently focused item or -1 
 741     // the number of lines per page 
 744     // this flag is set when something which should result in the window 
 745     // redrawing happens (i.e. an item was added or deleted, or its appearance 
 746     // changed) and OnPaint() doesn't redraw the window while it is set which 
 747     // allows to minimize the number of repaintings when a lot of items are 
 748     // being added. The real repainting occurs only after the next OnIdle() 
 752     wxColour            
*m_highlightColour
; 
 753     wxImageListType         
*m_small_image_list
; 
 754     wxImageListType         
*m_normal_image_list
; 
 756     int                  m_normal_spacing
; 
 760     wxTimer             
*m_renameTimer
; 
 765     // for double click logic 
 766     size_t m_lineLastClicked
, 
 767            m_lineBeforeLastClicked
; 
 770     // the total count of items in a virtual list control 
 773     // the object maintaining the items selection state, only used in virtual 
 775     wxSelectionStore m_selStore
; 
 777     // common part of all ctors 
 780     // get the line data for the given index 
 781     wxListLineData 
*GetLine(size_t n
) const 
 783         wxASSERT_MSG( n 
!= (size_t)-1, _T("invalid line index") ); 
 787             wxConstCast(this, wxListMainWindow
)->CacheLineData(n
); 
 795     // get a dummy line which can be used for geometry calculations and such: 
 796     // you must use GetLine() if you want to really draw the line 
 797     wxListLineData 
*GetDummyLine() const; 
 799     // cache the line data of the n-th line in m_lines[0] 
 800     void CacheLineData(size_t line
); 
 802     // get the range of visible lines 
 803     void GetVisibleLinesRange(size_t *from
, size_t *to
); 
 805     // force us to recalculate the range of visible lines 
 806     void ResetVisibleLinesRange() { m_lineFrom 
= (size_t)-1; } 
 808     // get the colour to be used for drawing the rules 
 809     wxColour 
GetRuleColour() const 
 814         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 819     // initialize the current item if needed 
 820     void UpdateCurrent(); 
 822     // delete all items but don't refresh: called from dtor 
 823     void DoDeleteAllItems(); 
 825     // the height of one line using the current font 
 826     wxCoord m_lineHeight
; 
 828     // the total header width or 0 if not calculated yet 
 829     wxCoord m_headerWidth
; 
 831     // the first and last lines being shown on screen right now (inclusive), 
 832     // both may be -1 if they must be calculated so never access them directly: 
 833     // use GetVisibleLinesRange() above instead 
 837     // the brushes to use for item highlighting when we do/don't have focus 
 838     wxBrush 
*m_highlightBrush
, 
 839             *m_highlightUnfocusedBrush
; 
 841     // if this is > 0, the control is frozen and doesn't redraw itself 
 842     size_t m_freezeCount
; 
 844     DECLARE_DYNAMIC_CLASS(wxListMainWindow
) 
 845     DECLARE_EVENT_TABLE() 
 847     friend class wxGenericListCtrl
; 
 850 // ============================================================================ 
 852 // ============================================================================ 
 854 //----------------------------------------------------------------------------- 
 856 //----------------------------------------------------------------------------- 
 858 wxListItemData::~wxListItemData() 
 860     // in the virtual list control the attributes are managed by the main 
 861     // program, so don't delete them 
 862     if ( !m_owner
->IsVirtual() ) 
 870 void wxListItemData::Init() 
 878 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
 884     if ( owner
->InReportView() ) 
 894 void wxListItemData::SetItem( const wxListItem 
&info 
) 
 896     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
 897         SetText(info
.m_text
); 
 898     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 899         m_image 
= info
.m_image
; 
 900     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
 901         m_data 
= info
.m_data
; 
 903     if ( info
.HasAttributes() ) 
 906             *m_attr 
= *info
.GetAttributes(); 
 908             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
 916         m_rect
->width 
= info
.m_width
; 
 920 void wxListItemData::SetPosition( int x
, int y 
) 
 922     wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") ); 
 928 void wxListItemData::SetSize( int width
, int height 
) 
 930     wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") ); 
 933         m_rect
->width 
= width
; 
 935         m_rect
->height 
= height
; 
 938 bool wxListItemData::IsHit( int x
, int y 
) const 
 940     wxCHECK_MSG( m_rect
, false, _T("can't be called in this mode") ); 
 942     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
); 
 945 int wxListItemData::GetX() const 
 947     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 952 int wxListItemData::GetY() const 
 954     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 959 int wxListItemData::GetWidth() const 
 961     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 963     return m_rect
->width
; 
 966 int wxListItemData::GetHeight() const 
 968     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
 970     return m_rect
->height
; 
 973 void wxListItemData::GetItem( wxListItem 
&info 
) const 
 975     info
.m_text 
= m_text
; 
 976     info
.m_image 
= m_image
; 
 977     info
.m_data 
= m_data
; 
 981         if ( m_attr
->HasTextColour() ) 
 982             info
.SetTextColour(m_attr
->GetTextColour()); 
 983         if ( m_attr
->HasBackgroundColour() ) 
 984             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
 985         if ( m_attr
->HasFont() ) 
 986             info
.SetFont(m_attr
->GetFont()); 
 990 //----------------------------------------------------------------------------- 
 992 //----------------------------------------------------------------------------- 
 994 void wxListHeaderData::Init() 
1005 wxListHeaderData::wxListHeaderData() 
1010 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
1017 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
1019     m_mask 
= item
.m_mask
; 
1021     if ( m_mask 
& wxLIST_MASK_TEXT 
) 
1022         m_text 
= item
.m_text
; 
1024     if ( m_mask 
& wxLIST_MASK_IMAGE 
) 
1025         m_image 
= item
.m_image
; 
1027     if ( m_mask 
& wxLIST_MASK_FORMAT 
) 
1028         m_format 
= item
.m_format
; 
1030     if ( m_mask 
& wxLIST_MASK_WIDTH 
) 
1031         SetWidth(item
.m_width
); 
1034 void wxListHeaderData::SetPosition( int x
, int y 
) 
1040 void wxListHeaderData::SetHeight( int h 
) 
1045 void wxListHeaderData::SetWidth( int w 
) 
1049         m_width 
= WIDTH_COL_DEFAULT
; 
1050     else if (m_width 
< WIDTH_COL_MIN
) 
1051         m_width 
= WIDTH_COL_MIN
; 
1054 void wxListHeaderData::SetFormat( int format 
) 
1059 bool wxListHeaderData::HasImage() const 
1061     return m_image 
!= -1; 
1064 bool wxListHeaderData::IsHit( int x
, int y 
) const 
1066     return ((x 
>= m_xpos
) && (x 
<= m_xpos
+m_width
) && (y 
>= m_ypos
) && (y 
<= m_ypos
+m_height
)); 
1069 void wxListHeaderData::GetItem( wxListItem
& item 
) 
1071     item
.m_mask 
= m_mask
; 
1072     item
.m_text 
= m_text
; 
1073     item
.m_image 
= m_image
; 
1074     item
.m_format 
= m_format
; 
1075     item
.m_width 
= m_width
; 
1078 int wxListHeaderData::GetImage() const 
1083 int wxListHeaderData::GetWidth() const 
1088 int wxListHeaderData::GetFormat() const 
1093 //----------------------------------------------------------------------------- 
1095 //----------------------------------------------------------------------------- 
1097 inline int wxListLineData::GetMode() const 
1099     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
1102 inline bool wxListLineData::InReportView() const 
1104     return m_owner
->HasFlag(wxLC_REPORT
); 
1107 inline bool wxListLineData::IsVirtual() const 
1109     return m_owner
->IsVirtual(); 
1112 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
1116     if ( InReportView() ) 
1122         m_gi 
= new GeometryInfo
; 
1125     m_highlighted 
= false; 
1127     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
1130 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
1132     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1133     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1135     wxListItemData 
*item 
= node
->GetData(); 
1140     switch ( GetMode() ) 
1143         case wxLC_SMALL_ICON
: 
1144             m_gi
->m_rectAll
.width 
= spacing
; 
1146             s 
= item
->GetText(); 
1151                 m_gi
->m_rectLabel
.width 
= 
1152                 m_gi
->m_rectLabel
.height 
= 0; 
1156                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
1160                 m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
1162                     m_gi
->m_rectAll
.width 
= lw
; 
1164                 m_gi
->m_rectLabel
.width 
= lw
; 
1165                 m_gi
->m_rectLabel
.height 
= lh
; 
1168             if (item
->HasImage()) 
1171                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1172                 m_gi
->m_rectIcon
.width 
= w 
+ 8; 
1173                 m_gi
->m_rectIcon
.height 
= h 
+ 8; 
1175                 if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
1176                     m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
1177                 if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
1178                     m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
1181             if ( item
->HasText() ) 
1183                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
1184                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
1186             else // no text, highlight the icon 
1188                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
1189                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
1194             s 
= item
->GetTextForMeasuring(); 
1196             dc
->GetTextExtent( s
, &lw
, &lh 
); 
1200             m_gi
->m_rectLabel
.width 
= lw
; 
1201             m_gi
->m_rectLabel
.height 
= lh
; 
1203             m_gi
->m_rectAll
.width 
= lw
; 
1204             m_gi
->m_rectAll
.height 
= lh
; 
1206             if (item
->HasImage()) 
1209                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1210                 m_gi
->m_rectIcon
.width 
= w
; 
1211                 m_gi
->m_rectIcon
.height 
= h
; 
1213                 m_gi
->m_rectAll
.width 
+= 4 + w
; 
1214                 if (h 
> m_gi
->m_rectAll
.height
) 
1215                     m_gi
->m_rectAll
.height 
= h
; 
1218             m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
1219             m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
1223             wxFAIL_MSG( _T("unexpected call to SetSize") ); 
1227             wxFAIL_MSG( _T("unknown mode") ); 
1231 void wxListLineData::SetPosition( int x
, int y
, int spacing 
) 
1233     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1234     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1236     wxListItemData 
*item 
= node
->GetData(); 
1238     switch ( GetMode() ) 
1241         case wxLC_SMALL_ICON
: 
1242             m_gi
->m_rectAll
.x 
= x
; 
1243             m_gi
->m_rectAll
.y 
= y
; 
1245             if ( item
->HasImage() ) 
1247                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 + 
1248                     (m_gi
->m_rectAll
.width 
- m_gi
->m_rectIcon
.width
) / 2; 
1249                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
1252             if ( item
->HasText() ) 
1254                 if (m_gi
->m_rectAll
.width 
> spacing
) 
1255                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1257                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2); 
1258                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
1259                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
1260                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
1262             else // no text, highlight the icon 
1264                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
1265                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
1270             m_gi
->m_rectAll
.x 
= x
; 
1271             m_gi
->m_rectAll
.y 
= y
; 
1273             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
1274             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
1275             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1277             if (item
->HasImage()) 
1279                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1280                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1281                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 6 + m_gi
->m_rectIcon
.width
; 
1285                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1290             wxFAIL_MSG( _T("unexpected call to SetPosition") ); 
1294             wxFAIL_MSG( _T("unknown mode") ); 
1298 void wxListLineData::InitItems( int num 
) 
1300     for (int i 
= 0; i 
< num
; i
++) 
1301         m_items
.Append( new wxListItemData(m_owner
) ); 
1304 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
1306     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1307     wxCHECK_RET( node
, _T("invalid column index in SetItem") ); 
1309     wxListItemData 
*item 
= node
->GetData(); 
1310     item
->SetItem( info 
); 
1313 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
1315     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1318         wxListItemData 
*item 
= node
->GetData(); 
1319         item
->GetItem( info 
); 
1323 wxString 
wxListLineData::GetText(int index
) const 
1327     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1330         wxListItemData 
*item 
= node
->GetData(); 
1331         s 
= item
->GetText(); 
1337 void wxListLineData::SetText( int index
, const wxString s 
) 
1339     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1342         wxListItemData 
*item 
= node
->GetData(); 
1347 void wxListLineData::SetImage( int index
, int image 
) 
1349     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1350     wxCHECK_RET( node
, _T("invalid column index in SetImage()") ); 
1352     wxListItemData 
*item 
= node
->GetData(); 
1353     item
->SetImage(image
); 
1356 int wxListLineData::GetImage( int index 
) const 
1358     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
1359     wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") ); 
1361     wxListItemData 
*item 
= node
->GetData(); 
1362     return item
->GetImage(); 
1365 wxListItemAttr 
*wxListLineData::GetAttr() const 
1367     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1368     wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") ); 
1370     wxListItemData 
*item 
= node
->GetData(); 
1371     return item
->GetAttr(); 
1374 void wxListLineData::SetAttr(wxListItemAttr 
*attr
) 
1376     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1377     wxCHECK_RET( node
, _T("invalid column index in SetAttr()") ); 
1379     wxListItemData 
*item 
= node
->GetData(); 
1380     item
->SetAttr(attr
); 
1383 bool wxListLineData::SetAttributes(wxDC 
*dc
, 
1384                                    const wxListItemAttr 
*attr
, 
1387     wxWindow 
*listctrl 
= m_owner
->GetParent(); 
1391     // don't use foreground colour for drawing highlighted items - this might 
1392     // make them completely invisible (and there is no way to do bit 
1393     // arithmetics on wxColour, unfortunately) 
1397         colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1401         if ( attr 
&& attr
->HasTextColour() ) 
1403             colText 
= attr
->GetTextColour(); 
1407             colText 
= listctrl
->GetForegroundColour(); 
1411     dc
->SetTextForeground(colText
); 
1415     if ( attr 
&& attr
->HasFont() ) 
1417         font 
= attr
->GetFont(); 
1421         font 
= listctrl
->GetFont(); 
1427     bool hasBgCol 
= attr 
&& attr
->HasBackgroundColour(); 
1428     if ( highlighted 
|| hasBgCol 
) 
1432             dc
->SetBrush( *m_owner
->GetHighlightBrush() ); 
1436             dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
)); 
1439         dc
->SetPen( *wxTRANSPARENT_PEN 
); 
1447 void wxListLineData::Draw( wxDC 
*dc 
) 
1449     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1450     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1452     bool highlighted 
= IsHighlighted(); 
1454     wxListItemAttr 
*attr 
= GetAttr(); 
1456     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1458         dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1461     // just for debugging to better see where the items are 
1463     dc
->SetPen(*wxRED_PEN
); 
1464     dc
->SetBrush(*wxTRANSPARENT_BRUSH
); 
1465     dc
->DrawRectangle( m_gi
->m_rectAll 
); 
1466     dc
->SetPen(*wxGREEN_PEN
); 
1467     dc
->DrawRectangle( m_gi
->m_rectIcon 
); 
1470     wxListItemData 
*item 
= node
->GetData(); 
1471     if (item
->HasImage()) 
1473         // centre the image inside our rectangle, this looks nicer when items 
1474         // ae aligned in a row 
1475         const wxRect
& rectIcon 
= m_gi
->m_rectIcon
; 
1477         m_owner
->DrawImage(item
->GetImage(), dc
, rectIcon
.x
, rectIcon
.y
); 
1480     if (item
->HasText()) 
1482         const wxRect
& rectLabel 
= m_gi
->m_rectLabel
; 
1484         wxDCClipper 
clipper(*dc
, rectLabel
); 
1485         dc
->DrawText(item
->GetText(), rectLabel
.x
, rectLabel
.y
); 
1489 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
1491                                        const wxRect
& rectHL
, 
1494     // TODO: later we should support setting different attributes for 
1495     //       different columns - to do it, just add "col" argument to 
1496     //       GetAttr() and move these lines into the loop below 
1497     wxListItemAttr 
*attr 
= GetAttr(); 
1498     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1500         dc
->DrawRectangle( rectHL 
); 
1503     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
1504             y 
= rect
.y 
+ (LINE_SPACING 
+ EXTRA_HEIGHT
) / 2; 
1507     for ( wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
1509           node 
= node
->GetNext(), col
++ ) 
1511         wxListItemData 
*item 
= node
->GetData(); 
1513         int width 
= m_owner
->GetColumnWidth(col
); 
1517         if ( item
->HasImage() ) 
1520             m_owner
->DrawImage( item
->GetImage(), dc
, xOld
, y 
); 
1521             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
1523             ix 
+= IMAGE_MARGIN_IN_REPORT_MODE
; 
1529         wxDCClipper 
clipper(*dc
, xOld
, y
, width 
- 8, rect
.height
); 
1531         if ( item
->HasText() ) 
1533             DrawTextFormatted(dc
, item
->GetText(), col
, xOld
, y
, width 
- 8); 
1538 void wxListLineData::DrawTextFormatted(wxDC 
*dc
, 
1539                                        const wxString 
&text
, 
1545     wxString drawntext
, ellipsis
; 
1546     wxCoord w
, h
, base_w
; 
1549     // determine if the string can fit inside the current width 
1550     dc
->GetTextExtent(text
, &w
, &h
); 
1553         // it can, draw it using the items alignment 
1554         m_owner
->GetColumn(col
, item
); 
1555         switch ( item
.GetAlign() ) 
1558                 wxFAIL_MSG( _T("unknown list item format") ); 
1561             case wxLIST_FORMAT_LEFT
: 
1565             case wxLIST_FORMAT_RIGHT
: 
1569             case wxLIST_FORMAT_CENTER
: 
1570                 x 
+= (width 
- w
) / 2; 
1574         dc
->DrawText(text
, x
, y
); 
1576     else // otherwise, truncate and add an ellipsis if possible 
1578         // determine the base width 
1579         ellipsis 
= wxString(wxT("...")); 
1580         dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1582         // continue until we have enough space or only one character left 
1584         size_t len 
= text
.Length(); 
1585         drawntext 
= text
.Left(len
); 
1588             dc
->GetTextExtent(drawntext
.Last(), &w_c
, &h_c
); 
1589             drawntext
.RemoveLast(); 
1592             if (w 
+ base_w 
<= width
) 
1596         // if still not enough space, remove ellipsis characters 
1597         while (ellipsis
.Length() > 0 && w 
+ base_w 
> width
) 
1599             ellipsis 
= ellipsis
.Left(ellipsis
.Length() - 1); 
1600             dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1603         // now draw the text 
1604         dc
->DrawText(drawntext
, x
, y
); 
1605         dc
->DrawText(ellipsis
, x 
+ w
, y
); 
1609 bool wxListLineData::Highlight( bool on 
) 
1611     wxCHECK_MSG( !IsVirtual(), false, _T("unexpected call to Highlight") ); 
1613     if ( on 
== m_highlighted 
) 
1621 void wxListLineData::ReverseHighlight( void ) 
1623     Highlight(!IsHighlighted()); 
1626 //----------------------------------------------------------------------------- 
1627 //  wxListHeaderWindow 
1628 //----------------------------------------------------------------------------- 
1630 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
) 
1632 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
1633     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
1634     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
1635     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
1638 void wxListHeaderWindow::Init() 
1640     m_currentCursor 
= (wxCursor 
*) NULL
; 
1641     m_isDragging 
= false; 
1645 wxListHeaderWindow::wxListHeaderWindow() 
1649     m_owner 
= (wxListMainWindow 
*) NULL
; 
1650     m_resizeCursor 
= (wxCursor 
*) NULL
; 
1653 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, 
1655                                         wxListMainWindow 
*owner
, 
1659                                         const wxString 
&name 
) 
1660                   : wxWindow( win
, id
, pos
, size
, style
, name 
) 
1665     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
1668     wxVisualAttributes attr 
= wxPanel::GetClassDefaultAttributes(); 
1669     SetOwnForegroundColour( attr
.colFg 
); 
1670     SetOwnBackgroundColour( attr
.colBg 
); 
1672         SetOwnFont( attr
.font 
); 
1674     SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
1675     SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
1677         SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT 
)); 
1681 wxListHeaderWindow::~wxListHeaderWindow() 
1683     delete m_resizeCursor
; 
1686 #ifdef __WXUNIVERSAL__ 
1687 #include "wx/univ/renderer.h" 
1688 #include "wx/univ/theme.h" 
1691 // shift the DC origin to match the position of the main window horz 
1692 // scrollbar: this allows us to always use logical coords 
1693 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
1696     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1699     m_owner
->GetViewStart( &x
, NULL 
); 
1701     // account for the horz scrollbar offset 
1702     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1705 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1707     wxPaintDC 
dc( this ); 
1714     dc
.SetFont( GetFont() ); 
1716     // width and height of the entire header window 
1718     GetClientSize( &w
, &h 
); 
1719     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1721     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1723     dc
.SetTextForeground(GetForegroundColour()); 
1725     int x 
= HEADER_OFFSET_X
; 
1727     int numColumns 
= m_owner
->GetColumnCount(); 
1729     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1731         m_owner
->GetColumn( i
, item 
); 
1732         int wCol 
= item
.m_width
; 
1734         // the width of the rect to draw: make it smaller to fit entirely 
1735         // inside the column rect 
1738         wxRendererNative::Get().DrawHeaderButton
 
1742                                     wxRect(x
, HEADER_OFFSET_Y
, cw
, h 
- 2), 
1743                                     m_parent
->IsEnabled() ? 0 
1744                                                           : wxCONTROL_DISABLED
 
1747         // see if we have enough space for the column label 
1749         // for this we need the width of the text 
1752         dc
.GetTextExtent(item
.GetText(), &wLabel
, &hLabel
); 
1753         wLabel 
+= 2*EXTRA_WIDTH
; 
1755         // and the width of the icon, if any 
1756         static const int MARGIN_BETWEEN_TEXT_AND_ICON 
= 2; 
1757         int ix 
= 0,     // init them just to suppress the compiler warnings 
1759         const int image 
= item
.m_image
; 
1760         wxImageListType 
*imageList
; 
1763             imageList 
= m_owner
->m_small_image_list
; 
1766                 imageList
->GetSize(image
, ix
, iy
); 
1767                 wLabel 
+= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
1775         // ignore alignment if there is not enough space anyhow 
1777         switch ( wLabel 
< cw 
? item
.GetAlign() : wxLIST_FORMAT_LEFT 
) 
1780                 wxFAIL_MSG( _T("unknown list item format") ); 
1783             case wxLIST_FORMAT_LEFT
: 
1787             case wxLIST_FORMAT_RIGHT
: 
1788                 xAligned 
= x 
+ cw 
- wLabel
; 
1791             case wxLIST_FORMAT_CENTER
: 
1792                 xAligned 
= x 
+ (cw 
- wLabel
) / 2; 
1797         // if we have an image, draw it on the right of the label 
1804                         xAligned 
+ wLabel 
- ix 
- MARGIN_BETWEEN_TEXT_AND_ICON
, 
1805                         HEADER_OFFSET_Y 
+ (h 
- 4 - iy
)/2, 
1806                         wxIMAGELIST_DRAW_TRANSPARENT
 
1809             cw 
-= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
1812         // draw the text clipping it so that it doesn't overwrite the column 
1814         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h 
- 4 ); 
1816         dc
.DrawText( item
.GetText(), 
1817                      xAligned 
+ EXTRA_WIDTH
, h 
/ 2 - hLabel 
/ 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT ); 
1825 void wxListHeaderWindow::DrawCurrent() 
1827     int x1 
= m_currentX
; 
1829     m_owner
->ClientToScreen( &x1
, &y1 
); 
1831     int x2 
= m_currentX
; 
1833     m_owner
->GetClientSize( NULL
, &y2 
); 
1834     m_owner
->ClientToScreen( &x2
, &y2 
); 
1837     dc
.SetLogicalFunction( wxINVERT 
); 
1838     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
1839     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1843     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1845     dc
.SetLogicalFunction( wxCOPY 
); 
1847     dc
.SetPen( wxNullPen 
); 
1848     dc
.SetBrush( wxNullBrush 
); 
1851 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1853     // we want to work with logical coords 
1855     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1856     int y 
= event
.GetY(); 
1860         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1862         // we don't draw the line beyond our window, but we allow dragging it 
1865         GetClientSize( &w
, NULL 
); 
1866         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1869         // erase the line if it was drawn 
1870         if ( m_currentX 
< w 
) 
1873         if (event
.ButtonUp()) 
1876             m_isDragging 
= false; 
1878             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1879             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1886                 m_currentX 
= m_minX 
+ 7; 
1888             // draw in the new location 
1889             if ( m_currentX 
< w 
) 
1893     else // not dragging 
1896         bool hit_border 
= false; 
1898         // end of the current column 
1901         // find the column where this event occured 
1903             countCol 
= m_owner
->GetColumnCount(); 
1904         for (col 
= 0; col 
< countCol
; col
++) 
1906             xpos 
+= m_owner
->GetColumnWidth( col 
); 
1909             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
1911                 // near the column border 
1918                 // inside the column 
1925         if ( col 
== countCol 
) 
1928         if (event
.LeftDown() || event
.RightUp()) 
1930             if (hit_border 
&& event
.LeftDown()) 
1932                 if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
1933                                    event
.GetPosition()) ) 
1935                     m_isDragging 
= true; 
1940                 //else: column resizing was vetoed by the user code 
1942             else // click on a column 
1944                 SendListEvent( event
.LeftDown() 
1945                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
1946                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
1947                                 event
.GetPosition()); 
1950         else if (event
.Moving()) 
1955                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
1956                 m_currentCursor 
= m_resizeCursor
; 
1960                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
1961                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1965                 SetCursor(*m_currentCursor
); 
1970 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1972     m_owner
->SetFocus(); 
1976 bool wxListHeaderWindow::SendListEvent(wxEventType type
, wxPoint pos
) 
1978     wxWindow 
*parent 
= GetParent(); 
1979     wxListEvent 
le( type
, parent
->GetId() ); 
1980     le
.SetEventObject( parent 
); 
1981     le
.m_pointDrag 
= pos
; 
1983     // the position should be relative to the parent window, not 
1984     // this one for compatibility with MSW and common sense: the 
1985     // user code doesn't know anything at all about this header 
1986     // window, so why should it get positions relative to it? 
1987     le
.m_pointDrag
.y 
-= GetSize().y
; 
1989     le
.m_col 
= m_column
; 
1990     return !parent
->GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
1993 //----------------------------------------------------------------------------- 
1994 // wxListRenameTimer (internal) 
1995 //----------------------------------------------------------------------------- 
1997 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
2002 void wxListRenameTimer::Notify() 
2004     m_owner
->OnRenameTimer(); 
2007 //----------------------------------------------------------------------------- 
2008 // wxListTextCtrl (internal) 
2009 //----------------------------------------------------------------------------- 
2011 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
) 
2012     EVT_CHAR           (wxListTextCtrl::OnChar
) 
2013     EVT_KEY_UP         (wxListTextCtrl::OnKeyUp
) 
2014     EVT_KILL_FOCUS     (wxListTextCtrl::OnKillFocus
) 
2017 wxListTextCtrl::wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
) 
2018               : m_startValue(owner
->GetItemText(itemEdit
)), 
2019                 m_itemEdited(itemEdit
) 
2024     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
2026     m_owner
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
2027                                   &rectLabel
.x
, &rectLabel
.y
); 
2029     (void)Create(owner
, wxID_ANY
, m_startValue
, 
2030                  wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2031                  wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
2034 void wxListTextCtrl::Finish() 
2038         wxPendingDelete
.Append(this); 
2042         m_owner
->SetFocus(); 
2046 bool wxListTextCtrl::AcceptChanges() 
2048     const wxString value 
= GetValue(); 
2050     if ( value 
== m_startValue 
) 
2052         // nothing changed, always accept 
2056     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
2058         // vetoed by the user 
2062     // accepted, do rename the item 
2063     m_owner
->SetItemText(m_itemEdited
, value
); 
2068 void wxListTextCtrl::OnChar( wxKeyEvent 
&event 
) 
2070     switch ( event
.m_keyCode 
) 
2073             if ( !AcceptChanges() ) 
2075                 // vetoed by the user code 
2078             //else: fall through 
2082             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2090 void wxListTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
2098     // auto-grow the textctrl: 
2099     wxSize parentSize 
= m_owner
->GetSize(); 
2100     wxPoint myPos 
= GetPosition(); 
2101     wxSize mySize 
= GetSize(); 
2103     GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); 
2104     if (myPos
.x 
+ sx 
> parentSize
.x
) 
2105         sx 
= parentSize
.x 
- myPos
.x
; 
2108     SetSize(sx
, wxDefaultCoord
); 
2113 void wxListTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2117         // We must finish regardless of success, otherwise we'll get 
2121         if ( !AcceptChanges() ) 
2122             m_owner
->OnRenameCancelled( m_itemEdited 
); 
2125     // We must let the native text control handle focus, too, otherwise 
2126     // it could have problems with the cursor (e.g., in wxGTK): 
2130 //----------------------------------------------------------------------------- 
2132 //----------------------------------------------------------------------------- 
2134 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
) 
2136 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
) 
2137   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2138   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2139   EVT_CHAR           (wxListMainWindow::OnChar
) 
2140   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2141   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2142   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2143   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2146 void wxListMainWindow::Init() 
2151     m_lineTo 
= (size_t)-1; 
2157     m_small_image_list 
= (wxImageListType 
*) NULL
; 
2158     m_normal_image_list 
= (wxImageListType 
*) NULL
; 
2160     m_small_spacing 
= 30; 
2161     m_normal_spacing 
= 40; 
2165     m_isCreated 
= false; 
2167     m_lastOnSame 
= false; 
2168     m_renameTimer 
= new wxListRenameTimer( this ); 
2172     m_lineBeforeLastClicked 
= (size_t)-1; 
2177 wxListMainWindow::wxListMainWindow() 
2182     m_highlightUnfocusedBrush 
= (wxBrush 
*) NULL
; 
2185 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2190                                     const wxString 
&name 
) 
2191                 : wxScrolledWindow( parent
, id
, pos
, size
, 
2192                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2196     m_highlightBrush 
= new wxBrush
 
2198                             wxSystemSettings::GetColour
 
2200                                 wxSYS_COLOUR_HIGHLIGHT
 
2205     m_highlightUnfocusedBrush 
= new wxBrush
 
2207                                        wxSystemSettings::GetColour
 
2209                                            wxSYS_COLOUR_BTNSHADOW
 
2217     SetScrollbars( 0, 0, 0, 0, 0, 0 ); 
2219     wxVisualAttributes attr 
= wxGenericListCtrl::GetClassDefaultAttributes(); 
2220     SetOwnForegroundColour( attr
.colFg 
); 
2221     SetOwnBackgroundColour( attr
.colBg 
); 
2223         SetOwnFont( attr
.font 
); 
2226 wxListMainWindow::~wxListMainWindow() 
2229     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
2231     delete m_highlightBrush
; 
2232     delete m_highlightUnfocusedBrush
; 
2234     delete m_renameTimer
; 
2237 void wxListMainWindow::CacheLineData(size_t line
) 
2239     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
2241     wxListLineData 
*ld 
= GetDummyLine(); 
2243     size_t countCol 
= GetColumnCount(); 
2244     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2246         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2249     ld
->SetImage(listctrl
->OnGetItemImage(line
)); 
2250     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
2253 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2255     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2257     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); 
2259     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2261     // we need to recreate the dummy line if the number of columns in the 
2262     // control changed as it would have the incorrect number of fields 
2264     if ( !m_lines
.IsEmpty() && 
2265             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
2267         self
->m_lines
.Clear(); 
2270     if ( m_lines
.IsEmpty() ) 
2272         wxListLineData 
*line 
= new wxListLineData(self
); 
2273         self
->m_lines
.Add(line
); 
2275         // don't waste extra memory -- there never going to be anything 
2276         // else/more in this array 
2277         self
->m_lines
.Shrink(); 
2283 // ---------------------------------------------------------------------------- 
2284 // line geometry (report mode only) 
2285 // ---------------------------------------------------------------------------- 
2287 wxCoord 
wxListMainWindow::GetLineHeight() const 
2289     // we cache the line height as calling GetTextExtent() is slow 
2290     if ( !m_lineHeight 
) 
2292         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2294         wxClientDC 
dc( self 
); 
2295         dc
.SetFont( GetFont() ); 
2298         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2300         if ( m_small_image_list 
&& m_small_image_list
->GetImageCount() ) 
2304             m_small_image_list
->GetSize(0, iw
, ih
); 
2309         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2312     return m_lineHeight
; 
2315 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2317     wxASSERT_MSG( InReportView(), _T("only works in report mode") ); 
2319     return LINE_SPACING 
+ line
*GetLineHeight(); 
2322 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2324     if ( !InReportView() ) 
2325         return GetLine(line
)->m_gi
->m_rectAll
; 
2328     rect
.x 
= HEADER_OFFSET_X
; 
2329     rect
.y 
= GetLineY(line
); 
2330     rect
.width 
= GetHeaderWidth(); 
2331     rect
.height 
= GetLineHeight(); 
2336 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2338     if ( !InReportView() ) 
2339         return GetLine(line
)->m_gi
->m_rectLabel
; 
2342     rect
.x 
= HEADER_OFFSET_X
; 
2343     rect
.y 
= GetLineY(line
); 
2344     rect
.width 
= GetColumnWidth(0); 
2345     rect
.height 
= GetLineHeight(); 
2350 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2352     if ( !InReportView() ) 
2353         return GetLine(line
)->m_gi
->m_rectIcon
; 
2355     wxListLineData 
*ld 
= GetLine(line
); 
2356     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2359     rect
.x 
= HEADER_OFFSET_X
; 
2360     rect
.y 
= GetLineY(line
); 
2361     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2366 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2368     return InReportView() ? GetLineRect(line
) 
2369                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2372 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2374     wxASSERT_MSG( line 
< GetItemCount(), _T("invalid line in HitTestLine") ); 
2376     wxListLineData 
*ld 
= GetLine(line
); 
2378     if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) ) 
2379         return wxLIST_HITTEST_ONITEMICON
; 
2381     // VS: Testing for "ld->HasText() || InReportView()" instead of 
2382     //     "ld->HasText()" is needed to make empty lines in report view 
2384     if ( ld
->HasText() || InReportView() ) 
2386         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2387                                      : GetLineLabelRect(line
); 
2389         if ( rect
.Inside(x
, y
) ) 
2390             return wxLIST_HITTEST_ONITEMLABEL
; 
2396 // ---------------------------------------------------------------------------- 
2397 // highlight (selection) handling 
2398 // ---------------------------------------------------------------------------- 
2400 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2404         return m_selStore
.IsSelected(line
); 
2408         wxListLineData 
*ld 
= GetLine(line
); 
2409         wxCHECK_MSG( ld
, false, _T("invalid index in IsHighlighted") ); 
2411         return ld
->IsHighlighted(); 
2415 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
2421         wxArrayInt linesChanged
; 
2422         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
2425             // meny items changed state, refresh everything 
2426             RefreshLines(lineFrom
, lineTo
); 
2428         else // only a few items changed state, refresh only them 
2430             size_t count 
= linesChanged
.GetCount(); 
2431             for ( size_t n 
= 0; n 
< count
; n
++ ) 
2433                 RefreshLine(linesChanged
[n
]); 
2437     else // iterate over all items in non report view 
2439         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2441             if ( HighlightLine(line
, highlight
) ) 
2449 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2455         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2459         wxListLineData 
*ld 
= GetLine(line
); 
2460         wxCHECK_MSG( ld
, false, _T("invalid index in HighlightLine") ); 
2462         changed 
= ld
->Highlight(highlight
); 
2467         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2468                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2474 void wxListMainWindow::RefreshLine( size_t line 
) 
2476     if ( InReportView() ) 
2478         size_t visibleFrom
, visibleTo
; 
2479         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2481         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
2485     wxRect rect 
= GetLineRect(line
); 
2487     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2488     RefreshRect( rect 
); 
2491 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2493     // we suppose that they are ordered by caller 
2494     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2496     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2498     if ( InReportView() ) 
2500         size_t visibleFrom
, visibleTo
; 
2501         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2503         if ( lineFrom 
< visibleFrom 
) 
2504             lineFrom 
= visibleFrom
; 
2505         if ( lineTo 
> visibleTo 
) 
2510         rect
.y 
= GetLineY(lineFrom
); 
2511         rect
.width 
= GetClientSize().x
; 
2512         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
2514         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2515         RefreshRect( rect 
); 
2519         // TODO: this should be optimized... 
2520         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2527 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2529     if ( InReportView() ) 
2531         size_t visibleFrom
, visibleTo
; 
2532         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2534         if ( lineFrom 
< visibleFrom 
) 
2535             lineFrom 
= visibleFrom
; 
2536         else if ( lineFrom 
> visibleTo 
) 
2541         rect
.y 
= GetLineY(lineFrom
); 
2542         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2544         wxSize size 
= GetClientSize(); 
2545         rect
.width 
= size
.x
; 
2546         // refresh till the bottom of the window 
2547         rect
.height 
= size
.y 
- rect
.y
; 
2549         RefreshRect( rect 
); 
2553         // TODO: how to do it more efficiently? 
2558 void wxListMainWindow::RefreshSelected() 
2564     if ( InReportView() ) 
2566         GetVisibleLinesRange(&from
, &to
); 
2571         to 
= GetItemCount() - 1; 
2574     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
2576         RefreshLine(m_current
); 
2579     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
2581         // NB: the test works as expected even if m_current == -1 
2582         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
2589 void wxListMainWindow::Freeze() 
2594 void wxListMainWindow::Thaw() 
2596     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen list control?") ); 
2598     if ( !--m_freezeCount 
) 
2604 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2606     // Note: a wxPaintDC must be constructed even if no drawing is 
2607     // done (a Windows requirement). 
2608     wxPaintDC 
dc( this ); 
2610     if ( IsEmpty() || m_freezeCount 
) 
2612         // nothing to draw or not the moment to draw it 
2618         // delay the repainting until we calculate all the items positions 
2625     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2629     dc
.SetFont( GetFont() ); 
2631     if ( InReportView() ) 
2633         int lineHeight 
= GetLineHeight(); 
2635         size_t visibleFrom
, visibleTo
; 
2636         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2639         wxCoord xOrig
, yOrig
; 
2640         CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
); 
2642         // tell the caller cache to cache the data 
2645             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2646                                 GetParent()->GetId()); 
2647             evCache
.SetEventObject( GetParent() ); 
2648             evCache
.m_oldItemIndex 
= visibleFrom
; 
2649             evCache
.m_itemIndex 
= visibleTo
; 
2650             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2653         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2655             rectLine 
= GetLineRect(line
); 
2657             if ( !IsExposed(rectLine
.x 
- xOrig
, rectLine
.y 
- yOrig
, 
2658                             rectLine
.width
, rectLine
.height
) ) 
2660                 // don't redraw unaffected lines to avoid flicker 
2664             GetLine(line
)->DrawInReportMode( &dc
, 
2666                                              GetLineHighlightRect(line
), 
2667                                              IsHighlighted(line
) ); 
2670         if ( HasFlag(wxLC_HRULES
) ) 
2672             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2673             wxSize clientSize 
= GetClientSize(); 
2675             // Don't draw the first one 
2676             for ( size_t i 
= visibleFrom
+1; i 
<= visibleTo
; i
++ ) 
2679                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2680                 dc
.DrawLine(0 - dev_x
, i
*lineHeight
, 
2681                             clientSize
.x 
- dev_x
, i
*lineHeight
); 
2684             // Draw last horizontal rule 
2685             if ( visibleTo 
== GetItemCount() - 1 ) 
2688                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2689                 dc
.DrawLine(0 - dev_x
, (m_lineTo
+1)*lineHeight
, 
2690                             clientSize
.x 
- dev_x 
, (m_lineTo
+1)*lineHeight 
); 
2694         // Draw vertical rules if required 
2695         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2697             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2699             wxRect firstItemRect
; 
2700             wxRect lastItemRect
; 
2701             GetItemRect(visibleFrom
, firstItemRect
); 
2702             GetItemRect(visibleTo
, lastItemRect
); 
2703             int x 
= firstItemRect
.GetX(); 
2705             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2706             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2708                 int colWidth 
= GetColumnWidth(col
); 
2710                 dc
.DrawLine(x 
- dev_x 
- 2, firstItemRect
.GetY() - 1 - dev_y
, 
2711                             x 
- dev_x 
- 2, lastItemRect
.GetBottom() + 1 - dev_y
); 
2717         size_t count 
= GetItemCount(); 
2718         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2720             GetLine(i
)->Draw( &dc 
); 
2725     // Don't draw rect outline under Mac at all. 
2730             dc
.SetPen( *wxBLACK_PEN 
); 
2731             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2732             dc
.DrawRectangle( GetLineHighlightRect(m_current
) ); 
2740 void wxListMainWindow::HighlightAll( bool on 
) 
2742     if ( IsSingleSel() ) 
2744         wxASSERT_MSG( !on
, _T("can't do this in a single sel control") ); 
2746         // we just have one item to turn off 
2747         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2749             HighlightLine(m_current
, false); 
2750             RefreshLine(m_current
); 
2755         HighlightLines(0, GetItemCount() - 1, on
); 
2759 void wxListMainWindow::SendNotify( size_t line
, 
2760                                    wxEventType command
, 
2763     wxListEvent 
le( command
, GetParent()->GetId() ); 
2764     le
.SetEventObject( GetParent() ); 
2765     le
.m_itemIndex 
= line
; 
2767     // set only for events which have position 
2768     if ( point 
!= wxDefaultPosition 
) 
2769         le
.m_pointDrag 
= point
; 
2771     // don't try to get the line info for virtual list controls: the main 
2772     // program has it anyhow and if we did it would result in accessing all 
2773     // the lines, even those which are not visible now and this is precisely 
2774     // what we're trying to avoid 
2775     if ( !IsVirtual() && (command 
!= wxEVT_COMMAND_LIST_DELETE_ITEM
) ) 
2777         if ( line 
!= (size_t)-1 ) 
2779             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2781         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2783     //else: there may be no more such item 
2785     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2788 void wxListMainWindow::ChangeCurrent(size_t current
) 
2790     m_current 
= current
; 
2792     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2795 void wxListMainWindow::EditLabel( long item 
) 
2797     wxCHECK_RET( (item 
>= 0) && ((size_t)item 
< GetItemCount()), 
2798                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2800     size_t itemEdit 
= (size_t)item
; 
2802     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2803     le
.SetEventObject( GetParent() ); 
2804     le
.m_itemIndex 
= item
; 
2805     wxListLineData 
*data 
= GetLine(itemEdit
); 
2806     wxCHECK_RET( data
, _T("invalid index in EditLabel()") ); 
2807     data
->GetItem( 0, le
.m_item 
); 
2808     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2810         // vetoed by user code 
2814     // We have to call this here because the label in question might just have 
2815     // been added and no screen update taken place. 
2819     wxListTextCtrl 
*text 
= new wxListTextCtrl(this, itemEdit
); 
2824 void wxListMainWindow::OnRenameTimer() 
2826     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2828     EditLabel( m_current 
); 
2831 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2833     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2834     le
.SetEventObject( GetParent() ); 
2835     le
.m_itemIndex 
= itemEdit
; 
2837     wxListLineData 
*data 
= GetLine(itemEdit
); 
2838     wxCHECK_MSG( data
, false, _T("invalid index in OnRenameAccept()") ); 
2840     data
->GetItem( 0, le
.m_item 
); 
2841     le
.m_item
.m_text 
= value
; 
2842     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2846 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2848     // let owner know that the edit was cancelled 
2849     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2851     le
.SetEditCanceled(true); 
2853     le
.SetEventObject( GetParent() ); 
2854     le
.m_itemIndex 
= itemEdit
; 
2856     wxListLineData 
*data 
= GetLine(itemEdit
); 
2857     wxCHECK_RET( data
, _T("invalid index in OnRenameCancelled()") ); 
2859     data
->GetItem( 0, le
.m_item 
); 
2861     GetEventHandler()->ProcessEvent( le 
); 
2864 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2866     event
.SetEventObject( GetParent() ); 
2867     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2870     if ( !HasCurrent() || IsEmpty() ) 
2876     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
2877         event
.ButtonDClick()) ) 
2880     int x 
= event
.GetX(); 
2881     int y 
= event
.GetY(); 
2882     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2884     // where did we hit it (if we did)? 
2887     size_t count 
= GetItemCount(), 
2890     if ( InReportView() ) 
2892         current 
= y 
/ GetLineHeight(); 
2893         if ( current 
< count 
) 
2894             hitResult 
= HitTestLine(current
, x
, y
); 
2898         // TODO: optimize it too! this is less simple than for report view but 
2899         //       enumerating all items is still not a way to do it!! 
2900         for ( current 
= 0; current 
< count
; current
++ ) 
2902             hitResult 
= HitTestLine(current
, x
, y
); 
2908     if (event
.Dragging()) 
2910         if (m_dragCount 
== 0) 
2912             // we have to report the raw, physical coords as we want to be 
2913             // able to call HitTest(event.m_pointDrag) from the user code to 
2914             // get the item being dragged 
2915             m_dragStart 
= event
.GetPosition(); 
2920         if (m_dragCount 
!= 3) 
2923         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
2924                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2926         wxListEvent 
le( command
, GetParent()->GetId() ); 
2927         le
.SetEventObject( GetParent() ); 
2928         le
.m_itemIndex 
= current
; 
2929         le
.m_pointDrag 
= m_dragStart
; 
2930         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2941         // outside of any item 
2945     bool forceClick 
= false; 
2946     if (event
.ButtonDClick()) 
2948         m_renameTimer
->Stop(); 
2949         m_lastOnSame 
= false; 
2951         if ( current 
== m_lineLastClicked 
) 
2953             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2959             // the first click was on another item, so don't interpret this as 
2960             // a double click, but as a simple click instead 
2965     if (event
.LeftUp() && m_lastOnSame
) 
2967         if ((current 
== m_current
) && 
2968             (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
2969             HasFlag(wxLC_EDIT_LABELS
)  ) 
2971             m_renameTimer
->Start( 100, true ); 
2973         m_lastOnSame 
= false; 
2975     else if (event
.RightDown()) 
2977         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, 
2978                     event
.GetPosition() ); 
2980     else if (event
.MiddleDown()) 
2982         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
2984     else if ( event
.LeftDown() || forceClick 
) 
2986         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2987         m_lineLastClicked 
= current
; 
2989         size_t oldCurrent 
= m_current
; 
2990         bool cmdModifierDown 
= event
.CmdDown(); 
2991         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
2993             HighlightAll( false ); 
2995             ChangeCurrent(current
); 
2997             ReverseHighlight(m_current
); 
2999         else // multi sel & either ctrl or shift is down 
3001             if (cmdModifierDown
) 
3003                 ChangeCurrent(current
); 
3005                 ReverseHighlight(m_current
); 
3007             else if (event
.ShiftDown()) 
3009                 ChangeCurrent(current
); 
3011                 size_t lineFrom 
= oldCurrent
, 
3014                 if ( lineTo 
< lineFrom 
) 
3017                     lineFrom 
= m_current
; 
3020                 HighlightLines(lineFrom
, lineTo
); 
3022             else // !ctrl, !shift 
3024                 // test in the enclosing if should make it impossible 
3025                 wxFAIL_MSG( _T("how did we get here?") ); 
3029         if (m_current 
!= oldCurrent
) 
3031             RefreshLine( oldCurrent 
); 
3034         // forceClick is only set if the previous click was on another item 
3035         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
); 
3039 void wxListMainWindow::MoveToItem(size_t item
) 
3041     if ( item 
== (size_t)-1 ) 
3044     wxRect rect 
= GetLineRect(item
); 
3046     int client_w
, client_h
; 
3047     GetClientSize( &client_w
, &client_h 
); 
3049     const int hLine 
= GetLineHeight(); 
3051     int view_x 
= SCROLL_UNIT_X
*GetScrollPos( wxHORIZONTAL 
); 
3052     int view_y 
= hLine
*GetScrollPos( wxVERTICAL 
); 
3054     if ( InReportView() ) 
3056         // the next we need the range of lines shown it might be different, so 
3058         ResetVisibleLinesRange(); 
3060         if (rect
.y 
< view_y 
) 
3061             Scroll( -1, rect
.y
/hLine 
); 
3062         if (rect
.y
+rect
.height
+5 > view_y
+client_h
) 
3063             Scroll( -1, (rect
.y
+rect
.height
-client_h
+hLine
)/hLine 
); 
3067         if (rect
.x
-view_x 
< 5) 
3068             Scroll( (rect
.x
-5)/SCROLL_UNIT_X
, -1 ); 
3069         if (rect
.x
+rect
.width
-5 > view_x
+client_w
) 
3070             Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/SCROLL_UNIT_X
, -1 ); 
3074 // ---------------------------------------------------------------------------- 
3075 // keyboard handling 
3076 // ---------------------------------------------------------------------------- 
3078 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
3080     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
3081                  _T("invalid item index in OnArrowChar()") ); 
3083     size_t oldCurrent 
= m_current
; 
3085     // in single selection we just ignore Shift as we can't select several 
3087     if ( event
.ShiftDown() && !IsSingleSel() ) 
3089         ChangeCurrent(newCurrent
); 
3091         // refresh the old focus to remove it 
3092         RefreshLine( oldCurrent 
); 
3094         // select all the items between the old and the new one 
3095         if ( oldCurrent 
> newCurrent 
) 
3097             newCurrent 
= oldCurrent
; 
3098             oldCurrent 
= m_current
; 
3101         HighlightLines(oldCurrent
, newCurrent
); 
3105         // all previously selected items are unselected unless ctrl is held 
3106         if ( !event
.ControlDown() ) 
3107             HighlightAll(false); 
3109         ChangeCurrent(newCurrent
); 
3111         // refresh the old focus to remove it 
3112         RefreshLine( oldCurrent 
); 
3114         if ( !event
.ControlDown() ) 
3116             HighlightLine( m_current
, true ); 
3120     RefreshLine( m_current 
); 
3125 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
3127     wxWindow 
*parent 
= GetParent(); 
3129     /* we propagate the key event up */ 
3130     wxKeyEvent 
ke( wxEVT_KEY_DOWN 
); 
3131     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3132     ke
.m_controlDown 
= event
.m_controlDown
; 
3133     ke
.m_altDown 
= event
.m_altDown
; 
3134     ke
.m_metaDown 
= event
.m_metaDown
; 
3135     ke
.m_keyCode 
= event
.m_keyCode
; 
3138     ke
.SetEventObject( parent 
); 
3139     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3144 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
3146     wxWindow 
*parent 
= GetParent(); 
3148     /* we send a list_key event up */ 
3151         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
3152         le
.m_itemIndex 
= m_current
; 
3153         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3154         le
.m_code 
= event
.GetKeyCode(); 
3155         le
.SetEventObject( parent 
); 
3156         parent
->GetEventHandler()->ProcessEvent( le 
); 
3159     /* we propagate the char event up */ 
3160     wxKeyEvent 
ke( wxEVT_CHAR 
); 
3161     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3162     ke
.m_controlDown 
= event
.m_controlDown
; 
3163     ke
.m_altDown 
= event
.m_altDown
; 
3164     ke
.m_metaDown 
= event
.m_metaDown
; 
3165     ke
.m_keyCode 
= event
.m_keyCode
; 
3168     ke
.SetEventObject( parent 
); 
3169     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3171     if (event
.GetKeyCode() == WXK_TAB
) 
3173         wxNavigationKeyEvent nevent
; 
3174         nevent
.SetWindowChange( event
.ControlDown() ); 
3175         nevent
.SetDirection( !event
.ShiftDown() ); 
3176         nevent
.SetEventObject( GetParent()->GetParent() ); 
3177         nevent
.SetCurrentFocus( m_parent 
); 
3178         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent 
)) 
3182     /* no item -> nothing to do */ 
3189     switch (event
.GetKeyCode()) 
3192             if ( m_current 
> 0 ) 
3193                 OnArrowChar( m_current 
- 1, event 
); 
3197             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
3198                 OnArrowChar( m_current 
+ 1, event 
); 
3203                 OnArrowChar( GetItemCount() - 1, event 
); 
3208                 OnArrowChar( 0, event 
); 
3213                 int steps 
= InReportView() ? m_linesPerPage 
- 1 : m_current 
% m_linesPerPage
; 
3215                 int index 
= m_current 
- steps
; 
3219                 OnArrowChar( index
, event 
); 
3225                 int steps 
= InReportView() 
3226                                ? m_linesPerPage 
- 1 
3227                                : m_linesPerPage 
- (m_current 
% m_linesPerPage
) - 1; 
3229                 size_t index 
= m_current 
+ steps
; 
3230                 size_t count 
= GetItemCount(); 
3231                 if ( index 
>= count 
) 
3234                 OnArrowChar( index
, event 
); 
3239             if ( !InReportView() ) 
3241                 int index 
= m_current 
- m_linesPerPage
; 
3245                 OnArrowChar( index
, event 
); 
3250             if ( !InReportView() ) 
3252                 size_t index 
= m_current 
+ m_linesPerPage
; 
3254                 size_t count 
= GetItemCount(); 
3255                 if ( index 
>= count 
) 
3258                 OnArrowChar( index
, event 
); 
3263             if ( IsSingleSel() ) 
3265                 SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3267                 if ( IsHighlighted(m_current
) ) 
3269                     // don't unselect the item in single selection mode 
3272                 //else: select it in ReverseHighlight() below if unselected 
3275             ReverseHighlight(m_current
); 
3280             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3288 // ---------------------------------------------------------------------------- 
3290 // ---------------------------------------------------------------------------- 
3292 void wxListMainWindow::SetFocus() 
3294     // VS: wxListMainWindow derives from wxPanel (via wxScrolledWindow) and wxPanel 
3295     //     overrides SetFocus in such way that it does never change focus from 
3296     //     panel's child to the panel itself. Unfortunately, we must be able to change 
3297     //     focus to the panel from wxListTextCtrl because the text control should 
3298     //     disappear when the user clicks outside it. 
3300     wxWindow 
*oldFocus 
= FindFocus(); 
3302     if ( oldFocus 
&& oldFocus
->GetParent() == this ) 
3304         wxWindow::SetFocus(); 
3308         wxScrolledWindow::SetFocus(); 
3312 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3316         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3317         event
.SetEventObject( GetParent() ); 
3318         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3322     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
3323     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
3324     // which are already drawn correctly resulting in horrible flicker - avoid 
3334 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3338         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
3339         event
.SetEventObject( GetParent() ); 
3340         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3347 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3349     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3351         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3353     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3355         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3357     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3359         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3361     else if ( InReportView() && (m_small_image_list
)) 
3363         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3367 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3369     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3371         m_normal_image_list
->GetSize( index
, width
, height 
); 
3373     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3375         m_small_image_list
->GetSize( index
, width
, height 
); 
3377     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3379         m_small_image_list
->GetSize( index
, width
, height 
); 
3381     else if ( InReportView() && m_small_image_list 
) 
3383         m_small_image_list
->GetSize( index
, width
, height 
); 
3392 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3394     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3395     dc
.SetFont( GetFont() ); 
3398     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3400     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3403 void wxListMainWindow::SetImageList( wxImageListType 
*imageList
, int which 
) 
3407     // calc the spacing from the icon size 
3410     if ((imageList
) && (imageList
->GetImageCount()) ) 
3412         imageList
->GetSize(0, width
, height
); 
3415     if (which 
== wxIMAGE_LIST_NORMAL
) 
3417         m_normal_image_list 
= imageList
; 
3418         m_normal_spacing 
= width 
+ 8; 
3421     if (which 
== wxIMAGE_LIST_SMALL
) 
3423         m_small_image_list 
= imageList
; 
3424         m_small_spacing 
= width 
+ 14; 
3425         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
3429 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3434         m_small_spacing 
= spacing
; 
3438         m_normal_spacing 
= spacing
; 
3442 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3444     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3447 // ---------------------------------------------------------------------------- 
3449 // ---------------------------------------------------------------------------- 
3451 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3453     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3455     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3457     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3458         item
.m_width 
= GetTextLength( item
.m_text 
); 
3460     wxListHeaderData 
*column 
= node
->GetData(); 
3461     column
->SetItem( item 
); 
3463     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3465         headerWin
->m_dirty 
= true; 
3469     // invalidate it as it has to be recalculated 
3473 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3475     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3476                  _T("invalid column index") ); 
3478     wxCHECK_RET( InReportView(), 
3479                  _T("SetColumnWidth() can only be called in report mode.") ); 
3482     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3484         headerWin
->m_dirty 
= true; 
3486     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3487     wxCHECK_RET( node
, _T("no column?") ); 
3489     wxListHeaderData 
*column 
= node
->GetData(); 
3491     size_t count 
= GetItemCount(); 
3493     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3495         width 
= GetTextLength(column
->GetText()); 
3497     else if ( width 
== wxLIST_AUTOSIZE 
) 
3501             // TODO: determine the max width somehow... 
3502             width 
= WIDTH_COL_DEFAULT
; 
3506             wxClientDC 
dc(this); 
3507             dc
.SetFont( GetFont() ); 
3509             int max 
= AUTOSIZE_COL_MARGIN
; 
3511             for ( size_t i 
= 0; i 
< count
; i
++ ) 
3513                 wxListLineData 
*line 
= GetLine(i
); 
3514                 wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3516                 wxCHECK_RET( n
, _T("no subitem?") ); 
3518                 wxListItemData 
*item 
= n
->GetData(); 
3521                 if (item
->HasImage()) 
3524                     GetImageSize( item
->GetImage(), ix
, iy 
); 
3528                 if (item
->HasText()) 
3531                     dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
3539             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3543     column
->SetWidth( width 
); 
3545     // invalidate it as it has to be recalculated 
3549 int wxListMainWindow::GetHeaderWidth() const 
3551     if ( !m_headerWidth 
) 
3553         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3555         size_t count 
= GetColumnCount(); 
3556         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3558             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3562     return m_headerWidth
; 
3565 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3567     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3568     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3570     wxListHeaderData 
*column 
= node
->GetData(); 
3571     column
->GetItem( item 
); 
3574 int wxListMainWindow::GetColumnWidth( int col 
) const 
3576     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3577     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3579     wxListHeaderData 
*column 
= node
->GetData(); 
3580     return column
->GetWidth(); 
3583 // ---------------------------------------------------------------------------- 
3585 // ---------------------------------------------------------------------------- 
3587 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3589     long id 
= item
.m_itemId
; 
3590     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3591                  _T("invalid item index in SetItem") ); 
3595         wxListLineData 
*line 
= GetLine((size_t)id
); 
3596         line
->SetItem( item
.m_col
, item 
); 
3599     // update the item on screen 
3601     GetItemRect(id
, rectItem
); 
3602     RefreshRect(rectItem
); 
3605 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3607      wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3608                   _T("invalid list ctrl item index in SetItem") ); 
3610     size_t oldCurrent 
= m_current
; 
3611     size_t item 
= (size_t)litem
;    // safe because of the check above 
3613     // do we need to change the focus? 
3614     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3616         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3618             // don't do anything if this item is already focused 
3619             if ( item 
!= m_current 
) 
3621                 ChangeCurrent(item
); 
3623                 if ( oldCurrent 
!= (size_t)-1 ) 
3625                     if ( IsSingleSel() ) 
3627                         HighlightLine(oldCurrent
, false); 
3630                     RefreshLine(oldCurrent
); 
3633                 RefreshLine( m_current 
); 
3638             // don't do anything if this item is not focused 
3639             if ( item 
== m_current 
) 
3643                 if ( IsSingleSel() ) 
3645                     // we must unselect the old current item as well or we 
3646                     // might end up with more than one selected item in a 
3647                     // single selection control 
3648                     HighlightLine(oldCurrent
, false); 
3651                 RefreshLine( oldCurrent 
); 
3656     // do we need to change the selection state? 
3657     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3659         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3661         if ( IsSingleSel() ) 
3665                 // selecting the item also makes it the focused one in the 
3667                 if ( m_current 
!= item 
) 
3669                     ChangeCurrent(item
); 
3671                     if ( oldCurrent 
!= (size_t)-1 ) 
3673                         HighlightLine( oldCurrent
, false ); 
3674                         RefreshLine( oldCurrent 
); 
3680                 // only the current item may be selected anyhow 
3681                 if ( item 
!= m_current 
) 
3686         if ( HighlightLine(item
, on
) ) 
3693 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
3695     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3696                  _T("invalid list ctrl item index in GetItemState()") ); 
3698     int ret 
= wxLIST_STATE_DONTCARE
; 
3700     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3702         if ( (size_t)item 
== m_current 
) 
3703             ret 
|= wxLIST_STATE_FOCUSED
; 
3706     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3708         if ( IsHighlighted(item
) ) 
3709             ret 
|= wxLIST_STATE_SELECTED
; 
3715 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
3717     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3718                  _T("invalid item index in GetItem") ); 
3720     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3721     line
->GetItem( item
.m_col
, item 
); 
3724 // ---------------------------------------------------------------------------- 
3726 // ---------------------------------------------------------------------------- 
3728 size_t wxListMainWindow::GetItemCount() const 
3730     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3733 void wxListMainWindow::SetItemCount(long count
) 
3735     m_selStore
.SetItemCount(count
); 
3736     m_countVirt 
= count
; 
3738     ResetVisibleLinesRange(); 
3740     // scrollbars must be reset 
3744 int wxListMainWindow::GetSelectedItemCount() const 
3746     // deal with the quick case first 
3747     if ( IsSingleSel() ) 
3749         return HasCurrent() ? IsHighlighted(m_current
) : false; 
3752     // virtual controls remmebers all its selections itself 
3754         return m_selStore
.GetSelectedCount(); 
3756     // TODO: we probably should maintain the number of items selected even for 
3757     //       non virtual controls as enumerating all lines is really slow... 
3758     size_t countSel 
= 0; 
3759     size_t count 
= GetItemCount(); 
3760     for ( size_t line 
= 0; line 
< count
; line
++ ) 
3762         if ( GetLine(line
)->IsHighlighted() ) 
3769 // ---------------------------------------------------------------------------- 
3770 // item position/size 
3771 // ---------------------------------------------------------------------------- 
3773 wxRect 
wxListMainWindow::GetViewRect() const 
3775     wxASSERT_MSG( !HasFlag(wxLC_REPORT 
| wxLC_LIST
), 
3776                     _T("wxListCtrl::GetViewRect() only works in icon mode") ); 
3778     // we need to find the longest/tallest label 
3781     const int count 
= GetItemCount(); 
3784         for ( int i 
= 0; i 
< count
; i
++ ) 
3789             wxCoord x 
= r
.GetRight(), 
3799     // some fudge needed to make it look prettier 
3800     xMax 
+= 2*EXTRA_BORDER_X
; 
3801     yMax 
+= 2*EXTRA_BORDER_Y
; 
3803     // account for the scrollbars if necessary 
3804     const wxSize sizeAll 
= GetClientSize(); 
3805     if ( xMax 
> sizeAll
.x 
) 
3806         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
3807     if ( yMax 
> sizeAll
.y 
) 
3808         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
3810     return wxRect(0, 0, xMax
, yMax
); 
3813 void wxListMainWindow::GetItemRect( long index
, wxRect 
&rect 
) const 
3815     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3816                  _T("invalid index in GetItemRect") ); 
3818     // ensure that we're laid out, otherwise we could return nonsense 
3821         wxConstCast(this, wxListMainWindow
)-> 
3822             RecalculatePositions(true /* no refresh */); 
3825     rect 
= GetLineRect((size_t)index
); 
3827     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
3830 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
3833     GetItemRect(item
, rect
); 
3841 // ---------------------------------------------------------------------------- 
3842 // geometry calculation 
3843 // ---------------------------------------------------------------------------- 
3845 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
3847     wxClientDC 
dc( this ); 
3848     dc
.SetFont( GetFont() ); 
3850     const size_t count 
= GetItemCount(); 
3853     if ( HasFlag(wxLC_ICON
) ) 
3854         iconSpacing 
= m_normal_spacing
; 
3855     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
3856         iconSpacing 
= m_small_spacing
; 
3860     // Note that we do not call GetClientSize() here but 
3861     // GetSize() and substract the border size for sunken 
3862     // borders manually. This is technically incorrect, 
3863     // but we need to know the client area's size WITHOUT 
3864     // scrollbars here. Since we don't know if there are 
3865     // any scrollbars, we use GetSize() instead. Another 
3866     // solution would be to call SetScrollbars() here to 
3867     // remove the scrollbars and call GetClientSize() then, 
3868     // but this might result in flicker and - worse - will 
3869     // reset the scrollbars to 0 which is not good at all 
3870     // if you resize a dialog/window, but don't want to 
3871     // reset the window scrolling. RR. 
3872     // Furthermore, we actually do NOT subtract the border 
3873     // width as 2 pixels is just the extra space which we 
3874     // need around the actual content in the window. Other- 
3875     // wise the text would e.g. touch the upper border. RR. 
3878     GetSize( &clientWidth
, &clientHeight 
); 
3880     const int lineHeight 
= GetLineHeight(); 
3882     if ( InReportView() ) 
3884         // all lines have the same height and we scroll one line per step 
3885         int entireHeight 
= count
*lineHeight 
+ LINE_SPACING
; 
3887         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
3889         ResetVisibleLinesRange(); 
3891         SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
3892                        GetHeaderWidth() / SCROLL_UNIT_X
, 
3893                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
3894                        GetScrollPos(wxHORIZONTAL
), 
3895                        GetScrollPos(wxVERTICAL
), 
3900         // we have 3 different layout strategies: either layout all items 
3901         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
3902         // to arrange them in top to bottom, left to right (don't ask me why 
3903         // not the other way round...) order 
3904         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
3906             int x 
= EXTRA_BORDER_X
; 
3907             int y 
= EXTRA_BORDER_Y
; 
3909             wxCoord widthMax 
= 0; 
3912             for ( i 
= 0; i 
< count
; i
++ ) 
3914                 wxListLineData 
*line 
= GetLine(i
); 
3915                 line
->CalculateSize( &dc
, iconSpacing 
); 
3916                 line
->SetPosition( x
, y
, iconSpacing 
); 
3918                 wxSize sizeLine 
= GetLineSize(i
); 
3920                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3922                     if ( sizeLine
.x 
> widthMax 
) 
3923                         widthMax 
= sizeLine
.x
; 
3927                 else // wxLC_ALIGN_LEFT 
3929                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
3933             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3935                 // traverse the items again and tweak their sizes so that they are 
3936                 // all the same in a row 
3937                 for ( i 
= 0; i 
< count
; i
++ ) 
3939                     wxListLineData 
*line 
= GetLine(i
); 
3940                     line
->m_gi
->ExtendWidth(widthMax
); 
3949                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3950                 (y 
+ lineHeight
) / lineHeight
, 
3951                 GetScrollPos( wxHORIZONTAL 
), 
3952                 GetScrollPos( wxVERTICAL 
), 
3956         else // "flowed" arrangement, the most complicated case 
3958             // at first we try without any scrollbars, if the items don't fit into 
3959             // the window, we recalculate after subtracting the space taken by the 
3962             int entireWidth 
= 0; 
3964             for (int tries 
= 0; tries 
< 2; tries
++) 
3966                 entireWidth 
= 2*EXTRA_BORDER_X
; 
3970                     // Now we have decided that the items do not fit into the 
3971                     // client area, so we need a scrollbar 
3972                     entireWidth 
+= SCROLL_UNIT_X
; 
3975                 int x 
= EXTRA_BORDER_X
; 
3976                 int y 
= EXTRA_BORDER_Y
; 
3977                 int maxWidthInThisRow 
= 0; 
3980                 int currentlyVisibleLines 
= 0; 
3982                 for (size_t i 
= 0; i 
< count
; i
++) 
3984                     currentlyVisibleLines
++; 
3985                     wxListLineData 
*line 
= GetLine(i
); 
3986                     line
->CalculateSize( &dc
, iconSpacing 
); 
3987                     line
->SetPosition( x
, y
, iconSpacing 
); 
3989                     wxSize sizeLine 
= GetLineSize(i
); 
3991                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
3992                         maxWidthInThisRow 
= sizeLine
.x
; 
3995                     if (currentlyVisibleLines 
> m_linesPerPage
) 
3996                         m_linesPerPage 
= currentlyVisibleLines
; 
3998                     if ( y 
+ sizeLine
.y 
>= clientHeight 
) 
4000                         currentlyVisibleLines 
= 0; 
4002                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
4003                         x 
+= maxWidthInThisRow
; 
4004                         entireWidth 
+= maxWidthInThisRow
; 
4005                         maxWidthInThisRow 
= 0; 
4008                     // We have reached the last item. 
4009                     if ( i 
== count 
- 1 ) 
4010                         entireWidth 
+= maxWidthInThisRow
; 
4012                     if ( (tries 
== 0) && 
4013                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
4015                         clientHeight 
-= wxSystemSettings:: 
4016                                             GetMetric(wxSYS_HSCROLL_Y
); 
4021                     if ( i 
== count 
- 1 ) 
4022                         tries 
= 1;  // Everything fits, no second try required. 
4030                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
4032                 GetScrollPos( wxHORIZONTAL 
), 
4041         // FIXME: why should we call it from here? 
4048 void wxListMainWindow::RefreshAll() 
4053     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
4054     if ( headerWin 
&& headerWin
->m_dirty 
) 
4056         headerWin
->m_dirty 
= false; 
4057         headerWin
->Refresh(); 
4061 void wxListMainWindow::UpdateCurrent() 
4063     if ( !HasCurrent() && !IsEmpty() ) 
4069 long wxListMainWindow::GetNextItem( long item
, 
4070                                     int WXUNUSED(geometry
), 
4074          max 
= GetItemCount(); 
4075     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
4076                  _T("invalid listctrl index in GetNextItem()") ); 
4078     // notice that we start with the next item (or the first one if item == -1) 
4079     // and this is intentional to allow writing a simple loop to iterate over 
4080     // all selected items 
4084         // this is not an error because the index was ok initially, just no 
4095     size_t count 
= GetItemCount(); 
4096     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
4098         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
4101         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
4108 // ---------------------------------------------------------------------------- 
4110 // ---------------------------------------------------------------------------- 
4112 void wxListMainWindow::DeleteItem( long lindex 
) 
4114     size_t count 
= GetItemCount(); 
4116     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
4117                  _T("invalid item index in DeleteItem") ); 
4119     size_t index 
= (size_t)lindex
; 
4121     // we don't need to adjust the index for the previous items 
4122     if ( HasCurrent() && m_current 
>= index 
) 
4124         // if the current item is being deleted, we want the next one to 
4125         // become selected - unless there is no next one - so don't adjust 
4126         // m_current in this case 
4127         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
4133     if ( InReportView() ) 
4135         ResetVisibleLinesRange(); 
4142         m_selStore
.OnItemDelete(index
); 
4146         m_lines
.RemoveAt( index 
); 
4149     // we need to refresh the (vert) scrollbar as the number of items changed 
4152     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM 
); 
4154     RefreshAfter(index
); 
4157 void wxListMainWindow::DeleteColumn( int col 
) 
4159     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4161     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
4164     delete node
->GetData(); 
4165     m_columns
.Erase( node 
); 
4169         // update all the items 
4170         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4172             wxListLineData 
* const line 
= GetLine(i
); 
4173             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
4174             delete n
->GetData(); 
4175             line
->m_items
.Erase(n
); 
4179     // invalidate it as it has to be recalculated 
4183 void wxListMainWindow::DoDeleteAllItems() 
4187         // nothing to do - in particular, don't send the event 
4193     // to make the deletion of all items faster, we don't send the 
4194     // notifications for each item deletion in this case but only one event 
4195     // for all of them: this is compatible with wxMSW and documented in 
4196     // DeleteAllItems() description 
4198     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
4199     event
.SetEventObject( GetParent() ); 
4200     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
4209     if ( InReportView() ) 
4211         ResetVisibleLinesRange(); 
4217 void wxListMainWindow::DeleteAllItems() 
4221     RecalculatePositions(); 
4224 void wxListMainWindow::DeleteEverything() 
4226     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
4231 // ---------------------------------------------------------------------------- 
4232 // scanning for an item 
4233 // ---------------------------------------------------------------------------- 
4235 void wxListMainWindow::EnsureVisible( long index 
) 
4237     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4238                  _T("invalid index in EnsureVisible") ); 
4240     // We have to call this here because the label in question might just have 
4241     // been added and its position is not known yet 
4244         RecalculatePositions(true /* no refresh */); 
4247     MoveToItem((size_t)index
); 
4250 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) ) 
4257     size_t count 
= GetItemCount(); 
4258     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
4260         wxListLineData 
*line 
= GetLine(i
); 
4261         if ( line
->GetText(0) == tmp 
) 
4268 long wxListMainWindow::FindItem(long start
, long data
) 
4274     size_t count 
= GetItemCount(); 
4275     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4277         wxListLineData 
*line 
= GetLine(i
); 
4279         line
->GetItem( 0, item 
); 
4280         if (item
.m_data 
== data
) 
4287 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) 
4289     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4291     size_t count 
= GetItemCount(); 
4293     if ( InReportView() ) 
4295         size_t current 
= y 
/ GetLineHeight(); 
4296         if ( current 
< count 
) 
4298             flags 
= HitTestLine(current
, x
, y
); 
4305         // TODO: optimize it too! this is less simple than for report view but 
4306         //       enumerating all items is still not a way to do it!! 
4307         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4309             flags 
= HitTestLine(current
, x
, y
); 
4318 // ---------------------------------------------------------------------------- 
4320 // ---------------------------------------------------------------------------- 
4322 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4324     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
4326     int count 
= GetItemCount(); 
4327     wxCHECK_RET( item
.m_itemId 
>= 0, _T("invalid item index") ); 
4329     if (item
.m_itemId 
> count
) 
4330         item
.m_itemId 
= count
; 
4332     size_t id 
= item
.m_itemId
; 
4337     // this is unused variable 
4340     if ( InReportView() ) 
4343         // this is unused variable 
4346         ResetVisibleLinesRange(); 
4348     else if ( HasFlag(wxLC_LIST
) ) 
4350         // this is unused variable 
4355     else if ( HasFlag(wxLC_ICON
) ) 
4357         // this is unused variable 
4362     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
4364         // this is unused variable 
4365         mode 
= wxLC_ICON
;  // no typo 
4371         wxFAIL_MSG( _T("unknown mode") ); 
4374     wxListLineData 
*line 
= new wxListLineData(this); 
4376     line
->SetItem( 0, item 
); 
4378     m_lines
.Insert( line
, id 
); 
4382     // If an item is selected at or below the point of insertion, we need to 
4383     // increment the member variables because the current row's index has gone 
4385     if ( HasCurrent() && m_current 
>= id 
) 
4390     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4392     RefreshLines(id
, GetItemCount() - 1); 
4395 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4398     if ( InReportView() ) 
4400         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4401             item
.m_width 
= GetTextLength( item
.m_text 
); 
4403         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4404         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4407             wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
4408             m_columns
.Insert( node
, column 
); 
4412             m_columns
.Append( column 
); 
4417             // update all the items 
4418             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4420                 wxListLineData 
* const line 
= GetLine(i
); 
4421                 wxListItemData 
* const data 
= new wxListItemData(this); 
4423                     line
->m_items
.Insert(col
, data
); 
4425                     line
->m_items
.Append(data
); 
4429         // invalidate it as it has to be recalculated 
4434 // ---------------------------------------------------------------------------- 
4436 // ---------------------------------------------------------------------------- 
4438 wxListCtrlCompare list_ctrl_compare_func_2
; 
4439 long              list_ctrl_compare_data
; 
4441 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4443     wxListLineData 
*line1 
= *arg1
; 
4444     wxListLineData 
*line2 
= *arg2
; 
4446     line1
->GetItem( 0, item 
); 
4447     long data1 
= item
.m_data
; 
4448     line2
->GetItem( 0, item 
); 
4449     long data2 
= item
.m_data
; 
4450     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4453 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
4455     list_ctrl_compare_func_2 
= fn
; 
4456     list_ctrl_compare_data 
= data
; 
4457     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4461 // ---------------------------------------------------------------------------- 
4463 // ---------------------------------------------------------------------------- 
4465 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4467     // update our idea of which lines are shown when we redraw the window the 
4469     ResetVisibleLinesRange(); 
4472 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
4473     wxScrolledWindow::OnScroll(event
); 
4475     HandleOnScroll( event 
); 
4478     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4480         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4481         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4483         lc
->m_headerWin
->Refresh(); 
4484         lc
->m_headerWin
->Update(); 
4488 int wxListMainWindow::GetCountPerPage() const 
4490     if ( !m_linesPerPage 
) 
4492         wxConstCast(this, wxListMainWindow
)-> 
4493             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4496     return m_linesPerPage
; 
4499 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4501     wxASSERT_MSG( InReportView(), _T("this is for report mode only") ); 
4503     if ( m_lineFrom 
== (size_t)-1 ) 
4505         size_t count 
= GetItemCount(); 
4508             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4510             // this may happen if SetScrollbars() hadn't been called yet 
4511             if ( m_lineFrom 
>= count 
) 
4512                 m_lineFrom 
= count 
- 1; 
4514             // we redraw one extra line but this is needed to make the redrawing 
4515             // logic work when there is a fractional number of lines on screen 
4516             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4517             if ( m_lineTo 
>= count 
) 
4518                 m_lineTo 
= count 
- 1; 
4520         else // empty control 
4523             m_lineTo 
= (size_t)-1; 
4527     wxASSERT_MSG( IsEmpty() || 
4528                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4529                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4537 // ------------------------------------------------------------------------------------- 
4538 // wxGenericListCtrl 
4539 // ------------------------------------------------------------------------------------- 
4541 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4543 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4544   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4547 wxGenericListCtrl::wxGenericListCtrl() 
4549     m_imageListNormal 
= (wxImageListType 
*) NULL
; 
4550     m_imageListSmall 
= (wxImageListType 
*) NULL
; 
4551     m_imageListState 
= (wxImageListType 
*) NULL
; 
4553     m_ownsImageListNormal 
= 
4554     m_ownsImageListSmall 
= 
4555     m_ownsImageListState 
= false; 
4557     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4558     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4562 wxGenericListCtrl::~wxGenericListCtrl() 
4564     if (m_ownsImageListNormal
) 
4565         delete m_imageListNormal
; 
4566     if (m_ownsImageListSmall
) 
4567         delete m_imageListSmall
; 
4568     if (m_ownsImageListState
) 
4569         delete m_imageListState
; 
4572 void wxGenericListCtrl::CalculateAndSetHeaderHeight() 
4576         // we use 'g' to get the descent, too 
4578         m_headerWin
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
); 
4579         h 
+= d 
+ 2 * HEADER_OFFSET_Y 
+ EXTRA_HEIGHT
; 
4581         // only update if changed 
4582         if ( h 
!= m_headerHeight 
) 
4586             m_headerWin
->SetSize(m_headerWin
->GetSize().x
, m_headerHeight
); 
4589                 ResizeReportView(true); 
4594 void wxGenericListCtrl::CreateHeaderWindow() 
4596     m_headerWin 
= new wxListHeaderWindow
 
4598                         this, wxID_ANY
, m_mainWin
, 
4600                         wxSize(GetClientSize().x
, m_headerHeight
), 
4603     CalculateAndSetHeaderHeight(); 
4606 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
4611                         const wxValidator 
&validator
, 
4612                         const wxString 
&name
) 
4616     m_imageListState 
= (wxImageListType 
*) NULL
; 
4617     m_ownsImageListNormal 
= 
4618     m_ownsImageListSmall 
= 
4619     m_ownsImageListState 
= false; 
4621     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4622     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4626     if ( !(style 
& wxLC_MASK_TYPE
) ) 
4628         style 
= style 
| wxLC_LIST
; 
4631     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
4634     // don't create the inner window with the border 
4635     style 
&= ~wxBORDER_MASK
; 
4637     m_mainWin 
= new wxListMainWindow( this, wxID_ANY
, wxPoint(0,0), size
, style 
); 
4639 #if defined( __WXMAC__ ) && __WXMAC_CARBON__ 
4641     font
.MacCreateThemeFont( kThemeViewsFont 
) ; 
4644     if ( InReportView() ) 
4646         CreateHeaderWindow(); 
4648         if ( HasFlag(wxLC_NO_HEADER
) ) 
4650             // VZ: why do we create it at all then? 
4651             m_headerWin
->Show( false ); 
4660 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
4662     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4663                   _T("wxLC_VIRTUAL can't be [un]set") ); 
4665     long flag 
= GetWindowStyle(); 
4669         if (style 
& wxLC_MASK_TYPE
) 
4670             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4671         if (style 
& wxLC_MASK_ALIGN
) 
4672             flag 
&= ~wxLC_MASK_ALIGN
; 
4673         if (style 
& wxLC_MASK_SORT
) 
4674             flag 
&= ~wxLC_MASK_SORT
; 
4686     SetWindowStyleFlag( flag 
); 
4689 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
4693         m_mainWin
->DeleteEverything(); 
4695         // has the header visibility changed? 
4696         bool hasHeader 
= HasHeader(); 
4697         bool willHaveHeader 
= (flag 
& wxLC_REPORT
) && !(flag 
& wxLC_NO_HEADER
); 
4699         if ( hasHeader 
!= willHaveHeader 
) 
4706                     // don't delete, just hide, as we can reuse it later 
4707                     m_headerWin
->Show(false); 
4709                 //else: nothing to do 
4711             else // must show header 
4715                     CreateHeaderWindow(); 
4717                 else // already have it, just show 
4719                     m_headerWin
->Show( true ); 
4723             ResizeReportView(willHaveHeader
); 
4727     wxWindow::SetWindowStyleFlag( flag 
); 
4730 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4732     m_mainWin
->GetColumn( col
, item 
); 
4736 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
4738     m_mainWin
->SetColumn( col
, item 
); 
4742 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
4744     return m_mainWin
->GetColumnWidth( col 
); 
4747 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
4749     m_mainWin
->SetColumnWidth( col
, width 
); 
4753 int wxGenericListCtrl::GetCountPerPage() const 
4755   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4758 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
4760     m_mainWin
->GetItem( info 
); 
4764 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
4766     m_mainWin
->SetItem( info 
); 
4770 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4773     info
.m_text 
= label
; 
4774     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4775     info
.m_itemId 
= index
; 
4779         info
.m_image 
= imageId
; 
4780         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4782     m_mainWin
->SetItem(info
); 
4786 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
4788     return m_mainWin
->GetItemState( item
, stateMask 
); 
4791 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4793     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4797 bool wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4800     info
.m_image 
= image
; 
4801     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4802     info
.m_itemId 
= item
; 
4803     m_mainWin
->SetItem( info 
); 
4807 wxString 
wxGenericListCtrl::GetItemText( long item 
) const 
4809     return m_mainWin
->GetItemText(item
); 
4812 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
4814     m_mainWin
->SetItemText(item
, str
); 
4817 long wxGenericListCtrl::GetItemData( long item 
) const 
4820     info
.m_itemId 
= item
; 
4821     m_mainWin
->GetItem( info 
); 
4825 bool wxGenericListCtrl::SetItemData( long item
, long data 
) 
4828     info
.m_mask 
= wxLIST_MASK_DATA
; 
4829     info
.m_itemId 
= item
; 
4831     m_mainWin
->SetItem( info 
); 
4835 wxRect 
wxGenericListCtrl::GetViewRect() const 
4837     return m_mainWin
->GetViewRect(); 
4840 bool wxGenericListCtrl::GetItemRect( long item
, wxRect 
&rect
,  int WXUNUSED(code
) ) const 
4842     m_mainWin
->GetItemRect( item
, rect 
); 
4843     if ( m_mainWin
->HasHeader() ) 
4844         rect
.y 
+= m_headerHeight 
+ 1; 
4848 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4850     m_mainWin
->GetItemPosition( item
, pos 
); 
4854 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4859 int wxGenericListCtrl::GetItemCount() const 
4861     return m_mainWin
->GetItemCount(); 
4864 int wxGenericListCtrl::GetColumnCount() const 
4866     return m_mainWin
->GetColumnCount(); 
4869 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4871     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4874 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
4876     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
4878     return wxSize(spacing
, spacing
); 
4881 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
4883     return m_mainWin
->GetItemSpacing( isSmall 
); 
4886 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
4889     info
.m_itemId 
= item
; 
4890     info
.SetTextColour( col 
); 
4891     m_mainWin
->SetItem( info 
); 
4894 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
4897     info
.m_itemId 
= item
; 
4898     m_mainWin
->GetItem( info 
); 
4899     return info
.GetTextColour(); 
4902 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
4905     info
.m_itemId 
= item
; 
4906     info
.SetBackgroundColour( col 
); 
4907     m_mainWin
->SetItem( info 
); 
4910 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
4913     info
.m_itemId 
= item
; 
4914     m_mainWin
->GetItem( info 
); 
4915     return info
.GetBackgroundColour(); 
4918 int wxGenericListCtrl::GetSelectedItemCount() const 
4920     return m_mainWin
->GetSelectedItemCount(); 
4923 wxColour 
wxGenericListCtrl::GetTextColour() const 
4925     return GetForegroundColour(); 
4928 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
4930     SetForegroundColour(col
); 
4933 long wxGenericListCtrl::GetTopItem() const 
4936     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
4940 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
4942     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
4945 wxImageListType 
*wxGenericListCtrl::GetImageList(int which
) const 
4947     if (which 
== wxIMAGE_LIST_NORMAL
) 
4949         return m_imageListNormal
; 
4951     else if (which 
== wxIMAGE_LIST_SMALL
) 
4953         return m_imageListSmall
; 
4955     else if (which 
== wxIMAGE_LIST_STATE
) 
4957         return m_imageListState
; 
4959     return (wxImageListType 
*) NULL
; 
4962 void wxGenericListCtrl::SetImageList( wxImageListType 
*imageList
, int which 
) 
4964     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4966         if (m_ownsImageListNormal
) delete m_imageListNormal
; 
4967         m_imageListNormal 
= imageList
; 
4968         m_ownsImageListNormal 
= false; 
4970     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4972         if (m_ownsImageListSmall
) delete m_imageListSmall
; 
4973         m_imageListSmall 
= imageList
; 
4974         m_ownsImageListSmall 
= false; 
4976     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4978         if (m_ownsImageListState
) delete m_imageListState
; 
4979         m_imageListState 
= imageList
; 
4980         m_ownsImageListState 
= false; 
4983     m_mainWin
->SetImageList( imageList
, which 
); 
4986 void wxGenericListCtrl::AssignImageList(wxImageListType 
*imageList
, int which
) 
4988     SetImageList(imageList
, which
); 
4989     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4990         m_ownsImageListNormal 
= true; 
4991     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4992         m_ownsImageListSmall 
= true; 
4993     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4994         m_ownsImageListState 
= true; 
4997 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
5002 bool wxGenericListCtrl::DeleteItem( long item 
) 
5004     m_mainWin
->DeleteItem( item 
); 
5008 bool wxGenericListCtrl::DeleteAllItems() 
5010     m_mainWin
->DeleteAllItems(); 
5014 bool wxGenericListCtrl::DeleteAllColumns() 
5016     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
5017     for ( size_t n 
= 0; n 
< count
; n
++ ) 
5023 void wxGenericListCtrl::ClearAll() 
5025     m_mainWin
->DeleteEverything(); 
5028 bool wxGenericListCtrl::DeleteColumn( int col 
) 
5030     m_mainWin
->DeleteColumn( col 
); 
5032     // if we don't have the header any longer, we need to relayout the window 
5033     if ( !GetColumnCount() ) 
5035         ResizeReportView(false /* no header */); 
5041 void wxGenericListCtrl::Edit( long item 
) 
5043     m_mainWin
->EditLabel( item 
); 
5046 bool wxGenericListCtrl::EnsureVisible( long item 
) 
5048     m_mainWin
->EnsureVisible( item 
); 
5052 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
,  bool partial 
) 
5054     return m_mainWin
->FindItem( start
, str
, partial 
); 
5057 long wxGenericListCtrl::FindItem( long start
, long data 
) 
5059     return m_mainWin
->FindItem( start
, data 
); 
5062 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
), 
5063                            int WXUNUSED(direction
)) 
5068 long wxGenericListCtrl::HitTest( const wxPoint 
&point
, int &flags 
) 
5070     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
5073 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
5075     m_mainWin
->InsertItem( info 
); 
5076     return info
.m_itemId
; 
5079 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
5082     info
.m_text 
= label
; 
5083     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5084     info
.m_itemId 
= index
; 
5085     return InsertItem( info 
); 
5088 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
5091     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5092     info
.m_image 
= imageIndex
; 
5093     info
.m_itemId 
= index
; 
5094     return InsertItem( info 
); 
5097 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
5100     info
.m_text 
= label
; 
5101     info
.m_image 
= imageIndex
; 
5102     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
5103     info
.m_itemId 
= index
; 
5104     return InsertItem( info 
); 
5107 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
5109     wxCHECK_MSG( m_headerWin
, -1, _T("can't add column in non report mode") ); 
5111     m_mainWin
->InsertColumn( col
, item 
); 
5113     // if we hadn't had header before and have it now we need to relayout the 
5115     if ( GetColumnCount() == 1 && m_mainWin
->HasHeader() ) 
5117         ResizeReportView(true /* have header */); 
5120     m_headerWin
->Refresh(); 
5125 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
5126                                int format
, int width 
) 
5129     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
5130     item
.m_text 
= heading
; 
5133         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
5134         item
.m_width 
= width
; 
5136     item
.m_format 
= format
; 
5138     return InsertColumn( col
, item 
); 
5141 bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) ) 
5147 // fn is a function which takes 3 long arguments: item1, item2, data. 
5148 // item1 is the long data associated with a first item (NOT the index). 
5149 // item2 is the long data associated with a second item (NOT the index). 
5150 // data is the same value as passed to SortItems. 
5151 // The return value is a negative number if the first item should precede the second 
5152 // item, a positive number of the second item should precede the first, 
5153 // or zero if the two items are equivalent. 
5154 // data is arbitrary data to be passed to the sort function. 
5156 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
5158     m_mainWin
->SortItems( fn
, data 
); 
5162 // ---------------------------------------------------------------------------- 
5164 // ---------------------------------------------------------------------------- 
5166 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
5171     ResizeReportView(m_mainWin
->HasHeader()); 
5173     m_mainWin
->RecalculatePositions(); 
5176 void wxGenericListCtrl::ResizeReportView(bool showHeader
) 
5179     GetClientSize( &cw
, &ch 
); 
5183         m_headerWin
->SetSize( 0, 0, cw
, m_headerHeight 
); 
5184         m_mainWin
->SetSize( 0, m_headerHeight 
+ 1, cw
, ch 
- m_headerHeight 
- 1 ); 
5186     else // no header window 
5188         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
5192 void wxGenericListCtrl::OnInternalIdle() 
5194     wxWindow::OnInternalIdle(); 
5196     // do it only if needed 
5197     if ( !m_mainWin
->m_dirty 
) 
5200     m_mainWin
->RecalculatePositions(); 
5203 // ---------------------------------------------------------------------------- 
5205 // ---------------------------------------------------------------------------- 
5207 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5211         m_mainWin
->SetBackgroundColour( colour 
); 
5212         m_mainWin
->m_dirty 
= true; 
5218 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5220     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5225         m_mainWin
->SetForegroundColour( colour 
); 
5226         m_mainWin
->m_dirty 
= true; 
5231         m_headerWin
->SetForegroundColour( colour 
); 
5237 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5239     if ( !wxWindow::SetFont( font 
) ) 
5244         m_mainWin
->SetFont( font 
); 
5245         m_mainWin
->m_dirty 
= true; 
5250         m_headerWin
->SetFont( font 
); 
5251         CalculateAndSetHeaderHeight(); 
5262 #include "wx/listbox.h" 
5267 wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
5270     // Use the same color scheme as wxListBox 
5271     return wxListBox::GetClassDefaultAttributes(variant
); 
5273     wxUnusedVar(variant
); 
5274     wxVisualAttributes attr
; 
5275     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
5276     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
5277     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
5282 // ---------------------------------------------------------------------------- 
5283 // methods forwarded to m_mainWin 
5284 // ---------------------------------------------------------------------------- 
5286 #if wxUSE_DRAG_AND_DROP 
5288 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5290     m_mainWin
->SetDropTarget( dropTarget 
); 
5293 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5295     return m_mainWin
->GetDropTarget(); 
5298 #endif // wxUSE_DRAG_AND_DROP 
5300 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5302     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : false; 
5305 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5307     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5310 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5312     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5315 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5318     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5321 #endif // wxUSE_MENUS 
5324 void wxGenericListCtrl::SetFocus() 
5326     /* The test in window.cpp fails as we are a composite 
5327        window, so it checks against "this", but not m_mainWin. */ 
5328     if ( FindFocus() != this ) 
5329         m_mainWin
->SetFocus(); 
5332 // ---------------------------------------------------------------------------- 
5333 // virtual list control support 
5334 // ---------------------------------------------------------------------------- 
5336 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5338     // this is a pure virtual function, in fact - which is not really pure 
5339     // because the controls which are not virtual don't need to implement it 
5340     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5342     return wxEmptyString
; 
5345 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5348     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemImage not supposed to be called") ); 
5354 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5356     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5357                   _T("invalid item index in OnGetItemAttr()") ); 
5359     // no attributes by default 
5363 void wxGenericListCtrl::SetItemCount(long count
) 
5365     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
5367     m_mainWin
->SetItemCount(count
); 
5370 void wxGenericListCtrl::RefreshItem(long item
) 
5372     m_mainWin
->RefreshLine(item
); 
5375 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5377     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5381  * Generic wxListCtrl is more or less a container for two other 
5382  * windows which drawings are done upon. These are namely 
5383  * 'm_headerWin' and 'm_mainWin'. 
5384  * Here we override 'virtual wxWindow::Refresh()' to mimic the 
5385  * behaviour wxListCtrl has under wxMSW. 
5387 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5391         // The easy case, no rectangle specified. 
5393             m_headerWin
->Refresh(eraseBackground
); 
5396             m_mainWin
->Refresh(eraseBackground
); 
5400         // Refresh the header window 
5403             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5404             rectHeader
.Intersect(*rect
); 
5405             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5408                 m_headerWin
->GetPosition(&x
, &y
); 
5409                 rectHeader
.Offset(-x
, -y
); 
5410                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5415         // Refresh the main window 
5418             wxRect rectMain 
= m_mainWin
->GetRect(); 
5419             rectMain
.Intersect(*rect
); 
5420             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5423                 m_mainWin
->GetPosition(&x
, &y
); 
5424                 rectMain
.Offset(-x
, -y
); 
5425                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5431 void wxGenericListCtrl::Freeze() 
5433     m_mainWin
->Freeze(); 
5436 void wxGenericListCtrl::Thaw() 
5441 #endif // wxUSE_LISTCTRL