From 94248d2ed19bb207a49cf1a5bd9bfea0fd04760b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 7 Jan 2012 15:09:43 +0000 Subject: [PATCH] Implement best size calculation for report mode wxListCtrl. Use the column labels to determine the minimal width required by the control to show them all in full. Also declare all image list and column-related wxListCtrl methods in wxListCtrlBase now as we need some of them in DoGetBestClientSize() implementation. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@70282 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/generic/listctrl.h | 11 ++-- include/wx/generic/private/listctrl.h | 4 +- include/wx/listbase.h | 65 ++++++++++++++++++++++++ include/wx/msw/listctrl.h | 12 ++--- include/wx/osx/listctrl.h | 10 +--- src/common/listctrlcmn.cpp | 73 +++++++++++++++++++++++++++ src/generic/listctrl.cpp | 35 ++++--------- src/msw/listctrl.cpp | 20 +------- src/osx/carbon/listctrl_mac.cpp | 28 +--------- 10 files changed, 162 insertions(+), 97 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index d36572119a..7bf55bb1f9 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -465,6 +465,7 @@ All (GUI): - Allow using wxEVT_UPDATE_UI with wxRibbonButtonBar (Emilien Kia). - Add wxRibbonButtonBar::InsertXXXButton() methods (Emilien Kia). - Fix multiple item selection in generic wxTreeCtrl (Igor Korot). +- Implement best size calculation for report mode wxListCtrl. GTK: diff --git a/include/wx/generic/listctrl.h b/include/wx/generic/listctrl.h index 5b8de4c7c6..4117b7a9d1 100644 --- a/include/wx/generic/listctrl.h +++ b/include/wx/generic/listctrl.h @@ -14,8 +14,6 @@ #include "wx/scrolwin.h" #include "wx/textctrl.h" -class WXDLLIMPEXP_FWD_CORE wxImageList; - #if wxUSE_DRAG_AND_DROP class WXDLLIMPEXP_FWD_CORE wxDropTarget; #endif @@ -66,7 +64,7 @@ public: const wxString &name = wxListCtrlNameStr); bool GetColumn( int col, wxListItem& item ) const; - bool SetColumn( int col, wxListItem& item ); + bool SetColumn( int col, const wxListItem& item ); int GetColumnWidth( int col ) const; bool SetColumnWidth( int col, int width); int GetCountPerPage() const; // not the same in wxGLC as in Windows, I think @@ -134,9 +132,6 @@ public: long InsertItem( long index, const wxString& label ); long InsertItem( long index, int imageIndex ); long InsertItem( long index, const wxString& label, int imageIndex ); - long InsertColumn( long col, wxListItem& info ); - long InsertColumn( long col, const wxString& heading, - int format = wxLIST_FORMAT_LEFT, int width = -1 ); bool ScrollList( int dx, int dy ); bool SortItems( wxListCtrlCompare fn, wxIntPtr data ); @@ -208,6 +203,10 @@ public: wxListMainWindow *m_mainWin; protected: + // Implement base class pure virtual methods. + long DoInsertColumn(long col, const wxListItem& info); + + virtual bool DoPopupMenu( wxMenu *menu, int x, int y ); // take into account the coordinates difference between the container diff --git a/include/wx/generic/private/listctrl.h b/include/wx/generic/private/listctrl.h index 30dc76f736..66752660c6 100644 --- a/include/wx/generic/private/listctrl.h +++ b/include/wx/generic/private/listctrl.h @@ -581,7 +581,7 @@ public: void SetItemSpacing( int spacing, bool isSmall = false ); int GetItemSpacing( bool isSmall = false ); - void SetColumn( int col, wxListItem &item ); + void SetColumn( int col, const wxListItem &item ); void SetColumnWidth( int col, int width ); void GetColumn( int col, wxListItem &item ) const; int GetColumnWidth( int col ) const; @@ -645,7 +645,7 @@ public: long FindItem( const wxPoint& pt ); long HitTest( int x, int y, int &flags ) const; void InsertItem( wxListItem &item ); - void InsertColumn( long col, wxListItem &item ); + void InsertColumn( long col, const wxListItem &item ); int GetItemWidthWithImage(wxListItem * item); void SortItems( wxListCtrlCompare fn, wxIntPtr data ); diff --git a/include/wx/listbase.h b/include/wx/listbase.h index 55849b3c76..85450e236c 100644 --- a/include/wx/listbase.h +++ b/include/wx/listbase.h @@ -17,6 +17,8 @@ #include "wx/gdicmn.h" #include "wx/event.h" +class WXDLLIMPEXP_FWD_CORE wxImageList; + // ---------------------------------------------------------------------------- // types // ---------------------------------------------------------------------------- @@ -384,9 +386,72 @@ class WXDLLIMPEXP_CORE wxListCtrlBase : public wxControl public: wxListCtrlBase() { } + // Image list methods. + // ------------------- + + // Associate the given (possibly NULL to indicate that no images will be + // used) image list with the control. The ownership of the image list + // passes to the control, i.e. it will be deleted when the control itself + // is destroyed. + // + // The value of "which" must be one of wxIMAGE_LIST_{NORMAL,SMALL,STATE}. + virtual void AssignImageList(wxImageList* imageList, int which) = 0; + + // Same as AssignImageList() but the control does not delete the image list + // so it can be shared among several controls. + virtual void SetImageList(wxImageList* imageList, int which) = 0; + + // Return the currently used image list, may be NULL. + virtual wxImageList* GetImageList(int which) const = 0; + + + // Column-related methods. + // ----------------------- + + // All these methods can only be used in report view mode. + + // Add a new column to the control at the position "col". + // + // Returns the index of the newly inserted column or -1 on error. + long InsertColumn(long col, const wxListItem& info); + long InsertColumn(long col, + const wxString& heading, + int format = wxLIST_FORMAT_LEFT, + int width = -1); + + // Delete the given or all columns. + virtual bool DeleteColumn(int col) = 0; + virtual bool DeleteAllColumns() = 0; + + // Return the current number of columns. + virtual int GetColumnCount() const = 0; + + // Get or update information about the given column. Set item mask to + // indicate the fields to retrieve or change. + // + // Returns false on error, e.g. if the column index is invalid. + virtual bool GetColumn(int col, wxListItem& item) const = 0; + virtual bool SetColumn(int col, const wxListItem& item) = 0; + + // Convenient wrappers for the above methods which get or update just the + // column width. + virtual int GetColumnWidth(int col) const = 0; + virtual bool SetColumnWidth(int col, int width) = 0; + + + // Other miscellaneous accessors. + // ------------------------------ + // Convenient functions for testing the list control mode: bool InReportView() const { return HasFlag(wxLC_REPORT); } bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); } + +protected: + // Real implementations methods to which our public forwards. + virtual long DoInsertColumn(long col, const wxListItem& info) = 0; + + // Overridden methods of the base class. + virtual wxSize DoGetBestClientSize() const; }; // ---------------------------------------------------------------------------- diff --git a/include/wx/msw/listctrl.h b/include/wx/msw/listctrl.h index c4cb6597ac..75c30270be 100644 --- a/include/wx/msw/listctrl.h +++ b/include/wx/msw/listctrl.h @@ -16,7 +16,6 @@ #include "wx/dynarray.h" #include "wx/vector.h" -class WXDLLIMPEXP_FWD_CORE wxImageList; class wxMSWListItemData; // define this symbol to indicate the availability of SetColumnsOrder() and @@ -320,14 +319,6 @@ public: // Insert an image/string item long InsertItem(long index, const wxString& label, int imageIndex); - // For list view mode (only), inserts a column. - long InsertColumn(long col, const wxListItem& info); - - long InsertColumn(long col, - const wxString& heading, - int format = wxLIST_FORMAT_LEFT, - int width = -1); - // set the number of items in a virtual list control void SetItemCount(long count); @@ -393,6 +384,9 @@ protected: // common part of all ctors void Init(); + // Implement base class pure virtual methods. + long DoInsertColumn(long col, const wxListItem& info); + // free memory taken by all internal data void FreeAllInternalData(); diff --git a/include/wx/osx/listctrl.h b/include/wx/osx/listctrl.h index 0e9fcf1226..23b660dfdd 100644 --- a/include/wx/osx/listctrl.h +++ b/include/wx/osx/listctrl.h @@ -252,12 +252,6 @@ class WXDLLIMPEXP_CORE wxListCtrl: public wxListCtrlBase // Insert an image/string item long InsertItem(long index, const wxString& label, int imageIndex); - // For list view mode (only), inserts a column. - long InsertColumn(long col, wxListItem& info); - - long InsertColumn(long col, const wxString& heading, int format = wxLIST_FORMAT_LEFT, - int width = -1); - // Scrolls the list control. If in icon, small icon or report view mode, // x specifies the number of pixels to scroll. If in list view mode, x // specifies the number of columns to scroll. @@ -371,14 +365,14 @@ class WXDLLIMPEXP_CORE wxListCtrl: public wxListCtrlBase GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL); protected: + // Implement base class pure virtual methods. + long DoInsertColumn(long col, const wxListItem& info); // protected overrides needed for pimpl approach virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); - virtual wxSize DoGetBestSize() const; - long m_current; wxListCtrlTextCtrlWrapper *m_textctrlWrapper; wxListCtrlRenameTimer *m_renameTimer; diff --git a/src/common/listctrlcmn.cpp b/src/common/listctrlcmn.cpp index e2b18e9602..861beef994 100644 --- a/src/common/listctrlcmn.cpp +++ b/src/common/listctrlcmn.cpp @@ -27,6 +27,10 @@ #include "wx/listctrl.h" +#ifndef WX_PRECOMP + #include "wx/dcclient.h" +#endif + const char wxListCtrlNameStr[] = "listCtrl"; // ListCtrl events @@ -128,4 +132,73 @@ IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl) IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject) IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent) +// ---------------------------------------------------------------------------- +// wxListCtrlBase implementation +// ---------------------------------------------------------------------------- + +long +wxListCtrlBase::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 > -1 ) + { + item.m_mask |= wxLIST_MASK_WIDTH; + item.m_width = width; + } + item.m_format = format; + + return InsertColumn(col, item); +} + +long wxListCtrlBase::InsertColumn(long col, const wxListItem& info) +{ + long rc = DoInsertColumn(col, info); + if ( rc != -1 ) + { + // As our best size calculation depends on the column headers, + // invalidate the previously cached best size when a column is added. + InvalidateBestSize(); + } + + return rc; +} + +wxSize wxListCtrlBase::DoGetBestClientSize() const +{ + // There is no obvious way to determine the best size in icon and list + // modes so just don't do it for now. + if ( !InReportView() ) + return wxControl::DoGetBestClientSize(); + + // In report mode, we use only the column headers, not items, to determine + // the best width. The reason for this is that it's easier (we can't just + // iterate over all items, especially not in a virtual control, so we'd + // have to do something relatively complicated such as checking the size of + // some items in the beginning and the end only) and also because the + // columns are usually static while the list contents is dynamic so it + // usually doesn't make much sense to adjust the control size to it anyhow. + // And finally, scrollbars can always be used with the items while the + // headers are just truncated if there is not enough place for them. + const int columns = GetColumnCount(); + if ( HasFlag(wxLC_NO_HEADER) || !columns ) + return wxControl::DoGetBestClientSize(); + + wxClientDC dc(const_cast(this)); + + // Total width of all headers determines the best control width. + int totalWidth = 0; + for ( int col = 0; col < columns; col++ ) + { + totalWidth += GetColumnWidth(col); + } + + // Use some arbitrary height, there is no good way to determine it. + return wxSize(totalWidth, 10*dc.GetCharHeight()); +} + #endif // wxUSE_LISTCTRL diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 49d023895b..d6c70b065f 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -3017,18 +3017,18 @@ int wxListMainWindow::GetItemSpacing( bool isSmall ) // columns // ---------------------------------------------------------------------------- -void wxListMainWindow::SetColumn( int col, wxListItem &item ) +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(GetTextLength( item.m_text )); + wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; if ( headerWin ) headerWin->m_dirty = true; @@ -4122,15 +4122,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(GetTextLength( item.m_text )); - wxListHeaderData *column = new wxListHeaderData( item ); wxColWidthInfo *colWidthInfo = new wxColWidthInfo(); bool insert = (col >= 0) && ((size_t)col < m_columns.GetCount()); @@ -4528,7 +4528,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; @@ -4945,7 +4945,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") ); @@ -4959,23 +4959,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); diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 45e1d0c503..0d8ee0e785 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -1730,7 +1730,7 @@ long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex) } // For list view mode (only), inserts a column. -long wxListCtrl::InsertColumn(long col, const wxListItem& item) +long wxListCtrl::DoInsertColumn(long col, const wxListItem& item) { LV_COLUMN lvCol; wxConvertToMSWListCol(GetHwnd(), col, item, lvCol); @@ -1757,24 +1757,6 @@ long wxListCtrl::InsertColumn(long col, const wxListItem& item) return n; } -long wxListCtrl::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 > -1 ) - { - item.m_mask |= wxLIST_MASK_WIDTH; - item.m_width = width; - } - item.m_format = format; - - return InsertColumn(col, item); -} - // scroll the control by the given number of pixels (exception: in list view, // dx is interpreted as number of columns) bool wxListCtrl::ScrollList(int dx, int dy) diff --git a/src/osx/carbon/listctrl_mac.cpp b/src/osx/carbon/listctrl_mac.cpp index 96d9a10738..40b16b2ba8 100644 --- a/src/osx/carbon/listctrl_mac.cpp +++ b/src/osx/carbon/listctrl_mac.cpp @@ -801,11 +801,6 @@ void wxListCtrl::DoSetSize( int x, int y, int width, int height, int sizeFlags ) } } -wxSize wxListCtrl::DoGetBestSize() const -{ - return wxWindow::DoGetBestSize(); -} - bool wxListCtrl::SetFont(const wxFont& font) { bool rv = true; @@ -2161,7 +2156,7 @@ long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex) } // For list view mode (only), inserts a column. -long wxListCtrl::InsertColumn(long col, wxListItem& item) +long wxListCtrl::DoInsertColumn(long col, wxListItem& item) { if (m_genericImpl) return m_genericImpl->InsertColumn(col, item); @@ -2214,27 +2209,6 @@ long wxListCtrl::InsertColumn(long col, wxListItem& item) return col; } -long wxListCtrl::InsertColumn(long col, - const wxString& heading, - int format, - int width) -{ - if (m_genericImpl) - return m_genericImpl->InsertColumn(col, heading, format, width); - - wxListItem item; - item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT; - item.m_text = heading; - if ( width > -1 ) - { - item.m_mask |= wxLIST_MASK_WIDTH; - item.m_width = width; - } - item.m_format = format; - - return InsertColumn(col, item); -} - // scroll the control by the given number of pixels (exception: in list view, // dx is interpreted as number of columns) bool wxListCtrl::ScrollList(int dx, int dy) -- 2.45.2