]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/listctrl.cpp
removed unneeded makefiles
[wxWidgets.git] / src / generic / listctrl.cpp
index 583333642acd0cb7ec9c8bd30e5c8a16dc20381c..ad5c03498851e38ea4654e12e6d113a40c6ed68e 100644 (file)
@@ -106,21 +106,26 @@ DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
 // // the height of the header window (FIXME: should depend on its font!)
 // static const int HEADER_HEIGHT = 23;
 
-// the scrollbar units
 static const int SCROLL_UNIT_X = 15;
-static const int SCROLL_UNIT_Y = 15;
 
 // the spacing between the lines (in report mode)
 static const int LINE_SPACING = 0;
 
 // extra margins around the text label
-static const int EXTRA_WIDTH = 3;
+static const int EXTRA_WIDTH = 4;
 static const int EXTRA_HEIGHT = 4;
 
+// margin between the window and the items
+static const int EXTRA_BORDER_X = 2;
+static const int EXTRA_BORDER_Y = 2;
+
 // offset for the header window
 static const int HEADER_OFFSET_X = 1;
 static const int HEADER_OFFSET_Y = 1;
 
+// margin between rows of icons in [small] icon view
+static const int MARGIN_BETWEEN_ROWS = 6;
+
 // when autosizing the columns, add some slack
 static const int AUTOSIZE_COL_MARGIN = 10;
 
@@ -275,6 +280,18 @@ public:
 
         // the part to be highlighted
         wxRect m_rectHighlight;
+
+        // extend all our rects to be centered inside theo ne of given width
+        void ExtendWidth(wxCoord w)
+        {
+            wxASSERT_MSG( m_rectAll.width <= w,
+                            _T("width can only be increased") );
+
+            m_rectAll.width = w;
+            m_rectLabel.x = m_rectAll.x + (w - m_rectLabel.width)/2;
+            m_rectIcon.x = m_rectAll.x + (w - m_rectIcon.width)/2;
+            m_rectHighlight.x = m_rectAll.x + (w - m_rectHighlight.width)/2;
+        }
     } *m_gi;
 
     // is this item selected? [NB: not used in virtual mode]
@@ -305,7 +322,7 @@ public:
     void CalculateSize( wxDC *dc, int spacing );
 
     // remember the position this line appears at
-    void SetPosition( int x, int y,  int window_width, int spacing );
+    void SetPosition( int x, int y, int spacing );
 
     // wxListCtrl API
 
@@ -502,7 +519,7 @@ public:
 
     // do we have a header window?
     bool HasHeader() const
-        { return HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER); }
+        { return InReportView() && !HasFlag(wxLC_NO_HEADER); }
 
     void HighlightAll( bool on );
 
@@ -724,8 +741,6 @@ public:
     bool                 m_dirty;
 
     wxColour            *m_highlightColour;
-    int                  m_xScroll,
-                         m_yScroll;
     wxImageListType         *m_small_image_list;
     wxImageListType         *m_normal_image_list;
     int                  m_small_spacing;
@@ -753,9 +768,6 @@ protected:
     // common part of all ctors
     void Init();
 
-    // intiialize m_[xy]Scroll
-    void InitScrolling();
-
     // get the line data for the given index
     wxListLineData *GetLine(size_t n) const
     {
@@ -1113,96 +1125,89 @@ void wxListLineData::CalculateSize( wxDC *dc, int spacing )
 
     wxListItemData *item = node->GetData();
 
+    wxString s;
+    wxCoord lw, lh;
+
     switch ( GetMode() )
     {
         case wxLC_ICON:
         case wxLC_SMALL_ICON:
-            {
-                m_gi->m_rectAll.width = spacing;
+            m_gi->m_rectAll.width = spacing;
 
-                wxString s = item->GetText();
+            s = item->GetText();
 
-                wxCoord lw, lh;
-                if ( s.empty() )
-                {
-                    lh =
-                    m_gi->m_rectLabel.width =
-                    m_gi->m_rectLabel.height = 0;
-                }
-                else // has label
-                {
-                    dc->GetTextExtent( s, &lw, &lh );
-                    if (lh < SCROLL_UNIT_Y)
-                        lh = SCROLL_UNIT_Y;
-                    lw += EXTRA_WIDTH;
-                    lh += EXTRA_HEIGHT;
-
-                    m_gi->m_rectAll.height = spacing + lh;
-                    if (lw > spacing)
-                        m_gi->m_rectAll.width = lw;
-
-                    m_gi->m_rectLabel.width = lw;
-                    m_gi->m_rectLabel.height = lh;
-                }
-
-                if (item->HasImage())
-                {
-                    int w, h;
-                    m_owner->GetImageSize( item->GetImage(), w, h );
-                    m_gi->m_rectIcon.width = w + 8;
-                    m_gi->m_rectIcon.height = h + 8;
-
-                    if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
-                        m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
-                    if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
-                        m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
-                }
-
-                if ( item->HasText() )
-                {
-                    m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
-                    m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
-                }
-                else // no text, highlight the icon
-                {
-                    m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
-                    m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
-                }
+            if ( s.empty() )
+            {
+                lh =
+                m_gi->m_rectLabel.width =
+                m_gi->m_rectLabel.height = 0;
             }
-            break;
-
-        case wxLC_LIST:
+            else // has label
             {
-                wxString s = item->GetTextForMeasuring();
-
-                wxCoord lw,lh;
                 dc->GetTextExtent( s, &lw, &lh );
-                if (lh < SCROLL_UNIT_Y)
-                    lh = SCROLL_UNIT_Y;
                 lw += EXTRA_WIDTH;
                 lh += EXTRA_HEIGHT;
 
+                m_gi->m_rectAll.height = spacing + lh;
+                if (lw > spacing)
+                    m_gi->m_rectAll.width = lw;
+
                 m_gi->m_rectLabel.width = lw;
                 m_gi->m_rectLabel.height = lh;
+            }
 
-                m_gi->m_rectAll.width = lw;
-                m_gi->m_rectAll.height = lh;
+            if (item->HasImage())
+            {
+                int w, h;
+                m_owner->GetImageSize( item->GetImage(), w, h );
+                m_gi->m_rectIcon.width = w + 8;
+                m_gi->m_rectIcon.height = h + 8;
+
+                if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
+                    m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
+                if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
+                    m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
+            }
 
-                if (item->HasImage())
-                {
-                    int w, h;
-                    m_owner->GetImageSize( item->GetImage(), w, h );
-                    m_gi->m_rectIcon.width = w;
-                    m_gi->m_rectIcon.height = h;
-
-                    m_gi->m_rectAll.width += 4 + w;
-                    if (h > m_gi->m_rectAll.height)
-                        m_gi->m_rectAll.height = h;
-                }
+            if ( item->HasText() )
+            {
+                m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
+                m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
+            }
+            else // no text, highlight the icon
+            {
+                m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
+                m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
+            }
+            break;
+
+        case wxLC_LIST:
+            s = item->GetTextForMeasuring();
 
-                m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
-                m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
+            dc->GetTextExtent( s, &lw, &lh );
+            lw += EXTRA_WIDTH;
+            lh += EXTRA_HEIGHT;
+
+            m_gi->m_rectLabel.width = lw;
+            m_gi->m_rectLabel.height = lh;
+
+            m_gi->m_rectAll.width = lw;
+            m_gi->m_rectAll.height = lh;
+
+            if (item->HasImage())
+            {
+                int w, h;
+                m_owner->GetImageSize( item->GetImage(), w, h );
+                m_gi->m_rectIcon.width = w;
+                m_gi->m_rectIcon.height = h;
+
+                m_gi->m_rectAll.width += 4 + w;
+                if (h > m_gi->m_rectAll.height)
+                    m_gi->m_rectAll.height = h;
             }
+
+            m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
+            m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
             break;
 
         case wxLC_REPORT:
@@ -1214,9 +1219,7 @@ void wxListLineData::CalculateSize( wxDC *dc, int spacing )
     }
 }
 
-void wxListLineData::SetPosition( int x, int y,
-                                  int WXUNUSED(window_width),
-                                  int spacing )
+void wxListLineData::SetPosition( int x, int y, int spacing )
 {
     wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
     wxCHECK_RET( node, _T("no subitems at all??") );
@@ -1446,20 +1449,31 @@ void wxListLineData::Draw( wxDC *dc )
         dc->DrawRectangle( m_gi->m_rectHighlight );
     }
 
+    // just for debugging to better see where the items are
+#if 0
+    dc->SetPen(*wxRED_PEN);
+    dc->SetBrush(*wxTRANSPARENT_BRUSH);
+    dc->DrawRectangle( m_gi->m_rectAll );
+    dc->SetPen(*wxGREEN_PEN);
+    dc->DrawRectangle( m_gi->m_rectIcon );
+#endif // 0
+
     wxListItemData *item = node->GetData();
     if (item->HasImage())
     {
-        wxRect rectIcon = m_gi->m_rectIcon;
-        m_owner->DrawImage( item->GetImage(), dc,
-                            rectIcon.x, rectIcon.y );
+        // centre the image inside our rectangle, this looks nicer when items
+        // ae aligned in a row
+        const wxRect& rectIcon = m_gi->m_rectIcon;
+
+        m_owner->DrawImage(item->GetImage(), dc, rectIcon.x, rectIcon.y);
     }
 
     if (item->HasText())
     {
-        wxRect rectLabel = m_gi->m_rectLabel;
+        const wxRect& rectLabel = m_gi->m_rectLabel;
 
         wxDCClipper clipper(*dc, rectLabel);
-        dc->DrawText( item->GetText(), rectLabel.x, rectLabel.y );
+        dc->DrawText(item->GetText(), rectLabel.x, rectLabel.y);
     }
 }
 
@@ -1585,7 +1599,7 @@ void wxListLineData::DrawTextFormatted(wxDC *dc,
 
 bool wxListLineData::Highlight( bool on )
 {
-    wxCHECK_MSG( !m_owner->IsVirtual(), FALSE, _T("unexpected call to Highlight") );
+    wxCHECK_MSG( !IsVirtual(), FALSE, _T("unexpected call to Highlight") );
 
     if ( on == m_highlighted )
         return FALSE;
@@ -1718,7 +1732,8 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
 
         // for this we need the width of the text
         wxCoord wLabel;
-        dc.GetTextExtent(item.GetText(), &wLabel, NULL);
+       wxCoord hLabel;
+        dc.GetTextExtent(item.GetText(), &wLabel, &hLabel);
         wLabel += 2*EXTRA_WIDTH;
 
         // and the width of the icon, if any
@@ -1783,7 +1798,7 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
         wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
 
         dc.DrawText( item.GetText(),
-                     xAligned + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
+                     xAligned + EXTRA_WIDTH, h / 2 - hLabel / 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT );
 
         x += wCol;
     }
@@ -1903,8 +1918,8 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
                 {
                     m_isDragging = TRUE;
                     m_currentX = x;
-                    DrawCurrent();
                     CaptureMouse();
+                    DrawCurrent();
                 }
                 //else: column resizing was vetoed by the user code
             }
@@ -1939,6 +1954,7 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
 void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
 {
     m_owner->SetFocus();
+    m_owner->Update();
 }
 
 bool wxListHeaderWindow::SendListEvent(wxEventType type, wxPoint pos)
@@ -2084,11 +2100,11 @@ void wxListTextCtrl::OnKillFocus( wxFocusEvent &event )
     {
         // We must finish regardless of success, otherwise we'll get focus problems
         Finish();
-    
+
         if ( !AcceptChanges() )
             m_owner->OnRenameCancelled( m_itemEdited );
     }
-        
+
     event.Skip();
 }
 
@@ -2139,29 +2155,12 @@ void wxListMainWindow::Init()
     m_freezeCount = 0;
 }
 
-void wxListMainWindow::InitScrolling()
-{
-    if ( HasFlag(wxLC_REPORT) )
-    {
-        m_xScroll = SCROLL_UNIT_X;
-        m_yScroll = SCROLL_UNIT_Y;
-    }
-    else
-    {
-        m_xScroll = SCROLL_UNIT_Y;
-        m_yScroll = 0;
-    }
-}
-
 wxListMainWindow::wxListMainWindow()
 {
     Init();
 
     m_highlightBrush =
     m_highlightUnfocusedBrush = (wxBrush *) NULL;
-
-    m_xScroll =
-    m_yScroll = 0;
 }
 
 wxListMainWindow::wxListMainWindow( wxWindow *parent,
@@ -2196,8 +2195,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent,
     wxSize sz = size;
     sz.y = 25;
 
-    InitScrolling();
-    SetScrollbars( m_xScroll, m_yScroll, 0, 0, 0, 0 );
+    SetScrollbars( 0, 0, 0, 0, 0, 0 );
 
     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX ) );
 }
@@ -2265,8 +2263,6 @@ wxListLineData *wxListMainWindow::GetDummyLine() const
 
 wxCoord wxListMainWindow::GetLineHeight() const
 {
-    wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
-
     // we cache the line height as calling GetTextExtent() is slow
     if ( !m_lineHeight )
     {
@@ -2278,9 +2274,6 @@ wxCoord wxListMainWindow::GetLineHeight() const
         wxCoord y;
         dc.GetTextExtent(_T("H"), NULL, &y);
 
-        if ( y < SCROLL_UNIT_Y )
-            y = SCROLL_UNIT_Y;
-
         if ( m_small_image_list && m_small_image_list->GetImageCount() )
         {
             int iw = 0;
@@ -2298,7 +2291,7 @@ wxCoord wxListMainWindow::GetLineHeight() const
 
 wxCoord wxListMainWindow::GetLineY(size_t line) const
 {
-    wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
+    wxASSERT_MSG( InReportView(), _T("only works in report mode") );
 
     return LINE_SPACING + line*GetLineHeight();
 }
@@ -2457,7 +2450,7 @@ bool wxListMainWindow::HighlightLine( size_t line, bool highlight )
 
 void wxListMainWindow::RefreshLine( size_t line )
 {
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         size_t visibleFrom, visibleTo;
         GetVisibleLinesRange(&visibleFrom, &visibleTo);
@@ -2479,7 +2472,7 @@ void wxListMainWindow::RefreshLines( size_t lineFrom, size_t lineTo )
 
     wxASSERT_MSG( lineTo < GetItemCount(), _T("invalid line range") );
 
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         size_t visibleFrom, visibleTo;
         GetVisibleLinesRange(&visibleFrom, &visibleTo);
@@ -2510,7 +2503,7 @@ void wxListMainWindow::RefreshLines( size_t lineFrom, size_t lineTo )
 
 void wxListMainWindow::RefreshAfter( size_t lineFrom )
 {
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         size_t visibleFrom, visibleTo;
         GetVisibleLinesRange(&visibleFrom, &visibleTo);
@@ -2612,7 +2605,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
 
     dc.SetFont( GetFont() );
 
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         int lineHeight = GetLineHeight();
 
@@ -2680,7 +2673,6 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
         {
             wxPen pen(GetRuleColour(), 1, wxSOLID);
 
-            int col = 0;
             wxRect firstItemRect;
             wxRect lastItemRect;
             GetItemRect(visibleFrom, firstItemRect);
@@ -2688,7 +2680,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
             int x = firstItemRect.GetX();
             dc.SetPen(pen);
             dc.SetBrush(* wxTRANSPARENT_BRUSH);
-            for (col = 0; col < GetColumnCount(); col++)
+            for (int col = 0; col < GetColumnCount(); col++)
             {
                 int colWidth = GetColumnWidth(col);
                 x += colWidth;
@@ -2706,22 +2698,18 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
         }
     }
 
+#ifndef __WXMAC__
+    // Don't draw rect outline under Mac at all.
     if ( HasCurrent() )
     {
-        // don't draw rect outline under Max if we already have the background
-        // color but under other platforms only draw it if we do: it is a bit
-        // silly to draw "focus rect" if we don't have focus!
-#ifdef __WXMAC__
-        if ( !m_hasFocus )
-#else // !__WXMAC__
         if ( m_hasFocus )
-#endif // __WXMAC__/!__WXMAC__
         {
             dc.SetPen( *wxBLACK_PEN );
             dc.SetBrush( *wxTRANSPARENT_BRUSH );
             dc.DrawRectangle( GetLineHighlightRect(m_current) );
         }
     }
+#endif
 
     dc.EndDrawing();
 }
@@ -2832,23 +2820,13 @@ bool wxListMainWindow::OnRenameAccept(size_t itemEdit, const wxString& value)
                 le.IsAllowed();
 }
 
-#ifdef __VMS__ // Ignore unreacheable code
-# pragma message disable initnotreach
-#endif
-
 void wxListMainWindow::OnRenameCancelled(size_t itemEdit)
 {
-    // wxMSW seems not to notify the program about
-    // cancelled label edits.
-    return;
-
     // let owner know that the edit was cancelled
     wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
-    
-    // These only exist for wxTreeCtrl, which should probably be changed
-    // le.m_editCancelled = TRUE;
-    // le.m_label = wxEmptyString;
-    
+
+    le.SetEditCanceled(TRUE);
+
     le.SetEventObject( GetParent() );
     le.m_itemIndex = itemEdit;
 
@@ -2859,9 +2837,6 @@ void wxListMainWindow::OnRenameCancelled(size_t itemEdit)
 
     GetEventHandler()->ProcessEvent( le );
 }
-#ifdef __VMS__
-# pragma message enable initnotreach
-#endif
 
 void wxListMainWindow::OnMouse( wxMouseEvent &event )
 {
@@ -2889,7 +2864,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
     size_t count = GetItemCount(),
            current;
 
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         current = y / GetLineHeight();
         if ( current < count )
@@ -3048,26 +3023,28 @@ void wxListMainWindow::MoveToItem(size_t item)
     int client_w, client_h;
     GetClientSize( &client_w, &client_h );
 
-    int view_x = m_xScroll*GetScrollPos( wxHORIZONTAL );
-    int view_y = m_yScroll*GetScrollPos( wxVERTICAL );
+    const int hLine = GetLineHeight();
+
+    int view_x = SCROLL_UNIT_X*GetScrollPos( wxHORIZONTAL );
+    int view_y = hLine*GetScrollPos( wxVERTICAL );
 
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         // the next we need the range of lines shown it might be different, so
         // recalculate it
         ResetVisibleLinesRange();
 
         if (rect.y < view_y )
-            Scroll( -1, rect.y/m_yScroll );
+            Scroll( -1, rect.y/hLine );
         if (rect.y+rect.height+5 > view_y+client_h)
-            Scroll( -1, (rect.y+rect.height-client_h+SCROLL_UNIT_Y)/m_yScroll );
+            Scroll( -1, (rect.y+rect.height-client_h+hLine)/hLine );
     }
     else // !report
     {
         if (rect.x-view_x < 5)
-            Scroll( (rect.x-5)/m_xScroll, -1 );
+            Scroll( (rect.x-5)/SCROLL_UNIT_X, -1 );
         if (rect.x+rect.width-5 > view_x+client_w)
-            Scroll( (rect.x+rect.width-client_w+SCROLL_UNIT_X)/m_xScroll, -1 );
+            Scroll( (rect.x+rect.width-client_w+SCROLL_UNIT_X)/SCROLL_UNIT_X, -1 );
     }
 }
 
@@ -3088,6 +3065,9 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
     {
         ChangeCurrent(newCurrent);
 
+        // refresh the old focus to remove it
+        RefreshLine( oldCurrent );
+
         // select all the items between the old and the new one
         if ( oldCurrent > newCurrent )
         {
@@ -3104,7 +3084,7 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
             HighlightAll(FALSE);
 
         ChangeCurrent(newCurrent);
-
+        
         // refresh the old focus to remove it
         RefreshLine( oldCurrent );
 
@@ -3113,7 +3093,7 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
             HighlightLine( m_current, TRUE );
         }
     }
-
+       
     RefreshLine( m_current );
 
     MoveToFocus();
@@ -3207,15 +3187,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
 
         case WXK_PRIOR:
             {
-                int steps = 0;
-                if ( HasFlag(wxLC_REPORT) )
-                {
-                    steps = m_linesPerPage - 1;
-                }
-                else
-                {
-                    steps = m_current % m_linesPerPage;
-                }
+                int steps = InReportView() ? m_linesPerPage - 1 : m_current % m_linesPerPage;
 
                 int index = m_current - steps;
                 if (index < 0)
@@ -3227,15 +3199,9 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
 
         case WXK_NEXT:
             {
-                int steps = 0;
-                if ( HasFlag(wxLC_REPORT) )
-                {
-                    steps = m_linesPerPage - 1;
-                }
-                else
-                {
-                    steps = m_linesPerPage - (m_current % m_linesPerPage) - 1;
-                }
+                int steps = InReportView()
+                               ? m_linesPerPage - 1
+                               : m_linesPerPage - (m_current % m_linesPerPage) - 1;
 
                 size_t index = m_current + steps;
                 size_t count = GetItemCount();
@@ -3247,7 +3213,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
             break;
 
         case WXK_LEFT:
-            if ( !HasFlag(wxLC_REPORT) )
+            if ( !InReportView() )
             {
                 int index = m_current - m_linesPerPage;
                 if (index < 0)
@@ -3258,7 +3224,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
             break;
 
         case WXK_RIGHT:
-            if ( !HasFlag(wxLC_REPORT) )
+            if ( !InReportView() )
             {
                 size_t index = m_current + m_linesPerPage;
 
@@ -3322,6 +3288,14 @@ void wxListMainWindow::SetFocus()
 
 void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
 {
+    if ( GetParent() )
+    {
+        wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
+        event.SetEventObject( GetParent() );
+        if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
+            return;
+    }
+
     // wxGTK sends us EVT_SET_FOCUS events even if we had never got
     // EVT_KILL_FOCUS before which means that we finish by redrawing the items
     // which are already drawn correctly resulting in horrible flicker - avoid
@@ -3332,19 +3306,18 @@ void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
 
         RefreshSelected();
     }
-
-    if ( !GetParent() )
-        return;
-
-    wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
-    event.SetEventObject( GetParent() );
-    GetParent()->GetEventHandler()->ProcessEvent( event );
 }
 
 void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
 {
+    if ( GetParent() )
+    {
+        wxFocusEvent event( wxEVT_KILL_FOCUS, GetParent()->GetId() );
+        event.SetEventObject( GetParent() );
+        if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
+            return;
+    }
     m_hasFocus = FALSE;
-
     RefreshSelected();
 }
 
@@ -3362,7 +3335,7 @@ void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y )
     {
         m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
     }
-    else if ( HasFlag(wxLC_REPORT) && (m_small_image_list))
+    else if ( InReportView() && (m_small_image_list))
     {
         m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
     }
@@ -3382,7 +3355,7 @@ void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const
     {
         m_small_image_list->GetSize( index, width, height );
     }
-    else if ( HasFlag(wxLC_REPORT) && m_small_image_list )
+    else if ( InReportView() && m_small_image_list )
     {
         m_small_image_list->GetSize( index, width, height );
     }
@@ -3479,7 +3452,7 @@ void wxListMainWindow::SetColumnWidth( int col, int width )
     wxCHECK_RET( col >= 0 && col < GetColumnCount(),
                  _T("invalid column index") );
 
-    wxCHECK_RET( HasFlag(wxLC_REPORT),
+    wxCHECK_RET( InReportView(),
                  _T("SetColumnWidth() can only be called in report mode.") );
 
     m_dirty = TRUE;
@@ -3800,11 +3773,16 @@ wxRect wxListMainWindow::GetViewRect() const
         }
     }
 
-#if 0
-    // account for the scrollbar
-    yMax += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
-    xMax += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
-#endif
+    // some fudge needed to make it look prettier
+    xMax += 2*EXTRA_BORDER_X;
+    yMax += 2*EXTRA_BORDER_Y;
+
+    // account for the scrollbars if necessary
+    const wxSize sizeAll = GetClientSize();
+    if ( xMax > sizeAll.x )
+        yMax += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
+    if ( yMax > sizeAll.y )
+        xMax += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
 
     return wxRect(0, 0, xMax, yMax);
 }
@@ -3846,6 +3824,8 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh)
     wxClientDC dc( this );
     dc.SetFont( GetFont() );
 
+    const size_t count = GetItemCount();
+
     int iconSpacing;
     if ( HasFlag(wxLC_ICON) )
         iconSpacing = m_normal_spacing;
@@ -3874,106 +3854,163 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh)
         clientHeight;
     GetSize( &clientWidth, &clientHeight );
 
-    if ( HasFlag(wxLC_REPORT) )
-    {
-        // all lines have the same height
-        int lineHeight = GetLineHeight();
+    const int lineHeight = GetLineHeight();
 
-        // scroll one line per step
-        m_yScroll = lineHeight;
-
-        size_t lineCount = GetItemCount();
-        int entireHeight = lineCount*lineHeight + LINE_SPACING;
+    if ( InReportView() )
+    {
+        // all lines have the same height and we scroll one line per step
+        int entireHeight = count*lineHeight + LINE_SPACING;
 
         m_linesPerPage = clientHeight / lineHeight;
 
         ResetVisibleLinesRange();
 
-        SetScrollbars( m_xScroll, m_yScroll,
-                       GetHeaderWidth() / m_xScroll,
-                       (entireHeight + m_yScroll - 1)/m_yScroll,
+        SetScrollbars( SCROLL_UNIT_X, lineHeight,
+                       GetHeaderWidth() / SCROLL_UNIT_X,
+                       (entireHeight + lineHeight - 1) / lineHeight,
                        GetScrollPos(wxHORIZONTAL),
                        GetScrollPos(wxVERTICAL),
                        TRUE );
     }
     else // !report
     {
-        // at first we try without any scrollbar. if the items don't
-        // fit into the window, we recalculate after subtracting an
-        // approximated 15 pt for the horizontal scrollbar
-
-        int entireWidth = 0;
-
-        for (int tries = 0; tries < 2; tries++)
+        // we have 3 different layout strategies: either layout all items
+        // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or
+        // to arrange them in top to bottom, left to right (don't ask me why
+        // not the other way round...) order
+        if ( HasFlag(wxLC_ALIGN_LEFT | wxLC_ALIGN_TOP) )
         {
-            // We start with 4 for the border around all items
-            entireWidth = 4;
-
-            if (tries == 1)
-            {
-                // Now we have decided that the items do not fit into the
-                // client area. Unfortunately, wxWindows sometimes thinks
-                // that it does fit and therefore NO horizontal scrollbar
-                // is inserted. This looks ugly, so we fudge here and make
-                // the calculated width bigger than was actually has been
-                // calculated. This ensures that wxScrolledWindows puts
-                // a scrollbar at the bottom of its client area.
-                entireWidth += SCROLL_UNIT_X;
-            }
+            int x = EXTRA_BORDER_X;
+            int y = EXTRA_BORDER_Y;
 
-            // Start at 2,2 so the text does not touch the border
-            int x = 2;
-            int y = 2;
-            int maxWidth = 0;
-            m_linesPerPage = 0;
-            int currentlyVisibleLines = 0;
+            wxCoord widthMax = 0;
 
-            size_t count = GetItemCount();
-            for (size_t i = 0; i < count; i++)
+            size_t i;
+            for ( i = 0; i < count; i++ )
             {
-                currentlyVisibleLines++;
                 wxListLineData *line = GetLine(i);
                 line->CalculateSize( &dc, iconSpacing );
-                line->SetPosition( x, y, clientWidth, iconSpacing );  // Why clientWidth? (FIXME)
+                line->SetPosition( x, y, iconSpacing );
 
                 wxSize sizeLine = GetLineSize(i);
 
-                if ( maxWidth < sizeLine.x )
-                    maxWidth = sizeLine.x;
+                if ( HasFlag(wxLC_ALIGN_TOP) )
+                {
+                    if ( sizeLine.x > widthMax )
+                        widthMax = sizeLine.x;
 
-                y += sizeLine.y;
-                if (currentlyVisibleLines > m_linesPerPage)
-                    m_linesPerPage = currentlyVisibleLines;
+                    y += sizeLine.y;
+                }
+                else // wxLC_ALIGN_LEFT
+                {
+                    x += sizeLine.x + MARGIN_BETWEEN_ROWS;
+                }
+            }
 
-                // Assume that the size of the next one is the same... (FIXME)
-                if ( y + sizeLine.y >= clientHeight )
+            if ( HasFlag(wxLC_ALIGN_TOP) )
+            {
+                // traverse the items again and tweak their sizes so that they are
+                // all the same in a row
+                for ( i = 0; i < count; i++ )
                 {
-                    currentlyVisibleLines = 0;
-                    y = 2;
-                    x += maxWidth+6;
-                    entireWidth += maxWidth+6;
-                    maxWidth = 0;
+                    wxListLineData *line = GetLine(i);
+                    line->m_gi->ExtendWidth(widthMax);
                 }
+            }
+
+
+            SetScrollbars
+            (
+                SCROLL_UNIT_X,
+                lineHeight,
+                (x + SCROLL_UNIT_X) / SCROLL_UNIT_X,
+                (y + lineHeight) / lineHeight,
+                GetScrollPos( wxHORIZONTAL ),
+                GetScrollPos( wxVERTICAL ),
+                TRUE
+            );
+        }
+        else // "flowed" arrangement, the most complicated case
+        {
+            // at first we try without any scrollbars, if the items don't fit into
+            // the window, we recalculate after subtracting the space taken by the
+            // scrollbar
 
-                // We have reached the last item.
-                if ( i == count - 1 )
-                    entireWidth += maxWidth;
+            int entireWidth = 0;
 
-                if ( (tries == 0) && (entireWidth+SCROLL_UNIT_X > clientWidth) )
+            for (int tries = 0; tries < 2; tries++)
+            {
+                entireWidth = 2*EXTRA_BORDER_X;
+
+                if (tries == 1)
                 {
-                    clientHeight -= 15; // We guess the scrollbar height. (FIXME)
-                    m_linesPerPage = 0;
-                    currentlyVisibleLines = 0;
-                    break;
+                    // Now we have decided that the items do not fit into the
+                    // client area, so we need a scrollbar
+                    entireWidth += SCROLL_UNIT_X;
                 }
 
-                if ( i == count - 1 )
-                    tries = 1;  // Everything fits, no second try required.
+                int x = EXTRA_BORDER_X;
+                int y = EXTRA_BORDER_Y;
+                int maxWidthInThisRow = 0;
+
+                m_linesPerPage = 0;
+                int currentlyVisibleLines = 0;
+
+                for (size_t i = 0; i < count; i++)
+                {
+                    currentlyVisibleLines++;
+                    wxListLineData *line = GetLine(i);
+                    line->CalculateSize( &dc, iconSpacing );
+                    line->SetPosition( x, y, iconSpacing );
+
+                    wxSize sizeLine = GetLineSize(i);
+
+                    if ( maxWidthInThisRow < sizeLine.x )
+                        maxWidthInThisRow = sizeLine.x;
+
+                    y += sizeLine.y;
+                    if (currentlyVisibleLines > m_linesPerPage)
+                        m_linesPerPage = currentlyVisibleLines;
+
+                    if ( y + sizeLine.y >= clientHeight )
+                    {
+                        currentlyVisibleLines = 0;
+                        y = EXTRA_BORDER_Y;
+                        maxWidthInThisRow += MARGIN_BETWEEN_ROWS;
+                        x += maxWidthInThisRow;
+                        entireWidth += maxWidthInThisRow;
+                        maxWidthInThisRow = 0;
+                    }
+
+                    // We have reached the last item.
+                    if ( i == count - 1 )
+                        entireWidth += maxWidthInThisRow;
+
+                    if ( (tries == 0) &&
+                            (entireWidth + SCROLL_UNIT_X > clientWidth) )
+                    {
+                        clientHeight -= wxSystemSettings::
+                                            GetMetric(wxSYS_HSCROLL_Y);
+                        m_linesPerPage = 0;
+                        break;
+                    }
+
+                    if ( i == count - 1 )
+                        tries = 1;  // Everything fits, no second try required.
+                }
             }
-        }
 
-        int scroll_pos = GetScrollPos( wxHORIZONTAL );
-        SetScrollbars( m_xScroll, m_yScroll, (entireWidth+SCROLL_UNIT_X) / m_xScroll, 0, scroll_pos, 0, TRUE );
+            SetScrollbars
+            (
+                SCROLL_UNIT_X,
+                lineHeight,
+                (entireWidth + SCROLL_UNIT_X) / SCROLL_UNIT_X,
+                0,
+                GetScrollPos( wxHORIZONTAL ),
+                0,
+                TRUE
+            );
+        }
     }
 
     if ( !noRefresh )
@@ -4230,7 +4267,7 @@ long wxListMainWindow::HitTest( int x, int y, int &flags )
 
     size_t count = GetItemCount();
 
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         size_t current = y / GetLineHeight();
         if ( current < count )
@@ -4271,18 +4308,39 @@ void wxListMainWindow::InsertItem( wxListItem &item )
 
     m_dirty = TRUE;
 
+    #if 0
+    // this is unused variable
     int mode = 0;
-    if ( HasFlag(wxLC_REPORT) )
+    #endif
+    if ( InReportView() )
     {
+        #if 0
+        // this is unused variable
         mode = wxLC_REPORT;
+        #endif
         ResetVisibleLinesRange();
     }
     else if ( HasFlag(wxLC_LIST) )
+        #if 0
+        // this is unused variable
         mode = wxLC_LIST;
+        #else
+        {}
+        #endif
     else if ( HasFlag(wxLC_ICON) )
+        #if 0
+        // this is unused variable
         mode = wxLC_ICON;
+        #else
+        {}
+        #endif
     else if ( HasFlag(wxLC_SMALL_ICON) )
+        #if 0
+        // this is unused variable
         mode = wxLC_ICON;  // no typo
+        #else
+        {}
+        #endif
     else
     {
         wxFAIL_MSG( _T("unknown mode") );
@@ -4296,6 +4354,14 @@ void wxListMainWindow::InsertItem( wxListItem &item )
 
     m_dirty = TRUE;
 
+    // If an item is selected at or below the point of insertion, we need to
+    // increment the member variables because the current row's index has gone
+    // up by one
+    if ( HasCurrent() && m_current >= id )
+    {
+        m_current++;
+    }
+
     SendNotify(id, wxEVT_COMMAND_LIST_INSERT_ITEM);
 
     RefreshLines(id, GetItemCount() - 1);
@@ -4304,7 +4370,7 @@ void wxListMainWindow::InsertItem( wxListItem &item )
 void wxListMainWindow::InsertColumn( long col, wxListItem &item )
 {
     m_dirty = TRUE;
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         if (item.m_width == wxLIST_AUTOSIZE_USEHEADER)
             item.m_width = GetTextLength( item.m_text );
@@ -4407,7 +4473,7 @@ int wxListMainWindow::GetCountPerPage() const
 
 void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to)
 {
-    wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("this is for report mode only") );
+    wxASSERT_MSG( InReportView(), _T("this is for report mode only") );
 
     if ( m_lineFrom == (size_t)-1 )
     {
@@ -4480,11 +4546,24 @@ wxGenericListCtrl::~wxGenericListCtrl()
 
 void wxGenericListCtrl::CalculateAndSetHeaderHeight()
 {
-    // we use the letter "H" for calculating the needed space, basing on the current font
-    int w, h;
-    m_headerWin->GetTextExtent(wxT("H"), &w, &h);
-    m_headerHeight = h + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
-    m_headerWin->SetSize(m_headerWin->GetSize().x, m_headerHeight);
+    if ( m_headerWin )
+    {
+        // we use 'g' to get the descent, too
+        int w, h, d;
+        m_headerWin->GetTextExtent(wxT("Hg"), &w, &h, &d);
+        h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
+
+        // only update if changed
+        if ( h != m_headerHeight )
+        {
+            m_headerHeight = h;
+
+            m_headerWin->SetSize(m_headerWin->GetSize().x, m_headerHeight);
+
+            if ( HasHeader() )
+                ResizeReportView(TRUE);
+        }
+    }
 }
 
 void wxGenericListCtrl::CreateHeaderWindow()
@@ -4517,6 +4596,8 @@ bool wxGenericListCtrl::Create(wxWindow *parent,
     m_mainWin = (wxListMainWindow*) NULL;
     m_headerWin = (wxListHeaderWindow*) NULL;
 
+    m_headerHeight = 0;
+
     if ( !(style & wxLC_MASK_TYPE) )
     {
         style = style | wxLC_LIST;
@@ -4530,7 +4611,7 @@ bool wxGenericListCtrl::Create(wxWindow *parent,
 
     m_mainWin = new wxListMainWindow( this, -1, wxPoint(0,0), size, style );
 
-    if ( HasFlag(wxLC_REPORT) )
+    if ( InReportView() )
     {
         CreateHeaderWindow();
 
@@ -4580,8 +4661,8 @@ void wxGenericListCtrl::SetWindowStyleFlag( long flag )
         m_mainWin->DeleteEverything();
 
         // has the header visibility changed?
-        bool hasHeader = HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER),
-             willHaveHeader = (flag & wxLC_REPORT) && !(flag & wxLC_NO_HEADER);
+        bool hasHeader = HasHeader();
+        bool willHaveHeader = (flag & wxLC_REPORT) && !(flag & wxLC_NO_HEADER);
 
         if ( hasHeader != willHaveHeader )
         {
@@ -5079,7 +5160,7 @@ void wxGenericListCtrl::ResizeReportView(bool showHeader)
 void wxGenericListCtrl::OnInternalIdle()
 {
     wxWindow::OnInternalIdle();
-    
+
     // do it only if needed
     if ( !m_mainWin->m_dirty )
         return;
@@ -5214,7 +5295,8 @@ int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item)) const
     return -1;
 }
 
-wxListItemAttr *wxGenericListCtrl::OnGetItemAttr(long item) const
+wxListItemAttr *
+wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const
 {
     wxASSERT_MSG( item >= 0 && item < GetItemCount(),
                   _T("invalid item index in OnGetItemAttr()") );