You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
5.7 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020 CERN
  5. * @author Maciej Suminski <maciej.suminski@cern.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "properties_panel.h"
  21. #include <tool/selection.h>
  22. #include <eda_base_frame.h>
  23. #include <eda_item.h>
  24. #include <import_export.h>
  25. #include <algorithm>
  26. #include <set>
  27. #include <wx/settings.h>
  28. #include <wx/stattext.h>
  29. extern APIIMPORT wxPGGlobalVarsClass* wxPGGlobalVars;
  30. PROPERTIES_PANEL::PROPERTIES_PANEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame )
  31. : wxPanel( aParent ), m_frame( aFrame )
  32. {
  33. wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
  34. // on some platforms wxPGGlobalVars is initialized automatically,
  35. // but others need an explicit init
  36. if( !wxPGGlobalVars )
  37. wxPGInitResourceModule();
  38. m_caption = new wxStaticText( this, wxID_ANY, _( "No objects selected" ), wxDefaultPosition,
  39. wxDefaultSize, 0 );
  40. mainSizer->Add( m_caption, 0, wxALL | wxEXPAND, 5 );
  41. m_grid = new wxPropertyGrid( this, wxID_ANY, wxDefaultPosition, wxSize( 300, 400 ),
  42. wxPG_AUTO_SORT | wxPG_DEFAULT_STYLE );
  43. m_grid->SetUnspecifiedValueAppearance( wxPGCell( wxT( "<...>" ) ) );
  44. mainSizer->Add( m_grid, 1, wxALL | wxEXPAND, 5 );
  45. m_grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
  46. SetSizer( mainSizer );
  47. Layout();
  48. m_grid->CenterSplitter();
  49. Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanged ), NULL, this );
  50. Connect( wxEVT_PG_CHANGING, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanging ), NULL, this );
  51. Connect( wxEVT_SHOW, wxShowEventHandler( PROPERTIES_PANEL::onShow ), NULL, this );
  52. }
  53. void PROPERTIES_PANEL::update( const SELECTION& aSelection )
  54. {
  55. m_grid->Clear();
  56. m_displayed.clear();
  57. if( aSelection.Empty() )
  58. {
  59. m_caption->SetLabel( _( "No objects selected" ) );
  60. return;
  61. }
  62. // Get all the selected types
  63. std::set<TYPE_ID> types;
  64. for( EDA_ITEM* item : aSelection )
  65. types.insert( TYPE_HASH( *item ) );
  66. wxCHECK( !types.empty(), /* void */ );
  67. if( aSelection.Size() > 1 )
  68. {
  69. m_caption->SetLabel( _( "Multiple objects selected" ) );
  70. }
  71. else
  72. {
  73. m_caption->SetLabel( aSelection.Front()->GetTypeDesc() );
  74. }
  75. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  76. propMgr.SetUnits( m_frame->GetUserUnits() );
  77. std::set<PROPERTY_BASE*> commonProps;
  78. const PROPERTY_LIST& allProperties = propMgr.GetProperties( *types.begin() );
  79. copy( allProperties.begin(), allProperties.end(), inserter( commonProps, commonProps.begin() ) );
  80. // Get all possible properties
  81. for( const auto& type : types )
  82. {
  83. const PROPERTY_LIST& itemProps = propMgr.GetProperties( type );
  84. for( auto it = commonProps.begin(); it != commonProps.end(); /* ++it in the loop */ )
  85. {
  86. if( !binary_search( itemProps.begin(), itemProps.end(), *it ) )
  87. it = commonProps.erase( it );
  88. else
  89. ++it;
  90. }
  91. }
  92. // Find a set of properties that is common to all selected items
  93. for( const auto& property : commonProps )
  94. {
  95. if( !property->Available( aSelection.Front() ) )
  96. continue;
  97. // Either determine the common value for a property or "<...>" to indicate multiple values
  98. bool available = true;
  99. wxVariant commonVal, itemVal;
  100. for( EDA_ITEM* item : aSelection )
  101. {
  102. if( !property->Available( item ) )
  103. break; // there is an item that does not have this property, so do not display it
  104. wxVariant& value = commonVal.IsNull() ? commonVal : itemVal;
  105. const wxAny& any = item->Get( property );
  106. bool converted = false;
  107. if( property->HasChoices() )
  108. {
  109. // handle enums as ints, since there are no default conversion functions for wxAny
  110. int tmp;
  111. converted = any.GetAs<int>( &tmp );
  112. if( converted )
  113. value = wxVariant( tmp );
  114. }
  115. if( !converted ) // all other types
  116. converted = any.GetAs( &value );
  117. if( !converted )
  118. {
  119. wxFAIL_MSG( "Could not convert wxAny to wxVariant" );
  120. available = false;
  121. break;
  122. }
  123. if( !commonVal.IsNull() && value != commonVal )
  124. {
  125. commonVal.MakeNull(); // items have different values for this property
  126. break;
  127. }
  128. }
  129. if( available )
  130. {
  131. wxPGProperty* pgProp = createPGProperty( property );
  132. if( pgProp )
  133. {
  134. pgProp->SetValue( commonVal );
  135. m_grid->Append( pgProp );
  136. m_displayed.push_back( property );
  137. }
  138. }
  139. }
  140. m_grid->FitColumns();
  141. }
  142. void PROPERTIES_PANEL::onShow( wxShowEvent& aEvent )
  143. {
  144. if( aEvent.IsShown() )
  145. UpdateData();
  146. }