1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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 ///////////////////////////////////////////////////////////////////////////// 
  13 //   1. we need to implement searching/sorting for virtual controls somehow 
  14 //   2. when changing selection the lines are refreshed twice 
  17 // For compilers that support precompilation, includes "wx.h". 
  18 #include "wx/wxprec.h" 
  26 #include "wx/listctrl.h" 
  29     #include "wx/scrolwin.h" 
  31     #include "wx/settings.h" 
  32     #include "wx/dynarray.h" 
  33     #include "wx/dcclient.h" 
  34     #include "wx/dcscreen.h" 
  36     #include "wx/settings.h" 
  40 #include "wx/imaglist.h" 
  41 #include "wx/renderer.h" 
  42 #include "wx/generic/private/listctrl.h" 
  45     #include "wx/osx/private.h" 
  48 #if defined(__WXMSW__) && !defined(__WXWINCE__) && !defined(__WXUNIVERSAL__) 
  49     #define "wx/msw/wrapwin.h" 
  52 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
  53 // be removed, as well as the #else case below. 
  54 #define _USE_VISATTR 0 
  57 // ---------------------------------------------------------------------------- 
  59 // ---------------------------------------------------------------------------- 
  61 // // the height of the header window (FIXME: should depend on its font!) 
  62 // static const int HEADER_HEIGHT = 23; 
  64 static const int SCROLL_UNIT_X 
= 15; 
  66 // the spacing between the lines (in report mode) 
  67 static const int LINE_SPACING 
= 0; 
  69 // extra margins around the text label 
  71 static const int EXTRA_WIDTH 
= 6; 
  73 static const int EXTRA_WIDTH 
= 4; 
  77 static const int EXTRA_HEIGHT 
= 6; 
  79 static const int EXTRA_HEIGHT 
= 4; 
  82 // margin between the window and the items 
  83 static const int EXTRA_BORDER_X 
= 2; 
  84 static const int EXTRA_BORDER_Y 
= 2; 
  86 // offset for the header window 
  87 static const int HEADER_OFFSET_X 
= 0; 
  88 static const int HEADER_OFFSET_Y 
= 0; 
  90 // margin between rows of icons in [small] icon view 
  91 static const int MARGIN_BETWEEN_ROWS 
= 6; 
  93 // when autosizing the columns, add some slack 
  94 static const int AUTOSIZE_COL_MARGIN 
= 10; 
  96 // default width for the header columns 
  97 static const int WIDTH_COL_DEFAULT 
= 80; 
  99 // the space between the image and the text in the report mode 
 100 static const int IMAGE_MARGIN_IN_REPORT_MODE 
= 5; 
 102 // the space between the image and the text in the report mode in header 
 103 static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE 
= 2; 
 107 // ---------------------------------------------------------------------------- 
 108 // arrays/list implementations 
 109 // ---------------------------------------------------------------------------- 
 111 #include "wx/listimpl.cpp" 
 112 WX_DEFINE_LIST(wxListItemDataList
) 
 114 #include "wx/arrimpl.cpp" 
 115 WX_DEFINE_OBJARRAY(wxListLineDataArray
) 
 117 #include "wx/listimpl.cpp" 
 118 WX_DEFINE_LIST(wxListHeaderDataList
) 
 121 // ---------------------------------------------------------------------------- 
 123 // ---------------------------------------------------------------------------- 
 125 wxListItemData::~wxListItemData() 
 127     // in the virtual list control the attributes are managed by the main 
 128     // program, so don't delete them 
 129     if ( !m_owner
->IsVirtual() ) 
 135 void wxListItemData::Init() 
 143 wxListItemData::wxListItemData(wxListMainWindow 
*owner
) 
 149     if ( owner
->InReportView() ) 
 155 void wxListItemData::SetItem( const wxListItem 
&info 
) 
 157     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
 158         SetText(info
.m_text
); 
 159     if ( info
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 160         m_image 
= info
.m_image
; 
 161     if ( info
.m_mask 
& wxLIST_MASK_DATA 
) 
 162         m_data 
= info
.m_data
; 
 164     if ( info
.HasAttributes() ) 
 167             m_attr
->AssignFrom(*info
.GetAttributes()); 
 169             m_attr 
= new wxListItemAttr(*info
.GetAttributes()); 
 177         m_rect
->width 
= info
.m_width
; 
 181 void wxListItemData::SetPosition( int x
, int y 
) 
 183     wxCHECK_RET( m_rect
, wxT("unexpected SetPosition() call") ); 
 189 void wxListItemData::SetSize( int width
, int height 
) 
 191     wxCHECK_RET( m_rect
, wxT("unexpected SetSize() call") ); 
 194         m_rect
->width 
= width
; 
 196         m_rect
->height 
= height
; 
 199 bool wxListItemData::IsHit( int x
, int y 
) const 
 201     wxCHECK_MSG( m_rect
, false, wxT("can't be called in this mode") ); 
 203     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Contains(x
, y
); 
 206 int wxListItemData::GetX() const 
 208     wxCHECK_MSG( m_rect
, 0, wxT("can't be called in this mode") ); 
 213 int wxListItemData::GetY() const 
 215     wxCHECK_MSG( m_rect
, 0, wxT("can't be called in this mode") ); 
 220 int wxListItemData::GetWidth() const 
 222     wxCHECK_MSG( m_rect
, 0, wxT("can't be called in this mode") ); 
 224     return m_rect
->width
; 
 227 int wxListItemData::GetHeight() const 
 229     wxCHECK_MSG( m_rect
, 0, wxT("can't be called in this mode") ); 
 231     return m_rect
->height
; 
 234 void wxListItemData::GetItem( wxListItem 
&info 
) const 
 236     long mask 
= info
.m_mask
; 
 238         // by default, get everything for backwards compatibility 
 241     if ( mask 
& wxLIST_MASK_TEXT 
) 
 242         info
.m_text 
= m_text
; 
 243     if ( mask 
& wxLIST_MASK_IMAGE 
) 
 244         info
.m_image 
= m_image
; 
 245     if ( mask 
& wxLIST_MASK_DATA 
) 
 246         info
.m_data 
= m_data
; 
 250         if ( m_attr
->HasTextColour() ) 
 251             info
.SetTextColour(m_attr
->GetTextColour()); 
 252         if ( m_attr
->HasBackgroundColour() ) 
 253             info
.SetBackgroundColour(m_attr
->GetBackgroundColour()); 
 254         if ( m_attr
->HasFont() ) 
 255             info
.SetFont(m_attr
->GetFont()); 
 259 //----------------------------------------------------------------------------- 
 261 //----------------------------------------------------------------------------- 
 263 void wxListHeaderData::Init() 
 275 wxListHeaderData::wxListHeaderData() 
 280 wxListHeaderData::wxListHeaderData( const wxListItem 
&item 
) 
 287 void wxListHeaderData::SetItem( const wxListItem 
&item 
) 
 289     m_mask 
= item
.m_mask
; 
 291     if ( m_mask 
& wxLIST_MASK_TEXT 
) 
 292         m_text 
= item
.m_text
; 
 294     if ( m_mask 
& wxLIST_MASK_IMAGE 
) 
 295         m_image 
= item
.m_image
; 
 297     if ( m_mask 
& wxLIST_MASK_FORMAT 
) 
 298         m_format 
= item
.m_format
; 
 300     if ( m_mask 
& wxLIST_MASK_WIDTH 
) 
 301         SetWidth(item
.m_width
); 
 303     if ( m_mask 
& wxLIST_MASK_STATE 
) 
 304         SetState(item
.m_state
); 
 307 void wxListHeaderData::SetPosition( int x
, int y 
) 
 313 void wxListHeaderData::SetHeight( int h 
) 
 318 void wxListHeaderData::SetWidth( int w 
) 
 320     m_width 
= w 
< 0 ? WIDTH_COL_DEFAULT 
: w
; 
 323 void wxListHeaderData::SetState( int flag 
) 
 328 void wxListHeaderData::SetFormat( int format 
) 
 333 bool wxListHeaderData::HasImage() const 
 335     return m_image 
!= -1; 
 338 bool wxListHeaderData::IsHit( int x
, int y 
) const 
 340     return ((x 
>= m_xpos
) && (x 
<= m_xpos
+m_width
) && (y 
>= m_ypos
) && (y 
<= m_ypos
+m_height
)); 
 343 void wxListHeaderData::GetItem( wxListItem
& item 
) 
 345     item
.m_mask 
= m_mask
; 
 346     item
.m_text 
= m_text
; 
 347     item
.m_image 
= m_image
; 
 348     item
.m_format 
= m_format
; 
 349     item
.m_width 
= m_width
; 
 350     item
.m_state 
= m_state
; 
 353 int wxListHeaderData::GetImage() const 
 358 int wxListHeaderData::GetWidth() const 
 363 int wxListHeaderData::GetFormat() const 
 368 int wxListHeaderData::GetState() const 
 373 //----------------------------------------------------------------------------- 
 375 //----------------------------------------------------------------------------- 
 377 inline int wxListLineData::GetMode() const 
 379     return m_owner
->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE
; 
 382 inline bool wxListLineData::InReportView() const 
 384     return m_owner
->HasFlag(wxLC_REPORT
); 
 387 inline bool wxListLineData::IsVirtual() const 
 389     return m_owner
->IsVirtual(); 
 392 wxListLineData::wxListLineData( wxListMainWindow 
*owner 
) 
 396     if ( InReportView() ) 
 399         m_gi 
= new GeometryInfo
; 
 401     m_highlighted 
= false; 
 403     InitItems( GetMode() == wxLC_REPORT 
? m_owner
->GetColumnCount() : 1 ); 
 406 void wxListLineData::CalculateSize( wxDC 
*dc
, int spacing 
) 
 408     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
 409     wxCHECK_RET( node
, wxT("no subitems at all??") ); 
 411     wxListItemData 
*item 
= node
->GetData(); 
 419         case wxLC_SMALL_ICON
: 
 420             m_gi
->m_rectAll
.width 
= spacing
; 
 427                 m_gi
->m_rectLabel
.width 
= 
 428                 m_gi
->m_rectLabel
.height 
= 0; 
 432                 dc
->GetTextExtent( s
, &lw
, &lh 
); 
 436                 m_gi
->m_rectAll
.height 
= spacing 
+ lh
; 
 438                     m_gi
->m_rectAll
.width 
= lw
; 
 440                 m_gi
->m_rectLabel
.width 
= lw
; 
 441                 m_gi
->m_rectLabel
.height 
= lh
; 
 444             if (item
->HasImage()) 
 447                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
 448                 m_gi
->m_rectIcon
.width 
= w 
+ 8; 
 449                 m_gi
->m_rectIcon
.height 
= h 
+ 8; 
 451                 if ( m_gi
->m_rectIcon
.width 
> m_gi
->m_rectAll
.width 
) 
 452                     m_gi
->m_rectAll
.width 
= m_gi
->m_rectIcon
.width
; 
 453                 if ( m_gi
->m_rectIcon
.height 
+ lh 
> m_gi
->m_rectAll
.height 
- 4 ) 
 454                     m_gi
->m_rectAll
.height 
= m_gi
->m_rectIcon
.height 
+ lh 
+ 4; 
 457             if ( item
->HasText() ) 
 459                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectLabel
.width
; 
 460                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectLabel
.height
; 
 462             else // no text, highlight the icon 
 464                 m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectIcon
.width
; 
 465                 m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectIcon
.height
; 
 470             s 
= item
->GetTextForMeasuring(); 
 472             dc
->GetTextExtent( s
, &lw
, &lh 
); 
 476             m_gi
->m_rectLabel
.width 
= lw
; 
 477             m_gi
->m_rectLabel
.height 
= lh
; 
 479             m_gi
->m_rectAll
.width 
= lw
; 
 480             m_gi
->m_rectAll
.height 
= lh
; 
 482             if (item
->HasImage()) 
 485                 m_owner
->GetImageSize( item
->GetImage(), w
, h 
); 
 486                 m_gi
->m_rectIcon
.width 
= w
; 
 487                 m_gi
->m_rectIcon
.height 
= h
; 
 489                 m_gi
->m_rectAll
.width 
+= 4 + w
; 
 490                 if (h 
> m_gi
->m_rectAll
.height
) 
 491                     m_gi
->m_rectAll
.height 
= h
; 
 494             m_gi
->m_rectHighlight
.width 
= m_gi
->m_rectAll
.width
; 
 495             m_gi
->m_rectHighlight
.height 
= m_gi
->m_rectAll
.height
; 
 499             wxFAIL_MSG( wxT("unexpected call to SetSize") ); 
 503             wxFAIL_MSG( wxT("unknown mode") ); 
 508 void wxListLineData::SetPosition( int x
, int y
, int spacing 
) 
 510     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
 511     wxCHECK_RET( node
, wxT("no subitems at all??") ); 
 513     wxListItemData 
*item 
= node
->GetData(); 
 518         case wxLC_SMALL_ICON
: 
 519             m_gi
->m_rectAll
.x 
= x
; 
 520             m_gi
->m_rectAll
.y 
= y
; 
 522             if ( item
->HasImage() ) 
 524                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 4 + 
 525                     (m_gi
->m_rectAll
.width 
- m_gi
->m_rectIcon
.width
) / 2; 
 526                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 4; 
 529             if ( item
->HasText() ) 
 531                 if (m_gi
->m_rectAll
.width 
> spacing
) 
 532                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2); 
 534                     m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2) + (spacing 
/ 2) - (m_gi
->m_rectLabel
.width 
/ 2); 
 535                 m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ m_gi
->m_rectAll
.height 
+ 2 - m_gi
->m_rectLabel
.height
; 
 536                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectLabel
.x 
- 2; 
 537                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectLabel
.y 
- 2; 
 539             else // no text, highlight the icon 
 541                 m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectIcon
.x 
- 4; 
 542                 m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectIcon
.y 
- 4; 
 547             m_gi
->m_rectAll
.x 
= x
; 
 548             m_gi
->m_rectAll
.y 
= y
; 
 550             m_gi
->m_rectHighlight
.x 
= m_gi
->m_rectAll
.x
; 
 551             m_gi
->m_rectHighlight
.y 
= m_gi
->m_rectAll
.y
; 
 552             m_gi
->m_rectLabel
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
 554             if (item
->HasImage()) 
 556                 m_gi
->m_rectIcon
.x 
= m_gi
->m_rectAll
.x 
+ 2; 
 557                 m_gi
->m_rectIcon
.y 
= m_gi
->m_rectAll
.y 
+ 2; 
 558                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ 4 + (EXTRA_WIDTH
/2) + m_gi
->m_rectIcon
.width
; 
 562                 m_gi
->m_rectLabel
.x 
= m_gi
->m_rectAll
.x 
+ (EXTRA_WIDTH
/2); 
 567             wxFAIL_MSG( wxT("unexpected call to SetPosition") ); 
 571             wxFAIL_MSG( wxT("unknown mode") ); 
 576 void wxListLineData::InitItems( int num 
) 
 578     for (int i 
= 0; i 
< num
; i
++) 
 579         m_items
.Append( new wxListItemData(m_owner
) ); 
 582 void wxListLineData::SetItem( int index
, const wxListItem 
&info 
) 
 584     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
 585     wxCHECK_RET( node
, wxT("invalid column index in SetItem") ); 
 587     wxListItemData 
*item 
= node
->GetData(); 
 588     item
->SetItem( info 
); 
 591 void wxListLineData::GetItem( int index
, wxListItem 
&info 
) 
 593     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
 596         wxListItemData 
*item 
= node
->GetData(); 
 597         item
->GetItem( info 
); 
 601 wxString 
wxListLineData::GetText(int index
) const 
 605     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
 608         wxListItemData 
*item 
= node
->GetData(); 
 615 void wxListLineData::SetText( int index
, const wxString
& s 
) 
 617     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
 620         wxListItemData 
*item 
= node
->GetData(); 
 625 void wxListLineData::SetImage( int index
, int image 
) 
 627     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
 628     wxCHECK_RET( node
, wxT("invalid column index in SetImage()") ); 
 630     wxListItemData 
*item 
= node
->GetData(); 
 631     item
->SetImage(image
); 
 634 int wxListLineData::GetImage( int index 
) const 
 636     wxListItemDataList::compatibility_iterator node 
= m_items
.Item( index 
); 
 637     wxCHECK_MSG( node
, -1, wxT("invalid column index in GetImage()") ); 
 639     wxListItemData 
*item 
= node
->GetData(); 
 640     return item
->GetImage(); 
 643 wxListItemAttr 
*wxListLineData::GetAttr() const 
 645     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
 646     wxCHECK_MSG( node
, NULL
, wxT("invalid column index in GetAttr()") ); 
 648     wxListItemData 
*item 
= node
->GetData(); 
 649     return item
->GetAttr(); 
 652 void wxListLineData::SetAttr(wxListItemAttr 
*attr
) 
 654     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
 655     wxCHECK_RET( node
, wxT("invalid column index in SetAttr()") ); 
 657     wxListItemData 
*item 
= node
->GetData(); 
 661 void wxListLineData::ApplyAttributes(wxDC 
*dc
, 
 662                                      const wxRect
& rectHL
, 
 666     const wxListItemAttr 
* const attr 
= GetAttr(); 
 668     wxWindow 
* const listctrl 
= m_owner
->GetParent(); 
 670     const bool hasFocus 
= listctrl
->HasFocus() 
 671 #if defined(__WXMAC__) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON 
 672                 && IsControlActive( (ControlRef
)listctrl
->GetHandle() ) 
 678     // don't use foreground colour for drawing highlighted items - this might 
 679     // make them completely invisible (and there is no way to do bit 
 680     // arithmetics on wxColour, unfortunately) 
 691             colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
 693             colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT
); 
 696     else if ( attr 
&& attr
->HasTextColour() ) 
 697         colText 
= attr
->GetTextColour(); 
 699         colText 
= listctrl
->GetForegroundColour(); 
 701     dc
->SetTextForeground(colText
); 
 705     if ( attr 
&& attr
->HasFont() ) 
 706         font 
= attr
->GetFont(); 
 708         font 
= listctrl
->GetFont(); 
 715         // Use the renderer method to ensure that the selected items use the 
 717         int flags 
= wxCONTROL_SELECTED
; 
 719             flags 
|= wxCONTROL_FOCUSED
; 
 721            flags 
|= wxCONTROL_CURRENT
; 
 722         wxRendererNative::Get(). 
 723             DrawItemSelectionRect( m_owner
, *dc
, rectHL
, flags 
); 
 725     else if ( attr 
&& attr
->HasBackgroundColour() ) 
 727         // Draw the background using the items custom background colour. 
 728         dc
->SetBrush(attr
->GetBackgroundColour()); 
 729         dc
->SetPen(*wxTRANSPARENT_PEN
); 
 730         dc
->DrawRectangle(rectHL
); 
 733     // just for debugging to better see where the items are 
 735     dc
->SetPen(*wxRED_PEN
); 
 736     dc
->SetBrush(*wxTRANSPARENT_BRUSH
); 
 737     dc
->DrawRectangle( m_gi
->m_rectAll 
); 
 738     dc
->SetPen(*wxGREEN_PEN
); 
 739     dc
->DrawRectangle( m_gi
->m_rectIcon 
); 
 743 void wxListLineData::Draw(wxDC 
*dc
, bool current
) 
 745     wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
 746     wxCHECK_RET( node
, wxT("no subitems at all??") ); 
 748     ApplyAttributes(dc
, m_gi
->m_rectHighlight
, IsHighlighted(), current
); 
 750     wxListItemData 
*item 
= node
->GetData(); 
 751     if (item
->HasImage()) 
 753         // centre the image inside our rectangle, this looks nicer when items 
 754         // ae aligned in a row 
 755         const wxRect
& rectIcon 
= m_gi
->m_rectIcon
; 
 757         m_owner
->DrawImage(item
->GetImage(), dc
, rectIcon
.x
, rectIcon
.y
); 
 762         const wxRect
& rectLabel 
= m_gi
->m_rectLabel
; 
 764         wxDCClipper 
clipper(*dc
, rectLabel
); 
 765         dc
->DrawText(item
->GetText(), rectLabel
.x
, rectLabel
.y
); 
 769 void wxListLineData::DrawInReportMode( wxDC 
*dc
, 
 771                                        const wxRect
& rectHL
, 
 775     // TODO: later we should support setting different attributes for 
 776     //       different columns - to do it, just add "col" argument to 
 777     //       GetAttr() and move these lines into the loop below 
 779     ApplyAttributes(dc
, rectHL
, highlighted
, current
); 
 781     wxCoord x 
= rect
.x 
+ HEADER_OFFSET_X
, 
 782             yMid 
= rect
.y 
+ rect
.height
/2; 
 784     // This probably needs to be done 
 785     // on all platforms as the icons 
 786     // otherwise nearly touch the border 
 791     for ( wxListItemDataList::compatibility_iterator node 
= m_items
.GetFirst(); 
 793           node 
= node
->GetNext(), col
++ ) 
 795         wxListItemData 
*item 
= node
->GetData(); 
 797         int width 
= m_owner
->GetColumnWidth(col
); 
 802         const int wText 
= width
; 
 803         wxDCClipper 
clipper(*dc
, xOld
, rect
.y
, wText
, rect
.height
); 
 805         if ( item
->HasImage() ) 
 808             m_owner
->GetImageSize( item
->GetImage(), ix
, iy 
); 
 809             m_owner
->DrawImage( item
->GetImage(), dc
, xOld
, yMid 
- iy
/2 ); 
 811             ix 
+= IMAGE_MARGIN_IN_REPORT_MODE
; 
 817         if ( item
->HasText() ) 
 818             DrawTextFormatted(dc
, item
->GetText(), col
, xOld
, yMid
, width
); 
 822 void wxListLineData::DrawTextFormatted(wxDC 
*dc
, 
 823                                        const wxString
& textOrig
, 
 829     // we don't support displaying multiple lines currently (and neither does 
 830     // wxMSW FWIW) so just merge all the lines 
 831     wxString 
text(textOrig
); 
 832     text
.Replace(wxT("\n"), wxT(" ")); 
 835     dc
->GetTextExtent(text
, &w
, &h
); 
 837     const wxCoord y 
= yMid 
- (h 
+ 1)/2; 
 839     wxDCClipper 
clipper(*dc
, x
, y
, width
, h
); 
 841     // determine if the string can fit inside the current width 
 844         // it can, draw it using the items alignment 
 846         m_owner
->GetColumn(col
, item
); 
 847         switch ( item
.GetAlign() ) 
 849             case wxLIST_FORMAT_LEFT
: 
 853             case wxLIST_FORMAT_RIGHT
: 
 857             case wxLIST_FORMAT_CENTER
: 
 858                 x 
+= (width 
- w
) / 2; 
 862                 wxFAIL_MSG( wxT("unknown list item format") ); 
 866         dc
->DrawText(text
, x
, y
); 
 868     else // otherwise, truncate and add an ellipsis if possible 
 870         // determine the base width 
 871         wxString 
ellipsis(wxT("...")); 
 873         dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
 875         // continue until we have enough space or only one character left 
 877         size_t len 
= text
.length(); 
 878         wxString drawntext 
= text
.Left(len
); 
 881             dc
->GetTextExtent(drawntext
.Last(), &w_c
, &h_c
); 
 882             drawntext
.RemoveLast(); 
 885             if (w 
+ base_w 
<= width
) 
 889         // if still not enough space, remove ellipsis characters 
 890         while (ellipsis
.length() > 0 && w 
+ base_w 
> width
) 
 892             ellipsis 
= ellipsis
.Left(ellipsis
.length() - 1); 
 893             dc
->GetTextExtent(ellipsis
, &base_w
, &h
); 
 897         dc
->DrawText(drawntext
, x
, y
); 
 898         dc
->DrawText(ellipsis
, x 
+ w
, y
); 
 902 bool wxListLineData::Highlight( bool on 
) 
 904     wxCHECK_MSG( !IsVirtual(), false, wxT("unexpected call to Highlight") ); 
 906     if ( on 
== m_highlighted 
) 
 914 void wxListLineData::ReverseHighlight( void ) 
 916     Highlight(!IsHighlighted()); 
 919 //----------------------------------------------------------------------------- 
 920 //  wxListHeaderWindow 
 921 //----------------------------------------------------------------------------- 
 923 BEGIN_EVENT_TABLE(wxListHeaderWindow
,wxWindow
) 
 924     EVT_PAINT         (wxListHeaderWindow::OnPaint
) 
 925     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse
) 
 926     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus
) 
 929 void wxListHeaderWindow::Init() 
 931     m_currentCursor 
= NULL
; 
 932     m_isDragging 
= false; 
 934     m_sendSetColumnWidth 
= false; 
 937 wxListHeaderWindow::wxListHeaderWindow() 
 942     m_resizeCursor 
= NULL
; 
 945 wxListHeaderWindow::wxListHeaderWindow( wxWindow 
*win
, 
 947                                         wxListMainWindow 
*owner
, 
 951                                         const wxString 
&name 
) 
 952                   : wxWindow( win
, id
, pos
, size
, style
, name 
) 
 957     m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
 960     wxVisualAttributes attr 
= wxPanel::GetClassDefaultAttributes(); 
 961     SetOwnForegroundColour( attr
.colFg 
); 
 962     SetOwnBackgroundColour( attr
.colBg 
); 
 964         SetOwnFont( attr
.font 
); 
 966     SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
 967     SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
 969         SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT 
)); 
 973 wxListHeaderWindow::~wxListHeaderWindow() 
 975     delete m_resizeCursor
; 
 978 #ifdef __WXUNIVERSAL__ 
 979 #include "wx/univ/renderer.h" 
 980 #include "wx/univ/theme.h" 
 983 // shift the DC origin to match the position of the main window horz 
 984 // scrollbar: this allows us to always use logical coords 
 985 void wxListHeaderWindow::AdjustDC(wxDC
& dc
) 
 987     wxGenericListCtrl 
*parent 
= m_owner
->GetListCtrl(); 
 990     parent
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
 993     parent
->GetViewStart( &view_start
, NULL 
); 
 998     dc
.GetDeviceOrigin( &org_x
, &org_y 
); 
1000     // account for the horz scrollbar offset 
1002     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
1004         // Maybe we just have to check for m_signX 
1005         // in the DC, but I leave the #ifdef __WXGTK__ 
1007         dc
.SetDeviceOrigin( org_x 
+ (view_start 
* xpix
), org_y 
); 
1011         dc
.SetDeviceOrigin( org_x 
- (view_start 
* xpix
), org_y 
); 
1014 void wxListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1016     wxGenericListCtrl 
*parent 
= m_owner
->GetListCtrl(); 
1018     wxPaintDC 
dc( this ); 
1022     dc
.SetFont( GetFont() ); 
1024     // width and height of the entire header window 
1026     GetClientSize( &w
, &h 
); 
1027     parent
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1029     dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
1030     dc
.SetTextForeground(GetForegroundColour()); 
1032     int x 
= HEADER_OFFSET_X
; 
1033     int numColumns 
= m_owner
->GetColumnCount(); 
1035     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1037         m_owner
->GetColumn( i
, item 
); 
1038         int wCol 
= item
.m_width
; 
1044         if (!m_parent
->IsEnabled()) 
1045             flags 
|= wxCONTROL_DISABLED
; 
1047 // NB: The code below is not really Mac-specific, but since we are close 
1048 // to 2.8 release and I don't have time to test on other platforms, I 
1049 // defined this only for wxMac. If this behaviour is desired on 
1050 // other platforms, please go ahead and revise or remove the #ifdef. 
1052         if ( !m_owner
->IsVirtual() && (item
.m_mask 
& wxLIST_MASK_STATE
) && 
1053                 (item
.m_state 
& wxLIST_STATE_SELECTED
) ) 
1054             flags 
|= wxCONTROL_SELECTED
; 
1058            flags 
|= wxCONTROL_SPECIAL
; // mark as first column 
1060         wxRendererNative::Get().DrawHeaderButton
 
1064                                     wxRect(x
, HEADER_OFFSET_Y
, cw
, ch
), 
1068         // see if we have enough space for the column label 
1070         // for this we need the width of the text 
1073         dc
.GetTextExtent(item
.GetText(), &wLabel
, &hLabel
); 
1074         wLabel 
+= 2 * EXTRA_WIDTH
; 
1076         // and the width of the icon, if any 
1077         int ix 
= 0, iy 
= 0;    // init them just to suppress the compiler warnings 
1078         const int image 
= item
.m_image
; 
1079         wxImageList 
*imageList
; 
1082             imageList 
= m_owner
->GetSmallImageList(); 
1085                 imageList
->GetSize(image
, ix
, iy
); 
1086                 wLabel 
+= ix 
+ HEADER_IMAGE_MARGIN_IN_REPORT_MODE
; 
1094         // ignore alignment if there is not enough space anyhow 
1096         switch ( wLabel 
< cw 
? item
.GetAlign() : wxLIST_FORMAT_LEFT 
) 
1099                 wxFAIL_MSG( wxT("unknown list item format") ); 
1102             case wxLIST_FORMAT_LEFT
: 
1106             case wxLIST_FORMAT_RIGHT
: 
1107                 xAligned 
= x 
+ cw 
- wLabel
; 
1110             case wxLIST_FORMAT_CENTER
: 
1111                 xAligned 
= x 
+ (cw 
- wLabel
) / 2; 
1115         // draw the text and image clipping them so that they 
1116         // don't overwrite the column boundary 
1117         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h
); 
1119         // if we have an image, draw it on the right of the label 
1126                         xAligned 
+ wLabel 
- ix 
- HEADER_IMAGE_MARGIN_IN_REPORT_MODE
, 
1127                         HEADER_OFFSET_Y 
+ (h 
- iy
)/2, 
1128                         wxIMAGELIST_DRAW_TRANSPARENT
 
1132         dc
.DrawText( item
.GetText(), 
1133                      xAligned 
+ EXTRA_WIDTH
, (h 
- hLabel
) / 2 ); 
1138     // Fill in what's missing to the right of the columns, otherwise we will 
1139     // leave an unpainted area when columns are removed (and it looks better) 
1142         wxRendererNative::Get().DrawHeaderButton
 
1146                                     wxRect(x
, HEADER_OFFSET_Y
, w 
- x
, h
), 
1147                                     wxCONTROL_DIRTY 
// mark as last column 
1152 void wxListHeaderWindow::OnInternalIdle() 
1154     wxWindow::OnInternalIdle(); 
1156     if (m_sendSetColumnWidth
) 
1158         m_owner
->SetColumnWidth( m_colToSend
, m_widthToSend 
); 
1159         m_sendSetColumnWidth 
= false; 
1163 void wxListHeaderWindow::DrawCurrent() 
1166     // m_owner->SetColumnWidth( m_column, m_currentX - m_minX ); 
1167     m_sendSetColumnWidth 
= true; 
1168     m_colToSend 
= m_column
; 
1169     m_widthToSend 
= m_currentX 
- m_minX
; 
1171     int x1 
= m_currentX
; 
1173     m_owner
->ClientToScreen( &x1
, &y1 
); 
1175     int x2 
= m_currentX
; 
1177     m_owner
->GetClientSize( NULL
, &y2 
); 
1178     m_owner
->ClientToScreen( &x2
, &y2 
); 
1181     dc
.SetLogicalFunction( wxINVERT 
); 
1182     dc
.SetPen( wxPen(*wxBLACK
, 2) ); 
1183     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1187     dc
.DrawLine( x1
, y1
, x2
, y2 
); 
1189     dc
.SetLogicalFunction( wxCOPY 
); 
1191     dc
.SetPen( wxNullPen 
); 
1192     dc
.SetBrush( wxNullBrush 
); 
1196 void wxListHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1198     wxGenericListCtrl 
*parent 
= m_owner
->GetListCtrl(); 
1200     // we want to work with logical coords 
1202     parent
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1203     int y 
= event
.GetY(); 
1207         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1209         // we don't draw the line beyond our window, but we allow dragging it 
1212         GetClientSize( &w
, NULL 
); 
1213         parent
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1216         // erase the line if it was drawn 
1217         if ( m_currentX 
< w 
) 
1220         if (event
.ButtonUp()) 
1223             m_isDragging 
= false; 
1225             m_owner
->SetColumnWidth( m_column
, m_currentX 
- m_minX 
); 
1226             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1233                 m_currentX 
= m_minX 
+ 7; 
1235             // draw in the new location 
1236             if ( m_currentX 
< w 
) 
1240     else // not dragging 
1243         bool hit_border 
= false; 
1245         // end of the current column 
1248         // find the column where this event occurred 
1250             countCol 
= m_owner
->GetColumnCount(); 
1251         for (col 
= 0; col 
< countCol
; col
++) 
1253             xpos 
+= m_owner
->GetColumnWidth( col 
); 
1256             if ( (abs(x
-xpos
) < 3) && (y 
< 22) ) 
1258                 // near the column border 
1265                 // inside the column 
1272         if ( col 
== countCol 
) 
1275         if (event
.LeftDown() || event
.RightUp()) 
1277             if (hit_border 
&& event
.LeftDown()) 
1279                 if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, 
1280                                    event
.GetPosition()) ) 
1282                     m_isDragging 
= true; 
1287                 //else: column resizing was vetoed by the user code 
1289             else // click on a column 
1291                 // record the selected state of the columns 
1292                 if (event
.LeftDown()) 
1294                     for (int i
=0; i 
< m_owner
->GetColumnCount(); i
++) 
1297                         m_owner
->GetColumn(i
, colItem
); 
1298                         long state 
= colItem
.GetState(); 
1300                             colItem
.SetState(state 
| wxLIST_STATE_SELECTED
); 
1302                             colItem
.SetState(state 
& ~wxLIST_STATE_SELECTED
); 
1303                         m_owner
->SetColumn(i
, colItem
); 
1307                 SendListEvent( event
.LeftDown() 
1308                                     ? wxEVT_COMMAND_LIST_COL_CLICK
 
1309                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
, 
1310                                 event
.GetPosition()); 
1313         else if (event
.Moving()) 
1318                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
1319                 m_currentCursor 
= m_resizeCursor
; 
1323                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
1324                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1328                 SetCursor(*m_currentCursor
); 
1333 void wxListHeaderWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1335     m_owner
->SetFocus(); 
1339 bool wxListHeaderWindow::SendListEvent(wxEventType type
, const wxPoint
& pos
) 
1341     wxWindow 
*parent 
= GetParent(); 
1342     wxListEvent 
le( type
, parent
->GetId() ); 
1343     le
.SetEventObject( parent 
); 
1344     le
.m_pointDrag 
= pos
; 
1346     // the position should be relative to the parent window, not 
1347     // this one for compatibility with MSW and common sense: the 
1348     // user code doesn't know anything at all about this header 
1349     // window, so why should it get positions relative to it? 
1350     le
.m_pointDrag
.y 
-= GetSize().y
; 
1352     le
.m_col 
= m_column
; 
1353     return !parent
->GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
1356 //----------------------------------------------------------------------------- 
1357 // wxListRenameTimer (internal) 
1358 //----------------------------------------------------------------------------- 
1360 wxListRenameTimer::wxListRenameTimer( wxListMainWindow 
*owner 
) 
1365 void wxListRenameTimer::Notify() 
1367     m_owner
->OnRenameTimer(); 
1370 //----------------------------------------------------------------------------- 
1371 // wxListTextCtrlWrapper (internal) 
1372 //----------------------------------------------------------------------------- 
1374 BEGIN_EVENT_TABLE(wxListTextCtrlWrapper
, wxEvtHandler
) 
1375     EVT_CHAR           (wxListTextCtrlWrapper::OnChar
) 
1376     EVT_KEY_UP         (wxListTextCtrlWrapper::OnKeyUp
) 
1377     EVT_KILL_FOCUS     (wxListTextCtrlWrapper::OnKillFocus
) 
1380 wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow 
*owner
, 
1383               : m_startValue(owner
->GetItemText(itemEdit
)), 
1384                 m_itemEdited(itemEdit
) 
1388     m_aboutToFinish 
= false; 
1390     wxGenericListCtrl 
*parent 
= m_owner
->GetListCtrl(); 
1392     wxRect rectLabel 
= owner
->GetLineLabelRect(itemEdit
); 
1394     parent
->CalcScrolledPosition(rectLabel
.x
, rectLabel
.y
, 
1395                                   &rectLabel
.x
, &rectLabel
.y
); 
1397     m_text
->Create(owner
, wxID_ANY
, m_startValue
, 
1398                    wxPoint(rectLabel
.x
-4,rectLabel
.y
-4), 
1399                    wxSize(rectLabel
.width
+11,rectLabel
.height
+8)); 
1402     m_text
->PushEventHandler(this); 
1405 void wxListTextCtrlWrapper::EndEdit(EndReason reason
) 
1407     m_aboutToFinish 
= true; 
1412             // Notify the owner about the changes 
1415             // Even if vetoed, close the control (consistent with MSW) 
1420             m_owner
->OnRenameCancelled(m_itemEdited
); 
1426             // Don't generate any notifications for the control being destroyed 
1427             // and don't set focus to it neither. 
1433 void wxListTextCtrlWrapper::Finish( bool setfocus 
) 
1435     m_text
->RemoveEventHandler(this); 
1436     m_owner
->ResetTextControl( m_text 
); 
1438     wxPendingDelete
.Append( this ); 
1441         m_owner
->SetFocus(); 
1444 bool wxListTextCtrlWrapper::AcceptChanges() 
1446     const wxString value 
= m_text
->GetValue(); 
1448     // notice that we should always call OnRenameAccept() to generate the "end 
1449     // label editing" event, even if the user hasn't really changed anything 
1450     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
1452         // vetoed by the user 
1456     // accepted, do rename the item (unless nothing changed) 
1457     if ( value 
!= m_startValue 
) 
1458         m_owner
->SetItemText(m_itemEdited
, value
); 
1463 void wxListTextCtrlWrapper::OnChar( wxKeyEvent 
&event 
) 
1465     if ( !CheckForEndEditKey(event
) ) 
1469 bool wxListTextCtrlWrapper::CheckForEndEditKey(const wxKeyEvent
& event
) 
1471     switch ( event
.m_keyCode 
) 
1474             EndEdit( End_Accept 
); 
1478             EndEdit( End_Discard 
); 
1488 void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent 
&event 
) 
1490     if (m_aboutToFinish
) 
1492         // auto-grow the textctrl: 
1493         wxSize parentSize 
= m_owner
->GetSize(); 
1494         wxPoint myPos 
= m_text
->GetPosition(); 
1495         wxSize mySize 
= m_text
->GetSize(); 
1497         m_text
->GetTextExtent(m_text
->GetValue() + wxT("MM"), &sx
, &sy
); 
1498         if (myPos
.x 
+ sx 
> parentSize
.x
) 
1499             sx 
= parentSize
.x 
- myPos
.x
; 
1502        m_text
->SetSize(sx
, wxDefaultCoord
); 
1508 void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent 
&event 
) 
1510     if ( !m_aboutToFinish 
) 
1512         if ( !AcceptChanges() ) 
1513             m_owner
->OnRenameCancelled( m_itemEdited 
); 
1518     // We must let the native text control handle focus 
1522 //----------------------------------------------------------------------------- 
1524 //----------------------------------------------------------------------------- 
1526 BEGIN_EVENT_TABLE(wxListMainWindow
, wxWindow
) 
1527   EVT_PAINT          (wxListMainWindow::OnPaint
) 
1528   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse
) 
1529   EVT_CHAR_HOOK      (wxListMainWindow::OnCharHook
) 
1530   EVT_CHAR           (wxListMainWindow::OnChar
) 
1531   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown
) 
1532   EVT_KEY_UP         (wxListMainWindow::OnKeyUp
) 
1533   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus
) 
1534   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus
) 
1535   EVT_SCROLLWIN      (wxListMainWindow::OnScroll
) 
1536   EVT_CHILD_FOCUS    (wxListMainWindow::OnChildFocus
) 
1539 void wxListMainWindow::Init() 
1544     m_lineTo 
= (size_t)-1; 
1550     m_small_image_list 
= NULL
; 
1551     m_normal_image_list 
= NULL
; 
1553     m_small_spacing 
= 30; 
1554     m_normal_spacing 
= 40; 
1558     m_isCreated 
= false; 
1560     m_lastOnSame 
= false; 
1561     m_renameTimer 
= new wxListRenameTimer( this ); 
1562     m_textctrlWrapper 
= NULL
; 
1566     m_lineSelectSingleOnUp 
= 
1567     m_lineBeforeLastClicked 
= (size_t)-1; 
1570 wxListMainWindow::wxListMainWindow() 
1575     m_highlightUnfocusedBrush 
= NULL
; 
1578 wxListMainWindow::wxListMainWindow( wxWindow 
*parent
, 
1583                                     const wxString 
&name 
) 
1584                 : wxWindow( parent
, id
, pos
, size
, style
, name 
) 
1588     m_highlightBrush 
= new wxBrush
 
1590                             wxSystemSettings::GetColour
 
1592                                 wxSYS_COLOUR_HIGHLIGHT
 
1597     m_highlightUnfocusedBrush 
= new wxBrush
 
1599                                  wxSystemSettings::GetColour
 
1601                                      wxSYS_COLOUR_BTNSHADOW
 
1606     wxVisualAttributes attr 
= wxGenericListCtrl::GetClassDefaultAttributes(); 
1607     SetOwnForegroundColour( attr
.colFg 
); 
1608     SetOwnBackgroundColour( attr
.colBg 
); 
1610         SetOwnFont( attr
.font 
); 
1613 wxListMainWindow::~wxListMainWindow() 
1615     if ( m_textctrlWrapper 
) 
1616         m_textctrlWrapper
->EndEdit(wxListTextCtrlWrapper::End_Destroy
); 
1619     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
1620     WX_CLEAR_ARRAY(m_aColWidths
); 
1622     delete m_highlightBrush
; 
1623     delete m_highlightUnfocusedBrush
; 
1624     delete m_renameTimer
; 
1627 void wxListMainWindow::SetReportView(bool inReportView
) 
1629     const size_t count 
= m_lines
.size(); 
1630     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1632         m_lines
[n
].SetReportView(inReportView
); 
1636 void wxListMainWindow::CacheLineData(size_t line
) 
1638     wxGenericListCtrl 
*listctrl 
= GetListCtrl(); 
1640     wxListLineData 
*ld 
= GetDummyLine(); 
1642     size_t countCol 
= GetColumnCount(); 
1643     for ( size_t col 
= 0; col 
< countCol
; col
++ ) 
1645         ld
->SetText(col
, listctrl
->OnGetItemText(line
, col
)); 
1646         ld
->SetImage(col
, listctrl
->OnGetItemColumnImage(line
, col
)); 
1649     ld
->SetAttr(listctrl
->OnGetItemAttr(line
)); 
1652 wxListLineData 
*wxListMainWindow::GetDummyLine() const 
1654     wxASSERT_MSG( !IsEmpty(), wxT("invalid line index") ); 
1655     wxASSERT_MSG( IsVirtual(), wxT("GetDummyLine() shouldn't be called") ); 
1657     wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
1659     // we need to recreate the dummy line if the number of columns in the 
1660     // control changed as it would have the incorrect number of fields 
1662     if ( !m_lines
.IsEmpty() && 
1663             m_lines
[0].m_items
.GetCount() != (size_t)GetColumnCount() ) 
1665         self
->m_lines
.Clear(); 
1668     if ( m_lines
.IsEmpty() ) 
1670         wxListLineData 
*line 
= new wxListLineData(self
); 
1671         self
->m_lines
.Add(line
); 
1673         // don't waste extra memory -- there never going to be anything 
1674         // else/more in this array 
1675         self
->m_lines
.Shrink(); 
1681 // ---------------------------------------------------------------------------- 
1682 // line geometry (report mode only) 
1683 // ---------------------------------------------------------------------------- 
1685 wxCoord 
wxListMainWindow::GetLineHeight() const 
1687     // we cache the line height as calling GetTextExtent() is slow 
1688     if ( !m_lineHeight 
) 
1690         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
1692         wxClientDC 
dc( self 
); 
1693         dc
.SetFont( GetFont() ); 
1696         dc
.GetTextExtent(wxT("H"), NULL
, &y
); 
1698         if ( m_small_image_list 
&& m_small_image_list
->GetImageCount() ) 
1701             m_small_image_list
->GetSize(0, iw
, ih
); 
1706         self
->m_lineHeight 
= y 
+ LINE_SPACING
; 
1709     return m_lineHeight
; 
1712 wxCoord 
wxListMainWindow::GetLineY(size_t line
) const 
1714     wxASSERT_MSG( InReportView(), wxT("only works in report mode") ); 
1716     return LINE_SPACING 
+ line 
* GetLineHeight(); 
1719 wxRect 
wxListMainWindow::GetLineRect(size_t line
) const 
1721     if ( !InReportView() ) 
1722         return GetLine(line
)->m_gi
->m_rectAll
; 
1725     rect
.x 
= HEADER_OFFSET_X
; 
1726     rect
.y 
= GetLineY(line
); 
1727     rect
.width 
= GetHeaderWidth(); 
1728     rect
.height 
= GetLineHeight(); 
1733 wxRect 
wxListMainWindow::GetLineLabelRect(size_t line
) const 
1735     if ( !InReportView() ) 
1736         return GetLine(line
)->m_gi
->m_rectLabel
; 
1739     wxListLineData 
*data 
= GetLine(line
); 
1740     wxListItemDataList::compatibility_iterator node 
= data
->m_items
.GetFirst(); 
1743         wxListItemData 
*item 
= node
->GetData(); 
1744         if ( item
->HasImage() ) 
1747             GetImageSize( item
->GetImage(), ix
, iy 
); 
1748             image_x 
= 3 + ix 
+ IMAGE_MARGIN_IN_REPORT_MODE
; 
1753     rect
.x 
= image_x 
+ HEADER_OFFSET_X
; 
1754     rect
.y 
= GetLineY(line
); 
1755     rect
.width 
= GetColumnWidth(0) - image_x
; 
1756     rect
.height 
= GetLineHeight(); 
1761 wxRect 
wxListMainWindow::GetLineIconRect(size_t line
) const 
1763     if ( !InReportView() ) 
1764         return GetLine(line
)->m_gi
->m_rectIcon
; 
1766     wxListLineData 
*ld 
= GetLine(line
); 
1767     wxASSERT_MSG( ld
->HasImage(), wxT("should have an image") ); 
1770     rect
.x 
= HEADER_OFFSET_X
; 
1771     rect
.y 
= GetLineY(line
); 
1772     GetImageSize(ld
->GetImage(), rect
.width
, rect
.height
); 
1777 wxRect 
wxListMainWindow::GetLineHighlightRect(size_t line
) const 
1779     return InReportView() ? GetLineRect(line
) 
1780                           : GetLine(line
)->m_gi
->m_rectHighlight
; 
1783 long wxListMainWindow::HitTestLine(size_t line
, int x
, int y
) const 
1785     wxASSERT_MSG( line 
< GetItemCount(), wxT("invalid line in HitTestLine") ); 
1787     wxListLineData 
*ld 
= GetLine(line
); 
1789     if ( ld
->HasImage() && GetLineIconRect(line
).Contains(x
, y
) ) 
1790         return wxLIST_HITTEST_ONITEMICON
; 
1792     // VS: Testing for "ld->HasText() || InReportView()" instead of 
1793     //     "ld->HasText()" is needed to make empty lines in report view 
1795     if ( ld
->HasText() || InReportView() ) 
1797         wxRect rect 
= InReportView() ? GetLineRect(line
) 
1798                                      : GetLineLabelRect(line
); 
1800         if ( rect
.Contains(x
, y
) ) 
1801             return wxLIST_HITTEST_ONITEMLABEL
; 
1807 // ---------------------------------------------------------------------------- 
1808 // highlight (selection) handling 
1809 // ---------------------------------------------------------------------------- 
1811 bool wxListMainWindow::IsHighlighted(size_t line
) const 
1815         return m_selStore
.IsSelected(line
); 
1819         wxListLineData 
*ld 
= GetLine(line
); 
1820         wxCHECK_MSG( ld
, false, wxT("invalid index in IsHighlighted") ); 
1822         return ld
->IsHighlighted(); 
1826 void wxListMainWindow::HighlightLines( size_t lineFrom
, 
1832         wxArrayInt linesChanged
; 
1833         if ( !m_selStore
.SelectRange(lineFrom
, lineTo
, highlight
, 
1836             // meny items changed state, refresh everything 
1837             RefreshLines(lineFrom
, lineTo
); 
1839         else // only a few items changed state, refresh only them 
1841             size_t count 
= linesChanged
.GetCount(); 
1842             for ( size_t n 
= 0; n 
< count
; n
++ ) 
1844                 RefreshLine(linesChanged
[n
]); 
1848     else // iterate over all items in non report view 
1850         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
1852             if ( HighlightLine(line
, highlight
) ) 
1858 bool wxListMainWindow::HighlightLine( size_t line
, bool highlight 
) 
1864         changed 
= m_selStore
.SelectItem(line
, highlight
); 
1868         wxListLineData 
*ld 
= GetLine(line
); 
1869         wxCHECK_MSG( ld
, false, wxT("invalid index in HighlightLine") ); 
1871         changed 
= ld
->Highlight(highlight
); 
1876         SendNotify( line
, highlight 
? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
1877                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED 
); 
1883 void wxListMainWindow::RefreshLine( size_t line 
) 
1885     if ( InReportView() ) 
1887         size_t visibleFrom
, visibleTo
; 
1888         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
1890         if ( line 
< visibleFrom 
|| line 
> visibleTo 
) 
1894     wxRect rect 
= GetLineRect(line
); 
1896     GetListCtrl()->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
1897     RefreshRect( rect 
); 
1900 void wxListMainWindow::RefreshLines( size_t lineFrom
, size_t lineTo 
) 
1902     // we suppose that they are ordered by caller 
1903     wxASSERT_MSG( lineFrom 
<= lineTo
, wxT("indices in disorder") ); 
1905     wxASSERT_MSG( lineTo 
< GetItemCount(), wxT("invalid line range") ); 
1907     if ( InReportView() ) 
1909         size_t visibleFrom
, visibleTo
; 
1910         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
1912         if ( lineFrom 
< visibleFrom 
) 
1913             lineFrom 
= visibleFrom
; 
1914         if ( lineTo 
> visibleTo 
) 
1919         rect
.y 
= GetLineY(lineFrom
); 
1920         rect
.width 
= GetClientSize().x
; 
1921         rect
.height 
= GetLineY(lineTo
) - rect
.y 
+ GetLineHeight(); 
1923         GetListCtrl()->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
1924         RefreshRect( rect 
); 
1928         // TODO: this should be optimized... 
1929         for ( size_t line 
= lineFrom
; line 
<= lineTo
; line
++ ) 
1936 void wxListMainWindow::RefreshAfter( size_t lineFrom 
) 
1938     if ( InReportView() ) 
1940         size_t visibleFrom
, visibleTo
; 
1941         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
1943         if ( lineFrom 
< visibleFrom 
) 
1944             lineFrom 
= visibleFrom
; 
1945         else if ( lineFrom 
> visibleTo 
) 
1950         rect
.y 
= GetLineY(lineFrom
); 
1951         GetListCtrl()->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
1953         wxSize size 
= GetClientSize(); 
1954         rect
.width 
= size
.x
; 
1956         // refresh till the bottom of the window 
1957         rect
.height 
= size
.y 
- rect
.y
; 
1959         RefreshRect( rect 
); 
1963         // TODO: how to do it more efficiently? 
1968 void wxListMainWindow::RefreshSelected() 
1974     if ( InReportView() ) 
1976         GetVisibleLinesRange(&from
, &to
); 
1981         to 
= GetItemCount() - 1; 
1984     if ( HasCurrent() && m_current 
>= from 
&& m_current 
<= to 
) 
1985         RefreshLine(m_current
); 
1987     for ( size_t line 
= from
; line 
<= to
; line
++ ) 
1989         // NB: the test works as expected even if m_current == -1 
1990         if ( line 
!= m_current 
&& IsHighlighted(line
) ) 
1995 void wxListMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1997     // Note: a wxPaintDC must be constructed even if no drawing is 
1998     // done (a Windows requirement). 
1999     wxPaintDC 
dc( this ); 
2003         // nothing to draw or not the moment to draw it 
2008         RecalculatePositions( false ); 
2010     GetListCtrl()->PrepareDC( dc 
); 
2013     GetListCtrl()->CalcScrolledPosition( 0, 0, &dev_x
, &dev_y 
); 
2015     dc
.SetFont( GetFont() ); 
2017     if ( InReportView() ) 
2019         int lineHeight 
= GetLineHeight(); 
2021         size_t visibleFrom
, visibleTo
; 
2022         GetVisibleLinesRange(&visibleFrom
, &visibleTo
); 
2025         int xOrig 
= dc
.LogicalToDeviceX( 0 ); 
2026         int yOrig 
= dc
.LogicalToDeviceY( 0 ); 
2028         // tell the caller cache to cache the data 
2031             wxListEvent 
evCache(wxEVT_COMMAND_LIST_CACHE_HINT
, 
2032                                 GetParent()->GetId()); 
2033             evCache
.SetEventObject( GetParent() ); 
2034             evCache
.m_oldItemIndex 
= visibleFrom
; 
2035             evCache
.m_itemIndex 
= visibleTo
; 
2036             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2039         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2041             rectLine 
= GetLineRect(line
); 
2044             if ( !IsExposed(rectLine
.x 
+ xOrig
, rectLine
.y 
+ yOrig
, 
2045                             rectLine
.width
, rectLine
.height
) ) 
2047                 // don't redraw unaffected lines to avoid flicker 
2051             GetLine(line
)->DrawInReportMode( &dc
, 
2053                                              GetLineHighlightRect(line
), 
2054                                              IsHighlighted(line
), 
2055                                              line 
== m_current 
); 
2058         if ( HasFlag(wxLC_HRULES
) ) 
2060             wxPen 
pen(GetRuleColour(), 1, wxPENSTYLE_SOLID
); 
2061             wxSize clientSize 
= GetClientSize(); 
2063             size_t i 
= visibleFrom
; 
2064             if (i 
== 0) i 
= 1; // Don't draw the first one 
2065             for ( ; i 
<= visibleTo
; i
++ ) 
2068                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2069                 dc
.DrawLine(0 - dev_x
, i 
* lineHeight
, 
2070                             clientSize
.x 
- dev_x
, i 
* lineHeight
); 
2073             // Draw last horizontal rule 
2074             if ( visibleTo 
== GetItemCount() - 1 ) 
2077                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2078                 dc
.DrawLine(0 - dev_x
, (m_lineTo 
+ 1) * lineHeight
, 
2079                             clientSize
.x 
- dev_x 
, (m_lineTo 
+ 1) * lineHeight 
); 
2083         // Draw vertical rules if required 
2084         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2086             wxPen 
pen(GetRuleColour(), 1, wxPENSTYLE_SOLID
); 
2087             wxRect firstItemRect
, lastItemRect
; 
2089             GetItemRect(visibleFrom
, firstItemRect
); 
2090             GetItemRect(visibleTo
, lastItemRect
); 
2091             int x 
= firstItemRect
.GetX(); 
2093             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2095             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2097                 int colWidth 
= GetColumnWidth(col
); 
2099                 int x_pos 
= x 
- dev_x
; 
2100                 if (col 
< GetColumnCount()-1) x_pos 
-= 2; 
2101                 dc
.DrawLine(x_pos
, firstItemRect
.GetY() - 1 - dev_y
, 
2102                             x_pos
, lastItemRect
.GetBottom() + 1 - dev_y
); 
2108         size_t count 
= GetItemCount(); 
2109         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2111             GetLine(i
)->Draw( &dc
, i 
== m_current 
); 
2115     // DrawFocusRect() is unusable under Mac, it draws outside of the highlight 
2116     // rectangle somehow and so leaves traces when the item is not selected any 
2117     // more, see #12229. 
2122         if ( IsHighlighted(m_current
) ) 
2123             flags 
|= wxCONTROL_SELECTED
; 
2125         wxRendererNative::Get(). 
2126             DrawFocusRect(this, dc
, GetLineHighlightRect(m_current
), flags
); 
2128 #endif // !__WXMAC__ 
2131 void wxListMainWindow::HighlightAll( bool on 
) 
2133     if ( IsSingleSel() ) 
2135         wxASSERT_MSG( !on
, wxT("can't do this in a single selection control") ); 
2137         // we just have one item to turn off 
2138         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2140             HighlightLine(m_current
, false); 
2141             RefreshLine(m_current
); 
2144     else // multi selection 
2147             HighlightLines(0, GetItemCount() - 1, on
); 
2151 void wxListMainWindow::OnChildFocus(wxChildFocusEvent
& WXUNUSED(event
)) 
2153     // Do nothing here.  This prevents the default handler in wxScrolledWindow 
2154     // from needlessly scrolling the window when the edit control is 
2155     // dismissed.  See ticket #9563. 
2158 void wxListMainWindow::SendNotify( size_t line
, 
2159                                    wxEventType command
, 
2160                                    const wxPoint
& point 
) 
2162     wxListEvent 
le( command
, GetParent()->GetId() ); 
2163     le
.SetEventObject( GetParent() ); 
2165     le
.m_itemIndex 
= line
; 
2167     // set only for events which have position 
2168     if ( point 
!= wxDefaultPosition 
) 
2169         le
.m_pointDrag 
= point
; 
2171     // don't try to get the line info for virtual list controls: the main 
2172     // program has it anyhow and if we did it would result in accessing all 
2173     // the lines, even those which are not visible now and this is precisely 
2174     // what we're trying to avoid 
2177         if ( line 
!= (size_t)-1 ) 
2179             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2181         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2183     //else: there may be no more such item 
2185     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2188 void wxListMainWindow::ChangeCurrent(size_t current
) 
2190     m_current 
= current
; 
2192     // as the current item changed, we shouldn't start editing it when the 
2193     // "slow click" timer expires as the click happened on another item 
2194     if ( m_renameTimer
->IsRunning() ) 
2195         m_renameTimer
->Stop(); 
2197     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2200 wxTextCtrl 
*wxListMainWindow::EditLabel(long item
, wxClassInfo
* textControlClass
) 
2202     wxCHECK_MSG( (item 
>= 0) && ((size_t)item 
< GetItemCount()), NULL
, 
2203                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2205     wxASSERT_MSG( textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
)), 
2206                  wxT("EditLabel() needs a text control") ); 
2208     size_t itemEdit 
= (size_t)item
; 
2210     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2211     le
.SetEventObject( GetParent() ); 
2212     le
.m_itemIndex 
= item
; 
2213     wxListLineData 
*data 
= GetLine(itemEdit
); 
2214     wxCHECK_MSG( data
, NULL
, wxT("invalid index in EditLabel()") ); 
2215     data
->GetItem( 0, le
.m_item 
); 
2217     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2219         // vetoed by user code 
2223     // We have to call this here because the label in question might just have 
2224     // been added and no screen update taken place. 
2227         // TODO: use wxTheApp->SafeYieldFor(NULL, wxEVT_CATEGORY_UI) instead 
2228         //       so that no pending events may change the item count (see below) 
2229         //       IMPORTANT: needs to be tested! 
2232         // Pending events dispatched by wxSafeYield might have changed the item 
2234         if ( (size_t)item 
>= GetItemCount() ) 
2238     wxTextCtrl 
* const text 
= (wxTextCtrl 
*)textControlClass
->CreateObject(); 
2239     m_textctrlWrapper 
= new wxListTextCtrlWrapper(this, text
, item
); 
2240     return m_textctrlWrapper
->GetText(); 
2243 void wxListMainWindow::OnRenameTimer() 
2245     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2247     EditLabel( m_current 
); 
2250 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2252     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2253     le
.SetEventObject( GetParent() ); 
2254     le
.m_itemIndex 
= itemEdit
; 
2256     wxListLineData 
*data 
= GetLine(itemEdit
); 
2258     wxCHECK_MSG( data
, false, wxT("invalid index in OnRenameAccept()") ); 
2260     data
->GetItem( 0, le
.m_item 
); 
2261     le
.m_item
.m_text 
= value
; 
2262     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2266 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2268     // let owner know that the edit was cancelled 
2269     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2271     le
.SetEditCanceled(true); 
2273     le
.SetEventObject( GetParent() ); 
2274     le
.m_itemIndex 
= itemEdit
; 
2276     wxListLineData 
*data 
= GetLine(itemEdit
); 
2277     wxCHECK_RET( data
, wxT("invalid index in OnRenameCancelled()") ); 
2279     data
->GetItem( 0, le
.m_item 
); 
2280     GetEventHandler()->ProcessEvent( le 
); 
2283 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2286     // On wxMac we can't depend on the EVT_KILL_FOCUS event to properly 
2287     // shutdown the edit control when the mouse is clicked elsewhere on the 
2288     // listctrl because the order of events is different (or something like 
2289     // that), so explicitly end the edit if it is active. 
2290     if ( event
.LeftDown() && m_textctrlWrapper 
) 
2291         m_textctrlWrapper
->EndEdit(wxListTextCtrlWrapper::End_Accept
); 
2294     if ( event
.LeftDown() ) 
2297     event
.SetEventObject( GetParent() ); 
2298     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2301     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
2303         // let the base class handle mouse wheel events. 
2308     if ( !HasCurrent() || IsEmpty() ) 
2310         if (event
.RightDown()) 
2312             SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
2314             wxContextMenuEvent 
evtCtx(wxEVT_CONTEXT_MENU
, 
2315                                       GetParent()->GetId(), 
2316                                       ClientToScreen(event
.GetPosition())); 
2317             evtCtx
.SetEventObject(GetParent()); 
2318             GetParent()->GetEventHandler()->ProcessEvent(evtCtx
); 
2326     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
2327         event
.ButtonDClick()) ) 
2330     int x 
= event
.GetX(); 
2331     int y 
= event
.GetY(); 
2332     GetListCtrl()->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2334     // where did we hit it (if we did)? 
2337     size_t count 
= GetItemCount(), 
2340     if ( InReportView() ) 
2342         current 
= y 
/ GetLineHeight(); 
2343         if ( current 
< count 
) 
2344             hitResult 
= HitTestLine(current
, x
, y
); 
2348         // TODO: optimize it too! this is less simple than for report view but 
2349         //       enumerating all items is still not a way to do it!! 
2350         for ( current 
= 0; current 
< count
; current
++ ) 
2352             hitResult 
= HitTestLine(current
, x
, y
); 
2358     if (event
.Dragging()) 
2360         if (m_dragCount 
== 0) 
2362             // we have to report the raw, physical coords as we want to be 
2363             // able to call HitTest(event.m_pointDrag) from the user code to 
2364             // get the item being dragged 
2365             m_dragStart 
= event
.GetPosition(); 
2370         if (m_dragCount 
!= 3) 
2373         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
2374                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2376         wxListEvent 
le( command
, GetParent()->GetId() ); 
2377         le
.SetEventObject( GetParent() ); 
2378         le
.m_itemIndex 
= m_lineLastClicked
; 
2379         le
.m_pointDrag 
= m_dragStart
; 
2380         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2391         // outside of any item 
2392         if (event
.RightDown()) 
2394             SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
2396             wxContextMenuEvent 
evtCtx( 
2398                 GetParent()->GetId(), 
2399                 ClientToScreen(event
.GetPosition())); 
2400             evtCtx
.SetEventObject(GetParent()); 
2401             GetParent()->GetEventHandler()->ProcessEvent(evtCtx
); 
2405             // reset the selection and bail out 
2406             HighlightAll(false); 
2412     bool forceClick 
= false; 
2413     if (event
.ButtonDClick()) 
2415         if ( m_renameTimer
->IsRunning() ) 
2416             m_renameTimer
->Stop(); 
2418         m_lastOnSame 
= false; 
2420         if ( current 
== m_lineLastClicked 
) 
2422             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2428             // The first click was on another item, so don't interpret this as 
2429             // a double click, but as a simple click instead 
2436         if (m_lineSelectSingleOnUp 
!= (size_t)-1) 
2438             // select single line 
2439             HighlightAll( false ); 
2440             ReverseHighlight(m_lineSelectSingleOnUp
); 
2445             if ((current 
== m_current
) && 
2446                 (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
2447                 HasFlag(wxLC_EDIT_LABELS
) ) 
2449                 if ( !InReportView() || 
2450                         GetLineLabelRect(current
).Contains(x
, y
) ) 
2452                     int dclick 
= wxSystemSettings::GetMetric(wxSYS_DCLICK_MSEC
); 
2453                     m_renameTimer
->Start(dclick 
> 0 ? dclick 
: 250, true); 
2458         m_lastOnSame 
= false; 
2459         m_lineSelectSingleOnUp 
= (size_t)-1; 
2463         // This is necessary, because after a DnD operation in 
2464         // from and to ourself, the up event is swallowed by the 
2465         // DnD code. So on next non-up event (which means here and 
2466         // now) m_lineSelectSingleOnUp should be reset. 
2467         m_lineSelectSingleOnUp 
= (size_t)-1; 
2469     if (event
.RightDown()) 
2471         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2472         m_lineLastClicked 
= current
; 
2474         // If the item is already selected, do not update the selection. 
2475         // Multi-selections should not be cleared if a selected item is clicked. 
2476         if (!IsHighlighted(current
)) 
2478             HighlightAll(false); 
2479             ChangeCurrent(current
); 
2480             ReverseHighlight(m_current
); 
2483         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
2485         // Allow generation of context menu event 
2488     else if (event
.MiddleDown()) 
2490         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
2492     else if ( event
.LeftDown() || forceClick 
) 
2494         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2495         m_lineLastClicked 
= current
; 
2497         size_t oldCurrent 
= m_current
; 
2498         bool oldWasSelected 
= IsHighlighted(m_current
); 
2500         bool cmdModifierDown 
= event
.CmdDown(); 
2501         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
2503             if ( IsSingleSel() || !IsHighlighted(current
) ) 
2505                 HighlightAll( false ); 
2507                 ChangeCurrent(current
); 
2509                 ReverseHighlight(m_current
); 
2511             else // multi sel & current is highlighted & no mod keys 
2513                 m_lineSelectSingleOnUp 
= current
; 
2514                 ChangeCurrent(current
); // change focus 
2517         else // multi sel & either ctrl or shift is down 
2519             if (cmdModifierDown
) 
2521                 ChangeCurrent(current
); 
2523                 ReverseHighlight(m_current
); 
2525             else if (event
.ShiftDown()) 
2527                 ChangeCurrent(current
); 
2529                 size_t lineFrom 
= oldCurrent
, 
2532                 if ( lineTo 
< lineFrom 
) 
2535                     lineFrom 
= m_current
; 
2538                 HighlightLines(lineFrom
, lineTo
); 
2540             else // !ctrl, !shift 
2542                 // test in the enclosing if should make it impossible 
2543                 wxFAIL_MSG( wxT("how did we get here?") ); 
2547         if (m_current 
!= oldCurrent
) 
2548             RefreshLine( oldCurrent 
); 
2550         // forceClick is only set if the previous click was on another item 
2551         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
) && oldWasSelected
; 
2555 void wxListMainWindow::MoveToItem(size_t item
) 
2557     if ( item 
== (size_t)-1 ) 
2560     wxRect rect 
= GetLineRect(item
); 
2562     int client_w
, client_h
; 
2563     GetClientSize( &client_w
, &client_h 
); 
2565     const int hLine 
= GetLineHeight(); 
2567     int view_x 
= SCROLL_UNIT_X 
* GetListCtrl()->GetScrollPos( wxHORIZONTAL 
); 
2568     int view_y 
= hLine 
* GetListCtrl()->GetScrollPos( wxVERTICAL 
); 
2570     if ( InReportView() ) 
2572         // the next we need the range of lines shown it might be different, 
2573         // so recalculate it 
2574         ResetVisibleLinesRange(); 
2576         if (rect
.y 
< view_y
) 
2577             GetListCtrl()->Scroll( -1, rect
.y 
/ hLine 
); 
2578         if (rect
.y 
+ rect
.height 
+ 5 > view_y 
+ client_h
) 
2579             GetListCtrl()->Scroll( -1, (rect
.y 
+ rect
.height 
- client_h 
+ hLine
) / hLine 
); 
2582         // At least on Mac the visible lines value will get reset inside of 
2583         // Scroll *before* it actually scrolls the window because of the 
2584         // Update() that happens there, so it will still have the wrong value. 
2585         // So let's reset it again and wait for it to be recalculated in the 
2586         // next paint event.  I would expect this problem to show up in wxGTK 
2587         // too but couldn't duplicate it there.  Perhaps the order of events 
2588         // is different...  --Robin 
2589         ResetVisibleLinesRange(); 
2597         if (rect
.x
-view_x 
< 5) 
2598             sx 
= (rect
.x 
- 5) / SCROLL_UNIT_X
; 
2599         if (rect
.x 
+ rect
.width 
- 5 > view_x 
+ client_w
) 
2600             sx 
= (rect
.x 
+ rect
.width 
- client_w 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
; 
2602         if (rect
.y
-view_y 
< 5) 
2603             sy 
= (rect
.y 
- 5) / hLine
; 
2604         if (rect
.y 
+ rect
.height 
- 5 > view_y 
+ client_h
) 
2605             sy 
= (rect
.y 
+ rect
.height 
- client_h 
+ hLine
) / hLine
; 
2607         GetListCtrl()->Scroll(sx
, sy
); 
2611 bool wxListMainWindow::ScrollList(int WXUNUSED(dx
), int dy
) 
2613     if ( !InReportView() ) 
2615         // TODO: this should work in all views but is not implemented now 
2620     GetVisibleLinesRange(&top
, &bottom
); 
2622     if ( bottom 
== (size_t)-1 ) 
2625     ResetVisibleLinesRange(); 
2627     int hLine 
= GetLineHeight(); 
2629     GetListCtrl()->Scroll(-1, top 
+ dy 
/ hLine
); 
2632     // see comment in MoveToItem() for why we do this 
2633     ResetVisibleLinesRange(); 
2639 // ---------------------------------------------------------------------------- 
2640 // keyboard handling 
2641 // ---------------------------------------------------------------------------- 
2643 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
2645     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
2646                  wxT("invalid item index in OnArrowChar()") ); 
2648     size_t oldCurrent 
= m_current
; 
2650     // in single selection we just ignore Shift as we can't select several 
2652     if ( event
.ShiftDown() && !IsSingleSel() ) 
2654         ChangeCurrent(newCurrent
); 
2656         // refresh the old focus to remove it 
2657         RefreshLine( oldCurrent 
); 
2659         // select all the items between the old and the new one 
2660         if ( oldCurrent 
> newCurrent 
) 
2662             newCurrent 
= oldCurrent
; 
2663             oldCurrent 
= m_current
; 
2666         HighlightLines(oldCurrent
, newCurrent
); 
2670         // all previously selected items are unselected unless ctrl is held 
2671         // in a multiselection control 
2672         if ( !event
.ControlDown() || IsSingleSel() ) 
2673             HighlightAll(false); 
2675         ChangeCurrent(newCurrent
); 
2677         // refresh the old focus to remove it 
2678         RefreshLine( oldCurrent 
); 
2680         // in single selection mode we must always have a selected item 
2681         if ( !event
.ControlDown() || IsSingleSel() ) 
2682             HighlightLine( m_current
, true ); 
2685     RefreshLine( m_current 
); 
2690 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
2692     wxWindow 
*parent 
= GetParent(); 
2694     // propagate the key event upwards 
2695     wxKeyEvent 
ke(event
); 
2696     ke
.SetEventObject( parent 
); 
2697     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
2700     // send a list event 
2701     wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, parent
->GetId() ); 
2702     le
.m_itemIndex 
= m_current
; 
2704         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
2705     le
.m_code 
= event
.GetKeyCode(); 
2706     le
.SetEventObject( parent 
); 
2707     if (parent
->GetEventHandler()->ProcessEvent( le 
)) 
2713 void wxListMainWindow::OnKeyUp( wxKeyEvent 
&event 
) 
2715     wxWindow 
*parent 
= GetParent(); 
2717     // propagate the key event upwards 
2718     wxKeyEvent 
ke(event
); 
2719     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
2725 void wxListMainWindow::OnCharHook( wxKeyEvent 
&event 
) 
2727     if ( m_textctrlWrapper 
) 
2729         // When an in-place editor is active we should ensure that it always 
2730         // gets the key events that are special to it. 
2731         if ( m_textctrlWrapper
->CheckForEndEditKey(event
) ) 
2733             // Skip the call to wxEvent::Skip() below. 
2741 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
2743     wxWindow 
*parent 
= GetParent(); 
2745     // propagate the char event upwards 
2746     wxKeyEvent 
ke(event
); 
2747     ke
.SetEventObject( parent 
); 
2748     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
2751     if ( HandleAsNavigationKey(event
) ) 
2754     // no item -> nothing to do 
2761     // don't use m_linesPerPage directly as it might not be computed yet 
2762     const int pageSize 
= GetCountPerPage(); 
2763     wxCHECK_RET( pageSize
, wxT("should have non zero page size") ); 
2765     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2767         if (event
.GetKeyCode() == WXK_RIGHT
) 
2768             event
.m_keyCode 
= WXK_LEFT
; 
2769         else if (event
.GetKeyCode() == WXK_LEFT
) 
2770             event
.m_keyCode 
= WXK_RIGHT
; 
2773     switch ( event
.GetKeyCode() ) 
2776             if ( m_current 
> 0 ) 
2777                 OnArrowChar( m_current 
- 1, event 
); 
2781             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
2782                 OnArrowChar( m_current 
+ 1, event 
); 
2787                 OnArrowChar( GetItemCount() - 1, event 
); 
2792                 OnArrowChar( 0, event 
); 
2797                 int steps 
= InReportView() ? pageSize 
- 1 
2798                                            : m_current 
% pageSize
; 
2800                 int index 
= m_current 
- steps
; 
2804                 OnArrowChar( index
, event 
); 
2810                 int steps 
= InReportView() 
2812                                 : pageSize 
- (m_current 
% pageSize
) - 1; 
2814                 size_t index 
= m_current 
+ steps
; 
2815                 size_t count 
= GetItemCount(); 
2816                 if ( index 
>= count 
) 
2819                 OnArrowChar( index
, event 
); 
2824             if ( !InReportView() ) 
2826                 int index 
= m_current 
- pageSize
; 
2830                 OnArrowChar( index
, event 
); 
2835             if ( !InReportView() ) 
2837                 size_t index 
= m_current 
+ pageSize
; 
2839                 size_t count 
= GetItemCount(); 
2840                 if ( index 
>= count 
) 
2843                 OnArrowChar( index
, event 
); 
2848             if ( IsSingleSel() ) 
2850                 if ( event
.ControlDown() ) 
2852                     ReverseHighlight(m_current
); 
2854                 else // normal space press 
2856                     SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2859             else // multiple selection 
2861                 ReverseHighlight(m_current
); 
2867             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2875 // ---------------------------------------------------------------------------- 
2877 // ---------------------------------------------------------------------------- 
2879 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
2883         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
2884         event
.SetEventObject( GetParent() ); 
2885         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2889     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
2890     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
2891     // which are already drawn correctly resulting in horrible flicker - avoid 
2901 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
2905         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
2906         event
.SetEventObject( GetParent() ); 
2907         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2915 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
2917     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
2919         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
2921     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
2923         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
2925     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
2927         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
2929     else if ( InReportView() && (m_small_image_list
)) 
2931         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
2935 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
2937     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
2939         m_normal_image_list
->GetSize( index
, width
, height 
); 
2941     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
2943         m_small_image_list
->GetSize( index
, width
, height 
); 
2945     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
2947         m_small_image_list
->GetSize( index
, width
, height 
); 
2949     else if ( InReportView() && m_small_image_list 
) 
2951         m_small_image_list
->GetSize( index
, width
, height 
); 
2960 int wxListMainWindow::GetTextLength( const wxString 
&s 
) const 
2962     wxClientDC 
dc( wxConstCast(this, wxListMainWindow
) ); 
2963     dc
.SetFont( GetFont() ); 
2966     dc
.GetTextExtent( s
, &lw
, NULL 
); 
2968     return lw 
+ AUTOSIZE_COL_MARGIN
; 
2971 void wxListMainWindow::SetImageList( wxImageList 
*imageList
, int which 
) 
2975     // calc the spacing from the icon size 
2976     int width 
= 0, height 
= 0; 
2978     if ((imageList
) && (imageList
->GetImageCount()) ) 
2979         imageList
->GetSize(0, width
, height
); 
2981     if (which 
== wxIMAGE_LIST_NORMAL
) 
2983         m_normal_image_list 
= imageList
; 
2984         m_normal_spacing 
= width 
+ 8; 
2987     if (which 
== wxIMAGE_LIST_SMALL
) 
2989         m_small_image_list 
= imageList
; 
2990         m_small_spacing 
= width 
+ 14; 
2991         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
2995 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
2999         m_small_spacing 
= spacing
; 
3001         m_normal_spacing 
= spacing
; 
3004 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3006     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3009 // ---------------------------------------------------------------------------- 
3011 // ---------------------------------------------------------------------------- 
3013 void wxListMainWindow::SetColumn( int col
, wxListItem 
&item 
) 
3015     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3017     wxCHECK_RET( node
, wxT("invalid column index in SetColumn") ); 
3019     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3020         item
.m_width 
= GetTextLength( item
.m_text 
); 
3022     wxListHeaderData 
*column 
= node
->GetData(); 
3023     column
->SetItem( item 
); 
3025     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3027         headerWin
->m_dirty 
= true; 
3031     // invalidate it as it has to be recalculated 
3035 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3037     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3038                  wxT("invalid column index") ); 
3040     wxCHECK_RET( InReportView(), 
3041                  wxT("SetColumnWidth() can only be called in report mode.") ); 
3045     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3047         headerWin
->m_dirty 
= true; 
3049     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3050     wxCHECK_RET( node
, wxT("no column?") ); 
3052     wxListHeaderData 
*column 
= node
->GetData(); 
3054     size_t count 
= GetItemCount(); 
3056     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3058         width 
= GetTextLength(column
->GetText()); 
3059         width 
+= 2*EXTRA_WIDTH
; 
3061         // check for column header's image availability 
3062         const int image 
= column
->GetImage(); 
3065             if ( m_small_image_list 
) 
3068                 m_small_image_list
->GetSize(image
, ix
, iy
); 
3069                 width 
+= ix 
+ HEADER_IMAGE_MARGIN_IN_REPORT_MODE
; 
3073     else if ( width 
== wxLIST_AUTOSIZE 
) 
3077             // TODO: determine the max width somehow... 
3078             width 
= WIDTH_COL_DEFAULT
; 
3082             wxClientDC 
dc(this); 
3083             dc
.SetFont( GetFont() ); 
3085             int max 
= AUTOSIZE_COL_MARGIN
; 
3087             //  if the cached column width isn't valid then recalculate it 
3088             if (m_aColWidths
.Item(col
)->bNeedsUpdate
) 
3090                 for (size_t i 
= 0; i 
< count
; i
++) 
3092                     wxListLineData 
*line 
= GetLine( i 
); 
3093                     wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3095                     wxCHECK_RET( n
, wxT("no subitem?") ); 
3097                     wxListItemData 
*itemData 
= n
->GetData(); 
3100                     itemData
->GetItem(item
); 
3101                     int itemWidth 
= GetItemWidthWithImage(&item
); 
3102                     if (itemWidth 
> max
) 
3106                 m_aColWidths
.Item(col
)->bNeedsUpdate 
= false; 
3107                 m_aColWidths
.Item(col
)->nMaxWidth 
= max
; 
3110             max 
= m_aColWidths
.Item(col
)->nMaxWidth
; 
3111             width 
= max 
+ AUTOSIZE_COL_MARGIN
; 
3115     column
->SetWidth( width 
); 
3117     // invalidate it as it has to be recalculated 
3121 int wxListMainWindow::GetHeaderWidth() const 
3123     if ( !m_headerWidth 
) 
3125         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3127         size_t count 
= GetColumnCount(); 
3128         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3130             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3134     return m_headerWidth
; 
3137 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3139     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3140     wxCHECK_RET( node
, wxT("invalid column index in GetColumn") ); 
3142     wxListHeaderData 
*column 
= node
->GetData(); 
3143     column
->GetItem( item 
); 
3146 int wxListMainWindow::GetColumnWidth( int col 
) const 
3148     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3149     wxCHECK_MSG( node
, 0, wxT("invalid column index") ); 
3151     wxListHeaderData 
*column 
= node
->GetData(); 
3152     return column
->GetWidth(); 
3155 // ---------------------------------------------------------------------------- 
3157 // ---------------------------------------------------------------------------- 
3159 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3161     long id 
= item
.m_itemId
; 
3162     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3163                  wxT("invalid item index in SetItem") ); 
3167         wxListLineData 
*line 
= GetLine((size_t)id
); 
3168         line
->SetItem( item
.m_col
, item 
); 
3170         // Set item state if user wants 
3171         if ( item
.m_mask 
& wxLIST_MASK_STATE 
) 
3172             SetItemState( item
.m_itemId
, item
.m_state
, item
.m_state 
); 
3176             //  update the Max Width Cache if needed 
3177             int width 
= GetItemWidthWithImage(&item
); 
3179             if (width 
> m_aColWidths
.Item(item
.m_col
)->nMaxWidth
) 
3180                 m_aColWidths
.Item(item
.m_col
)->nMaxWidth 
= width
; 
3184     // update the item on screen 
3186     GetItemRect(id
, rectItem
); 
3187     RefreshRect(rectItem
); 
3190 void wxListMainWindow::SetItemStateAll(long state
, long stateMask
) 
3195     // first deal with selection 
3196     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3198         // set/clear select state 
3201             // optimized version for virtual listctrl. 
3202             m_selStore
.SelectRange(0, GetItemCount() - 1, state 
== wxLIST_STATE_SELECTED
); 
3205         else if ( state 
& wxLIST_STATE_SELECTED 
) 
3207             const long count 
= GetItemCount(); 
3208             for( long i 
= 0; i 
<  count
; i
++ ) 
3210                 SetItemState( i
, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED 
); 
3216             // clear for non virtual (somewhat optimized by using GetNextItem()) 
3218             while ( (i 
= GetNextItem(i
, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
)) != -1 ) 
3220                 SetItemState( i
, 0, wxLIST_STATE_SELECTED 
); 
3225     if ( HasCurrent() && (state 
== 0) && (stateMask 
& wxLIST_STATE_FOCUSED
) ) 
3227         // unfocus all: only one item can be focussed, so clearing focus for 
3228         // all items is simply clearing focus of the focussed item. 
3229         SetItemState(m_current
, state
, stateMask
); 
3231     //(setting focus to all items makes no sense, so it is not handled here.) 
3234 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3238         SetItemStateAll(state
, stateMask
); 
3242     wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3243                  wxT("invalid list ctrl item index in SetItem") ); 
3245     size_t oldCurrent 
= m_current
; 
3246     size_t item 
= (size_t)litem
;    // safe because of the check above 
3248     // do we need to change the focus? 
3249     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3251         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3253             // don't do anything if this item is already focused 
3254             if ( item 
!= m_current 
) 
3256                 ChangeCurrent(item
); 
3258                 if ( oldCurrent 
!= (size_t)-1 ) 
3260                     if ( IsSingleSel() ) 
3262                         HighlightLine(oldCurrent
, false); 
3265                     RefreshLine(oldCurrent
); 
3268                 RefreshLine( m_current 
); 
3273             // don't do anything if this item is not focused 
3274             if ( item 
== m_current 
) 
3278                 if ( IsSingleSel() ) 
3280                     // we must unselect the old current item as well or we 
3281                     // might end up with more than one selected item in a 
3282                     // single selection control 
3283                     HighlightLine(oldCurrent
, false); 
3286                 RefreshLine( oldCurrent 
); 
3291     // do we need to change the selection state? 
3292     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3294         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3296         if ( IsSingleSel() ) 
3300                 // selecting the item also makes it the focused one in the 
3302                 if ( m_current 
!= item 
) 
3304                     ChangeCurrent(item
); 
3306                     if ( oldCurrent 
!= (size_t)-1 ) 
3308                         HighlightLine( oldCurrent
, false ); 
3309                         RefreshLine( oldCurrent 
); 
3315                 // only the current item may be selected anyhow 
3316                 if ( item 
!= m_current 
) 
3321         if ( HighlightLine(item
, on
) ) 
3328 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
3330     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3331                  wxT("invalid list ctrl item index in GetItemState()") ); 
3333     int ret 
= wxLIST_STATE_DONTCARE
; 
3335     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3337         if ( (size_t)item 
== m_current 
) 
3338             ret 
|= wxLIST_STATE_FOCUSED
; 
3341     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3343         if ( IsHighlighted(item
) ) 
3344             ret 
|= wxLIST_STATE_SELECTED
; 
3350 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
3352     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3353                  wxT("invalid item index in GetItem") ); 
3355     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3356     line
->GetItem( item
.m_col
, item 
); 
3358     // Get item state if user wants it 
3359     if ( item
.m_mask 
& wxLIST_MASK_STATE 
) 
3360         item
.m_state 
= GetItemState( item
.m_itemId
, wxLIST_STATE_SELECTED 
| 
3361                                                  wxLIST_STATE_FOCUSED 
); 
3364 // ---------------------------------------------------------------------------- 
3366 // ---------------------------------------------------------------------------- 
3368 size_t wxListMainWindow::GetItemCount() const 
3370     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3373 void wxListMainWindow::SetItemCount(long count
) 
3375     m_selStore
.SetItemCount(count
); 
3376     m_countVirt 
= count
; 
3378     ResetVisibleLinesRange(); 
3380     // scrollbars must be reset 
3384 int wxListMainWindow::GetSelectedItemCount() const 
3386     // deal with the quick case first 
3387     if ( IsSingleSel() ) 
3388         return HasCurrent() ? IsHighlighted(m_current
) : false; 
3390     // virtual controls remmebers all its selections itself 
3392         return m_selStore
.GetSelectedCount(); 
3394     // TODO: we probably should maintain the number of items selected even for 
3395     //       non virtual controls as enumerating all lines is really slow... 
3396     size_t countSel 
= 0; 
3397     size_t count 
= GetItemCount(); 
3398     for ( size_t line 
= 0; line 
< count
; line
++ ) 
3400         if ( GetLine(line
)->IsHighlighted() ) 
3407 // ---------------------------------------------------------------------------- 
3408 // item position/size 
3409 // ---------------------------------------------------------------------------- 
3411 wxRect 
wxListMainWindow::GetViewRect() const 
3413     wxASSERT_MSG( !HasFlag(wxLC_LIST
), "not implemented for list view" ); 
3415     // we need to find the longest/tallest label 
3416     wxCoord xMax 
= 0, yMax 
= 0; 
3417     const int count 
= GetItemCount(); 
3420         for ( int i 
= 0; i 
< count
; i
++ ) 
3422             // we need logical, not physical, coordinates here, so use 
3423             // GetLineRect() instead of GetItemRect() 
3424             wxRect r 
= GetLineRect(i
); 
3426             wxCoord x 
= r
.GetRight(), 
3436     // some fudge needed to make it look prettier 
3437     xMax 
+= 2 * EXTRA_BORDER_X
; 
3438     yMax 
+= 2 * EXTRA_BORDER_Y
; 
3440     // account for the scrollbars if necessary 
3441     const wxSize sizeAll 
= GetClientSize(); 
3442     if ( xMax 
> sizeAll
.x 
) 
3443         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
3444     if ( yMax 
> sizeAll
.y 
) 
3445         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
3447     return wxRect(0, 0, xMax
, yMax
); 
3451 wxListMainWindow::GetSubItemRect(long item
, long subItem
, wxRect
& rect
) const 
3453     wxCHECK_MSG( subItem 
== wxLIST_GETSUBITEMRECT_WHOLEITEM 
|| InReportView(), 
3455                  wxT("GetSubItemRect only meaningful in report view") ); 
3456     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), false, 
3457                  wxT("invalid item in GetSubItemRect") ); 
3459     // ensure that we're laid out, otherwise we could return nonsense 
3462         wxConstCast(this, wxListMainWindow
)-> 
3463             RecalculatePositions(true /* no refresh */); 
3466     rect 
= GetLineRect((size_t)item
); 
3468     // Adjust rect to specified column 
3469     if ( subItem 
!= wxLIST_GETSUBITEMRECT_WHOLEITEM 
) 
3471         wxCHECK_MSG( subItem 
>= 0 && subItem 
< GetColumnCount(), false, 
3472                      wxT("invalid subItem in GetSubItemRect") ); 
3474         for (int i 
= 0; i 
< subItem
; i
++) 
3476             rect
.x 
+= GetColumnWidth(i
); 
3478         rect
.width 
= GetColumnWidth(subItem
); 
3481     GetListCtrl()->CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
3486 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
3489     GetItemRect(item
, rect
); 
3497 // ---------------------------------------------------------------------------- 
3498 // geometry calculation 
3499 // ---------------------------------------------------------------------------- 
3501 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
3503     const int lineHeight 
= GetLineHeight(); 
3505     wxClientDC 
dc( this ); 
3506     dc
.SetFont( GetFont() ); 
3508     const size_t count 
= GetItemCount(); 
3511     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3512         iconSpacing 
= m_normal_spacing
; 
3513     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3514         iconSpacing 
= m_small_spacing
; 
3518     // Note that we do not call GetClientSize() here but 
3519     // GetSize() and subtract the border size for sunken 
3520     // borders manually. This is technically incorrect, 
3521     // but we need to know the client area's size WITHOUT 
3522     // scrollbars here. Since we don't know if there are 
3523     // any scrollbars, we use GetSize() instead. Another 
3524     // solution would be to call SetScrollbars() here to 
3525     // remove the scrollbars and call GetClientSize() then, 
3526     // but this might result in flicker and - worse - will 
3527     // reset the scrollbars to 0 which is not good at all 
3528     // if you resize a dialog/window, but don't want to 
3529     // reset the window scrolling. RR. 
3530     // Furthermore, we actually do NOT subtract the border 
3531     // width as 2 pixels is just the extra space which we 
3532     // need around the actual content in the window. Other- 
3533     // wise the text would e.g. touch the upper border. RR. 
3536     GetSize( &clientWidth
, &clientHeight 
); 
3538     if ( InReportView() ) 
3540         // all lines have the same height and we scroll one line per step 
3541         int entireHeight 
= count 
* lineHeight 
+ LINE_SPACING
; 
3543         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
3545         ResetVisibleLinesRange(); 
3547         GetListCtrl()->SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
3548                        GetHeaderWidth() / SCROLL_UNIT_X
, 
3549                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
3550                        GetListCtrl()->GetScrollPos(wxHORIZONTAL
), 
3551                        GetListCtrl()->GetScrollPos(wxVERTICAL
), 
3556         // we have 3 different layout strategies: either layout all items 
3557         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
3558         // to arrange them in top to bottom, left to right (don't ask me why 
3559         // not the other way round...) order 
3560         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
3562             int x 
= EXTRA_BORDER_X
; 
3563             int y 
= EXTRA_BORDER_Y
; 
3565             wxCoord widthMax 
= 0; 
3568             for ( i 
= 0; i 
< count
; i
++ ) 
3570                 wxListLineData 
*line 
= GetLine(i
); 
3571                 line
->CalculateSize( &dc
, iconSpacing 
); 
3572                 line
->SetPosition( x
, y
, iconSpacing 
); 
3574                 wxSize sizeLine 
= GetLineSize(i
); 
3576                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3578                     if ( sizeLine
.x 
> widthMax 
) 
3579                         widthMax 
= sizeLine
.x
; 
3583                 else // wxLC_ALIGN_LEFT 
3585                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
3589             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3591                 // traverse the items again and tweak their sizes so that they are 
3592                 // all the same in a row 
3593                 for ( i 
= 0; i 
< count
; i
++ ) 
3595                     wxListLineData 
*line 
= GetLine(i
); 
3596                     line
->m_gi
->ExtendWidth(widthMax
); 
3600             GetListCtrl()->SetScrollbars
 
3604                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3605                 (y 
+ lineHeight
) / lineHeight
, 
3606                 GetListCtrl()->GetScrollPos( wxHORIZONTAL 
), 
3607                 GetListCtrl()->GetScrollPos( wxVERTICAL 
), 
3611         else // "flowed" arrangement, the most complicated case 
3613             // at first we try without any scrollbars, if the items don't fit into 
3614             // the window, we recalculate after subtracting the space taken by the 
3617             int entireWidth 
= 0; 
3619             for (int tries 
= 0; tries 
< 2; tries
++) 
3621                 entireWidth 
= 2 * EXTRA_BORDER_X
; 
3625                     // Now we have decided that the items do not fit into the 
3626                     // client area, so we need a scrollbar 
3627                     entireWidth 
+= SCROLL_UNIT_X
; 
3630                 int x 
= EXTRA_BORDER_X
; 
3631                 int y 
= EXTRA_BORDER_Y
; 
3633                 // Note that "row" here is vertical, i.e. what is called 
3634                 // "column" in many other places in wxWidgets. 
3635                 int maxWidthInThisRow 
= 0; 
3638                 int currentlyVisibleLines 
= 0; 
3640                 for (size_t i 
= 0; i 
< count
; i
++) 
3642                     currentlyVisibleLines
++; 
3643                     wxListLineData 
*line 
= GetLine( i 
); 
3644                     line
->CalculateSize( &dc
, iconSpacing 
); 
3645                     line
->SetPosition( x
, y
, iconSpacing 
); 
3647                     wxSize sizeLine 
= GetLineSize( i 
); 
3649                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
3650                         maxWidthInThisRow 
= sizeLine
.x
; 
3653                     if (currentlyVisibleLines 
> m_linesPerPage
) 
3654                         m_linesPerPage 
= currentlyVisibleLines
; 
3656                     // Have we reached the end of the row either because no 
3657                     // more items would fit or because there are simply no more 
3659                     if ( y 
+ sizeLine
.y 
>= clientHeight
 
3662                         // Adjust all items in this row to have the same 
3663                         // width to ensure that they all align horizontally. 
3664                         size_t firstRowLine 
= i 
- currentlyVisibleLines 
+ 1; 
3665                         for (size_t j 
= firstRowLine
; j 
<= i
; j
++) 
3667                             GetLine(j
)->m_gi
->ExtendWidth(maxWidthInThisRow
); 
3670                         currentlyVisibleLines 
= 0; 
3672                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
3673                         x 
+= maxWidthInThisRow
; 
3674                         entireWidth 
+= maxWidthInThisRow
; 
3675                         maxWidthInThisRow 
= 0; 
3678                     if ( (tries 
== 0) && 
3679                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
3681                         clientHeight 
-= wxSystemSettings:: 
3682                                             GetMetric(wxSYS_HSCROLL_Y
); 
3687                     if ( i 
== count 
- 1 ) 
3688                         tries 
= 1;  // Everything fits, no second try required. 
3692             GetListCtrl()->SetScrollbars
 
3696                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3698                 GetListCtrl()->GetScrollPos( wxHORIZONTAL 
), 
3707         // FIXME: why should we call it from here? 
3714 void wxListMainWindow::RefreshAll() 
3719     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3720     if ( headerWin 
&& headerWin
->m_dirty 
) 
3722         headerWin
->m_dirty 
= false; 
3723         headerWin
->Refresh(); 
3727 void wxListMainWindow::UpdateCurrent() 
3729     if ( !HasCurrent() && !IsEmpty() ) 
3733 long wxListMainWindow::GetNextItem( long item
, 
3734                                     int WXUNUSED(geometry
), 
3738          max 
= GetItemCount(); 
3739     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
3740                  wxT("invalid listctrl index in GetNextItem()") ); 
3742     // notice that we start with the next item (or the first one if item == -1) 
3743     // and this is intentional to allow writing a simple loop to iterate over 
3744     // all selected items 
3747         // this is not an error because the index was OK initially, 
3748         // just no such item 
3755     size_t count 
= GetItemCount(); 
3756     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
3758         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
3761         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
3768 // ---------------------------------------------------------------------------- 
3770 // ---------------------------------------------------------------------------- 
3772 void wxListMainWindow::DeleteItem( long lindex 
) 
3774     size_t count 
= GetItemCount(); 
3776     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
3777                  wxT("invalid item index in DeleteItem") ); 
3779     size_t index 
= (size_t)lindex
; 
3781     // we don't need to adjust the index for the previous items 
3782     if ( HasCurrent() && m_current 
>= index 
) 
3784         // if the current item is being deleted, we want the next one to 
3785         // become selected - unless there is no next one - so don't adjust 
3786         // m_current in this case 
3787         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
3791     if ( InReportView() ) 
3793         //  mark the Column Max Width cache as dirty if the items in the line 
3794         //  we're deleting contain the Max Column Width 
3795         wxListLineData 
* const line 
= GetLine(index
); 
3796         wxListItemDataList::compatibility_iterator n
; 
3797         wxListItemData 
*itemData
; 
3801         for (size_t i 
= 0; i 
< m_columns
.GetCount(); i
++) 
3803             n 
= line
->m_items
.Item( i 
); 
3804             itemData 
= n
->GetData(); 
3805             itemData
->GetItem(item
); 
3807             itemWidth 
= GetItemWidthWithImage(&item
); 
3809             if (itemWidth 
>= m_aColWidths
.Item(i
)->nMaxWidth
) 
3810                 m_aColWidths
.Item(i
)->bNeedsUpdate 
= true; 
3813         ResetVisibleLinesRange(); 
3816     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
, wxDefaultPosition 
); 
3821         m_selStore
.OnItemDelete(index
); 
3825         m_lines
.RemoveAt( index 
); 
3828     // we need to refresh the (vert) scrollbar as the number of items changed 
3831     RefreshAfter(index
); 
3834 void wxListMainWindow::DeleteColumn( int col 
) 
3836     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3838     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
3841     delete node
->GetData(); 
3842     m_columns
.Erase( node 
); 
3846         // update all the items 
3847         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
3849             wxListLineData 
* const line 
= GetLine(i
); 
3851             // In the following atypical but possible scenario it can be 
3852             // legal to call DeleteColumn() but the items may not have any 
3854             //  1. In report view, insert a second column. 
3855             //  2. Still in report view, add an item with 2 values. 
3856             //  3. Switch to an icon (or list) view. 
3857             //  4. Add an item -- necessarily with 1 value only. 
3858             //  5. Switch back to report view. 
3859             //  6. Call DeleteColumn(). 
3860             // So we need to check for this as otherwise we would simply crash 
3862             if ( line
->m_items
.GetCount() <= static_cast<unsigned>(col
) ) 
3865             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3866             delete n
->GetData(); 
3867             line
->m_items
.Erase(n
); 
3871     if ( InReportView() )   //  we only cache max widths when in Report View 
3873         delete m_aColWidths
.Item(col
); 
3874         m_aColWidths
.RemoveAt(col
); 
3877     // invalidate it as it has to be recalculated 
3881 void wxListMainWindow::DoDeleteAllItems() 
3884         // nothing to do - in particular, don't send the event 
3889     // to make the deletion of all items faster, we don't send the 
3890     // notifications for each item deletion in this case but only one event 
3891     // for all of them: this is compatible with wxMSW and documented in 
3892     // DeleteAllItems() description 
3894     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
3895     event
.SetEventObject( GetParent() ); 
3896     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
3904     if ( InReportView() ) 
3906         ResetVisibleLinesRange(); 
3907         for (size_t i 
= 0; i 
< m_aColWidths
.GetCount(); i
++) 
3909             m_aColWidths
.Item(i
)->bNeedsUpdate 
= true; 
3916 void wxListMainWindow::DeleteAllItems() 
3920     RecalculatePositions(); 
3923 void wxListMainWindow::DeleteEverything() 
3925     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
3926     WX_CLEAR_ARRAY(m_aColWidths
); 
3931 // ---------------------------------------------------------------------------- 
3932 // scanning for an item 
3933 // ---------------------------------------------------------------------------- 
3935 void wxListMainWindow::EnsureVisible( long index 
) 
3937     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3938                  wxT("invalid index in EnsureVisible") ); 
3940     // We have to call this here because the label in question might just have 
3941     // been added and its position is not known yet 
3943         RecalculatePositions(true /* no refresh */); 
3945     MoveToItem((size_t)index
); 
3948 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool partial 
) 
3954     wxString str_upper 
= str
.Upper(); 
3958     size_t count 
= GetItemCount(); 
3959     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
3961         wxListLineData 
*line 
= GetLine(i
); 
3962         wxString line_upper 
= line
->GetText(0).Upper(); 
3965             if (line_upper 
== str_upper 
) 
3970             if (line_upper
.find(str_upper
) == 0) 
3978 long wxListMainWindow::FindItem(long start
, wxUIntPtr data
) 
3984     size_t count 
= GetItemCount(); 
3985     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
3987         wxListLineData 
*line 
= GetLine(i
); 
3989         line
->GetItem( 0, item 
); 
3990         if (item
.m_data 
== data
) 
3997 long wxListMainWindow::FindItem( const wxPoint
& pt 
) 
4000     GetVisibleLinesRange( &topItem
, NULL 
); 
4003     GetItemPosition( GetItemCount() - 1, p 
); 
4007     long id 
= (long)floor( pt
.y 
* double(GetItemCount() - topItem 
- 1) / p
.y 
+ topItem 
); 
4008     if ( id 
>= 0 && id 
< (long)GetItemCount() ) 
4014 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) const 
4016     GetListCtrl()->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4018     size_t count 
= GetItemCount(); 
4020     if ( InReportView() ) 
4022         size_t current 
= y 
/ GetLineHeight(); 
4023         if ( current 
< count 
) 
4025             flags 
= HitTestLine(current
, x
, y
); 
4032         // TODO: optimize it too! this is less simple than for report view but 
4033         //       enumerating all items is still not a way to do it!! 
4034         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4036             flags 
= HitTestLine(current
, x
, y
); 
4045 // ---------------------------------------------------------------------------- 
4047 // ---------------------------------------------------------------------------- 
4049 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4051     wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual control") ); 
4053     int count 
= GetItemCount(); 
4054     wxCHECK_RET( item
.m_itemId 
>= 0, wxT("invalid item index") ); 
4056     if (item
.m_itemId 
> count
) 
4057         item
.m_itemId 
= count
; 
4059     size_t id 
= item
.m_itemId
; 
4063     if ( InReportView() ) 
4065         ResetVisibleLinesRange(); 
4067         const unsigned col 
= item
.GetColumn(); 
4068         wxCHECK_RET( col 
< m_aColWidths
.size(), "invalid item column" ); 
4070         // calculate the width of the item and adjust the max column width 
4071         wxColWidthInfo 
*pWidthInfo 
= m_aColWidths
.Item(col
); 
4072         int width 
= GetItemWidthWithImage(&item
); 
4073         item
.SetWidth(width
); 
4074         if (width 
> pWidthInfo
->nMaxWidth
) 
4075             pWidthInfo
->nMaxWidth 
= width
; 
4078     wxListLineData 
*line 
= new wxListLineData(this); 
4080     line
->SetItem( item
.m_col
, item 
); 
4081     if ( item
.m_mask 
& wxLIST_MASK_IMAGE 
) 
4083         // Reset the buffered height if it's not big enough for the new image. 
4084         int image 
= item
.GetImage(); 
4085         if ( m_small_image_list 
&& image 
!= -1 && InReportView() ) 
4087             int imageWidth
, imageHeight
; 
4088             m_small_image_list
->GetSize(image
, imageWidth
, imageHeight
); 
4090             if ( imageHeight 
> m_lineHeight 
) 
4095     m_lines
.Insert( line
, id 
); 
4099     // If an item is selected at or below the point of insertion, we need to 
4100     // increment the member variables because the current row's index has gone 
4102     if ( HasCurrent() && m_current 
>= id 
) 
4105     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4107     RefreshLines(id
, GetItemCount() - 1); 
4110 void wxListMainWindow::InsertColumn( long col
, wxListItem 
&item 
) 
4113     if ( InReportView() ) 
4115         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4116             item
.m_width 
= GetTextLength( item
.m_text 
); 
4118         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4119         wxColWidthInfo 
*colWidthInfo 
= new wxColWidthInfo(); 
4121         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4124             wxListHeaderDataList::compatibility_iterator
 
4125                 node 
= m_columns
.Item( col 
); 
4126             m_columns
.Insert( node
, column 
); 
4127             m_aColWidths
.Insert( colWidthInfo
, col 
); 
4131             m_columns
.Append( column 
); 
4132             m_aColWidths
.Add( colWidthInfo 
); 
4137             // update all the items 
4138             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4140                 wxListLineData 
* const line 
= GetLine(i
); 
4141                 wxListItemData 
* const data 
= new wxListItemData(this); 
4143                     line
->m_items
.Insert(col
, data
); 
4145                     line
->m_items
.Append(data
); 
4149         // invalidate it as it has to be recalculated 
4154 int wxListMainWindow::GetItemWidthWithImage(wxListItem 
* item
) 
4157     wxClientDC 
dc(this); 
4159     dc
.SetFont( GetFont() ); 
4161     if (item
->GetImage() != -1) 
4164         GetImageSize( item
->GetImage(), ix
, iy 
); 
4168     if (!item
->GetText().empty()) 
4171         dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
4178 // ---------------------------------------------------------------------------- 
4180 // ---------------------------------------------------------------------------- 
4182 static wxListCtrlCompare list_ctrl_compare_func_2
; 
4183 static wxIntPtr          list_ctrl_compare_data
; 
4185 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4187     wxListLineData 
*line1 
= *arg1
; 
4188     wxListLineData 
*line2 
= *arg2
; 
4190     line1
->GetItem( 0, item 
); 
4191     wxUIntPtr data1 
= item
.m_data
; 
4192     line2
->GetItem( 0, item 
); 
4193     wxUIntPtr data2 
= item
.m_data
; 
4194     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4197 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, wxIntPtr data 
) 
4199     // selections won't make sense any more after sorting the items so reset 
4201     HighlightAll(false); 
4204     list_ctrl_compare_func_2 
= fn
; 
4205     list_ctrl_compare_data 
= data
; 
4206     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4210 // ---------------------------------------------------------------------------- 
4212 // ---------------------------------------------------------------------------- 
4214 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4216     // update our idea of which lines are shown when we redraw the window the 
4218     ResetVisibleLinesRange(); 
4220     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4222         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4223         wxCHECK_RET( lc
, wxT("no listctrl window?") ); 
4225         if (lc
->m_headerWin
) // when we use wxLC_NO_HEADER, m_headerWin==NULL 
4227             lc
->m_headerWin
->Refresh(); 
4228             lc
->m_headerWin
->Update(); 
4233 int wxListMainWindow::GetCountPerPage() const 
4235     if ( !m_linesPerPage 
) 
4237         wxConstCast(this, wxListMainWindow
)-> 
4238             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4241     return m_linesPerPage
; 
4244 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4246     wxASSERT_MSG( InReportView(), wxT("this is for report mode only") ); 
4248     if ( m_lineFrom 
== (size_t)-1 ) 
4250         size_t count 
= GetItemCount(); 
4253             m_lineFrom 
= GetListCtrl()->GetScrollPos(wxVERTICAL
); 
4255             // this may happen if SetScrollbars() hadn't been called yet 
4256             if ( m_lineFrom 
>= count 
) 
4257                 m_lineFrom 
= count 
- 1; 
4259             // we redraw one extra line but this is needed to make the redrawing 
4260             // logic work when there is a fractional number of lines on screen 
4261             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4262             if ( m_lineTo 
>= count 
) 
4263                 m_lineTo 
= count 
- 1; 
4265         else // empty control 
4268             m_lineTo 
= (size_t)-1; 
4272     wxASSERT_MSG( IsEmpty() || 
4273                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4274                   wxT("GetVisibleLinesRange() returns incorrect result") ); 
4282 // ------------------------------------------------------------------------------------- 
4283 // wxGenericListCtrl 
4284 // ------------------------------------------------------------------------------------- 
4286 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4288 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxControl
) 
4289   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4290   EVT_SCROLLWIN(wxGenericListCtrl::OnScroll
) 
4293 void wxGenericListCtrl::Init() 
4295     m_imageListNormal 
= NULL
; 
4296     m_imageListSmall 
= NULL
; 
4297     m_imageListState 
= NULL
; 
4299     m_ownsImageListNormal 
= 
4300     m_ownsImageListSmall 
= 
4301     m_ownsImageListState 
= false; 
4307 wxGenericListCtrl::~wxGenericListCtrl() 
4309     if (m_ownsImageListNormal
) 
4310         delete m_imageListNormal
; 
4311     if (m_ownsImageListSmall
) 
4312         delete m_imageListSmall
; 
4313     if (m_ownsImageListState
) 
4314         delete m_imageListState
; 
4317 void wxGenericListCtrl::CreateOrDestroyHeaderWindowAsNeeded() 
4319     bool needs_header 
= HasHeader(); 
4320     bool has_header 
= (m_headerWin 
!= NULL
); 
4322     if (needs_header 
== has_header
) 
4327         m_headerWin 
= new wxListHeaderWindow
 
4329                         this, wxID_ANY
, m_mainWin
, 
4334                           wxRendererNative::Get().GetHeaderButtonHeight(this) 
4339 #if defined( __WXMAC__ ) 
4340         static wxFont 
font( wxOSX_SYSTEM_FONT_SMALL 
); 
4341         m_headerWin
->SetFont( font 
); 
4344         GetSizer()->Prepend( m_headerWin
, 0, wxGROW 
); 
4348         GetSizer()->Detach( m_headerWin 
); 
4350         wxDELETE(m_headerWin
); 
4354 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
4359                         const wxValidator 
&validator
, 
4360                         const wxString 
&name
) 
4364     // just like in other ports, an assert will fail if the user doesn't give any type style: 
4365     wxASSERT_MSG( (style 
& wxLC_MASK_TYPE
), 
4366                   wxT("wxListCtrl style should have exactly one mode bit set") ); 
4368     if ( !wxControl::Create( parent
, id
, pos
, size
, style
|wxVSCROLL
|wxHSCROLL
, validator
, name 
) ) 
4372     style 
&= ~wxBORDER_MASK
; 
4373     style 
|= wxBORDER_THEME
; 
4376     m_mainWin 
= new wxListMainWindow( this, wxID_ANY
, wxPoint(0, 0), size
, style 
); 
4378     SetTargetWindow( m_mainWin 
); 
4380     // We use the cursor keys for moving the selection, not scrolling, so call 
4381     // this method to ensure wxScrollHelperEvtHandler doesn't catch all 
4382     // keyboard events forwarded to us from wxListMainWindow. 
4383     DisableKeyboardScrolling(); 
4385     wxBoxSizer 
*sizer 
= new wxBoxSizer( wxVERTICAL 
); 
4386     sizer
->Add( m_mainWin
, 1, wxGROW 
); 
4389     CreateOrDestroyHeaderWindowAsNeeded(); 
4391     SetInitialSize(size
); 
4396 wxBorder 
wxGenericListCtrl::GetDefaultBorder() const 
4398     return wxBORDER_THEME
; 
4401 #if defined(__WXMSW__) && !defined(__WXWINCE__) && !defined(__WXUNIVERSAL__) 
4402 WXLRESULT 
wxGenericListCtrl::MSWWindowProc(WXUINT nMsg
, 
4406     WXLRESULT rc 
= wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
4408     // we need to process arrows ourselves for scrolling 
4409     if ( nMsg 
== WM_GETDLGCODE 
) 
4411         rc 
|= DLGC_WANTARROWS
; 
4418 wxSize 
wxGenericListCtrl::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
4420     wxSize newsize 
= size
; 
4422        newsize
.y 
-= m_headerWin
->GetSize().y
; 
4427 void wxGenericListCtrl::OnScroll(wxScrollWinEvent
& event
) 
4429     // update our idea of which lines are shown when we redraw 
4430     // the window the next time 
4431     m_mainWin
->ResetVisibleLinesRange(); 
4433     HandleOnScroll( event 
); 
4435     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4437         m_headerWin
->Refresh(); 
4438         m_headerWin
->Update(); 
4442 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
4444     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4445                   wxT("wxLC_VIRTUAL can't be [un]set") ); 
4447     long flag 
= GetWindowStyle(); 
4451         if (style 
& wxLC_MASK_TYPE
) 
4452             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4453         if (style 
& wxLC_MASK_ALIGN
) 
4454             flag 
&= ~wxLC_MASK_ALIGN
; 
4455         if (style 
& wxLC_MASK_SORT
) 
4456             flag 
&= ~wxLC_MASK_SORT
; 
4464     // some styles can be set without recreating everything (as happens in 
4465     // SetWindowStyleFlag() which calls wxListMainWindow::DeleteEverything()) 
4466     if ( !(style 
& ~(wxLC_HRULES 
| wxLC_VRULES
)) ) 
4469         wxWindow::SetWindowStyleFlag(flag
); 
4473         SetWindowStyleFlag( flag 
); 
4477 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
4479     // we add wxHSCROLL and wxVSCROLL in ctor unconditionally and it never 
4480     // makes sense to remove them as we'll always add scrollbars anyhow when 
4482     flag 
|= wxHSCROLL 
| wxVSCROLL
; 
4484     const bool wasInReportView 
= HasFlag(wxLC_REPORT
); 
4486     // update the window style first so that the header is created or destroyed 
4487     // corresponding to the new style 
4488     wxWindow::SetWindowStyleFlag( flag 
); 
4492         const bool inReportView 
= (flag 
& wxLC_REPORT
) != 0; 
4493         if ( inReportView 
!= wasInReportView 
) 
4495             // we need to notify the main window about this change as it must 
4496             // update its data structures 
4497             m_mainWin
->SetReportView(inReportView
); 
4500         // m_mainWin->DeleteEverything();  wxMSW doesn't do that 
4502         CreateOrDestroyHeaderWindowAsNeeded(); 
4504         GetSizer()->Layout(); 
4508 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4510     m_mainWin
->GetColumn( col
, item 
); 
4514 bool wxGenericListCtrl::SetColumn( int col
, wxListItem
& item 
) 
4516     m_mainWin
->SetColumn( col
, item 
); 
4520 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
4522     return m_mainWin
->GetColumnWidth( col 
); 
4525 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
4527     m_mainWin
->SetColumnWidth( col
, width 
); 
4531 int wxGenericListCtrl::GetCountPerPage() const 
4533   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4536 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
4538     m_mainWin
->GetItem( info 
); 
4542 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
4544     m_mainWin
->SetItem( info 
); 
4548 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4551     info
.m_text 
= label
; 
4552     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4553     info
.m_itemId 
= index
; 
4557         info
.m_image 
= imageId
; 
4558         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4561     m_mainWin
->SetItem(info
); 
4565 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
4567     return m_mainWin
->GetItemState( item
, stateMask 
); 
4570 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4572     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4577 wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4579     return SetItemColumnImage(item
, 0, image
); 
4583 wxGenericListCtrl::SetItemColumnImage( long item
, long column
, int image 
) 
4586     info
.m_image 
= image
; 
4587     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4588     info
.m_itemId 
= item
; 
4589     info
.m_col 
= column
; 
4590     m_mainWin
->SetItem( info 
); 
4594 wxString 
wxGenericListCtrl::GetItemText( long item
, int col 
) const 
4596     return m_mainWin
->GetItemText(item
, col
); 
4599 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
4601     m_mainWin
->SetItemText(item
, str
); 
4604 wxUIntPtr 
wxGenericListCtrl::GetItemData( long item 
) const 
4607     info
.m_mask 
= wxLIST_MASK_DATA
; 
4608     info
.m_itemId 
= item
; 
4609     m_mainWin
->GetItem( info 
); 
4613 bool wxGenericListCtrl::SetItemPtrData( long item
, wxUIntPtr data 
) 
4616     info
.m_mask 
= wxLIST_MASK_DATA
; 
4617     info
.m_itemId 
= item
; 
4619     m_mainWin
->SetItem( info 
); 
4623 wxRect 
wxGenericListCtrl::GetViewRect() const 
4625     return m_mainWin
->GetViewRect(); 
4628 bool wxGenericListCtrl::GetItemRect(long item
, wxRect
& rect
, int code
) const 
4630     return GetSubItemRect(item
, wxLIST_GETSUBITEMRECT_WHOLEITEM
, rect
, code
); 
4633 bool wxGenericListCtrl::GetSubItemRect(long item
, 
4636                                        int WXUNUSED(code
)) const 
4638     if ( !m_mainWin
->GetSubItemRect( item
, subItem
, rect 
) ) 
4641     if ( m_mainWin
->HasHeader() ) 
4642         rect
.y 
+= m_headerWin
->GetSize().y 
+ 1; 
4647 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4649     m_mainWin
->GetItemPosition( item
, pos 
); 
4653 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4658 int wxGenericListCtrl::GetItemCount() const 
4660     return m_mainWin
->GetItemCount(); 
4663 int wxGenericListCtrl::GetColumnCount() const 
4665     return m_mainWin
->GetColumnCount(); 
4668 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4670     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4673 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
4675     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
4677     return wxSize(spacing
, spacing
); 
4680 #if WXWIN_COMPATIBILITY_2_6 
4681 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
4683     return m_mainWin
->GetItemSpacing( isSmall 
); 
4685 #endif // WXWIN_COMPATIBILITY_2_6 
4687 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
4690     info
.m_itemId 
= item
; 
4691     info
.SetTextColour( col 
); 
4692     m_mainWin
->SetItem( info 
); 
4695 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
4698     info
.m_itemId 
= item
; 
4699     m_mainWin
->GetItem( info 
); 
4700     return info
.GetTextColour(); 
4703 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
4706     info
.m_itemId 
= item
; 
4707     info
.SetBackgroundColour( col 
); 
4708     m_mainWin
->SetItem( info 
); 
4711 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
4714     info
.m_itemId 
= item
; 
4715     m_mainWin
->GetItem( info 
); 
4716     return info
.GetBackgroundColour(); 
4719 void wxGenericListCtrl::SetItemFont( long item
, const wxFont 
&f 
) 
4722     info
.m_itemId 
= item
; 
4724     m_mainWin
->SetItem( info 
); 
4727 wxFont 
wxGenericListCtrl::GetItemFont( long item 
) const 
4730     info
.m_itemId 
= item
; 
4731     m_mainWin
->GetItem( info 
); 
4732     return info
.GetFont(); 
4735 int wxGenericListCtrl::GetSelectedItemCount() const 
4737     return m_mainWin
->GetSelectedItemCount(); 
4740 wxColour 
wxGenericListCtrl::GetTextColour() const 
4742     return GetForegroundColour(); 
4745 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
4747     SetForegroundColour(col
); 
4750 long wxGenericListCtrl::GetTopItem() const 
4753     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
4757 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
4759     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
4762 wxImageList 
*wxGenericListCtrl::GetImageList(int which
) const 
4764     if (which 
== wxIMAGE_LIST_NORMAL
) 
4765         return m_imageListNormal
; 
4766     else if (which 
== wxIMAGE_LIST_SMALL
) 
4767         return m_imageListSmall
; 
4768     else if (which 
== wxIMAGE_LIST_STATE
) 
4769         return m_imageListState
; 
4774 void wxGenericListCtrl::SetImageList( wxImageList 
*imageList
, int which 
) 
4776     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4778         if (m_ownsImageListNormal
) 
4779             delete m_imageListNormal
; 
4780         m_imageListNormal 
= imageList
; 
4781         m_ownsImageListNormal 
= false; 
4783     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4785         if (m_ownsImageListSmall
) 
4786             delete m_imageListSmall
; 
4787         m_imageListSmall 
= imageList
; 
4788         m_ownsImageListSmall 
= false; 
4790     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4792         if (m_ownsImageListState
) 
4793             delete m_imageListState
; 
4794         m_imageListState 
= imageList
; 
4795         m_ownsImageListState 
= false; 
4798     m_mainWin
->SetImageList( imageList
, which 
); 
4801 void wxGenericListCtrl::AssignImageList(wxImageList 
*imageList
, int which
) 
4803     SetImageList(imageList
, which
); 
4804     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4805         m_ownsImageListNormal 
= true; 
4806     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4807         m_ownsImageListSmall 
= true; 
4808     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4809         m_ownsImageListState 
= true; 
4812 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
4817 bool wxGenericListCtrl::DeleteItem( long item 
) 
4819     m_mainWin
->DeleteItem( item 
); 
4823 bool wxGenericListCtrl::DeleteAllItems() 
4825     m_mainWin
->DeleteAllItems(); 
4829 bool wxGenericListCtrl::DeleteAllColumns() 
4831     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
4832     for ( size_t n 
= 0; n 
< count
; n
++ ) 
4837 void wxGenericListCtrl::ClearAll() 
4839     m_mainWin
->DeleteEverything(); 
4842 bool wxGenericListCtrl::DeleteColumn( int col 
) 
4844     m_mainWin
->DeleteColumn( col 
); 
4846     // if we don't have the header any longer, we need to relayout the window 
4847     // if ( !GetColumnCount() ) 
4850     // Ensure that the non-existent columns are really removed from display. 
4856 wxTextCtrl 
*wxGenericListCtrl::EditLabel(long item
, 
4857                                          wxClassInfo
* textControlClass
) 
4859     return m_mainWin
->EditLabel( item
, textControlClass 
); 
4862 wxTextCtrl 
*wxGenericListCtrl::GetEditControl() const 
4864     return m_mainWin
->GetEditControl(); 
4867 bool wxGenericListCtrl::EnsureVisible( long item 
) 
4869     m_mainWin
->EnsureVisible( item 
); 
4873 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
, bool partial 
) 
4875     return m_mainWin
->FindItem( start
, str
, partial 
); 
4878 long wxGenericListCtrl::FindItem( long start
, wxUIntPtr data 
) 
4880     return m_mainWin
->FindItem( start
, data 
); 
4883 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& pt
, 
4884                            int WXUNUSED(direction
)) 
4886     return m_mainWin
->FindItem( pt 
); 
4889 // TODO: sub item hit testing 
4890 long wxGenericListCtrl::HitTest(const wxPoint
& point
, int& flags
, long *) const 
4892     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
4895 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
4897     m_mainWin
->InsertItem( info 
); 
4898     return info
.m_itemId
; 
4901 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
4904     info
.m_text 
= label
; 
4905     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4906     info
.m_itemId 
= index
; 
4907     return InsertItem( info 
); 
4910 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
4913     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4914     info
.m_image 
= imageIndex
; 
4915     info
.m_itemId 
= index
; 
4916     return InsertItem( info 
); 
4919 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
4922     info
.m_text 
= label
; 
4923     info
.m_image 
= imageIndex
; 
4924     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4925     if (imageIndex 
> -1) 
4926         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4927     info
.m_itemId 
= index
; 
4928     return InsertItem( info 
); 
4931 long wxGenericListCtrl::InsertColumn( long col
, wxListItem 
&item 
) 
4933     wxCHECK_MSG( InReportView(), -1, wxT("can't add column in non report mode") ); 
4935     m_mainWin
->InsertColumn( col
, item 
); 
4937     // NOTE: if wxLC_NO_HEADER was given, then we are in report view mode but 
4938     //       still have m_headerWin==NULL 
4940         m_headerWin
->Refresh(); 
4945 long wxGenericListCtrl::InsertColumn( long col
, const wxString 
&heading
, 
4946                                int format
, int width 
) 
4949     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
4950     item
.m_text 
= heading
; 
4953         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
4954         item
.m_width 
= width
; 
4957     item
.m_format 
= format
; 
4959     return InsertColumn( col
, item 
); 
4962 bool wxGenericListCtrl::ScrollList( int dx
, int dy 
) 
4964     return m_mainWin
->ScrollList(dx
, dy
); 
4968 // fn is a function which takes 3 long arguments: item1, item2, data. 
4969 // item1 is the long data associated with a first item (NOT the index). 
4970 // item2 is the long data associated with a second item (NOT the index). 
4971 // data is the same value as passed to SortItems. 
4972 // The return value is a negative number if the first item should precede the second 
4973 // item, a positive number of the second item should precede the first, 
4974 // or zero if the two items are equivalent. 
4975 // data is arbitrary data to be passed to the sort function. 
4977 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, wxIntPtr data 
) 
4979     m_mainWin
->SortItems( fn
, data 
); 
4983 // ---------------------------------------------------------------------------- 
4985 // ---------------------------------------------------------------------------- 
4987 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
4989     if (!m_mainWin
) return; 
4991     // We need to override OnSize so that our scrolled 
4992     // window a) does call Layout() to use sizers for 
4993     // positioning the controls but b) does not query 
4994     // the sizer for their size and use that for setting 
4995     // the scrollable area as set that ourselves by 
4996     // calling SetScrollbar() further down. 
5000     m_mainWin
->RecalculatePositions(); 
5005 void wxGenericListCtrl::OnInternalIdle() 
5007     wxWindow::OnInternalIdle(); 
5009     if (m_mainWin
->m_dirty
) 
5010         m_mainWin
->RecalculatePositions(); 
5013 // ---------------------------------------------------------------------------- 
5015 // ---------------------------------------------------------------------------- 
5017 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5021         m_mainWin
->SetBackgroundColour( colour 
); 
5022         m_mainWin
->m_dirty 
= true; 
5028 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5030     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5035         m_mainWin
->SetForegroundColour( colour 
); 
5036         m_mainWin
->m_dirty 
= true; 
5040         m_headerWin
->SetForegroundColour( colour 
); 
5045 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5047     if ( !wxWindow::SetFont( font 
) ) 
5052         m_mainWin
->SetFont( font 
); 
5053         m_mainWin
->m_dirty 
= true; 
5058         m_headerWin
->SetFont( font 
); 
5059         // CalculateAndSetHeaderHeight(); 
5069 wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
5072     // Use the same color scheme as wxListBox 
5073     return wxListBox::GetClassDefaultAttributes(variant
); 
5075     wxUnusedVar(variant
); 
5076     wxVisualAttributes attr
; 
5077     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT
); 
5078     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
5079     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
5084 // ---------------------------------------------------------------------------- 
5085 // methods forwarded to m_mainWin 
5086 // ---------------------------------------------------------------------------- 
5088 #if wxUSE_DRAG_AND_DROP 
5090 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5092     m_mainWin
->SetDropTarget( dropTarget 
); 
5095 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5097     return m_mainWin
->GetDropTarget(); 
5102 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5104     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : false; 
5107 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5109     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5112 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5114     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5117 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5120     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5126 void wxGenericListCtrl::DoClientToScreen( int *x
, int *y 
) const 
5128     // It's not clear whether this can be called before m_mainWin is created 
5129     // but it seems better to be on the safe side and check. 
5131         m_mainWin
->DoClientToScreen(x
, y
); 
5133         wxControl::DoClientToScreen(x
, y
); 
5136 void wxGenericListCtrl::DoScreenToClient( int *x
, int *y 
) const 
5138     // At least in wxGTK/Univ build this method can be called before m_mainWin 
5139     // is created so avoid crashes in this case. 
5141         m_mainWin
->DoScreenToClient(x
, y
); 
5143         wxControl::DoScreenToClient(x
, y
); 
5146 void wxGenericListCtrl::SetFocus() 
5148     // The test in window.cpp fails as we are a composite 
5149     // window, so it checks against "this", but not m_mainWin. 
5150     if ( DoFindFocus() != this ) 
5151         m_mainWin
->SetFocus(); 
5154 wxSize 
wxGenericListCtrl::DoGetBestClientSize() const 
5156     // Something is better than nothing even if this is completely arbitrary. 
5157     wxSize 
sizeBest(100, 80); 
5159     if ( !InReportView() ) 
5161         // Ensure that our minimal width is at least big enough to show all our 
5162         // items. This is important for wxListbook to size itself correctly. 
5164         // Remember the offset of the first item: this corresponds to the 
5165         // margins around the item so we will add it to the minimal size below 
5166         // to ensure that we have equal margins on all sides. 
5169         // We can iterate over all items as there shouldn't be too many of them 
5170         // in non-report view. If it ever becomes a problem, we could examine 
5171         // just the first few items probably, the determination of the best 
5172         // size is less important if we will need scrollbars anyhow. 
5173         for ( int n 
= 0; n 
< GetItemCount(); n
++ ) 
5175             const wxRect itemRect 
= m_mainWin
->GetLineRect(n
); 
5178                 // Remember the position of the first item as all the rest are 
5179                 // offset by at least this number of pixels too. 
5180                 ofs 
= itemRect
.GetPosition(); 
5183             sizeBest
.IncTo(itemRect
.GetSize()); 
5186         sizeBest
.IncBy(2*ofs
); 
5189         // If we have the scrollbars we need to account for them too. And to 
5190         // make sure the scrollbars status is up to date we need to call this 
5191         // function to set them. 
5192         m_mainWin
->RecalculatePositions(true /* no refresh */); 
5194         // Unfortunately we can't use wxWindow::HasScrollbar() here as we need 
5195         // to use m_mainWin client/virtual size for determination of whether we 
5196         // use scrollbars and not the size of this window itself. Maybe that 
5197         // function should be extended to work correctly in the case when our 
5198         // scrollbars manage a different window from this one but currently it 
5200         const wxSize sizeClient 
= m_mainWin
->GetClientSize(); 
5201         const wxSize sizeVirt 
= m_mainWin
->GetVirtualSize(); 
5203         if ( sizeVirt
.x 
> sizeClient
.x 
/* HasScrollbar(wxHORIZONTAL) */ ) 
5204             sizeBest
.y 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
5206         if ( sizeVirt
.y 
> sizeClient
.y 
/* HasScrollbar(wxVERTICAL) */ ) 
5207             sizeBest
.x 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
5213 // ---------------------------------------------------------------------------- 
5214 // virtual list control support 
5215 // ---------------------------------------------------------------------------- 
5217 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5219     // this is a pure virtual function, in fact - which is not really pure 
5220     // because the controls which are not virtual don't need to implement it 
5221     wxFAIL_MSG( wxT("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5223     return wxEmptyString
; 
5226 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5228     wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL
), 
5230                 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden.")); 
5234 int wxGenericListCtrl::OnGetItemColumnImage(long item
, long column
) const 
5237         return OnGetItemImage(item
); 
5243 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5245     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5246                   wxT("invalid item index in OnGetItemAttr()") ); 
5248     // no attributes by default 
5252 void wxGenericListCtrl::SetItemCount(long count
) 
5254     wxASSERT_MSG( IsVirtual(), wxT("this is for virtual controls only") ); 
5256     m_mainWin
->SetItemCount(count
); 
5259 void wxGenericListCtrl::RefreshItem(long item
) 
5261     m_mainWin
->RefreshLine(item
); 
5264 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5266     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5269 // Generic wxListCtrl is more or less a container for two other 
5270 // windows which drawings are done upon. These are namely 
5271 // 'm_headerWin' and 'm_mainWin'. 
5272 // Here we override 'virtual wxWindow::Refresh()' to mimic the 
5273 // behaviour wxListCtrl has under wxMSW. 
5275 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5279         // The easy case, no rectangle specified. 
5281             m_headerWin
->Refresh(eraseBackground
); 
5284             m_mainWin
->Refresh(eraseBackground
); 
5288         // Refresh the header window 
5291             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5292             rectHeader
.Intersect(*rect
); 
5293             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5296                 m_headerWin
->GetPosition(&x
, &y
); 
5297                 rectHeader
.Offset(-x
, -y
); 
5298                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5302         // Refresh the main window 
5305             wxRect rectMain 
= m_mainWin
->GetRect(); 
5306             rectMain
.Intersect(*rect
); 
5307             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5310                 m_mainWin
->GetPosition(&x
, &y
); 
5311                 rectMain
.Offset(-x
, -y
); 
5312                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5318 void wxGenericListCtrl::Update() 
5322         if ( m_mainWin
->m_dirty 
) 
5323             m_mainWin
->RecalculatePositions(); 
5325         m_mainWin
->Update(); 
5329         m_headerWin
->Update(); 
5332 #endif // wxUSE_LISTCTRL