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 // ---------------------------------------------------------------------------- 
  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 #if defined(__WXGTK__) 
  73     #include "wx/gtk/win_gtk.h" 
  76 // ---------------------------------------------------------------------------- 
  78 // ---------------------------------------------------------------------------- 
  80 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
) 
  81 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
) 
  82 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
) 
  83 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
) 
  84 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
) 
  85 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
) 
  86 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
) 
  87 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
) 
  88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
) 
  89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
) 
  90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
) 
  91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
) 
  92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
) 
  93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
) 
  94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
) 
  95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING
) 
  96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG
) 
  97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
) 
  98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
) 
  99 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
) 
 100 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED
) 
 101 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
) 
 103 // ---------------------------------------------------------------------------- 
 105 // ---------------------------------------------------------------------------- 
 107 // the height of the header window (FIXME: should depend on its font!) 
 108 static const int HEADER_HEIGHT 
= 23; 
 110 // the scrollbar units 
 111 static const int SCROLL_UNIT_X 
= 15; 
 112 static const int SCROLL_UNIT_Y 
= 15; 
 114 // the spacing between the lines (in report mode) 
 115 static const int LINE_SPACING 
= 0; 
 117 // extra margins around the text label 
 118 static const int EXTRA_WIDTH 
= 3; 
 119 static const int EXTRA_HEIGHT 
= 4; 
 121 // offset for the header window 
 122 static const int HEADER_OFFSET_X 
= 1; 
 123 static const int HEADER_OFFSET_Y 
= 1; 
 125 // when autosizing the columns, add some slack 
 126 static const int AUTOSIZE_COL_MARGIN 
= 10; 
 128 // default and minimal widths for the header columns 
 129 static const int WIDTH_COL_DEFAULT 
= 80; 
 130 static const int WIDTH_COL_MIN 
= 10; 
 132 // the space between the image and the text in the report mode 
 133 static const int IMAGE_MARGIN_IN_REPORT_MODE 
= 5; 
 135 // ============================================================================ 
 137 // ============================================================================ 
 139 // ---------------------------------------------------------------------------- 
 141 // ---------------------------------------------------------------------------- 
 143 int CMPFUNC_CONV 
wxSizeTCmpFn(size_t n1
, size_t n2
) { return n1 
- n2
; } 
 145 WX_DEFINE_SORTED_EXPORTED_ARRAY_LONG(size_t, wxIndexArray
); 
 147 // this class is used to store the selected items in the virtual list control 
 148 // (but it is not tied to list control and so can be used with other controls 
 149 // such as wxListBox in wxUniv) 
 151 // the idea is to make it really smart later (i.e. store the selections as an 
 152 // array of ranes + individual items) but, as I don't have time to do it now 
 153 // (this would require writing code to merge/break ranges and much more) keep 
 154 // it simple but define a clean interface to it which allows it to be made 
 156 class WXDLLEXPORT wxSelectionStore
 
 159     wxSelectionStore() : m_itemsSel(wxSizeTCmpFn
) { Init(); } 
 161     // set the total number of items we handle 
 162     void SetItemCount(size_t count
) { m_count 
= count
; } 
 164     // special case of SetItemCount(0) 
 165     void Clear() { m_itemsSel
.Clear(); m_count 
= 0; m_defaultState 
= FALSE
; } 
 167     // must be called when a new item is inserted/added 
 168     void OnItemAdd(size_t item
) { wxFAIL_MSG( _T("TODO") ); } 
 170     // must be called when an item is deleted 
 171     void OnItemDelete(size_t item
); 
 173     // select one item, use SelectRange() insted if possible! 
 175     // returns true if the items selection really changed 
 176     bool SelectItem(size_t item
, bool select 
= TRUE
); 
 178     // select the range of items 
 180     // return true and fill the itemsChanged array with the indices of items 
 181     // which have changed state if "few" of them did, otherwise return false 
 182     // (meaning that too many items changed state to bother counting them 
 184     bool SelectRange(size_t itemFrom
, size_t itemTo
, 
 186                      wxArrayInt 
*itemsChanged 
= NULL
); 
 188     // return true if the given item is selected 
 189     bool IsSelected(size_t item
) const; 
 191     // return the total number of selected items 
 192     size_t GetSelectedCount() const 
 194         return m_defaultState 
? m_count 
- m_itemsSel
.GetCount() 
 195                               : m_itemsSel
.GetCount(); 
 200     void Init() { m_defaultState 
= FALSE
; } 
 202     // the total number of items we handle 
 205     // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if 
 206     // there are more selected items than non selected ones - this allows to 
 207     // handle selection of all items efficiently 
 210     // the array of items whose selection state is different from default 
 211     wxIndexArray m_itemsSel
; 
 213     DECLARE_NO_COPY_CLASS(wxSelectionStore
) 
 216 //----------------------------------------------------------------------------- 
 217 //  wxListItemData (internal) 
 218 //----------------------------------------------------------------------------- 
 220 class WXDLLEXPORT wxListItemData
 
 223     wxListItemData(wxListMainWindow 
*owner
); 
 226     void SetItem( const wxListItem 
&info 
); 
 227     void SetImage( int image 
) { m_image 
= image
; } 
 228     void SetData( long data 
) { m_data 
= data
; } 
 229     void SetPosition( int x
, int y 
); 
 230     void SetSize( int width
, int height 
); 
 232     bool HasText() const { return !m_text
.empty(); } 
 233     const wxString
& GetText() const { return m_text
; } 
 234     void SetText(const wxString
& text
) { m_text 
= text
; } 
 236     // we can't use empty string for measuring the string width/height, so 
 237     // always return something 
 238     wxString 
GetTextForMeasuring() const 
 240         wxString s 
= GetText(); 
 247     bool IsHit( int x
, int y 
) const; 
 251     int GetWidth() const; 
 252     int GetHeight() const; 
 254     int GetImage() const { return m_image
; } 
 255     bool HasImage() const { return GetImage() != -1; } 
 257     void GetItem( wxListItem 
&info 
) const; 
 259     void SetAttr(wxListItemAttr 
*attr
) { m_attr 
= attr
; } 
 260     wxListItemAttr 
*GetAttr() const { return m_attr
; } 
 263     // the item image or -1 
 266     // user data associated with the item 
 269     // the item coordinates are not used in report mode, instead this pointer 
 270     // is NULL and the owner window is used to retrieve the item position and 
 274     // the list ctrl we are in 
 275     wxListMainWindow 
*m_owner
; 
 277     // custom attributes or NULL 
 278     wxListItemAttr 
*m_attr
; 
 281     // common part of all ctors 
 287 //----------------------------------------------------------------------------- 
 288 //  wxListHeaderData (internal) 
 289 //----------------------------------------------------------------------------- 
 291 class WXDLLEXPORT wxListHeaderData 
: public wxObject
 
 295     wxListHeaderData( const wxListItem 
&info 
); 
 296     void SetItem( const wxListItem 
&item 
); 
 297     void SetPosition( int x
, int y 
); 
 298     void SetWidth( int w 
); 
 299     void SetFormat( int format 
); 
 300     void SetHeight( int h 
); 
 301     bool HasImage() const; 
 303     bool HasText() const { return !m_text
.empty(); } 
 304     const wxString
& GetText() const { return m_text
; } 
 305     void SetText(const wxString
& text
) { m_text 
= text
; } 
 307     void GetItem( wxListItem 
&item 
); 
 309     bool IsHit( int x
, int y 
) const; 
 310     int GetImage() const; 
 311     int GetWidth() const; 
 312     int GetFormat() const; 
 328 //----------------------------------------------------------------------------- 
 329 //  wxListLineData (internal) 
 330 //----------------------------------------------------------------------------- 
 332 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
); 
 333 #include "wx/listimpl.cpp" 
 334 WX_DEFINE_LIST(wxListItemDataList
); 
 336 class WXDLLEXPORT wxListLineData
 
 339     // the list of subitems: only may have more than one item in report mode 
 340     wxListItemDataList m_items
; 
 342     // this is not used in report view 
 354         // the part to be highlighted 
 355         wxRect m_rectHighlight
; 
 358     // is this item selected? [NB: not used in virtual mode] 
 361     // back pointer to the list ctrl 
 362     wxListMainWindow 
*m_owner
; 
 365     wxListLineData(wxListMainWindow 
*owner
); 
 367     ~wxListLineData() { delete m_gi
; } 
 369     // are we in report mode? 
 370     inline bool InReportView() const; 
 372     // are we in virtual report mode? 
 373     inline bool IsVirtual() const; 
 375     // these 2 methods shouldn't be called for report view controls, in that 
 376     // case we determine our position/size ourselves 
 378     // calculate the size of the line 
 379     void CalculateSize( wxDC 
*dc
, int spacing 
); 
 381     // remember the position this line appears at 
 382     void SetPosition( int x
, int y
,  int window_width
, int spacing 
); 
 386     void SetImage( int image 
) { SetImage(0, image
); } 
 387     int GetImage() const { return GetImage(0); } 
 388     bool HasImage() const { return GetImage() != -1; } 
 389     bool HasText() const { return !GetText(0).empty(); } 
 391     void SetItem( int index
, const wxListItem 
&info 
); 
 392     void GetItem( int index
, wxListItem 
&info 
); 
 394     wxString 
GetText(int index
) const; 
 395     void SetText( int index
, const wxString s 
); 
 397     wxListItemAttr 
*GetAttr() const; 
 398     void SetAttr(wxListItemAttr 
*attr
); 
 400     // return true if the highlighting really changed 
 401     bool Highlight( bool on 
); 
 403     void ReverseHighlight(); 
 405     bool IsHighlighted() const 
 407         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); 
 409         return m_highlighted
; 
 412     // draw the line on the given DC in icon/list mode 
 413     void Draw( wxDC 
*dc 
); 
 415     // the same in report mode 
 416     void DrawInReportMode( wxDC 
*dc
, 
 418                            const wxRect
& rectHL
, 
 422     // set the line to contain num items (only can be > 1 in report mode) 
 423     void InitItems( int num 
); 
 425     // get the mode (i.e. style)  of the list control 
 426     inline int GetMode() const; 
 428     // prepare the DC for drawing with these item's attributes, return true if 
 429     // we need to draw the items background to highlight it, false otherwise 
 430     bool SetAttributes(wxDC 
*dc
, 
 431                        const wxListItemAttr 
*attr
, 
 434     // draw the text on the DC with the correct justification; also add an 
 435     // ellipsis if the text is too large to fit in the current width 
 436     void DrawTextFormatted(wxDC 
*dc
, const wxString 
&text
, int col
, int x
, int y
, int width
); 
 438     // these are only used by GetImage/SetImage above, we don't support images 
 439     // with subitems at the public API level yet 
 440     void SetImage( int index
, int image 
); 
 441     int GetImage( int index 
) const; 
 444 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
); 
 445 #include "wx/arrimpl.cpp" 
 446 WX_DEFINE_OBJARRAY(wxListLineDataArray
); 
 448 //----------------------------------------------------------------------------- 
 449 //  wxListHeaderWindow (internal) 
 450 //----------------------------------------------------------------------------- 
 452 class WXDLLEXPORT wxListHeaderWindow 
: public wxWindow
 
 455     wxListMainWindow  
*m_owner
; 
 456     wxCursor          
*m_currentCursor
; 
 457     wxCursor          
*m_resizeCursor
; 
 460     // column being resized or -1 
 463     // divider line position in logical (unscrolled) coords 
 466     // minimal position beyond which the divider line can't be dragged in 
 471     wxListHeaderWindow(); 
 473     wxListHeaderWindow( wxWindow 
*win
, 
 475                         wxListMainWindow 
*owner
, 
 476                         const wxPoint 
&pos 
= wxDefaultPosition
, 
 477                         const wxSize 
&size 
= wxDefaultSize
, 
 479                         const wxString 
&name 
= wxT("wxlistctrlcolumntitles") ); 
 481     virtual ~wxListHeaderWindow(); 
 483     void DoDrawRect( wxDC 
*dc
, int x
, int y
, int w
, int h 
); 
 485     void AdjustDC(wxDC
& dc
); 
 487     void OnPaint( wxPaintEvent 
&event 
); 
 488     void OnMouse( wxMouseEvent 
&event 
); 
 489     void OnSetFocus( wxFocusEvent 
&event 
); 
 495     // common part of all ctors 
 498     void SendListEvent(wxEventType type
, wxPoint pos
); 
 500     DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
) 
 501     DECLARE_EVENT_TABLE() 
 504 //----------------------------------------------------------------------------- 
 505 // wxListRenameTimer (internal) 
 506 //----------------------------------------------------------------------------- 
 508 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
 
 511     wxListMainWindow 
*m_owner
; 
 514     wxListRenameTimer( wxListMainWindow 
*owner 
); 
 518 //----------------------------------------------------------------------------- 
 519 //  wxListTextCtrl (internal) 
 520 //----------------------------------------------------------------------------- 
 522 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
 
 525     wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
); 
 528     void OnChar( wxKeyEvent 
&event 
); 
 529     void OnKeyUp( wxKeyEvent 
&event 
); 
 530     void OnKillFocus( wxFocusEvent 
&event 
); 
 532     bool AcceptChanges(); 
 536     wxListMainWindow   
*m_owner
; 
 537     wxString            m_startValue
; 
 541     DECLARE_EVENT_TABLE() 
 544 //----------------------------------------------------------------------------- 
 545 //  wxListMainWindow (internal) 
 546 //----------------------------------------------------------------------------- 
 548 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
); 
 549 #include "wx/listimpl.cpp" 
 550 WX_DEFINE_LIST(wxListHeaderDataList
); 
 552 class WXDLLEXPORT wxListMainWindow 
: public wxScrolledWindow
 
 556     wxListMainWindow( wxWindow 
*parent
, 
 558                       const wxPoint
& pos 
= wxDefaultPosition
, 
 559                       const wxSize
& size 
= wxDefaultSize
, 
 561                       const wxString 
&name 
= _T("listctrlmainwindow") ); 
 563     virtual ~wxListMainWindow(); 
 565     bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); } 
 567     // return true if this is a virtual list control 
 568     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); } 
 570     // return true if the control is in report mode 
 571     bool InReportView() const { return HasFlag(wxLC_REPORT
); } 
 573     // return true if we are in single selection mode, false if multi sel 
 574     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); } 
 576     // do we have a header window? 
 577     bool HasHeader() const 
 578         { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); } 
 580     void HighlightAll( bool on 
); 
 582     // all these functions only do something if the line is currently visible 
 584     // change the line "selected" state, return TRUE if it really changed 
 585     bool HighlightLine( size_t line
, bool highlight 
= TRUE
); 
 587     // as HighlightLine() but do it for the range of lines: this is incredibly 
 588     // more efficient for virtual list controls! 
 590     // NB: unlike HighlightLine() this one does refresh the lines on screen 
 591     void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on 
= TRUE 
); 
 593     // toggle the line state and refresh it 
 594     void ReverseHighlight( size_t line 
) 
 595         { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); } 
 597     // return true if the line is highlighted 
 598     bool IsHighlighted(size_t line
) const; 
 600     // refresh one or several lines at once 
 601     void RefreshLine( size_t line 
); 
 602     void RefreshLines( size_t lineFrom
, size_t lineTo 
); 
 604     // refresh all selected items 
 605     void RefreshSelected(); 
 607     // refresh all lines below the given one: the difference with 
 608     // RefreshLines() is that the index here might not be a valid one (happens 
 609     // when the last line is deleted) 
 610     void RefreshAfter( size_t lineFrom 
); 
 612     // the methods which are forwarded to wxListLineData itself in list/icon 
 613     // modes but are here because the lines don't store their positions in the 
 616     // get the bound rect for the entire line 
 617     wxRect 
GetLineRect(size_t line
) const; 
 619     // get the bound rect of the label 
 620     wxRect 
GetLineLabelRect(size_t line
) const; 
 622     // get the bound rect of the items icon (only may be called if we do have 
 624     wxRect 
GetLineIconRect(size_t line
) const; 
 626     // get the rect to be highlighted when the item has focus 
 627     wxRect 
GetLineHighlightRect(size_t line
) const; 
 629     // get the size of the total line rect 
 630     wxSize 
GetLineSize(size_t line
) const 
 631         { return GetLineRect(line
).GetSize(); } 
 633     // return the hit code for the corresponding position (in this line) 
 634     long HitTestLine(size_t line
, int x
, int y
) const; 
 636     // bring the selected item into view, scrolling to it if necessary 
 637     void MoveToItem(size_t item
); 
 639     // bring the current item into view 
 640     void MoveToFocus() { MoveToItem(m_current
); } 
 642     // start editing the label of the given item 
 643     void EditLabel( long item 
); 
 645     // suspend/resume redrawing the control 
 651     void OnRenameTimer(); 
 652     bool OnRenameAccept(size_t itemEdit
, const wxString
& value
); 
 654     void OnMouse( wxMouseEvent 
&event 
); 
 656     // called to switch the selection from the current item to newCurrent, 
 657     void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event 
); 
 659     void OnChar( wxKeyEvent 
&event 
); 
 660     void OnKeyDown( wxKeyEvent 
&event 
); 
 661     void OnSetFocus( wxFocusEvent 
&event 
); 
 662     void OnKillFocus( wxFocusEvent 
&event 
); 
 663     void OnScroll(wxScrollWinEvent
& event
) ; 
 665     void OnPaint( wxPaintEvent 
&event 
); 
 667     void DrawImage( int index
, wxDC 
*dc
, int x
, int y 
); 
 668     void GetImageSize( int index
, int &width
, int &height 
) const; 
 669     int GetTextLength( const wxString 
&s 
) const; 
 671     void SetImageList( wxImageListType 
*imageList
, int which 
); 
 672     void SetItemSpacing( int spacing
, bool isSmall 
= FALSE 
); 
 673     int GetItemSpacing( bool isSmall 
= FALSE 
); 
 675     void SetColumn( int col
, wxListItem 
&item 
); 
 676     void SetColumnWidth( int col
, int width 
); 
 677     void GetColumn( int col
, wxListItem 
&item 
) const; 
 678     int GetColumnWidth( int col 
) const; 
 679     int GetColumnCount() const { return m_columns
.GetCount(); } 
 681     // returns the sum of the heights of all columns 
 682     int GetHeaderWidth() const; 
 684     int GetCountPerPage() const; 
 686     void SetItem( wxListItem 
&item 
); 
 687     void GetItem( wxListItem 
&item 
) const; 
 688     void SetItemState( long item
, long state
, long stateMask 
); 
 689     int GetItemState( long item
, long stateMask 
) const; 
 690     void GetItemRect( long index
, wxRect 
&rect 
) const; 
 691     bool GetItemPosition( long item
, wxPoint
& pos 
) const; 
 692     int GetSelectedItemCount() const; 
 694     wxString 
GetItemText(long item
) const 
 697         info
.m_itemId 
= item
; 
 702     void SetItemText(long item
, const wxString
& value
) 
 705         info
.m_mask 
= wxLIST_MASK_TEXT
; 
 706         info
.m_itemId 
= item
; 
 711     // set the scrollbars and update the positions of the items 
 712     void RecalculatePositions(bool noRefresh 
= FALSE
); 
 714     // refresh the window and the header 
 717     long GetNextItem( long item
, int geometry
, int state 
) const; 
 718     void DeleteItem( long index 
); 
 719     void DeleteAllItems(); 
 720     void DeleteColumn( int col 
); 
 721     void DeleteEverything(); 
 722     void EnsureVisible( long index 
); 
 723     long FindItem( long start
, const wxString
& str
, bool partial 
= FALSE 
); 
 724     long FindItem( long start
, long data
); 
 725     long HitTest( int x
, int y
, int &flags 
); 
 726     void InsertItem( wxListItem 
&item 
); 
 727     void InsertColumn( long col
, wxListItem 
&item 
); 
 728     void SortItems( wxListCtrlCompare fn
, long data 
); 
 730     size_t GetItemCount() const; 
 731     bool IsEmpty() const { return GetItemCount() == 0; } 
 732     void SetItemCount(long count
); 
 734     // change the current (== focused) item, send a notification event 
 735     void ChangeCurrent(size_t current
); 
 736     void ResetCurrent() { ChangeCurrent((size_t)-1); } 
 737     bool HasCurrent() const { return m_current 
!= (size_t)-1; } 
 739     // send out a wxListEvent 
 740     void SendNotify( size_t line
, 
 742                      wxPoint point 
= wxDefaultPosition 
); 
 744     // override base class virtual to reset m_lineHeight when the font changes 
 745     virtual bool SetFont(const wxFont
& font
) 
 747         if ( !wxScrolledWindow::SetFont(font
) ) 
 755     // these are for wxListLineData usage only 
 757     // get the backpointer to the list ctrl 
 758     wxGenericListCtrl 
*GetListCtrl() const 
 760         return wxStaticCast(GetParent(), wxGenericListCtrl
); 
 763     // get the height of all lines (assuming they all do have the same height) 
 764     wxCoord 
GetLineHeight() const; 
 766     // get the y position of the given line (only for report view) 
 767     wxCoord 
GetLineY(size_t line
) const; 
 769     // get the brush to use for the item highlighting 
 770     wxBrush 
*GetHighlightBrush() const 
 772         return m_hasFocus 
? m_highlightBrush 
: m_highlightUnfocusedBrush
; 
 776     // the array of all line objects for a non virtual list control (for the 
 777     // virtual list control we only ever use m_lines[0]) 
 778     wxListLineDataArray  m_lines
; 
 780     // the list of column objects 
 781     wxListHeaderDataList m_columns
; 
 783     // currently focused item or -1 
 786     // the number of lines per page 
 789     // this flag is set when something which should result in the window 
 790     // redrawing happens (i.e. an item was added or deleted, or its appearance 
 791     // changed) and OnPaint() doesn't redraw the window while it is set which 
 792     // allows to minimize the number of repaintings when a lot of items are 
 793     // being added. The real repainting occurs only after the next OnIdle() 
 797     wxColour            
*m_highlightColour
; 
 800     wxImageListType         
*m_small_image_list
; 
 801     wxImageListType         
*m_normal_image_list
; 
 803     int                  m_normal_spacing
; 
 807     wxTimer             
*m_renameTimer
; 
 812     // for double click logic 
 813     size_t m_lineLastClicked
, 
 814            m_lineBeforeLastClicked
; 
 817     // the total count of items in a virtual list control 
 820     // the object maintaining the items selection state, only used in virtual 
 822     wxSelectionStore m_selStore
; 
 824     // common part of all ctors 
 827     // intiialize m_[xy]Scroll 
 828     void InitScrolling(); 
 830     // get the line data for the given index 
 831     wxListLineData 
*GetLine(size_t n
) const 
 833         wxASSERT_MSG( n 
!= (size_t)-1, _T("invalid line index") ); 
 837             wxConstCast(this, wxListMainWindow
)->CacheLineData(n
); 
 845     // get a dummy line which can be used for geometry calculations and such: 
 846     // you must use GetLine() if you want to really draw the line 
 847     wxListLineData 
*GetDummyLine() const; 
 849     // cache the line data of the n-th line in m_lines[0] 
 850     void CacheLineData(size_t line
); 
 852     // get the range of visible lines 
 853     void GetVisibleLinesRange(size_t *from
, size_t *to
); 
 855     // force us to recalculate the range of visible lines 
 856     void ResetVisibleLinesRange() { m_lineFrom 
= (size_t)-1; } 
 858     // get the colour to be used for drawing the rules 
 859     wxColour 
GetRuleColour() const 
 864         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 869     // initialize the current item if needed 
 870     void UpdateCurrent(); 
 872     // delete all items but don't refresh: called from dtor 
 873     void DoDeleteAllItems(); 
 875     // the height of one line using the current font 
 876     wxCoord m_lineHeight
; 
 878     // the total header width or 0 if not calculated yet 
 879     wxCoord m_headerWidth
; 
 881     // the first and last lines being shown on screen right now (inclusive), 
 882     // both may be -1 if they must be calculated so never access them directly: 
 883     // use GetVisibleLinesRange() above instead 
 887     // the brushes to use for item highlighting when we do/don't have focus 
 888     wxBrush 
*m_highlightBrush
, 
 889             *m_highlightUnfocusedBrush
; 
 891     // if this is > 0, the control is frozen and doesn't redraw itself 
 892     size_t m_freezeCount
; 
 894     DECLARE_DYNAMIC_CLASS(wxListMainWindow
) 
 895     DECLARE_EVENT_TABLE() 
 897     friend class wxGenericListCtrl
; 
 900 // ============================================================================ 
 902 // ============================================================================ 
 904 // ---------------------------------------------------------------------------- 
 906 // ---------------------------------------------------------------------------- 
 908 bool wxSelectionStore::IsSelected(size_t item
) const 
 910     bool isSel 
= m_itemsSel
.Index(item
) != wxNOT_FOUND
; 
 912     // if the default state is to be selected, being in m_itemsSel means that 
 913     // the item is not selected, so we have to inverse the logic 
 914     return m_defaultState 
? !isSel 
: isSel
; 
 917 bool wxSelectionStore::SelectItem(size_t item
, bool select
) 
 919     // search for the item ourselves as like this we get the index where to 
 920     // insert it later if needed, so we do only one search in the array instead 
 921     // of two (adding item to a sorted array requires a search) 
 922     size_t index 
= m_itemsSel
.IndexForInsert(item
); 
 923     bool isSel 
= index 
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
; 
 925     if ( select 
!= m_defaultState 
) 
 929             m_itemsSel
.AddAt(item
, index
); 
 934     else // reset to default state 
 938             m_itemsSel
.RemoveAt(index
); 
 946 bool wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, 
 948                                    wxArrayInt 
*itemsChanged
) 
 950     // 100 is hardcoded but it shouldn't matter much: the important thing is 
 951     // that we don't refresh everything when really few (e.g. 1 or 2) items 
 953     static const size_t MANY_ITEMS 
= 100; 
 955     wxASSERT_MSG( itemFrom 
<= itemTo
, _T("should be in order") ); 
 957     // are we going to have more [un]selected items than the other ones? 
 958     if ( itemTo 
- itemFrom 
> m_count
/2 ) 
 960         if ( select 
!= m_defaultState 
) 
 962             // the default state now becomes the same as 'select' 
 963             m_defaultState 
= select
; 
 965             // so all the old selections (which had state select) shouldn't be 
 966             // selected any more, but all the other ones should 
 967             wxIndexArray selOld 
= m_itemsSel
; 
 970             // TODO: it should be possible to optimize the searches a bit 
 971             //       knowing the possible range 
 974             for ( item 
= 0; item 
< itemFrom
; item
++ ) 
 976                 if ( selOld
.Index(item
) == wxNOT_FOUND 
) 
 977                     m_itemsSel
.Add(item
); 
 980             for ( item 
= itemTo 
+ 1; item 
< m_count
; item
++ ) 
 982                 if ( selOld
.Index(item
) == wxNOT_FOUND 
) 
 983                     m_itemsSel
.Add(item
); 
 986             // many items (> half) changed state 
 989         else // select == m_defaultState 
 991             // get the inclusive range of items between itemFrom and itemTo 
 992             size_t count 
= m_itemsSel
.GetCount(), 
 993                    start 
= m_itemsSel
.IndexForInsert(itemFrom
), 
 994                    end 
= m_itemsSel
.IndexForInsert(itemTo
); 
 996             if ( start 
== count 
|| m_itemsSel
[start
] < itemFrom 
) 
1001             if ( end 
== count 
|| m_itemsSel
[end
] > itemTo 
) 
1008                 // delete all of them (from end to avoid changing indices) 
1009                 for ( int i 
= end
; i 
>= (int)start
; i
-- ) 
1013                         if ( itemsChanged
->GetCount() > MANY_ITEMS 
) 
1015                             // stop counting (see comment below) 
1016                             itemsChanged 
= NULL
; 
1020                             itemsChanged
->Add(m_itemsSel
[i
]); 
1024                     m_itemsSel
.RemoveAt(i
); 
1029     else // "few" items change state 
1033             itemsChanged
->Empty(); 
1036         // just add the items to the selection 
1037         for ( size_t item 
= itemFrom
; item 
<= itemTo
; item
++ ) 
1039             if ( SelectItem(item
, select
) && itemsChanged 
) 
1041                 itemsChanged
->Add(item
); 
1043                 if ( itemsChanged
->GetCount() > MANY_ITEMS 
) 
1045                     // stop counting them, we'll just eat gobs of memory 
1046                     // for nothing at all - faster to refresh everything in 
1048                     itemsChanged 
= NULL
; 
1054     // we set it to NULL if there are many items changing state 
1055     return itemsChanged 
!= NULL
; 
1058 void wxSelectionStore::OnItemDelete(size_t item
) 
1060     size_t count 
= m_itemsSel
.GetCount(), 
1061            i 
= m_itemsSel
.IndexForInsert(item
); 
1063     if ( i 
< count 
&& m_itemsSel
[i
] == item 
) 
1065         // this item itself was in m_itemsSel, remove it from there 
1066         m_itemsSel
.RemoveAt(i
); 
1071     // and adjust the index of all which follow it 
1074         // all following elements must be greater than the one we deleted 
1075         wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") ); 
1081 //----------------------------------------------------------------------------- 
1083 //----------------------------------------------------------------------------- 
1085 wxListItemData::~wxListItemData() 
1087     // in the virtual list control the attributes are managed by the main 
1088     // program, so don't delete them 
1089     if ( !m_owner
->IsVirtual() ) 
1097 void wxListItemData::Init() 
1105 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
1111     if ( owner
->InReportView() ) 
1117         m_rect 
= new wxRect
; 
1121 void wxListItemData::SetItem( const wxListItem 
&info 
) 
1123     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
1124         SetText(info
.m_text
); 
1125     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
1126         m_image 
= info
.m_image
; 
1127     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
1128         m_data 
= info
.m_data
; 
1130     if ( info
.HasAttributes() ) 
1133             *m_attr 
= *info
.GetAttributes(); 
1135             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
1143         m_rect
->width 
= info
.m_width
; 
1147 void wxListItemData::SetPosition( int x
, int y 
) 
1149     wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") ); 
1155 void wxListItemData::SetSize( int width
, int height 
) 
1157     wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") ); 
1160         m_rect
->width 
= width
; 
1162         m_rect
->height 
= height
; 
1165 bool wxListItemData::IsHit( int x
, int y 
) const 
1167     wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") ); 
1169     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
); 
1172 int wxListItemData::GetX() const 
1174     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
1179 int wxListItemData::GetY() const 
1181     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
1186 int wxListItemData::GetWidth() const 
1188     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
1190     return m_rect
->width
; 
1193 int wxListItemData::GetHeight() const 
1195     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
1197     return m_rect
->height
; 
1200 void wxListItemData::GetItem( wxListItem 
&info 
) const 
1202     info
.m_text 
= m_text
; 
1203     info
.m_image 
= m_image
; 
1204     info
.m_data 
= m_data
; 
1208         if ( m_attr
->HasTextColour() ) 
1209             info
.SetTextColour(m_attr
->GetTextColour()); 
1210         if ( m_attr
->HasBackgroundColour() ) 
1211             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
1212         if ( m_attr
->HasFont() ) 
1213             info
.SetFont(m_attr
->GetFont()); 
1217 //----------------------------------------------------------------------------- 
1219 //----------------------------------------------------------------------------- 
1221 void wxListHeaderData::Init() 
1232 wxListHeaderData::wxListHeaderData() 
1237 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
1244 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
1246     m_mask 
= item
.m_mask
; 
1248     if ( m_mask 
& wxLIST_MASK_TEXT 
) 
1249         m_text 
= item
.m_text
; 
1251     if ( m_mask 
& wxLIST_MASK_IMAGE 
) 
1252         m_image 
= item
.m_image
; 
1254     if ( m_mask 
& wxLIST_MASK_FORMAT 
) 
1255         m_format 
= item
.m_format
; 
1257     if ( m_mask 
& wxLIST_MASK_WIDTH 
) 
1258         SetWidth(item
.m_width
); 
1261 void wxListHeaderData::SetPosition( int x
, int y 
) 
1267 void wxListHeaderData::SetHeight( int h 
) 
1272 void wxListHeaderData::SetWidth( int w 
) 
1276         m_width 
= WIDTH_COL_DEFAULT
; 
1277     else if (m_width 
< WIDTH_COL_MIN
) 
1278         m_width 
= WIDTH_COL_MIN
; 
1281 void wxListHeaderData::SetFormat( int format 
) 
1286 bool wxListHeaderData::HasImage() const 
1288     return m_image 
!= -1; 
1291 bool wxListHeaderData::IsHit( int x
, int y 
) const 
1293     return ((x 
>= m_xpos
) && (x 
<= m_xpos
+m_width
) && (y 
>= m_ypos
) && (y 
<= m_ypos
+m_height
)); 
1296 void wxListHeaderData::GetItem( wxListItem
& item 
) 
1298     item
.m_mask 
= m_mask
; 
1299     item
.m_text 
= m_text
; 
1300     item
.m_image 
= m_image
; 
1301     item
.m_format 
= m_format
; 
1302     item
.m_width 
= m_width
; 
1305 int wxListHeaderData::GetImage() const 
1310 int wxListHeaderData::GetWidth() const 
1315 int wxListHeaderData::GetFormat() const 
1320 //----------------------------------------------------------------------------- 
1322 //----------------------------------------------------------------------------- 
1324 inline int wxListLineData::GetMode() const 
1326     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
1329 inline bool wxListLineData::InReportView() const 
1331     return m_owner
->HasFlag(wxLC_REPORT
); 
1334 inline bool wxListLineData::IsVirtual() const 
1336     return m_owner
->IsVirtual(); 
1339 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
1342     m_items
.DeleteContents( TRUE 
); 
1344     if ( InReportView() ) 
1350         m_gi 
= new GeometryInfo
; 
1353     m_highlighted 
= FALSE
; 
1355     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
1358 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
1360     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1361     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1363     wxListItemData 
*item 
= node
->GetData(); 
1365     switch ( GetMode() ) 
1368         case wxLC_SMALL_ICON
: 
1370                 m_gi
->m_rectAll
.width 
= spacing
; 
1372                 wxString s 
= item
->GetText(); 
1378                     m_gi
->m_rectLabel
.width 
= 
1379                     m_gi
->m_rectLabel
.height 
= 0; 
1383                     dc
->GetTextExtent( s
, &lw
, &lh 
); 
1384                     if (lh 
< SCROLL_UNIT_Y
) 
1389                     m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
1391                         m_gi
->m_rectAll
.width 
= lw
; 
1393                     m_gi
->m_rectLabel
.width 
= lw
; 
1394                     m_gi
->m_rectLabel
.height 
= lh
; 
1397                 if (item
->HasImage()) 
1400                     m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1401                     m_gi
->m_rectIcon
.width 
= w 
+ 8; 
1402                     m_gi
->m_rectIcon
.height 
= h 
+ 8; 
1404                     if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
1405                         m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
1406                     if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
1407                         m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
1410                 if ( item
->HasText() ) 
1412                     m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
1413                     m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
1415                 else // no text, highlight the icon 
1417                     m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
1418                     m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
1425                 wxString s 
= item
->GetTextForMeasuring(); 
1428                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
1429                 if (lh 
< SCROLL_UNIT_Y
) 
1434                 m_gi
->m_rectLabel
.width 
= lw
; 
1435                 m_gi
->m_rectLabel
.height 
= lh
; 
1437                 m_gi
->m_rectAll
.width 
= lw
; 
1438                 m_gi
->m_rectAll
.height 
= lh
; 
1440                 if (item
->HasImage()) 
1443                     m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1444                     m_gi
->m_rectIcon
.width 
= w
; 
1445                     m_gi
->m_rectIcon
.height 
= h
; 
1447                     m_gi
->m_rectAll
.width 
+= 4 + w
; 
1448                     if (h 
> m_gi
->m_rectAll
.height
) 
1449                         m_gi
->m_rectAll
.height 
= h
; 
1452                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
1453                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
1458             wxFAIL_MSG( _T("unexpected call to SetSize") ); 
1462             wxFAIL_MSG( _T("unknown mode") ); 
1466 void wxListLineData::SetPosition( int x
, int y
, 
1470     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1471     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1473     wxListItemData 
*item 
= node
->GetData(); 
1475     switch ( GetMode() ) 
1478         case wxLC_SMALL_ICON
: 
1479             m_gi
->m_rectAll
.x 
= x
; 
1480             m_gi
->m_rectAll
.y 
= y
; 
1482             if ( item
->HasImage() ) 
1484                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 + 
1485                     (m_gi
->m_rectAll
.width 
- m_gi
->m_rectIcon
.width
) / 2; 
1486                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
1489             if ( item
->HasText() ) 
1491                 if (m_gi
->m_rectAll
.width 
> spacing
) 
1492                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1494                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2); 
1495                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
1496                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
1497                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
1499             else // no text, highlight the icon 
1501                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
1502                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
1507             m_gi
->m_rectAll
.x 
= x
; 
1508             m_gi
->m_rectAll
.y 
= y
; 
1510             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
1511             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
1512             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1514             if (item
->HasImage()) 
1516                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1517                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1518                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 6 + m_gi
->m_rectIcon
.width
; 
1522                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1527             wxFAIL_MSG( _T("unexpected call to SetPosition") ); 
1531             wxFAIL_MSG( _T("unknown mode") ); 
1535 void wxListLineData::InitItems( int num 
) 
1537     for (int i 
= 0; i 
< num
; i
++) 
1538         m_items
.Append( new wxListItemData(m_owner
) ); 
1541 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
1543     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1544     wxCHECK_RET( node
, _T("invalid column index in SetItem") ); 
1546     wxListItemData 
*item 
= node
->GetData(); 
1547     item
->SetItem( info 
); 
1550 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
1552     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1555         wxListItemData 
*item 
= node
->GetData(); 
1556         item
->GetItem( info 
); 
1560 wxString 
wxListLineData::GetText(int index
) const 
1564     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1567         wxListItemData 
*item 
= node
->GetData(); 
1568         s 
= item
->GetText(); 
1574 void wxListLineData::SetText( int index
, const wxString s 
) 
1576     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1579         wxListItemData 
*item 
= node
->GetData(); 
1584 void wxListLineData::SetImage( int index
, int image 
) 
1586     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1587     wxCHECK_RET( node
, _T("invalid column index in SetImage()") ); 
1589     wxListItemData 
*item 
= node
->GetData(); 
1590     item
->SetImage(image
); 
1593 int wxListLineData::GetImage( int index 
) const 
1595     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1596     wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") ); 
1598     wxListItemData 
*item 
= node
->GetData(); 
1599     return item
->GetImage(); 
1602 wxListItemAttr 
*wxListLineData::GetAttr() const 
1604     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1605     wxCHECK_MSG( node
, NULL
, _T("invalid column index in GetAttr()") ); 
1607     wxListItemData 
*item 
= node
->GetData(); 
1608     return item
->GetAttr(); 
1611 void wxListLineData::SetAttr(wxListItemAttr 
*attr
) 
1613     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1614     wxCHECK_RET( node
, _T("invalid column index in SetAttr()") ); 
1616     wxListItemData 
*item 
= node
->GetData(); 
1617     item
->SetAttr(attr
); 
1620 bool wxListLineData::SetAttributes(wxDC 
*dc
, 
1621                                    const wxListItemAttr 
*attr
, 
1624     wxWindow 
*listctrl 
= m_owner
->GetParent(); 
1628     // don't use foreground colour for drawing highlighted items - this might 
1629     // make them completely invisible (and there is no way to do bit 
1630     // arithmetics on wxColour, unfortunately) 
1634         colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1638         if ( attr 
&& attr
->HasTextColour() ) 
1640             colText 
= attr
->GetTextColour(); 
1644             colText 
= listctrl
->GetForegroundColour(); 
1648     dc
->SetTextForeground(colText
); 
1652     if ( attr 
&& attr
->HasFont() ) 
1654         font 
= attr
->GetFont(); 
1658         font 
= listctrl
->GetFont(); 
1664     bool hasBgCol 
= attr 
&& attr
->HasBackgroundColour(); 
1665     if ( highlighted 
|| hasBgCol 
) 
1669             dc
->SetBrush( *m_owner
->GetHighlightBrush() ); 
1673             dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
)); 
1676         dc
->SetPen( *wxTRANSPARENT_PEN 
); 
1684 void wxListLineData::Draw( wxDC 
*dc 
) 
1686     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1687     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1689     bool highlighted 
= IsHighlighted(); 
1691     wxListItemAttr 
*attr 
= GetAttr(); 
1693     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1695         dc
->DrawRectangle( m_gi
->m_rectHighlight 
); 
1698     wxListItemData 
*item 
= node
->GetData(); 
1699     if (item
->HasImage()) 
1701         wxRect rectIcon 
= m_gi
->m_rectIcon
; 
1702         m_owner
->DrawImage( item
->GetImage(), dc
, 
1703                             rectIcon
.x
, rectIcon
.y 
); 
1706     if (item
->HasText()) 
1708         wxRect rectLabel 
= m_gi
->m_rectLabel
; 
1710         wxDCClipper 
clipper(*dc
, rectLabel
); 
1711         dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y 
); 
1715 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
1717                                        const wxRect
& rectHL
, 
1720     // TODO: later we should support setting different attributes for 
1721     //       different columns - to do it, just add "col" argument to 
1722     //       GetAttr() and move these lines into the loop below 
1723     wxListItemAttr 
*attr 
= GetAttr(); 
1724     if ( SetAttributes(dc
, attr
, highlighted
) ) 
1726         dc
->DrawRectangle( rectHL 
); 
1729     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
1730             y 
= rect
.y 
+ (LINE_SPACING 
+ EXTRA_HEIGHT
) / 2; 
1733     for ( wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1735           node 
= node
->GetNext(), col
++ ) 
1737         wxListItemData 
*item 
= node
->GetData(); 
1739         int width 
= m_owner
->GetColumnWidth(col
); 
1743         if ( item
->HasImage() ) 
1746             m_owner
->DrawImage( item
->GetImage(), dc
, xOld
, y 
); 
1747             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
1749             ix 
+= IMAGE_MARGIN_IN_REPORT_MODE
; 
1755         wxDCClipper 
clipper(*dc
, xOld
, y
, width 
- 8, rect
.height
); 
1757         if ( item
->HasText() ) 
1759             DrawTextFormatted(dc
, item
->GetText(), col
, xOld
, y
, width 
- 8); 
1764 void wxListLineData::DrawTextFormatted(wxDC 
*dc
, 
1765                                        const wxString 
&text
, 
1771     wxString drawntext
, ellipsis
; 
1772     wxCoord w
, h
, base_w
; 
1775     // determine if the string can fit inside the current width 
1776     dc
->GetTextExtent(text
, &w
, &h
); 
1779         // it can, draw it using the items alignment 
1780         m_owner
->GetColumn(col
, item
); 
1781         switch ( item
.GetAlign() ) 
1784                 wxFAIL_MSG( _T("unknown list item format") ); 
1787             case wxLIST_FORMAT_LEFT
: 
1791             case wxLIST_FORMAT_RIGHT
: 
1795             case wxLIST_FORMAT_CENTER
: 
1796                 x 
+= (width 
- w
) / 2; 
1800         dc
->DrawText(text
, x
, y
); 
1802     else // otherwise, truncate and add an ellipsis if possible 
1804         // determine the base width 
1805         ellipsis 
= wxString(wxT("...")); 
1806         dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1808         // continue until we have enough space or only one character left 
1809         drawntext 
= text
.Left(text
.Length() - 1); 
1810         while (drawntext
.Length() > 1) 
1812             dc
->GetTextExtent(drawntext
, &w
, &h
); 
1813             if (w 
+ base_w 
<= width
) 
1815             drawntext 
= drawntext
.Left(drawntext
.Length() - 1); 
1818         // if still not enough space, remove ellipsis characters 
1819         while (ellipsis
.Length() > 0 && w 
+ base_w 
> width
) 
1821             ellipsis 
= ellipsis
.Left(ellipsis
.Length() - 1); 
1822             dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
1825         // now draw the text 
1826         dc
->DrawText(drawntext
, x
, y
); 
1827         dc
->DrawText(ellipsis
, x 
+ w
, y
); 
1831 bool wxListLineData::Highlight( bool on 
) 
1833     wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") ); 
1835     if ( on 
== m_highlighted 
) 
1843 void wxListLineData::ReverseHighlight( void ) 
1845     Highlight(!IsHighlighted()); 
1848 //----------------------------------------------------------------------------- 
1849 //  wxListHeaderWindow 
1850 //----------------------------------------------------------------------------- 
1852 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
) 
1854 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
1855     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
1856     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
1857     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
1860 void wxListHeaderWindow::Init() 
1862     m_currentCursor 
= (wxCursor 
*) NULL
; 
1863     m_isDragging 
= FALSE
; 
1867 wxListHeaderWindow::wxListHeaderWindow() 
1871     m_owner 
= (wxListMainWindow 
*) NULL
; 
1872     m_resizeCursor 
= (wxCursor 
*) NULL
; 
1875 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, 
1877                                         wxListMainWindow 
*owner
, 
1881                                         const wxString 
&name 
) 
1882                   : wxWindow( win
, id
, pos
, size
, style
, name 
) 
1887     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
1889     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
) ); 
1892 wxListHeaderWindow::~wxListHeaderWindow() 
1894     delete m_resizeCursor
; 
1897 #ifdef __WXUNIVERSAL__ 
1898 #include "wx/univ/renderer.h" 
1899 #include "wx/univ/theme.h" 
1902 void wxListHeaderWindow::DoDrawRect( wxDC 
*dc
, int x
, int y
, int w
, int h 
) 
1904 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
1905     GtkStateType state 
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
 
1906                                                : GTK_STATE_INSENSITIVE
; 
1908     x 
= dc
->XLOG2DEV( x 
); 
1910     gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
, 
1911                    state
, GTK_SHADOW_OUT
, 
1912                    (GdkRectangle
*) NULL
, m_wxwindow
, 
1913                    (char *)"button", // const_cast 
1914                    x
-1, y
-1, w
+2, h
+2); 
1915 #elif defined(__WXUNIVERSAL__) 
1916     wxTheme 
*theme 
= wxTheme::Get(); 
1917     wxRenderer 
*renderer 
= theme
->GetRenderer(); 
1918     renderer
->DrawBorder( *dc
, wxBORDER_RAISED
, wxRect(x
,y
,w
,h
), 0 ); 
1919 #elif defined(__WXMAC__) 
1920     const int m_corner 
= 1; 
1922     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
1924     dc
->SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW 
) , 1 , wxSOLID 
) ); 
1925     dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h 
);  // right (outer) 
1926     dc
->DrawRectangle( x
, y
+h
, w
+1, 1 );          // bottom (outer) 
1928     wxPen 
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID 
); 
1931     dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h 
);  // right (inner) 
1932     dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 );      // bottom (inner) 
1934     dc
->SetPen( *wxWHITE_PEN 
); 
1935     dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 );   // top (outer) 
1936     dc
->DrawRectangle( x
, y
, 1, h 
);              // left (outer) 
1937     dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 ); 
1938     dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 ); 
1940     const int m_corner 
= 1; 
1942     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
1944     dc
->SetPen( *wxBLACK_PEN 
); 
1945     dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h 
);  // right (outer) 
1946     dc
->DrawRectangle( x
, y
+h
, w
+1, 1 );          // bottom (outer) 
1948     wxPen 
pen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW 
), 1, wxSOLID 
); 
1951     dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h 
);  // right (inner) 
1952     dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 );      // bottom (inner) 
1954     dc
->SetPen( *wxWHITE_PEN 
); 
1955     dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 );   // top (outer) 
1956     dc
->DrawRectangle( x
, y
, 1, h 
);              // left (outer) 
1957     dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 ); 
1958     dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 ); 
1962 // shift the DC origin to match the position of the main window horz 
1963 // scrollbar: this allows us to always use logical coords 
1964 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
1967     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1970     m_owner
->GetViewStart( &x
, NULL 
); 
1972     // account for the horz scrollbar offset 
1973     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1976 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1978 #if defined(__WXGTK__) 
1979     wxClientDC 
dc( this ); 
1981     wxPaintDC 
dc( this ); 
1989     dc
.SetFont( GetFont() ); 
1991     // width and height of the entire header window 
1993     GetClientSize( &w
, &h 
); 
1994     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1996     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1998     // do *not* use the listctrl colour for headers - one day we will have a 
1999     // function to set it separately 
2000     //dc.SetTextForeground( *wxBLACK ); 
2001     dc
.SetTextForeground(wxSystemSettings:: 
2002                             GetSystemColour( wxSYS_COLOUR_WINDOWTEXT 
)); 
2004     int x 
= HEADER_OFFSET_X
; 
2006     int numColumns 
= m_owner
->GetColumnCount(); 
2008     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
2010         m_owner
->GetColumn( i
, item 
); 
2011         int wCol 
= item
.m_width
; 
2013         // the width of the rect to draw: make it smaller to fit entirely 
2014         // inside the column rect 
2017         dc
.SetPen( *wxWHITE_PEN 
); 
2019         DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 ); 
2021         // see if we have enough space for the column label 
2023         // for this we need the width of the text 
2025         dc
.GetTextExtent(item
.GetText(), &wLabel
, NULL
); 
2026         wLabel 
+= 2*EXTRA_WIDTH
; 
2028         // and the width of the icon, if any 
2029         static const int MARGIN_BETWEEN_TEXT_AND_ICON 
= 2; 
2030         int ix 
= 0,     // init them just to suppress the compiler warnings 
2032         const int image 
= item
.m_image
; 
2033         wxImageListType 
*imageList
; 
2036             imageList 
= m_owner
->m_small_image_list
; 
2039                 imageList
->GetSize(image
, ix
, iy
); 
2040                 wLabel 
+= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
2048         // ignore alignment if there is not enough space anyhow 
2050         switch ( wLabel 
< cw 
? item
.GetAlign() : wxLIST_FORMAT_LEFT 
) 
2053                 wxFAIL_MSG( _T("unknown list item format") ); 
2056             case wxLIST_FORMAT_LEFT
: 
2060             case wxLIST_FORMAT_RIGHT
: 
2061                 xAligned 
= x 
+ cw 
- wLabel
; 
2064             case wxLIST_FORMAT_CENTER
: 
2065                 xAligned 
= x 
+ (cw 
- wLabel
) / 2; 
2070         // if we have an image, draw it on the right of the label 
2077                         xAligned 
+ wLabel 
- ix 
- MARGIN_BETWEEN_TEXT_AND_ICON
, 
2078                         HEADER_OFFSET_Y 
+ (h 
- 4 - iy
)/2, 
2079                         wxIMAGELIST_DRAW_TRANSPARENT
 
2082             cw 
-= ix 
+ MARGIN_BETWEEN_TEXT_AND_ICON
; 
2085         // draw the text clipping it so that it doesn't overwrite the column 
2087         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h 
- 4 ); 
2089         dc
.DrawText( item
.GetText(), 
2090                      xAligned 
+ EXTRA_WIDTH
, HEADER_OFFSET_Y 
+ EXTRA_HEIGHT 
); 
2098 void wxListHeaderWindow::DrawCurrent() 
2100     int x1 
= m_currentX
; 
2102     m_owner
->ClientToScreen( &x1
, &y1 
); 
2104     int x2 
= m_currentX
; 
2106     m_owner
->GetClientSize( NULL
, &y2 
); 
2107     m_owner
->ClientToScreen( &x2
, &y2 
); 
2110     dc
.SetLogicalFunction( wxINVERT 
); 
2111     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
2112     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2116     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
2118     dc
.SetLogicalFunction( wxCOPY 
); 
2120     dc
.SetPen( wxNullPen 
); 
2121     dc
.SetBrush( wxNullBrush 
); 
2124 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
2126     // we want to work with logical coords 
2128     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
2129     int y 
= event
.GetY(); 
2133         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, 
2134                       event
.GetPosition()); 
2136         // we don't draw the line beyond our window, but we allow dragging it 
2139         GetClientSize( &w
, NULL 
); 
2140         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
2143         // erase the line if it was drawn 
2144         if ( m_currentX 
< w 
) 
2147         if (event
.ButtonUp()) 
2150             m_isDragging 
= FALSE
; 
2152             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
2153             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, 
2154                           event
.GetPosition()); 
2161                 m_currentX 
= m_minX 
+ 7; 
2163             // draw in the new location 
2164             if ( m_currentX 
< w 
) 
2168     else // not dragging 
2171         bool hit_border 
= FALSE
; 
2173         // end of the current column 
2176         // find the column where this event occured 
2178             countCol 
= m_owner
->GetColumnCount(); 
2179         for (col 
= 0; col 
< countCol
; col
++) 
2181             xpos 
+= m_owner
->GetColumnWidth( col 
); 
2184             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
2186                 // near the column border 
2193                 // inside the column 
2200         if ( col 
== countCol 
) 
2203         if (event
.LeftDown() || event
.RightUp()) 
2205             if (hit_border 
&& event
.LeftDown()) 
2207                 m_isDragging 
= TRUE
; 
2211                 SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
2212                               event
.GetPosition()); 
2214             else // click on a column 
2216                 SendListEvent( event
.LeftDown() 
2217                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
2218                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
2219                                 event
.GetPosition()); 
2222         else if (event
.Moving()) 
2227                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
2228                 m_currentCursor 
= m_resizeCursor
; 
2232                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
2233                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
2237                 SetCursor(*m_currentCursor
); 
2242 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
2244     m_owner
->SetFocus(); 
2247 void wxListHeaderWindow::SendListEvent(wxEventType type
, wxPoint pos
) 
2249     wxWindow 
*parent 
= GetParent(); 
2250     wxListEvent 
le( type
, parent
->GetId() ); 
2251     le
.SetEventObject( parent 
); 
2252     le
.m_pointDrag 
= pos
; 
2254     // the position should be relative to the parent window, not 
2255     // this one for compatibility with MSW and common sense: the 
2256     // user code doesn't know anything at all about this header 
2257     // window, so why should it get positions relative to it? 
2258     le
.m_pointDrag
.y 
-= GetSize().y
; 
2260     le
.m_col 
= m_column
; 
2261     parent
->GetEventHandler()->ProcessEvent( le 
); 
2264 //----------------------------------------------------------------------------- 
2265 // wxListRenameTimer (internal) 
2266 //----------------------------------------------------------------------------- 
2268 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
2273 void wxListRenameTimer::Notify() 
2275     m_owner
->OnRenameTimer(); 
2278 //----------------------------------------------------------------------------- 
2279 // wxListTextCtrl (internal) 
2280 //----------------------------------------------------------------------------- 
2282 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
) 
2283     EVT_CHAR           (wxListTextCtrl::OnChar
) 
2284     EVT_KEY_UP         (wxListTextCtrl::OnKeyUp
) 
2285     EVT_KILL_FOCUS     (wxListTextCtrl::OnKillFocus
) 
2288 wxListTextCtrl::wxListTextCtrl(wxListMainWindow 
*owner
, size_t itemEdit
) 
2289               : m_startValue(owner
->GetItemText(itemEdit
)), 
2290                 m_itemEdited(itemEdit
) 
2295     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
2297     m_owner
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
2298                                   &rectLabel
.x
, &rectLabel
.y
); 
2300     (void)Create(owner
, wxID_ANY
, m_startValue
, 
2301                  wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2302                  wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
2305 void wxListTextCtrl::Finish() 
2309         wxPendingDelete
.Append(this); 
2313         m_owner
->SetFocus(); 
2317 bool wxListTextCtrl::AcceptChanges() 
2319     const wxString value 
= GetValue(); 
2321     if ( value 
== m_startValue 
) 
2323         // nothing changed, always accept 
2327     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
2329         // vetoed by the user 
2333     // accepted, do rename the item 
2334     m_owner
->SetItemText(m_itemEdited
, value
); 
2339 void wxListTextCtrl::OnChar( wxKeyEvent 
&event 
) 
2341     switch ( event
.m_keyCode 
) 
2344             if ( !AcceptChanges() ) 
2346                 // vetoed by the user code 
2349             //else: fall through 
2360 void wxListTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
2368     // auto-grow the textctrl: 
2369     wxSize parentSize 
= m_owner
->GetSize(); 
2370     wxPoint myPos 
= GetPosition(); 
2371     wxSize mySize 
= GetSize(); 
2373     GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); 
2374     if (myPos
.x 
+ sx 
> parentSize
.x
) 
2375         sx 
= parentSize
.x 
- myPos
.x
; 
2383 void wxListTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2387         (void)AcceptChanges(); 
2395 //----------------------------------------------------------------------------- 
2397 //----------------------------------------------------------------------------- 
2399 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
) 
2401 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
) 
2402   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2403   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2404   EVT_CHAR           (wxListMainWindow::OnChar
) 
2405   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2406   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2407   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2408   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2411 void wxListMainWindow::Init() 
2413     m_columns
.DeleteContents( TRUE 
); 
2417     m_lineTo 
= (size_t)-1; 
2423     m_small_image_list 
= (wxImageListType 
*) NULL
; 
2424     m_normal_image_list 
= (wxImageListType 
*) NULL
; 
2426     m_small_spacing 
= 30; 
2427     m_normal_spacing 
= 40; 
2431     m_isCreated 
= FALSE
; 
2433     m_lastOnSame 
= FALSE
; 
2434     m_renameTimer 
= new wxListRenameTimer( this ); 
2438     m_lineBeforeLastClicked 
= (size_t)-1; 
2443 void wxListMainWindow::InitScrolling() 
2445     if ( HasFlag(wxLC_REPORT
) ) 
2447         m_xScroll 
= SCROLL_UNIT_X
; 
2448         m_yScroll 
= SCROLL_UNIT_Y
; 
2452         m_xScroll 
= SCROLL_UNIT_Y
; 
2457 wxListMainWindow::wxListMainWindow() 
2462     m_highlightUnfocusedBrush 
= (wxBrush 
*) NULL
; 
2468 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2473                                     const wxString 
&name 
) 
2474                 : wxScrolledWindow( parent
, id
, pos
, size
, 
2475                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2479     m_highlightBrush 
= new wxBrush
 
2481                             wxSystemSettings::GetColour
 
2483                                 wxSYS_COLOUR_HIGHLIGHT
 
2488     m_highlightUnfocusedBrush 
= new wxBrush
 
2490                                        wxSystemSettings::GetColour
 
2492                                            wxSYS_COLOUR_BTNSHADOW
 
2501     SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 ); 
2503     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX 
) ); 
2506 wxListMainWindow::~wxListMainWindow() 
2510     delete m_highlightBrush
; 
2511     delete m_highlightUnfocusedBrush
; 
2513     delete m_renameTimer
; 
2516 void wxListMainWindow::CacheLineData(size_t line
) 
2518     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
2520     wxListLineData 
*ld 
= GetDummyLine(); 
2522     size_t countCol 
= GetColumnCount(); 
2523     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2525         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2528     ld
->SetImage(listctrl
->OnGetItemImage(line
)); 
2529     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
2532 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2534     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2536     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); 
2538     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2540     // we need to recreate the dummy line if the number of columns in the 
2541     // control changed as it would have the incorrect number of fields 
2543     if ( !m_lines
.IsEmpty() && 
2544             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
2546         self
->m_lines
.Clear(); 
2549     if ( m_lines
.IsEmpty() ) 
2551         wxListLineData 
*line 
= new wxListLineData(self
); 
2552         self
->m_lines
.Add(line
); 
2554         // don't waste extra memory -- there never going to be anything 
2555         // else/more in this array 
2556         self
->m_lines
.Shrink(); 
2562 // ---------------------------------------------------------------------------- 
2563 // line geometry (report mode only) 
2564 // ---------------------------------------------------------------------------- 
2566 wxCoord 
wxListMainWindow::GetLineHeight() const 
2568     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") ); 
2570     // we cache the line height as calling GetTextExtent() is slow 
2571     if ( !m_lineHeight 
) 
2573         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2575         wxClientDC 
dc( self 
); 
2576         dc
.SetFont( GetFont() ); 
2579         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2581         if ( y 
< SCROLL_UNIT_Y 
) 
2585         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2588     return m_lineHeight
; 
2591 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2593     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") ); 
2595     return LINE_SPACING 
+ line
*GetLineHeight(); 
2598 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2600     if ( !InReportView() ) 
2601         return GetLine(line
)->m_gi
->m_rectAll
; 
2604     rect
.x 
= HEADER_OFFSET_X
; 
2605     rect
.y 
= GetLineY(line
); 
2606     rect
.width 
= GetHeaderWidth(); 
2607     rect
.height 
= GetLineHeight(); 
2612 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2614     if ( !InReportView() ) 
2615         return GetLine(line
)->m_gi
->m_rectLabel
; 
2618     rect
.x 
= HEADER_OFFSET_X
; 
2619     rect
.y 
= GetLineY(line
); 
2620     rect
.width 
= GetColumnWidth(0); 
2621     rect
.height 
= GetLineHeight(); 
2626 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2628     if ( !InReportView() ) 
2629         return GetLine(line
)->m_gi
->m_rectIcon
; 
2631     wxListLineData 
*ld 
= GetLine(line
); 
2632     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2635     rect
.x 
= HEADER_OFFSET_X
; 
2636     rect
.y 
= GetLineY(line
); 
2637     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2642 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2644     return InReportView() ? GetLineRect(line
) 
2645                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2648 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2650     wxASSERT_MSG( line 
< GetItemCount(), _T("invalid line in HitTestLine") ); 
2652     wxListLineData 
*ld 
= GetLine(line
); 
2654     if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) ) 
2655         return wxLIST_HITTEST_ONITEMICON
; 
2657     // VS: Testing for "ld->HasText() || InReportView()" instead of 
2658     //     "ld->HasText()" is needed to make empty lines in report view 
2660     if ( ld
->HasText() || InReportView() ) 
2662         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2663                                      : GetLineLabelRect(line
); 
2665         if ( rect
.Inside(x
, y
) ) 
2666             return wxLIST_HITTEST_ONITEMLABEL
; 
2672 // ---------------------------------------------------------------------------- 
2673 // highlight (selection) handling 
2674 // ---------------------------------------------------------------------------- 
2676 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2680         return m_selStore
.IsSelected(line
); 
2684         wxListLineData 
*ld 
= GetLine(line
); 
2685         wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") ); 
2687         return ld
->IsHighlighted(); 
2691 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
2697         wxArrayInt linesChanged
; 
2698         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
2701             // meny items changed state, refresh everything 
2702             RefreshLines(lineFrom
, lineTo
); 
2704         else // only a few items changed state, refresh only them 
2706             size_t count 
= linesChanged
.GetCount(); 
2707             for ( size_t n 
= 0; n 
< count
; n
++ ) 
2709                 RefreshLine(linesChanged
[n
]); 
2713     else // iterate over all items in non report view 
2715         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2717             if ( HighlightLine(line
, highlight
) ) 
2725 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2731         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2735         wxListLineData 
*ld 
= GetLine(line
); 
2736         wxCHECK_MSG( ld
, FALSE
, _T("invalid index in HighlightLine") ); 
2738         changed 
= ld
->Highlight(highlight
); 
2743         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2744                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2750 void wxListMainWindow::RefreshLine( size_t line 
) 
2752     if ( HasFlag(wxLC_REPORT
) ) 
2754         size_t visibleFrom
, visibleTo
; 
2755         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2757         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
2761     wxRect rect 
= GetLineRect(line
); 
2763     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2764     RefreshRect( rect 
); 
2767 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2769     // we suppose that they are ordered by caller 
2770     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2772     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2774     if ( HasFlag(wxLC_REPORT
) ) 
2776         size_t visibleFrom
, visibleTo
; 
2777         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2779         if ( lineFrom 
< visibleFrom 
) 
2780             lineFrom 
= visibleFrom
; 
2781         if ( lineTo 
> visibleTo 
) 
2786         rect
.y 
= GetLineY(lineFrom
); 
2787         rect
.width 
= GetClientSize().x
; 
2788         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
2790         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2791         RefreshRect( rect 
); 
2795         // TODO: this should be optimized... 
2796         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2803 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2805     if ( HasFlag(wxLC_REPORT
) ) 
2807         size_t visibleFrom
, visibleTo
; 
2808         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2810         if ( lineFrom 
< visibleFrom 
) 
2811             lineFrom 
= visibleFrom
; 
2812         else if ( lineFrom 
> visibleTo 
) 
2817         rect
.y 
= GetLineY(lineFrom
); 
2818         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2820         wxSize size 
= GetClientSize(); 
2821         rect
.width 
= size
.x
; 
2822         // refresh till the bottom of the window 
2823         rect
.height 
= size
.y 
- rect
.y
; 
2825         RefreshRect( rect 
); 
2829         // TODO: how to do it more efficiently? 
2834 void wxListMainWindow::RefreshSelected() 
2840     if ( InReportView() ) 
2842         GetVisibleLinesRange(&from
, &to
); 
2847         to 
= GetItemCount() - 1; 
2850     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
2852         RefreshLine(m_current
); 
2855     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
2857         // NB: the test works as expected even if m_current == -1 
2858         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
2865 void wxListMainWindow::Freeze() 
2870 void wxListMainWindow::Thaw() 
2872     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen list control?") ); 
2874     if ( !--m_freezeCount 
) 
2880 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2882     // Note: a wxPaintDC must be constructed even if no drawing is 
2883     // done (a Windows requirement). 
2884     wxPaintDC 
dc( this ); 
2886     if ( IsEmpty() || m_freezeCount 
) 
2888         // nothing to draw or not the moment to draw it 
2894         // delay the repainting until we calculate all the items positions 
2901     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2905     dc
.SetFont( GetFont() ); 
2907     if ( HasFlag(wxLC_REPORT
) ) 
2909         int lineHeight 
= GetLineHeight(); 
2911         size_t visibleFrom
, visibleTo
; 
2912         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2915         wxCoord xOrig
, yOrig
; 
2916         CalcUnscrolledPosition(0, 0, &xOrig
, &yOrig
); 
2918         // tell the caller cache to cache the data 
2921             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2922                                 GetParent()->GetId()); 
2923             evCache
.SetEventObject( GetParent() ); 
2924             evCache
.m_oldItemIndex 
= visibleFrom
; 
2925             evCache
.m_itemIndex 
= visibleTo
; 
2926             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2929         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2931             rectLine 
= GetLineRect(line
); 
2933             if ( !IsExposed(rectLine
.x 
- xOrig
, rectLine
.y 
- yOrig
, 
2934                             rectLine
.width
, rectLine
.height
) ) 
2936                 // don't redraw unaffected lines to avoid flicker 
2940             GetLine(line
)->DrawInReportMode( &dc
, 
2942                                              GetLineHighlightRect(line
), 
2943                                              IsHighlighted(line
) ); 
2946         if ( HasFlag(wxLC_HRULES
) ) 
2948             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2949             wxSize clientSize 
= GetClientSize(); 
2951             // Don't draw the first one 
2952             for ( size_t i 
= visibleFrom
+1; i 
<= visibleTo
; i
++ ) 
2955                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2956                 dc
.DrawLine(0 - dev_x
, i
*lineHeight
, 
2957                             clientSize
.x 
- dev_x
, i
*lineHeight
); 
2960             // Draw last horizontal rule 
2961             if ( visibleTo 
== GetItemCount() - 1 ) 
2964                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2965                 dc
.DrawLine(0 - dev_x
, (m_lineTo
+1)*lineHeight
, 
2966                             clientSize
.x 
- dev_x 
, (m_lineTo
+1)*lineHeight 
); 
2970         // Draw vertical rules if required 
2971         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2973             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2976             wxRect firstItemRect
; 
2977             wxRect lastItemRect
; 
2978             GetItemRect(visibleFrom
, firstItemRect
); 
2979             GetItemRect(visibleTo
, lastItemRect
); 
2980             int x 
= firstItemRect
.GetX(); 
2982             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2983             for (col 
= 0; col 
< GetColumnCount(); col
++) 
2985                 int colWidth 
= GetColumnWidth(col
); 
2987                 dc
.DrawLine(x 
- dev_x 
- 2, firstItemRect
.GetY() - 1 - dev_y
, 
2988                             x 
- dev_x 
- 2, lastItemRect
.GetBottom() + 1 - dev_y
); 
2994         size_t count 
= GetItemCount(); 
2995         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2997             GetLine(i
)->Draw( &dc 
); 
3003         // don't draw rect outline under Max if we already have the background 
3004         // color but under other platforms only draw it if we do: it is a bit 
3005         // silly to draw "focus rect" if we don't have focus! 
3010 #endif // __WXMAC__/!__WXMAC__ 
3012             dc
.SetPen( *wxBLACK_PEN 
); 
3013             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
3014             dc
.DrawRectangle( GetLineHighlightRect(m_current
) ); 
3021 void wxListMainWindow::HighlightAll( bool on 
) 
3023     if ( IsSingleSel() ) 
3025         wxASSERT_MSG( !on
, _T("can't do this in a single sel control") ); 
3027         // we just have one item to turn off 
3028         if ( HasCurrent() && IsHighlighted(m_current
) ) 
3030             HighlightLine(m_current
, FALSE
); 
3031             RefreshLine(m_current
); 
3036         HighlightLines(0, GetItemCount() - 1, on
); 
3040 void wxListMainWindow::SendNotify( size_t line
, 
3041                                    wxEventType command
, 
3044     wxListEvent 
le( command
, GetParent()->GetId() ); 
3045     le
.SetEventObject( GetParent() ); 
3046     le
.m_itemIndex 
= line
; 
3048     // set only for events which have position 
3049     if ( point 
!= wxDefaultPosition 
) 
3050         le
.m_pointDrag 
= point
; 
3052     // don't try to get the line info for virtual list controls: the main 
3053     // program has it anyhow and if we did it would result in accessing all 
3054     // the lines, even those which are not visible now and this is precisely 
3055     // what we're trying to avoid 
3056     if ( !IsVirtual() && (command 
!= wxEVT_COMMAND_LIST_DELETE_ITEM
) ) 
3058         if ( line 
!= (size_t)-1 ) 
3060             GetLine(line
)->GetItem( 0, le
.m_item 
); 
3062         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
3064     //else: there may be no more such item 
3066     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
3069 void wxListMainWindow::ChangeCurrent(size_t current
) 
3071     m_current 
= current
; 
3073     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
3076 void wxListMainWindow::EditLabel( long item 
) 
3078     wxCHECK_RET( (item 
>= 0) && ((size_t)item 
< GetItemCount()), 
3079                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
3081     size_t itemEdit 
= (size_t)item
; 
3083     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
3084     le
.SetEventObject( GetParent() ); 
3085     le
.m_itemIndex 
= item
; 
3086     wxListLineData 
*data 
= GetLine(itemEdit
); 
3087     wxCHECK_RET( data
, _T("invalid index in EditLabel()") ); 
3088     data
->GetItem( 0, le
.m_item 
); 
3089     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
3091         // vetoed by user code 
3095     // We have to call this here because the label in question might just have 
3096     // been added and no screen update taken place. 
3100     wxListTextCtrl 
*text 
= new wxListTextCtrl(this, itemEdit
); 
3105 void wxListMainWindow::OnRenameTimer() 
3107     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
3109     EditLabel( m_current 
); 
3112 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
3114     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
3115     le
.SetEventObject( GetParent() ); 
3116     le
.m_itemIndex 
= itemEdit
; 
3118     wxListLineData 
*data 
= GetLine(itemEdit
); 
3119     wxCHECK_MSG( data
, FALSE
, _T("invalid index in OnRenameAccept()") ); 
3121     data
->GetItem( 0, le
.m_item 
); 
3122     le
.m_item
.m_text 
= value
; 
3123     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
3127 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
3129     event
.SetEventObject( GetParent() ); 
3130     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
3133     if ( !HasCurrent() || IsEmpty() ) 
3139     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
3140         event
.ButtonDClick()) ) 
3143     int x 
= event
.GetX(); 
3144     int y 
= event
.GetY(); 
3145     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
3147     // where did we hit it (if we did)? 
3150     size_t count 
= GetItemCount(), 
3153     if ( HasFlag(wxLC_REPORT
) ) 
3155         current 
= y 
/ GetLineHeight(); 
3156         if ( current 
< count 
) 
3157             hitResult 
= HitTestLine(current
, x
, y
); 
3161         // TODO: optimize it too! this is less simple than for report view but 
3162         //       enumerating all items is still not a way to do it!! 
3163         for ( current 
= 0; current 
< count
; current
++ ) 
3165             hitResult 
= HitTestLine(current
, x
, y
); 
3171     if (event
.Dragging()) 
3173         if (m_dragCount 
== 0) 
3175             // we have to report the raw, physical coords as we want to be 
3176             // able to call HitTest(event.m_pointDrag) from the user code to 
3177             // get the item being dragged 
3178             m_dragStart 
= event
.GetPosition(); 
3183         if (m_dragCount 
!= 3) 
3186         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
3187                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
3189         wxListEvent 
le( command
, GetParent()->GetId() ); 
3190         le
.SetEventObject( GetParent() ); 
3191         le
.m_pointDrag 
= m_dragStart
; 
3192         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
3203         // outside of any item 
3207     bool forceClick 
= FALSE
; 
3208     if (event
.ButtonDClick()) 
3210         m_renameTimer
->Stop(); 
3211         m_lastOnSame 
= FALSE
; 
3213         if ( current 
== m_lineLastClicked 
) 
3215             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3221             // the first click was on another item, so don't interpret this as 
3222             // a double click, but as a simple click instead 
3227     if (event
.LeftUp() && m_lastOnSame
) 
3229         if ((current 
== m_current
) && 
3230             (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
3231             HasFlag(wxLC_EDIT_LABELS
)  ) 
3233             m_renameTimer
->Start( 100, TRUE 
); 
3235         m_lastOnSame 
= FALSE
; 
3237     else if (event
.RightDown()) 
3239         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, 
3240                     event
.GetPosition() ); 
3242     else if (event
.MiddleDown()) 
3244         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
3246     else if ( event
.LeftDown() || forceClick 
) 
3248         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3249         m_lineLastClicked 
= current
; 
3251         size_t oldCurrent 
= m_current
; 
3253         if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) ) 
3255             HighlightAll( FALSE 
); 
3257             ChangeCurrent(current
); 
3259             ReverseHighlight(m_current
); 
3261         else // multi sel & either ctrl or shift is down 
3263             if (event
.ControlDown()) 
3265                 ChangeCurrent(current
); 
3267                 ReverseHighlight(m_current
); 
3269             else if (event
.ShiftDown()) 
3271                 ChangeCurrent(current
); 
3273                 size_t lineFrom 
= oldCurrent
, 
3276                 if ( lineTo 
< lineFrom 
) 
3279                     lineFrom 
= m_current
; 
3282                 HighlightLines(lineFrom
, lineTo
); 
3284             else // !ctrl, !shift 
3286                 // test in the enclosing if should make it impossible 
3287                 wxFAIL_MSG( _T("how did we get here?") ); 
3291         if (m_current 
!= oldCurrent
) 
3293             RefreshLine( oldCurrent 
); 
3296         // forceClick is only set if the previous click was on another item 
3297         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
); 
3301 void wxListMainWindow::MoveToItem(size_t item
) 
3303     if ( item 
== (size_t)-1 ) 
3306     wxRect rect 
= GetLineRect(item
); 
3308     int client_w
, client_h
; 
3309     GetClientSize( &client_w
, &client_h 
); 
3311     int view_x 
= m_xScroll
*GetScrollPos( wxHORIZONTAL 
); 
3312     int view_y 
= m_yScroll
*GetScrollPos( wxVERTICAL 
); 
3314     if ( HasFlag(wxLC_REPORT
) ) 
3316         // the next we need the range of lines shown it might be different, so 
3318         ResetVisibleLinesRange(); 
3320         if (rect
.y 
< view_y 
) 
3321             Scroll( -1, rect
.y
/m_yScroll 
); 
3322         if (rect
.y
+rect
.height
+5 > view_y
+client_h
) 
3323             Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll 
); 
3327         if (rect
.x
-view_x 
< 5) 
3328             Scroll( (rect
.x
-5)/m_xScroll
, -1 ); 
3329         if (rect
.x
+rect
.width
-5 > view_x
+client_w
) 
3330             Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 ); 
3334 // ---------------------------------------------------------------------------- 
3335 // keyboard handling 
3336 // ---------------------------------------------------------------------------- 
3338 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
3340     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
3341                  _T("invalid item index in OnArrowChar()") ); 
3343     size_t oldCurrent 
= m_current
; 
3345     // in single selection we just ignore Shift as we can't select several 
3347     if ( event
.ShiftDown() && !IsSingleSel() ) 
3349         ChangeCurrent(newCurrent
); 
3351         // select all the items between the old and the new one 
3352         if ( oldCurrent 
> newCurrent 
) 
3354             newCurrent 
= oldCurrent
; 
3355             oldCurrent 
= m_current
; 
3358         HighlightLines(oldCurrent
, newCurrent
); 
3362         // all previously selected items are unselected unless ctrl is held 
3363         if ( !event
.ControlDown() ) 
3364             HighlightAll(FALSE
); 
3366         ChangeCurrent(newCurrent
); 
3368         // refresh the old focus to remove it 
3369         RefreshLine( oldCurrent 
); 
3371         if ( !event
.ControlDown() ) 
3373             HighlightLine( m_current
, TRUE 
); 
3377     RefreshLine( m_current 
); 
3382 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
3384     wxWindow 
*parent 
= GetParent(); 
3386     /* we propagate the key event up */ 
3387     wxKeyEvent 
ke( wxEVT_KEY_DOWN 
); 
3388     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3389     ke
.m_controlDown 
= event
.m_controlDown
; 
3390     ke
.m_altDown 
= event
.m_altDown
; 
3391     ke
.m_metaDown 
= event
.m_metaDown
; 
3392     ke
.m_keyCode 
= event
.m_keyCode
; 
3395     ke
.SetEventObject( parent 
); 
3396     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3401 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
3403     wxWindow 
*parent 
= GetParent(); 
3405     /* we send a list_key event up */ 
3408         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
3409         le
.m_itemIndex 
= m_current
; 
3410         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3411         le
.m_code 
= event
.GetKeyCode(); 
3412         le
.SetEventObject( parent 
); 
3413         parent
->GetEventHandler()->ProcessEvent( le 
); 
3416     /* we propagate the char event up */ 
3417     wxKeyEvent 
ke( wxEVT_CHAR 
); 
3418     ke
.m_shiftDown 
= event
.m_shiftDown
; 
3419     ke
.m_controlDown 
= event
.m_controlDown
; 
3420     ke
.m_altDown 
= event
.m_altDown
; 
3421     ke
.m_metaDown 
= event
.m_metaDown
; 
3422     ke
.m_keyCode 
= event
.m_keyCode
; 
3425     ke
.SetEventObject( parent 
); 
3426     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
3428     if (event
.GetKeyCode() == WXK_TAB
) 
3430         wxNavigationKeyEvent nevent
; 
3431         nevent
.SetWindowChange( event
.ControlDown() ); 
3432         nevent
.SetDirection( !event
.ShiftDown() ); 
3433         nevent
.SetEventObject( GetParent()->GetParent() ); 
3434         nevent
.SetCurrentFocus( m_parent 
); 
3435         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent 
)) 
3439     /* no item -> nothing to do */ 
3446     switch (event
.GetKeyCode()) 
3449             if ( m_current 
> 0 ) 
3450                 OnArrowChar( m_current 
- 1, event 
); 
3454             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
3455                 OnArrowChar( m_current 
+ 1, event 
); 
3460                 OnArrowChar( GetItemCount() - 1, event 
); 
3465                 OnArrowChar( 0, event 
); 
3471                 if ( HasFlag(wxLC_REPORT
) ) 
3473                     steps 
= m_linesPerPage 
- 1; 
3477                     steps 
= m_current 
% m_linesPerPage
; 
3480                 int index 
= m_current 
- steps
; 
3484                 OnArrowChar( index
, event 
); 
3491                 if ( HasFlag(wxLC_REPORT
) ) 
3493                     steps 
= m_linesPerPage 
- 1; 
3497                     steps 
= m_linesPerPage 
- (m_current 
% m_linesPerPage
) - 1; 
3500                 size_t index 
= m_current 
+ steps
; 
3501                 size_t count 
= GetItemCount(); 
3502                 if ( index 
>= count 
) 
3505                 OnArrowChar( index
, event 
); 
3510             if ( !HasFlag(wxLC_REPORT
) ) 
3512                 int index 
= m_current 
- m_linesPerPage
; 
3516                 OnArrowChar( index
, event 
); 
3521             if ( !HasFlag(wxLC_REPORT
) ) 
3523                 size_t index 
= m_current 
+ m_linesPerPage
; 
3525                 size_t count 
= GetItemCount(); 
3526                 if ( index 
>= count 
) 
3529                 OnArrowChar( index
, event 
); 
3534             if ( IsSingleSel() ) 
3536                 SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3538                 if ( IsHighlighted(m_current
) ) 
3540                     // don't unselect the item in single selection mode 
3543                 //else: select it in ReverseHighlight() below if unselected 
3546             ReverseHighlight(m_current
); 
3551             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
3559 // ---------------------------------------------------------------------------- 
3561 // ---------------------------------------------------------------------------- 
3563 void wxListMainWindow::SetFocus() 
3565     // VS: wxListMainWindow derives from wxPanel (via wxScrolledWindow) and wxPanel 
3566     //     overrides SetFocus in such way that it does never change focus from 
3567     //     panel's child to the panel itself. Unfortunately, we must be able to change 
3568     //     focus to the panel from wxListTextCtrl because the text control should 
3569     //     disappear when the user clicks outside it. 
3571     wxWindow 
*oldFocus 
= FindFocus(); 
3573     if ( oldFocus 
&& oldFocus
->GetParent() == this ) 
3575         wxWindow::SetFocus(); 
3579         wxScrolledWindow::SetFocus(); 
3583 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3585     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
3586     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
3587     // which are already drawn correctly resulting in horrible flicker - avoid 
3599     wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3600     event
.SetEventObject( GetParent() ); 
3601     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
3604 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3611 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3613     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3615         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3617     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3619         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3621     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3623         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3625     else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
)) 
3627         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3631 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3633     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3635         m_normal_image_list
->GetSize( index
, width
, height 
); 
3637     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3639         m_small_image_list
->GetSize( index
, width
, height 
); 
3641     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3643         m_small_image_list
->GetSize( index
, width
, height 
); 
3645     else if ( HasFlag(wxLC_REPORT
) && m_small_image_list 
) 
3647         m_small_image_list
->GetSize( index
, width
, height 
); 
3656 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3658     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3659     dc
.SetFont( GetFont() ); 
3662     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3664     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3667 void wxListMainWindow::SetImageList( wxImageListType 
*imageList
, int which 
) 
3671     // calc the spacing from the icon size 
3674     if ((imageList
) && (imageList
->GetImageCount()) ) 
3676         imageList
->GetSize(0, width
, height
); 
3679     if (which 
== wxIMAGE_LIST_NORMAL
) 
3681         m_normal_image_list 
= imageList
; 
3682         m_normal_spacing 
= width 
+ 8; 
3685     if (which 
== wxIMAGE_LIST_SMALL
) 
3687         m_small_image_list 
= imageList
; 
3688         m_small_spacing 
= width 
+ 14; 
3692 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3697         m_small_spacing 
= spacing
; 
3701         m_normal_spacing 
= spacing
; 
3705 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3707     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3710 // ---------------------------------------------------------------------------- 
3712 // ---------------------------------------------------------------------------- 
3714 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3716     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3718     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3720     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3721         item
.m_width 
= GetTextLength( item
.m_text 
); 
3723     wxListHeaderData 
*column 
= node
->GetData(); 
3724     column
->SetItem( item 
); 
3726     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3728         headerWin
->m_dirty 
= TRUE
; 
3732     // invalidate it as it has to be recalculated 
3736 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3738     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3739                  _T("invalid column index") ); 
3741     wxCHECK_RET( HasFlag(wxLC_REPORT
), 
3742                  _T("SetColumnWidth() can only be called in report mode.") ); 
3745     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3747         headerWin
->m_dirty 
= TRUE
; 
3749     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3750     wxCHECK_RET( node
, _T("no column?") ); 
3752     wxListHeaderData 
*column 
= node
->GetData(); 
3754     size_t count 
= GetItemCount(); 
3756     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3758         width 
= GetTextLength(column
->GetText()); 
3760     else if ( width 
== wxLIST_AUTOSIZE 
) 
3764             // TODO: determine the max width somehow... 
3765             width 
= WIDTH_COL_DEFAULT
; 
3769             wxClientDC 
dc(this); 
3770             dc
.SetFont( GetFont() ); 
3772             int max 
= AUTOSIZE_COL_MARGIN
; 
3774             for ( size_t i 
= 0; i 
< count
; i
++ ) 
3776                 wxListLineData 
*line 
= GetLine(i
); 
3777                 wxListItemDataList::Node 
*n 
= line
->m_items
.Item( col 
); 
3779                 wxCHECK_RET( n
, _T("no subitem?") ); 
3781                 wxListItemData 
*item 
= n
->GetData(); 
3784                 if (item
->HasImage()) 
3787                     GetImageSize( item
->GetImage(), ix
, iy 
); 
3791                 if (item
->HasText()) 
3794                     dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
3802             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3806     column
->SetWidth( width 
); 
3808     // invalidate it as it has to be recalculated 
3812 int wxListMainWindow::GetHeaderWidth() const 
3814     if ( !m_headerWidth 
) 
3816         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3818         size_t count 
= GetColumnCount(); 
3819         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3821             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3825     return m_headerWidth
; 
3828 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3830     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3831     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3833     wxListHeaderData 
*column 
= node
->GetData(); 
3834     column
->GetItem( item 
); 
3837 int wxListMainWindow::GetColumnWidth( int col 
) const 
3839     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3840     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3842     wxListHeaderData 
*column 
= node
->GetData(); 
3843     return column
->GetWidth(); 
3846 // ---------------------------------------------------------------------------- 
3848 // ---------------------------------------------------------------------------- 
3850 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3852     long id 
= item
.m_itemId
; 
3853     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3854                  _T("invalid item index in SetItem") ); 
3858         wxListLineData 
*line 
= GetLine((size_t)id
); 
3859         line
->SetItem( item
.m_col
, item 
); 
3862     // update the item on screen 
3864     GetItemRect(id
, rectItem
); 
3865     RefreshRect(rectItem
); 
3868 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3870      wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3871                   _T("invalid list ctrl item index in SetItem") ); 
3873     size_t oldCurrent 
= m_current
; 
3874     size_t item 
= (size_t)litem
;    // safe because of the check above 
3876     // do we need to change the focus? 
3877     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3879         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3881             // don't do anything if this item is already focused 
3882             if ( item 
!= m_current 
) 
3884                 ChangeCurrent(item
); 
3886                 if ( oldCurrent 
!= (size_t)-1 ) 
3888                     if ( IsSingleSel() ) 
3890                         HighlightLine(oldCurrent
, FALSE
); 
3893                     RefreshLine(oldCurrent
); 
3896                 RefreshLine( m_current 
); 
3901             // don't do anything if this item is not focused 
3902             if ( item 
== m_current 
) 
3906                 if ( IsSingleSel() ) 
3908                     // we must unselect the old current item as well or we 
3909                     // might end up with more than one selected item in a 
3910                     // single selection control 
3911                     HighlightLine(oldCurrent
, FALSE
); 
3914                 RefreshLine( oldCurrent 
); 
3919     // do we need to change the selection state? 
3920     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3922         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3924         if ( IsSingleSel() ) 
3928                 // selecting the item also makes it the focused one in the 
3930                 if ( m_current 
!= item 
) 
3932                     ChangeCurrent(item
); 
3934                     if ( oldCurrent 
!= (size_t)-1 ) 
3936                         HighlightLine( oldCurrent
, FALSE 
); 
3937                         RefreshLine( oldCurrent 
); 
3943                 // only the current item may be selected anyhow 
3944                 if ( item 
!= m_current 
) 
3949         if ( HighlightLine(item
, on
) ) 
3956 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
3958     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3959                  _T("invalid list ctrl item index in GetItemState()") ); 
3961     int ret 
= wxLIST_STATE_DONTCARE
; 
3963     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3965         if ( (size_t)item 
== m_current 
) 
3966             ret 
|= wxLIST_STATE_FOCUSED
; 
3969     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3971         if ( IsHighlighted(item
) ) 
3972             ret 
|= wxLIST_STATE_SELECTED
; 
3978 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
3980     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3981                  _T("invalid item index in GetItem") ); 
3983     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3984     line
->GetItem( item
.m_col
, item 
); 
3987 // ---------------------------------------------------------------------------- 
3989 // ---------------------------------------------------------------------------- 
3991 size_t wxListMainWindow::GetItemCount() const 
3993     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3996 void wxListMainWindow::SetItemCount(long count
) 
3998     m_selStore
.SetItemCount(count
); 
3999     m_countVirt 
= count
; 
4001     ResetVisibleLinesRange(); 
4003     // scrollbars must be reset 
4007 int wxListMainWindow::GetSelectedItemCount() const 
4009     // deal with the quick case first 
4010     if ( IsSingleSel() ) 
4012         return HasCurrent() ? IsHighlighted(m_current
) : FALSE
; 
4015     // virtual controls remmebers all its selections itself 
4017         return m_selStore
.GetSelectedCount(); 
4019     // TODO: we probably should maintain the number of items selected even for 
4020     //       non virtual controls as enumerating all lines is really slow... 
4021     size_t countSel 
= 0; 
4022     size_t count 
= GetItemCount(); 
4023     for ( size_t line 
= 0; line 
< count
; line
++ ) 
4025         if ( GetLine(line
)->IsHighlighted() ) 
4032 // ---------------------------------------------------------------------------- 
4033 // item position/size 
4034 // ---------------------------------------------------------------------------- 
4036 void wxListMainWindow::GetItemRect( long index
, wxRect 
&rect 
) const 
4038     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4039                  _T("invalid index in GetItemRect") ); 
4041     rect 
= GetLineRect((size_t)index
); 
4043     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
4046 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
4049     GetItemRect(item
, rect
); 
4057 // ---------------------------------------------------------------------------- 
4058 // geometry calculation 
4059 // ---------------------------------------------------------------------------- 
4061 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
4063     wxClientDC 
dc( this ); 
4064     dc
.SetFont( GetFont() ); 
4067     if ( HasFlag(wxLC_ICON
) ) 
4068         iconSpacing 
= m_normal_spacing
; 
4069     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
4070         iconSpacing 
= m_small_spacing
; 
4074     // Note that we do not call GetClientSize() here but 
4075     // GetSize() and substract the border size for sunken 
4076     // borders manually. This is technically incorrect, 
4077     // but we need to know the client area's size WITHOUT 
4078     // scrollbars here. Since we don't know if there are 
4079     // any scrollbars, we use GetSize() instead. Another 
4080     // solution would be to call SetScrollbars() here to 
4081     // remove the scrollbars and call GetClientSize() then, 
4082     // but this might result in flicker and - worse - will 
4083     // reset the scrollbars to 0 which is not good at all 
4084     // if you resize a dialog/window, but don't want to 
4085     // reset the window scrolling. RR. 
4086     // Furthermore, we actually do NOT subtract the border 
4087     // width as 2 pixels is just the extra space which we 
4088     // need around the actual content in the window. Other- 
4089     // wise the text would e.g. touch the upper border. RR. 
4092     GetSize( &clientWidth
, &clientHeight 
); 
4094     if ( HasFlag(wxLC_REPORT
) ) 
4096         // all lines have the same height 
4097         int lineHeight 
= GetLineHeight(); 
4099         // scroll one line per step 
4100         m_yScroll 
= lineHeight
; 
4102         size_t lineCount 
= GetItemCount(); 
4103         int entireHeight 
= lineCount
*lineHeight 
+ LINE_SPACING
; 
4105         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
4107         ResetVisibleLinesRange(); 
4109         SetScrollbars( m_xScroll
, m_yScroll
, 
4110                        GetHeaderWidth() / m_xScroll
, 
4111                        (entireHeight 
+ m_yScroll 
- 1)/m_yScroll
, 
4112                        GetScrollPos(wxHORIZONTAL
), 
4113                        GetScrollPos(wxVERTICAL
), 
4118         // at first we try without any scrollbar. if the items don't 
4119         // fit into the window, we recalculate after subtracting an 
4120         // approximated 15 pt for the horizontal scrollbar 
4122         int entireWidth 
= 0; 
4124         for (int tries 
= 0; tries 
< 2; tries
++) 
4126             // We start with 4 for the border around all items 
4131                 // Now we have decided that the items do not fit into the 
4132                 // client area. Unfortunately, wxWindows sometimes thinks 
4133                 // that it does fit and therefore NO horizontal scrollbar 
4134                 // is inserted. This looks ugly, so we fudge here and make 
4135                 // the calculated width bigger than was actually has been 
4136                 // calculated. This ensures that wxScrolledWindows puts 
4137                 // a scrollbar at the bottom of its client area. 
4138                 entireWidth 
+= SCROLL_UNIT_X
; 
4141             // Start at 2,2 so the text does not touch the border 
4146             int currentlyVisibleLines 
= 0; 
4148             size_t count 
= GetItemCount(); 
4149             for (size_t i 
= 0; i 
< count
; i
++) 
4151                 currentlyVisibleLines
++; 
4152                 wxListLineData 
*line 
= GetLine(i
); 
4153                 line
->CalculateSize( &dc
, iconSpacing 
); 
4154                 line
->SetPosition( x
, y
, clientWidth
, iconSpacing 
);  // Why clientWidth? (FIXME) 
4156                 wxSize sizeLine 
= GetLineSize(i
); 
4158                 if ( maxWidth 
< sizeLine
.x 
) 
4159                     maxWidth 
= sizeLine
.x
; 
4162                 if (currentlyVisibleLines 
> m_linesPerPage
) 
4163                     m_linesPerPage 
= currentlyVisibleLines
; 
4165                 // Assume that the size of the next one is the same... (FIXME) 
4166                 if ( y 
+ sizeLine
.y 
>= clientHeight 
) 
4168                     currentlyVisibleLines 
= 0; 
4171                     entireWidth 
+= maxWidth
+6; 
4175                 // We have reached the last item. 
4176                 if ( i 
== count 
- 1 ) 
4177                     entireWidth 
+= maxWidth
; 
4179                 if ( (tries 
== 0) && (entireWidth
+SCROLL_UNIT_X 
> clientWidth
) ) 
4181                     clientHeight 
-= 15; // We guess the scrollbar height. (FIXME) 
4183                     currentlyVisibleLines 
= 0; 
4187                 if ( i 
== count 
- 1 ) 
4188                     tries 
= 1;  // Everything fits, no second try required. 
4192         int scroll_pos 
= GetScrollPos( wxHORIZONTAL 
); 
4193         SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE 
); 
4198         // FIXME: why should we call it from here? 
4205 void wxListMainWindow::RefreshAll() 
4210     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
4211     if ( headerWin 
&& headerWin
->m_dirty 
) 
4213         headerWin
->m_dirty 
= FALSE
; 
4214         headerWin
->Refresh(); 
4218 void wxListMainWindow::UpdateCurrent() 
4220     if ( !HasCurrent() && !IsEmpty() ) 
4226 long wxListMainWindow::GetNextItem( long item
, 
4227                                     int WXUNUSED(geometry
), 
4231          max 
= GetItemCount(); 
4232     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
4233                  _T("invalid listctrl index in GetNextItem()") ); 
4235     // notice that we start with the next item (or the first one if item == -1) 
4236     // and this is intentional to allow writing a simple loop to iterate over 
4237     // all selected items 
4241         // this is not an error because the index was ok initially, just no 
4252     size_t count 
= GetItemCount(); 
4253     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
4255         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
4258         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
4265 // ---------------------------------------------------------------------------- 
4267 // ---------------------------------------------------------------------------- 
4269 void wxListMainWindow::DeleteItem( long lindex 
) 
4271     size_t count 
= GetItemCount(); 
4273     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
4274                  _T("invalid item index in DeleteItem") ); 
4276     size_t index 
= (size_t)lindex
; 
4278     // we don't need to adjust the index for the previous items 
4279     if ( HasCurrent() && m_current 
>= index 
) 
4281         // if the current item is being deleted, we want the next one to 
4282         // become selected - unless there is no next one - so don't adjust 
4283         // m_current in this case 
4284         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
4290     if ( InReportView() ) 
4292         ResetVisibleLinesRange(); 
4299         m_selStore
.OnItemDelete(index
); 
4303         m_lines
.RemoveAt( index 
); 
4306     // we need to refresh the (vert) scrollbar as the number of items changed 
4309     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM 
); 
4311     RefreshAfter(index
); 
4314 void wxListMainWindow::DeleteColumn( int col 
) 
4316     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
4318     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
4321     m_columns
.DeleteNode( node 
); 
4323     // invalidate it as it has to be recalculated 
4327 void wxListMainWindow::DoDeleteAllItems() 
4331         // nothing to do - in particular, don't send the event 
4337     // to make the deletion of all items faster, we don't send the 
4338     // notifications for each item deletion in this case but only one event 
4339     // for all of them: this is compatible with wxMSW and documented in 
4340     // DeleteAllItems() description 
4342     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
4343     event
.SetEventObject( GetParent() ); 
4344     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
4353     if ( InReportView() ) 
4355         ResetVisibleLinesRange(); 
4361 void wxListMainWindow::DeleteAllItems() 
4365     RecalculatePositions(); 
4368 void wxListMainWindow::DeleteEverything() 
4375 // ---------------------------------------------------------------------------- 
4376 // scanning for an item 
4377 // ---------------------------------------------------------------------------- 
4379 void wxListMainWindow::EnsureVisible( long index 
) 
4381     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
4382                  _T("invalid index in EnsureVisible") ); 
4384     // We have to call this here because the label in question might just have 
4385     // been added and its position is not known yet 
4388         RecalculatePositions(TRUE 
/* no refresh */); 
4391     MoveToItem((size_t)index
); 
4394 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) ) 
4401     size_t count 
= GetItemCount(); 
4402     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
4404         wxListLineData 
*line 
= GetLine(i
); 
4405         if ( line
->GetText(0) == tmp 
) 
4412 long wxListMainWindow::FindItem(long start
, long data
) 
4418     size_t count 
= GetItemCount(); 
4419     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4421         wxListLineData 
*line 
= GetLine(i
); 
4423         line
->GetItem( 0, item 
); 
4424         if (item
.m_data 
== data
) 
4431 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) 
4433     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4435     size_t count 
= GetItemCount(); 
4437     if ( HasFlag(wxLC_REPORT
) ) 
4439         size_t current 
= y 
/ GetLineHeight(); 
4440         if ( current 
< count 
) 
4442             flags 
= HitTestLine(current
, x
, y
); 
4449         // TODO: optimize it too! this is less simple than for report view but 
4450         //       enumerating all items is still not a way to do it!! 
4451         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4453             flags 
= HitTestLine(current
, x
, y
); 
4462 // ---------------------------------------------------------------------------- 
4464 // ---------------------------------------------------------------------------- 
4466 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4468     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
4470     size_t count 
= GetItemCount(); 
4471     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
<= count
, 
4472                  _T("invalid item index") ); 
4474     size_t id 
= item
.m_itemId
; 
4479     if ( HasFlag(wxLC_REPORT
) ) 
4482         ResetVisibleLinesRange(); 
4484     else if ( HasFlag(wxLC_LIST
) ) 
4486     else if ( HasFlag(wxLC_ICON
) ) 
4488     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
4489         mode 
= wxLC_ICON
;  // no typo 
4492         wxFAIL_MSG( _T("unknown mode") ); 
4495     wxListLineData 
*line 
= new wxListLineData(this); 
4497     line
->SetItem( 0, item 
); 
4499     m_lines
.Insert( line
, id 
); 
4502     RefreshLines(id
, GetItemCount() - 1); 
4505 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4508     if ( HasFlag(wxLC_REPORT
) ) 
4510         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4511             item
.m_width 
= GetTextLength( item
.m_text 
); 
4512         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4513         if ((col 
>= 0) && (col 
< (int)m_columns
.GetCount())) 
4515             wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
4516             m_columns
.Insert( node
, column 
); 
4520             m_columns
.Append( column 
); 
4523         // invalidate it as it has to be recalculated 
4528 // ---------------------------------------------------------------------------- 
4530 // ---------------------------------------------------------------------------- 
4532 wxListCtrlCompare list_ctrl_compare_func_2
; 
4533 long              list_ctrl_compare_data
; 
4535 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4537     wxListLineData 
*line1 
= *arg1
; 
4538     wxListLineData 
*line2 
= *arg2
; 
4540     line1
->GetItem( 0, item 
); 
4541     long data1 
= item
.m_data
; 
4542     line2
->GetItem( 0, item 
); 
4543     long data2 
= item
.m_data
; 
4544     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4547 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
4549     list_ctrl_compare_func_2 
= fn
; 
4550     list_ctrl_compare_data 
= data
; 
4551     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4555 // ---------------------------------------------------------------------------- 
4557 // ---------------------------------------------------------------------------- 
4559 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4561     // update our idea of which lines are shown when we redraw the window the 
4563     ResetVisibleLinesRange(); 
4566 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
4567     wxScrolledWindow::OnScroll(event
); 
4569     HandleOnScroll( event 
); 
4572     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4574         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4575         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4577         lc
->m_headerWin
->Refresh(); 
4578         lc
->m_headerWin
->Update(); 
4582 int wxListMainWindow::GetCountPerPage() const 
4584     if ( !m_linesPerPage 
) 
4586         wxConstCast(this, wxListMainWindow
)-> 
4587             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4590     return m_linesPerPage
; 
4593 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4595     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") ); 
4597     if ( m_lineFrom 
== (size_t)-1 ) 
4599         size_t count 
= GetItemCount(); 
4602             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4604             // this may happen if SetScrollbars() hadn't been called yet 
4605             if ( m_lineFrom 
>= count 
) 
4606                 m_lineFrom 
= count 
- 1; 
4608             // we redraw one extra line but this is needed to make the redrawing 
4609             // logic work when there is a fractional number of lines on screen 
4610             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4611             if ( m_lineTo 
>= count 
) 
4612                 m_lineTo 
= count 
- 1; 
4614         else // empty control 
4617             m_lineTo 
= (size_t)-1; 
4621     wxASSERT_MSG( IsEmpty() || 
4622                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4623                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4631 // ------------------------------------------------------------------------------------- 
4632 // wxGenericListCtrl 
4633 // ------------------------------------------------------------------------------------- 
4635 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4637 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4638   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4639   EVT_IDLE(wxGenericListCtrl::OnIdle
) 
4642 wxGenericListCtrl::wxGenericListCtrl() 
4644     m_imageListNormal 
= (wxImageListType 
*) NULL
; 
4645     m_imageListSmall 
= (wxImageListType 
*) NULL
; 
4646     m_imageListState 
= (wxImageListType 
*) NULL
; 
4648     m_ownsImageListNormal 
= 
4649     m_ownsImageListSmall 
= 
4650     m_ownsImageListState 
= FALSE
; 
4652     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4653     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4656 wxGenericListCtrl::~wxGenericListCtrl() 
4658     if (m_ownsImageListNormal
) 
4659         delete m_imageListNormal
; 
4660     if (m_ownsImageListSmall
) 
4661         delete m_imageListSmall
; 
4662     if (m_ownsImageListState
) 
4663         delete m_imageListState
; 
4666 void wxGenericListCtrl::CreateHeaderWindow() 
4668     m_headerWin 
= new wxListHeaderWindow
 
4670                         this, -1, m_mainWin
, 
4672                         wxSize(GetClientSize().x
, HEADER_HEIGHT
), 
4677 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
4682                         const wxValidator 
&validator
, 
4683                         const wxString 
&name
) 
4687     m_imageListState 
= (wxImageListType 
*) NULL
; 
4688     m_ownsImageListNormal 
= 
4689     m_ownsImageListSmall 
= 
4690     m_ownsImageListState 
= FALSE
; 
4692     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4693     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4695     if ( !(style 
& wxLC_MASK_TYPE
) ) 
4697         style 
= style 
| wxLC_LIST
; 
4700     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
4703     // don't create the inner window with the border 
4704     style 
&= ~wxSUNKEN_BORDER
; 
4706     m_mainWin 
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style 
); 
4708     if ( HasFlag(wxLC_REPORT
) ) 
4710         CreateHeaderWindow(); 
4712         if ( HasFlag(wxLC_NO_HEADER
) ) 
4714             // VZ: why do we create it at all then? 
4715             m_headerWin
->Show( FALSE 
); 
4722 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
4724     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4725                   _T("wxLC_VIRTUAL can't be [un]set") ); 
4727     long flag 
= GetWindowStyle(); 
4731         if (style 
& wxLC_MASK_TYPE
) 
4732             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4733         if (style 
& wxLC_MASK_ALIGN
) 
4734             flag 
&= ~wxLC_MASK_ALIGN
; 
4735         if (style 
& wxLC_MASK_SORT
) 
4736             flag 
&= ~wxLC_MASK_SORT
; 
4748     SetWindowStyleFlag( flag 
); 
4751 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
4755         m_mainWin
->DeleteEverything(); 
4757         // has the header visibility changed? 
4758         bool hasHeader 
= HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
), 
4759              willHaveHeader 
= (flag 
& wxLC_REPORT
) && !(flag 
& wxLC_NO_HEADER
); 
4761         if ( hasHeader 
!= willHaveHeader 
) 
4768                     // don't delete, just hide, as we can reuse it later 
4769                     m_headerWin
->Show(FALSE
); 
4771                 //else: nothing to do 
4773             else // must show header 
4777                     CreateHeaderWindow(); 
4779                 else // already have it, just show 
4781                     m_headerWin
->Show( TRUE 
); 
4785             ResizeReportView(willHaveHeader
); 
4789     wxWindow::SetWindowStyleFlag( flag 
); 
4792 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4794     m_mainWin
->GetColumn( col
, item 
); 
4798 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
4800     m_mainWin
->SetColumn( col
, item 
); 
4804 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
4806     return m_mainWin
->GetColumnWidth( col 
); 
4809 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
4811     m_mainWin
->SetColumnWidth( col
, width 
); 
4815 int wxGenericListCtrl::GetCountPerPage() const 
4817   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4820 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
4822     m_mainWin
->GetItem( info 
); 
4826 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
4828     m_mainWin
->SetItem( info 
); 
4832 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4835     info
.m_text 
= label
; 
4836     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4837     info
.m_itemId 
= index
; 
4841         info
.m_image 
= imageId
; 
4842         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4844     m_mainWin
->SetItem(info
); 
4848 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
4850     return m_mainWin
->GetItemState( item
, stateMask 
); 
4853 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4855     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4859 bool wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4862     info
.m_image 
= image
; 
4863     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4864     info
.m_itemId 
= item
; 
4865     m_mainWin
->SetItem( info 
); 
4869 wxString 
wxGenericListCtrl::GetItemText( long item 
) const 
4871     return m_mainWin
->GetItemText(item
); 
4874 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
4876     m_mainWin
->SetItemText(item
, str
); 
4879 long wxGenericListCtrl::GetItemData( long item 
) const 
4882     info
.m_itemId 
= item
; 
4883     m_mainWin
->GetItem( info 
); 
4887 bool wxGenericListCtrl::SetItemData( long item
, long data 
) 
4890     info
.m_mask 
= wxLIST_MASK_DATA
; 
4891     info
.m_itemId 
= item
; 
4893     m_mainWin
->SetItem( info 
); 
4897 bool wxGenericListCtrl::GetItemRect( long item
, wxRect 
&rect
,  int WXUNUSED(code
) ) const 
4899     m_mainWin
->GetItemRect( item
, rect 
); 
4903 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4905     m_mainWin
->GetItemPosition( item
, pos 
); 
4909 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4914 int wxGenericListCtrl::GetItemCount() const 
4916     return m_mainWin
->GetItemCount(); 
4919 int wxGenericListCtrl::GetColumnCount() const 
4921     return m_mainWin
->GetColumnCount(); 
4924 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4926     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4929 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
4931     return m_mainWin
->GetItemSpacing( isSmall 
); 
4934 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
4937     info
.m_itemId 
= item
; 
4938     info
.SetTextColour( col 
); 
4939     m_mainWin
->SetItem( info 
); 
4942 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
4945     info
.m_itemId 
= item
; 
4946     m_mainWin
->GetItem( info 
); 
4947     return info
.GetTextColour(); 
4950 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
4953     info
.m_itemId 
= item
; 
4954     info
.SetBackgroundColour( col 
); 
4955     m_mainWin
->SetItem( info 
); 
4958 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
4961     info
.m_itemId 
= item
; 
4962     m_mainWin
->GetItem( info 
); 
4963     return info
.GetBackgroundColour(); 
4966 int wxGenericListCtrl::GetSelectedItemCount() const 
4968     return m_mainWin
->GetSelectedItemCount(); 
4971 wxColour 
wxGenericListCtrl::GetTextColour() const 
4973     return GetForegroundColour(); 
4976 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
4978     SetForegroundColour(col
); 
4981 long wxGenericListCtrl::GetTopItem() const 
4984     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
4988 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
4990     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
4993 wxImageListType 
*wxGenericListCtrl::GetImageList(int which
) const 
4995     if (which 
== wxIMAGE_LIST_NORMAL
) 
4997         return m_imageListNormal
; 
4999     else if (which 
== wxIMAGE_LIST_SMALL
) 
5001         return m_imageListSmall
; 
5003     else if (which 
== wxIMAGE_LIST_STATE
) 
5005         return m_imageListState
; 
5007     return (wxImageListType 
*) NULL
; 
5010 void wxGenericListCtrl::SetImageList( wxImageListType 
*imageList
, int which 
) 
5012     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5014         if (m_ownsImageListNormal
) delete m_imageListNormal
; 
5015         m_imageListNormal 
= imageList
; 
5016         m_ownsImageListNormal 
= FALSE
; 
5018     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5020         if (m_ownsImageListSmall
) delete m_imageListSmall
; 
5021         m_imageListSmall 
= imageList
; 
5022         m_ownsImageListSmall 
= FALSE
; 
5024     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5026         if (m_ownsImageListState
) delete m_imageListState
; 
5027         m_imageListState 
= imageList
; 
5028         m_ownsImageListState 
= FALSE
; 
5031     m_mainWin
->SetImageList( imageList
, which 
); 
5034 void wxGenericListCtrl::AssignImageList(wxImageListType 
*imageList
, int which
) 
5036     SetImageList(imageList
, which
); 
5037     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
5038         m_ownsImageListNormal 
= TRUE
; 
5039     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
5040         m_ownsImageListSmall 
= TRUE
; 
5041     else if ( which 
== wxIMAGE_LIST_STATE 
) 
5042         m_ownsImageListState 
= TRUE
; 
5045 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
5050 bool wxGenericListCtrl::DeleteItem( long item 
) 
5052     m_mainWin
->DeleteItem( item 
); 
5056 bool wxGenericListCtrl::DeleteAllItems() 
5058     m_mainWin
->DeleteAllItems(); 
5062 bool wxGenericListCtrl::DeleteAllColumns() 
5064     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
5065     for ( size_t n 
= 0; n 
< count
; n
++ ) 
5071 void wxGenericListCtrl::ClearAll() 
5073     m_mainWin
->DeleteEverything(); 
5076 bool wxGenericListCtrl::DeleteColumn( int col 
) 
5078     m_mainWin
->DeleteColumn( col 
); 
5080     // if we don't have the header any longer, we need to relayout the window 
5081     if ( !GetColumnCount() ) 
5083         ResizeReportView(FALSE 
/* no header */); 
5089 void wxGenericListCtrl::Edit( long item 
) 
5091     m_mainWin
->EditLabel( item 
); 
5094 bool wxGenericListCtrl::EnsureVisible( long item 
) 
5096     m_mainWin
->EnsureVisible( item 
); 
5100 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
,  bool partial 
) 
5102     return m_mainWin
->FindItem( start
, str
, partial 
); 
5105 long wxGenericListCtrl::FindItem( long start
, long data 
) 
5107     return m_mainWin
->FindItem( start
, data 
); 
5110 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
), 
5111                            int WXUNUSED(direction
)) 
5116 long wxGenericListCtrl::HitTest( const wxPoint 
&point
, int &flags 
) 
5118     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
5121 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
5123     m_mainWin
->InsertItem( info 
); 
5124     return info
.m_itemId
; 
5127 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
5130     info
.m_text 
= label
; 
5131     info
.m_mask 
= wxLIST_MASK_TEXT
; 
5132     info
.m_itemId 
= index
; 
5133     return InsertItem( info 
); 
5136 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
5139     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
5140     info
.m_image 
= imageIndex
; 
5141     info
.m_itemId 
= index
; 
5142     return InsertItem( info 
); 
5145 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
5148     info
.m_text 
= label
; 
5149     info
.m_image 
= imageIndex
; 
5150     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
5151     info
.m_itemId 
= index
; 
5152     return InsertItem( info 
); 
5155 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
5157     wxCHECK_MSG( m_headerWin
, -1, _T("can't add column in non report mode") ); 
5159     m_mainWin
->InsertColumn( col
, item 
); 
5161     // if we hadn't had header before and have it now we need to relayout the 
5163     if ( GetColumnCount() == 1 ) 
5165         ResizeReportView(TRUE 
/* have header */); 
5168     m_headerWin
->Refresh(); 
5173 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
5174                                int format
, int width 
) 
5177     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
5178     item
.m_text 
= heading
; 
5181         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
5182         item
.m_width 
= width
; 
5184     item
.m_format 
= format
; 
5186     return InsertColumn( col
, item 
); 
5189 bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) ) 
5195 // fn is a function which takes 3 long arguments: item1, item2, data. 
5196 // item1 is the long data associated with a first item (NOT the index). 
5197 // item2 is the long data associated with a second item (NOT the index). 
5198 // data is the same value as passed to SortItems. 
5199 // The return value is a negative number if the first item should precede the second 
5200 // item, a positive number of the second item should precede the first, 
5201 // or zero if the two items are equivalent. 
5202 // data is arbitrary data to be passed to the sort function. 
5204 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
5206     m_mainWin
->SortItems( fn
, data 
); 
5210 // ---------------------------------------------------------------------------- 
5212 // ---------------------------------------------------------------------------- 
5214 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
5219     ResizeReportView(m_mainWin
->HasHeader()); 
5221     m_mainWin
->RecalculatePositions(); 
5224 void wxGenericListCtrl::ResizeReportView(bool showHeader
) 
5227     GetClientSize( &cw
, &ch 
); 
5231         m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT 
); 
5232         m_mainWin
->SetSize( 0, HEADER_HEIGHT 
+ 1, cw
, ch 
- HEADER_HEIGHT 
- 1 ); 
5234     else // no header window 
5236         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
5240 void wxGenericListCtrl::OnIdle( wxIdleEvent 
& event 
) 
5244     // do it only if needed 
5245     if ( !m_mainWin
->m_dirty 
) 
5248     m_mainWin
->RecalculatePositions(); 
5251 // ---------------------------------------------------------------------------- 
5253 // ---------------------------------------------------------------------------- 
5255 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5259         m_mainWin
->SetBackgroundColour( colour 
); 
5260         m_mainWin
->m_dirty 
= TRUE
; 
5266 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5268     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5273         m_mainWin
->SetForegroundColour( colour 
); 
5274         m_mainWin
->m_dirty 
= TRUE
; 
5279         m_headerWin
->SetForegroundColour( colour 
); 
5285 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5287     if ( !wxWindow::SetFont( font 
) ) 
5292         m_mainWin
->SetFont( font 
); 
5293         m_mainWin
->m_dirty 
= TRUE
; 
5298         m_headerWin
->SetFont( font 
); 
5304 // ---------------------------------------------------------------------------- 
5305 // methods forwarded to m_mainWin 
5306 // ---------------------------------------------------------------------------- 
5308 #if wxUSE_DRAG_AND_DROP 
5310 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5312     m_mainWin
->SetDropTarget( dropTarget 
); 
5315 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5317     return m_mainWin
->GetDropTarget(); 
5320 #endif // wxUSE_DRAG_AND_DROP 
5322 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5324     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
; 
5327 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5329     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5332 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5334     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5337 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5340     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5343 #endif // wxUSE_MENUS 
5346 void wxGenericListCtrl::SetFocus() 
5348     /* The test in window.cpp fails as we are a composite 
5349        window, so it checks against "this", but not m_mainWin. */ 
5350     if ( FindFocus() != this ) 
5351         m_mainWin
->SetFocus(); 
5354 // ---------------------------------------------------------------------------- 
5355 // virtual list control support 
5356 // ---------------------------------------------------------------------------- 
5358 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5360     // this is a pure virtual function, in fact - which is not really pure 
5361     // because the controls which are not virtual don't need to implement it 
5362     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5364     return wxEmptyString
; 
5367 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5370     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemImage not supposed to be called") ); 
5375 wxListItemAttr 
*wxGenericListCtrl::OnGetItemAttr(long item
) const 
5377     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5378                   _T("invalid item index in OnGetItemAttr()") ); 
5380     // no attributes by default 
5384 void wxGenericListCtrl::SetItemCount(long count
) 
5386     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
5388     m_mainWin
->SetItemCount(count
); 
5391 void wxGenericListCtrl::RefreshItem(long item
) 
5393     m_mainWin
->RefreshLine(item
); 
5396 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5398     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5401 void wxGenericListCtrl::Freeze() 
5403     m_mainWin
->Freeze(); 
5406 void wxGenericListCtrl::Thaw() 
5411 #endif // wxUSE_LISTCTRL