X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4d0c23087a957d9535030e7b327049c717cd8bf1..7d6a4d96961eac84d05db8bb24c64d39003f6e54:/src/generic/listctrl.cpp diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 8ad024386e..de34935ced 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -342,12 +342,23 @@ bool wxListHeaderData::IsHit( int x, int y ) const void wxListHeaderData::GetItem( wxListItem& item ) { - item.m_mask = m_mask; - item.m_text = m_text; - item.m_image = m_image; - item.m_format = m_format; - item.m_width = m_width; - item.m_state = m_state; + long mask = item.m_mask; + if ( !mask ) + { + // by default, get everything for backwards compatibility + mask = -1; + } + + if ( mask & wxLIST_MASK_STATE ) + item.m_state = m_state; + if ( mask & wxLIST_MASK_TEXT ) + item.m_text = m_text; + if ( mask & wxLIST_MASK_IMAGE ) + item.m_image = m_image; + if ( mask & wxLIST_MASK_WIDTH ) + item.m_width = m_width; + if ( mask & wxLIST_MASK_FORMAT ) + item.m_format = m_format; } int wxListHeaderData::GetImage() const @@ -923,7 +934,6 @@ void wxListLineData::ReverseHighlight( void ) BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow) EVT_PAINT (wxListHeaderWindow::OnPaint) EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse) - EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus) END_EVENT_TABLE() void wxListHeaderWindow::Init() @@ -1330,12 +1340,6 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) } } -void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) -{ - m_owner->SetFocus(); - m_owner->Update(); -} - bool wxListHeaderWindow::SendListEvent(wxEventType type, const wxPoint& pos) { wxWindow *parent = GetParent(); @@ -1578,10 +1582,9 @@ wxListMainWindow::wxListMainWindow() wxListMainWindow::wxListMainWindow( wxWindow *parent, wxWindowID id, const wxPoint& pos, - const wxSize& size, - long style, - const wxString &name ) - : wxWindow( parent, id, pos, size, style, name ) + const wxSize& size ) + : wxWindow( parent, id, pos, size, + wxWANTS_CHARS | wxBORDER_NONE ) { Init(); @@ -2032,6 +2035,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) GetParent()->GetId()); evCache.SetEventObject( GetParent() ); evCache.m_oldItemIndex = visibleFrom; + evCache.m_item.m_itemId = evCache.m_itemIndex = visibleTo; GetParent()->GetEventHandler()->ProcessEvent( evCache ); } @@ -2162,6 +2166,7 @@ void wxListMainWindow::SendNotify( size_t line, wxListEvent le( command, GetParent()->GetId() ); le.SetEventObject( GetParent() ); + le.m_item.m_itemId = le.m_itemIndex = line; // set only for events which have position @@ -2202,13 +2207,14 @@ wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass wxCHECK_MSG( (item >= 0) && ((size_t)item < GetItemCount()), NULL, wxT("wrong index in wxGenericListCtrl::EditLabel()") ); - wxASSERT_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)), + wxASSERT_MSG( textControlClass->IsKindOf(wxCLASSINFO(wxTextCtrl)), wxT("EditLabel() needs a text control") ); size_t itemEdit = (size_t)item; wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() ); le.SetEventObject( GetParent() ); + le.m_item.m_itemId = le.m_itemIndex = item; wxListLineData *data = GetLine(itemEdit); wxCHECK_MSG( data, NULL, wxT("invalid index in EditLabel()") ); @@ -2251,6 +2257,7 @@ bool wxListMainWindow::OnRenameAccept(size_t itemEdit, const wxString& value) { wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() ); le.SetEventObject( GetParent() ); + le.m_item.m_itemId = le.m_itemIndex = itemEdit; wxListLineData *data = GetLine(itemEdit); @@ -2271,6 +2278,7 @@ void wxListMainWindow::OnRenameCancelled(size_t itemEdit) le.SetEditCanceled(true); le.SetEventObject( GetParent() ); + le.m_item.m_itemId = le.m_itemIndex = itemEdit; wxListLineData *data = GetLine(itemEdit); @@ -2355,37 +2363,19 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) } } + // Update drag events counter first as we must do it even if the mouse is + // not on any item right now as we must keep count in case we started + // dragging from the empty control area but continued to do it over a valid + // item -- in this situation we must not start dragging this item. if (event.Dragging()) - { - if (m_dragCount == 0) - { - // we have to report the raw, physical coords as we want to be - // able to call HitTest(event.m_pointDrag) from the user code to - // get the item being dragged - m_dragStart = event.GetPosition(); - } - m_dragCount++; - - if (m_dragCount != 3) - return; - - int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG - : wxEVT_COMMAND_LIST_BEGIN_DRAG; - - wxListEvent le( command, GetParent()->GetId() ); - le.SetEventObject( GetParent() ); - le.m_itemIndex = m_lineLastClicked; - le.m_pointDrag = m_dragStart; - GetParent()->GetEventHandler()->ProcessEvent( le ); - - return; - } else - { m_dragCount = 0; - } + // The only mouse event that can be generated without any valid item is + // wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK as it can be useful to have a global + // popup menu for the list control itself which should be shown even when + // the user clicks outside of any item. if ( !hitResult ) { // outside of any item @@ -2409,6 +2399,27 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) return; } + if ( event.Dragging() ) + { + if (m_dragCount == 1) + { + // we have to report the raw, physical coords as we want to be + // able to call HitTest(event.m_pointDrag) from the user code to + // get the item being dragged + m_dragStart = event.GetPosition(); + } + + if (m_dragCount != 3) + return; + + int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG + : wxEVT_COMMAND_LIST_BEGIN_DRAG; + + SendNotify( m_lineLastClicked, command, m_dragStart ); + + return; + } + bool forceClick = false; if (event.ButtonDClick()) { @@ -2699,6 +2710,7 @@ void wxListMainWindow::OnKeyDown( wxKeyEvent &event ) // send a list event wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, parent->GetId() ); + le.m_item.m_itemId = le.m_itemIndex = m_current; if (HasCurrent()) GetLine(m_current)->GetItem( 0, le.m_item ); @@ -2957,17 +2969,6 @@ void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const } } -int wxListMainWindow::GetTextLength( const wxString &s ) const -{ - wxClientDC dc( wxConstCast(this, wxListMainWindow) ); - dc.SetFont( GetFont() ); - - wxCoord lw; - dc.GetTextExtent( s, &lw, NULL ); - - return lw + AUTOSIZE_COL_MARGIN; -} - void wxListMainWindow::SetImageList( wxImageList *imageList, int which ) { m_dirty = true; @@ -3010,18 +3011,42 @@ int wxListMainWindow::GetItemSpacing( bool isSmall ) // columns // ---------------------------------------------------------------------------- -void wxListMainWindow::SetColumn( int col, wxListItem &item ) +int +wxListMainWindow::ComputeMinHeaderWidth(const wxListHeaderData* column) const +{ + wxClientDC dc(const_cast(this)); + + int width = dc.GetTextExtent(column->GetText()).x + AUTOSIZE_COL_MARGIN; + + width += 2*EXTRA_WIDTH; + + // check for column header's image availability + const int image = column->GetImage(); + if ( image != -1 ) + { + if ( m_small_image_list ) + { + int ix = 0, iy = 0; + m_small_image_list->GetSize(image, ix, iy); + width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE; + } + } + + return width; +} + +void wxListMainWindow::SetColumn( int col, const wxListItem &item ) { wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); wxCHECK_RET( node, wxT("invalid column index in SetColumn") ); - if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER ) - item.m_width = GetTextLength( item.m_text ); - wxListHeaderData *column = node->GetData(); column->SetItem( item ); + if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER ) + column->SetWidth(ComputeMinHeaderWidth(column)); + wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; if ( headerWin ) headerWin->m_dirty = true; @@ -3055,29 +3080,13 @@ void wxListMainWindow::SetColumnWidth( int col, int width ) if (width == wxLIST_AUTOSIZE_USEHEADER) { - width = GetTextLength(column->GetText()); - width += 2*EXTRA_WIDTH; - - // check for column header's image availability - const int image = column->GetImage(); - if ( image != -1 ) - { - if ( m_small_image_list ) - { - int ix = 0, iy = 0; - m_small_image_list->GetSize(image, ix, iy); - width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE; - } - } + width = ComputeMinHeaderWidth(column); } else if ( width == wxLIST_AUTOSIZE ) { - if ( IsVirtual() ) - { - // TODO: determine the max width somehow... - width = WIDTH_COL_DEFAULT; - } - else // !virtual + width = ComputeMinHeaderWidth(column); + + if ( !IsVirtual() ) { wxClientDC dc(this); dc.SetFont( GetFont() ); @@ -3107,8 +3116,9 @@ void wxListMainWindow::SetColumnWidth( int col, int width ) m_aColWidths.Item(col)->nMaxWidth = max; } - max = m_aColWidths.Item(col)->nMaxWidth; - width = max + AUTOSIZE_COL_MARGIN; + max = m_aColWidths.Item(col)->nMaxWidth + AUTOSIZE_COL_MARGIN; + if ( width < max ) + width = max; } } @@ -3181,10 +3191,14 @@ void wxListMainWindow::SetItem( wxListItem &item ) } } - // update the item on screen - wxRect rectItem; - GetItemRect(id, rectItem); - RefreshRect(rectItem); + // update the item on screen unless we're going to update everything soon + // anyhow + if ( !m_dirty ) + { + wxRect rectItem; + GetItemRect(id, rectItem); + RefreshRect(rectItem); + } } void wxListMainWindow::SetItemStateAll(long state, long stateMask) @@ -3660,11 +3674,15 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) || i == count - 1) { // Adjust all items in this row to have the same - // width to ensure that they all align horizontally. - size_t firstRowLine = i - currentlyVisibleLines + 1; - for (size_t j = firstRowLine; j <= i; j++) + // width to ensure that they all align horizontally in + // icon view. + if ( HasFlag(wxLC_ICON) || HasFlag(wxLC_SMALL_ICON) ) { - GetLine(j)->m_gi->ExtendWidth(maxWidthInThisRow); + size_t firstRowLine = i - currentlyVisibleLines + 1; + for (size_t j = firstRowLine; j <= i; j++) + { + GetLine(j)->m_gi->ExtendWidth(maxWidthInThisRow); + } } currentlyVisibleLines = 0; @@ -3847,6 +3865,21 @@ void wxListMainWindow::DeleteColumn( int col ) for ( size_t i = 0; i < m_lines.GetCount(); i++ ) { wxListLineData * const line = GetLine(i); + + // In the following atypical but possible scenario it can be + // legal to call DeleteColumn() but the items may not have any + // values for it: + // 1. In report view, insert a second column. + // 2. Still in report view, add an item with 2 values. + // 3. Switch to an icon (or list) view. + // 4. Add an item -- necessarily with 1 value only. + // 5. Switch back to report view. + // 6. Call DeleteColumn(). + // So we need to check for this as otherwise we would simply crash + // if this happens. + if ( line->m_items.GetCount() <= static_cast(col) ) + continue; + wxListItemDataList::compatibility_iterator n = line->m_items.Item( col ); delete n->GetData(); line->m_items.Erase(n); @@ -4092,15 +4125,15 @@ void wxListMainWindow::InsertItem( wxListItem &item ) RefreshLines(id, GetItemCount() - 1); } -void wxListMainWindow::InsertColumn( long col, wxListItem &item ) +void wxListMainWindow::InsertColumn( long col, const wxListItem &item ) { m_dirty = true; if ( InReportView() ) { + wxListHeaderData *column = new wxListHeaderData( item ); if (item.m_width == wxLIST_AUTOSIZE_USEHEADER) - item.m_width = GetTextLength( item.m_text ); + column->SetWidth(ComputeMinHeaderWidth(column)); - wxListHeaderData *column = new wxListHeaderData( item ); wxColWidthInfo *colWidthInfo = new wxColWidthInfo(); bool insert = (col >= 0) && ((size_t)col < m_columns.GetCount()); @@ -4270,7 +4303,7 @@ void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to) IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl, wxControl) -BEGIN_EVENT_TABLE(wxGenericListCtrl,wxControl) +BEGIN_EVENT_TABLE(wxGenericListCtrl,wxListCtrlBase) EVT_SIZE(wxGenericListCtrl::OnSize) EVT_SCROLLWIN(wxGenericListCtrl::OnScroll) END_EVENT_TABLE() @@ -4350,15 +4383,12 @@ bool wxGenericListCtrl::Create(wxWindow *parent, wxASSERT_MSG( (style & wxLC_MASK_TYPE), wxT("wxListCtrl style should have exactly one mode bit set") ); - if ( !wxControl::Create( parent, id, pos, size, style|wxVSCROLL|wxHSCROLL, validator, name ) ) + if ( !wxListCtrlBase::Create( parent, id, pos, size, + style | wxVSCROLL | wxHSCROLL, + validator, name ) ) return false; -#ifdef __WXGTK__ - style &= ~wxBORDER_MASK; - style |= wxBORDER_THEME; -#endif - - m_mainWin = new wxListMainWindow( this, wxID_ANY, wxPoint(0, 0), size, style ); + m_mainWin = new wxListMainWindow(this, wxID_ANY, wxPoint(0, 0), size); SetTargetWindow( m_mainWin ); @@ -4388,7 +4418,7 @@ WXLRESULT wxGenericListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - WXLRESULT rc = wxControl::MSWWindowProc(nMsg, wParam, lParam); + WXLRESULT rc = wxListCtrlBase::MSWWindowProc(nMsg, wParam, lParam); // we need to process arrows ourselves for scrolling if ( nMsg == WM_GETDLGCODE ) @@ -4496,7 +4526,7 @@ bool wxGenericListCtrl::GetColumn(int col, wxListItem &item) const return true; } -bool wxGenericListCtrl::SetColumn( int col, wxListItem& item ) +bool wxGenericListCtrl::SetColumn( int col, const wxListItem& item ) { m_mainWin->SetColumn( col, item ); return true; @@ -4913,7 +4943,7 @@ long wxGenericListCtrl::InsertItem( long index, const wxString &label, int image return InsertItem( info ); } -long wxGenericListCtrl::InsertColumn( long col, wxListItem &item ) +long wxGenericListCtrl::DoInsertColumn( long col, const wxListItem &item ) { wxCHECK_MSG( InReportView(), -1, wxT("can't add column in non report mode") ); @@ -4927,23 +4957,6 @@ long wxGenericListCtrl::InsertColumn( long col, wxListItem &item ) return 0; } -long wxGenericListCtrl::InsertColumn( long col, const wxString &heading, - int format, int width ) -{ - wxListItem item; - item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT; - item.m_text = heading; - if (width >= -2) - { - item.m_mask |= wxLIST_MASK_WIDTH; - item.m_width = width; - } - - item.m_format = format; - - return InsertColumn( col, item ); -} - bool wxGenericListCtrl::ScrollList( int dx, int dy ) { return m_mainWin->ScrollList(dx, dy); @@ -5115,7 +5128,7 @@ void wxGenericListCtrl::DoClientToScreen( int *x, int *y ) const if ( m_mainWin ) m_mainWin->DoClientToScreen(x, y); else - wxControl::DoClientToScreen(x, y); + wxListCtrlBase::DoClientToScreen(x, y); } void wxGenericListCtrl::DoScreenToClient( int *x, int *y ) const @@ -5125,21 +5138,13 @@ void wxGenericListCtrl::DoScreenToClient( int *x, int *y ) const if ( m_mainWin ) m_mainWin->DoScreenToClient(x, y); else - wxControl::DoScreenToClient(x, y); -} - -void wxGenericListCtrl::SetFocus() -{ - // The test in window.cpp fails as we are a composite - // window, so it checks against "this", but not m_mainWin. - if ( DoFindFocus() != this ) - m_mainWin->SetFocus(); + wxListCtrlBase::DoScreenToClient(x, y); } wxSize wxGenericListCtrl::DoGetBestClientSize() const { - // Something is better than nothing even if this is completely arbitrary. - wxSize sizeBest(100, 80); + // The base class version can compute the best size in report view only. + wxSize sizeBest = wxListCtrlBase::DoGetBestClientSize(); if ( !InReportView() ) {