X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0a816d95815bc4b77f860e88e8f12bf3e9adab10..db0ff83efbd6105c04d5ab84c85094e887e97b9a:/src/generic/listctrl.cpp?ds=inline diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index b556a2e8eb..3b9727dd86 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -37,15 +37,22 @@ #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 -#include "wx/gtk/win_gtk.h" +#if defined(__WXGTK__) + #include + #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) // ---------------------------------------------------------------------------- @@ -116,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 @@ -427,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 @@ -465,6 +473,8 @@ private: // common part of all ctors void Init(); + void SendListEvent(wxEventType type, wxPoint pos); + DECLARE_DYNAMIC_CLASS(wxListHeaderWindow) DECLARE_EVENT_TABLE() }; @@ -494,6 +504,7 @@ private: wxString *m_res; wxListMainWindow *m_owner; wxString m_startValue; + bool m_finished; public: wxListTextCtrl() {} @@ -509,7 +520,7 @@ public: void OnKillFocus( wxFocusEvent &event ); private: - DECLARE_DYNAMIC_CLASS(wxListTextCtrl); + DECLARE_DYNAMIC_CLASS(wxListTextCtrl) DECLARE_EVENT_TABLE() }; @@ -611,7 +622,15 @@ 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 SetFocus(); + void OnRenameTimer(); void OnRenameAccept(); @@ -678,7 +697,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 @@ -810,7 +831,7 @@ protected: #ifdef __WXMAC__ return *wxWHITE; #else - return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT); + return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); #endif } @@ -821,12 +842,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,7 +858,10 @@ private: wxBrush *m_highlightBrush, *m_highlightUnfocusedBrush; - DECLARE_DYNAMIC_CLASS(wxListMainWindow); + // if this is > 0, the control is frozen and doesn't redraw itself + size_t m_freezeCount; + + DECLARE_DYNAMIC_CLASS(wxListMainWindow) DECLARE_EVENT_TABLE() }; @@ -965,8 +983,10 @@ bool wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo, // stop counting (see comment below) itemsChanged = NULL; } - - itemsChanged->Add(m_itemsSel[i]); + else + { + itemsChanged->Add(m_itemsSel[i]); + } } m_itemsSel.RemoveAt(i); @@ -1579,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 { @@ -1733,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) @@ -1770,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() @@ -1780,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; @@ -1788,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) @@ -1819,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) @@ -1849,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 ); @@ -1879,7 +1900,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 +1944,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(); } @@ -1935,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 ); @@ -1966,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; @@ -1983,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 { @@ -2005,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; @@ -2027,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()) @@ -2035,17 +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_col = m_column; - parent->GetEventHandler()->ProcessEvent( le ); + event.GetPosition()); } } else if (event.Moving()) @@ -2073,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) //----------------------------------------------------------------------------- @@ -2091,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) @@ -2118,6 +2161,7 @@ wxListTextCtrl::wxListTextCtrl( wxWindow *parent, (*m_accept) = FALSE; (*m_res) = ""; m_startValue = value; + m_finished = FALSE; } void wxListTextCtrl::OnChar( wxKeyEvent &event ) @@ -2130,9 +2174,12 @@ void wxListTextCtrl::OnChar( wxKeyEvent &event ) if (!wxPendingDelete.Member(this)) wxPendingDelete.Append(this); - if ((*m_accept) && ((*m_res) != m_startValue)) + if ((*m_res) != m_startValue) m_owner->OnRenameAccept(); + m_finished = TRUE; + m_owner->SetFocus(); + return; } if (event.m_keyCode == WXK_ESCAPE) @@ -2143,6 +2190,9 @@ void wxListTextCtrl::OnChar( wxKeyEvent &event ) if (!wxPendingDelete.Member(this)) wxPendingDelete.Append(this); + m_finished = TRUE; + m_owner->SetFocus(); + return; } @@ -2151,12 +2201,18 @@ void wxListTextCtrl::OnChar( wxKeyEvent &event ) void wxListTextCtrl::OnKeyUp( wxKeyEvent &event ) { + if (m_finished) + { + event.Skip(); + return; + } + // auto-grow the textctrl: wxSize parentSize = m_owner->GetSize(); wxPoint myPos = GetPosition(); wxSize mySize = GetSize(); int sx, sy; - GetTextExtent(GetValue() + _T("MM"), &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) @@ -2166,12 +2222,21 @@ void wxListTextCtrl::OnKeyUp( wxKeyEvent &event ) event.Skip(); } -void wxListTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) +void wxListTextCtrl::OnKillFocus( wxFocusEvent &event ) { + if (m_finished) + { + event.Skip(); + return; + } + if (!wxPendingDelete.Member(this)) wxPendingDelete.Append(this); - if ((*m_accept) && ((*m_res) != m_startValue)) + (*m_accept) = TRUE; + (*m_res) = GetValue(); + + if ((*m_res) != m_startValue) m_owner->OnRenameAccept(); } @@ -2179,7 +2244,7 @@ void wxListTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) // wxListMainWindow //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow); +IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow) BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow) EVT_PAINT (wxListMainWindow::OnPaint) @@ -2221,6 +2286,8 @@ void wxListMainWindow::Init() m_currentEdit = m_lineLastClicked = m_lineBeforeLastClicked = (size_t)-1; + + m_freezeCount = 0; } void wxListMainWindow::InitScrolling() @@ -2261,7 +2328,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent, m_highlightBrush = new wxBrush ( - wxSystemSettings::GetSystemColour + wxSystemSettings::GetColour ( wxSYS_COLOUR_HIGHLIGHT ), @@ -2270,7 +2337,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent, m_highlightUnfocusedBrush = new wxBrush ( - wxSystemSettings::GetSystemColour + wxSystemSettings::GetColour ( wxSYS_COLOUR_BTNSHADOW ), @@ -2283,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() @@ -2425,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); @@ -2628,15 +2698,30 @@ void wxListMainWindow::RefreshSelected() } } +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) ) { // Note: a wxPaintDC must be constructed even if no drawing is // 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 +2890,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 ) @@ -2845,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 ( @@ -2983,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 ); @@ -3026,7 +3116,8 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) if ( IsSingleSel() || !(event.ControlDown() || event.ShiftDown()) ) { HighlightAll( FALSE ); - m_current = current; + + ChangeCurrent(current); ReverseHighlight(m_current); } @@ -3034,13 +3125,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 +3154,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 +3209,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 +3226,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 +3237,6 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event) } } - OnUnfocusLine( oldCurrent ); - OnFocusLine( m_current ); RefreshLine( m_current ); MoveToFocus(); @@ -3208,7 +3295,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 +3396,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 +3411,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: @@ -3347,22 +3423,41 @@ 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) ) { - m_hasFocus = TRUE; - - if (!GetParent()) - 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 + // it + if ( !m_hasFocus ) + { + m_hasFocus = TRUE; - RefreshSelected(); + RefreshSelected(); + } -#ifdef __WXGTK__ - g_focusWindow = GetParent(); -#endif + if ( !GetParent() ) + return; wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() ); event.SetEventObject( GetParent() ); @@ -3655,9 +3750,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 +3770,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 +3790,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 ) { @@ -3842,9 +3932,25 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) else iconSpacing = 0; + // Note that we do not call GetClientSize() here but + // GetSize() and substract the border size for sunken + // borders manually. This is technically incorrect, + // but we need to know the client area's size WITHOUT + // scrollbars here. Since we don't know if there are + // any scrollbars, we use GetSize() instead. Another + // solution would be to call SetScrollbars() here to + // remove the scrollbars and call GetClientSize() then, + // but this might result in flicker and - worse - will + // reset the scrollbars to 0 which is not good at all + // if you resize a dialog/window, but don't want to + // reset the window scrolling. RR. + // Furthermore, we actually do NOT subtract the border + // width as 2 pixels is just the extra space which we + // need around the actual content in the window. Other- + // wise the text would e.g. touch the upper border. RR. int clientWidth, clientHeight; - GetClientSize( &clientWidth, &clientHeight ); + GetSize( &clientWidth, &clientHeight ); if ( HasFlag(wxLC_REPORT) ) { @@ -3874,13 +3980,26 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) // fit into the window, we recalculate after subtracting an // approximated 15 pt for the horizontal scrollbar - clientHeight -= 4; // sunken frame - int entireWidth = 0; for (int tries = 0; tries < 2; tries++) { - entireWidth = 0; + // 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; + } + + // Start at 2,2 so the text does not touch the border int x = 2; int y = 2; int maxWidth = 0; @@ -3893,7 +4012,7 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) currentlyVisibleLines++; wxListLineData *line = GetLine(i); line->CalculateSize( &dc, iconSpacing ); - line->SetPosition( x, y, clientWidth, iconSpacing ); + line->SetPosition( x, y, clientWidth, iconSpacing ); // Why clientWidth? (FIXME) wxSize sizeLine = GetLineSize(i); @@ -3904,8 +4023,8 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) if (currentlyVisibleLines > m_linesPerPage) m_linesPerPage = currentlyVisibleLines; - // assume that the size of the next one is the same... (FIXME) - if ( y + sizeLine.y - 6 >= clientHeight ) + // Assume that the size of the next one is the same... (FIXME) + if ( y + sizeLine.y >= clientHeight ) { currentlyVisibleLines = 0; y = 2; @@ -3913,17 +4032,21 @@ 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 > clientWidth)) + + if ( (tries == 0) && (entireWidth+SCROLL_UNIT_X > clientWidth) ) { - clientHeight -= 15; // scrollbar height + clientHeight -= 15; // We guess the scrollbar height. (FIXME) m_linesPerPage = 0; currentlyVisibleLines = 0; break; } + if ( i == count - 1 ) - tries = 1; // everything fits, no second try required + tries = 1; // Everything fits, no second try required. } } @@ -3957,12 +4080,7 @@ void wxListMainWindow::UpdateCurrent() { if ( !HasCurrent() && !IsEmpty() ) { - m_current = 0; - } - - if ( m_current != (size_t)-1 ) - { - OnFocusLine( m_current ); + ChangeCurrent(0); } } @@ -4062,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() @@ -4256,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; } } @@ -4308,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(); } } @@ -4402,53 +4524,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 +4531,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 +4554,6 @@ wxListCtrl::wxListCtrl() wxListCtrl::~wxListCtrl() { - if ( m_mainWin ) - m_mainWin->ResetCurrent(); - if (m_ownsImageListNormal) delete m_imageListNormal; if (m_ownsImageListSmall) @@ -4861,7 +4935,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 +5254,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