]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/listctrl.cpp
new makefile
[wxWidgets.git] / src / generic / listctrl.cpp
index 9f32c43da4a62f9874dc4951df0b30b68383a783..3b9727dd864989005a96761bddb5164fbf3146f9 100644 (file)
@@ -50,7 +50,7 @@
 #include "wx/imaglist.h"
 #include "wx/listctrl.h"
 
-#ifdef __WXGTK__
+#if defined(__WXGTK__)
     #include <gtk/gtk.h>
     #include "wx/gtk/win_gtk.h"
 #endif
@@ -124,7 +124,7 @@ static const int IMAGE_MARGIN_IN_REPORT_MODE = 5;
 
 int CMPFUNC_CONV wxSizeTCmpFn(size_t n1, size_t n2) { return n1 - n2; }
 
-WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray);
+WX_DEFINE_SORTED_EXPORTED_ARRAY_LONG(size_t, wxIndexArray);
 
 // this class is used to store the selected items in the virtual list control
 // (but it is not tied to list control and so can be used with other controls
@@ -435,7 +435,7 @@ protected:
     wxCursor          *m_resizeCursor;
     bool               m_isDragging;
 
-    // column being resized
+    // column being resized or -1
     int m_column;
 
     // divider line position in logical (unscrolled) coords
@@ -473,6 +473,8 @@ private:
     // common part of all ctors
     void Init();
 
+    void SendListEvent(wxEventType type, wxPoint pos);
+
     DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
     DECLARE_EVENT_TABLE()
 };
@@ -518,7 +520,7 @@ public:
     void OnKillFocus( wxFocusEvent &event );
 
 private:
-    DECLARE_DYNAMIC_CLASS(wxListTextCtrl);
+    DECLARE_DYNAMIC_CLASS(wxListTextCtrl)
     DECLARE_EVENT_TABLE()
 };
 
@@ -627,6 +629,8 @@ public:
     void Freeze();
     void Thaw();
 
+    void SetFocus();
+
     void OnRenameTimer();
     void OnRenameAccept();
 
@@ -827,7 +831,7 @@ protected:
 #ifdef __WXMAC__
         return *wxWHITE;
 #else
-        return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT);
+        return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
 #endif
     }
 
@@ -857,7 +861,7 @@ private:
     // if this is > 0, the control is frozen and doesn't redraw itself
     size_t m_freezeCount;
 
-    DECLARE_DYNAMIC_CLASS(wxListMainWindow);
+    DECLARE_DYNAMIC_CLASS(wxListMainWindow)
     DECLARE_EVENT_TABLE()
 };
 
@@ -1595,7 +1599,7 @@ bool wxListLineData::SetAttributes(wxDC *dc,
     wxColour colText;
     if ( highlighted )
     {
-        colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+        colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
     }
     else
     {
@@ -1749,7 +1753,7 @@ void wxListLineData::ReverseHighlight( void )
 //  wxListHeaderWindow
 //-----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow);
+IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow)
 
 BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow)
     EVT_PAINT         (wxListHeaderWindow::OnPaint)
@@ -1786,7 +1790,7 @@ wxListHeaderWindow::wxListHeaderWindow( wxWindow *win,
     m_owner = owner;
     m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
 
-    SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ) );
+    SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
 }
 
 wxListHeaderWindow::~wxListHeaderWindow()
@@ -1796,7 +1800,7 @@ wxListHeaderWindow::~wxListHeaderWindow()
 
 void wxListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
 {
-#ifdef __WXGTK__
+#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
     GtkStateType state = m_parent->IsEnabled() ? GTK_STATE_NORMAL
                                                : GTK_STATE_INSENSITIVE;
 
@@ -1804,14 +1808,15 @@ void wxListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
 
     gtk_paint_box (m_wxwindow->style, GTK_PIZZA(m_wxwindow)->bin_window,
                    state, GTK_SHADOW_OUT,
-                   (GdkRectangle*) NULL, m_wxwindow, "button",
+                   (GdkRectangle*) NULL, m_wxwindow,
+                   (char *)"button", // const_cast
                    x-1, y-1, w+2, h+2);
 #elif defined( __WXMAC__  )
     const int m_corner = 1;
 
     dc->SetBrush( *wxTRANSPARENT_BRUSH );
 
-    dc->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW ) , 1 , wxSOLID ) );
+    dc->SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW ) , 1 , wxSOLID ) );
     dc->DrawLine( x+w-m_corner+1, y, x+w, y+h );  // right (outer)
     dc->DrawRectangle( x, y+h, w+1, 1 );          // bottom (outer)
 
@@ -1835,7 +1840,7 @@ void wxListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
     dc->DrawLine( x+w-m_corner+1, y, x+w, y+h );  // right (outer)
     dc->DrawRectangle( x, y+h, w+1, 1 );          // bottom (outer)
 
-    wxPen pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID );
+    wxPen pen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID );
 
     dc->SetPen( pen );
     dc->DrawLine( x+w-m_corner, y, x+w-1, y+h );  // right (inner)
@@ -1865,7 +1870,7 @@ void wxListHeaderWindow::AdjustDC(wxDC& dc)
 
 void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
 {
-#ifdef __WXGTK__
+#if defined(__WXGTK__)
     wxClientDC dc( this );
 #else
     wxPaintDC dc( this );
@@ -1949,9 +1954,9 @@ void wxListHeaderWindow::DrawCurrent()
 {
     int x1 = m_currentX;
     int y1 = 0;
-    ClientToScreen( &x1, &y1 );
+    m_owner->ClientToScreen( &x1, &y1 );
 
-    int x2 = m_currentX-1;
+    int x2 = m_currentX;
     int y2 = 0;
     m_owner->GetClientSize( NULL, &y2 );
     m_owner->ClientToScreen( &x2, &y2 );
@@ -1980,6 +1985,9 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
 
     if (m_isDragging)
     {
+        SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING,
+                      event.GetPosition());
+
         // we don't draw the line beyond our window, but we allow dragging it
         // there
         int w = 0;
@@ -1997,6 +2005,8 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
             m_isDragging = FALSE;
             m_dirty = TRUE;
             m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
+            SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG,
+                          event.GetPosition());
         }
         else
         {
@@ -2019,8 +2029,9 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
         int xpos = 0;
 
         // find the column where this event occured
-        int countCol = m_owner->GetColumnCount();
-        for (int col = 0; col < countCol; col++)
+        int col,
+            countCol = m_owner->GetColumnCount();
+        for (col = 0; col < countCol; col++)
         {
             xpos += m_owner->GetColumnWidth( col );
             m_column = col;
@@ -2041,6 +2052,9 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
             m_minX = xpos;
         }
 
+        if ( col == countCol )
+            m_column = -1;
+
         if (event.LeftDown() || event.RightUp())
         {
             if (hit_border && event.LeftDown())
@@ -2049,25 +2063,15 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
                 m_currentX = x;
                 DrawCurrent();
                 CaptureMouse();
+                SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG,
+                              event.GetPosition());
             }
             else // click on a column
             {
-                wxWindow *parent = GetParent();
-                wxListEvent le( event.LeftDown()
+                SendListEvent( event.LeftDown()
                                     ? wxEVT_COMMAND_LIST_COL_CLICK
                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK,
-                                parent->GetId() );
-                le.SetEventObject( parent );
-                le.m_pointDrag = event.GetPosition();
-
-                // the position should be relative to the parent window, not
-                // this one for compatibility with MSW and common sense: the
-                // user code doesn't know anything at all about this header
-                // window, so why should it get positions relative to it?
-                le.m_pointDrag.y -= GetSize().y;
-
-                le.m_col = m_column;
-                parent->GetEventHandler()->ProcessEvent( le );
+                                event.GetPosition());
             }
         }
         else if (event.Moving())
@@ -2095,6 +2099,23 @@ void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
     m_owner->SetFocus();
 }
 
+void wxListHeaderWindow::SendListEvent(wxEventType type, wxPoint pos)
+{
+    wxWindow *parent = GetParent();
+    wxListEvent le( type, parent->GetId() );
+    le.SetEventObject( parent );
+    le.m_pointDrag = pos;
+
+    // the position should be relative to the parent window, not
+    // this one for compatibility with MSW and common sense: the
+    // user code doesn't know anything at all about this header
+    // window, so why should it get positions relative to it?
+    le.m_pointDrag.y -= GetSize().y;
+
+    le.m_col = m_column;
+    parent->GetEventHandler()->ProcessEvent( le );
+}
+
 //-----------------------------------------------------------------------------
 // wxListRenameTimer (internal)
 //-----------------------------------------------------------------------------
@@ -2113,7 +2134,7 @@ void wxListRenameTimer::Notify()
 // wxListTextCtrl (internal)
 //-----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl,wxTextCtrl);
+IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl,wxTextCtrl)
 
 BEGIN_EVENT_TABLE(wxListTextCtrl,wxTextCtrl)
     EVT_CHAR           (wxListTextCtrl::OnChar)
@@ -2157,7 +2178,7 @@ void wxListTextCtrl::OnChar( wxKeyEvent &event )
             m_owner->OnRenameAccept();
 
         m_finished = TRUE;
-        m_owner->SetFocus(); // This doesn't work. TODO.
+        m_owner->SetFocus();
 
         return;
     }
@@ -2170,7 +2191,7 @@ void wxListTextCtrl::OnChar( wxKeyEvent &event )
             wxPendingDelete.Append(this);
 
         m_finished = TRUE;
-        m_owner->SetFocus(); // This doesn't work. TODO.
+        m_owner->SetFocus();
 
         return;
     }
@@ -2191,7 +2212,7 @@ void wxListTextCtrl::OnKeyUp( wxKeyEvent &event )
     wxPoint myPos = GetPosition();
     wxSize mySize = GetSize();
     int sx, sy;
-    GetTextExtent(GetValue() + _T("M"), &sx, &sy); // FIXME: MM??
+    GetTextExtent(GetValue() + _T("MM"), &sx, &sy);
     if (myPos.x + sx > parentSize.x)
         sx = parentSize.x - myPos.x;
     if (mySize.x > sx)
@@ -2214,7 +2235,7 @@ void wxListTextCtrl::OnKillFocus( wxFocusEvent &event )
 
     (*m_accept) = TRUE;
     (*m_res) = GetValue();
-    
+
     if ((*m_res) != m_startValue)
         m_owner->OnRenameAccept();
 }
@@ -2223,7 +2244,7 @@ void wxListTextCtrl::OnKillFocus( wxFocusEvent &event )
 //  wxListMainWindow
 //-----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow);
+IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow)
 
 BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow)
   EVT_PAINT          (wxListMainWindow::OnPaint)
@@ -2307,7 +2328,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent,
 
     m_highlightBrush = new wxBrush
                            (
-                            wxSystemSettings::GetSystemColour
+                            wxSystemSettings::GetColour
                             (
                                 wxSYS_COLOUR_HIGHLIGHT
                             ),
@@ -2316,7 +2337,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent,
 
     m_highlightUnfocusedBrush = new wxBrush
                                     (
-                                       wxSystemSettings::GetSystemColour
+                                       wxSystemSettings::GetColour
                                        (
                                            wxSYS_COLOUR_BTNSHADOW
                                        ),
@@ -2329,7 +2350,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent,
     InitScrolling();
     SetScrollbars( m_xScroll, m_yScroll, 0, 0, 0, 0 );
 
-    SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) );
+    SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX ) );
 }
 
 wxListMainWindow::~wxListMainWindow()
@@ -2471,7 +2492,10 @@ long wxListMainWindow::HitTestLine(size_t line, int x, int y) const
     if ( ld->HasImage() && GetLineIconRect(line).Inside(x, y) )
         return wxLIST_HITTEST_ONITEMICON;
 
-    if ( ld->HasText() )
+    // VS: Testing for "ld->HasText() || InReportView()" instead of
+    //     "ld->HasText()" is needed to make empty lines in report view
+    //     possible
+    if ( ld->HasText() || InReportView() )
     {
         wxRect rect = InReportView() ? GetLineRect(line)
                                      : GetLineLabelRect(line);
@@ -2659,14 +2683,6 @@ void wxListMainWindow::RefreshSelected()
         to = GetItemCount() - 1;
     }
 
-    // VZ: this code would work fine if wxGTK wxWindow::Refresh() were
-    //     reasonable, i.e. if it only generated one expose event for
-    //     several calls to it - as it is, each Refresh() results in a
-    //     repaint which provokes flicker too horrible to be seen
-    //
-    //     when/if wxGTK is fixed, this code should be restored as normally it
-    //     should generate _less_ flicker than the version below
-#ifndef __WXGTK__
     if ( HasCurrent() && m_current >= from && m_current <= to )
     {
         RefreshLine(m_current);
@@ -2680,26 +2696,6 @@ void wxListMainWindow::RefreshSelected()
             RefreshLine(line);
         }
     }
-#else // __WXGTK__
-    size_t selMin = (size_t)-1,
-           selMax = 0;
-
-    for ( size_t line = from; line <= to; line++ )
-    {
-        if ( IsHighlighted(line) || (line == m_current) )
-        {
-            if ( line < selMin )
-                selMin = line;
-            if ( line > selMax )
-                selMax = line;
-        }
-    }
-
-    if ( selMin != (size_t)-1 )
-    {
-        RefreshLines(selMin, selMax);
-    }
-#endif // !__WXGTK__/__WXGTK__
 }
 
 void wxListMainWindow::Freeze()
@@ -2935,14 +2931,10 @@ void wxListMainWindow::EditLabel( long item )
     if (m_dirty)
         wxSafeYield();
 
-    wxClientDC dc(this);
-    PrepareDC( dc );
-
     wxString s = data->GetText(0);
     wxRect rectLabel = GetLineLabelRect(m_currentEdit);
 
-    rectLabel.x = dc.LogicalToDeviceX( rectLabel.x );
-    rectLabel.y = dc.LogicalToDeviceY( rectLabel.y );
+    CalcScrolledPosition(rectLabel.x, rectLabel.y, &rectLabel.x, &rectLabel.y);
 
     wxListTextCtrl *text = new wxListTextCtrl
                                (
@@ -3073,7 +3065,15 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
         m_renameTimer->Stop();
         m_lastOnSame = FALSE;
 
+#ifdef __WXGTK__
+        // FIXME: wxGTK generates bad sequence of events prior to doubleclick
+        //        ("down, up, down, double, up" while other ports
+        //        do "down, up, double, up"). We have to have this hack
+        //        in place till somebody fixes wxGTK...
         if ( current == m_lineBeforeLastClicked )
+#else
+        if ( current == m_lineLastClicked )
+#endif
         {
             SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
 
@@ -3423,9 +3423,25 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
 // focus handling
 // ----------------------------------------------------------------------------
 
-#ifdef __WXGTK__
-extern wxWindow *g_focusWindow;
-#endif
+void wxListMainWindow::SetFocus()
+{
+    // VS: wxListMainWindow derives from wxPanel (via wxScrolledWindow) and wxPanel
+    //     overrides SetFocus in such way that it does never change focus from
+    //     panel's child to the panel itself. Unfortunately, we must be able to change
+    //     focus to the panel from wxListTextCtrl because the text control should
+    //     disappear when the user clicks outside it.
+
+    wxWindow *oldFocus = FindFocus();
+
+    if ( oldFocus && oldFocus->GetParent() == this )
+    {
+        wxWindow::SetFocus();
+    }
+    else
+    {
+        wxScrolledWindow::SetFocus();
+    }
+}
 
 void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
 {
@@ -3443,10 +3459,6 @@ void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
     if ( !GetParent() )
         return;
 
-#ifdef __WXGTK__
-    g_focusWindow = GetParent();
-#endif
-
     wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
     event.SetEventObject( GetParent() );
     GetParent()->GetEventHandler()->ProcessEvent( event );
@@ -3939,7 +3951,7 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh)
     int clientWidth,
         clientHeight;
     GetSize( &clientWidth, &clientHeight );
-    
+
     if ( HasFlag(wxLC_REPORT) )
     {
         // all lines have the same height
@@ -3974,7 +3986,7 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh)
         {
             // 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
@@ -3986,7 +3998,7 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh)
                 // a scrollbar at the bottom of its client area.
                 entireWidth += SCROLL_UNIT_X;
             }
-            
+
             // Start at 2,2 so the text does not touch the border
             int x = 2;
             int y = 2;
@@ -4020,11 +4032,11 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh)
                     entireWidth += maxWidth+6;
                     maxWidth = 0;
                 }
-                
+
                 // We have reached the last item.
                 if ( i == count - 1 )
                     entireWidth += maxWidth;
-                    
+
                 if ( (tries == 0) && (entireWidth+SCROLL_UNIT_X > clientWidth) )
                 {
                     clientHeight -= 15; // We guess the scrollbar height. (FIXME)
@@ -4032,7 +4044,7 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh)
                     currentlyVisibleLines = 0;
                     break;
                 }
-                
+
                 if ( i == count - 1 )
                     tries = 1;  // Everything fits, no second try required.
             }
@@ -4168,6 +4180,9 @@ void wxListMainWindow::DeleteColumn( int col )
 
     m_dirty = TRUE;
     m_columns.DeleteNode( node );
+
+    // invalidate it as it has to be recalculated
+    m_headerWidth = 0;
 }
 
 void wxListMainWindow::DoDeleteAllItems()
@@ -4362,6 +4377,9 @@ void wxListMainWindow::InsertColumn( long col, wxListItem &item )
         {
             m_columns.Append( column );
         }
+
+        // invalidate it as it has to be recalculated
+        m_headerWidth = 0;
     }
 }
 
@@ -4414,10 +4432,8 @@ void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
         wxListCtrl* lc = GetListCtrl();
         wxCHECK_RET( lc, _T("no listctrl window?") );
 
-        lc->m_headerWin->Refresh() ;
-#ifdef __WXMAC__
-        lc->m_headerWin->MacUpdateImmediately() ;
-#endif
+        lc->m_headerWin->Refresh();
+        lc->m_headerWin->Update();
     }
 }