]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/listctrl.cpp
no real changes
[wxWidgets.git] / src / generic / listctrl.cpp
index b556a2e8eb27fe50c09d56080533cb22728ca228..8c05bafe0aa5ef9be010d4ed8ac374f536da4fe4 100644 (file)
 
 #if wxUSE_LISTCTRL
 
-#include "wx/dcscreen.h"
-#include "wx/app.h"
-#include "wx/listctrl.h"
+#ifndef WX_PRECOMP
+    #include "wx/app.h"
+
+    #include "wx/dynarray.h"
+
+    #include "wx/dcscreen.h"
+
+    #include "wx/textctrl.h"
+#endif
+
 #include "wx/imaglist.h"
-#include "wx/dynarray.h"
+#include "wx/listctrl.h"
 
 #ifdef __WXGTK__
-#include <gtk/gtk.h>
-#include "wx/gtk/win_gtk.h"
+    #include <gtk/gtk.h>
+    #include "wx/gtk/win_gtk.h"
 #endif
 
 // ----------------------------------------------------------------------------
@@ -72,6 +79,7 @@ DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG)
 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED)
 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
 
 // ----------------------------------------------------------------------------
@@ -611,7 +619,13 @@ public:
     // bring the current item into view
     void MoveToFocus() { MoveToItem(m_current); }
 
+    // start editing the label of the given item
     void EditLabel( long item );
+
+    // suspend/resume redrawing the control
+    void Freeze();
+    void Thaw();
+
     void OnRenameTimer();
     void OnRenameAccept();
 
@@ -678,7 +692,9 @@ public:
     bool IsEmpty() const { return GetItemCount() == 0; }
     void SetItemCount(long count);
 
-    void ResetCurrent() { m_current = (size_t)-1; }
+    // change the current (== focused) item, send a notification event
+    void ChangeCurrent(size_t current);
+    void ResetCurrent() { ChangeCurrent((size_t)-1); }
     bool HasCurrent() const { return m_current != (size_t)-1; }
 
     // send out a wxListEvent
@@ -821,12 +837,6 @@ private:
     // delete all items but don't refresh: called from dtor
     void DoDeleteAllItems();
 
-    // called when an item is [un]focuded, i.e. becomes [not] current
-    //
-    // currently unused
-    void OnFocusLine( size_t line );
-    void OnUnfocusLine( size_t line );
-
     // the height of one line using the current font
     wxCoord m_lineHeight;
 
@@ -843,6 +853,9 @@ private:
     wxBrush *m_highlightBrush,
             *m_highlightUnfocusedBrush;
 
+    // if this is > 0, the control is frozen and doesn't redraw itself
+    size_t m_freezeCount;
+
     DECLARE_DYNAMIC_CLASS(wxListMainWindow);
     DECLARE_EVENT_TABLE()
 };
@@ -1879,7 +1892,7 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
 
     int numColumns = m_owner->GetColumnCount();
     wxListItem item;
-    for (int i = 0; i < numColumns; i++)
+    for ( int i = 0; i < numColumns && x < w; i++ )
     {
         m_owner->GetColumn( i, item );
         int wCol = item.m_width;
@@ -1923,11 +1936,9 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
         dc.DrawText( item.GetText(),
                      x + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
 
-        if ( x > w - wCol + 5 )
-            break;
-
         x += wCol;
     }
+
     dc.EndDrawing();
 }
 
@@ -2044,6 +2055,14 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
                                     : 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 );
             }
@@ -2221,6 +2240,8 @@ void wxListMainWindow::Init()
     m_currentEdit =
     m_lineLastClicked =
     m_lineBeforeLastClicked = (size_t)-1;
+
+    m_freezeCount = 0;
 }
 
 void wxListMainWindow::InitScrolling()
@@ -2613,6 +2634,14 @@ 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);
@@ -2626,6 +2655,41 @@ 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()
+{
+    m_freezeCount++;
+}
+
+void wxListMainWindow::Thaw()
+{
+    wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen list control?") );
+
+    if ( !--m_freezeCount )
+    {
+        Refresh();
+    }
 }
 
 void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
@@ -2634,9 +2698,9 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
     // done (a Windows requirement).
     wxPaintDC dc( this );
 
-    if ( IsEmpty() )
+    if ( IsEmpty() || m_freezeCount )
     {
-        // empty control. nothing to draw
+        // nothing to draw or not the moment to draw it
         return;
     }
 
@@ -2805,21 +2869,22 @@ void wxListMainWindow::SendNotify( size_t line,
     // what we're trying to avoid
     if ( !IsVirtual() && (command != wxEVT_COMMAND_LIST_DELETE_ITEM) )
     {
-        GetLine(line)->GetItem( 0, le.m_item );
+        if ( line != (size_t)-1 )
+        {
+            GetLine(line)->GetItem( 0, le.m_item );
+        }
+        //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event
     }
     //else: there may be no more such item
 
     GetParent()->GetEventHandler()->ProcessEvent( le );
 }
 
-void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line) )
+void wxListMainWindow::ChangeCurrent(size_t current)
 {
-//  SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
-}
+    m_current = current;
 
-void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line) )
-{
-//  SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
+    SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED);
 }
 
 void wxListMainWindow::EditLabel( long item )
@@ -3026,7 +3091,8 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
         if ( IsSingleSel() || !(event.ControlDown() || event.ShiftDown()) )
         {
             HighlightAll( FALSE );
-            m_current = current;
+
+            ChangeCurrent(current);
 
             ReverseHighlight(m_current);
         }
@@ -3034,13 +3100,13 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
         {
             if (event.ControlDown())
             {
-                m_current = current;
+                ChangeCurrent(current);
 
                 ReverseHighlight(m_current);
             }
             else if (event.ShiftDown())
             {
-                m_current = current;
+                ChangeCurrent(current);
 
                 size_t lineFrom = oldCurrent,
                        lineTo = current;
@@ -3063,8 +3129,6 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
         if (m_current != oldCurrent)
         {
             RefreshLine( oldCurrent );
-            OnUnfocusLine( oldCurrent );
-            OnFocusLine( m_current );
         }
 
         // forceClick is only set if the previous click was on another item
@@ -3120,7 +3184,7 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
     // items anyhow
     if ( event.ShiftDown() && !IsSingleSel() )
     {
-        m_current = newCurrent;
+        ChangeCurrent(newCurrent);
 
         // select all the items between the old and the new one
         if ( oldCurrent > newCurrent )
@@ -3137,7 +3201,7 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
         if ( !event.ControlDown() )
             HighlightAll(FALSE);
 
-        m_current = newCurrent;
+        ChangeCurrent(newCurrent);
 
         HighlightLine( oldCurrent, FALSE );
         RefreshLine( oldCurrent );
@@ -3148,8 +3212,6 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
         }
     }
 
-    OnUnfocusLine( oldCurrent );
-    OnFocusLine( m_current );
     RefreshLine( m_current );
 
     MoveToFocus();
@@ -3208,7 +3270,8 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
         nevent.SetDirection( !event.ShiftDown() );
         nevent.SetEventObject( GetParent()->GetParent() );
         nevent.SetCurrentFocus( m_parent );
-        if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) return;
+        if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
+            return;
     }
 
     /* no item -> nothing to do */
@@ -3308,12 +3371,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
         case WXK_SPACE:
             if ( IsSingleSel() )
             {
-                wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
-                                GetParent()->GetId() );
-                le.SetEventObject( GetParent() );
-                le.m_itemIndex = m_current;
-                GetLine(m_current)->GetItem( 0, le.m_item );
-                GetParent()->GetEventHandler()->ProcessEvent( le );
+                SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
 
                 if ( IsHighlighted(m_current) )
                 {
@@ -3328,14 +3386,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
 
         case WXK_RETURN:
         case WXK_EXECUTE:
-            {
-                wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
-                                GetParent()->GetId() );
-                le.SetEventObject( GetParent() );
-                le.m_itemIndex = m_current;
-                GetLine(m_current)->GetItem( 0, le.m_item );
-                GetParent()->GetEventHandler()->ProcessEvent( le );
-            }
+            SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
             break;
 
         default:
@@ -3353,12 +3404,19 @@ extern wxWindow *g_focusWindow;
 
 void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
 {
-    m_hasFocus = TRUE;
+    // 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
+    // it
+    if ( !m_hasFocus )
+    {
+        m_hasFocus = TRUE;
 
-    if (!GetParent())
-        return;
+        RefreshSelected();
+    }
 
-    RefreshSelected();
+    if ( !GetParent() )
+        return;
 
 #ifdef __WXGTK__
     g_focusWindow = GetParent();
@@ -3655,9 +3713,7 @@ void wxListMainWindow::SetItemState( long litem, long state, long stateMask )
             // don't do anything if this item is already focused
             if ( item != m_current )
             {
-                OnUnfocusLine( m_current );
-                m_current = item;
-                OnFocusLine( m_current );
+                ChangeCurrent(item);
 
                 if ( oldCurrent != (size_t)-1 )
                 {
@@ -3677,8 +3733,7 @@ void wxListMainWindow::SetItemState( long litem, long state, long stateMask )
             // don't do anything if this item is not focused
             if ( item == m_current )
             {
-                OnUnfocusLine( m_current );
-                m_current = (size_t)-1;
+                ResetCurrent();
 
                 RefreshLine( oldCurrent );
             }
@@ -3698,9 +3753,7 @@ void wxListMainWindow::SetItemState( long litem, long state, long stateMask )
                 // single sel mode
                 if ( m_current != item )
                 {
-                    OnUnfocusLine( m_current );
-                    m_current = item;
-                    OnFocusLine( m_current );
+                    ChangeCurrent(item);
 
                     if ( oldCurrent != (size_t)-1 )
                     {
@@ -3957,12 +4010,7 @@ void wxListMainWindow::UpdateCurrent()
 {
     if ( !HasCurrent() && !IsEmpty() )
     {
-        m_current = 0;
-    }
-
-    if ( m_current != (size_t)-1 )
-    {
-        OnFocusLine( m_current );
+        ChangeCurrent(0);
     }
 }
 
@@ -4402,53 +4450,6 @@ void wxListItem::ClearAttributes()
     }
 }
 
-// -------------------------------------------------------------------------------------
-// wxListEvent
-// -------------------------------------------------------------------------------------
-
-IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
-
-wxListEvent::wxListEvent( wxEventType commandType, int id )
-           : wxNotifyEvent( commandType, id )
-{
-    m_code = 0;
-    m_itemIndex = 0;
-    m_oldItemIndex = 0;
-    m_col = 0;
-    m_cancelled = FALSE;
-    m_pointDrag.x = 0;
-    m_pointDrag.y = 0;
-}
-
-void wxListEvent::CopyObject(wxObject& object_dest) const
-{
-    wxListEvent *obj = (wxListEvent *)&object_dest;
-
-    wxNotifyEvent::CopyObject(object_dest);
-
-    obj->m_code = m_code;
-    obj->m_itemIndex = m_itemIndex;
-    obj->m_oldItemIndex = m_oldItemIndex;
-    obj->m_col = m_col;
-    obj->m_cancelled = m_cancelled;
-    obj->m_pointDrag = m_pointDrag;
-    obj->m_item.m_mask = m_item.m_mask;
-    obj->m_item.m_itemId = m_item.m_itemId;
-    obj->m_item.m_col = m_item.m_col;
-    obj->m_item.m_state = m_item.m_state;
-    obj->m_item.m_stateMask = m_item.m_stateMask;
-    obj->m_item.m_text = m_item.m_text;
-    obj->m_item.m_image = m_item.m_image;
-    obj->m_item.m_data = m_item.m_data;
-    obj->m_item.m_format = m_item.m_format;
-    obj->m_item.m_width = m_item.m_width;
-
-    if ( m_item.HasAttributes() )
-    {
-        obj->m_item.SetTextColour(m_item.GetTextColour());
-    }
-}
-
 // -------------------------------------------------------------------------------------
 // wxListCtrl
 // -------------------------------------------------------------------------------------
@@ -4456,6 +4457,8 @@ void wxListEvent::CopyObject(wxObject& object_dest) const
 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
 IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
 
+IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
+
 BEGIN_EVENT_TABLE(wxListCtrl,wxControl)
   EVT_SIZE(wxListCtrl::OnSize)
   EVT_IDLE(wxListCtrl::OnIdle)
@@ -4477,9 +4480,6 @@ wxListCtrl::wxListCtrl()
 
 wxListCtrl::~wxListCtrl()
 {
-    if ( m_mainWin )
-        m_mainWin->ResetCurrent();
-
     if (m_ownsImageListNormal)
         delete m_imageListNormal;
     if (m_ownsImageListSmall)
@@ -4861,7 +4861,7 @@ bool wxListCtrl::DeleteAllColumns()
 {
     size_t count = m_mainWin->m_columns.GetCount();
     for ( size_t n = 0; n < count; n++ )
-        DeleteColumn(n);
+        DeleteColumn(0);
 
     return TRUE;
 }
@@ -5180,4 +5180,14 @@ void wxListCtrl::RefreshItems(long itemFrom, long itemTo)
     m_mainWin->RefreshLines(itemFrom, itemTo);
 }
 
+void wxListCtrl::Freeze()
+{
+    m_mainWin->Freeze();
+}
+
+void wxListCtrl::Thaw()
+{
+    m_mainWin->Thaw();
+}
+
 #endif // wxUSE_LISTCTRL