From a74aa3850a394d5bdd18bf4d4b26a8681bb09702 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbrand@ucdavis.edu> Date: Sat, 9 Feb 2019 16:57:53 -0800 Subject: [PATCH] libtree: Update width automatically When filtering, we update the width of the displayed column to ensure the full text is visible to the user. Check is rough, based on line width (doesn't completely account for differing char widths) but is sufficient for the approximate difference Fixes: lp:1815401 * https://bugs.launchpad.net/kicad/+bug/1815401 Fixes: lp:1788495 * https://bugs.launchpad.net/kicad/+bug/1788495 --- common/lib_tree_model.h | 1 + common/lib_tree_model_adapter.cpp | 57 +++++++++++++++++++++++++------ common/lib_tree_model_adapter.h | 12 ++++--- common/widgets/lib_tree.cpp | 17 +++++++-- common/widgets/lib_tree.h | 4 +-- 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/common/lib_tree_model.h b/common/lib_tree_model.h index 970cc0dfa5..98b21fdbd7 100644 --- a/common/lib_tree_model.h +++ b/common/lib_tree_model.h @@ -104,6 +104,7 @@ public: LIB_ID LibId; ///< LIB_ID determined by the parent library nickname and alias name. int Unit; ///< Actual unit, or zero bool IsRoot; ///< Indicates if the symbol is a root symbol instead of an alias. + int VisLen; ///< Length of the string as shown on screen /** * Update the score for this part. This is accumulative - it will be diff --git a/common/lib_tree_model_adapter.cpp b/common/lib_tree_model_adapter.cpp index d7c15240b7..f433f1cf81 100644 --- a/common/lib_tree_model_adapter.cpp +++ b/common/lib_tree_model_adapter.cpp @@ -28,8 +28,6 @@ #include <wx/wupdlock.h> -LIB_TREE_MODEL_ADAPTER::WIDTH_CACHE LIB_TREE_MODEL_ADAPTER::m_width_cache; - static const int kDataViewIndent = 20; @@ -99,6 +97,17 @@ void LIB_TREE_MODEL_ADAPTER::ShowUnits( bool aShow ) } +void LIB_TREE_MODEL_ADAPTER::UpdateWidth( int aCol ) +{ + auto col = m_widget->GetColumn( aCol ); + + if( col ) + { + col->SetWidth( ColWidth( m_tree, aCol, col->GetTitle() ) ); + } +} + + void LIB_TREE_MODEL_ADAPTER::SetPreselectNode( LIB_ID const& aLibId, int aUnit ) { m_preselect_lib_id = aLibId; @@ -112,10 +121,15 @@ void LIB_TREE_MODEL_ADAPTER::DoAddLibrary( wxString const& aNodeName, wxString c { auto& lib_node = m_tree.AddLib( aNodeName, aDesc ); + lib_node.VisLen = wxTheApp->GetTopWindow()->GetTextExtent( lib_node.Name ).x; + for( auto item: aItemList ) { if( item ) - lib_node.AddItem( item ); + { + auto& child_node = lib_node.AddItem( item ); + child_node.VisLen = wxTheApp->GetTopWindow()->GetTextExtent( child_node.Name ).x; + } } lib_node.AssignIntrinsicRanks( presorted ); @@ -170,6 +184,8 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( wxString const& aSearch ) m_widget->Select( item ); m_widget->EnsureVisible( item ); } + + UpdateWidth( 0 ); } @@ -183,10 +199,8 @@ void LIB_TREE_MODEL_ADAPTER::AttachTo( wxDataViewCtrl* aDataViewCtrl ) wxString part_head = _( "Item" ); wxString desc_head = _( "Description" ); - m_col_part = aDataViewCtrl->AppendTextColumn( part_head, 0, wxDATAVIEW_CELL_INERT, - ColWidth( m_tree, 0, part_head ) ); - m_col_desc = aDataViewCtrl->AppendTextColumn( desc_head, 1, wxDATAVIEW_CELL_INERT, - ColWidth( m_tree, 1, desc_head ) ); + m_col_part = aDataViewCtrl->AppendTextColumn( part_head, 0, wxDATAVIEW_CELL_INERT, 360 ); + m_col_desc = aDataViewCtrl->AppendTextColumn( desc_head, 1, wxDATAVIEW_CELL_INERT, 2000 ); } @@ -349,10 +363,33 @@ bool LIB_TREE_MODEL_ADAPTER::GetAttr( wxDataViewItem const& aItem, int LIB_TREE_MODEL_ADAPTER::ColWidth( LIB_TREE_NODE& aTree, int aCol, wxString const& aHeading ) { - // It's too expensive to calculate widths on really big trees, and the user probably - // wants it left where they dragged it anyway. if( aCol == 0 ) - return 360; + { + int padding = m_widget->GetTextExtent( "MM" ).x; + int longest = m_widget->GetTextExtent( aHeading ).x; + + for( auto& node : aTree.Children ) + { + auto item = ToItem( &*node ); + + if( !item.IsOk() ) + continue; + + if( node->Score > 0 ) + longest = std::max( longest, node->VisLen + padding ); + + if( !m_widget->IsExpanded( item ) ) + continue; + + for( auto& childNode : node->Children ) + { + if( childNode->Score > 0 ) + longest = std::max( longest, childNode->VisLen + 2 * padding ); + } + } + + return longest; + } else return 2000; } diff --git a/common/lib_tree_model_adapter.h b/common/lib_tree_model_adapter.h index fc1b74bed8..1446cd70ce 100644 --- a/common/lib_tree_model_adapter.h +++ b/common/lib_tree_model_adapter.h @@ -28,6 +28,7 @@ #include <wx/hashmap.h> #include <wx/dataview.h> +#include <wx/headerctrl.h> #include <vector> #include <functional> @@ -133,6 +134,13 @@ public: */ void ShowUnits( bool aShow ); + /** + * Update the column size based on the displayed contents + * + * @param aCol Which column to resize + */ + void UpdateWidth( int aCol ); + /** * Set the component name to be selected if there are no search results. * May be set at any time; updates at the next UpdateSearchString(). @@ -327,10 +335,6 @@ private: wxDataViewColumn* m_col_desc; wxDataViewCtrl* m_widget; - WX_DECLARE_STRING_HASH_MAP( std::vector<int>, WIDTH_CACHE ); - - static WIDTH_CACHE m_width_cache; - /** * Compute the width required for the given column of a node and its * children. diff --git a/common/widgets/lib_tree.cpp b/common/widgets/lib_tree.cpp index effd8bec3b..2810a26851 100644 --- a/common/widgets/lib_tree.cpp +++ b/common/widgets/lib_tree.cpp @@ -41,8 +41,7 @@ LIB_TREE::LIB_TREE( wxWindow* aParent, LIB_TABLE* aLibTable, LIB_TREE_MODEL_ADAP m_adapter( aAdapter ), m_query_ctrl( nullptr ), m_details_ctrl( nullptr ), - m_menuActive( false ), - m_filtering( false ) + m_menuActive( false ) { // create space for context menu pointers, INVALID is the max value m_menus.resize( LIB_TREE_NODE::TYPE::INVALID + 1 ); @@ -114,6 +113,8 @@ LIB_TREE::LIB_TREE( wxWindow* aParent, LIB_TABLE* aLibTable, LIB_TREE_MODEL_ADAP m_tree_ctrl->Bind( wxEVT_DATAVIEW_ITEM_ACTIVATED, &LIB_TREE::onTreeActivate, this ); m_tree_ctrl->Bind( wxEVT_DATAVIEW_SELECTION_CHANGED, &LIB_TREE::onTreeSelect, this ); m_tree_ctrl->Bind( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, &LIB_TREE::onContextMenu, this ); + m_tree_ctrl->Bind( wxEVT_DATAVIEW_ITEM_EXPANDED, &LIB_TREE::onExpandCollapse, this ); + m_tree_ctrl->Bind( wxEVT_DATAVIEW_ITEM_COLLAPSED, &LIB_TREE::onExpandCollapse, this ); Bind( COMPONENT_PRESELECTED, &LIB_TREE::onPreselect, this ); @@ -129,6 +130,7 @@ LIB_TREE::LIB_TREE( wxWindow* aParent, LIB_TABLE* aLibTable, LIB_TREE_MODEL_ADAP // There may be a part preselected in the model. Make sure it is displayed. postPreselectEvent(); + m_adapter->UpdateWidth( 0 ); Layout(); sizer->Fit( this ); @@ -193,7 +195,6 @@ void LIB_TREE::Regenerate( bool aKeepState ) wxString filter = m_query_ctrl->GetValue(); m_adapter->UpdateSearchString( filter ); - m_filtering = !filter.IsEmpty(); postPreselectEvent(); // Restore the state @@ -228,6 +229,7 @@ void LIB_TREE::selectIfValid( const wxDataViewItem& aTreeId ) if( aTreeId.IsOk() ) { m_tree_ctrl->EnsureVisible( aTreeId ); + m_adapter->UpdateWidth( 0 ); m_tree_ctrl->Select( aTreeId ); postPreselectEvent(); } @@ -237,7 +239,10 @@ void LIB_TREE::selectIfValid( const wxDataViewItem& aTreeId ) void LIB_TREE::centerIfValid( const wxDataViewItem& aTreeId ) { if( aTreeId.IsOk() ) + { m_tree_ctrl->EnsureVisible( aTreeId ); + m_adapter->UpdateWidth( 0 ); + } } @@ -361,6 +366,12 @@ void LIB_TREE::onTreeSelect( wxDataViewEvent& aEvent ) } +void LIB_TREE::onExpandCollapse( wxDataViewEvent& aEvent ) +{ + m_adapter->UpdateWidth( 0 ); +} + + void LIB_TREE::onTreeActivate( wxDataViewEvent& aEvent ) { if( !GetSelectedLibId().IsValid() ) diff --git a/common/widgets/lib_tree.h b/common/widgets/lib_tree.h index 278a099dfe..9b0e01ee9c 100644 --- a/common/widgets/lib_tree.h +++ b/common/widgets/lib_tree.h @@ -169,6 +169,7 @@ protected: void onTreeSelect( wxDataViewEvent& aEvent ); void onTreeActivate( wxDataViewEvent& aEvent ); + void onExpandCollapse( wxDataViewEvent& aEvent ); void onUpdateUI( wxUpdateUIEvent& aEvent ); void onDetailsLink( wxHtmlLinkEvent& aEvent ); @@ -188,9 +189,6 @@ protected: ///> Flag indicating whether a right-click context menu is active bool m_menuActive; - ///> Flag indicating whether the results are filtered using the search query - bool m_filtering; - ///> State of the widget before any filters applied STATE m_unfilteredState; };