#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
// ----------------------------------------------------------------------------
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)
// ----------------------------------------------------------------------------
// 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();
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
// 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;
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()
};
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;
dc.DrawText( item.GetText(),
x + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
- if ( x > w - wCol + 5 )
- break;
-
x += wCol;
}
+
dc.EndDrawing();
}
m_currentEdit =
m_lineLastClicked =
m_lineBeforeLastClicked = (size_t)-1;
+
+ m_freezeCount = 0;
}
void wxListMainWindow::InitScrolling()
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);
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) )
// 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;
}
// 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 )
if ( IsSingleSel() || !(event.ControlDown() || event.ShiftDown()) )
{
HighlightAll( FALSE );
- m_current = current;
+
+ ChangeCurrent(current);
ReverseHighlight(m_current);
}
{
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;
if (m_current != oldCurrent)
{
RefreshLine( oldCurrent );
- OnUnfocusLine( oldCurrent );
- OnFocusLine( m_current );
}
// forceClick is only set if the previous click was on another item
// 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 )
if ( !event.ControlDown() )
HighlightAll(FALSE);
- m_current = newCurrent;
+ ChangeCurrent(newCurrent);
HighlightLine( oldCurrent, FALSE );
RefreshLine( oldCurrent );
}
}
- OnUnfocusLine( oldCurrent );
- OnFocusLine( m_current );
RefreshLine( m_current );
MoveToFocus();
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 */
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) )
{
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:
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();
// 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 )
{
// 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 );
}
// single sel mode
if ( m_current != item )
{
- OnUnfocusLine( m_current );
- m_current = item;
- OnFocusLine( m_current );
+ ChangeCurrent(item);
if ( oldCurrent != (size_t)-1 )
{
{
if ( !HasCurrent() && !IsEmpty() )
{
- m_current = 0;
- }
-
- if ( m_current != (size_t)-1 )
- {
- OnFocusLine( m_current );
+ ChangeCurrent(0);
}
}
}
}
-// -------------------------------------------------------------------------------------
-// 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
// -------------------------------------------------------------------------------------
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)
wxListCtrl::~wxListCtrl()
{
- if ( m_mainWin )
- m_mainWin->ResetCurrent();
-
if (m_ownsImageListNormal)
delete m_imageListNormal;
if (m_ownsImageListSmall)
{
size_t count = m_mainWin->m_columns.GetCount();
for ( size_t n = 0; n < count; n++ )
- DeleteColumn(n);
+ DeleteColumn(0);
return TRUE;
}
m_mainWin->RefreshLines(itemFrom, itemTo);
}
+void wxListCtrl::Freeze()
+{
+ m_mainWin->Freeze();
+}
+
+void wxListCtrl::Thaw()
+{
+ m_mainWin->Thaw();
+}
+
#endif // wxUSE_LISTCTRL