From 3146d03aaaa666afde2b9968dc313269ebd21851 Mon Sep 17 00:00:00 2001 From: Ian McInerney Date: Fri, 26 Mar 2021 15:47:02 +0000 Subject: [PATCH] Properly ellipsize layer names in the GerbView layer manager Before, the layers were always ellipsized if the name was >30 characters, even if the widget was wide enough to display the full name. Now they are ellipsized when needed (e.g. if the widget is shrunk small enough). Fixes https://gitlab.com/kicad/code/kicad/issues/1919 --- common/CMakeLists.txt | 1 + common/widgets/wx_ellipsized_static_text.cpp | 41 ++++++++++++ gerbview/gerber_file_image_list.cpp | 6 +- gerbview/gerber_file_image_list.h | 21 ++++--- gerbview/gerbview_frame.cpp | 4 ++ gerbview/widgets/gerbview_layer_widget.cpp | 3 +- gerbview/widgets/layer_widget.cpp | 16 ++++- gerbview/widgets/layer_widget.h | 10 +++ include/widgets/wx_ellipsized_static_text.h | 65 ++++++++++++++++++++ 9 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 common/widgets/wx_ellipsized_static_text.cpp create mode 100644 include/widgets/wx_ellipsized_static_text.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 7d19f214ce..26e09004ff 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -242,6 +242,7 @@ set( COMMON_WIDGET_SRCS widgets/widget_hotkey_list.cpp widgets/wx_aui_art_providers.cpp widgets/wx_busy_indicator.cpp + widgets/wx_ellipsized_static_text.cpp widgets/wx_grid.cpp ) diff --git a/common/widgets/wx_ellipsized_static_text.cpp b/common/widgets/wx_ellipsized_static_text.cpp new file mode 100644 index 0000000000..27026a1b19 --- /dev/null +++ b/common/widgets/wx_ellipsized_static_text.cpp @@ -0,0 +1,41 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +WX_ELLIPSIZED_STATIC_TEXT::WX_ELLIPSIZED_STATIC_TEXT( wxWindow* aParent, wxWindowID aID, + const wxString& aLabel, const wxPoint& aPos, + const wxSize& aSize, long aStyle ) + : wxStaticText( aParent, aID, aLabel, aPos, aSize, aStyle ), + m_minimumString( "M...M" ) +{ +} + + +wxSize WX_ELLIPSIZED_STATIC_TEXT::DoGetBestSize() const +{ + // This is slightly awkward because DoGetBestSize is const upstream, but we need the non-const + // object to measure the text size in this function. + return KIUI::GetTextSize( m_minimumString, const_cast( this ) ); +} diff --git a/gerbview/gerber_file_image_list.cpp b/gerbview/gerber_file_image_list.cpp index d7a3fb2774..270c001c62 100644 --- a/gerbview/gerber_file_image_list.cpp +++ b/gerbview/gerber_file_image_list.cpp @@ -118,7 +118,7 @@ void GERBER_FILE_IMAGE_LIST::DeleteImage( int aIdx ) } // Build a name for image aIdx which can be used in layers manager -const wxString GERBER_FILE_IMAGE_LIST::GetDisplayName( int aIdx, bool aNameOnly ) +const wxString GERBER_FILE_IMAGE_LIST::GetDisplayName( int aIdx, bool aNameOnly, bool aFullName ) { wxString name; @@ -136,10 +136,10 @@ const wxString GERBER_FILE_IMAGE_LIST::GetDisplayName( int aIdx, bool aNameOnly wxFileName fn( gerber->m_FileName ); wxString filename = fn.GetFullName(); - // if the filename is too long, display a shortened name: + // If the filename is too long, display a shortened name if requested const int maxlen = 30; - if( filename.Length() > maxlen ) + if( !aFullName && filename.Length() > maxlen ) { wxString shortenedfn = filename.Left(2) + "..." + filename.Right(maxlen-5); filename = shortenedfn; diff --git a/gerbview/gerber_file_image_list.h b/gerbview/gerber_file_image_list.h index fca12d502e..ef4d25467c 100644 --- a/gerbview/gerber_file_image_list.h +++ b/gerbview/gerber_file_image_list.h @@ -76,8 +76,8 @@ public: unsigned ImagesMaxCount() { return m_GERBER_List.size(); } /** - * Add a GERBER_FILE_IMAGE* at index aIdx - * or at the first free location if aIdx < 0 + * Add a GERBER_FILE_IMAGE* at index aIdx or at the first free location if aIdx < 0 + * * @param aGbrImage = the image to add * @param aIdx = the location to use ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) * @return true if the index used, or -1 if no room to add image @@ -86,17 +86,25 @@ public: /** - * remove all loaded data in list, and delete all images. Memory is freed + * Remove all loaded data in list, and delete all images, freeing the memory. */ void DeleteAllImages(); /** - * delete the loaded data of image aIdx. Memory is freed + * Delete the loaded data of image aIdx, freeing the memory. + * * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) */ void DeleteImage( int aIdx ); /** + * Get the display name for the layer at aIdx. + * + * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) + * @param aNameOnly = false (default) to add the layer number (for layers manager) + * or true to return only the name without layer name (status bar) + * @param aFullName = false (default) to ellipsize the name, true to return the full name. + * * @return a name for image aIdx which can be used in layers manager * and layer selector or in the status bar * if a file is loaded, the name is: @@ -105,11 +113,8 @@ public: * " *" * if no file loaded, the name is: * "Layer n" with n = aIdx+1 - * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) - * @param aNameOnly = false (default) to add the layer number (for layers manager) - * or true to return only the name without layer name (status bar) */ - const wxString GetDisplayName( int aIdx, bool aNameOnly = false ); + const wxString GetDisplayName( int aIdx, bool aNameOnly = false, bool aFullName = false ); /** * Sort loaded images by Z order priority, if they have the X2 FileFormat info diff --git a/gerbview/gerbview_frame.cpp b/gerbview/gerbview_frame.cpp index 35ac0053fd..df734414fb 100644 --- a/gerbview/gerbview_frame.cpp +++ b/gerbview/gerbview_frame.cpp @@ -134,6 +134,10 @@ GERBVIEW_FRAME::GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent ) // Create the PCB_LAYER_WIDGET *after* SetLayout(): m_LayersManager = new GERBER_LAYER_WIDGET( this, GetCanvas() ); + // Update the minimum string length in the layer panel with the length of the last default layer + wxString lyrName = GetImagesList()->GetDisplayName( GetImagesList()->ImagesMaxCount(), false, true ); + m_LayersManager->SetSmallestLayerString( lyrName ); + // LoadSettings() *after* creating m_LayersManager, because LoadSettings() // initialize parameters in m_LayersManager LoadSettings( config() ); diff --git a/gerbview/widgets/gerbview_layer_widget.cpp b/gerbview/widgets/gerbview_layer_widget.cpp index 7f5f950a8b..1632286cb1 100644 --- a/gerbview/widgets/gerbview_layer_widget.cpp +++ b/gerbview/widgets/gerbview_layer_widget.cpp @@ -221,7 +221,8 @@ void GERBER_LAYER_WIDGET::ReFill() int aRow = findLayerRow( layer ); bool visible = true; COLOR4D color = myframe->GetLayerColor( GERBER_DRAW_LAYER( layer ) ); - wxString msg = GetImagesList()->GetDisplayName( layer ); + wxString msg = GetImagesList()->GetDisplayName( layer, /* include layer number */ false, + /* Get the full name */ true ); if( myframe->GetCanvas() ) visible = myframe->GetCanvas()->GetView()->IsLayerVisible( GERBER_DRAW_LAYER( layer ) ); diff --git a/gerbview/widgets/layer_widget.cpp b/gerbview/widgets/layer_widget.cpp index 19872b84ac..e671b95b86 100644 --- a/gerbview/widgets/layer_widget.cpp +++ b/gerbview/widgets/layer_widget.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -345,11 +346,16 @@ void LAYER_WIDGET::insertLayerRow( int aRow, const ROW& aSpec ) // column 3 (COLUMN_COLOR_LYRNAME) col = COLUMN_COLOR_LYRNAME; - wxStaticText* st = new wxStaticText( m_LayerScrolledWindow, encodeId( col, aSpec.id ), aSpec.rowName ); + WX_ELLIPSIZED_STATIC_TEXT* st = new WX_ELLIPSIZED_STATIC_TEXT( m_LayerScrolledWindow, + encodeId( col, aSpec.id ), + aSpec.rowName, wxDefaultPosition, + wxDefaultSize, + wxST_ELLIPSIZE_MIDDLE ); shrinkFont( st, m_PointSize ); st->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this ); st->SetToolTip( aSpec.tooltip ); - m_LayersFlexGridSizer->wxSizer::Insert( index+col, st, 0, flags ); + st->SetMinimumStringLength( m_smallestLayerString ); + m_LayersFlexGridSizer->wxSizer::Insert( index+col, st, 0, flags | wxEXPAND ); // column 4 (COLUMN_ALPHA_INDICATOR) col = COLUMN_ALPHA_INDICATOR; @@ -475,7 +481,8 @@ void LAYER_WIDGET::passOnFocus() LAYER_WIDGET::LAYER_WIDGET( wxWindow* aParent, wxWindow* aFocusOwner, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : - wxPanel( aParent, id, pos, size, style ) + wxPanel( aParent, id, pos, size, style ), + m_smallestLayerString( "M...M" ) { int indicatorSize = ConvertDialogToPixels( wxSize( 6, 6 ) ).x; m_IconProvider = new ROW_ICON_PROVIDER( indicatorSize ); @@ -512,6 +519,9 @@ LAYER_WIDGET::LAYER_WIDGET( wxWindow* aParent, wxWindow* aFocusOwner, wxWindowID m_LayersFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL ); m_LayersFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE ); + // Make column 3 growable/stretchable + m_LayersFlexGridSizer->AddGrowableCol( 3, 1 ); + m_LayerScrolledWindow->SetSizer( m_LayersFlexGridSizer ); m_LayerScrolledWindow->Layout(); m_LayersFlexGridSizer->Fit( m_LayerScrolledWindow ); diff --git a/gerbview/widgets/layer_widget.h b/gerbview/widgets/layer_widget.h index c7616eacf4..09157afa94 100644 --- a/gerbview/widgets/layer_widget.h +++ b/gerbview/widgets/layer_widget.h @@ -138,6 +138,8 @@ protected: ROW_ICON_PROVIDER* m_IconProvider; + wxString m_smallestLayerString; + /** * Virtual Function useAlternateBitmap * @return true if bitmaps shown in Render layer list @@ -271,6 +273,14 @@ public: virtual ~LAYER_WIDGET(); + /** + * Set the string that is used for determining the smallest string displayed in the layer's tab. + */ + void SetSmallestLayerString( const wxString& aString ) + { + m_smallestLayerString = aString; + } + /** * Function GetBestSize * returns the preferred minimum size, taking into consideration the diff --git a/include/widgets/wx_ellipsized_static_text.h b/include/widgets/wx_ellipsized_static_text.h new file mode 100644 index 0000000000..42a6c714f6 --- /dev/null +++ b/include/widgets/wx_ellipsized_static_text.h @@ -0,0 +1,65 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef WX_ELLIPSIZED_STATIC_TEXT_H_ +#define WX_ELLIPSIZED_STATIC_TEXT_H_ + +#include + +/** + * A version of a wxStaticText control that will request a smaller size than the full string. + * + * This can be used with the ellipsization styles to ensure that the control will actually ellipsize + * properly inside sizer elements (since they ask for the best size but GTK reports the best size + * as being the full string length, even when ellipsization is enabled). This work around is discussed + * in upstream ticket https://trac.wxwidgets.org/ticket/18992. + */ +class WX_ELLIPSIZED_STATIC_TEXT: public wxStaticText +{ +public: + WX_ELLIPSIZED_STATIC_TEXT( wxWindow* aParent, wxWindowID aID, const wxString& aLabel, + const wxPoint& aPos = wxDefaultPosition, + const wxSize& aSize = wxDefaultSize, + long aStyle = 0 ); + + /** + * Set the string that is used for determining the requested size of the control. The control + * will return this string length from GetBestSize(), irregardless of what string the control + * is displaying. + * + * @param aString is the smallest string to display without ellipses + */ + void SetMinimumStringLength( const wxString& aString ) + { + m_minimumString = aString; + } + +protected: + wxSize DoGetBestSize() const override; + +private: + wxString m_minimumString; // The string that is used to set the minimum control width +}; + + +#endif // WX_ELLIPSIZED_STATIC_TEXT_H_