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_item
.m_itemId 
= 
2036             evCache
.m_itemIndex 
= visibleTo
; 
2037             GetParent()->GetEventHandler()->ProcessEvent( evCache 
); 
2040         for ( size_t line 
= visibleFrom
; line 
<= visibleTo
; line
++ ) 
2042             rectLine 
= GetLineRect(line
); 
2045             if ( !IsExposed(rectLine
.x 
+ xOrig
, rectLine
.y 
+ yOrig
, 
2046                             rectLine
.width
, rectLine
.height
) ) 
2048                 // don't redraw unaffected lines to avoid flicker 
2052             GetLine(line
)->DrawInReportMode( &dc
, 
2054                                              GetLineHighlightRect(line
), 
2055                                              IsHighlighted(line
), 
2056                                              line 
== m_current 
); 
2059         if ( HasFlag(wxLC_HRULES
) ) 
2061             wxPen 
pen(GetRuleColour(), 1, wxPENSTYLE_SOLID
); 
2062             wxSize clientSize 
= GetClientSize(); 
2064             size_t i 
= visibleFrom
; 
2065             if (i 
== 0) i 
= 1; // Don't draw the first one 
2066             for ( ; i 
<= visibleTo
; i
++ ) 
2069                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2070                 dc
.DrawLine(0 - dev_x
, i 
* lineHeight
, 
2071                             clientSize
.x 
- dev_x
, i 
* lineHeight
); 
2074             // Draw last horizontal rule 
2075             if ( visibleTo 
== GetItemCount() - 1 ) 
2078                 dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
2079                 dc
.DrawLine(0 - dev_x
, (m_lineTo 
+ 1) * lineHeight
, 
2080                             clientSize
.x 
- dev_x 
, (m_lineTo 
+ 1) * lineHeight 
); 
2084         // Draw vertical rules if required 
2085         if ( HasFlag(wxLC_VRULES
) && !IsEmpty() ) 
2087             wxPen 
pen(GetRuleColour(), 1, wxPENSTYLE_SOLID
); 
2088             wxRect firstItemRect
, lastItemRect
; 
2090             GetItemRect(visibleFrom
, firstItemRect
); 
2091             GetItemRect(visibleTo
, lastItemRect
); 
2092             int x 
= firstItemRect
.GetX(); 
2094             dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2096             for (int col 
= 0; col 
< GetColumnCount(); col
++) 
2098                 int colWidth 
= GetColumnWidth(col
); 
2100                 int x_pos 
= x 
- dev_x
; 
2101                 if (col 
< GetColumnCount()-1) x_pos 
-= 2; 
2102                 dc
.DrawLine(x_pos
, firstItemRect
.GetY() - 1 - dev_y
, 
2103                             x_pos
, lastItemRect
.GetBottom() + 1 - dev_y
); 
2109         size_t count 
= GetItemCount(); 
2110         for ( size_t i 
= 0; i 
< count
; i
++ ) 
2112             GetLine(i
)->Draw( &dc
, i 
== m_current 
); 
2116     // DrawFocusRect() is unusable under Mac, it draws outside of the highlight 
2117     // rectangle somehow and so leaves traces when the item is not selected any 
2118     // more, see #12229. 
2123         if ( IsHighlighted(m_current
) ) 
2124             flags 
|= wxCONTROL_SELECTED
; 
2126         wxRendererNative::Get(). 
2127             DrawFocusRect(this, dc
, GetLineHighlightRect(m_current
), flags
); 
2129 #endif // !__WXMAC__ 
2132 void wxListMainWindow::HighlightAll( bool on 
) 
2134     if ( IsSingleSel() ) 
2136         wxASSERT_MSG( !on
, wxT("can't do this in a single selection control") ); 
2138         // we just have one item to turn off 
2139         if ( HasCurrent() && IsHighlighted(m_current
) ) 
2141             HighlightLine(m_current
, false); 
2142             RefreshLine(m_current
); 
2145     else // multi selection 
2148             HighlightLines(0, GetItemCount() - 1, on
); 
2152 void wxListMainWindow::OnChildFocus(wxChildFocusEvent
& WXUNUSED(event
)) 
2154     // Do nothing here.  This prevents the default handler in wxScrolledWindow 
2155     // from needlessly scrolling the window when the edit control is 
2156     // dismissed.  See ticket #9563. 
2159 void wxListMainWindow::SendNotify( size_t line
, 
2160                                    wxEventType command
, 
2161                                    const wxPoint
& point 
) 
2163     wxListEvent 
le( command
, GetParent()->GetId() ); 
2164     le
.SetEventObject( GetParent() ); 
2166     le
.m_item
.m_itemId 
= 
2167     le
.m_itemIndex 
= line
; 
2169     // set only for events which have position 
2170     if ( point 
!= wxDefaultPosition 
) 
2171         le
.m_pointDrag 
= point
; 
2173     // don't try to get the line info for virtual list controls: the main 
2174     // program has it anyhow and if we did it would result in accessing all 
2175     // the lines, even those which are not visible now and this is precisely 
2176     // what we're trying to avoid 
2179         if ( line 
!= (size_t)-1 ) 
2181             GetLine(line
)->GetItem( 0, le
.m_item 
); 
2183         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event 
2185     //else: there may be no more such item 
2187     GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2190 void wxListMainWindow::ChangeCurrent(size_t current
) 
2192     m_current 
= current
; 
2194     // as the current item changed, we shouldn't start editing it when the 
2195     // "slow click" timer expires as the click happened on another item 
2196     if ( m_renameTimer
->IsRunning() ) 
2197         m_renameTimer
->Stop(); 
2199     SendNotify(current
, wxEVT_COMMAND_LIST_ITEM_FOCUSED
); 
2202 wxTextCtrl 
*wxListMainWindow::EditLabel(long item
, wxClassInfo
* textControlClass
) 
2204     wxCHECK_MSG( (item 
>= 0) && ((size_t)item 
< GetItemCount()), NULL
, 
2205                  wxT("wrong index in wxGenericListCtrl::EditLabel()") ); 
2207     wxASSERT_MSG( textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
)), 
2208                  wxT("EditLabel() needs a text control") ); 
2210     size_t itemEdit 
= (size_t)item
; 
2212     wxListEvent 
le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
, GetParent()->GetId() ); 
2213     le
.SetEventObject( GetParent() ); 
2214     le
.m_item
.m_itemId 
= 
2215     le
.m_itemIndex 
= item
; 
2216     wxListLineData 
*data 
= GetLine(itemEdit
); 
2217     wxCHECK_MSG( data
, NULL
, wxT("invalid index in EditLabel()") ); 
2218     data
->GetItem( 0, le
.m_item 
); 
2220     if ( GetParent()->GetEventHandler()->ProcessEvent( le 
) && !le
.IsAllowed() ) 
2222         // vetoed by user code 
2226     // We have to call this here because the label in question might just have 
2227     // been added and no screen update taken place. 
2230         // TODO: use wxTheApp->SafeYieldFor(NULL, wxEVT_CATEGORY_UI) instead 
2231         //       so that no pending events may change the item count (see below) 
2232         //       IMPORTANT: needs to be tested! 
2235         // Pending events dispatched by wxSafeYield might have changed the item 
2237         if ( (size_t)item 
>= GetItemCount() ) 
2241     wxTextCtrl 
* const text 
= (wxTextCtrl 
*)textControlClass
->CreateObject(); 
2242     m_textctrlWrapper 
= new wxListTextCtrlWrapper(this, text
, item
); 
2243     return m_textctrlWrapper
->GetText(); 
2246 void wxListMainWindow::OnRenameTimer() 
2248     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); 
2250     EditLabel( m_current 
); 
2253 bool wxListMainWindow::OnRenameAccept(size_t itemEdit
, const wxString
& value
) 
2255     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2256     le
.SetEventObject( GetParent() ); 
2257     le
.m_item
.m_itemId 
= 
2258     le
.m_itemIndex 
= itemEdit
; 
2260     wxListLineData 
*data 
= GetLine(itemEdit
); 
2262     wxCHECK_MSG( data
, false, wxT("invalid index in OnRenameAccept()") ); 
2264     data
->GetItem( 0, le
.m_item 
); 
2265     le
.m_item
.m_text 
= value
; 
2266     return !GetParent()->GetEventHandler()->ProcessEvent( le 
) || 
2270 void wxListMainWindow::OnRenameCancelled(size_t itemEdit
) 
2272     // let owner know that the edit was cancelled 
2273     wxListEvent 
le( wxEVT_COMMAND_LIST_END_LABEL_EDIT
, GetParent()->GetId() ); 
2275     le
.SetEditCanceled(true); 
2277     le
.SetEventObject( GetParent() ); 
2278     le
.m_item
.m_itemId 
= 
2279     le
.m_itemIndex 
= itemEdit
; 
2281     wxListLineData 
*data 
= GetLine(itemEdit
); 
2282     wxCHECK_RET( data
, wxT("invalid index in OnRenameCancelled()") ); 
2284     data
->GetItem( 0, le
.m_item 
); 
2285     GetEventHandler()->ProcessEvent( le 
); 
2288 void wxListMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2291     // On wxMac we can't depend on the EVT_KILL_FOCUS event to properly 
2292     // shutdown the edit control when the mouse is clicked elsewhere on the 
2293     // listctrl because the order of events is different (or something like 
2294     // that), so explicitly end the edit if it is active. 
2295     if ( event
.LeftDown() && m_textctrlWrapper 
) 
2296         m_textctrlWrapper
->EndEdit(wxListTextCtrlWrapper::End_Accept
); 
2299     if ( event
.LeftDown() ) 
2302     event
.SetEventObject( GetParent() ); 
2303     if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2306     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
2308         // let the base class handle mouse wheel events. 
2313     if ( !HasCurrent() || IsEmpty() ) 
2315         if (event
.RightDown()) 
2317             SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
2319             wxContextMenuEvent 
evtCtx(wxEVT_CONTEXT_MENU
, 
2320                                       GetParent()->GetId(), 
2321                                       ClientToScreen(event
.GetPosition())); 
2322             evtCtx
.SetEventObject(GetParent()); 
2323             GetParent()->GetEventHandler()->ProcessEvent(evtCtx
); 
2331     if ( !(event
.Dragging() || event
.ButtonDown() || event
.LeftUp() || 
2332         event
.ButtonDClick()) ) 
2335     int x 
= event
.GetX(); 
2336     int y 
= event
.GetY(); 
2337     GetListCtrl()->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2339     // where did we hit it (if we did)? 
2342     size_t count 
= GetItemCount(), 
2345     if ( InReportView() ) 
2347         current 
= y 
/ GetLineHeight(); 
2348         if ( current 
< count 
) 
2349             hitResult 
= HitTestLine(current
, x
, y
); 
2353         // TODO: optimize it too! this is less simple than for report view but 
2354         //       enumerating all items is still not a way to do it!! 
2355         for ( current 
= 0; current 
< count
; current
++ ) 
2357             hitResult 
= HitTestLine(current
, x
, y
); 
2363     if (event
.Dragging()) 
2365         if (m_dragCount 
== 0) 
2367             // we have to report the raw, physical coords as we want to be 
2368             // able to call HitTest(event.m_pointDrag) from the user code to 
2369             // get the item being dragged 
2370             m_dragStart 
= event
.GetPosition(); 
2375         if (m_dragCount 
!= 3) 
2378         int command 
= event
.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
 
2379                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2381         wxListEvent 
le( command
, GetParent()->GetId() ); 
2382         le
.SetEventObject( GetParent() ); 
2383         le
.m_item
.m_itemId 
= 
2384         le
.m_itemIndex 
= m_lineLastClicked
; 
2385         le
.m_pointDrag 
= m_dragStart
; 
2386         GetParent()->GetEventHandler()->ProcessEvent( le 
); 
2397         // outside of any item 
2398         if (event
.RightDown()) 
2400             SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
2402             wxContextMenuEvent 
evtCtx( 
2404                 GetParent()->GetId(), 
2405                 ClientToScreen(event
.GetPosition())); 
2406             evtCtx
.SetEventObject(GetParent()); 
2407             GetParent()->GetEventHandler()->ProcessEvent(evtCtx
); 
2411             // reset the selection and bail out 
2412             HighlightAll(false); 
2418     bool forceClick 
= false; 
2419     if (event
.ButtonDClick()) 
2421         if ( m_renameTimer
->IsRunning() ) 
2422             m_renameTimer
->Stop(); 
2424         m_lastOnSame 
= false; 
2426         if ( current 
== m_lineLastClicked 
) 
2428             SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2434             // The first click was on another item, so don't interpret this as 
2435             // a double click, but as a simple click instead 
2442         if (m_lineSelectSingleOnUp 
!= (size_t)-1) 
2444             // select single line 
2445             HighlightAll( false ); 
2446             ReverseHighlight(m_lineSelectSingleOnUp
); 
2451             if ((current 
== m_current
) && 
2452                 (hitResult 
== wxLIST_HITTEST_ONITEMLABEL
) && 
2453                 HasFlag(wxLC_EDIT_LABELS
) ) 
2455                 if ( !InReportView() || 
2456                         GetLineLabelRect(current
).Contains(x
, y
) ) 
2458                     int dclick 
= wxSystemSettings::GetMetric(wxSYS_DCLICK_MSEC
); 
2459                     m_renameTimer
->Start(dclick 
> 0 ? dclick 
: 250, true); 
2464         m_lastOnSame 
= false; 
2465         m_lineSelectSingleOnUp 
= (size_t)-1; 
2469         // This is necessary, because after a DnD operation in 
2470         // from and to ourself, the up event is swallowed by the 
2471         // DnD code. So on next non-up event (which means here and 
2472         // now) m_lineSelectSingleOnUp should be reset. 
2473         m_lineSelectSingleOnUp 
= (size_t)-1; 
2475     if (event
.RightDown()) 
2477         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2478         m_lineLastClicked 
= current
; 
2480         // If the item is already selected, do not update the selection. 
2481         // Multi-selections should not be cleared if a selected item is clicked. 
2482         if (!IsHighlighted(current
)) 
2484             HighlightAll(false); 
2485             ChangeCurrent(current
); 
2486             ReverseHighlight(m_current
); 
2489         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
, event
.GetPosition() ); 
2491         // Allow generation of context menu event 
2494     else if (event
.MiddleDown()) 
2496         SendNotify( current
, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK 
); 
2498     else if ( event
.LeftDown() || forceClick 
) 
2500         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2501         m_lineLastClicked 
= current
; 
2503         size_t oldCurrent 
= m_current
; 
2504         bool oldWasSelected 
= IsHighlighted(m_current
); 
2506         bool cmdModifierDown 
= event
.CmdDown(); 
2507         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
2509             if ( IsSingleSel() || !IsHighlighted(current
) ) 
2511                 HighlightAll( false ); 
2513                 ChangeCurrent(current
); 
2515                 ReverseHighlight(m_current
); 
2517             else // multi sel & current is highlighted & no mod keys 
2519                 m_lineSelectSingleOnUp 
= current
; 
2520                 ChangeCurrent(current
); // change focus 
2523         else // multi sel & either ctrl or shift is down 
2525             if (cmdModifierDown
) 
2527                 ChangeCurrent(current
); 
2529                 ReverseHighlight(m_current
); 
2531             else if (event
.ShiftDown()) 
2533                 ChangeCurrent(current
); 
2535                 size_t lineFrom 
= oldCurrent
, 
2538                 if ( lineTo 
< lineFrom 
) 
2541                     lineFrom 
= m_current
; 
2544                 HighlightLines(lineFrom
, lineTo
); 
2546             else // !ctrl, !shift 
2548                 // test in the enclosing if should make it impossible 
2549                 wxFAIL_MSG( wxT("how did we get here?") ); 
2553         if (m_current 
!= oldCurrent
) 
2554             RefreshLine( oldCurrent 
); 
2556         // forceClick is only set if the previous click was on another item 
2557         m_lastOnSame 
= !forceClick 
&& (m_current 
== oldCurrent
) && oldWasSelected
; 
2561 void wxListMainWindow::MoveToItem(size_t item
) 
2563     if ( item 
== (size_t)-1 ) 
2566     wxRect rect 
= GetLineRect(item
); 
2568     int client_w
, client_h
; 
2569     GetClientSize( &client_w
, &client_h 
); 
2571     const int hLine 
= GetLineHeight(); 
2573     int view_x 
= SCROLL_UNIT_X 
* GetListCtrl()->GetScrollPos( wxHORIZONTAL 
); 
2574     int view_y 
= hLine 
* GetListCtrl()->GetScrollPos( wxVERTICAL 
); 
2576     if ( InReportView() ) 
2578         // the next we need the range of lines shown it might be different, 
2579         // so recalculate it 
2580         ResetVisibleLinesRange(); 
2582         if (rect
.y 
< view_y
) 
2583             GetListCtrl()->Scroll( -1, rect
.y 
/ hLine 
); 
2584         if (rect
.y 
+ rect
.height 
+ 5 > view_y 
+ client_h
) 
2585             GetListCtrl()->Scroll( -1, (rect
.y 
+ rect
.height 
- client_h 
+ hLine
) / hLine 
); 
2588         // At least on Mac the visible lines value will get reset inside of 
2589         // Scroll *before* it actually scrolls the window because of the 
2590         // Update() that happens there, so it will still have the wrong value. 
2591         // So let's reset it again and wait for it to be recalculated in the 
2592         // next paint event.  I would expect this problem to show up in wxGTK 
2593         // too but couldn't duplicate it there.  Perhaps the order of events 
2594         // is different...  --Robin 
2595         ResetVisibleLinesRange(); 
2603         if (rect
.x
-view_x 
< 5) 
2604             sx 
= (rect
.x 
- 5) / SCROLL_UNIT_X
; 
2605         if (rect
.x 
+ rect
.width 
- 5 > view_x 
+ client_w
) 
2606             sx 
= (rect
.x 
+ rect
.width 
- client_w 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
; 
2608         if (rect
.y
-view_y 
< 5) 
2609             sy 
= (rect
.y 
- 5) / hLine
; 
2610         if (rect
.y 
+ rect
.height 
- 5 > view_y 
+ client_h
) 
2611             sy 
= (rect
.y 
+ rect
.height 
- client_h 
+ hLine
) / hLine
; 
2613         GetListCtrl()->Scroll(sx
, sy
); 
2617 bool wxListMainWindow::ScrollList(int WXUNUSED(dx
), int dy
) 
2619     if ( !InReportView() ) 
2621         // TODO: this should work in all views but is not implemented now 
2626     GetVisibleLinesRange(&top
, &bottom
); 
2628     if ( bottom 
== (size_t)-1 ) 
2631     ResetVisibleLinesRange(); 
2633     int hLine 
= GetLineHeight(); 
2635     GetListCtrl()->Scroll(-1, top 
+ dy 
/ hLine
); 
2638     // see comment in MoveToItem() for why we do this 
2639     ResetVisibleLinesRange(); 
2645 // ---------------------------------------------------------------------------- 
2646 // keyboard handling 
2647 // ---------------------------------------------------------------------------- 
2649 void wxListMainWindow::OnArrowChar(size_t newCurrent
, const wxKeyEvent
& event
) 
2651     wxCHECK_RET( newCurrent 
< (size_t)GetItemCount(), 
2652                  wxT("invalid item index in OnArrowChar()") ); 
2654     size_t oldCurrent 
= m_current
; 
2656     // in single selection we just ignore Shift as we can't select several 
2658     if ( event
.ShiftDown() && !IsSingleSel() ) 
2660         ChangeCurrent(newCurrent
); 
2662         // refresh the old focus to remove it 
2663         RefreshLine( oldCurrent 
); 
2665         // select all the items between the old and the new one 
2666         if ( oldCurrent 
> newCurrent 
) 
2668             newCurrent 
= oldCurrent
; 
2669             oldCurrent 
= m_current
; 
2672         HighlightLines(oldCurrent
, newCurrent
); 
2676         // all previously selected items are unselected unless ctrl is held 
2677         // in a multiselection control 
2678         if ( !event
.ControlDown() || IsSingleSel() ) 
2679             HighlightAll(false); 
2681         ChangeCurrent(newCurrent
); 
2683         // refresh the old focus to remove it 
2684         RefreshLine( oldCurrent 
); 
2686         // in single selection mode we must always have a selected item 
2687         if ( !event
.ControlDown() || IsSingleSel() ) 
2688             HighlightLine( m_current
, true ); 
2691     RefreshLine( m_current 
); 
2696 void wxListMainWindow::OnKeyDown( wxKeyEvent 
&event 
) 
2698     wxWindow 
*parent 
= GetParent(); 
2700     // propagate the key event upwards 
2701     wxKeyEvent 
ke(event
); 
2702     ke
.SetEventObject( parent 
); 
2703     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
2706     // send a list event 
2707     wxListEvent 
le( wxEVT_COMMAND_LIST_KEY_DOWN
, parent
->GetId() ); 
2708     le
.m_item
.m_itemId 
= 
2709     le
.m_itemIndex 
= m_current
; 
2711         GetLine(m_current
)->GetItem( 0, le
.m_item 
); 
2712     le
.m_code 
= event
.GetKeyCode(); 
2713     le
.SetEventObject( parent 
); 
2714     if (parent
->GetEventHandler()->ProcessEvent( le 
)) 
2720 void wxListMainWindow::OnKeyUp( wxKeyEvent 
&event 
) 
2722     wxWindow 
*parent 
= GetParent(); 
2724     // propagate the key event upwards 
2725     wxKeyEvent 
ke(event
); 
2726     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
2732 void wxListMainWindow::OnCharHook( wxKeyEvent 
&event 
) 
2734     if ( m_textctrlWrapper 
) 
2736         // When an in-place editor is active we should ensure that it always 
2737         // gets the key events that are special to it. 
2738         if ( m_textctrlWrapper
->CheckForEndEditKey(event
) ) 
2740             // Skip the call to wxEvent::Skip() below. 
2748 void wxListMainWindow::OnChar( wxKeyEvent 
&event 
) 
2750     wxWindow 
*parent 
= GetParent(); 
2752     // propagate the char event upwards 
2753     wxKeyEvent 
ke(event
); 
2754     ke
.SetEventObject( parent 
); 
2755     if (parent
->GetEventHandler()->ProcessEvent( ke 
)) 
2758     if ( HandleAsNavigationKey(event
) ) 
2761     // no item -> nothing to do 
2768     // don't use m_linesPerPage directly as it might not be computed yet 
2769     const int pageSize 
= GetCountPerPage(); 
2770     wxCHECK_RET( pageSize
, wxT("should have non zero page size") ); 
2772     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2774         if (event
.GetKeyCode() == WXK_RIGHT
) 
2775             event
.m_keyCode 
= WXK_LEFT
; 
2776         else if (event
.GetKeyCode() == WXK_LEFT
) 
2777             event
.m_keyCode 
= WXK_RIGHT
; 
2780     switch ( event
.GetKeyCode() ) 
2783             if ( m_current 
> 0 ) 
2784                 OnArrowChar( m_current 
- 1, event 
); 
2788             if ( m_current 
< (size_t)GetItemCount() - 1 ) 
2789                 OnArrowChar( m_current 
+ 1, event 
); 
2794                 OnArrowChar( GetItemCount() - 1, event 
); 
2799                 OnArrowChar( 0, event 
); 
2804                 int steps 
= InReportView() ? pageSize 
- 1 
2805                                            : m_current 
% pageSize
; 
2807                 int index 
= m_current 
- steps
; 
2811                 OnArrowChar( index
, event 
); 
2817                 int steps 
= InReportView() 
2819                                 : pageSize 
- (m_current 
% pageSize
) - 1; 
2821                 size_t index 
= m_current 
+ steps
; 
2822                 size_t count 
= GetItemCount(); 
2823                 if ( index 
>= count 
) 
2826                 OnArrowChar( index
, event 
); 
2831             if ( !InReportView() ) 
2833                 int index 
= m_current 
- pageSize
; 
2837                 OnArrowChar( index
, event 
); 
2842             if ( !InReportView() ) 
2844                 size_t index 
= m_current 
+ pageSize
; 
2846                 size_t count 
= GetItemCount(); 
2847                 if ( index 
>= count 
) 
2850                 OnArrowChar( index
, event 
); 
2855             if ( IsSingleSel() ) 
2857                 if ( event
.ControlDown() ) 
2859                     ReverseHighlight(m_current
); 
2861                 else // normal space press 
2863                     SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2866             else // multiple selection 
2868                 ReverseHighlight(m_current
); 
2874             SendNotify( m_current
, wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
); 
2882 // ---------------------------------------------------------------------------- 
2884 // ---------------------------------------------------------------------------- 
2886 void wxListMainWindow::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
2890         wxFocusEvent 
event( wxEVT_SET_FOCUS
, GetParent()->GetId() ); 
2891         event
.SetEventObject( GetParent() ); 
2892         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2896     // wxGTK sends us EVT_SET_FOCUS events even if we had never got 
2897     // EVT_KILL_FOCUS before which means that we finish by redrawing the items 
2898     // which are already drawn correctly resulting in horrible flicker - avoid 
2908 void wxListMainWindow::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
2912         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetParent()->GetId() ); 
2913         event
.SetEventObject( GetParent() ); 
2914         if ( GetParent()->GetEventHandler()->ProcessEvent( event
) ) 
2922 void wxListMainWindow::DrawImage( int index
, wxDC 
*dc
, int x
, int y 
) 
2924     if ( HasFlag(wxLC_ICON
) && (m_normal_image_list
)) 
2926         m_normal_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
2928     else if ( HasFlag(wxLC_SMALL_ICON
) && (m_small_image_list
)) 
2930         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
2932     else if ( HasFlag(wxLC_LIST
) && (m_small_image_list
)) 
2934         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
2936     else if ( InReportView() && (m_small_image_list
)) 
2938         m_small_image_list
->Draw( index
, *dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
2942 void wxListMainWindow::GetImageSize( int index
, int &width
, int &height 
) const 
2944     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
2946         m_normal_image_list
->GetSize( index
, width
, height 
); 
2948     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
2950         m_small_image_list
->GetSize( index
, width
, height 
); 
2952     else if ( HasFlag(wxLC_LIST
) && m_small_image_list 
) 
2954         m_small_image_list
->GetSize( index
, width
, height 
); 
2956     else if ( InReportView() && m_small_image_list 
) 
2958         m_small_image_list
->GetSize( index
, width
, height 
); 
2967 void wxListMainWindow::SetImageList( wxImageList 
*imageList
, int which 
) 
2971     // calc the spacing from the icon size 
2972     int width 
= 0, height 
= 0; 
2974     if ((imageList
) && (imageList
->GetImageCount()) ) 
2975         imageList
->GetSize(0, width
, height
); 
2977     if (which 
== wxIMAGE_LIST_NORMAL
) 
2979         m_normal_image_list 
= imageList
; 
2980         m_normal_spacing 
= width 
+ 8; 
2983     if (which 
== wxIMAGE_LIST_SMALL
) 
2985         m_small_image_list 
= imageList
; 
2986         m_small_spacing 
= width 
+ 14; 
2987         m_lineHeight 
= 0;  // ensure that the line height will be recalc'd 
2991 void wxListMainWindow::SetItemSpacing( int spacing
, bool isSmall 
) 
2995         m_small_spacing 
= spacing
; 
2997         m_normal_spacing 
= spacing
; 
3000 int wxListMainWindow::GetItemSpacing( bool isSmall 
) 
3002     return isSmall 
? m_small_spacing 
: m_normal_spacing
; 
3005 // ---------------------------------------------------------------------------- 
3007 // ---------------------------------------------------------------------------- 
3010 wxListMainWindow::ComputeMinHeaderWidth(const wxListHeaderData
* column
) const 
3012     wxClientDC 
dc(const_cast<wxListMainWindow
*>(this)); 
3014     int width 
= dc
.GetTextExtent(column
->GetText()).x 
+ AUTOSIZE_COL_MARGIN
; 
3016     width 
+= 2*EXTRA_WIDTH
; 
3018     // check for column header's image availability 
3019     const int image 
= column
->GetImage(); 
3022         if ( m_small_image_list 
) 
3025             m_small_image_list
->GetSize(image
, ix
, iy
); 
3026             width 
+= ix 
+ HEADER_IMAGE_MARGIN_IN_REPORT_MODE
; 
3033 void wxListMainWindow::SetColumn( int col
, const wxListItem 
&item 
) 
3035     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3037     wxCHECK_RET( node
, wxT("invalid column index in SetColumn") ); 
3039     wxListHeaderData 
*column 
= node
->GetData(); 
3040     column
->SetItem( item 
); 
3042     if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER 
) 
3043         column
->SetWidth(ComputeMinHeaderWidth(column
)); 
3045     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3047         headerWin
->m_dirty 
= true; 
3051     // invalidate it as it has to be recalculated 
3055 void wxListMainWindow::SetColumnWidth( int col
, int width 
) 
3057     wxCHECK_RET( col 
>= 0 && col 
< GetColumnCount(), 
3058                  wxT("invalid column index") ); 
3060     wxCHECK_RET( InReportView(), 
3061                  wxT("SetColumnWidth() can only be called in report mode.") ); 
3065     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3067         headerWin
->m_dirty 
= true; 
3069     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3070     wxCHECK_RET( node
, wxT("no column?") ); 
3072     wxListHeaderData 
*column 
= node
->GetData(); 
3074     size_t count 
= GetItemCount(); 
3076     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3078         width 
= ComputeMinHeaderWidth(column
); 
3080     else if ( width 
== wxLIST_AUTOSIZE 
) 
3082         width 
= ComputeMinHeaderWidth(column
); 
3086             wxClientDC 
dc(this); 
3087             dc
.SetFont( GetFont() ); 
3089             int max 
= AUTOSIZE_COL_MARGIN
; 
3091             //  if the cached column width isn't valid then recalculate it 
3092             if (m_aColWidths
.Item(col
)->bNeedsUpdate
) 
3094                 for (size_t i 
= 0; i 
< count
; i
++) 
3096                     wxListLineData 
*line 
= GetLine( i 
); 
3097                     wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3099                     wxCHECK_RET( n
, wxT("no subitem?") ); 
3101                     wxListItemData 
*itemData 
= n
->GetData(); 
3104                     itemData
->GetItem(item
); 
3105                     int itemWidth 
= GetItemWidthWithImage(&item
); 
3106                     if (itemWidth 
> max
) 
3110                 m_aColWidths
.Item(col
)->bNeedsUpdate 
= false; 
3111                 m_aColWidths
.Item(col
)->nMaxWidth 
= max
; 
3114             max 
= m_aColWidths
.Item(col
)->nMaxWidth 
+ AUTOSIZE_COL_MARGIN
; 
3120     column
->SetWidth( width 
); 
3122     // invalidate it as it has to be recalculated 
3126 int wxListMainWindow::GetHeaderWidth() const 
3128     if ( !m_headerWidth 
) 
3130         wxListMainWindow 
*self 
= wxConstCast(this, wxListMainWindow
); 
3132         size_t count 
= GetColumnCount(); 
3133         for ( size_t col 
= 0; col 
< count
; col
++ ) 
3135             self
->m_headerWidth 
+= GetColumnWidth(col
); 
3139     return m_headerWidth
; 
3142 void wxListMainWindow::GetColumn( int col
, wxListItem 
&item 
) const 
3144     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3145     wxCHECK_RET( node
, wxT("invalid column index in GetColumn") ); 
3147     wxListHeaderData 
*column 
= node
->GetData(); 
3148     column
->GetItem( item 
); 
3151 int wxListMainWindow::GetColumnWidth( int col 
) const 
3153     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3154     wxCHECK_MSG( node
, 0, wxT("invalid column index") ); 
3156     wxListHeaderData 
*column 
= node
->GetData(); 
3157     return column
->GetWidth(); 
3160 // ---------------------------------------------------------------------------- 
3162 // ---------------------------------------------------------------------------- 
3164 void wxListMainWindow::SetItem( wxListItem 
&item 
) 
3166     long id 
= item
.m_itemId
; 
3167     wxCHECK_RET( id 
>= 0 && (size_t)id 
< GetItemCount(), 
3168                  wxT("invalid item index in SetItem") ); 
3172         wxListLineData 
*line 
= GetLine((size_t)id
); 
3173         line
->SetItem( item
.m_col
, item 
); 
3175         // Set item state if user wants 
3176         if ( item
.m_mask 
& wxLIST_MASK_STATE 
) 
3177             SetItemState( item
.m_itemId
, item
.m_state
, item
.m_state 
); 
3181             //  update the Max Width Cache if needed 
3182             int width 
= GetItemWidthWithImage(&item
); 
3184             if (width 
> m_aColWidths
.Item(item
.m_col
)->nMaxWidth
) 
3185                 m_aColWidths
.Item(item
.m_col
)->nMaxWidth 
= width
; 
3189     // update the item on screen unless we're going to update everything soon 
3194         GetItemRect(id
, rectItem
); 
3195         RefreshRect(rectItem
); 
3199 void wxListMainWindow::SetItemStateAll(long state
, long stateMask
) 
3204     // first deal with selection 
3205     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3207         // set/clear select state 
3210             // optimized version for virtual listctrl. 
3211             m_selStore
.SelectRange(0, GetItemCount() - 1, state 
== wxLIST_STATE_SELECTED
); 
3214         else if ( state 
& wxLIST_STATE_SELECTED 
) 
3216             const long count 
= GetItemCount(); 
3217             for( long i 
= 0; i 
<  count
; i
++ ) 
3219                 SetItemState( i
, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED 
); 
3225             // clear for non virtual (somewhat optimized by using GetNextItem()) 
3227             while ( (i 
= GetNextItem(i
, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
)) != -1 ) 
3229                 SetItemState( i
, 0, wxLIST_STATE_SELECTED 
); 
3234     if ( HasCurrent() && (state 
== 0) && (stateMask 
& wxLIST_STATE_FOCUSED
) ) 
3236         // unfocus all: only one item can be focussed, so clearing focus for 
3237         // all items is simply clearing focus of the focussed item. 
3238         SetItemState(m_current
, state
, stateMask
); 
3240     //(setting focus to all items makes no sense, so it is not handled here.) 
3243 void wxListMainWindow::SetItemState( long litem
, long state
, long stateMask 
) 
3247         SetItemStateAll(state
, stateMask
); 
3251     wxCHECK_RET( litem 
>= 0 && (size_t)litem 
< GetItemCount(), 
3252                  wxT("invalid list ctrl item index in SetItem") ); 
3254     size_t oldCurrent 
= m_current
; 
3255     size_t item 
= (size_t)litem
;    // safe because of the check above 
3257     // do we need to change the focus? 
3258     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3260         if ( state 
& wxLIST_STATE_FOCUSED 
) 
3262             // don't do anything if this item is already focused 
3263             if ( item 
!= m_current 
) 
3265                 ChangeCurrent(item
); 
3267                 if ( oldCurrent 
!= (size_t)-1 ) 
3269                     if ( IsSingleSel() ) 
3271                         HighlightLine(oldCurrent
, false); 
3274                     RefreshLine(oldCurrent
); 
3277                 RefreshLine( m_current 
); 
3282             // don't do anything if this item is not focused 
3283             if ( item 
== m_current 
) 
3287                 if ( IsSingleSel() ) 
3289                     // we must unselect the old current item as well or we 
3290                     // might end up with more than one selected item in a 
3291                     // single selection control 
3292                     HighlightLine(oldCurrent
, false); 
3295                 RefreshLine( oldCurrent 
); 
3300     // do we need to change the selection state? 
3301     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3303         bool on 
= (state 
& wxLIST_STATE_SELECTED
) != 0; 
3305         if ( IsSingleSel() ) 
3309                 // selecting the item also makes it the focused one in the 
3311                 if ( m_current 
!= item 
) 
3313                     ChangeCurrent(item
); 
3315                     if ( oldCurrent 
!= (size_t)-1 ) 
3317                         HighlightLine( oldCurrent
, false ); 
3318                         RefreshLine( oldCurrent 
); 
3324                 // only the current item may be selected anyhow 
3325                 if ( item 
!= m_current 
) 
3330         if ( HighlightLine(item
, on
) ) 
3337 int wxListMainWindow::GetItemState( long item
, long stateMask 
) const 
3339     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), 0, 
3340                  wxT("invalid list ctrl item index in GetItemState()") ); 
3342     int ret 
= wxLIST_STATE_DONTCARE
; 
3344     if ( stateMask 
& wxLIST_STATE_FOCUSED 
) 
3346         if ( (size_t)item 
== m_current 
) 
3347             ret 
|= wxLIST_STATE_FOCUSED
; 
3350     if ( stateMask 
& wxLIST_STATE_SELECTED 
) 
3352         if ( IsHighlighted(item
) ) 
3353             ret 
|= wxLIST_STATE_SELECTED
; 
3359 void wxListMainWindow::GetItem( wxListItem 
&item 
) const 
3361     wxCHECK_RET( item
.m_itemId 
>= 0 && (size_t)item
.m_itemId 
< GetItemCount(), 
3362                  wxT("invalid item index in GetItem") ); 
3364     wxListLineData 
*line 
= GetLine((size_t)item
.m_itemId
); 
3365     line
->GetItem( item
.m_col
, item 
); 
3367     // Get item state if user wants it 
3368     if ( item
.m_mask 
& wxLIST_MASK_STATE 
) 
3369         item
.m_state 
= GetItemState( item
.m_itemId
, wxLIST_STATE_SELECTED 
| 
3370                                                  wxLIST_STATE_FOCUSED 
); 
3373 // ---------------------------------------------------------------------------- 
3375 // ---------------------------------------------------------------------------- 
3377 size_t wxListMainWindow::GetItemCount() const 
3379     return IsVirtual() ? m_countVirt 
: m_lines
.GetCount(); 
3382 void wxListMainWindow::SetItemCount(long count
) 
3384     m_selStore
.SetItemCount(count
); 
3385     m_countVirt 
= count
; 
3387     ResetVisibleLinesRange(); 
3389     // scrollbars must be reset 
3393 int wxListMainWindow::GetSelectedItemCount() const 
3395     // deal with the quick case first 
3396     if ( IsSingleSel() ) 
3397         return HasCurrent() ? IsHighlighted(m_current
) : false; 
3399     // virtual controls remmebers all its selections itself 
3401         return m_selStore
.GetSelectedCount(); 
3403     // TODO: we probably should maintain the number of items selected even for 
3404     //       non virtual controls as enumerating all lines is really slow... 
3405     size_t countSel 
= 0; 
3406     size_t count 
= GetItemCount(); 
3407     for ( size_t line 
= 0; line 
< count
; line
++ ) 
3409         if ( GetLine(line
)->IsHighlighted() ) 
3416 // ---------------------------------------------------------------------------- 
3417 // item position/size 
3418 // ---------------------------------------------------------------------------- 
3420 wxRect 
wxListMainWindow::GetViewRect() const 
3422     wxASSERT_MSG( !HasFlag(wxLC_LIST
), "not implemented for list view" ); 
3424     // we need to find the longest/tallest label 
3425     wxCoord xMax 
= 0, yMax 
= 0; 
3426     const int count 
= GetItemCount(); 
3429         for ( int i 
= 0; i 
< count
; i
++ ) 
3431             // we need logical, not physical, coordinates here, so use 
3432             // GetLineRect() instead of GetItemRect() 
3433             wxRect r 
= GetLineRect(i
); 
3435             wxCoord x 
= r
.GetRight(), 
3445     // some fudge needed to make it look prettier 
3446     xMax 
+= 2 * EXTRA_BORDER_X
; 
3447     yMax 
+= 2 * EXTRA_BORDER_Y
; 
3449     // account for the scrollbars if necessary 
3450     const wxSize sizeAll 
= GetClientSize(); 
3451     if ( xMax 
> sizeAll
.x 
) 
3452         yMax 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
3453     if ( yMax 
> sizeAll
.y 
) 
3454         xMax 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
3456     return wxRect(0, 0, xMax
, yMax
); 
3460 wxListMainWindow::GetSubItemRect(long item
, long subItem
, wxRect
& rect
) const 
3462     wxCHECK_MSG( subItem 
== wxLIST_GETSUBITEMRECT_WHOLEITEM 
|| InReportView(), 
3464                  wxT("GetSubItemRect only meaningful in report view") ); 
3465     wxCHECK_MSG( item 
>= 0 && (size_t)item 
< GetItemCount(), false, 
3466                  wxT("invalid item in GetSubItemRect") ); 
3468     // ensure that we're laid out, otherwise we could return nonsense 
3471         wxConstCast(this, wxListMainWindow
)-> 
3472             RecalculatePositions(true /* no refresh */); 
3475     rect 
= GetLineRect((size_t)item
); 
3477     // Adjust rect to specified column 
3478     if ( subItem 
!= wxLIST_GETSUBITEMRECT_WHOLEITEM 
) 
3480         wxCHECK_MSG( subItem 
>= 0 && subItem 
< GetColumnCount(), false, 
3481                      wxT("invalid subItem in GetSubItemRect") ); 
3483         for (int i 
= 0; i 
< subItem
; i
++) 
3485             rect
.x 
+= GetColumnWidth(i
); 
3487         rect
.width 
= GetColumnWidth(subItem
); 
3490     GetListCtrl()->CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
); 
3495 bool wxListMainWindow::GetItemPosition(long item
, wxPoint
& pos
) const 
3498     GetItemRect(item
, rect
); 
3506 // ---------------------------------------------------------------------------- 
3507 // geometry calculation 
3508 // ---------------------------------------------------------------------------- 
3510 void wxListMainWindow::RecalculatePositions(bool noRefresh
) 
3512     const int lineHeight 
= GetLineHeight(); 
3514     wxClientDC 
dc( this ); 
3515     dc
.SetFont( GetFont() ); 
3517     const size_t count 
= GetItemCount(); 
3520     if ( HasFlag(wxLC_ICON
) && m_normal_image_list 
) 
3521         iconSpacing 
= m_normal_spacing
; 
3522     else if ( HasFlag(wxLC_SMALL_ICON
) && m_small_image_list 
) 
3523         iconSpacing 
= m_small_spacing
; 
3527     // Note that we do not call GetClientSize() here but 
3528     // GetSize() and subtract the border size for sunken 
3529     // borders manually. This is technically incorrect, 
3530     // but we need to know the client area's size WITHOUT 
3531     // scrollbars here. Since we don't know if there are 
3532     // any scrollbars, we use GetSize() instead. Another 
3533     // solution would be to call SetScrollbars() here to 
3534     // remove the scrollbars and call GetClientSize() then, 
3535     // but this might result in flicker and - worse - will 
3536     // reset the scrollbars to 0 which is not good at all 
3537     // if you resize a dialog/window, but don't want to 
3538     // reset the window scrolling. RR. 
3539     // Furthermore, we actually do NOT subtract the border 
3540     // width as 2 pixels is just the extra space which we 
3541     // need around the actual content in the window. Other- 
3542     // wise the text would e.g. touch the upper border. RR. 
3545     GetSize( &clientWidth
, &clientHeight 
); 
3547     if ( InReportView() ) 
3549         // all lines have the same height and we scroll one line per step 
3550         int entireHeight 
= count 
* lineHeight 
+ LINE_SPACING
; 
3552         m_linesPerPage 
= clientHeight 
/ lineHeight
; 
3554         ResetVisibleLinesRange(); 
3556         GetListCtrl()->SetScrollbars( SCROLL_UNIT_X
, lineHeight
, 
3557                        GetHeaderWidth() / SCROLL_UNIT_X
, 
3558                        (entireHeight 
+ lineHeight 
- 1) / lineHeight
, 
3559                        GetListCtrl()->GetScrollPos(wxHORIZONTAL
), 
3560                        GetListCtrl()->GetScrollPos(wxVERTICAL
), 
3565         // we have 3 different layout strategies: either layout all items 
3566         // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or 
3567         // to arrange them in top to bottom, left to right (don't ask me why 
3568         // not the other way round...) order 
3569         if ( HasFlag(wxLC_ALIGN_LEFT 
| wxLC_ALIGN_TOP
) ) 
3571             int x 
= EXTRA_BORDER_X
; 
3572             int y 
= EXTRA_BORDER_Y
; 
3574             wxCoord widthMax 
= 0; 
3577             for ( i 
= 0; i 
< count
; i
++ ) 
3579                 wxListLineData 
*line 
= GetLine(i
); 
3580                 line
->CalculateSize( &dc
, iconSpacing 
); 
3581                 line
->SetPosition( x
, y
, iconSpacing 
); 
3583                 wxSize sizeLine 
= GetLineSize(i
); 
3585                 if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3587                     if ( sizeLine
.x 
> widthMax 
) 
3588                         widthMax 
= sizeLine
.x
; 
3592                 else // wxLC_ALIGN_LEFT 
3594                     x 
+= sizeLine
.x 
+ MARGIN_BETWEEN_ROWS
; 
3598             if ( HasFlag(wxLC_ALIGN_TOP
) ) 
3600                 // traverse the items again and tweak their sizes so that they are 
3601                 // all the same in a row 
3602                 for ( i 
= 0; i 
< count
; i
++ ) 
3604                     wxListLineData 
*line 
= GetLine(i
); 
3605                     line
->m_gi
->ExtendWidth(widthMax
); 
3609             GetListCtrl()->SetScrollbars
 
3613                 (x 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3614                 (y 
+ lineHeight
) / lineHeight
, 
3615                 GetListCtrl()->GetScrollPos( wxHORIZONTAL 
), 
3616                 GetListCtrl()->GetScrollPos( wxVERTICAL 
), 
3620         else // "flowed" arrangement, the most complicated case 
3622             // at first we try without any scrollbars, if the items don't fit into 
3623             // the window, we recalculate after subtracting the space taken by the 
3626             int entireWidth 
= 0; 
3628             for (int tries 
= 0; tries 
< 2; tries
++) 
3630                 entireWidth 
= 2 * EXTRA_BORDER_X
; 
3634                     // Now we have decided that the items do not fit into the 
3635                     // client area, so we need a scrollbar 
3636                     entireWidth 
+= SCROLL_UNIT_X
; 
3639                 int x 
= EXTRA_BORDER_X
; 
3640                 int y 
= EXTRA_BORDER_Y
; 
3642                 // Note that "row" here is vertical, i.e. what is called 
3643                 // "column" in many other places in wxWidgets. 
3644                 int maxWidthInThisRow 
= 0; 
3647                 int currentlyVisibleLines 
= 0; 
3649                 for (size_t i 
= 0; i 
< count
; i
++) 
3651                     currentlyVisibleLines
++; 
3652                     wxListLineData 
*line 
= GetLine( i 
); 
3653                     line
->CalculateSize( &dc
, iconSpacing 
); 
3654                     line
->SetPosition( x
, y
, iconSpacing 
); 
3656                     wxSize sizeLine 
= GetLineSize( i 
); 
3658                     if ( maxWidthInThisRow 
< sizeLine
.x 
) 
3659                         maxWidthInThisRow 
= sizeLine
.x
; 
3662                     if (currentlyVisibleLines 
> m_linesPerPage
) 
3663                         m_linesPerPage 
= currentlyVisibleLines
; 
3665                     // Have we reached the end of the row either because no 
3666                     // more items would fit or because there are simply no more 
3668                     if ( y 
+ sizeLine
.y 
>= clientHeight
 
3671                         // Adjust all items in this row to have the same 
3672                         // width to ensure that they all align horizontally in 
3674                         if ( HasFlag(wxLC_ICON
) || HasFlag(wxLC_SMALL_ICON
) ) 
3676                             size_t firstRowLine 
= i 
- currentlyVisibleLines 
+ 1; 
3677                             for (size_t j 
= firstRowLine
; j 
<= i
; j
++) 
3679                                 GetLine(j
)->m_gi
->ExtendWidth(maxWidthInThisRow
); 
3683                         currentlyVisibleLines 
= 0; 
3685                         maxWidthInThisRow 
+= MARGIN_BETWEEN_ROWS
; 
3686                         x 
+= maxWidthInThisRow
; 
3687                         entireWidth 
+= maxWidthInThisRow
; 
3688                         maxWidthInThisRow 
= 0; 
3691                     if ( (tries 
== 0) && 
3692                             (entireWidth 
+ SCROLL_UNIT_X 
> clientWidth
) ) 
3694                         clientHeight 
-= wxSystemSettings:: 
3695                                             GetMetric(wxSYS_HSCROLL_Y
); 
3700                     if ( i 
== count 
- 1 ) 
3701                         tries 
= 1;  // Everything fits, no second try required. 
3705             GetListCtrl()->SetScrollbars
 
3709                 (entireWidth 
+ SCROLL_UNIT_X
) / SCROLL_UNIT_X
, 
3711                 GetListCtrl()->GetScrollPos( wxHORIZONTAL 
), 
3720         // FIXME: why should we call it from here? 
3727 void wxListMainWindow::RefreshAll() 
3732     wxListHeaderWindow 
*headerWin 
= GetListCtrl()->m_headerWin
; 
3733     if ( headerWin 
&& headerWin
->m_dirty 
) 
3735         headerWin
->m_dirty 
= false; 
3736         headerWin
->Refresh(); 
3740 void wxListMainWindow::UpdateCurrent() 
3742     if ( !HasCurrent() && !IsEmpty() ) 
3746 long wxListMainWindow::GetNextItem( long item
, 
3747                                     int WXUNUSED(geometry
), 
3751          max 
= GetItemCount(); 
3752     wxCHECK_MSG( (ret 
== -1) || (ret 
< max
), -1, 
3753                  wxT("invalid listctrl index in GetNextItem()") ); 
3755     // notice that we start with the next item (or the first one if item == -1) 
3756     // and this is intentional to allow writing a simple loop to iterate over 
3757     // all selected items 
3760         // this is not an error because the index was OK initially, 
3761         // just no such item 
3768     size_t count 
= GetItemCount(); 
3769     for ( size_t line 
= (size_t)ret
; line 
< count
; line
++ ) 
3771         if ( (state 
& wxLIST_STATE_FOCUSED
) && (line 
== m_current
) ) 
3774         if ( (state 
& wxLIST_STATE_SELECTED
) && IsHighlighted(line
) ) 
3781 // ---------------------------------------------------------------------------- 
3783 // ---------------------------------------------------------------------------- 
3785 void wxListMainWindow::DeleteItem( long lindex 
) 
3787     size_t count 
= GetItemCount(); 
3789     wxCHECK_RET( (lindex 
>= 0) && ((size_t)lindex 
< count
), 
3790                  wxT("invalid item index in DeleteItem") ); 
3792     size_t index 
= (size_t)lindex
; 
3794     // we don't need to adjust the index for the previous items 
3795     if ( HasCurrent() && m_current 
>= index 
) 
3797         // if the current item is being deleted, we want the next one to 
3798         // become selected - unless there is no next one - so don't adjust 
3799         // m_current in this case 
3800         if ( m_current 
!= index 
|| m_current 
== count 
- 1 ) 
3804     if ( InReportView() ) 
3806         //  mark the Column Max Width cache as dirty if the items in the line 
3807         //  we're deleting contain the Max Column Width 
3808         wxListLineData 
* const line 
= GetLine(index
); 
3809         wxListItemDataList::compatibility_iterator n
; 
3810         wxListItemData 
*itemData
; 
3814         for (size_t i 
= 0; i 
< m_columns
.GetCount(); i
++) 
3816             n 
= line
->m_items
.Item( i 
); 
3817             itemData 
= n
->GetData(); 
3818             itemData
->GetItem(item
); 
3820             itemWidth 
= GetItemWidthWithImage(&item
); 
3822             if (itemWidth 
>= m_aColWidths
.Item(i
)->nMaxWidth
) 
3823                 m_aColWidths
.Item(i
)->bNeedsUpdate 
= true; 
3826         ResetVisibleLinesRange(); 
3829     SendNotify( index
, wxEVT_COMMAND_LIST_DELETE_ITEM
, wxDefaultPosition 
); 
3834         m_selStore
.OnItemDelete(index
); 
3838         m_lines
.RemoveAt( index 
); 
3841     // we need to refresh the (vert) scrollbar as the number of items changed 
3844     RefreshAfter(index
); 
3847 void wxListMainWindow::DeleteColumn( int col 
) 
3849     wxListHeaderDataList::compatibility_iterator node 
= m_columns
.Item( col 
); 
3851     wxCHECK_RET( node
, wxT("invalid column index in DeleteColumn()") ); 
3854     delete node
->GetData(); 
3855     m_columns
.Erase( node 
); 
3859         // update all the items 
3860         for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
3862             wxListLineData 
* const line 
= GetLine(i
); 
3864             // In the following atypical but possible scenario it can be 
3865             // legal to call DeleteColumn() but the items may not have any 
3867             //  1. In report view, insert a second column. 
3868             //  2. Still in report view, add an item with 2 values. 
3869             //  3. Switch to an icon (or list) view. 
3870             //  4. Add an item -- necessarily with 1 value only. 
3871             //  5. Switch back to report view. 
3872             //  6. Call DeleteColumn(). 
3873             // So we need to check for this as otherwise we would simply crash 
3875             if ( line
->m_items
.GetCount() <= static_cast<unsigned>(col
) ) 
3878             wxListItemDataList::compatibility_iterator n 
= line
->m_items
.Item( col 
); 
3879             delete n
->GetData(); 
3880             line
->m_items
.Erase(n
); 
3884     if ( InReportView() )   //  we only cache max widths when in Report View 
3886         delete m_aColWidths
.Item(col
); 
3887         m_aColWidths
.RemoveAt(col
); 
3890     // invalidate it as it has to be recalculated 
3894 void wxListMainWindow::DoDeleteAllItems() 
3897         // nothing to do - in particular, don't send the event 
3902     // to make the deletion of all items faster, we don't send the 
3903     // notifications for each item deletion in this case but only one event 
3904     // for all of them: this is compatible with wxMSW and documented in 
3905     // DeleteAllItems() description 
3907     wxListEvent 
event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
, GetParent()->GetId() ); 
3908     event
.SetEventObject( GetParent() ); 
3909     GetParent()->GetEventHandler()->ProcessEvent( event 
); 
3917     if ( InReportView() ) 
3919         ResetVisibleLinesRange(); 
3920         for (size_t i 
= 0; i 
< m_aColWidths
.GetCount(); i
++) 
3922             m_aColWidths
.Item(i
)->bNeedsUpdate 
= true; 
3929 void wxListMainWindow::DeleteAllItems() 
3933     RecalculatePositions(); 
3936 void wxListMainWindow::DeleteEverything() 
3938     WX_CLEAR_LIST(wxListHeaderDataList
, m_columns
); 
3939     WX_CLEAR_ARRAY(m_aColWidths
); 
3944 // ---------------------------------------------------------------------------- 
3945 // scanning for an item 
3946 // ---------------------------------------------------------------------------- 
3948 void wxListMainWindow::EnsureVisible( long index 
) 
3950     wxCHECK_RET( index 
>= 0 && (size_t)index 
< GetItemCount(), 
3951                  wxT("invalid index in EnsureVisible") ); 
3953     // We have to call this here because the label in question might just have 
3954     // been added and its position is not known yet 
3956         RecalculatePositions(true /* no refresh */); 
3958     MoveToItem((size_t)index
); 
3961 long wxListMainWindow::FindItem(long start
, const wxString
& str
, bool partial 
) 
3967     wxString str_upper 
= str
.Upper(); 
3971     size_t count 
= GetItemCount(); 
3972     for ( size_t i 
= (size_t)pos
; i 
< count
; i
++ ) 
3974         wxListLineData 
*line 
= GetLine(i
); 
3975         wxString line_upper 
= line
->GetText(0).Upper(); 
3978             if (line_upper 
== str_upper 
) 
3983             if (line_upper
.find(str_upper
) == 0) 
3991 long wxListMainWindow::FindItem(long start
, wxUIntPtr data
) 
3997     size_t count 
= GetItemCount(); 
3998     for (size_t i 
= (size_t)pos
; i 
< count
; i
++) 
4000         wxListLineData 
*line 
= GetLine(i
); 
4002         line
->GetItem( 0, item 
); 
4003         if (item
.m_data 
== data
) 
4010 long wxListMainWindow::FindItem( const wxPoint
& pt 
) 
4013     GetVisibleLinesRange( &topItem
, NULL 
); 
4016     GetItemPosition( GetItemCount() - 1, p 
); 
4020     long id 
= (long)floor( pt
.y 
* double(GetItemCount() - topItem 
- 1) / p
.y 
+ topItem 
); 
4021     if ( id 
>= 0 && id 
< (long)GetItemCount() ) 
4027 long wxListMainWindow::HitTest( int x
, int y
, int &flags 
) const 
4029     GetListCtrl()->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
4031     size_t count 
= GetItemCount(); 
4033     if ( InReportView() ) 
4035         size_t current 
= y 
/ GetLineHeight(); 
4036         if ( current 
< count 
) 
4038             flags 
= HitTestLine(current
, x
, y
); 
4045         // TODO: optimize it too! this is less simple than for report view but 
4046         //       enumerating all items is still not a way to do it!! 
4047         for ( size_t current 
= 0; current 
< count
; current
++ ) 
4049             flags 
= HitTestLine(current
, x
, y
); 
4058 // ---------------------------------------------------------------------------- 
4060 // ---------------------------------------------------------------------------- 
4062 void wxListMainWindow::InsertItem( wxListItem 
&item 
) 
4064     wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual control") ); 
4066     int count 
= GetItemCount(); 
4067     wxCHECK_RET( item
.m_itemId 
>= 0, wxT("invalid item index") ); 
4069     if (item
.m_itemId 
> count
) 
4070         item
.m_itemId 
= count
; 
4072     size_t id 
= item
.m_itemId
; 
4076     if ( InReportView() ) 
4078         ResetVisibleLinesRange(); 
4080         const unsigned col 
= item
.GetColumn(); 
4081         wxCHECK_RET( col 
< m_aColWidths
.size(), "invalid item column" ); 
4083         // calculate the width of the item and adjust the max column width 
4084         wxColWidthInfo 
*pWidthInfo 
= m_aColWidths
.Item(col
); 
4085         int width 
= GetItemWidthWithImage(&item
); 
4086         item
.SetWidth(width
); 
4087         if (width 
> pWidthInfo
->nMaxWidth
) 
4088             pWidthInfo
->nMaxWidth 
= width
; 
4091     wxListLineData 
*line 
= new wxListLineData(this); 
4093     line
->SetItem( item
.m_col
, item 
); 
4094     if ( item
.m_mask 
& wxLIST_MASK_IMAGE 
) 
4096         // Reset the buffered height if it's not big enough for the new image. 
4097         int image 
= item
.GetImage(); 
4098         if ( m_small_image_list 
&& image 
!= -1 && InReportView() ) 
4100             int imageWidth
, imageHeight
; 
4101             m_small_image_list
->GetSize(image
, imageWidth
, imageHeight
); 
4103             if ( imageHeight 
> m_lineHeight 
) 
4108     m_lines
.Insert( line
, id 
); 
4112     // If an item is selected at or below the point of insertion, we need to 
4113     // increment the member variables because the current row's index has gone 
4115     if ( HasCurrent() && m_current 
>= id 
) 
4118     SendNotify(id
, wxEVT_COMMAND_LIST_INSERT_ITEM
); 
4120     RefreshLines(id
, GetItemCount() - 1); 
4123 void wxListMainWindow::InsertColumn( long col
, const wxListItem 
&item 
) 
4126     if ( InReportView() ) 
4128         wxListHeaderData 
*column 
= new wxListHeaderData( item 
); 
4129         if (item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4130             column
->SetWidth(ComputeMinHeaderWidth(column
)); 
4132         wxColWidthInfo 
*colWidthInfo 
= new wxColWidthInfo(); 
4134         bool insert 
= (col 
>= 0) && ((size_t)col 
< m_columns
.GetCount()); 
4137             wxListHeaderDataList::compatibility_iterator
 
4138                 node 
= m_columns
.Item( col 
); 
4139             m_columns
.Insert( node
, column 
); 
4140             m_aColWidths
.Insert( colWidthInfo
, col 
); 
4144             m_columns
.Append( column 
); 
4145             m_aColWidths
.Add( colWidthInfo 
); 
4150             // update all the items 
4151             for ( size_t i 
= 0; i 
< m_lines
.GetCount(); i
++ ) 
4153                 wxListLineData 
* const line 
= GetLine(i
); 
4154                 wxListItemData 
* const data 
= new wxListItemData(this); 
4156                     line
->m_items
.Insert(col
, data
); 
4158                     line
->m_items
.Append(data
); 
4162         // invalidate it as it has to be recalculated 
4167 int wxListMainWindow::GetItemWidthWithImage(wxListItem 
* item
) 
4170     wxClientDC 
dc(this); 
4172     dc
.SetFont( GetFont() ); 
4174     if (item
->GetImage() != -1) 
4177         GetImageSize( item
->GetImage(), ix
, iy 
); 
4181     if (!item
->GetText().empty()) 
4184         dc
.GetTextExtent( item
->GetText(), &w
, NULL 
); 
4191 // ---------------------------------------------------------------------------- 
4193 // ---------------------------------------------------------------------------- 
4195 static wxListCtrlCompare list_ctrl_compare_func_2
; 
4196 static wxIntPtr          list_ctrl_compare_data
; 
4198 int LINKAGEMODE 
list_ctrl_compare_func_1( wxListLineData 
**arg1
, wxListLineData 
**arg2 
) 
4200     wxListLineData 
*line1 
= *arg1
; 
4201     wxListLineData 
*line2 
= *arg2
; 
4203     line1
->GetItem( 0, item 
); 
4204     wxUIntPtr data1 
= item
.m_data
; 
4205     line2
->GetItem( 0, item 
); 
4206     wxUIntPtr data2 
= item
.m_data
; 
4207     return list_ctrl_compare_func_2( data1
, data2
, list_ctrl_compare_data 
); 
4210 void wxListMainWindow::SortItems( wxListCtrlCompare fn
, wxIntPtr data 
) 
4212     // selections won't make sense any more after sorting the items so reset 
4214     HighlightAll(false); 
4217     list_ctrl_compare_func_2 
= fn
; 
4218     list_ctrl_compare_data 
= data
; 
4219     m_lines
.Sort( list_ctrl_compare_func_1 
); 
4223 // ---------------------------------------------------------------------------- 
4225 // ---------------------------------------------------------------------------- 
4227 void wxListMainWindow::OnScroll(wxScrollWinEvent
& event
) 
4229     // update our idea of which lines are shown when we redraw the window the 
4231     ResetVisibleLinesRange(); 
4233     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4235         wxGenericListCtrl
* lc 
= GetListCtrl(); 
4236         wxCHECK_RET( lc
, wxT("no listctrl window?") ); 
4238         if (lc
->m_headerWin
) // when we use wxLC_NO_HEADER, m_headerWin==NULL 
4240             lc
->m_headerWin
->Refresh(); 
4241             lc
->m_headerWin
->Update(); 
4246 int wxListMainWindow::GetCountPerPage() const 
4248     if ( !m_linesPerPage 
) 
4250         wxConstCast(this, wxListMainWindow
)-> 
4251             m_linesPerPage 
= GetClientSize().y 
/ GetLineHeight(); 
4254     return m_linesPerPage
; 
4257 void wxListMainWindow::GetVisibleLinesRange(size_t *from
, size_t *to
) 
4259     wxASSERT_MSG( InReportView(), wxT("this is for report mode only") ); 
4261     if ( m_lineFrom 
== (size_t)-1 ) 
4263         size_t count 
= GetItemCount(); 
4266             m_lineFrom 
= GetListCtrl()->GetScrollPos(wxVERTICAL
); 
4268             // this may happen if SetScrollbars() hadn't been called yet 
4269             if ( m_lineFrom 
>= count 
) 
4270                 m_lineFrom 
= count 
- 1; 
4272             // we redraw one extra line but this is needed to make the redrawing 
4273             // logic work when there is a fractional number of lines on screen 
4274             m_lineTo 
= m_lineFrom 
+ m_linesPerPage
; 
4275             if ( m_lineTo 
>= count 
) 
4276                 m_lineTo 
= count 
- 1; 
4278         else // empty control 
4281             m_lineTo 
= (size_t)-1; 
4285     wxASSERT_MSG( IsEmpty() || 
4286                   (m_lineFrom 
<= m_lineTo 
&& m_lineTo 
< GetItemCount()), 
4287                   wxT("GetVisibleLinesRange() returns incorrect result") ); 
4295 // ------------------------------------------------------------------------------------- 
4296 // wxGenericListCtrl 
4297 // ------------------------------------------------------------------------------------- 
4299 IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl
, wxControl
) 
4301 BEGIN_EVENT_TABLE(wxGenericListCtrl
,wxListCtrlBase
) 
4302   EVT_SIZE(wxGenericListCtrl::OnSize
) 
4303   EVT_SCROLLWIN(wxGenericListCtrl::OnScroll
) 
4306 void wxGenericListCtrl::Init() 
4308     m_imageListNormal 
= NULL
; 
4309     m_imageListSmall 
= NULL
; 
4310     m_imageListState 
= NULL
; 
4312     m_ownsImageListNormal 
= 
4313     m_ownsImageListSmall 
= 
4314     m_ownsImageListState 
= false; 
4320 wxGenericListCtrl::~wxGenericListCtrl() 
4322     if (m_ownsImageListNormal
) 
4323         delete m_imageListNormal
; 
4324     if (m_ownsImageListSmall
) 
4325         delete m_imageListSmall
; 
4326     if (m_ownsImageListState
) 
4327         delete m_imageListState
; 
4330 void wxGenericListCtrl::CreateOrDestroyHeaderWindowAsNeeded() 
4332     bool needs_header 
= HasHeader(); 
4333     bool has_header 
= (m_headerWin 
!= NULL
); 
4335     if (needs_header 
== has_header
) 
4340         m_headerWin 
= new wxListHeaderWindow
 
4342                         this, wxID_ANY
, m_mainWin
, 
4347                           wxRendererNative::Get().GetHeaderButtonHeight(this) 
4352 #if defined( __WXMAC__ ) 
4353         static wxFont 
font( wxOSX_SYSTEM_FONT_SMALL 
); 
4354         m_headerWin
->SetFont( font 
); 
4357         GetSizer()->Prepend( m_headerWin
, 0, wxGROW 
); 
4361         GetSizer()->Detach( m_headerWin 
); 
4363         wxDELETE(m_headerWin
); 
4367 bool wxGenericListCtrl::Create(wxWindow 
*parent
, 
4372                         const wxValidator 
&validator
, 
4373                         const wxString 
&name
) 
4377     // just like in other ports, an assert will fail if the user doesn't give any type style: 
4378     wxASSERT_MSG( (style 
& wxLC_MASK_TYPE
), 
4379                   wxT("wxListCtrl style should have exactly one mode bit set") ); 
4381     if ( !wxListCtrlBase::Create( parent
, id
, pos
, size
, 
4382                                   style 
| wxVSCROLL 
| wxHSCROLL
, 
4387     style 
&= ~wxBORDER_MASK
; 
4388     style 
|= wxBORDER_THEME
; 
4391     m_mainWin 
= new wxListMainWindow( this, wxID_ANY
, wxPoint(0, 0), size
, style 
); 
4393     SetTargetWindow( m_mainWin 
); 
4395     // We use the cursor keys for moving the selection, not scrolling, so call 
4396     // this method to ensure wxScrollHelperEvtHandler doesn't catch all 
4397     // keyboard events forwarded to us from wxListMainWindow. 
4398     DisableKeyboardScrolling(); 
4400     wxBoxSizer 
*sizer 
= new wxBoxSizer( wxVERTICAL 
); 
4401     sizer
->Add( m_mainWin
, 1, wxGROW 
); 
4404     CreateOrDestroyHeaderWindowAsNeeded(); 
4406     SetInitialSize(size
); 
4411 wxBorder 
wxGenericListCtrl::GetDefaultBorder() const 
4413     return wxBORDER_THEME
; 
4416 #if defined(__WXMSW__) && !defined(__WXWINCE__) && !defined(__WXUNIVERSAL__) 
4417 WXLRESULT 
wxGenericListCtrl::MSWWindowProc(WXUINT nMsg
, 
4421     WXLRESULT rc 
= wxListCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
4423     // we need to process arrows ourselves for scrolling 
4424     if ( nMsg 
== WM_GETDLGCODE 
) 
4426         rc 
|= DLGC_WANTARROWS
; 
4433 wxSize 
wxGenericListCtrl::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
4435     wxSize newsize 
= size
; 
4437        newsize
.y 
-= m_headerWin
->GetSize().y
; 
4442 void wxGenericListCtrl::OnScroll(wxScrollWinEvent
& event
) 
4444     // update our idea of which lines are shown when we redraw 
4445     // the window the next time 
4446     m_mainWin
->ResetVisibleLinesRange(); 
4448     HandleOnScroll( event 
); 
4450     if ( event
.GetOrientation() == wxHORIZONTAL 
&& HasHeader() ) 
4452         m_headerWin
->Refresh(); 
4453         m_headerWin
->Update(); 
4457 void wxGenericListCtrl::SetSingleStyle( long style
, bool add 
) 
4459     wxASSERT_MSG( !(style 
& wxLC_VIRTUAL
), 
4460                   wxT("wxLC_VIRTUAL can't be [un]set") ); 
4462     long flag 
= GetWindowStyle(); 
4466         if (style 
& wxLC_MASK_TYPE
) 
4467             flag 
&= ~(wxLC_MASK_TYPE 
| wxLC_VIRTUAL
); 
4468         if (style 
& wxLC_MASK_ALIGN
) 
4469             flag 
&= ~wxLC_MASK_ALIGN
; 
4470         if (style 
& wxLC_MASK_SORT
) 
4471             flag 
&= ~wxLC_MASK_SORT
; 
4479     // some styles can be set without recreating everything (as happens in 
4480     // SetWindowStyleFlag() which calls wxListMainWindow::DeleteEverything()) 
4481     if ( !(style 
& ~(wxLC_HRULES 
| wxLC_VRULES
)) ) 
4484         wxWindow::SetWindowStyleFlag(flag
); 
4488         SetWindowStyleFlag( flag 
); 
4492 void wxGenericListCtrl::SetWindowStyleFlag( long flag 
) 
4494     // we add wxHSCROLL and wxVSCROLL in ctor unconditionally and it never 
4495     // makes sense to remove them as we'll always add scrollbars anyhow when 
4497     flag 
|= wxHSCROLL 
| wxVSCROLL
; 
4499     const bool wasInReportView 
= HasFlag(wxLC_REPORT
); 
4501     // update the window style first so that the header is created or destroyed 
4502     // corresponding to the new style 
4503     wxWindow::SetWindowStyleFlag( flag 
); 
4507         const bool inReportView 
= (flag 
& wxLC_REPORT
) != 0; 
4508         if ( inReportView 
!= wasInReportView 
) 
4510             // we need to notify the main window about this change as it must 
4511             // update its data structures 
4512             m_mainWin
->SetReportView(inReportView
); 
4515         // m_mainWin->DeleteEverything();  wxMSW doesn't do that 
4517         CreateOrDestroyHeaderWindowAsNeeded(); 
4519         GetSizer()->Layout(); 
4523 bool wxGenericListCtrl::GetColumn(int col
, wxListItem 
&item
) const 
4525     m_mainWin
->GetColumn( col
, item 
); 
4529 bool wxGenericListCtrl::SetColumn( int col
, const wxListItem
& item 
) 
4531     m_mainWin
->SetColumn( col
, item 
); 
4535 int wxGenericListCtrl::GetColumnWidth( int col 
) const 
4537     return m_mainWin
->GetColumnWidth( col 
); 
4540 bool wxGenericListCtrl::SetColumnWidth( int col
, int width 
) 
4542     m_mainWin
->SetColumnWidth( col
, width 
); 
4546 int wxGenericListCtrl::GetCountPerPage() const 
4548   return m_mainWin
->GetCountPerPage();  // different from Windows ? 
4551 bool wxGenericListCtrl::GetItem( wxListItem 
&info 
) const 
4553     m_mainWin
->GetItem( info 
); 
4557 bool wxGenericListCtrl::SetItem( wxListItem 
&info 
) 
4559     m_mainWin
->SetItem( info 
); 
4563 long wxGenericListCtrl::SetItem( long index
, int col
, const wxString
& label
, int imageId 
) 
4566     info
.m_text 
= label
; 
4567     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4568     info
.m_itemId 
= index
; 
4572         info
.m_image 
= imageId
; 
4573         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4576     m_mainWin
->SetItem(info
); 
4580 int wxGenericListCtrl::GetItemState( long item
, long stateMask 
) const 
4582     return m_mainWin
->GetItemState( item
, stateMask 
); 
4585 bool wxGenericListCtrl::SetItemState( long item
, long state
, long stateMask 
) 
4587     m_mainWin
->SetItemState( item
, state
, stateMask 
); 
4592 wxGenericListCtrl::SetItemImage( long item
, int image
, int WXUNUSED(selImage
) ) 
4594     return SetItemColumnImage(item
, 0, image
); 
4598 wxGenericListCtrl::SetItemColumnImage( long item
, long column
, int image 
) 
4601     info
.m_image 
= image
; 
4602     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4603     info
.m_itemId 
= item
; 
4604     info
.m_col 
= column
; 
4605     m_mainWin
->SetItem( info 
); 
4609 wxString 
wxGenericListCtrl::GetItemText( long item
, int col 
) const 
4611     return m_mainWin
->GetItemText(item
, col
); 
4614 void wxGenericListCtrl::SetItemText( long item
, const wxString
& str 
) 
4616     m_mainWin
->SetItemText(item
, str
); 
4619 wxUIntPtr 
wxGenericListCtrl::GetItemData( long item 
) const 
4622     info
.m_mask 
= wxLIST_MASK_DATA
; 
4623     info
.m_itemId 
= item
; 
4624     m_mainWin
->GetItem( info 
); 
4628 bool wxGenericListCtrl::SetItemPtrData( long item
, wxUIntPtr data 
) 
4631     info
.m_mask 
= wxLIST_MASK_DATA
; 
4632     info
.m_itemId 
= item
; 
4634     m_mainWin
->SetItem( info 
); 
4638 wxRect 
wxGenericListCtrl::GetViewRect() const 
4640     return m_mainWin
->GetViewRect(); 
4643 bool wxGenericListCtrl::GetItemRect(long item
, wxRect
& rect
, int code
) const 
4645     return GetSubItemRect(item
, wxLIST_GETSUBITEMRECT_WHOLEITEM
, rect
, code
); 
4648 bool wxGenericListCtrl::GetSubItemRect(long item
, 
4651                                        int WXUNUSED(code
)) const 
4653     if ( !m_mainWin
->GetSubItemRect( item
, subItem
, rect 
) ) 
4656     if ( m_mainWin
->HasHeader() ) 
4657         rect
.y 
+= m_headerWin
->GetSize().y 
+ 1; 
4662 bool wxGenericListCtrl::GetItemPosition( long item
, wxPoint
& pos 
) const 
4664     m_mainWin
->GetItemPosition( item
, pos 
); 
4668 bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item
), const wxPoint
& WXUNUSED(pos
) ) 
4673 int wxGenericListCtrl::GetItemCount() const 
4675     return m_mainWin
->GetItemCount(); 
4678 int wxGenericListCtrl::GetColumnCount() const 
4680     return m_mainWin
->GetColumnCount(); 
4683 void wxGenericListCtrl::SetItemSpacing( int spacing
, bool isSmall 
) 
4685     m_mainWin
->SetItemSpacing( spacing
, isSmall 
); 
4688 wxSize 
wxGenericListCtrl::GetItemSpacing() const 
4690     const int spacing 
= m_mainWin
->GetItemSpacing(HasFlag(wxLC_SMALL_ICON
)); 
4692     return wxSize(spacing
, spacing
); 
4695 #if WXWIN_COMPATIBILITY_2_6 
4696 int wxGenericListCtrl::GetItemSpacing( bool isSmall 
) const 
4698     return m_mainWin
->GetItemSpacing( isSmall 
); 
4700 #endif // WXWIN_COMPATIBILITY_2_6 
4702 void wxGenericListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
4705     info
.m_itemId 
= item
; 
4706     info
.SetTextColour( col 
); 
4707     m_mainWin
->SetItem( info 
); 
4710 wxColour 
wxGenericListCtrl::GetItemTextColour( long item 
) const 
4713     info
.m_itemId 
= item
; 
4714     m_mainWin
->GetItem( info 
); 
4715     return info
.GetTextColour(); 
4718 void wxGenericListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
4721     info
.m_itemId 
= item
; 
4722     info
.SetBackgroundColour( col 
); 
4723     m_mainWin
->SetItem( info 
); 
4726 wxColour 
wxGenericListCtrl::GetItemBackgroundColour( long item 
) const 
4729     info
.m_itemId 
= item
; 
4730     m_mainWin
->GetItem( info 
); 
4731     return info
.GetBackgroundColour(); 
4734 void wxGenericListCtrl::SetItemFont( long item
, const wxFont 
&f 
) 
4737     info
.m_itemId 
= item
; 
4739     m_mainWin
->SetItem( info 
); 
4742 wxFont 
wxGenericListCtrl::GetItemFont( long item 
) const 
4745     info
.m_itemId 
= item
; 
4746     m_mainWin
->GetItem( info 
); 
4747     return info
.GetFont(); 
4750 int wxGenericListCtrl::GetSelectedItemCount() const 
4752     return m_mainWin
->GetSelectedItemCount(); 
4755 wxColour 
wxGenericListCtrl::GetTextColour() const 
4757     return GetForegroundColour(); 
4760 void wxGenericListCtrl::SetTextColour(const wxColour
& col
) 
4762     SetForegroundColour(col
); 
4765 long wxGenericListCtrl::GetTopItem() const 
4768     m_mainWin
->GetVisibleLinesRange(&top
, NULL
); 
4772 long wxGenericListCtrl::GetNextItem( long item
, int geom
, int state 
) const 
4774     return m_mainWin
->GetNextItem( item
, geom
, state 
); 
4777 wxImageList 
*wxGenericListCtrl::GetImageList(int which
) const 
4779     if (which 
== wxIMAGE_LIST_NORMAL
) 
4780         return m_imageListNormal
; 
4781     else if (which 
== wxIMAGE_LIST_SMALL
) 
4782         return m_imageListSmall
; 
4783     else if (which 
== wxIMAGE_LIST_STATE
) 
4784         return m_imageListState
; 
4789 void wxGenericListCtrl::SetImageList( wxImageList 
*imageList
, int which 
) 
4791     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4793         if (m_ownsImageListNormal
) 
4794             delete m_imageListNormal
; 
4795         m_imageListNormal 
= imageList
; 
4796         m_ownsImageListNormal 
= false; 
4798     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4800         if (m_ownsImageListSmall
) 
4801             delete m_imageListSmall
; 
4802         m_imageListSmall 
= imageList
; 
4803         m_ownsImageListSmall 
= false; 
4805     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4807         if (m_ownsImageListState
) 
4808             delete m_imageListState
; 
4809         m_imageListState 
= imageList
; 
4810         m_ownsImageListState 
= false; 
4813     m_mainWin
->SetImageList( imageList
, which 
); 
4816 void wxGenericListCtrl::AssignImageList(wxImageList 
*imageList
, int which
) 
4818     SetImageList(imageList
, which
); 
4819     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
4820         m_ownsImageListNormal 
= true; 
4821     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
4822         m_ownsImageListSmall 
= true; 
4823     else if ( which 
== wxIMAGE_LIST_STATE 
) 
4824         m_ownsImageListState 
= true; 
4827 bool wxGenericListCtrl::Arrange( int WXUNUSED(flag
) ) 
4832 bool wxGenericListCtrl::DeleteItem( long item 
) 
4834     m_mainWin
->DeleteItem( item 
); 
4838 bool wxGenericListCtrl::DeleteAllItems() 
4840     m_mainWin
->DeleteAllItems(); 
4844 bool wxGenericListCtrl::DeleteAllColumns() 
4846     size_t count 
= m_mainWin
->m_columns
.GetCount(); 
4847     for ( size_t n 
= 0; n 
< count
; n
++ ) 
4852 void wxGenericListCtrl::ClearAll() 
4854     m_mainWin
->DeleteEverything(); 
4857 bool wxGenericListCtrl::DeleteColumn( int col 
) 
4859     m_mainWin
->DeleteColumn( col 
); 
4861     // if we don't have the header any longer, we need to relayout the window 
4862     // if ( !GetColumnCount() ) 
4865     // Ensure that the non-existent columns are really removed from display. 
4871 wxTextCtrl 
*wxGenericListCtrl::EditLabel(long item
, 
4872                                          wxClassInfo
* textControlClass
) 
4874     return m_mainWin
->EditLabel( item
, textControlClass 
); 
4877 wxTextCtrl 
*wxGenericListCtrl::GetEditControl() const 
4879     return m_mainWin
->GetEditControl(); 
4882 bool wxGenericListCtrl::EnsureVisible( long item 
) 
4884     m_mainWin
->EnsureVisible( item 
); 
4888 long wxGenericListCtrl::FindItem( long start
, const wxString
& str
, bool partial 
) 
4890     return m_mainWin
->FindItem( start
, str
, partial 
); 
4893 long wxGenericListCtrl::FindItem( long start
, wxUIntPtr data 
) 
4895     return m_mainWin
->FindItem( start
, data 
); 
4898 long wxGenericListCtrl::FindItem( long WXUNUSED(start
), const wxPoint
& pt
, 
4899                            int WXUNUSED(direction
)) 
4901     return m_mainWin
->FindItem( pt 
); 
4904 // TODO: sub item hit testing 
4905 long wxGenericListCtrl::HitTest(const wxPoint
& point
, int& flags
, long *) const 
4907     return m_mainWin
->HitTest( (int)point
.x
, (int)point
.y
, flags 
); 
4910 long wxGenericListCtrl::InsertItem( wxListItem
& info 
) 
4912     m_mainWin
->InsertItem( info 
); 
4913     return info
.m_itemId
; 
4916 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label 
) 
4919     info
.m_text 
= label
; 
4920     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4921     info
.m_itemId 
= index
; 
4922     return InsertItem( info 
); 
4925 long wxGenericListCtrl::InsertItem( long index
, int imageIndex 
) 
4928     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
4929     info
.m_image 
= imageIndex
; 
4930     info
.m_itemId 
= index
; 
4931     return InsertItem( info 
); 
4934 long wxGenericListCtrl::InsertItem( long index
, const wxString 
&label
, int imageIndex 
) 
4937     info
.m_text 
= label
; 
4938     info
.m_image 
= imageIndex
; 
4939     info
.m_mask 
= wxLIST_MASK_TEXT
; 
4940     if (imageIndex 
> -1) 
4941         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
4942     info
.m_itemId 
= index
; 
4943     return InsertItem( info 
); 
4946 long wxGenericListCtrl::DoInsertColumn( long col
, const wxListItem 
&item 
) 
4948     wxCHECK_MSG( InReportView(), -1, wxT("can't add column in non report mode") ); 
4950     m_mainWin
->InsertColumn( col
, item 
); 
4952     // NOTE: if wxLC_NO_HEADER was given, then we are in report view mode but 
4953     //       still have m_headerWin==NULL 
4955         m_headerWin
->Refresh(); 
4960 bool wxGenericListCtrl::ScrollList( int dx
, int dy 
) 
4962     return m_mainWin
->ScrollList(dx
, dy
); 
4966 // fn is a function which takes 3 long arguments: item1, item2, data. 
4967 // item1 is the long data associated with a first item (NOT the index). 
4968 // item2 is the long data associated with a second item (NOT the index). 
4969 // data is the same value as passed to SortItems. 
4970 // The return value is a negative number if the first item should precede the second 
4971 // item, a positive number of the second item should precede the first, 
4972 // or zero if the two items are equivalent. 
4973 // data is arbitrary data to be passed to the sort function. 
4975 bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn
, wxIntPtr data 
) 
4977     m_mainWin
->SortItems( fn
, data 
); 
4981 // ---------------------------------------------------------------------------- 
4983 // ---------------------------------------------------------------------------- 
4985 void wxGenericListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
4987     if (!m_mainWin
) return; 
4989     // We need to override OnSize so that our scrolled 
4990     // window a) does call Layout() to use sizers for 
4991     // positioning the controls but b) does not query 
4992     // the sizer for their size and use that for setting 
4993     // the scrollable area as set that ourselves by 
4994     // calling SetScrollbar() further down. 
4998     m_mainWin
->RecalculatePositions(); 
5003 void wxGenericListCtrl::OnInternalIdle() 
5005     wxWindow::OnInternalIdle(); 
5007     if (m_mainWin
->m_dirty
) 
5008         m_mainWin
->RecalculatePositions(); 
5011 // ---------------------------------------------------------------------------- 
5013 // ---------------------------------------------------------------------------- 
5015 bool wxGenericListCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
5019         m_mainWin
->SetBackgroundColour( colour 
); 
5020         m_mainWin
->m_dirty 
= true; 
5026 bool wxGenericListCtrl::SetForegroundColour( const wxColour 
&colour 
) 
5028     if ( !wxWindow::SetForegroundColour( colour 
) ) 
5033         m_mainWin
->SetForegroundColour( colour 
); 
5034         m_mainWin
->m_dirty 
= true; 
5038         m_headerWin
->SetForegroundColour( colour 
); 
5043 bool wxGenericListCtrl::SetFont( const wxFont 
&font 
) 
5045     if ( !wxWindow::SetFont( font 
) ) 
5050         m_mainWin
->SetFont( font 
); 
5051         m_mainWin
->m_dirty 
= true; 
5056         m_headerWin
->SetFont( font 
); 
5057         // CalculateAndSetHeaderHeight(); 
5067 wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
5070     // Use the same color scheme as wxListBox 
5071     return wxListBox::GetClassDefaultAttributes(variant
); 
5073     wxUnusedVar(variant
); 
5074     wxVisualAttributes attr
; 
5075     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT
); 
5076     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
5077     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
5082 // ---------------------------------------------------------------------------- 
5083 // methods forwarded to m_mainWin 
5084 // ---------------------------------------------------------------------------- 
5086 #if wxUSE_DRAG_AND_DROP 
5088 void wxGenericListCtrl::SetDropTarget( wxDropTarget 
*dropTarget 
) 
5090     m_mainWin
->SetDropTarget( dropTarget 
); 
5093 wxDropTarget 
*wxGenericListCtrl::GetDropTarget() const 
5095     return m_mainWin
->GetDropTarget(); 
5100 bool wxGenericListCtrl::SetCursor( const wxCursor 
&cursor 
) 
5102     return m_mainWin 
? m_mainWin
->wxWindow::SetCursor(cursor
) : false; 
5105 wxColour 
wxGenericListCtrl::GetBackgroundColour() const 
5107     return m_mainWin 
? m_mainWin
->GetBackgroundColour() : wxColour(); 
5110 wxColour 
wxGenericListCtrl::GetForegroundColour() const 
5112     return m_mainWin 
? m_mainWin
->GetForegroundColour() : wxColour(); 
5115 bool wxGenericListCtrl::DoPopupMenu( wxMenu 
*menu
, int x
, int y 
) 
5118     return m_mainWin
->PopupMenu( menu
, x
, y 
); 
5124 void wxGenericListCtrl::DoClientToScreen( int *x
, int *y 
) const 
5126     // It's not clear whether this can be called before m_mainWin is created 
5127     // but it seems better to be on the safe side and check. 
5129         m_mainWin
->DoClientToScreen(x
, y
); 
5131         wxListCtrlBase::DoClientToScreen(x
, y
); 
5134 void wxGenericListCtrl::DoScreenToClient( int *x
, int *y 
) const 
5136     // At least in wxGTK/Univ build this method can be called before m_mainWin 
5137     // is created so avoid crashes in this case. 
5139         m_mainWin
->DoScreenToClient(x
, y
); 
5141         wxListCtrlBase::DoScreenToClient(x
, y
); 
5144 void wxGenericListCtrl::SetFocus() 
5146     // The test in window.cpp fails as we are a composite 
5147     // window, so it checks against "this", but not m_mainWin. 
5148     if ( DoFindFocus() != this ) 
5149         m_mainWin
->SetFocus(); 
5152 wxSize 
wxGenericListCtrl::DoGetBestClientSize() const 
5154     // Something is better than nothing even if this is completely arbitrary. 
5155     wxSize 
sizeBest(100, 80); 
5157     if ( !InReportView() ) 
5159         // Ensure that our minimal width is at least big enough to show all our 
5160         // items. This is important for wxListbook to size itself correctly. 
5162         // Remember the offset of the first item: this corresponds to the 
5163         // margins around the item so we will add it to the minimal size below 
5164         // to ensure that we have equal margins on all sides. 
5167         // We can iterate over all items as there shouldn't be too many of them 
5168         // in non-report view. If it ever becomes a problem, we could examine 
5169         // just the first few items probably, the determination of the best 
5170         // size is less important if we will need scrollbars anyhow. 
5171         for ( int n 
= 0; n 
< GetItemCount(); n
++ ) 
5173             const wxRect itemRect 
= m_mainWin
->GetLineRect(n
); 
5176                 // Remember the position of the first item as all the rest are 
5177                 // offset by at least this number of pixels too. 
5178                 ofs 
= itemRect
.GetPosition(); 
5181             sizeBest
.IncTo(itemRect
.GetSize()); 
5184         sizeBest
.IncBy(2*ofs
); 
5187         // If we have the scrollbars we need to account for them too. And to 
5188         // make sure the scrollbars status is up to date we need to call this 
5189         // function to set them. 
5190         m_mainWin
->RecalculatePositions(true /* no refresh */); 
5192         // Unfortunately we can't use wxWindow::HasScrollbar() here as we need 
5193         // to use m_mainWin client/virtual size for determination of whether we 
5194         // use scrollbars and not the size of this window itself. Maybe that 
5195         // function should be extended to work correctly in the case when our 
5196         // scrollbars manage a different window from this one but currently it 
5198         const wxSize sizeClient 
= m_mainWin
->GetClientSize(); 
5199         const wxSize sizeVirt 
= m_mainWin
->GetVirtualSize(); 
5201         if ( sizeVirt
.x 
> sizeClient
.x 
/* HasScrollbar(wxHORIZONTAL) */ ) 
5202             sizeBest
.y 
+= wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y
); 
5204         if ( sizeVirt
.y 
> sizeClient
.y 
/* HasScrollbar(wxVERTICAL) */ ) 
5205             sizeBest
.x 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
5211 // ---------------------------------------------------------------------------- 
5212 // virtual list control support 
5213 // ---------------------------------------------------------------------------- 
5215 wxString 
wxGenericListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
5217     // this is a pure virtual function, in fact - which is not really pure 
5218     // because the controls which are not virtual don't need to implement it 
5219     wxFAIL_MSG( wxT("wxGenericListCtrl::OnGetItemText not supposed to be called") ); 
5221     return wxEmptyString
; 
5224 int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
5226     wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL
), 
5228                 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden.")); 
5232 int wxGenericListCtrl::OnGetItemColumnImage(long item
, long column
) const 
5235         return OnGetItemImage(item
); 
5241 wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
5243     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
5244                   wxT("invalid item index in OnGetItemAttr()") ); 
5246     // no attributes by default 
5250 void wxGenericListCtrl::SetItemCount(long count
) 
5252     wxASSERT_MSG( IsVirtual(), wxT("this is for virtual controls only") ); 
5254     m_mainWin
->SetItemCount(count
); 
5257 void wxGenericListCtrl::RefreshItem(long item
) 
5259     m_mainWin
->RefreshLine(item
); 
5262 void wxGenericListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
5264     m_mainWin
->RefreshLines(itemFrom
, itemTo
); 
5267 // Generic wxListCtrl is more or less a container for two other 
5268 // windows which drawings are done upon. These are namely 
5269 // 'm_headerWin' and 'm_mainWin'. 
5270 // Here we override 'virtual wxWindow::Refresh()' to mimic the 
5271 // behaviour wxListCtrl has under wxMSW. 
5273 void wxGenericListCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
5277         // The easy case, no rectangle specified. 
5279             m_headerWin
->Refresh(eraseBackground
); 
5282             m_mainWin
->Refresh(eraseBackground
); 
5286         // Refresh the header window 
5289             wxRect rectHeader 
= m_headerWin
->GetRect(); 
5290             rectHeader
.Intersect(*rect
); 
5291             if (rectHeader
.GetWidth() && rectHeader
.GetHeight()) 
5294                 m_headerWin
->GetPosition(&x
, &y
); 
5295                 rectHeader
.Offset(-x
, -y
); 
5296                 m_headerWin
->Refresh(eraseBackground
, &rectHeader
); 
5300         // Refresh the main window 
5303             wxRect rectMain 
= m_mainWin
->GetRect(); 
5304             rectMain
.Intersect(*rect
); 
5305             if (rectMain
.GetWidth() && rectMain
.GetHeight()) 
5308                 m_mainWin
->GetPosition(&x
, &y
); 
5309                 rectMain
.Offset(-x
, -y
); 
5310                 m_mainWin
->Refresh(eraseBackground
, &rectMain
); 
5316 void wxGenericListCtrl::Update() 
5320         if ( m_mainWin
->m_dirty 
) 
5321             m_mainWin
->RecalculatePositions(); 
5323         m_mainWin
->Update(); 
5327         m_headerWin
->Update(); 
5330 #endif // wxUSE_LISTCTRL