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 ///////////////////////////////////////////////////////////////////////////// 
  12    FIXME for virtual list controls 
  14   +1. clicking on the item with a mouse is awfully slow, what is going on? 
  15       note that selecting with keyboard seems to be much faster 
  16    => fixed HighlightAll() - iterating over 1000000 items *is* slow 
  18    2. background colour is wrong? 
  22    TODO for better virtual list control support: 
  24    1. less dumb line caching, we should cache at least all those visible 
  25       in the control itself and probably twice as many (we might also need to 
  26       cache the first one always for geometry calculations?) 
  28   +2. storing selections: we can't use an array to store the selected indices 
  29       like right now as selecting all in a control with 1000000 items is not 
  30       doable like this - instead, store selections as collection of individual 
  35    3. we need to implement searching/sorting somehow 
  37    4. the idea of storing the line index in the line itself is really stupid, 
  38       we shouldn't need it - but for this we have to get rid of all calles to 
  39       wxListLineData::GetFoo() and replace them with something like 
  41             ... we have it ourselves ... 
  46 // ============================================================================ 
  48 // ============================================================================ 
  50 // ---------------------------------------------------------------------------- 
  52 // ---------------------------------------------------------------------------- 
  55     #pragma implementation "listctrl.h" 
  56     #pragma implementation "listctrlbase.h" 
  59 // For compilers that support precompilation, includes "wx.h". 
  60 #include "wx/wxprec.h" 
  68 #include "wx/dcscreen.h" 
  70 #include "wx/listctrl.h" 
  71 #include "wx/imaglist.h" 
  72 #include "wx/dynarray.h" 
  76 #include "wx/gtk/win_gtk.h" 
  79 // ---------------------------------------------------------------------------- 
  81 // ---------------------------------------------------------------------------- 
  83 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
) 
  84 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
) 
  85 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
) 
  86 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
) 
  87 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
) 
  88 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
) 
  89 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
) 
  90 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
) 
  91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
) 
  92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
) 
  93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
) 
  94 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
) 
  95 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
) 
  96 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
) 
  97 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
) 
  98 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
) 
 100 // ---------------------------------------------------------------------------- 
 102 // ---------------------------------------------------------------------------- 
 104 // the height of the header window (FIXME: should depend on its font!) 
 105 static const int HEADER_HEIGHT 
= 23; 
 107 // the scrollbar units 
 108 static const int SCROLL_UNIT_X 
= 15; 
 109 static const int SCROLL_UNIT_Y 
= 15; 
 111 // the spacing between the lines (in report mode) 
 112 static const int LINE_SPACING 
= 0; 
 114 // extra margins around the text label 
 115 static const int EXTRA_WIDTH 
= 3; 
 116 static const int EXTRA_HEIGHT 
= 4; 
 118 // offset for the header window 
 119 static const int HEADER_OFFSET_X 
= 1; 
 120 static const int HEADER_OFFSET_Y 
= 1; 
 122 // when autosizing the columns, add some slack 
 123 static const int AUTOSIZE_COL_MARGIN 
= 10; 
 125 // default and minimal widths for the header columns 
 126 static const int WIDTH_COL_DEFAULT 
= 80; 
 127 static const int WIDTH_COL_MIN 
= 10; 
 129 // ============================================================================ 
 131 // ============================================================================ 
 133 // ---------------------------------------------------------------------------- 
 135 // ---------------------------------------------------------------------------- 
 137 int CMPFUNC_CONV 
wxSizeTCmpFn(size_t n1
, size_t n2
) { return n1 
- n2
; } 
 139 WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray
); 
 141 // this class is used to store the selected items in the virtual list control 
 142 // (but it is not tied to list control and so can be used with other controls 
 143 // such as wxListBox in wxUniv) 
 145 // the idea is to make it really smart later (i.e. store the selections as an 
 146 // array of ranes + individual items) but, as I don't have time to do it now 
 147 // (this would require writing code to merge/break ranges and much more) keep 
 148 // it simple but define a clean interface to it which allows it to be made 
 150 class WXDLLEXPORT wxSelectionStore
 
 153     wxSelectionStore() : m_itemsSel(wxSizeTCmpFn
) { Init(); } 
 155     // set the total number of items we handle 
 156     void SetItemCount(size_t count
) { m_count 
= count
; } 
 158     // special case of SetItemCount(0) 
 159     void Clear() { m_itemsSel
.Clear(); m_count 
= 0; } 
 161     // must be called when a new item is inserted/added 
 162     void OnItemAdd(size_t item
) { wxFAIL_MSG( _T("TODO") ); } 
 164     // must be called when an item is deleted 
 165     void OnItemDelete(size_t item
); 
 167     // select one item, use SelectRange() insted if possible! 
 169     // returns true if the items selection really changed 
 170     bool SelectItem(size_t item
, bool select 
= TRUE
); 
 172     // select the range of items 
 173     void SelectRange(size_t itemFrom
, size_t itemTo
, bool select 
= TRUE
); 
 175     // return true if the given item is selected 
 176     bool IsSelected(size_t item
) const; 
 178     // return the total number of selected items 
 179     size_t GetSelectedCount() const 
 181         return m_defaultState 
? m_count 
- m_itemsSel
.GetCount() 
 182                               : m_itemsSel
.GetCount(); 
 187     void Init() { m_defaultState 
= FALSE
; } 
 189     // the total number of items we handle 
 192     // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if 
 193     // there are more selected items than non selected ones - this allows to 
 194     // handle selection of all items efficiently 
 197     // the array of items whose selection state is different from default 
 198     wxIndexArray m_itemsSel
; 
 200     DECLARE_NO_COPY_CLASS(wxSelectionStore
) 
 203 //----------------------------------------------------------------------------- 
 204 //  wxListItemData (internal) 
 205 //----------------------------------------------------------------------------- 
 207 class WXDLLEXPORT wxListItemData
 
 210     wxListItemData(wxListMainWindow 
*owner
); 
 211     ~wxListItemData() { delete m_attr
; delete m_rect
; } 
 213     void SetItem( const wxListItem 
&info 
); 
 214     void SetImage( int image 
) { m_image 
= image
; } 
 215     void SetData( long data 
) { m_data 
= data
; } 
 216     void SetPosition( int x
, int y 
); 
 217     void SetSize( int width
, int height 
); 
 219     bool HasText() const { return !m_text
.empty(); } 
 220     const wxString
& GetText() const { return m_text
; } 
 221     void SetText(const wxString
& text
) { m_text 
= text
; } 
 223     // we can't use empty string for measuring the string width/height, so 
 224     // always return something 
 225     wxString 
GetTextForMeasuring() const 
 227         wxString s 
= GetText(); 
 234     bool IsHit( int x
, int y 
) const; 
 238     int GetWidth() const; 
 239     int GetHeight() const; 
 241     int GetImage() const { return m_image
; } 
 242     bool HasImage() const { return GetImage() != -1; } 
 244     void GetItem( wxListItem 
&info 
) const; 
 246     wxListItemAttr 
*GetAttributes() const { return m_attr
; } 
 249     // the item image or -1 
 252     // user data associated with the item 
 255     // the item coordinates are not used in report mode, instead this pointer 
 256     // is NULL and the owner window is used to retrieve the item position and 
 260     // the list ctrl we are in 
 261     wxListMainWindow 
*m_owner
; 
 263     // custom attributes or NULL 
 264     wxListItemAttr 
*m_attr
; 
 267     // common part of all ctors 
 273 //----------------------------------------------------------------------------- 
 274 //  wxListHeaderData (internal) 
 275 //----------------------------------------------------------------------------- 
 277 class WXDLLEXPORT wxListHeaderData 
: public wxObject
 
 291     wxListHeaderData( const wxListItem 
&info 
); 
 292     void SetItem( const wxListItem 
&item 
); 
 293     void SetPosition( int x
, int y 
); 
 294     void SetWidth( int w 
); 
 295     void SetFormat( int format 
); 
 296     void SetHeight( int h 
); 
 297     bool HasImage() const; 
 299     bool HasText() const { return !m_text
.empty(); } 
 300     const wxString
& GetText() const { return m_text
; } 
 301     void SetText(const wxString
& text
) { m_text 
= text
; } 
 303     void GetItem( wxListItem 
&item 
); 
 305     bool IsHit( int x
, int y 
) const; 
 306     int GetImage() const; 
 307     int GetWidth() const; 
 308     int GetFormat() const; 
 311     DECLARE_DYNAMIC_CLASS(wxListHeaderData
); 
 314 //----------------------------------------------------------------------------- 
 315 //  wxListLineData (internal) 
 316 //----------------------------------------------------------------------------- 
 318 WX_DECLARE_LIST(wxListItemData
, wxListItemDataList
); 
 319 #include "wx/listimpl.cpp" 
 320 WX_DEFINE_LIST(wxListItemDataList
); 
 322 class WXDLLEXPORT wxListLineData
 
 325     // the list of subitems: only may have more than one item in report mode 
 326     wxListItemDataList m_items
; 
 328     // this is not used in report view 
 340         // the part to be highlighted 
 341         wxRect m_rectHighlight
; 
 344     // is this item selected? [NB: not used in virtual mode] 
 347     // back pointer to the list ctrl 
 348     wxListMainWindow 
*m_owner
; 
 351     wxListLineData(wxListMainWindow 
*owner
); 
 353     ~wxListLineData() { delete m_gi
; } 
 355     // are we in report mode? 
 356     inline bool InReportView() const; 
 358     // are we in virtual report mode? 
 359     inline bool IsVirtual() const; 
 361     // these 2 methods shouldn't be called for report view controls, in that 
 362     // case we determine our position/size ourselves 
 364     // calculate the size of the line 
 365     void CalculateSize( wxDC 
*dc
, int spacing 
); 
 367     // remember the position this line appears at 
 368     void SetPosition( int x
, int y
,  int window_width
, int spacing 
); 
 372     void SetImage( int image 
) { SetImage(0, image
); } 
 373     int GetImage() const { return GetImage(0); } 
 374     bool HasImage() const { return GetImage() != -1; } 
 375     bool HasText() const { return !GetText(0).empty(); } 
 377     void SetItem( int index
, const wxListItem 
&info 
); 
 378     void GetItem( int index
, wxListItem 
&info 
); 
 380     wxString 
GetText(int index
) const; 
 381     void SetText( int index
, const wxString s 
); 
 383     // return true if the highlighting really changed 
 384     bool Highlight( bool on 
); 
 386     void ReverseHighlight(); 
 388     bool IsHighlighted() const 
 390         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); 
 392         return m_highlighted
; 
 395     // draw the line on the given DC in icon/list mode 
 396     void Draw( wxDC 
*dc 
); 
 398     // the same in report mode 
 399     void DrawInReportMode( wxDC 
*dc
, 
 401                            const wxRect
& rectHL
, 
 405     // set the line to contain num items (only can be > 1 in report mode) 
 406     void InitItems( int num 
); 
 408     // get the mode (i.e. style)  of the list control 
 409     inline int GetMode() const; 
 411     void SetAttributes(wxDC 
*dc
, 
 412                        const wxListItemAttr 
*attr
, 
 413                        const wxColour
& colText
, 
 417     // these are only used by GetImage/SetImage above, we don't support images 
 418     // with subitems at the public API level yet 
 419     void SetImage( int index
, int image 
); 
 420     int GetImage( int index 
) const; 
 423 WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData
, wxListLineDataArray
); 
 424 #include "wx/arrimpl.cpp" 
 425 WX_DEFINE_OBJARRAY(wxListLineDataArray
); 
 427 //----------------------------------------------------------------------------- 
 428 //  wxListHeaderWindow (internal) 
 429 //----------------------------------------------------------------------------- 
 431 class WXDLLEXPORT wxListHeaderWindow 
: public wxWindow
 
 434     wxListMainWindow  
*m_owner
; 
 435     wxCursor          
*m_currentCursor
; 
 436     wxCursor          
*m_resizeCursor
; 
 439     // column being resized 
 442     // divider line position in logical (unscrolled) coords 
 445     // minimal position beyond which the divider line can't be dragged in 
 450     wxListHeaderWindow(); 
 451     virtual ~wxListHeaderWindow(); 
 453     wxListHeaderWindow( wxWindow 
*win
, 
 455                         wxListMainWindow 
*owner
, 
 456                         const wxPoint 
&pos 
= wxDefaultPosition
, 
 457                         const wxSize 
&size 
= wxDefaultSize
, 
 459                         const wxString 
&name 
= "wxlistctrlcolumntitles" ); 
 461     void DoDrawRect( wxDC 
*dc
, int x
, int y
, int w
, int h 
); 
 463     void AdjustDC(wxDC
& dc
); 
 465     void OnPaint( wxPaintEvent 
&event 
); 
 466     void OnMouse( wxMouseEvent 
&event 
); 
 467     void OnSetFocus( wxFocusEvent 
&event 
); 
 473     DECLARE_DYNAMIC_CLASS(wxListHeaderWindow
) 
 474     DECLARE_EVENT_TABLE() 
 477 //----------------------------------------------------------------------------- 
 478 // wxListRenameTimer (internal) 
 479 //----------------------------------------------------------------------------- 
 481 class WXDLLEXPORT wxListRenameTimer
: public wxTimer
 
 484     wxListMainWindow 
*m_owner
; 
 487     wxListRenameTimer( wxListMainWindow 
*owner 
); 
 491 //----------------------------------------------------------------------------- 
 492 //  wxListTextCtrl (internal) 
 493 //----------------------------------------------------------------------------- 
 495 class WXDLLEXPORT wxListTextCtrl
: public wxTextCtrl
 
 500     wxListMainWindow   
*m_owner
; 
 501     wxString            m_startValue
; 
 505     wxListTextCtrl( wxWindow 
*parent
, const wxWindowID id
, 
 506                     bool *accept
, wxString 
*res
, wxListMainWindow 
*owner
, 
 507                     const wxString 
&value 
= "", 
 508                     const wxPoint 
&pos 
= wxDefaultPosition
, const wxSize 
&size 
= wxDefaultSize
, 
 510                     const wxValidator
& validator 
= wxDefaultValidator
, 
 511                     const wxString 
&name 
= "listctrltextctrl" ); 
 512     void OnChar( wxKeyEvent 
&event 
); 
 513     void OnKeyUp( wxKeyEvent 
&event 
); 
 514     void OnKillFocus( wxFocusEvent 
&event 
); 
 517     DECLARE_DYNAMIC_CLASS(wxListTextCtrl
); 
 518     DECLARE_EVENT_TABLE() 
 521 //----------------------------------------------------------------------------- 
 522 //  wxListMainWindow (internal) 
 523 //----------------------------------------------------------------------------- 
 525 WX_DECLARE_LIST(wxListHeaderData
, wxListHeaderDataList
); 
 526 #include "wx/listimpl.cpp" 
 527 WX_DEFINE_LIST(wxListHeaderDataList
); 
 529 class WXDLLEXPORT wxListMainWindow 
: public wxScrolledWindow
 
 533     wxListMainWindow( wxWindow 
*parent
, 
 535                       const wxPoint
& pos 
= wxDefaultPosition
, 
 536                       const wxSize
& size 
= wxDefaultSize
, 
 538                       const wxString 
&name 
= _T("listctrlmainwindow") ); 
 540     virtual ~wxListMainWindow(); 
 542     bool HasFlag(int flag
) const { return m_parent
->HasFlag(flag
); } 
 544     // return true if this is a virtual list control 
 545     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL
); } 
 547     // return true if the control is in report mode 
 548     bool InReportView() const { return HasFlag(wxLC_REPORT
); } 
 550     // return true if we are in single selection mode, false if multi sel 
 551     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL
); } 
 553     // do we have a header window? 
 554     bool HasHeader() const 
 555         { return HasFlag(wxLC_REPORT
) && !HasFlag(wxLC_NO_HEADER
); } 
 557     void HighlightAll( bool on 
); 
 559     // all these functions only do something if the line is currently visible 
 561     // change the line "selected" state, return TRUE if it really changed 
 562     bool HighlightLine( size_t line
, bool highlight 
= TRUE
); 
 564     // as HighlightLine() but do it for the range of lines: this is incredibly 
 565     // more efficient for virtual list controls! 
 567     // NB: unlike HighlightLine() this one does refresh the lines on screen 
 568     void HighlightLines( size_t lineFrom
, size_t lineTo
, bool on 
= TRUE 
); 
 570     // toggle the line state and refresh it 
 571     void ReverseHighlight( size_t line 
) 
 572         { HighlightLine(line
, !IsHighlighted(line
)); RefreshLine(line
); } 
 574     // return true if the line is highlighted 
 575     bool IsHighlighted(size_t line
) const; 
 577     // refresh one or several lines at once 
 578     void RefreshLine( size_t line 
); 
 579     void RefreshLines( size_t lineFrom
, size_t lineTo 
); 
 581     // refresh all lines below the given one: the difference with 
 582     // RefreshLines() is that the index here might not be a valid one (happens 
 583     // when the last line is deleted) 
 584     void RefreshAfter( size_t lineFrom 
); 
 586     // the methods which are forwarded to wxListLineData itself in list/icon 
 587     // modes but are here because the lines don't store their positions in the 
 590     // get the bound rect for the entire line 
 591     wxRect 
GetLineRect(size_t line
) const; 
 593     // get the bound rect of the label 
 594     wxRect 
GetLineLabelRect(size_t line
) const; 
 596     // get the bound rect of the items icon (only may be called if we do have 
 598     wxRect 
GetLineIconRect(size_t line
) const; 
 600     // get the rect to be highlighted when the item has focus 
 601     wxRect 
GetLineHighlightRect(size_t line
) const; 
 603     // get the size of the total line rect 
 604     wxSize 
GetLineSize(size_t line
) const 
 605         { return GetLineRect(line
).GetSize(); } 
 607     // return the hit code for the corresponding position (in this line) 
 608     long HitTestLine(size_t line
, int x
, int y
) const; 
 610     void EditLabel( long item 
); 
 611     void OnRenameTimer(); 
 612     void OnRenameAccept(); 
 614     void OnMouse( wxMouseEvent 
&event 
); 
 617     // called to switch the selection from the current item to newCurrent, 
 618     void OnArrowChar( size_t newCurrent
, const wxKeyEvent
& event 
); 
 620     void OnChar( wxKeyEvent 
&event 
); 
 621     void OnKeyDown( wxKeyEvent 
&event 
); 
 622     void OnSetFocus( wxFocusEvent 
&event 
); 
 623     void OnKillFocus( wxFocusEvent 
&event 
); 
 624     void OnScroll(wxScrollWinEvent
& event
) ; 
 626     void OnPaint( wxPaintEvent 
&event 
); 
 628     void DrawImage( int index
, wxDC 
*dc
, int x
, int y 
); 
 629     void GetImageSize( int index
, int &width
, int &height 
) const; 
 630     int GetTextLength( const wxString 
&s 
) const; 
 632     void SetImageList( wxImageList 
*imageList
, int which 
); 
 633     void SetItemSpacing( int spacing
, bool isSmall 
= FALSE 
); 
 634     int GetItemSpacing( bool isSmall 
= FALSE 
); 
 636     void SetColumn( int col
, wxListItem 
&item 
); 
 637     void SetColumnWidth( int col
, int width 
); 
 638     void GetColumn( int col
, wxListItem 
&item 
) const; 
 639     int GetColumnWidth( int col 
) const; 
 640     int GetColumnCount() const { return m_columns
.GetCount(); } 
 642     // returns the sum of the heights of all columns 
 643     int GetHeaderWidth() const; 
 645     int GetCountPerPage() const; 
 647     void SetItem( wxListItem 
&item 
); 
 648     void GetItem( wxListItem 
&item 
); 
 649     void SetItemState( long item
, long state
, long stateMask 
); 
 650     int GetItemState( long item
, long stateMask 
); 
 651     void GetItemRect( long index
, wxRect 
&rect 
); 
 652     bool GetItemPosition( long item
, wxPoint
& pos 
); 
 653     int GetSelectedItemCount(); 
 655     // set the scrollbars and update the positions of the items 
 656     void RecalculatePositions(); 
 658     // refresh the window and the header 
 661     long GetNextItem( long item
, int geometry
, int state 
); 
 662     void DeleteItem( long index 
); 
 663     void DeleteAllItems(); 
 664     void DeleteColumn( int col 
); 
 665     void DeleteEverything(); 
 666     void EnsureVisible( long index 
); 
 667     long FindItem( long start
, const wxString
& str
, bool partial 
= FALSE 
); 
 668     long FindItem( long start
, long data
); 
 669     long HitTest( int x
, int y
, int &flags 
); 
 670     void InsertItem( wxListItem 
&item 
); 
 671     void InsertColumn( long col
, wxListItem 
&item 
); 
 672     void SortItems( wxListCtrlCompare fn
, long data 
); 
 674     size_t GetItemCount() const; 
 675     bool IsEmpty() const { return GetItemCount() == 0; } 
 676     void SetItemCount(long count
); 
 678     void ResetCurrent() { m_current 
= (size_t)-1; } 
 679     bool HasCurrent() const { return m_current 
!= (size_t)-1; } 
 681     // send out a wxListEvent 
 682     void SendNotify( size_t line
, 
 684                      wxPoint point 
= wxDefaultPosition 
); 
 686     // override base class virtual to reset m_lineHeight when the font changes 
 687     virtual bool SetFont(const wxFont
& font
) 
 689         if ( !wxScrolledWindow::SetFont(font
) ) 
 697     // these are for wxListLineData usage only 
 699     // get the backpointer to the list ctrl 
 700     wxListCtrl 
*GetListCtrl() const 
 702         return wxStaticCast(GetParent(), wxListCtrl
); 
 705     // get the height of all lines (assuming they all do have the same height) 
 706     wxCoord 
GetLineHeight() const; 
 708     // get the y position of the given line (only for report view) 
 709     wxCoord 
GetLineY(size_t line
) const; 
 712     // the array of all line objects for a non virtual list control 
 713     wxListLineDataArray  m_lines
; 
 715     // the list of column objects 
 716     wxListHeaderDataList m_columns
; 
 718     // currently focused item or -1 
 721     // the item currently being edited or -1 
 722     size_t               m_currentEdit
; 
 724     // the number of lines per page 
 727     // this flag is set when something which should result in the window 
 728     // redrawing happens (i.e. an item was added or deleted, or its appearance 
 729     // changed) and OnPaint() doesn't redraw the window while it is set which 
 730     // allows to minimize the number of repaintings when a lot of items are 
 731     // being added. The real repainting occurs only after the next OnIdle() 
 735     wxBrush             
*m_highlightBrush
; 
 736     wxColour            
*m_highlightColour
; 
 739     wxImageList         
*m_small_image_list
; 
 740     wxImageList         
*m_normal_image_list
; 
 742     int                  m_normal_spacing
; 
 746     wxTimer             
*m_renameTimer
; 
 748     wxString             m_renameRes
; 
 753     // for double click logic 
 754     size_t m_lineLastClicked
, 
 755            m_lineBeforeLastClicked
; 
 758     // the total count of items in a virtual list control 
 761     // the object maintaining the items selection state, only used in virtual 
 763     wxSelectionStore m_selStore
; 
 765     // common part of all ctors 
 768     // intiialize m_[xy]Scroll 
 769     void InitScrolling(); 
 771     // get the line data for the given index 
 772     wxListLineData 
*GetLine(size_t n
) const 
 774         wxASSERT_MSG( n 
!= (size_t)-1, _T("invalid line index") ); 
 778             wxConstCast(this, wxListMainWindow
)->CacheLineData(n
); 
 786     // get a dummy line which can be used for geometry calculations and such: 
 787     // you must use GetLine() if you want to really draw the line 
 788     wxListLineData 
*GetDummyLine() const; 
 790     // cache the line data of the n-th line in m_lines[0] 
 791     void CacheLineData(size_t line
); 
 793     // get the range of visible lines 
 794     void GetVisibleLinesRange(size_t *from
, size_t *to
); 
 796     // force us to recalculate the range of visible lines 
 797     void ResetVisibleLinesRange() { m_lineFrom 
= (size_t)-1; } 
 799     // get the colour to be used for drawing the rules 
 800     wxColour 
GetRuleColour() const 
 805         return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
); 
 810     // initialize the current item if needed 
 811     void UpdateCurrent(); 
 813     // called when an item is [un]focuded, i.e. becomes [not] current 
 816     void OnFocusLine( size_t line 
); 
 817     void OnUnfocusLine( size_t line 
); 
 819     // the height of one line using the current font 
 820     wxCoord m_lineHeight
; 
 822     // the total header width or 0 if not calculated yet 
 823     wxCoord m_headerWidth
; 
 825     // the first and last lines being shown on screen right now (inclusive), 
 826     // both may be -1 if they must be calculated so never access them directly: 
 827     // use GetVisibleLinesRange() above instead 
 831     DECLARE_DYNAMIC_CLASS(wxListMainWindow
); 
 832     DECLARE_EVENT_TABLE() 
 835 // ============================================================================ 
 837 // ============================================================================ 
 839 // ---------------------------------------------------------------------------- 
 841 // ---------------------------------------------------------------------------- 
 843 bool wxSelectionStore::IsSelected(size_t item
) const 
 845     bool isSel 
= m_itemsSel
.Index(item
) != wxNOT_FOUND
; 
 847     // if the default state is to be selected, being in m_itemsSel means that 
 848     // the item is not selected, so we have to inverse the logic 
 849     return m_defaultState 
? !isSel 
: isSel
; 
 852 bool wxSelectionStore::SelectItem(size_t item
, bool select
) 
 854     // search for the item ourselves as like this we get the index where to 
 855     // insert it later if needed, so we do only one search in the array instead 
 856     // of two (adding item to a sorted array requires a search) 
 857     size_t index 
= m_itemsSel
.IndexForInsert(item
); 
 858     bool isSel 
= index 
< m_itemsSel
.GetCount() && m_itemsSel
[index
] == item
; 
 860     if ( select 
!= m_defaultState 
) 
 864             m_itemsSel
.AddAt(item
, index
); 
 869     else // reset to default state 
 873             m_itemsSel
.RemoveAt(index
); 
 881 void wxSelectionStore::SelectRange(size_t itemFrom
, size_t itemTo
, bool select
) 
 883     wxASSERT_MSG( itemFrom 
<= itemTo
, _T("should be in order") ); 
 885     // are we going to have more [un]selected items than the other ones? 
 886     if ( itemTo 
- itemFrom 
> m_count 
/ 2 ) 
 888         if ( select 
!= m_defaultState 
) 
 890             // the default state now becomes the same as 'select' 
 891             m_defaultState 
= select
; 
 893             // so all the old selections (which had state select) shouldn't be 
 894             // selected any more, but all the other ones should 
 895             wxIndexArray selOld 
= m_itemsSel
; 
 898             // TODO: it should be possible to optimize the searches a bit 
 899             //       knowing the possible range 
 902             for ( item 
= 0; item 
< itemFrom
; item
++ ) 
 904                 if ( selOld
.Index(item
) == wxNOT_FOUND 
) 
 905                     m_itemsSel
.Add(item
); 
 908             for ( item 
= itemTo 
+ 1; item 
< m_count
; item
++ ) 
 910                 if ( selOld
.Index(item
) == wxNOT_FOUND 
) 
 911                     m_itemsSel
.Add(item
); 
 914         else // select == m_defaultState 
 916             // get the inclusive range of items between itemFrom and itemTo 
 917             size_t count 
= m_itemsSel
.GetCount(), 
 918                    start 
= m_itemsSel
.IndexForInsert(itemFrom
), 
 919                    end 
= m_itemsSel
.IndexForInsert(itemTo
); 
 921             if ( start 
== count 
|| m_itemsSel
[start
] < itemFrom 
) 
 926             if ( end 
== count 
|| m_itemsSel
[end
] > itemTo 
) 
 933                 // delete all of them (from end to avoid changing indices) 
 934                 for ( int i 
= end
; i 
>= (int)start
; i
-- ) 
 936                     m_itemsSel
.RemoveAt(i
); 
 941     else // "few" items change state 
 943         // just add the items to the selection 
 944         for ( size_t item 
= itemFrom
; item 
<= itemTo
; item
++ ) 
 946             SelectItem(item
, select
); 
 951 void wxSelectionStore::OnItemDelete(size_t item
) 
 953     size_t count 
= m_itemsSel
.GetCount(), 
 954            i 
= m_itemsSel
.IndexForInsert(item
); 
 956     if ( i 
< count 
&& m_itemsSel
[i
] == item 
) 
 958         // this item itself was in m_itemsSel, remove it from there 
 959         m_itemsSel
.RemoveAt(i
); 
 964     // and adjust the index of all which follow it 
 967         // all following elements must be greater than the one we deleted 
 968         wxASSERT_MSG( m_itemsSel
[i
] > item
, _T("logic error") ); 
 974 //----------------------------------------------------------------------------- 
 976 //----------------------------------------------------------------------------- 
 978 void wxListItemData::Init() 
 986 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
 992     if ( owner
->HasFlag(wxLC_REPORT
) ) 
1002 void wxListItemData::SetItem( const wxListItem 
&info 
) 
1004     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
1005         SetText(info
.m_text
); 
1006     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
1007         m_image 
= info
.m_image
; 
1008     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
1009         m_data 
= info
.m_data
; 
1011     if ( info
.HasAttributes() ) 
1014             *m_attr 
= *info
.GetAttributes(); 
1016             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
1024         m_rect
->width 
= info
.m_width
; 
1028 void wxListItemData::SetPosition( int x
, int y 
) 
1030     wxCHECK_RET( m_rect
, _T("unexpected SetPosition() call") ); 
1036 void wxListItemData::SetSize( int width
, int height 
) 
1038     wxCHECK_RET( m_rect
, _T("unexpected SetSize() call") ); 
1041         m_rect
->width 
= width
; 
1043         m_rect
->height 
= height
; 
1046 bool wxListItemData::IsHit( int x
, int y 
) const 
1048     wxCHECK_MSG( m_rect
, FALSE
, _T("can't be called in this mode") ); 
1050     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x
, y
); 
1053 int wxListItemData::GetX() const 
1055     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
1060 int wxListItemData::GetY() const 
1062     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
1067 int wxListItemData::GetWidth() const 
1069     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
1071     return m_rect
->width
; 
1074 int wxListItemData::GetHeight() const 
1076     wxCHECK_MSG( m_rect
, 0, _T("can't be called in this mode") ); 
1078     return m_rect
->height
; 
1081 void wxListItemData::GetItem( wxListItem 
&info 
) const 
1083     info
.m_text 
= m_text
; 
1084     info
.m_image 
= m_image
; 
1085     info
.m_data 
= m_data
; 
1089         if ( m_attr
->HasTextColour() ) 
1090             info
.SetTextColour(m_attr
->GetTextColour()); 
1091         if ( m_attr
->HasBackgroundColour() ) 
1092             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
1093         if ( m_attr
->HasFont() ) 
1094             info
.SetFont(m_attr
->GetFont()); 
1098 //----------------------------------------------------------------------------- 
1100 //----------------------------------------------------------------------------- 
1102 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData
,wxObject
); 
1104 wxListHeaderData::wxListHeaderData() 
1115 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
1123 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
1125     m_mask 
= item
.m_mask
; 
1126     m_text 
= item
.m_text
; 
1127     m_image 
= item
.m_image
; 
1128     m_format 
= item
.m_format
; 
1130     SetWidth(item
.m_width
); 
1133 void wxListHeaderData::SetPosition( int x
, int y 
) 
1139 void wxListHeaderData::SetHeight( int h 
) 
1144 void wxListHeaderData::SetWidth( int w 
) 
1148         m_width 
= WIDTH_COL_DEFAULT
; 
1149     if (m_width 
< WIDTH_COL_MIN
) 
1150         m_width 
= WIDTH_COL_MIN
; 
1153 void wxListHeaderData::SetFormat( int format 
) 
1158 bool wxListHeaderData::HasImage() const 
1160     return (m_image 
!= 0); 
1163 bool wxListHeaderData::IsHit( int x
, int y 
) const 
1165     return ((x 
>= m_xpos
) && (x 
<= m_xpos
+m_width
) && (y 
>= m_ypos
) && (y 
<= m_ypos
+m_height
)); 
1168 void wxListHeaderData::GetItem( wxListItem 
&item 
) 
1170     item
.m_mask 
= m_mask
; 
1171     item
.m_text 
= m_text
; 
1172     item
.m_image 
= m_image
; 
1173     item
.m_format 
= m_format
; 
1174     item
.m_width 
= m_width
; 
1177 int wxListHeaderData::GetImage() const 
1182 int wxListHeaderData::GetWidth() const 
1187 int wxListHeaderData::GetFormat() const 
1192 //----------------------------------------------------------------------------- 
1194 //----------------------------------------------------------------------------- 
1196 inline int wxListLineData::GetMode() const 
1198     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
1201 inline bool wxListLineData::InReportView() const 
1203     return m_owner
->HasFlag(wxLC_REPORT
); 
1206 inline bool wxListLineData::IsVirtual() const 
1208     return m_owner
->IsVirtual(); 
1211 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
1214     m_items
.DeleteContents( TRUE 
); 
1216     if ( InReportView() ) 
1222         m_gi 
= new GeometryInfo
; 
1225     m_highlighted 
= FALSE
; 
1227     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
1230 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
1232     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1233     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1235     wxListItemData 
*item 
= node
->GetData(); 
1237     switch ( GetMode() ) 
1240         case wxLC_SMALL_ICON
: 
1242                 m_gi
->m_rectAll
.width 
= spacing
; 
1244                 wxString s 
= item
->GetText(); 
1250                     m_gi
->m_rectLabel
.width 
= 
1251                     m_gi
->m_rectLabel
.height 
= 0; 
1255                     dc
->GetTextExtent( s
, &lw
, &lh 
); 
1256                     if (lh 
< SCROLL_UNIT_Y
) 
1261                     m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
1263                         m_gi
->m_rectAll
.width 
= lw
; 
1265                     m_gi
->m_rectLabel
.width 
= lw
; 
1266                     m_gi
->m_rectLabel
.height 
= lh
; 
1269                 if (item
->HasImage()) 
1272                     m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1273                     m_gi
->m_rectIcon
.width 
= w 
+ 8; 
1274                     m_gi
->m_rectIcon
.height 
= h 
+ 8; 
1276                     if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
1277                         m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
1278                     if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
1279                         m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
1282                 if ( item
->HasText() ) 
1284                     m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
1285                     m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
1287                 else // no text, highlight the icon 
1289                     m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
1290                     m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
1297                 wxString s 
= item
->GetTextForMeasuring(); 
1300                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
1301                 if (lh 
< SCROLL_UNIT_Y
) 
1306                 m_gi
->m_rectLabel
.width 
= lw
; 
1307                 m_gi
->m_rectLabel
.height 
= lh
; 
1309                 m_gi
->m_rectAll
.width 
= lw
; 
1310                 m_gi
->m_rectAll
.height 
= lh
; 
1312                 if (item
->HasImage()) 
1315                     m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
1316                     m_gi
->m_rectIcon
.width 
= w
; 
1317                     m_gi
->m_rectIcon
.height 
= h
; 
1319                     m_gi
->m_rectAll
.width 
+= 4 + w
; 
1320                     if (h 
> m_gi
->m_rectAll
.height
) 
1321                         m_gi
->m_rectAll
.height 
= h
; 
1324                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
1325                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
1330             wxFAIL_MSG( _T("unexpected call to SetSize") ); 
1334             wxFAIL_MSG( _T("unknown mode") ); 
1338 void wxListLineData::SetPosition( int x
, int y
, 
1342     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1343     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1345     wxListItemData 
*item 
= node
->GetData(); 
1347     switch ( GetMode() ) 
1350         case wxLC_SMALL_ICON
: 
1351             m_gi
->m_rectAll
.x 
= x
; 
1352             m_gi
->m_rectAll
.y 
= y
; 
1354             if ( item
->HasImage() ) 
1356                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 
1357                                     + (spacing 
- m_gi
->m_rectIcon
.width
)/2; 
1358                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
1361             if ( item
->HasText() ) 
1363                 if (m_gi
->m_rectAll
.width 
> spacing
) 
1364                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1366                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2 + (spacing
/2) - (m_gi
->m_rectLabel
.width
/2); 
1367                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
1368                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
1369                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
1371             else // no text, highlight the icon 
1373                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
1374                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
1379             m_gi
->m_rectAll
.x 
= x
; 
1380             m_gi
->m_rectAll
.y 
= y
; 
1382             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
1383             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
1384             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1386             if (item
->HasImage()) 
1388                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1389                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
1390                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 6 + m_gi
->m_rectIcon
.width
; 
1394                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
1399             wxFAIL_MSG( _T("unexpected call to SetPosition") ); 
1403             wxFAIL_MSG( _T("unknown mode") ); 
1407 void wxListLineData::InitItems( int num 
) 
1409     for (int i 
= 0; i 
< num
; i
++) 
1410         m_items
.Append( new wxListItemData(m_owner
) ); 
1413 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
1415     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1416     wxCHECK_RET( node
, _T("invalid column index in SetItem") ); 
1418     wxListItemData 
*item 
= node
->GetData(); 
1419     item
->SetItem( info 
); 
1422 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
1424     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1427         wxListItemData 
*item 
= node
->GetData(); 
1428         item
->GetItem( info 
); 
1432 wxString 
wxListLineData::GetText(int index
) const 
1436     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1439         wxListItemData 
*item 
= node
->GetData(); 
1440         s 
= item
->GetText(); 
1446 void wxListLineData::SetText( int index
, const wxString s 
) 
1448     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1451         wxListItemData 
*item 
= node
->GetData(); 
1456 void wxListLineData::SetImage( int index
, int image 
) 
1458     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1459     wxCHECK_RET( node
, _T("invalid column index in SetImage()") ); 
1461     wxListItemData 
*item 
= node
->GetData(); 
1462     item
->SetImage(image
); 
1465 int wxListLineData::GetImage( int index 
) const 
1467     wxListItemDataList::Node 
*node 
= m_items
.Item( index 
); 
1468     wxCHECK_MSG( node
, -1, _T("invalid column index in GetImage()") ); 
1470     wxListItemData 
*item 
= node
->GetData(); 
1471     return item
->GetImage(); 
1474 void wxListLineData::SetAttributes(wxDC 
*dc
, 
1475                                    const wxListItemAttr 
*attr
, 
1476                                    const wxColour
& colText
, 
1480     // don't use foregroud colour for drawing highlighted items - this might 
1481     // make them completely invisible (and there is no way to do bit 
1482     // arithmetics on wxColour, unfortunately) 
1483     if ( !highlight 
&& attr 
&& attr
->HasTextColour() ) 
1485         dc
->SetTextForeground(attr
->GetTextColour()); 
1489         dc
->SetTextForeground(colText
); 
1492     if ( attr 
&& attr
->HasFont() ) 
1494         dc
->SetFont(attr
->GetFont()); 
1502 void wxListLineData::Draw( wxDC 
*dc 
) 
1504     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1505     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1507     wxListItemData 
*item 
= node
->GetData(); 
1508     if (item
->HasImage()) 
1510         wxRect rectIcon 
= m_gi
->m_rectIcon
; 
1511         m_owner
->DrawImage( item
->GetImage(), dc
, 
1512                             rectIcon
.x
, rectIcon
.y 
); 
1515     if (item
->HasText()) 
1517         wxRect rectLabel 
= m_gi
->m_rectLabel
; 
1518         dc
->DrawText( item
->GetText(), rectLabel
.x
, rectLabel
.y 
); 
1522 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
1524                                        const wxRect
& rectHL
, 
1527     // use our own flag if we maintain it 
1529         highlighted 
= m_highlighted
; 
1531     // default foreground colour 
1532     wxWindow 
*listctrl 
= m_owner
->GetParent(); 
1536         colText 
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
); 
1540         colText 
= listctrl
->GetForegroundColour(); 
1544     wxFont font 
= listctrl
->GetFont(); 
1546     // VZ: currently we set the colours/fonts only once, but like this (i.e. 
1547     //     using SetAttributes() inside the loop), it will be trivial to 
1548     //     customize the subitems (in report mode) too. 
1549     wxListItemData 
*item 
= m_items
.GetFirst()->GetData(); 
1550     wxListItemAttr 
*attr 
= item
->GetAttributes(); 
1551     SetAttributes(dc
, attr
, colText
, font
, highlighted
); 
1553     bool hasBgCol 
= attr 
&& attr
->HasBackgroundColour(); 
1554     if ( highlighted 
|| hasBgCol 
) 
1558             dc
->SetBrush( *m_owner
->m_highlightBrush 
); 
1563                 dc
->SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
)); 
1565                 dc
->SetBrush( * wxWHITE_BRUSH 
); 
1568         dc
->SetPen( * wxTRANSPARENT_PEN 
); 
1569         dc
->DrawRectangle( rectHL 
); 
1572     wxListItemDataList::Node 
*node 
= m_items
.GetFirst(); 
1573     wxCHECK_RET( node
, _T("no subitems at all??") ); 
1576     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
1577             y 
= rect
.y 
+ (LINE_SPACING 
+ EXTRA_HEIGHT
) / 2; 
1581         wxListItemData 
*item 
= node
->GetData(); 
1585         if ( item
->HasImage() ) 
1588             m_owner
->DrawImage( item
->GetImage(), dc
, x
, y 
); 
1589             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
1590             x 
+= ix 
+ 5; // FIXME: what is "5"? 
1593         int width 
= m_owner
->GetColumnWidth(col
++); 
1595         wxDCClipper 
clipper(*dc
, x
, y
, width
, rect
.height
); 
1597         if ( item
->HasText() ) 
1599             dc
->DrawText( item
->GetText(), x
, y 
); 
1604         node 
= node
->GetNext(); 
1608 bool wxListLineData::Highlight( bool on 
) 
1610     wxCHECK_MSG( !m_owner
->IsVirtual(), FALSE
, _T("unexpected call to Highlight") ); 
1612     if ( on 
== m_highlighted 
) 
1620 void wxListLineData::ReverseHighlight( void ) 
1622     Highlight(!IsHighlighted()); 
1625 //----------------------------------------------------------------------------- 
1626 //  wxListHeaderWindow 
1627 //----------------------------------------------------------------------------- 
1629 IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow
,wxWindow
); 
1631 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
1632     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
1633     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
1634     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
1637 wxListHeaderWindow::wxListHeaderWindow( void ) 
1639     m_owner 
= (wxListMainWindow 
*) NULL
; 
1640     m_currentCursor 
= (wxCursor 
*) NULL
; 
1641     m_resizeCursor 
= (wxCursor 
*) NULL
; 
1642     m_isDragging 
= FALSE
; 
1645 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, wxWindowID id
, wxListMainWindow 
*owner
, 
1646       const wxPoint 
&pos
, const wxSize 
&size
, 
1647       long style
, const wxString 
&name 
) : 
1648   wxWindow( win
, id
, pos
, size
, style
, name 
) 
1651 //  m_currentCursor = wxSTANDARD_CURSOR; 
1652     m_currentCursor 
= (wxCursor 
*) NULL
; 
1653     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
1654     m_isDragging 
= FALSE
; 
1657     SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE 
) ); 
1660 wxListHeaderWindow::~wxListHeaderWindow( void ) 
1662     delete m_resizeCursor
; 
1665 void wxListHeaderWindow::DoDrawRect( wxDC 
*dc
, int x
, int y
, int w
, int h 
) 
1668     GtkStateType state 
= m_parent
->IsEnabled() ? GTK_STATE_NORMAL
 
1669                                                : GTK_STATE_INSENSITIVE
; 
1671     x 
= dc
->XLOG2DEV( x 
); 
1673     gtk_paint_box (m_wxwindow
->style
, GTK_PIZZA(m_wxwindow
)->bin_window
, 
1674                    state
, GTK_SHADOW_OUT
, 
1675                    (GdkRectangle
*) NULL
, m_wxwindow
, "button", 
1676                    x
-1, y
-1, w
+2, h
+2); 
1677 #elif defined( __WXMAC__  ) 
1678     const int m_corner 
= 1; 
1680     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
1682     dc
->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW 
) , 1 , wxSOLID 
) ); 
1683     dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h 
);  // right (outer) 
1684     dc
->DrawRectangle( x
, y
+h
, w
+1, 1 );          // bottom (outer) 
1686     wxPen 
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID 
); 
1689     dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h 
);  // right (inner) 
1690     dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 );      // bottom (inner) 
1692     dc
->SetPen( *wxWHITE_PEN 
); 
1693     dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 );   // top (outer) 
1694     dc
->DrawRectangle( x
, y
, 1, h 
);              // left (outer) 
1695     dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 ); 
1696     dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 ); 
1698     const int m_corner 
= 1; 
1700     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
1702     dc
->SetPen( *wxBLACK_PEN 
); 
1703     dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h 
);  // right (outer) 
1704     dc
->DrawRectangle( x
, y
+h
, w
+1, 1 );          // bottom (outer) 
1706     wxPen 
pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW 
), 1, wxSOLID 
); 
1709     dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h 
);  // right (inner) 
1710     dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 );      // bottom (inner) 
1712     dc
->SetPen( *wxWHITE_PEN 
); 
1713     dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 );   // top (outer) 
1714     dc
->DrawRectangle( x
, y
, 1, h 
);              // left (outer) 
1715     dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 ); 
1716     dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 ); 
1720 // shift the DC origin to match the position of the main window horz 
1721 // scrollbar: this allows us to always use logical coords 
1722 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
1725     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1728     m_owner
->GetViewStart( &x
, NULL 
); 
1730     // account for the horz scrollbar offset 
1731     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1734 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1737     wxClientDC 
dc( this ); 
1739     wxPaintDC 
dc( this ); 
1747     dc
.SetFont( GetFont() ); 
1749     // width and height of the entire header window 
1751     GetClientSize( &w
, &h 
); 
1752     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1754     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1756     // do *not* use the listctrl colour for headers - one day we will have a 
1757     // function to set it separately 
1758     //dc.SetTextForeground( *wxBLACK ); 
1759     dc
.SetTextForeground(wxSystemSettings:: 
1760                             GetSystemColour( wxSYS_COLOUR_WINDOWTEXT 
)); 
1762     int x 
= HEADER_OFFSET_X
; 
1764     int numColumns 
= m_owner
->GetColumnCount(); 
1766     for (int i 
= 0; i 
< numColumns
; i
++) 
1768         m_owner
->GetColumn( i
, item 
); 
1769         int wCol 
= item
.m_width
; 
1770         int cw 
= wCol 
- 2; // the width of the rect to draw 
1772         int xEnd 
= x 
+ wCol
; 
1774         dc
.SetPen( *wxWHITE_PEN 
); 
1776         DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 ); 
1777         dc
.SetClippingRegion( x
, HEADER_OFFSET_Y
, cw
-5, h
-4 ); 
1778         dc
.DrawText( item
.GetText(), x 
+ EXTRA_WIDTH
, HEADER_OFFSET_Y 
+ EXTRA_HEIGHT 
); 
1779         dc
.DestroyClippingRegion(); 
1788 void wxListHeaderWindow::DrawCurrent() 
1790     int x1 
= m_currentX
; 
1792     ClientToScreen( &x1
, &y1 
); 
1794     int x2 
= m_currentX
-1; 
1796     m_owner
->GetClientSize( NULL
, &y2 
); 
1797     m_owner
->ClientToScreen( &x2
, &y2 
); 
1800     dc
.SetLogicalFunction( wxINVERT 
); 
1801     dc
.SetPen( wxPen( *wxBLACK
, 2, wxSOLID 
) ); 
1802     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1806     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1808     dc
.SetLogicalFunction( wxCOPY 
); 
1810     dc
.SetPen( wxNullPen 
); 
1811     dc
.SetBrush( wxNullBrush 
); 
1814 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1816     // we want to work with logical coords 
1818     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1819     int y 
= event
.GetY(); 
1823         // we don't draw the line beyond our window, but we allow dragging it 
1826         GetClientSize( &w
, NULL 
); 
1827         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1830         // erase the line if it was drawn 
1831         if ( m_currentX 
< w 
) 
1834         if (event
.ButtonUp()) 
1837             m_isDragging 
= FALSE
; 
1839             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1846                 m_currentX 
= m_minX 
+ 7; 
1848             // draw in the new location 
1849             if ( m_currentX 
< w 
) 
1853     else // not dragging 
1856         bool hit_border 
= FALSE
; 
1858         // end of the current column 
1861         // find the column where this event occured 
1862         int countCol 
= m_owner
->GetColumnCount(); 
1863         for (int col 
= 0; col 
< countCol
; col
++) 
1865             xpos 
+= m_owner
->GetColumnWidth( col 
); 
1868             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
1870                 // near the column border 
1877                 // inside the column 
1884         if (event
.LeftDown()) 
1888                 m_isDragging 
= TRUE
; 
1895                 wxWindow 
*parent 
= GetParent(); 
1896                 wxListEvent 
le( wxEVT_COMMAND_LIST_COL_CLICK
, parent
->GetId() ); 
1897                 le
.SetEventObject( parent 
); 
1898                 le
.m_col 
= m_column
; 
1899                 parent
->GetEventHandler()->ProcessEvent( le 
); 
1902         else if (event
.Moving()) 
1907                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
1908                 m_currentCursor 
= m_resizeCursor
; 
1912                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
1913                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1917                 SetCursor(*m_currentCursor
); 
1922 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1924     m_owner
->SetFocus(); 
1927 //----------------------------------------------------------------------------- 
1928 // wxListRenameTimer (internal) 
1929 //----------------------------------------------------------------------------- 
1931 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
1936 void wxListRenameTimer::Notify() 
1938     m_owner
->OnRenameTimer(); 
1941 //----------------------------------------------------------------------------- 
1942 // wxListTextCtrl (internal) 
1943 //----------------------------------------------------------------------------- 
1945 IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl
,wxTextCtrl
); 
1947 BEGIN_EVENT_TABLE(wxListTextCtrl
,wxTextCtrl
) 
1948     EVT_CHAR           (wxListTextCtrl::OnChar
) 
1949     EVT_KEY_UP         (wxListTextCtrl::OnKeyUp
) 
1950     EVT_KILL_FOCUS     (wxListTextCtrl::OnKillFocus
) 
1953 wxListTextCtrl::wxListTextCtrl( wxWindow 
*parent
, 
1954                                 const wxWindowID id
, 
1957                                 wxListMainWindow 
*owner
, 
1958                                 const wxString 
&value
, 
1962                                 const wxValidator
& validator
, 
1963                                 const wxString 
&name 
) 
1964               : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name 
) 
1969     (*m_accept
) = FALSE
; 
1971     m_startValue 
= value
; 
1974 void wxListTextCtrl::OnChar( wxKeyEvent 
&event 
) 
1976     if (event
.m_keyCode 
== WXK_RETURN
) 
1979         (*m_res
) = GetValue(); 
1981         if (!wxPendingDelete
.Member(this)) 
1982             wxPendingDelete
.Append(this); 
1984         if ((*m_accept
) && ((*m_res
) != m_startValue
)) 
1985             m_owner
->OnRenameAccept(); 
1989     if (event
.m_keyCode 
== WXK_ESCAPE
) 
1991         (*m_accept
) = FALSE
; 
1994         if (!wxPendingDelete
.Member(this)) 
1995             wxPendingDelete
.Append(this); 
2003 void wxListTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
2005     // auto-grow the textctrl: 
2006     wxSize parentSize 
= m_owner
->GetSize(); 
2007     wxPoint myPos 
= GetPosition(); 
2008     wxSize mySize 
= GetSize(); 
2010     GetTextExtent(GetValue() + _T("MM"), &sx
, &sy
); // FIXME: MM?? 
2011     if (myPos
.x 
+ sx 
> parentSize
.x
) 
2012         sx 
= parentSize
.x 
- myPos
.x
; 
2020 void wxListTextCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
2022     if (!wxPendingDelete
.Member(this)) 
2023         wxPendingDelete
.Append(this); 
2025     if ((*m_accept
) && ((*m_res
) != m_startValue
)) 
2026         m_owner
->OnRenameAccept(); 
2029 //----------------------------------------------------------------------------- 
2031 //----------------------------------------------------------------------------- 
2033 IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow
,wxScrolledWindow
); 
2035 BEGIN_EVENT_TABLE(wxListMainWindow
,wxScrolledWindow
) 
2036   EVT_PAINT          (wxListMainWindow::OnPaint
) 
2037   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
2038   EVT_CHAR           (wxListMainWindow::OnChar
) 
2039   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
2040   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
2041   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
2042   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
2045 void wxListMainWindow::Init() 
2047     m_columns
.DeleteContents( TRUE 
); 
2051     m_lineTo 
= (size_t)-1; 
2057     m_small_image_list 
= (wxImageList 
*) NULL
; 
2058     m_normal_image_list 
= (wxImageList 
*) NULL
; 
2060     m_small_spacing 
= 30; 
2061     m_normal_spacing 
= 40; 
2065     m_isCreated 
= FALSE
; 
2067     m_lastOnSame 
= FALSE
; 
2068     m_renameTimer 
= new wxListRenameTimer( this ); 
2069     m_renameAccept 
= FALSE
; 
2074     m_lineBeforeLastClicked 
= (size_t)-1; 
2077 void wxListMainWindow::InitScrolling() 
2079     if ( HasFlag(wxLC_REPORT
) ) 
2081         m_xScroll 
= SCROLL_UNIT_X
; 
2082         m_yScroll 
= SCROLL_UNIT_Y
; 
2086         m_xScroll 
= SCROLL_UNIT_Y
; 
2091 wxListMainWindow::wxListMainWindow() 
2095     m_highlightBrush 
= (wxBrush 
*) NULL
; 
2101 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
2106                                     const wxString 
&name 
) 
2107                 : wxScrolledWindow( parent
, id
, pos
, size
, 
2108                                     style 
| wxHSCROLL 
| wxVSCROLL
, name 
) 
2112     m_highlightBrush 
= new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), wxSOLID 
); 
2117     SetScrollbars( m_xScroll
, m_yScroll
, 0, 0, 0, 0 ); 
2119     SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX 
) ); 
2122 wxListMainWindow::~wxListMainWindow() 
2126     delete m_highlightBrush
; 
2128     delete m_renameTimer
; 
2131 void wxListMainWindow::CacheLineData(size_t line
) 
2133     wxListCtrl 
*listctrl 
= GetListCtrl(); 
2135     wxListLineData 
*ld 
= GetDummyLine(); 
2137     size_t countCol 
= GetColumnCount(); 
2138     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
2140         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
2143     ld
->SetImage(listctrl
->OnGetItemImage(line
)); 
2146 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
2148     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); 
2150     if ( m_lines
.IsEmpty() ) 
2152         // normal controls are supposed to have something in m_lines 
2153         // already if it's not empty 
2154         wxASSERT_MSG( IsVirtual(), _T("logic error") ); 
2156         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2157         wxListLineData 
*line 
= new wxListLineData(self
); 
2158         self
->m_lines
.Add(line
); 
2164 // ---------------------------------------------------------------------------- 
2165 // line geometry (report mode only) 
2166 // ---------------------------------------------------------------------------- 
2168 wxCoord 
wxListMainWindow::GetLineHeight() const 
2170     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") ); 
2172     // we cache the line height as calling GetTextExtent() is slow 
2173     if ( !m_lineHeight 
) 
2175         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
2177         wxClientDC 
dc( self 
); 
2178         dc
.SetFont( GetFont() ); 
2181         dc
.GetTextExtent(_T("H"), NULL
, &y
); 
2183         if ( y 
< SCROLL_UNIT_Y 
) 
2187         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
2190     return m_lineHeight
; 
2193 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
2195     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("only works in report mode") ); 
2197     return LINE_SPACING 
+ line
*GetLineHeight(); 
2200 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
2202     if ( !InReportView() ) 
2203         return GetLine(line
)->m_gi
->m_rectAll
; 
2206     rect
.x 
= HEADER_OFFSET_X
; 
2207     rect
.y 
= GetLineY(line
); 
2208     rect
.width 
= GetHeaderWidth(); 
2209     rect
.height 
= GetLineHeight(); 
2214 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
2216     if ( !InReportView() ) 
2217         return GetLine(line
)->m_gi
->m_rectLabel
; 
2220     rect
.x 
= HEADER_OFFSET_X
; 
2221     rect
.y 
= GetLineY(line
); 
2222     rect
.width 
= GetColumnWidth(0); 
2223     rect
.height 
= GetLineHeight(); 
2228 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
2230     if ( !InReportView() ) 
2231         return GetLine(line
)->m_gi
->m_rectIcon
; 
2233     wxListLineData 
*ld 
= GetLine(line
); 
2234     wxASSERT_MSG( ld
->HasImage(), _T("should have an image") ); 
2237     rect
.x 
= HEADER_OFFSET_X
; 
2238     rect
.y 
= GetLineY(line
); 
2239     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
2244 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
2246     return InReportView() ? GetLineRect(line
) 
2247                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
2250 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
2252     wxListLineData 
*ld 
= GetLine(line
); 
2254     if ( ld
->HasImage() && GetLineIconRect(line
).Inside(x
, y
) ) 
2255         return wxLIST_HITTEST_ONITEMICON
; 
2257     if ( ld
->HasText() ) 
2259         wxRect rect 
= InReportView() ? GetLineRect(line
) 
2260                                      : GetLineLabelRect(line
); 
2262         if ( rect
.Inside(x
, y
) ) 
2263             return wxLIST_HITTEST_ONITEMLABEL
; 
2269 // ---------------------------------------------------------------------------- 
2270 // highlight (selection) handling 
2271 // ---------------------------------------------------------------------------- 
2273 bool wxListMainWindow::IsHighlighted(size_t line
) const 
2277         return m_selStore
.IsSelected(line
); 
2281         wxListLineData 
*ld 
= GetLine(line
); 
2282         wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") ); 
2284         return ld
->IsHighlighted(); 
2288 void wxListMainWindow::HighlightLines( size_t lineFrom
, size_t lineTo
, bool highlight 
) 
2292         m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
); 
2293         RefreshLines(lineFrom
, lineTo
); 
2297         // do it the dumb way 
2298         bool needsRefresh 
= FALSE
; 
2299         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2301             if ( HighlightLine(line
, highlight
) ) 
2302                 needsRefresh 
= TRUE
; 
2306             RefreshLines(lineFrom
, lineTo
); 
2310 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
2316         changed 
= m_selStore
.SelectItem(line
, highlight
); 
2320         wxListLineData 
*ld 
= GetLine(line
); 
2321         wxCHECK_MSG( ld
, FALSE
, _T("invalid index in IsHighlighted") ); 
2323         changed 
= ld
->Highlight(highlight
); 
2328         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2329                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
2335 void wxListMainWindow::RefreshLine( size_t line 
) 
2337     wxRect rect 
= GetLineRect(line
); 
2339     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2340     RefreshRect( rect 
); 
2343 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
2345     // we suppose that they are ordered by caller 
2346     wxASSERT_MSG( lineFrom 
<= lineTo
, _T("indices in disorder") ); 
2348     wxASSERT_MSG( lineTo 
< GetItemCount(), _T("invalid line range") ); 
2350     if ( HasFlag(wxLC_REPORT
) ) 
2352         size_t visibleFrom
, visibleTo
; 
2353         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2355         if ( lineFrom 
< visibleFrom 
) 
2356             lineFrom 
= visibleFrom
; 
2357         if ( lineTo 
> visibleTo 
) 
2362         rect
.y 
= GetLineY(lineFrom
); 
2363         rect
.width 
= GetClientSize().x
; 
2364         rect
.height 
= GetLineY(lineTo
) - rect
.y
; 
2366         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2367         RefreshRect( rect 
); 
2371         // TODO: this should be optimized... 
2372         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
2379 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
2381     if ( HasFlag(wxLC_REPORT
) ) 
2384         GetVisibleLinesRange(&visibleFrom
, NULL
); 
2386         if ( lineFrom 
< visibleFrom 
) 
2387             lineFrom 
= visibleFrom
; 
2391         rect
.y 
= GetLineY(lineFrom
); 
2393         wxSize size 
= GetClientSize(); 
2394         rect
.width 
= size
.x
; 
2395         // refresh till the bottom of the window 
2396         rect
.height 
= size
.y 
- rect
.y
; 
2398         CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2399         RefreshRect( rect 
); 
2404         // TODO: how to do it more efficiently? 
2409 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2411     // Note: a wxPaintDC must be constructed even if no drawing is 
2412     // done (a Windows requirement). 
2413     wxPaintDC 
dc( this ); 
2417         // empty control. nothing to draw 
2424     CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2428     dc
.SetFont( GetFont() ); 
2430     if ( HasFlag(wxLC_REPORT
) ) 
2432         int lineHeight 
= GetLineHeight(); 
2434         size_t visibleFrom
, visibleTo
; 
2435         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2436         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2438             GetLine(line
)->DrawInReportMode( &dc
, 
2440                                              GetLineHighlightRect(line
), 
2441                                              IsHighlighted(line
) ); 
2444         if ( HasFlag(wxLC_HRULES
) ) 
2446             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2447             wxSize clientSize 
= GetClientSize(); 
2449             for ( size_t i 
= visibleFrom
; i 
<= visibleTo
; i
++ ) 
2452                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2453                 dc
.DrawLine(0 - dev_x
, i
*lineHeight
, 
2454                             clientSize
.x 
- dev_x
, i
*lineHeight
); 
2457             // Draw last horizontal rule 
2458             if ( visibleTo 
> visibleFrom 
) 
2461                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2462                 dc
.DrawLine(0 - dev_x
, m_lineTo
*lineHeight
, 
2463                             clientSize
.x 
- dev_x 
, m_lineTo
*lineHeight 
); 
2467         // Draw vertical rules if required 
2468         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2470             wxPen 
pen(GetRuleColour(), 1, wxSOLID
); 
2473             wxRect firstItemRect
; 
2474             wxRect lastItemRect
; 
2475             GetItemRect(0, firstItemRect
); 
2476             GetItemRect(GetItemCount() - 1, lastItemRect
); 
2477             int x 
= firstItemRect
.GetX(); 
2479             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2480             for (col 
= 0; col 
< GetColumnCount(); col
++) 
2482                 int colWidth 
= GetColumnWidth(col
); 
2484                 dc
.DrawLine(x 
- dev_x
, firstItemRect
.GetY() - 1 - dev_y
, 
2485                             x 
- dev_x
, lastItemRect
.GetBottom() + 1 - dev_y
); 
2491         size_t count 
= GetItemCount(); 
2492         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2494             GetLine(i
)->Draw( &dc 
); 
2498     if ( HasCurrent() && m_hasFocus 
) 
2501         // no rect outline, we already have the background color 
2503         dc
.SetPen( *wxBLACK_PEN 
); 
2504         dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2505         dc
.DrawRectangle( GetLineHighlightRect(m_current
) ); 
2512 void wxListMainWindow::HighlightAll( bool on 
) 
2514     if ( IsSingleSel() ) 
2516         wxASSERT_MSG( !on
, _T("can't do this in a single sel control") ); 
2518         // we just have one item to turn off 
2519         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2521             HighlightLine(m_current
, FALSE
); 
2522             RefreshLine(m_current
); 
2527         HighlightLines(0, GetItemCount() - 1, on
); 
2531 void wxListMainWindow::SendNotify( size_t line
, 
2532                                    wxEventType command
, 
2535     wxListEvent 
le( command
, GetParent()->GetId() ); 
2536     le
.SetEventObject( GetParent() ); 
2537     le
.m_itemIndex 
= line
; 
2539     // set only for events which have position 
2540     if ( point 
!= wxDefaultPosition 
) 
2541         le
.m_pointDrag 
= point
; 
2543     GetLine(line
)->GetItem( 0, le
.m_item 
); 
2544     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2547 void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line
) ) 
2549 //  SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED ); 
2552 void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line
) ) 
2554 //  SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED ); 
2557 void wxListMainWindow::EditLabel( long item 
) 
2559     wxCHECK_RET( (item 
>= 0) && ((size_t)item 
< GetItemCount()), 
2560                  wxT("wrong index in wxListCtrl::EditLabel()") ); 
2562     m_currentEdit 
= (size_t)item
; 
2564     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2565     le
.SetEventObject( GetParent() ); 
2566     le
.m_itemIndex 
= item
; 
2567     wxListLineData 
*data 
= GetLine(m_currentEdit
); 
2568     wxCHECK_RET( data
, _T("invalid index in EditLabel()") ); 
2569     data
->GetItem( 0, le
.m_item 
); 
2570     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2572     if (!le
.IsAllowed()) 
2575     // We have to call this here because the label in question might just have 
2576     // been added and no screen update taken place. 
2580     wxClientDC 
dc(this); 
2583     wxString s 
= data
->GetText(0); 
2584     wxRect rectLabel 
= GetLineLabelRect(m_currentEdit
); 
2586     rectLabel
.x 
= dc
.LogicalToDeviceX( rectLabel
.x 
); 
2587     rectLabel
.y 
= dc
.LogicalToDeviceY( rectLabel
.y 
); 
2589     wxListTextCtrl 
*text 
= new wxListTextCtrl
 
2596                                 wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
2597                                 wxSize(rectLabel
.width
+11,rectLabel
.height
+8) 
2602 void wxListMainWindow::OnRenameTimer() 
2604     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2606     EditLabel( m_current 
); 
2609 void wxListMainWindow::OnRenameAccept() 
2611     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2612     le
.SetEventObject( GetParent() ); 
2613     le
.m_itemIndex 
= m_currentEdit
; 
2615     wxListLineData 
*data 
= GetLine(m_currentEdit
); 
2616     wxCHECK_RET( data
, _T("invalid index in OnRenameAccept()") ); 
2618     data
->GetItem( 0, le
.m_item 
); 
2619     le
.m_item
.m_text 
= m_renameRes
; 
2620     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2622     if (!le
.IsAllowed()) return; 
2625     info
.m_mask 
= wxLIST_MASK_TEXT
; 
2626     info
.m_itemId 
= le
.m_itemIndex
; 
2627     info
.m_text 
= m_renameRes
; 
2628     info
.SetTextColour(le
.m_item
.GetTextColour()); 
2632 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2634     event
.SetEventObject( GetParent() ); 
2635     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2638     if ( !HasCurrent() || IsEmpty() ) 
2644     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
2645         event
.ButtonDClick()) ) 
2648     int x 
= event
.GetX(); 
2649     int y 
= event
.GetY(); 
2650     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2652     /* Did we actually hit an item ? */ 
2655     size_t count 
= GetItemCount(), 
2658     if ( HasFlag(wxLC_REPORT
) ) 
2660         current 
= y 
/ GetLineHeight(); 
2661         hitResult 
= HitTestLine(current
, x
, y
); 
2665         // TODO: optimize it too! this is less simple than for report view but 
2666         //       enumerating all items is still not a way to do it!! 
2667         for ( current 
= 0; current 
< count 
&& !hitResult
; current
++ ) 
2669             hitResult 
= HitTestLine(current
, x
, y
); 
2673     if (event
.Dragging()) 
2675         if (m_dragCount 
== 0) 
2676             m_dragStart 
= wxPoint(x
,y
); 
2680         if (m_dragCount 
!= 3) 
2683         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
2684                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2686         wxListEvent 
le( command
, GetParent()->GetId() ); 
2687         le
.SetEventObject( GetParent() ); 
2688         le
.m_pointDrag 
= m_dragStart
; 
2689         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2700         // outside of any item 
2704     bool forceClick 
= FALSE
; 
2705     if (event
.ButtonDClick()) 
2707         m_renameTimer
->Stop(); 
2708         m_lastOnSame 
= FALSE
; 
2710         if ( current 
== m_lineBeforeLastClicked 
) 
2712             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2718             // the first click was on another item, so don't interpret this as 
2719             // a double click, but as a simple click instead 
2724     if (event
.LeftUp() && m_lastOnSame
) 
2726         if ((current 
== m_current
) && 
2727             (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
2728             HasFlag(wxLC_EDIT_LABELS
)  ) 
2730             m_renameTimer
->Start( 100, TRUE 
); 
2732         m_lastOnSame 
= FALSE
; 
2734     else if (event
.RightDown()) 
2736         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, 
2737                     event
.GetPosition() ); 
2739     else if (event
.MiddleDown()) 
2741         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
2743     else if ( event
.LeftDown() || forceClick 
) 
2745         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2746         m_lineLastClicked 
= current
; 
2748         size_t oldCurrent 
= m_current
; 
2750         if ( IsSingleSel() || !(event
.ControlDown() || event
.ShiftDown()) ) 
2752             HighlightAll( FALSE 
); 
2753             m_current 
= current
; 
2755             ReverseHighlight(m_current
); 
2757         else // multi sel & either ctrl or shift is down 
2759             if (event
.ControlDown()) 
2761                 m_current 
= current
; 
2763                 ReverseHighlight(m_current
); 
2765             else if (event
.ShiftDown()) 
2767                 m_current 
= current
; 
2769                 size_t lineFrom 
= oldCurrent
, 
2772                 if ( lineTo 
< lineFrom 
) 
2775                     lineFrom 
= m_current
; 
2778                 HighlightLines(lineFrom
, lineTo
); 
2780             else // !ctrl, !shift 
2782                 // test in the enclosing if should make it impossible 
2783                 wxFAIL_MSG( _T("how did we get here?") ); 
2787         if (m_current 
!= oldCurrent
) 
2789             RefreshLine( oldCurrent 
); 
2790             OnUnfocusLine( oldCurrent 
); 
2791             OnFocusLine( m_current 
); 
2794         // forceClick is only set if the previous click was on another item 
2795         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
); 
2799 void wxListMainWindow::MoveToFocus() 
2801     if ( !HasCurrent() ) 
2804     wxRect rect 
= GetLineRect(m_current
); 
2806     int client_w
, client_h
; 
2807     GetClientSize( &client_w
, &client_h 
); 
2809     int view_x 
= m_xScroll
*GetScrollPos( wxHORIZONTAL 
); 
2810     int view_y 
= m_yScroll
*GetScrollPos( wxVERTICAL 
); 
2812     if ( HasFlag(wxLC_REPORT
) ) 
2814         // the next we need the range of lines shown it might be different, so 
2816         ResetVisibleLinesRange(); 
2818         if (rect
.y 
< view_y 
) 
2819             Scroll( -1, rect
.y
/m_yScroll 
); 
2820         if (rect
.y
+rect
.height
+5 > view_y
+client_h
) 
2821             Scroll( -1, (rect
.y
+rect
.height
-client_h
+SCROLL_UNIT_Y
)/m_yScroll 
); 
2825         if (rect
.x
-view_x 
< 5) 
2826             Scroll( (rect
.x
-5)/m_xScroll
, -1 ); 
2827         if (rect
.x
+rect
.width
-5 > view_x
+client_w
) 
2828             Scroll( (rect
.x
+rect
.width
-client_w
+SCROLL_UNIT_X
)/m_xScroll
, -1 ); 
2832 // ---------------------------------------------------------------------------- 
2833 // keyboard handling 
2834 // ---------------------------------------------------------------------------- 
2836 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
2838     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
2839                  _T("invalid item index in OnArrowChar()") ); 
2841     size_t oldCurrent 
= m_current
; 
2843     // in single selection we just ignore Shift as we can't select several 
2845     if ( event
.ShiftDown() && !IsSingleSel() ) 
2847         m_current 
= newCurrent
; 
2849         // select all the items between the old and the new one 
2850         if ( oldCurrent 
> newCurrent 
) 
2852             newCurrent 
= oldCurrent
; 
2853             oldCurrent 
= m_current
; 
2856         HighlightLines(oldCurrent
, newCurrent
); 
2860         // all previously selected items are unselected unless ctrl is held 
2861         if ( !event
.ControlDown() ) 
2862             HighlightAll(FALSE
); 
2864         m_current 
= newCurrent
; 
2866         HighlightLine( oldCurrent
, FALSE 
); 
2867         RefreshLine( oldCurrent 
); 
2869         if ( !event
.ControlDown() ) 
2871             HighlightLine( m_current
, TRUE 
); 
2875     OnUnfocusLine( oldCurrent 
); 
2876     OnFocusLine( m_current 
); 
2877     RefreshLine( m_current 
); 
2882 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
2884     wxWindow 
*parent 
= GetParent(); 
2886     /* we propagate the key event up */ 
2887     wxKeyEvent 
ke( wxEVT_KEY_DOWN 
); 
2888     ke
.m_shiftDown 
= event
.m_shiftDown
; 
2889     ke
.m_controlDown 
= event
.m_controlDown
; 
2890     ke
.m_altDown 
= event
.m_altDown
; 
2891     ke
.m_metaDown 
= event
.m_metaDown
; 
2892     ke
.m_keyCode 
= event
.m_keyCode
; 
2895     ke
.SetEventObject( parent 
); 
2896     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
2901 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
2903     wxWindow 
*parent 
= GetParent(); 
2905     /* we send a list_key event up */ 
2908         wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, GetParent()->GetId() ); 
2909         le
.m_itemIndex 
= m_current
; 
2910         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
2911         le
.m_code 
= (int)event
.KeyCode(); 
2912         le
.SetEventObject( parent 
); 
2913         parent
->GetEventHandler()->ProcessEvent( le 
); 
2916     /* we propagate the char event up */ 
2917     wxKeyEvent 
ke( wxEVT_CHAR 
); 
2918     ke
.m_shiftDown 
= event
.m_shiftDown
; 
2919     ke
.m_controlDown 
= event
.m_controlDown
; 
2920     ke
.m_altDown 
= event
.m_altDown
; 
2921     ke
.m_metaDown 
= event
.m_metaDown
; 
2922     ke
.m_keyCode 
= event
.m_keyCode
; 
2925     ke
.SetEventObject( parent 
); 
2926     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) return; 
2928     if (event
.KeyCode() == WXK_TAB
) 
2930         wxNavigationKeyEvent nevent
; 
2931         nevent
.SetWindowChange( event
.ControlDown() ); 
2932         nevent
.SetDirection( !event
.ShiftDown() ); 
2933         nevent
.SetEventObject( GetParent()->GetParent() ); 
2934         nevent
.SetCurrentFocus( m_parent 
); 
2935         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent 
)) return; 
2938     /* no item -> nothing to do */ 
2945     switch (event
.KeyCode()) 
2948             if ( m_current 
> 0 ) 
2949                 OnArrowChar( m_current 
- 1, event 
); 
2953             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
2954                 OnArrowChar( m_current 
+ 1, event 
); 
2959                 OnArrowChar( GetItemCount() - 1, event 
); 
2964                 OnArrowChar( 0, event 
); 
2970                 if ( HasFlag(wxLC_REPORT
) ) 
2972                     steps 
= m_linesPerPage 
- 1; 
2976                     steps 
= m_current 
% m_linesPerPage
; 
2979                 int index 
= m_current 
- steps
; 
2983                 OnArrowChar( index
, event 
); 
2990                 if ( HasFlag(wxLC_REPORT
) ) 
2992                     steps 
= m_linesPerPage 
- 1; 
2996                     steps 
= m_linesPerPage 
- (m_current 
% m_linesPerPage
) - 1; 
2999                 size_t index 
= m_current 
+ steps
; 
3000                 size_t count 
= GetItemCount(); 
3001                 if ( index 
>= count 
) 
3004                 OnArrowChar( index
, event 
); 
3009             if ( !HasFlag(wxLC_REPORT
) ) 
3011                 int index 
= m_current 
- m_linesPerPage
; 
3015                 OnArrowChar( index
, event 
); 
3020             if ( !HasFlag(wxLC_REPORT
) ) 
3022                 size_t index 
= m_current 
+ m_linesPerPage
; 
3024                 size_t count 
= GetItemCount(); 
3025                 if ( index 
>= count 
) 
3028                 OnArrowChar( index
, event 
); 
3033             if ( IsSingleSel() ) 
3035                 wxListEvent 
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
, 
3036                                 GetParent()->GetId() ); 
3037                 le
.SetEventObject( GetParent() ); 
3038                 le
.m_itemIndex 
= m_current
; 
3039                 GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3040                 GetParent()->GetEventHandler()->ProcessEvent( le 
); 
3044                 ReverseHighlight(m_current
); 
3051                 wxListEvent 
le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED
, 
3052                                 GetParent()->GetId() ); 
3053                 le
.SetEventObject( GetParent() ); 
3054                 le
.m_itemIndex 
= m_current
; 
3055                 GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
3056                 GetParent()->GetEventHandler()->ProcessEvent( le 
); 
3065 // ---------------------------------------------------------------------------- 
3067 // ---------------------------------------------------------------------------- 
3070 extern wxWindow 
*g_focusWindow
; 
3073 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3078         RefreshLine( m_current 
); 
3084     g_focusWindow 
= GetParent(); 
3087     wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
3088     event
.SetEventObject( GetParent() ); 
3089     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
3092 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
3097         RefreshLine( m_current 
); 
3100 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
3102     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
3104         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3106     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
3108         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3110     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
3112         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3114     else if ( HasFlag(wxLC_REPORT
) && (m_small_image_list
)) 
3116         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3120 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
3122     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3124         m_normal_image_list
->GetSize( index
, width
, height 
); 
3126     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3128         m_small_image_list
->GetSize( index
, width
, height 
); 
3130     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
3132         m_small_image_list
->GetSize( index
, width
, height 
); 
3134     else if ( HasFlag(wxLC_REPORT
) && m_small_image_list 
) 
3136         m_small_image_list
->GetSize( index
, width
, height 
); 
3145 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
3147     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
3148     dc
.SetFont( GetFont() ); 
3151     dc
.GetTextExtent( s
, &lw
, NULL 
); 
3153     return lw 
+ AUTOSIZE_COL_MARGIN
; 
3156 void wxListMainWindow::SetImageList( wxImageList 
*imageList
, int which 
) 
3160     // calc the spacing from the icon size 
3163     if ((imageList
) && (imageList
->GetImageCount()) ) 
3165         imageList
->GetSize(0, width
, height
); 
3168     if (which 
== wxIMAGE_LIST_NORMAL
) 
3170         m_normal_image_list 
= imageList
; 
3171         m_normal_spacing 
= width 
+ 8; 
3174     if (which 
== wxIMAGE_LIST_SMALL
) 
3176         m_small_image_list 
= imageList
; 
3177         m_small_spacing 
= width 
+ 14; 
3181 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
3186         m_small_spacing 
= spacing
; 
3190         m_normal_spacing 
= spacing
; 
3194 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3196     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3199 // ---------------------------------------------------------------------------- 
3201 // ---------------------------------------------------------------------------- 
3203 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3205     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3207     wxCHECK_RET( node
, _T("invalid column index in SetColumn") ); 
3209     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3210         item
.m_width 
= GetTextLength( item
.m_text 
); 
3212     wxListHeaderData 
*column 
= node
->GetData(); 
3213     column
->SetItem( item 
); 
3215     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3217         headerWin
->m_dirty 
= TRUE
; 
3221     // invalidate it as it has to be recalculated 
3225 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3227     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3228                  _T("invalid column index") ); 
3230     wxCHECK_RET( HasFlag(wxLC_REPORT
), 
3231                  _T("SetColumnWidth() can only be called in report mode.") ); 
3235     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3236     wxCHECK_RET( node
, _T("no column?") ); 
3238     wxListHeaderData 
*column 
= node
->GetData(); 
3240     size_t count 
= GetItemCount(); 
3242     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3244         width 
= GetTextLength(column
->GetText()); 
3246     else if ( width 
== wxLIST_AUTOSIZE 
) 
3250             // TODO: determine the max width somehow... 
3251             width 
= WIDTH_COL_DEFAULT
; 
3255             wxClientDC 
dc(this); 
3256             dc
.SetFont( GetFont() ); 
3258             int max 
= AUTOSIZE_COL_MARGIN
; 
3260             for ( size_t i 
= 0; i 
< count
; i
++ ) 
3262                 wxListLineData 
*line 
= GetLine(i
); 
3263                 wxListItemDataList::Node 
*n 
= line
->m_items
.Item( col 
); 
3265                 wxCHECK_RET( n
, _T("no subitem?") ); 
3267                 wxListItemData 
*item 
= n
->GetData(); 
3270                 if (item
->HasImage()) 
3273                     GetImageSize( item
->GetImage(), ix
, iy 
); 
3277                 if (item
->HasText()) 
3280                     dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
3288             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3292     column
->SetWidth( width 
); 
3294     // invalidate it as it has to be recalculated 
3298 int wxListMainWindow::GetHeaderWidth() const 
3300     if ( !m_headerWidth 
) 
3302         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3304         size_t count 
= GetColumnCount(); 
3305         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3307             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3311     return m_headerWidth
; 
3314 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3316     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3317     wxCHECK_RET( node
, _T("invalid column index in GetColumn") ); 
3319     wxListHeaderData 
*column 
= node
->GetData(); 
3320     column
->GetItem( item 
); 
3323 int wxListMainWindow::GetColumnWidth( int col 
) const 
3325     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3326     wxCHECK_MSG( node
, 0, _T("invalid column index") ); 
3328     wxListHeaderData 
*column 
= node
->GetData(); 
3329     return column
->GetWidth(); 
3332 // ---------------------------------------------------------------------------- 
3334 // ---------------------------------------------------------------------------- 
3336 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3338     long id 
= item
.m_itemId
; 
3339     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3340                  _T("invalid item index in SetItem") ); 
3344         // just refresh the line to show the new value of the text/image 
3345         RefreshLine((size_t)id
); 
3351         wxListLineData 
*line 
= GetLine((size_t)id
); 
3352         if ( HasFlag(wxLC_REPORT
) ) 
3353             item
.m_width 
= GetColumnWidth( item
.m_col 
); 
3354         line
->SetItem( item
.m_col
, item 
); 
3358 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3360      wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3361                   _T("invalid list ctrl item index in SetItem") ); 
3363     size_t oldCurrent 
= m_current
; 
3364     size_t item 
= (size_t)litem
;    // sdafe because of the check above 
3366     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3368         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3370             // don't do anything if this item is already focused 
3371             if ( item 
!= m_current 
) 
3373                 OnUnfocusLine( m_current 
); 
3375                 OnFocusLine( m_current 
); 
3377                 if ( IsSingleSel() && (oldCurrent 
!= (size_t)-1) ) 
3379                     HighlightLine(oldCurrent
, FALSE
); 
3380                     RefreshLine(oldCurrent
); 
3383                 RefreshLine( m_current 
); 
3388             // don't do anything if this item is not focused 
3389             if ( item 
== m_current 
) 
3391                 OnUnfocusLine( m_current 
); 
3392                 m_current 
= (size_t)-1; 
3397     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3399         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3401         if ( IsSingleSel() ) 
3405                 // selecting the item also makes it the focused one in the 
3407                 if ( m_current 
!= item 
) 
3409                     OnUnfocusLine( m_current 
); 
3411                     OnFocusLine( m_current 
); 
3413                     if ( oldCurrent 
!= (size_t)-1 ) 
3415                         HighlightLine( oldCurrent
, FALSE 
); 
3416                         RefreshLine( oldCurrent 
); 
3422                 // only the current item may be selected anyhow 
3423                 if ( item 
!= m_current 
) 
3428         if ( HighlightLine(item
, on
) ) 
3435 int wxListMainWindow::GetItemState( long item
, long stateMask 
) 
3437     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3438                  _T("invalid list ctrl item index in GetItemState()") ); 
3440     int ret 
= wxLIST_STATE_DONTCARE
; 
3442     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3444         if ( (size_t)item 
== m_current 
) 
3445             ret 
|= wxLIST_STATE_FOCUSED
; 
3448     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3450         if ( IsHighlighted(item
) ) 
3451             ret 
|= wxLIST_STATE_SELECTED
; 
3457 void wxListMainWindow::GetItem( wxListItem 
&item 
) 
3459     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3460                  _T("invalid item index in GetItem") ); 
3462     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3463     line
->GetItem( item
.m_col
, item 
); 
3466 // ---------------------------------------------------------------------------- 
3468 // ---------------------------------------------------------------------------- 
3470 size_t wxListMainWindow::GetItemCount() const 
3472     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3475 void wxListMainWindow::SetItemCount(long count
) 
3477     m_selStore
.SetItemCount(count
); 
3478     m_countVirt 
= count
; 
3483 int wxListMainWindow::GetSelectedItemCount() 
3485     // deal with the quick case first 
3486     if ( IsSingleSel() ) 
3488         return HasCurrent() ? IsHighlighted(m_current
) : FALSE
; 
3491     // virtual controls remmebers all its selections itself 
3493         return m_selStore
.GetSelectedCount(); 
3495     // TODO: we probably should maintain the number of items selected even for 
3496     //       non virtual controls as enumerating all lines is really slow... 
3497     size_t countSel 
= 0; 
3498     size_t count 
= GetItemCount(); 
3499     for ( size_t line 
= 0; line 
< count
; line
++ ) 
3501         if ( GetLine(line
)->IsHighlighted() ) 
3508 // ---------------------------------------------------------------------------- 
3509 // item position/size 
3510 // ---------------------------------------------------------------------------- 
3512 void wxListMainWindow::GetItemRect( long index
, wxRect 
&rect 
) 
3514     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3515                  _T("invalid index in GetItemRect") ); 
3517     rect 
= GetLineRect((size_t)index
); 
3519     CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
3522 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) 
3525     GetItemRect(item
, rect
); 
3533 // ---------------------------------------------------------------------------- 
3534 // geometry calculation 
3535 // ---------------------------------------------------------------------------- 
3537 void wxListMainWindow::RecalculatePositions() 
3542     wxClientDC 
dc( this ); 
3543     dc
.SetFont( GetFont() ); 
3546     if ( HasFlag(wxLC_ICON
) ) 
3547         iconSpacing 
= m_normal_spacing
; 
3548     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
3549         iconSpacing 
= m_small_spacing
; 
3555     GetClientSize( &clientWidth
, &clientHeight 
); 
3557     if ( HasFlag(wxLC_REPORT
) ) 
3559         // all lines have the same height 
3560         int lineHeight 
= GetLineHeight(); 
3562         // scroll one line per step 
3563         m_yScroll 
= lineHeight
; 
3565         size_t lineCount 
= GetItemCount(); 
3566         int entireHeight 
= lineCount
*lineHeight 
+ LINE_SPACING
; 
3568         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
3570         ResetVisibleLinesRange(); 
3572         SetScrollbars( m_xScroll
, m_yScroll
, 
3573                        (GetHeaderWidth() + m_xScroll 
- 1)/m_xScroll
, 
3574                        (entireHeight 
+ m_yScroll 
- 1)/m_yScroll
, 
3575                        GetScrollPos(wxHORIZONTAL
), 
3576                        GetScrollPos(wxVERTICAL
), 
3581         // at first we try without any scrollbar. if the items don't 
3582         // fit into the window, we recalculate after subtracting an 
3583         // approximated 15 pt for the horizontal scrollbar 
3585         clientHeight 
-= 4;  // sunken frame 
3587         int entireWidth 
= 0; 
3589         for (int tries 
= 0; tries 
< 2; tries
++) 
3596             int currentlyVisibleLines 
= 0; 
3598             size_t count 
= GetItemCount(); 
3599             for (size_t i 
= 0; i 
< count
; i
++) 
3601                 currentlyVisibleLines
++; 
3602                 wxListLineData 
*line 
= GetLine(i
); 
3603                 line
->CalculateSize( &dc
, iconSpacing 
); 
3604                 line
->SetPosition( x
, y
, clientWidth
, iconSpacing 
); 
3606                 wxSize sizeLine 
= GetLineSize(i
); 
3608                 if ( maxWidth 
< sizeLine
.x 
) 
3609                     maxWidth 
= sizeLine
.x
; 
3612                 if (currentlyVisibleLines 
> m_linesPerPage
) 
3613                     m_linesPerPage 
= currentlyVisibleLines
; 
3615                 // assume that the size of the next one is the same... (FIXME) 
3616                 if ( y 
+ sizeLine
.y 
- 6 >= clientHeight 
) 
3618                     currentlyVisibleLines 
= 0; 
3621                     entireWidth 
+= maxWidth
+6; 
3624                 if ( i 
== count 
- 1 ) 
3625                     entireWidth 
+= maxWidth
; 
3626                 if ((tries 
== 0) && (entireWidth 
> clientWidth
)) 
3628                     clientHeight 
-= 15; // scrollbar height 
3630                     currentlyVisibleLines 
= 0; 
3633                 if ( i 
== count 
- 1 ) 
3634                     tries 
= 1;  // everything fits, no second try required 
3638         int scroll_pos 
= GetScrollPos( wxHORIZONTAL 
); 
3639         SetScrollbars( m_xScroll
, m_yScroll
, (entireWidth
+SCROLL_UNIT_X
) / m_xScroll
, 0, scroll_pos
, 0, TRUE 
); 
3642     // FIXME: why should we call it from here? 
3648 void wxListMainWindow::RefreshAll() 
3653     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3656         headerWin
->m_dirty 
= FALSE
; 
3657         headerWin
->Refresh(); 
3661 void wxListMainWindow::UpdateCurrent() 
3663     if ( !HasCurrent() && !IsEmpty() ) 
3668     if ( m_current 
!= (size_t)-1 ) 
3670         OnFocusLine( m_current 
); 
3674 long wxListMainWindow::GetNextItem( long item
, 
3675                                     int WXUNUSED(geometry
), 
3679          max 
= GetItemCount(); 
3680     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
3681                  _T("invalid listctrl index in GetNextItem()") ); 
3683     // notice that we start with the next item (or the first one if item == -1) 
3684     // and this is intentional to allow writing a simple loop to iterate over 
3685     // all selected items 
3689         // this is not an error because the index was ok initially, just no 
3700     size_t count 
= GetItemCount(); 
3701     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
3703         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
3706         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
3713 // ---------------------------------------------------------------------------- 
3715 // ---------------------------------------------------------------------------- 
3717 void wxListMainWindow::DeleteItem( long lindex 
) 
3719     size_t count 
= GetItemCount(); 
3721     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
3722                  _T("invalid item index in DeleteItem") ); 
3724     size_t index 
= (size_t)lindex
; 
3728     // select the next item when the selected one is deleted 
3729     if ( m_current 
== index 
) 
3731         // the last valid index after deleting the item will be count-2 
3732         if ( m_current 
== count 
- 1 ) 
3738     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM 
); 
3740     if ( InReportView() ) 
3742         ResetVisibleLinesRange(); 
3749         m_selStore
.OnItemDelete(index
); 
3753         m_lines
.RemoveAt( index 
); 
3756     RefreshAfter(index
); 
3759 void wxListMainWindow::DeleteColumn( int col 
) 
3761     wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3763     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
3766     m_columns
.DeleteNode( node 
); 
3769 void wxListMainWindow::DeleteAllItems() 
3773         // nothing to do - in particular, don't send the event 
3781     // to make the deletion of all items faster, we don't send the 
3782     // notifications for each item deletion in this case but only one event 
3783     // for all of them: this is compatible with wxMSW and documented in 
3784     // DeleteAllItems() description 
3786     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
3787     event
.SetEventObject( GetParent() ); 
3788     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
3794         ResetVisibleLinesRange(); 
3797     if ( InReportView() ) 
3799         ResetVisibleLinesRange(); 
3807 void wxListMainWindow::DeleteEverything() 
3814 // ---------------------------------------------------------------------------- 
3815 // scanning for an item 
3816 // ---------------------------------------------------------------------------- 
3818 void wxListMainWindow::EnsureVisible( long index 
) 
3820     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3821                  _T("invalid index in EnsureVisible") ); 
3823     // We have to call this here because the label in question might just have 
3824     // been added and no screen update taken place. 
3828     size_t oldCurrent 
= m_current
; 
3829     m_current 
= (size_t)index
; 
3831     m_current 
= oldCurrent
; 
3834 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool WXUNUSED(partial
) ) 
3841     size_t count 
= GetItemCount(); 
3842     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
3844         wxListLineData 
*line 
= GetLine(i
); 
3845         if ( line
->GetText(0) == tmp 
) 
3852 long wxListMainWindow::FindItem(long start
, long data
) 
3858     size_t count 
= GetItemCount(); 
3859     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
3861         wxListLineData 
*line 
= GetLine(i
); 
3863         line
->GetItem( 0, item 
); 
3864         if (item
.m_data 
== data
) 
3871 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) 
3873     CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
3875     if ( HasFlag(wxLC_REPORT
) ) 
3877         size_t current 
= y 
/ GetLineHeight(); 
3878         flags 
= HitTestLine(current
, x
, y
); 
3884         // TODO: optimize it too! this is less simple than for report view but 
3885         //       enumerating all items is still not a way to do it!! 
3886         size_t count 
= GetItemCount(); 
3887         for ( size_t current 
= 0; current 
< count
; current
++ ) 
3889             flags 
= HitTestLine(current
, x
, y
); 
3898 // ---------------------------------------------------------------------------- 
3900 // ---------------------------------------------------------------------------- 
3902 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
3904     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); 
3906     size_t count 
= GetItemCount(); 
3907     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
<= count
, 
3908                  _T("invalid item index") ); 
3910     size_t id 
= item
.m_itemId
; 
3915     if ( HasFlag(wxLC_REPORT
) ) 
3917     else if ( HasFlag(wxLC_LIST
) ) 
3919     else if ( HasFlag(wxLC_ICON
) ) 
3921     else if ( HasFlag(wxLC_SMALL_ICON
) ) 
3922         mode 
= wxLC_ICON
;  // no typo 
3925         wxFAIL_MSG( _T("unknown mode") ); 
3928     wxListLineData 
*line 
= new wxListLineData(this); 
3930     line
->SetItem( 0, item 
); 
3932     m_lines
.Insert( line
, id 
); 
3934     RefreshLines(id
, GetItemCount() - 1); 
3937 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
3940     if ( HasFlag(wxLC_REPORT
) ) 
3942         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3943             item
.m_width 
= GetTextLength( item
.m_text 
); 
3944         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
3945         if ((col 
>= 0) && (col 
< (int)m_columns
.GetCount())) 
3947             wxListHeaderDataList::Node 
*node 
= m_columns
.Item( col 
); 
3948             m_columns
.Insert( node
, column 
); 
3952             m_columns
.Append( column 
); 
3957 // ---------------------------------------------------------------------------- 
3959 // ---------------------------------------------------------------------------- 
3961 wxListCtrlCompare list_ctrl_compare_func_2
; 
3962 long              list_ctrl_compare_data
; 
3964 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
3966     wxListLineData 
*line1 
= *arg1
; 
3967     wxListLineData 
*line2 
= *arg2
; 
3969     line1
->GetItem( 0, item 
); 
3970     long data1 
= item
.m_data
; 
3971     line2
->GetItem( 0, item 
); 
3972     long data2 
= item
.m_data
; 
3973     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
3976 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, long data 
) 
3978     list_ctrl_compare_func_2 
= fn
; 
3979     list_ctrl_compare_data 
= data
; 
3980     m_lines
.Sort( list_ctrl_compare_func_1 
); 
3984 // ---------------------------------------------------------------------------- 
3986 // ---------------------------------------------------------------------------- 
3988 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
3990     // update our idea of which lines are shown when we redraw the window the 
3992     ResetVisibleLinesRange(); 
3995 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
3996     wxScrolledWindow::OnScroll(event
); 
3998     HandleOnScroll( event 
); 
4001     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4003         wxListCtrl
* lc 
= GetListCtrl(); 
4004         wxCHECK_RET( lc
, _T("no listctrl window?") ); 
4006         lc
->m_headerWin
->Refresh() ; 
4008         lc
->m_headerWin
->MacUpdateImmediately() ; 
4013 int wxListMainWindow::GetCountPerPage() const 
4015     if ( !m_linesPerPage 
) 
4017         wxConstCast(this, wxListMainWindow
)-> 
4018             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4021     return m_linesPerPage
; 
4024 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4026     wxASSERT_MSG( HasFlag(wxLC_REPORT
), _T("this is for report mode only") ); 
4028     if ( m_lineFrom 
== (size_t)-1 ) 
4030         size_t count 
= GetItemCount(); 
4033             m_lineFrom 
= GetScrollPos(wxVERTICAL
); 
4035             wxASSERT_MSG( m_lineFrom 
< count
, _T("invalid scroll position?") ); 
4037             // we redraw one extra line but this is needed to make the redrawing 
4038             // logic work when there is a fractional number of lines on screen 
4039             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4040             if ( m_lineTo 
>= count 
) 
4041                 m_lineTo 
= count 
- 1; 
4043         else // empty control 
4046             m_lineTo 
= (size_t)-1; 
4050     wxASSERT_MSG( m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount(), 
4051                   _T("GetVisibleLinesRange() returns incorrect result") ); 
4059 // ------------------------------------------------------------------------------------- 
4061 // ------------------------------------------------------------------------------------- 
4063 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
) 
4065 wxListItem::wxListItem() 
4074     m_format 
= wxLIST_FORMAT_CENTRE
; 
4080 void wxListItem::Clear() 
4089     m_format 
= wxLIST_FORMAT_CENTRE
; 
4096 void wxListItem::ClearAttributes() 
4105 // ------------------------------------------------------------------------------------- 
4107 // ------------------------------------------------------------------------------------- 
4109 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
) 
4111 wxListEvent::wxListEvent( wxEventType commandType
, int id 
) 
4112            : wxNotifyEvent( commandType
, id 
) 
4118     m_cancelled 
= FALSE
; 
4123 void wxListEvent::CopyObject(wxObject
& object_dest
) const 
4125     wxListEvent 
*obj 
= (wxListEvent 
*)&object_dest
; 
4127     wxNotifyEvent::CopyObject(object_dest
); 
4129     obj
->m_code 
= m_code
; 
4130     obj
->m_itemIndex 
= m_itemIndex
; 
4131     obj
->m_oldItemIndex 
= m_oldItemIndex
; 
4133     obj
->m_cancelled 
= m_cancelled
; 
4134     obj
->m_pointDrag 
= m_pointDrag
; 
4135     obj
->m_item
.m_mask 
= m_item
.m_mask
; 
4136     obj
->m_item
.m_itemId 
= m_item
.m_itemId
; 
4137     obj
->m_item
.m_col 
= m_item
.m_col
; 
4138     obj
->m_item
.m_state 
= m_item
.m_state
; 
4139     obj
->m_item
.m_stateMask 
= m_item
.m_stateMask
; 
4140     obj
->m_item
.m_text 
= m_item
.m_text
; 
4141     obj
->m_item
.m_image 
= m_item
.m_image
; 
4142     obj
->m_item
.m_data 
= m_item
.m_data
; 
4143     obj
->m_item
.m_format 
= m_item
.m_format
; 
4144     obj
->m_item
.m_width 
= m_item
.m_width
; 
4146     if ( m_item
.HasAttributes() ) 
4148         obj
->m_item
.SetTextColour(m_item
.GetTextColour()); 
4152 // ------------------------------------------------------------------------------------- 
4154 // ------------------------------------------------------------------------------------- 
4156 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
) 
4158 BEGIN_EVENT_TABLE(wxListCtrl
,wxControl
) 
4159   EVT_SIZE(wxListCtrl::OnSize
) 
4160   EVT_IDLE(wxListCtrl::OnIdle
) 
4163 wxListCtrl::wxListCtrl() 
4165     m_imageListNormal 
= (wxImageList 
*) NULL
; 
4166     m_imageListSmall 
= (wxImageList 
*) NULL
; 
4167     m_imageListState 
= (wxImageList 
*) NULL
; 
4169     m_ownsImageListNormal 
= 
4170     m_ownsImageListSmall 
= 
4171     m_ownsImageListState 
= FALSE
; 
4173     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4174     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4177 wxListCtrl::~wxListCtrl() 
4180         m_mainWin
->ResetCurrent(); 
4182     if (m_ownsImageListNormal
) 
4183         delete m_imageListNormal
; 
4184     if (m_ownsImageListSmall
) 
4185         delete m_imageListSmall
; 
4186     if (m_ownsImageListState
) 
4187         delete m_imageListState
; 
4190 void wxListCtrl::CreateHeaderWindow() 
4192     m_headerWin 
= new wxListHeaderWindow
 
4194                         this, -1, m_mainWin
, 
4196                         wxSize(GetClientSize().x
, HEADER_HEIGHT
), 
4201 bool wxListCtrl::Create(wxWindow 
*parent
, 
4206                         const wxValidator 
&validator
, 
4207                         const wxString 
&name
) 
4211     m_imageListState 
= (wxImageList 
*) NULL
; 
4212     m_ownsImageListNormal 
= 
4213     m_ownsImageListSmall 
= 
4214     m_ownsImageListState 
= FALSE
; 
4216     m_mainWin 
= (wxListMainWindow
*) NULL
; 
4217     m_headerWin 
= (wxListHeaderWindow
*) NULL
; 
4219     if ( !(style 
& wxLC_MASK_TYPE
) ) 
4221         style 
= style 
| wxLC_LIST
; 
4224     if ( !wxControl::Create( parent
, id
, pos
, size
, style
, validator
, name 
) ) 
4227     // don't create the inner window with the border 
4228     style 
&= ~wxSUNKEN_BORDER
; 
4230     m_mainWin 
= new wxListMainWindow( this, -1, wxPoint(0,0), size
, style 
); 
4232     if ( HasFlag(wxLC_REPORT
) ) 
4234         CreateHeaderWindow(); 
4236         if ( HasFlag(wxLC_NO_HEADER
) ) 
4238             // VZ: why do we create it at all then? 
4239             m_headerWin
->Show( FALSE 
); 
4246 void wxListCtrl::SetSingleStyle( long style
, bool add 
) 
4248     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4249                   _T("wxLC_VIRTUAL can't be [un]set") ); 
4251     long flag 
= GetWindowStyle(); 
4255         if (style 
& wxLC_MASK_TYPE
) 
4256             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4257         if (style 
& wxLC_MASK_ALIGN
) 
4258             flag 
&= ~wxLC_MASK_ALIGN
; 
4259         if (style 
& wxLC_MASK_SORT
) 
4260             flag 
&= ~wxLC_MASK_SORT
; 
4272     SetWindowStyleFlag( flag 
); 
4275 void wxListCtrl::SetWindowStyleFlag( long flag 
) 
4279         m_mainWin
->DeleteEverything(); 
4283         GetClientSize( &width
, &height 
); 
4285         if (flag 
& wxLC_REPORT
) 
4287             if (!HasFlag(wxLC_REPORT
)) 
4291                     CreateHeaderWindow(); 
4293                     if (HasFlag(wxLC_NO_HEADER
)) 
4294                         m_headerWin
->Show( FALSE 
); 
4298                     if (flag 
& wxLC_NO_HEADER
) 
4299                         m_headerWin
->Show( FALSE 
); 
4301                         m_headerWin
->Show( TRUE 
); 
4307             if ( m_mainWin
->HasHeader() ) 
4309                 m_headerWin
->Show( FALSE 
); 
4314     wxWindow::SetWindowStyleFlag( flag 
); 
4317 bool wxListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4319     m_mainWin
->GetColumn( col
, item 
); 
4323 bool wxListCtrl::SetColumn( int col
, wxListItem
& item 
) 
4325     m_mainWin
->SetColumn( col
, item 
); 
4329 int wxListCtrl::GetColumnWidth( int col 
) const 
4331     return m_mainWin
->GetColumnWidth( col 
); 
4334 bool wxListCtrl::SetColumnWidth( int col
, int width 
) 
4336     m_mainWin
->SetColumnWidth( col
, width 
); 
4340 int wxListCtrl::GetCountPerPage() const 
4342   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4345 bool wxListCtrl::GetItem( wxListItem 
&info 
) const 
4347     m_mainWin
->GetItem( info 
); 
4351 bool wxListCtrl::SetItem( wxListItem 
&info 
) 
4353     m_mainWin
->SetItem( info 
); 
4357 long wxListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4360     info
.m_text 
= label
; 
4361     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4362     info
.m_itemId 
= index
; 
4366         info
.m_image 
= imageId
; 
4367         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4369     m_mainWin
->SetItem(info
); 
4373 int wxListCtrl::GetItemState( long item
, long stateMask 
) const 
4375     return m_mainWin
->GetItemState( item
, stateMask 
); 
4378 bool wxListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4380     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4384 bool wxListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4387     info
.m_image 
= image
; 
4388     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4389     info
.m_itemId 
= item
; 
4390     m_mainWin
->SetItem( info 
); 
4394 wxString 
wxListCtrl::GetItemText( long item 
) const 
4397     info
.m_itemId 
= item
; 
4398     m_mainWin
->GetItem( info 
); 
4402 void wxListCtrl::SetItemText( long item
, const wxString 
&str 
) 
4405     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4406     info
.m_itemId 
= item
; 
4408     m_mainWin
->SetItem( info 
); 
4411 long wxListCtrl::GetItemData( long item 
) const 
4414     info
.m_itemId 
= item
; 
4415     m_mainWin
->GetItem( info 
); 
4419 bool wxListCtrl::SetItemData( long item
, long data 
) 
4422     info
.m_mask 
= wxLIST_MASK_DATA
; 
4423     info
.m_itemId 
= item
; 
4425     m_mainWin
->SetItem( info 
); 
4429 bool wxListCtrl::GetItemRect( long item
, wxRect 
&rect
,  int WXUNUSED(code
) ) const 
4431     m_mainWin
->GetItemRect( item
, rect 
); 
4435 bool wxListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4437     m_mainWin
->GetItemPosition( item
, pos 
); 
4441 bool wxListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4446 int wxListCtrl::GetItemCount() const 
4448     return m_mainWin
->GetItemCount(); 
4451 int wxListCtrl::GetColumnCount() const 
4453     return m_mainWin
->GetColumnCount(); 
4456 void wxListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4458     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4461 int wxListCtrl::GetItemSpacing( bool isSmall 
) const 
4463     return m_mainWin
->GetItemSpacing( isSmall 
); 
4466 int wxListCtrl::GetSelectedItemCount() const 
4468     return m_mainWin
->GetSelectedItemCount(); 
4471 wxColour 
wxListCtrl::GetTextColour() const 
4473     return GetForegroundColour(); 
4476 void wxListCtrl::SetTextColour(const wxColour
& col
) 
4478     SetForegroundColour(col
); 
4481 long wxListCtrl::GetTopItem() const 
4486 long wxListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
4488     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
4491 wxImageList 
*wxListCtrl::GetImageList(int which
) const 
4493     if (which 
== wxIMAGE_LIST_NORMAL
) 
4495         return m_imageListNormal
; 
4497     else if (which 
== wxIMAGE_LIST_SMALL
) 
4499         return m_imageListSmall
; 
4501     else if (which 
== wxIMAGE_LIST_STATE
) 
4503         return m_imageListState
; 
4505     return (wxImageList 
*) NULL
; 
4508 void wxListCtrl::SetImageList( wxImageList 
*imageList
, int which 
) 
4510     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4512         if (m_ownsImageListNormal
) delete m_imageListNormal
; 
4513         m_imageListNormal 
= imageList
; 
4514         m_ownsImageListNormal 
= FALSE
; 
4516     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4518         if (m_ownsImageListSmall
) delete m_imageListSmall
; 
4519         m_imageListSmall 
= imageList
; 
4520         m_ownsImageListSmall 
= FALSE
; 
4522     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4524         if (m_ownsImageListState
) delete m_imageListState
; 
4525         m_imageListState 
= imageList
; 
4526         m_ownsImageListState 
= FALSE
; 
4529     m_mainWin
->SetImageList( imageList
, which 
); 
4532 void wxListCtrl::AssignImageList(wxImageList 
*imageList
, int which
) 
4534     SetImageList(imageList
, which
); 
4535     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4536         m_ownsImageListNormal 
= TRUE
; 
4537     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4538         m_ownsImageListSmall 
= TRUE
; 
4539     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4540         m_ownsImageListState 
= TRUE
; 
4543 bool wxListCtrl::Arrange( int WXUNUSED(flag
) ) 
4548 bool wxListCtrl::DeleteItem( long item 
) 
4550     m_mainWin
->DeleteItem( item 
); 
4554 bool wxListCtrl::DeleteAllItems() 
4556     m_mainWin
->DeleteAllItems(); 
4560 bool wxListCtrl::DeleteAllColumns() 
4562     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
4563     for ( size_t n 
= 0; n 
< count
; n
++ ) 
4569 void wxListCtrl::ClearAll() 
4571     m_mainWin
->DeleteEverything(); 
4574 bool wxListCtrl::DeleteColumn( int col 
) 
4576     m_mainWin
->DeleteColumn( col 
); 
4580 void wxListCtrl::Edit( long item 
) 
4582     m_mainWin
->EditLabel( item 
); 
4585 bool wxListCtrl::EnsureVisible( long item 
) 
4587     m_mainWin
->EnsureVisible( item 
); 
4591 long wxListCtrl::FindItem( long start
, const wxString
& str
,  bool partial 
) 
4593     return m_mainWin
->FindItem( start
, str
, partial 
); 
4596 long wxListCtrl::FindItem( long start
, long data 
) 
4598     return m_mainWin
->FindItem( start
, data 
); 
4601 long wxListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& WXUNUSED(pt
), 
4602                            int WXUNUSED(direction
)) 
4607 long wxListCtrl::HitTest( const wxPoint 
&point
, int &flags 
) 
4609     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
4612 long wxListCtrl::InsertItem( wxListItem
& info 
) 
4614     m_mainWin
->InsertItem( info 
); 
4615     return info
.m_itemId
; 
4618 long wxListCtrl::InsertItem( long index
, const wxString 
&label 
) 
4621     info
.m_text 
= label
; 
4622     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4623     info
.m_itemId 
= index
; 
4624     return InsertItem( info 
); 
4627 long wxListCtrl::InsertItem( long index
, int imageIndex 
) 
4630     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4631     info
.m_image 
= imageIndex
; 
4632     info
.m_itemId 
= index
; 
4633     return InsertItem( info 
); 
4636 long wxListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
4639     info
.m_text 
= label
; 
4640     info
.m_image 
= imageIndex
; 
4641     info
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_IMAGE
; 
4642     info
.m_itemId 
= index
; 
4643     return InsertItem( info 
); 
4646 long wxListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
4648     wxASSERT( m_headerWin 
); 
4649     m_mainWin
->InsertColumn( col
, item 
); 
4650     m_headerWin
->Refresh(); 
4655 long wxListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
4656                                int format
, int width 
) 
4659     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
4660     item
.m_text 
= heading
; 
4663         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
4664         item
.m_width 
= width
; 
4666     item
.m_format 
= format
; 
4668     return InsertColumn( col
, item 
); 
4671 bool wxListCtrl::ScrollList( int WXUNUSED(dx
), int WXUNUSED(dy
) ) 
4677 // fn is a function which takes 3 long arguments: item1, item2, data. 
4678 // item1 is the long data associated with a first item (NOT the index). 
4679 // item2 is the long data associated with a second item (NOT the index). 
4680 // data is the same value as passed to SortItems. 
4681 // The return value is a negative number if the first item should precede the second 
4682 // item, a positive number of the second item should precede the first, 
4683 // or zero if the two items are equivalent. 
4684 // data is arbitrary data to be passed to the sort function. 
4686 bool wxListCtrl::SortItems( wxListCtrlCompare fn
, long data 
) 
4688     m_mainWin
->SortItems( fn
, data 
); 
4692 // ---------------------------------------------------------------------------- 
4694 // ---------------------------------------------------------------------------- 
4696 void wxListCtrl::OnSize(wxSizeEvent
& event
) 
4702     GetClientSize( &cw
, &ch 
); 
4704     if ( m_mainWin
->HasHeader() ) 
4706         m_headerWin
->SetSize( 0, 0, cw
, HEADER_HEIGHT 
); 
4707         m_mainWin
->SetSize( 0, HEADER_HEIGHT 
+ 1, cw
, ch 
- HEADER_HEIGHT 
- 1 ); 
4709     else // no header window 
4711         m_mainWin
->SetSize( 0, 0, cw
, ch 
); 
4714     m_mainWin
->RecalculatePositions(); 
4717 void wxListCtrl::OnIdle( wxIdleEvent 
& event 
) 
4721     // do it only if needed 
4722     if ( !m_mainWin
->m_dirty 
) 
4725     m_mainWin
->RecalculatePositions(); 
4728 // ---------------------------------------------------------------------------- 
4730 // ---------------------------------------------------------------------------- 
4732 bool wxListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
4736         m_mainWin
->SetBackgroundColour( colour 
); 
4737         m_mainWin
->m_dirty 
= TRUE
; 
4743 bool wxListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
4745     if ( !wxWindow::SetForegroundColour( colour 
) ) 
4750         m_mainWin
->SetForegroundColour( colour 
); 
4751         m_mainWin
->m_dirty 
= TRUE
; 
4756         m_headerWin
->SetForegroundColour( colour 
); 
4762 bool wxListCtrl::SetFont( const wxFont 
&font 
) 
4764     if ( !wxWindow::SetFont( font 
) ) 
4769         m_mainWin
->SetFont( font 
); 
4770         m_mainWin
->m_dirty 
= TRUE
; 
4775         m_headerWin
->SetFont( font 
); 
4781 // ---------------------------------------------------------------------------- 
4782 // methods forwarded to m_mainWin 
4783 // ---------------------------------------------------------------------------- 
4785 #if wxUSE_DRAG_AND_DROP 
4787 void wxListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
4789     m_mainWin
->SetDropTarget( dropTarget 
); 
4792 wxDropTarget 
*wxListCtrl::GetDropTarget() const 
4794     return m_mainWin
->GetDropTarget(); 
4797 #endif // wxUSE_DRAG_AND_DROP 
4799 bool wxListCtrl::SetCursor( const wxCursor 
&cursor 
) 
4801     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : FALSE
; 
4804 wxColour 
wxListCtrl::GetBackgroundColour() const 
4806     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
4809 wxColour 
wxListCtrl::GetForegroundColour() const 
4811     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
4814 bool wxListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
4817     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
4820 #endif // wxUSE_MENUS 
4823 void wxListCtrl::SetFocus() 
4825     /* The test in window.cpp fails as we are a composite 
4826        window, so it checks against "this", but not m_mainWin. */ 
4827     if ( FindFocus() != this ) 
4828         m_mainWin
->SetFocus(); 
4831 // ---------------------------------------------------------------------------- 
4832 // virtual list control support 
4833 // ---------------------------------------------------------------------------- 
4835 wxString 
wxListCtrl::OnGetItemText(long item
, long col
) const 
4837     // this is a pure virtual function, in fact - which is not really pure 
4838     // because the controls which are not virtual don't need to implement it 
4839     wxFAIL_MSG( _T("not supposed to be called") ); 
4841     return wxEmptyString
; 
4844 int wxListCtrl::OnGetItemImage(long item
) const 
4847     wxFAIL_MSG( _T("not supposed to be called") ); 
4852 void wxListCtrl::SetItemCount(long count
) 
4854     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
4856     m_mainWin
->SetItemCount(count
); 
4859 #endif // wxUSE_LISTCTRL