From f6f6ebd5f9f635c81f1a5f8d285a8e2097bbf80c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Feb 2020 09:40:25 +0100 Subject: [PATCH] WIP: Properties GUI --- common/CMakeLists.txt | 2 + common/pg_properties.cpp | 282 ++++++++++ common/widgets/properties_panel.cpp | 149 +++++ common/widgets/properties_panel.h | 75 +++ include/pg_properties.h | 112 ++++ include/property.h | 2 - include/validators.h | 5 + pcbnew/CMakeLists.txt | 2 + pcbnew/dialogs/pcb_properties_panel.cpp | 118 ++++ pcbnew/dialogs/pcb_properties_panel.h | 56 ++ pcbnew/menubar_pcb_editor.cpp | 1 + pcbnew/pcb_base_edit_frame.cpp | 15 +- pcbnew/pcb_base_edit_frame.h | 9 + pcbnew/pcb_edit_frame.cpp | 21 +- pcbnew/pcb_edit_frame.h | 5 + pcbnew/pcb_layer_widget.cpp | 708 ++++++++++++++++++++++++ pcbnew/pcb_layer_widget.h | 182 ++++++ pcbnew/pcb_shape.cpp | 1 - pcbnew/pcbnew_settings.cpp | 3 + pcbnew/pcbnew_settings.h | 1 + pcbnew/toolbars_pcb_editor.cpp | 8 + pcbnew/tools/board_editor_control.cpp | 8 + pcbnew/tools/board_editor_control.h | 3 +- pcbnew/tools/pcb_actions.cpp | 5 + pcbnew/tools/pcb_actions.h | 1 + pcbnew/tools/pcb_control.h | 2 +- pcbnew/tools/properties_tool.cpp | 45 ++ pcbnew/tools/properties_tool.h | 42 ++ qa/tools/pcb_test_window/CMakeLists.txt | 22 +- 29 files changed, 1867 insertions(+), 18 deletions(-) create mode 100644 common/pg_properties.cpp create mode 100644 common/widgets/properties_panel.cpp create mode 100644 common/widgets/properties_panel.h create mode 100644 include/pg_properties.h create mode 100644 pcbnew/dialogs/pcb_properties_panel.cpp create mode 100644 pcbnew/dialogs/pcb_properties_panel.h create mode 100644 pcbnew/pcb_layer_widget.cpp create mode 100644 pcbnew/pcb_layer_widget.h create mode 100644 pcbnew/tools/properties_tool.cpp create mode 100644 pcbnew/tools/properties_tool.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 08b884e431..ea5db40904 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -189,6 +189,7 @@ set( COMMON_WIDGET_SRCS widgets/number_badge.cpp widgets/paged_dialog.cpp widgets/progress_reporter_base.cpp + widgets/properties_panel.cpp widgets/split_button.cpp widgets/stepped_slider.cpp widgets/text_ctrl_eval.cpp @@ -498,6 +499,7 @@ set( PCB_COMMON_SRCS fp_lib_table.cpp hash_eda.cpp page_info.cpp + pg_properties.cpp ${CMAKE_SOURCE_DIR}/pcbnew/pcb_base_frame.cpp ${CMAKE_SOURCE_DIR}/pcbnew/pcb_expr_evaluator.cpp ${CMAKE_SOURCE_DIR}/pcbnew/board_commit.cpp diff --git a/common/pg_properties.cpp b/common/pg_properties.cpp new file mode 100644 index 0000000000..2ccaf86278 --- /dev/null +++ b/common/pg_properties.cpp @@ -0,0 +1,282 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * @author Maciej Suminski + * + * 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 3 + * 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, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +// reg-ex describing a signed valid value with a unit +static const wxChar REGEX_SIGNED_DISTANCE[] = wxT( "([-+]?[0-9]+[\\.?[0-9]*) *(mm|in)*" ); +static const wxChar REGEX_UNSIGNED_DISTANCE[] = wxT( "([0-9]+[\\.?[0-9]*) *(mm|in)*" ); + +wxPGProperty* PGPropertyFactory( const PROPERTY_BASE* aProperty ) +{ + wxPGProperty* ret = nullptr; + PROPERTY_DISPLAY display = aProperty->Display(); + + switch( display ) + { + case PROPERTY_DISPLAY::SIZE: + ret = new PGPROPERTY_SIZE(); + break; + + case PROPERTY_DISPLAY::COORD: + ret = new PGPROPERTY_COORD(); + break; + + case PROPERTY_DISPLAY::DECIDEGREE: /* fall-through */ + case PROPERTY_DISPLAY::DEGREE: + { + auto prop = new PGPROPERTY_ANGLE(); + + if( display == PROPERTY_DISPLAY::DECIDEGREE ) + prop->SetScale( 10.0 ); + + ret = prop; + break; + } + + default: + wxFAIL; + /* fall through */ + case PROPERTY_DISPLAY::DEFAULT: + { + // Create a corresponding wxPGProperty + size_t typeId = aProperty->TypeHash(); + + // Enum property + if( aProperty->HasChoices() ) + { + // I do not know why enum property takes a non-const reference to wxPGChoices.. + ret = new wxEnumProperty( wxPG_LABEL, wxPG_LABEL, + const_cast( aProperty->Choices() ) ); + } + + else if( typeId == TYPE_HASH( int ) || typeId == TYPE_HASH( long ) ) + { + ret = new wxIntProperty(); + } + + else if( typeId == TYPE_HASH( unsigned int ) || typeId == TYPE_HASH( unsigned long ) ) + { + ret = new wxUIntProperty(); + } + + else if( typeId == TYPE_HASH( float ) || typeId == TYPE_HASH( double ) ) + { + ret = new wxFloatProperty(); + } + + else if( typeId == TYPE_HASH( bool ) ) + { + ret = new wxBoolProperty(); + } + + else if( typeId == TYPE_HASH( wxString ) ) + { + ret = new wxStringProperty(); + } + + else + { + wxFAIL_MSG( wxString::Format( "Property '" + aProperty->Name() + + "' is not supported by PGPropertyFactory" ) ); + ret = new wxPropertyCategory(); + ret->Enable( false ); + } + break; + } + } + + if( ret ) + { + ret->SetLabel( aProperty->Name() ); + ret->SetName( aProperty->Name() ); + ret->Enable( !aProperty->IsReadOnly() ); + ret->SetClientData( const_cast( aProperty ) ); + } + + return ret; +} + + +PGPROPERTY_DISTANCE::PGPROPERTY_DISTANCE( const wxString& aRegEx ) +{ + m_regExValidator.reset( new REGEX_VALIDATOR( aRegEx ) ); +} + + +PGPROPERTY_DISTANCE::~PGPROPERTY_DISTANCE() +{ +} + + +bool PGPROPERTY_DISTANCE::StringToDistance( wxVariant& aVariant, const wxString& aText, int aArgFlags ) const +{ + wxRegEx regDimension( m_regExValidator->GetRegEx(), wxRE_ICASE ); + wxASSERT( regDimension.IsValid() ); + + if( !regDimension.Matches( aText ) ) + { + aVariant.MakeNull(); + return false; + } + + + // Get the value + wxString valueText = regDimension.GetMatch( aText, 1 ); + double value = 0.0; + + if( !valueText.ToDouble( &value ) ) + { + aVariant.MakeNull(); + return false; + } + + + // Determine units: use the app setting if unit is not explicitly specified + EDA_UNITS unit; + wxString unitText = regDimension.GetMatch( aText, 2 ).Lower(); + + if( unitText == "mm" ) + unit = EDA_UNITS::MILLIMETRES; + else if( unitText == "in" ) + unit = EDA_UNITS::INCHES; + else + unit = PROPERTY_MANAGER::Instance().GetUnits(); + + + // Conversion to internal units + long newValueIU; + + switch( unit ) + { + case EDA_UNITS::INCHES: + newValueIU = Mils2iu( value * 1000.0 ); + break; + + case EDA_UNITS::MILLIMETRES: + newValueIU = Millimeter2iu( value ); + break; + + case EDA_UNITS::UNSCALED: + newValueIU = value; + break; + + default: + // DEGREEs are handled by PGPROPERTY_ANGLE + wxFAIL; + break; + } + + if( aVariant.IsNull() || newValueIU != aVariant.GetLong() ) + { + aVariant = newValueIU; + return true; + } + + return false; +} + + +wxString PGPROPERTY_DISTANCE::DistanceToString( wxVariant& aVariant, int aArgFlags ) const +{ + wxCHECK( aVariant.GetType() == wxPG_VARIANT_TYPE_LONG, wxEmptyString ); + + switch( PROPERTY_MANAGER::Instance().GetUnits() ) + { + case EDA_UNITS::INCHES: + return wxString::Format( wxT( "%g in" ), Iu2Mils( aVariant.GetLong() ) / 1000.0 ); + + case EDA_UNITS::MILLIMETRES: + return wxString::Format( wxT( "%g mm" ), Iu2Millimeter( aVariant.GetLong() ) ); + + case EDA_UNITS::UNSCALED: + return wxString::Format( wxT( "%li" ), aVariant.GetLong() ); + + default: + // DEGREEs are handled by PGPROPERTY_ANGLE + break; + } + + wxFAIL; + return wxEmptyString; +} + + +PGPROPERTY_SIZE::PGPROPERTY_SIZE( const wxString& aLabel, const wxString& aName, + long aValue ) + : wxUIntProperty( aLabel, aName, aValue ), PGPROPERTY_DISTANCE( REGEX_UNSIGNED_DISTANCE ) +{ +} + + +wxValidator* PGPROPERTY_SIZE::DoGetValidator() const +{ + return m_regExValidator.get(); +} + + +PGPROPERTY_COORD::PGPROPERTY_COORD( const wxString& aLabel, const wxString& aName, + long aValue ) + : wxIntProperty( aLabel, aName, aValue ), PGPROPERTY_DISTANCE( REGEX_SIGNED_DISTANCE ) +{ +} + + +wxValidator* PGPROPERTY_COORD::DoGetValidator() const +{ + return m_regExValidator.get(); +} + + +bool PGPROPERTY_ANGLE::StringToValue( wxVariant& aVariant, const wxString& aText, int aArgFlags ) const +{ + double value = 0.0; + + if( !aText.ToDouble( &value ) ) + { + aVariant.MakeNull(); + return true; + } + + value *= m_scale; + + if( aVariant.IsNull() || aVariant.GetDouble() != value ) + { + aVariant = value; + return true; + } + + return false; +} + + +wxString PGPROPERTY_ANGLE::ValueToString( wxVariant& aVariant, int aArgFlags ) const +{ + wxCHECK( aVariant.GetType() == wxPG_VARIANT_TYPE_DOUBLE, wxEmptyString ); + return wxString::Format( wxT("%g\u00B0"), aVariant.GetDouble() / m_scale ); +} diff --git a/common/widgets/properties_panel.cpp b/common/widgets/properties_panel.cpp new file mode 100644 index 0000000000..bf3e6e0383 --- /dev/null +++ b/common/widgets/properties_panel.cpp @@ -0,0 +1,149 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * @author Maciej Suminski + * + * 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 3 + * 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, see . + */ + +#include "properties_panel.h" +#include +#include +#include + +#include +#include + +using namespace std; + +PROPERTIES_PANEL::PROPERTIES_PANEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame ) + : wxPanel( aParent ), m_frame( aFrame ) +{ + wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL ); + + m_grid = new wxPropertyGrid( this, wxID_ANY, wxDefaultPosition, wxSize( 300, 400 ), + wxPG_AUTO_SORT | wxPG_SPLITTER_AUTO_CENTER | wxPG_DEFAULT_STYLE ); + m_grid->SetUnspecifiedValueAppearance( wxPGCell( "<...>" ) ); + mainSizer->Add( m_grid, 1, wxALL | wxEXPAND, 5 ); + + SetSizer( mainSizer ); + Layout(); + + Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanged ), NULL, this ); + Connect( wxEVT_PG_CHANGING, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanging ), NULL, this ); +} + + +void PROPERTIES_PANEL::update( const SELECTION& aSelection ) +{ + m_grid->Clear(); + m_displayed.clear(); + + if( aSelection.Empty() ) + return; + + // Get all the selected types + set types; + + for( EDA_ITEM* item : aSelection ) + types.insert( TYPE_HASH( *item ) ); + + wxCHECK( !types.empty(), /* void */ ); + PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); + propMgr.SetUnits( m_frame->GetUserUnits() ); + + set commonProps; + const PROPERTY_LIST& allProperties = propMgr.GetProperties( *types.begin() ); + copy( allProperties.begin(), allProperties.end(), inserter( commonProps, commonProps.begin() ) ); + + // Get all possible properties + for( const auto& type : types ) + { + const PROPERTY_LIST& itemProps = propMgr.GetProperties( type ); + + for( auto it = commonProps.begin(); it != commonProps.end(); /* ++it in the loop */ ) + { + if( !binary_search( itemProps.begin(), itemProps.end(), *it ) ) + it = commonProps.erase( it ); + else + ++it; + } + } + + // Find a set of properties that is common to all selected items + for( const auto& property : commonProps ) + { + if( !property->Available( aSelection.Front() ) ) + continue; + + // Either determine the common value for a property or "<...>" to mark multiple values + bool first = true; + bool available = true; + wxVariant commonVal, itemVal; + + for( EDA_ITEM* item : aSelection ) + { + wxVariant& value = first ? commonVal : itemVal; + + if( !first && !property->Available( item ) ) + { + // there is an item that does not have this property + available = false; + break; + } + + const wxAny& any = static_cast( item )->Get( property ); + + if( !any.GetAs( &value ) ) + { + int tmp; + + if( any.GetAs( &tmp ) ) // needed to handle enums + { + value = wxVariant( tmp ); + } + else + { + wxFAIL_MSG( "Could not convert wxAny to wxVariant" ); + // if it is an enum, be sure that there is a corresponding ENUM_TO_WXANY + available = false; + break; + } + } + + if( !first && value != commonVal ) + { + commonVal.MakeNull(); // items have different values for this property + break; + } + + first = false; + } + + if( available ) + { + wxPGProperty* pgProp = createPGProperty( property ); + + if( pgProp ) + { + pgProp->SetValue( commonVal ); + m_grid->Append( pgProp ); + m_displayed.push_back( property ); + } + } + } + + m_grid->FitColumns(); +} diff --git a/common/widgets/properties_panel.h b/common/widgets/properties_panel.h new file mode 100644 index 0000000000..302684e35a --- /dev/null +++ b/common/widgets/properties_panel.h @@ -0,0 +1,75 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Maciej Suminski + * + * 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 PROPERTIES_PANEL_H +#define PROPERTIES_PANEL_H + +#include +#include + +#include + +class EDA_BASE_FRAME; +class SELECTION; +class PROPERTY_BASE; + +class PROPERTIES_PANEL : public wxPanel +{ +public: + PROPERTIES_PANEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame ); + + virtual ~PROPERTIES_PANEL() + { + } + + virtual void Update() override = 0; + + wxPropertyGrid* GetPropertyGrid() + { + return m_grid; + } + + int PropertiesCount() const + { + return m_displayed.size(); + } + + const std::vector& Properties() const + { + return m_displayed; + } + +protected: + virtual void update( const SELECTION& aSelection ); + virtual wxPGProperty* createPGProperty( const PROPERTY_BASE* aProperty ) const = 0; + + // Event handlers + virtual void valueChanging( wxPropertyGridEvent& aEvent ) {} + virtual void valueChanged( wxPropertyGridEvent& aEvent ) {} + + std::vector m_displayed; + wxPropertyGrid* m_grid; + EDA_BASE_FRAME* m_frame; +}; + +#endif /* PROPERTIES_PANEL_H */ diff --git a/include/pg_properties.h b/include/pg_properties.h new file mode 100644 index 0000000000..6227361349 --- /dev/null +++ b/include/pg_properties.h @@ -0,0 +1,112 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * @author Maciej Suminski + * + * 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 3 + * 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, see . + */ + +#ifndef PG_PROPERTIES_H +#define PG_PROPERTIES_H + +#include +#include +#include +#include + +class PROPERTY_BASE; +class REGEX_VALIDATOR; + +wxPGProperty* PGPropertyFactory( const PROPERTY_BASE* aProperty ); + +///> Customized abstract wxPGProperty class to handle coordinate/size units +class PGPROPERTY_DISTANCE +{ +public: + PGPROPERTY_DISTANCE( const wxString& aRegEx ); + virtual ~PGPROPERTY_DISTANCE() = 0; + +protected: + bool StringToDistance( wxVariant& aVariant, const wxString& aText, int aArgFlags = 0 ) const; + wxString DistanceToString( wxVariant& aVariant, int aArgFlags = 0 ) const; + + std::unique_ptr m_regExValidator; +}; + + +class PGPROPERTY_SIZE : public wxUIntProperty, public PGPROPERTY_DISTANCE +{ +public: + PGPROPERTY_SIZE( const wxString& aLabel = wxPG_LABEL, const wxString& aName = wxPG_LABEL, + long aValue = 0 ); + + bool StringToValue( wxVariant& aVariant, const wxString& aText, int aArgFlags = 0 ) const override + { + return StringToDistance( aVariant, aText, aArgFlags ); + } + + wxString ValueToString( wxVariant& aVariant, int aArgFlags = 0 ) const override + { + return DistanceToString( aVariant, aArgFlags ); + } + + wxValidator* DoGetValidator() const override; +}; + + +class PGPROPERTY_COORD : public wxIntProperty, public PGPROPERTY_DISTANCE +{ +public: + PGPROPERTY_COORD( const wxString& aLabel = wxPG_LABEL, const wxString& aName = wxPG_LABEL, + long aValue = 0 ); + + bool StringToValue( wxVariant& aVariant, const wxString& aText, int aArgFlags = 0 ) const override + { + return StringToDistance( aVariant, aText, aArgFlags ); + } + + wxString ValueToString( wxVariant& aVariant, int aArgFlags = 0 ) const override + { + return DistanceToString( aVariant, aArgFlags ); + } + + wxValidator* DoGetValidator() const override; +}; + + +///> Customized wxPGProperty class to handle angles +class PGPROPERTY_ANGLE : public wxFloatProperty +{ +public: + PGPROPERTY_ANGLE( const wxString& aLabel = wxPG_LABEL, const wxString& aName = wxPG_LABEL, + double aValue = 0 ) + : wxFloatProperty( aLabel, aName, aValue ), m_scale( 1.0 ) + { + } + + bool StringToValue( wxVariant& aVariant, const wxString& aText, int aArgFlags = 0 ) const override; + wxString ValueToString( wxVariant& aVariant, int aArgFlags = 0 ) const override; + + void SetScale( double aScale ) + { + m_scale = aScale; + } + +protected: + ///> Scale factor to convert between raw and displayed value + double m_scale; +}; + +#endif /* PG_PROPERTIES_H */ diff --git a/include/property.h b/include/property.h index 3964de90aa..a0077fd17c 100644 --- a/include/property.h +++ b/include/property.h @@ -177,7 +177,6 @@ private: public: PROPERTY_BASE( const wxString& aName, PROPERTY_DISPLAY aDisplay = DEFAULT ) : - m_id( 0 ), m_name( aName ), m_display( aDisplay ), m_availFunc( [](INSPECTABLE*)->bool { return true; } ) @@ -281,7 +280,6 @@ protected: virtual wxAny getter( void* aObject ) const = 0; private: - const size_t m_id; const wxString m_name; const PROPERTY_DISPLAY m_display; diff --git a/include/validators.h b/include/validators.h index 86d9616d5e..449e0643b8 100644 --- a/include/validators.h +++ b/include/validators.h @@ -149,6 +149,11 @@ public: bool Validate( wxWindow* aParent ) override; + const wxString& GetRegEx() const + { + return m_regExString; + } + protected: ///< Compiles and stores a regular expression void compileRegEx( const wxString& aRegEx, int aFlags ); diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 1577929550..79cee6fbb3 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -183,6 +183,7 @@ set( PCBNEW_DIALOGS dialogs/panel_setup_text_and_graphics_base.cpp dialogs/panel_setup_tracks_and_vias.cpp dialogs/panel_setup_tracks_and_vias_base.cpp + dialogs/pcb_properties_panel.cpp footprint_wizard.cpp footprint_wizard_frame.cpp footprint_wizard_frame_functions.cpp @@ -355,6 +356,7 @@ set( PCBNEW_CLASS_SRCS tools/placement_tool.cpp tools/pcb_point_editor.cpp tools/position_relative_tool.cpp + tools/properties_tool.cpp tools/tool_event_utils.cpp tools/zone_create_helper.cpp tools/zone_filler_tool.cpp diff --git a/pcbnew/dialogs/pcb_properties_panel.cpp b/pcbnew/dialogs/pcb_properties_panel.cpp new file mode 100644 index 0000000000..082f3dfe6d --- /dev/null +++ b/pcbnew/dialogs/pcb_properties_panel.cpp @@ -0,0 +1,118 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * @author Maciej Suminski + * + * 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 3 + * 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, see . + */ + +#include "pcb_properties_panel.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +PCB_PROPERTIES_PANEL::PCB_PROPERTIES_PANEL( wxWindow* aParent, PCB_EDIT_FRAME* aFrame ) + : PROPERTIES_PANEL( aParent, aFrame ), m_frame( aFrame ), m_propMgr( PROPERTY_MANAGER::Instance() ) +{ + m_propMgr.Rebuild(); +} + + +void PCB_PROPERTIES_PANEL::Update() +{ + PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool(); + const SELECTION& selection = selectionTool->GetSelection(); + + // TODO perhaps it could be called less often? use PROPERTIES_TOOL and catch MODEL_RELOAD? + updateLists( static_cast( m_frame )->GetBoard() ); + update( selection ); +} + + +wxPGProperty* PCB_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProperty ) const +{ + return PGPropertyFactory( aProperty ); +} + + +void PCB_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent ) +{ + PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool(); + const SELECTION& selection = selectionTool->GetSelection(); + BOARD_ITEM* firstItem = static_cast( selection.Front() ); + PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *firstItem ), aEvent.GetPropertyName() ); + wxVariant newValue = aEvent.GetPropertyValue(); + BOARD_COMMIT changes( m_frame ); + + for( EDA_ITEM* edaItem : selection ) + { + BOARD_ITEM* item = static_cast( edaItem ); + changes.Modify( item ); + item->Set( property, newValue ); + } + + changes.Push( _( "Change property" ) ); + m_frame->Refresh(); +} + + +void PCB_PROPERTIES_PANEL::updateLists( const BOARD* aBoard ) +{ + wxPGChoices layersAll, layersCu, layersNonCu, nets; + + // Regenerate all layers + for( LSEQ layerSeq = aBoard->GetEnabledLayers().UIOrder(); layerSeq; ++layerSeq ) + layersAll.Add( LSET::Name( *layerSeq ), *layerSeq ); + + m_propMgr.GetProperty( TYPE_HASH( BOARD_ITEM ), _( "Layer" ) )->SetChoices( layersAll ); + + + // Regenerate non-copper layers + for( LSEQ layerSeq = LSET( LSET::AllNonCuMask() & aBoard->GetEnabledLayers() ).UIOrder(); layerSeq; ++layerSeq ) + layersNonCu.Add( LSET::Name( *layerSeq ), *layerSeq ); + + m_propMgr.GetProperty( TYPE_HASH( PCB_SHAPE ), _( "Layer" ) )->SetChoices( layersNonCu ); + + + // Regenerate copper layers + for( LSEQ layerSeq = LSET( LSET::AllCuMask() & aBoard->GetEnabledLayers() ).UIOrder(); layerSeq; ++layerSeq ) + layersCu.Add( LSET::Name( *layerSeq ), *layerSeq ); + + m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _( "Layer" ) )->SetChoices( layersCu ); + + + // Regenerate non-copper layers + for( LSEQ layerSeq = LSET( LSET::AllNonCuMask() & aBoard->GetEnabledLayers() ).UIOrder(); layerSeq; ++layerSeq ) + layersNonCu.Add( LSET::Name( *layerSeq ), *layerSeq ); + + m_propMgr.GetProperty( TYPE_HASH( PCB_SHAPE ), _( "Layer" ) )->SetChoices( layersNonCu ); + + + // Regenerate nets + for( const auto& netinfo : aBoard->GetNetInfo().NetsByNetcode() ) + { + nets.Add( netinfo.second->GetNetname(), netinfo.first ); + } + + auto netProperty = m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _( "Net" ) ); + netProperty->SetChoices( nets ); +} diff --git a/pcbnew/dialogs/pcb_properties_panel.h b/pcbnew/dialogs/pcb_properties_panel.h new file mode 100644 index 0000000000..cb867c9133 --- /dev/null +++ b/pcbnew/dialogs/pcb_properties_panel.h @@ -0,0 +1,56 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * @author Maciej Suminski + * + * 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 3 + * 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, see . + */ + +#ifndef PCB_PROPERTIES_PANEL_H +#define PCB_PROPERTIES_PANEL_H + +#include + +class SELECTION; +class BOARD; +class PCB_EDIT_FRAME; +class PROPERTY_MANAGER; + +class PCB_PROPERTIES_PANEL : public PROPERTIES_PANEL +{ +public: + PCB_PROPERTIES_PANEL( wxWindow* aParent, PCB_EDIT_FRAME* aFrame ); + + virtual ~PCB_PROPERTIES_PANEL() + { + } + + void Update() override; + +protected: + wxPGProperty* createPGProperty( const PROPERTY_BASE* aProperty ) const override; + + void valueChanged( wxPropertyGridEvent& aEvent ) override; + + ///> Regenerates caches storing layer and net names + void updateLists( const BOARD* aBoard ); + + PCB_EDIT_FRAME* m_frame; + PROPERTY_MANAGER& m_propMgr; + + wxPGChoices m_nets; +}; + +#endif /* PCB_PROPERTIES_PANEL_H */ diff --git a/pcbnew/menubar_pcb_editor.cpp b/pcbnew/menubar_pcb_editor.cpp index c2fd4feb89..8a8eaeb72d 100644 --- a/pcbnew/menubar_pcb_editor.cpp +++ b/pcbnew/menubar_pcb_editor.cpp @@ -228,6 +228,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() ACTION_MENU* viewMenu = new ACTION_MENU( false, selTool ); viewMenu->Add( PCB_ACTIONS::showLayersManager, ACTION_MENU::CHECK ); + viewMenu->Add( PCB_ACTIONS::showProperties , ACTION_MENU::CHECK ); viewMenu->Add( ACTIONS::showFootprintBrowser ); viewMenu->Add( ACTIONS::show3DViewer ); diff --git a/pcbnew/pcb_base_edit_frame.cpp b/pcbnew/pcb_base_edit_frame.cpp index f0c5a8b028..e404d3ad0c 100644 --- a/pcbnew/pcb_base_edit_frame.cpp +++ b/pcbnew/pcb_base_edit_frame.cpp @@ -37,8 +37,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -50,7 +52,9 @@ PCB_BASE_EDIT_FRAME::PCB_BASE_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent, PCB_BASE_FRAME( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ), m_undoRedoBlocked( false ), m_selectionFilterPanel( nullptr ), - m_appearancePanel( nullptr ) + m_appearancePanel( nullptr ), + m_propertiesPanel( nullptr ), + m_tabbedPanel( nullptr ) { Bind( wxEVT_IDLE, [this]( wxIdleEvent& aEvent ) @@ -256,6 +260,7 @@ void PCB_BASE_EDIT_FRAME::unitsChangeRefresh() } ReCreateAuxiliaryToolbar(); + UpdateProperties(); } @@ -303,3 +308,11 @@ void PCB_BASE_EDIT_FRAME::handleActivateEvent( wxActivateEvent& aEvent ) } +void PCB_BASE_EDIT_FRAME::UpdateProperties() +{ + if( !m_propertiesPanel || !m_propertiesPanel->IsShownOnScreen() ) + return; + + m_propertiesPanel->Update(); +} + diff --git a/pcbnew/pcb_base_edit_frame.h b/pcbnew/pcb_base_edit_frame.h index 065bc6128f..918bf45a1f 100644 --- a/pcbnew/pcb_base_edit_frame.h +++ b/pcbnew/pcb_base_edit_frame.h @@ -32,6 +32,7 @@ class APPEARANCE_CONTROLS; class BOARD_ITEM_CONTAINER; class PANEL_SELECTION_FILTER; +class PROPERTIES_PANEL; /** * Common, abstract interface for edit frames. @@ -214,6 +215,10 @@ public: APPEARANCE_CONTROLS* GetAppearancePanel() { return m_appearancePanel; } + PROPERTIES_PANEL* GetPropertiesPanel() { return m_propertiesPanel; } + + void UpdateProperties(); + protected: /** * Prompts a user to select global or project library tables @@ -241,6 +246,10 @@ protected: PANEL_SELECTION_FILTER* m_selectionFilterPanel; APPEARANCE_CONTROLS* m_appearancePanel; + PROPERTIES_PANEL* m_propertiesPanel; + + /// Panel with Layers and Object Inspector tabs + wxAuiNotebook* m_tabbedPanel; }; #endif diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index ac77439853..ea07dddaeb 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,7 @@ #include #include #include +#include #include #include #include @@ -188,6 +190,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : m_show_layer_manager_tools = true; m_supportsAutoSave = true; m_probingSchToPcb = false; + m_show_properties = true; // We don't know what state board was in when it was last saved, so we have to // assume dirty @@ -207,7 +210,6 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : EDA_DRAW_PANEL_GAL::GAL_FALLBACK ); SetCanvas( canvas ); - SetBoard( new BOARD() ); wxIcon icon; @@ -222,6 +224,12 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : SetIcons( icon_bundle ); + m_tabbedPanel = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxAUI_NB_BOTTOM | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | + wxAUI_NB_SCROLL_BUTTONS ); + + m_propertiesPanel = new PCB_PROPERTIES_PANEL( m_tabbedPanel, this ); + // LoadSettings() *after* creating m_LayersManager, because LoadSettings() // initialize parameters in m_LayersManager LoadSettings( config() ); @@ -281,6 +289,11 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : .Caption( _( "Selection Filter" ) ).PaneBorder( false ) .MinSize( 180, -1 ).BestSize( 180, -1 ) ); + m_auimgr.AddPane( m_tabbedPanel, // TODO check + EDA_PANE().Palette().Name( "TabbedPanel" ).Right().Layer( 3 ) + .PaneBorder( false ).MinSize( 300, -1 ) + .TopDockable( false ).BottomDockable( false ) ); + // Center m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" ) .Center() ); @@ -566,6 +579,7 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new CONVERT_TOOL ); m_toolManager->RegisterTool( new GROUP_TOOL ); m_toolManager->RegisterTool( new SCRIPTING_TOOL ); + m_toolManager->RegisterTool( new PROPERTIES_TOOL ); m_toolManager->InitTools(); for( TOOL_BASE* tool : m_toolManager->Tools() ) @@ -1006,7 +1020,10 @@ void PCB_EDIT_FRAME::doCloseWindow() // on some platforms (Windows) that generate useless redraw of items in // the Layer Manager if( m_show_layer_manager_tools ) + { m_auimgr.GetPane( "LayersManager" ).Show( false ); + m_auimgr.GetPane( "TabbedPanel" ).Show( false ); + } // Unlink the old project if needed GetBoard()->ClearProject(); @@ -1100,6 +1117,7 @@ void PCB_EDIT_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg ) if( cfg ) { m_show_layer_manager_tools = cfg->m_AuiPanels.show_layer_manager; + m_show_properties = cfg->m_AuiPanels.show_properties; } } @@ -1116,6 +1134,7 @@ void PCB_EDIT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg ) cfg->m_AuiPanels.show_layer_manager = m_show_layer_manager_tools; cfg->m_AuiPanels.right_panel_width = m_appearancePanel->GetSize().x; cfg->m_AuiPanels.appearance_panel_tab = m_appearancePanel->GetTabIndex(); + cfg->m_AuiPanels.show_properties = m_show_properties; } } diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h index 17746e4ad0..788c3adaaf 100644 --- a/pcbnew/pcb_edit_frame.h +++ b/pcbnew/pcb_edit_frame.h @@ -148,7 +148,10 @@ public: // User interface update command event handlers. void OnUpdateLayerSelectBox( wxUpdateUIEvent& aEvent ); + bool LayerManagerShown(); + bool PropertiesShown(); + void OnUpdateSelectViaSize( wxUpdateUIEvent& aEvent ); void OnUpdateSelectTrackWidth( wxUpdateUIEvent& aEvent ); void OnUpdateSelectAutoWidth( wxUpdateUIEvent& aEvent ); @@ -294,6 +297,7 @@ public: void PrepareLayerIndicator( bool aForceRebuild = false ); void ToggleLayersManager(); + void ToggleProperties(); /** * Create an ASCII footprint position file. @@ -805,6 +809,7 @@ public: wxChoice* m_SelViaSizeBox; // a choice box to display and select current via diameter bool m_show_layer_manager_tools; + bool m_show_properties; bool m_ZoneFillsDirty; // Board has been modified since last zone fill. diff --git a/pcbnew/pcb_layer_widget.cpp b/pcbnew/pcb_layer_widget.cpp new file mode 100644 index 0000000000..f78c2b3af0 --- /dev/null +++ b/pcbnew/pcb_layer_widget.cpp @@ -0,0 +1,708 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2017 Jean-Pierre Charras, jean-pierre.charras@gpisa-lab.inpg.fr + * Copyright (C) 2010-2012 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010-2017 KiCad Developers, see change_log.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/// This is a read only template that is copied and modified before adding to LAYER_WIDGET +const LAYER_WIDGET::ROW PCB_LAYER_WIDGET::s_render_rows[] = { + +#define RR LAYER_WIDGET::ROW // Render Row abbreviation to reduce source width +#define NOCOLOR COLOR4D::UNSPECIFIED // specify rows that do not have a color selector icon + + // text id color tooltip + RR( _( "Footprints Front" ), LAYER_MOD_FR, NOCOLOR, _( "Show footprints that are on board's front") ), + RR( _( "Footprints Back" ), LAYER_MOD_BK, NOCOLOR, _( "Show footprints that are on board's back") ), + RR( _( "Values" ), LAYER_MOD_VALUES, NOCOLOR, _( "Show footprint values") ), + RR( _( "Reference Designators" ),LAYER_MOD_REFERENCES, NOCOLOR, _( "Show footprint reference designators") ), + RR( _( "Footprint Text Front" ), LAYER_MOD_TEXT_FR, NOCOLOR, _( "Show footprint text on board's front" ) ), + RR( _( "Footprint Text Back" ), LAYER_MOD_TEXT_BK, NOCOLOR, _( "Show footprint text on board's back" ) ), + RR( _( "Hidden Text" ), LAYER_MOD_TEXT_INVISIBLE, WHITE, _( "Show footprint text marked as invisible" ) ), + RR( _( "Pads Front" ), LAYER_PAD_FR, WHITE, _( "Show footprint pads on board's front" ) ), + RR( _( "Pads Back" ), LAYER_PAD_BK, WHITE, _( "Show footprint pads on board's back" ) ), + RR( _( "Through Hole Pads" ), LAYER_PADS_TH, YELLOW, _( "Show through hole pads in specific color") ), + RR(), + RR( _( "Tracks" ), LAYER_TRACKS, NOCOLOR, _( "Show tracks" ) ), + RR( _( "Through Via" ), LAYER_VIA_THROUGH, WHITE, _( "Show through vias" ) ), + RR( _( "Bl/Buried Via" ), LAYER_VIA_BBLIND, WHITE, _( "Show blind or buried vias" ) ), + RR( _( "Micro Via" ), LAYER_VIA_MICROVIA, WHITE, _( "Show micro vias") ), + RR( _( "Non Plated Holes" ), LAYER_NON_PLATEDHOLES, WHITE, _( "Show non plated holes in specific color") ), + RR(), + RR( _( "Ratsnest" ), LAYER_RATSNEST, WHITE, _( "Show unconnected nets as a ratsnest") ), + RR( _( "No-Connects" ), LAYER_NO_CONNECTS, BLUE, _( "Show a marker on pads which have no net connected" ) ), + RR( _( "DRC Warnings" ), LAYER_DRC_WARNING, YELLOW, _( "DRC violations with a Warning severity" ) ), + RR( _( "DRC Errors" ), LAYER_DRC_ERROR, PURERED, _( "DRC violations with an Error severity" ) ), + RR( _( "Anchors" ), LAYER_ANCHOR, WHITE, _( "Show footprint and text origins as a cross" ) ), + RR( _( "Worksheet" ), LAYER_WORKSHEET, DARKRED, _( "Show worksheet") ), + RR( _( "Cursor" ), LAYER_CURSOR, WHITE, _( "PCB Cursor" ), true, false ), + RR( _( "Aux Items" ), LAYER_AUX_ITEMS, WHITE, _( "Auxiliary items (rulers, assistants, axes, etc.)" ), true, false ), + RR( _( "Grid" ), LAYER_GRID, WHITE, _( "Show the (x,y) grid dots" ) ), + RR( _( "Background" ), LAYER_PCB_BACKGROUND, BLACK, _( "PCB Background" ), true, false ) +}; + +static int s_allowed_in_FpEditor[] = +{ + LAYER_MOD_TEXT_INVISIBLE, + LAYER_NON_PLATEDHOLES, + LAYER_PADS_TH, + LAYER_PAD_FR, + LAYER_PAD_BK, + LAYER_MOD_VALUES, + LAYER_MOD_REFERENCES, + LAYER_CURSOR, + LAYER_AUX_ITEMS, + LAYER_GRID, + LAYER_PCB_BACKGROUND +}; + + +PCB_LAYER_WIDGET::PCB_LAYER_WIDGET( wxWindow* aParent, PCB_BASE_FRAME* aFrame, wxWindow* aFocusOwner, + bool aFpEditorMode ) : + LAYER_WIDGET( aParent, aFocusOwner ), + myframe( aFrame ) +{ + m_alwaysShowActiveCopperLayer = false; + m_fp_editor_mode = aFpEditorMode; + + // Update default tabs labels + SetLayersManagerTabsText(); + + //------------------------------------------------------ + // handle the popup menu over the layer window. + m_LayerScrolledWindow->Connect( wxEVT_RIGHT_DOWN, + wxMouseEventHandler( PCB_LAYER_WIDGET::onRightDownLayers ), NULL, this ); + + // since Popupmenu() calls this->ProcessEvent() we must call this->Connect() + // and not m_LayerScrolledWindow->Connect() + + Connect( ID_SHOW_ALL_COPPER_LAYERS, ID_LAST_VALUE - 1, + wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler( PCB_LAYER_WIDGET::onPopupSelection ), NULL, this ); +} + + +COLOR4D PCB_LAYER_WIDGET::getBackgroundLayerColor() +{ + return myframe->GetColorSettings()->GetColor( LAYER_PCB_BACKGROUND ); +} + + +bool PCB_LAYER_WIDGET::isAllowedInFpMode( int aId ) +{ + for( unsigned ii = 0; ii < arrayDim( s_allowed_in_FpEditor ); ii++ ) + if( s_allowed_in_FpEditor[ii] == aId ) + return true; + + return false; +} + + +bool PCB_LAYER_WIDGET::isLayerAllowedInFpMode( PCB_LAYER_ID aLayer ) +{ + static LSET allowed = LSET::AllTechMask(); + allowed.set( F_Cu ).set( B_Cu ); + return allowed.test( aLayer ); +} + + +void PCB_LAYER_WIDGET::AddRightClickMenuItems( wxMenu& menu ) +{ + AddMenuItem( &menu, ID_SHOW_ALL_COPPER_LAYERS, + _( "Show All Copper Layers" ), + KiBitmap( select_layer_pair_xpm ) ); + AddMenuItem( &menu, ID_HIDE_ALL_COPPER_LAYERS, + _( "Hide All Copper Layers" ), + KiBitmap( show_no_copper_layers_xpm ) ); + + menu.AppendSeparator(); + + AddMenuItem( &menu, ID_HIDE_ALL_COPPER_LAYERS_BUT_ACTIVE, + _( "Hide All Copper Layers But Active" ), + KiBitmap( select_w_layer_xpm ) ); + AddMenuItem( &menu, ID_ALWAYS_HIDE_ALL_COPPER_LAYERS_BUT_ACTIVE, + _( "Always Hide All Copper Layers But Active" ), + KiBitmap( select_w_layer_xpm ) ); + + menu.AppendSeparator(); + + AddMenuItem( &menu, ID_SHOW_ALL_NON_COPPER, + _( "Show All Non Copper Layers" ), + KiBitmap( select_w_layer_xpm ) ); + AddMenuItem( &menu, ID_HIDE_ALL_NON_COPPER, + _( "Hide All Non Copper Layers" ), + KiBitmap( show_no_copper_layers_xpm ) ); + + menu.AppendSeparator(); + + AddMenuItem( &menu, ID_SHOW_ALL_LAYERS, _( "Show All Layers" ), + KiBitmap( show_all_layers_xpm ) ); + AddMenuItem( &menu, ID_SHOW_NO_LAYERS, _( "Hide All Layers" ), + KiBitmap( show_no_layers_xpm ) ); + + menu.AppendSeparator(); + + AddMenuItem( &menu, ID_SHOW_ONLY_FRONT_ASSEMBLY, _( "Show Only Front Assembly Layers" ), + KiBitmap( shape_3d_xpm ) ); + + AddMenuItem( &menu, ID_SHOW_ONLY_FRONT, _( "Show Only Front Layers" ), + KiBitmap( show_all_front_layers_xpm ) ); + + // Only show the internal layer option if internal layers are enabled + if( myframe->GetBoard()->GetCopperLayerCount() > 2 ) + { + AddMenuItem( &menu, ID_SHOW_ONLY_INNER, _( "Show Only Inner Layers" ), + KiBitmap( show_all_copper_layers_xpm ) ); + } + + AddMenuItem( &menu, ID_SHOW_ONLY_BACK, _( "Show Only Back Layers" ), + KiBitmap( show_all_back_layers_xpm ) ); + + AddMenuItem( &menu, ID_SHOW_ONLY_BACK_ASSEMBLY, _( "Show Only Back Assembly Layers" ), + KiBitmap( shape_3d_back_xpm ) ); +} + + +void PCB_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event ) +{ + wxMenu menu; + + AddRightClickMenuItems( menu ); + PopupMenu( &menu ); + + passOnFocus(); +} + + +void PCB_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event ) +{ + // Force the active layer to be visible + bool forceActiveLayer = false; + + // Reset the always show property + m_alwaysShowActiveCopperLayer = false; + + // Make a distinction between the layers we want to enable and those we + // want to disable explictly. That way we can either or the current layerset + // or operate on all layers. + LSET layersToShow; + LSET layersToHide; + + switch( event.GetId() ) + { + case ID_SHOW_NO_LAYERS: + layersToHide = LSET::AllLayersMask(); + break; + + case ID_SHOW_ALL_LAYERS: + layersToShow = LSET::AllLayersMask(); + break; + + case ID_SHOW_ALL_COPPER_LAYERS: + layersToShow = LSET::AllCuMask(); + break; + + case ID_ALWAYS_HIDE_ALL_COPPER_LAYERS_BUT_ACTIVE: + m_alwaysShowActiveCopperLayer = true; + KI_FALLTHROUGH; + + case ID_HIDE_ALL_COPPER_LAYERS_BUT_ACTIVE: + forceActiveLayer = true; + KI_FALLTHROUGH; + + case ID_HIDE_ALL_COPPER_LAYERS: + layersToHide = LSET::AllCuMask(); + break; + + case ID_HIDE_ALL_NON_COPPER: + layersToHide = LSET::AllNonCuMask(); + break; + + case ID_SHOW_ALL_NON_COPPER: + layersToShow = LSET::AllNonCuMask(); + break; + + case ID_SHOW_ONLY_FRONT_ASSEMBLY: + // Include the edgecuts layer as well as the front assembly layers and hide the other layers + layersToShow = LSET::FrontAssembly().set( Edge_Cuts ); + layersToHide = ~layersToShow; + myframe->SetActiveLayer( F_SilkS ); + break; + + case ID_SHOW_ONLY_FRONT: + // Include the edgecuts layer as well as the front layers and hide the other layers + layersToShow = LSET::FrontMask().set( Edge_Cuts ); + layersToHide = ~layersToShow; + break; + + case ID_SHOW_ONLY_INNER: + // Include the edgecuts layer as well as the internal layers and hide the other layers + layersToShow = LSET::InternalCuMask().set( Edge_Cuts ); + layersToHide = ~layersToShow; + break; + + case ID_SHOW_ONLY_BACK: + // Include the edgecuts layer as well as the back layers and hide the other layers + layersToShow = LSET::BackMask().set( Edge_Cuts ); + layersToHide = ~layersToShow; + break; + + case ID_SHOW_ONLY_BACK_ASSEMBLY: + // Include the edgecuts layer as well as the back assembly layers and hide the other layers + layersToShow = LSET::BackAssembly().set( Edge_Cuts ); + layersToHide = ~layersToShow; + myframe->SetActiveLayer( B_SilkS ); + break; + } + + int rowCount = GetLayerRowCount(); + + for( int row = 0; row < rowCount; ++row ) + { + wxCheckBox* cb = static_cast( getLayerComp( row, COLUMN_COLOR_LYR_CB ) ); + PCB_LAYER_ID layer = ToLAYER_ID( getDecodedId( cb->GetId() ) ); + + bool visible = cb->GetValue(); + + if( layersToShow.Contains( layer ) ) + visible = true; + + if( layersToHide.Contains( layer ) ) + visible = false; + + // Force the active layer in the editor to be visible + if( forceActiveLayer && ( layer == myframe->GetActiveLayer() ) ) + visible = true; + + cb->SetValue( visible ); + OnLayerVisible( layer, visible, false ); + } + + // Refresh the drawing canvas + myframe->GetCanvas()->Refresh(); +} + + +void PCB_LAYER_WIDGET::SetLayersManagerTabsText() +{ + m_notebook->SetPageText( 0, _( "Layers" ) ); + m_notebook->SetPageText( 1, _( "Items" ) ); +} + + +void PCB_LAYER_WIDGET::ReFillRender() +{ + BOARD* board = myframe->GetBoard(); + + ClearRenderRows(); + + // Add "Items" tab rows to LAYER_WIDGET, after setting color and checkbox state. + // Because s_render_rows is created static, we must explicitly call + // wxGetTranslation for texts which are internationalized (tool tips + // and item names) + for( unsigned row=0; rowGetColorSettings()->GetColor( + static_cast( renderRow.id ) ); + renderRow.defaultColor = myframe->GetColorSettings()->GetDefaultColor( + static_cast( renderRow.id ) ); + } + + if( renderRow.id == LAYER_RATSNEST ) + renderRow.state = myframe->GetDisplayOptions().m_ShowGlobalRatsnest; + else if( renderRow.id == LAYER_GRID ) + renderRow.state = myframe->IsGridVisible(); + else + renderRow.state = board->IsElementVisible( + static_cast( renderRow.id ) ); + } + + AppendRenderRow( renderRow ); + } + + UpdateLayouts(); +} + + +void PCB_LAYER_WIDGET::SyncLayerVisibilities() +{ + BOARD* board = myframe->GetBoard(); + int count = GetLayerRowCount(); + + for( int row=0; rowGetId() ) ); + + // this does not fire a UI event + setLayerCheckbox( layerId, board->IsLayerVisible( layerId ) ); + } +} + + +#define ALPHA_EPSILON 0.04 + +void PCB_LAYER_WIDGET::SyncLayerAlphaIndicators() +{ + int count = GetLayerRowCount(); + TOOL_MANAGER* mgr = myframe->GetToolManager(); + KIGFX::PCB_PAINTER* painter = static_cast( mgr->GetView()->GetPainter() ); + KIGFX::PCB_RENDER_SETTINGS* settings = painter->GetSettings(); + + for( int row = 0; row < count; ++row ) + { + // this utilizes more implementation knowledge than ideal, eventually + // add member ROW getRow() or similar to base LAYER_WIDGET. + + wxWindow* w = getLayerComp( row, COLUMN_ICON_ACTIVE ); + PCB_LAYER_ID layerId = ToLAYER_ID( getDecodedId( w->GetId() ) ); + KIGFX::COLOR4D screenColor = settings->GetLayerColor( layerId ); + + COLOR_SWATCH* swatch = static_cast( getLayerComp( row, COLUMN_COLORBM ) ); + KIGFX::COLOR4D layerColor = swatch->GetSwatchColor(); + + INDICATOR_ICON* indicator = static_cast( getLayerComp( row, COLUMN_ALPHA_INDICATOR ) ); + + if( std::abs( screenColor.a - layerColor.a ) > ALPHA_EPSILON ) + { + if( screenColor.a < layerColor.a ) + indicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::DOWN ); + else + indicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::UP ); + } + else + indicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::OFF ); + } +} + + +void PCB_LAYER_WIDGET::SyncLayerColors() +{ + COLOR_SETTINGS* cs = myframe->GetColorSettings(); + + COLOR4D bg = cs->GetColor( LAYER_PCB_BACKGROUND ); + + int count = GetLayerRowCount(); + int row; + int col = 1; // bitmap button is column 1 in layers tab + + for( row = 0; row < count; ++row ) + { + COLOR_SWATCH* swatch = dynamic_cast( getLayerComp( row, col ) ); + + if( swatch ) + { + swatch->SetSwatchBackground( bg ); + swatch->SetSwatchColor( cs->GetColor( getDecodedId( swatch->GetId() ) ), false ); + } + } + + count = GetRenderRowCount(); + col = 0; // bitmap button is column 0 in render tab + + for( row = 0; row < count; ++row ) + { + COLOR_SWATCH* swatch = dynamic_cast( getRenderComp( row, col ) ); + + if( swatch ) + { + swatch->SetSwatchBackground( bg ); + swatch->SetSwatchColor( cs->GetColor( getDecodedId( swatch->GetId() ) ), false ); + } + } +} + + +void PCB_LAYER_WIDGET::ReFill() +{ + BOARD* brd = myframe->GetBoard(); + LSET enabled = brd->GetEnabledLayers(); + + ClearLayerRows(); + + wxString dsc; + + // show all coppers first, with front on top, back on bottom, then technical layers + for( LSEQ cu_stack = enabled.CuStack(); cu_stack; ++cu_stack ) + { + PCB_LAYER_ID layer = *cu_stack; + + switch( layer ) + { + case F_Cu: + dsc = _( "Front copper layer" ); + break; + + case B_Cu: + dsc = _( "Back copper layer" ); + break; + + default: + dsc = _( "Inner copper layer" ); + break; + } + + AppendLayerRow( LAYER_WIDGET::ROW( brd->GetLayerName( layer ), layer, + myframe->GetColorSettings()->GetColor( layer ), dsc, true, true, + myframe->GetColorSettings()->GetDefaultColor( layer ) ) ); + + if( m_fp_editor_mode && LSET::ForbiddenFootprintLayers().test( layer ) ) + { + getLayerComp( GetLayerRowCount()-1, COLUMN_COLOR_LYRNAME )->Enable( false ); + getLayerComp( GetLayerRowCount()-1, COLUMN_COLORBM )->SetToolTip( wxEmptyString ); + } + } + + UpdateLayouts(); + + + // technical layers are shown in this order: + // Because they are static, wxGetTranslation must be explicitly + // called for tooltips. + static const struct { + PCB_LAYER_ID layerId; + wxString tooltip; + } non_cu_seq[] = { + { F_Adhes, _( "Adhesive on board's front" ) }, + { B_Adhes, _( "Adhesive on board's back" ) }, + { F_Paste, _( "Solder paste on board's front" ) }, + { B_Paste, _( "Solder paste on board's back" ) }, + { F_SilkS, _( "Silkscreen on board's front" ) }, + { B_SilkS, _( "Silkscreen on board's back" ) }, + { F_Mask, _( "Solder mask on board's front" ) }, + { B_Mask, _( "Solder mask on board's back" ) }, + { Dwgs_User, _( "Explanatory drawings" ) }, + { Cmts_User, _( "Explanatory comments" ) }, + { Eco1_User, _( "User defined meaning" ) }, + { Eco2_User, _( "User defined meaning" ) }, + { Edge_Cuts, _( "Board's perimeter definition" ) }, + { Margin, _( "Board's edge setback outline" ) }, + { F_CrtYd, _( "Footprint courtyards on board's front" ) }, + { B_CrtYd, _( "Footprint courtyards on board's back" ) }, + { F_Fab, _( "Footprint assembly on board's front" ) }, + { B_Fab, _( "Footprint assembly on board's back" ) } + }; + + for( unsigned i=0; iGetLayerName( layer ), layer, + myframe->GetColorSettings()->GetColor( layer ), + wxGetTranslation( non_cu_seq[i].tooltip ), true, true, + myframe->GetColorSettings()->GetDefaultColor( layer ) ) ); + + if( m_fp_editor_mode && LSET::ForbiddenFootprintLayers().test( layer ) ) + { + getLayerComp( GetLayerRowCount()-1, COLUMN_COLOR_LYRNAME )->Enable( false ); + getLayerComp( GetLayerRowCount()-1, COLUMN_COLORBM )->SetToolTip( wxEmptyString ); + } + } +} + + +//------------------------------------------------ + +void PCB_LAYER_WIDGET::OnLayerColorChange( int aLayer, COLOR4D aColor ) +{ + COLOR_SETTINGS* cs = myframe->GetColorSettings(); + cs->SetColor( aLayer, aColor ); + + myframe->GetCanvas()->UpdateColors(); + + KIGFX::VIEW* view = myframe->GetCanvas()->GetView(); + view->UpdateLayerColor( aLayer ); + view->UpdateLayerColor( GetNetnameLayer( aLayer ) ); + + myframe->ReCreateHToolbar(); + + myframe->GetCanvas()->Refresh(); + + if( aLayer == LAYER_PCB_BACKGROUND ) + myframe->SetDrawBgColor( aColor ); +} + + +bool PCB_LAYER_WIDGET::OnLayerSelect( int aLayer ) +{ + // the layer change from the PCB_LAYER_WIDGET can be denied by returning + // false from this function. + PCB_LAYER_ID layer = ToLAYER_ID( aLayer ); + + if( m_fp_editor_mode && LSET::ForbiddenFootprintLayers().test( layer ) ) + return false; + + myframe->SetActiveLayer( layer ); + + bool hcm = ( myframe->GetDisplayOptions().m_ContrastModeDisplay != + HIGH_CONTRAST_MODE::NORMAL ); + + if( m_alwaysShowActiveCopperLayer ) + OnLayerSelected(); + else if( hcm ) + myframe->GetCanvas()->Refresh(); + + return true; +} + + +bool PCB_LAYER_WIDGET::OnLayerSelected() +{ + if( !m_alwaysShowActiveCopperLayer ) + return false; + + // postprocess after an active layer selection + // ensure active layer visible + wxCommandEvent event; + event.SetId( ID_ALWAYS_HIDE_ALL_COPPER_LAYERS_BUT_ACTIVE ); + onPopupSelection( event ); + + return true; +} + + +void PCB_LAYER_WIDGET::OnLayerVisible( int aLayer, bool isVisible, bool isFinal ) +{ + // In other frames than board editor, the board is a dummy board. + // so changing board settings makes sense (and works) only for the board editor frame + if( myframe->IsType( FRAME_PCB_EDITOR ) ) + { + BOARD* brd = myframe->GetBoard(); + + LSET visibleLayers = brd->GetVisibleLayers(); + + if( visibleLayers.test( aLayer ) != isVisible ) + { + visibleLayers.set( aLayer, isVisible ); + brd->SetVisibleLayers( visibleLayers ); + + if( myframe->GetCanvas() ) + myframe->GetCanvas()->GetView()->SetLayerVisible( aLayer, isVisible ); + } + } + else + if( myframe->GetCanvas() ) + myframe->GetCanvas()->GetView()->SetLayerVisible( aLayer, isVisible ); + + if( isFinal ) + myframe->GetCanvas()->Refresh(); +} + + +void PCB_LAYER_WIDGET::OnLayerRightClick( wxMenu& aMenu ) +{ + AddRightClickMenuItems( aMenu ); +} + + +void PCB_LAYER_WIDGET::OnRenderColorChange( int aId, COLOR4D aColor ) +{ + wxASSERT( aId > GAL_LAYER_ID_START && aId < GAL_LAYER_ID_END ); + + myframe->GetColorSettings()->SetColor( aId, aColor ); + myframe->GetCanvas()->UpdateColors(); + + KIGFX::VIEW* view = myframe->GetCanvas()->GetView(); + view->MarkTargetDirty( KIGFX::TARGET_NONCACHED ); // useful to update rastnest + view->UpdateLayerColor( aId ); + + // plated-through-holes don't have their own color; they use the background color + if( aId == LAYER_PCB_BACKGROUND ) + view->UpdateLayerColor( LAYER_PADS_PLATEDHOLES ); + + myframe->ReCreateHToolbar(); + myframe->GetCanvas()->ForceRefresh(); + myframe->GetCanvas()->Refresh(); +} + + +void PCB_LAYER_WIDGET::OnRenderEnable( int aId, bool isEnabled ) +{ + BOARD* brd = myframe->GetBoard(); + wxASSERT( aId > GAL_LAYER_ID_START && aId < GAL_LAYER_ID_END ); + + // Grid is not set through the board visibility + if( aId == LAYER_GRID ) + myframe->SetGridVisibility( isEnabled ); + else + brd->SetElementVisibility( static_cast( aId ), isEnabled ); + + if( aId == LAYER_RATSNEST ) + { + // don't touch the layers. ratsnest is enabled on per-item basis. + myframe->GetCanvas()->GetView()->MarkTargetDirty( KIGFX::TARGET_NONCACHED ); + myframe->GetCanvas()->GetView()->SetLayerVisible( aId, true ); + + if( myframe->IsType( FRAME_PCB_EDITOR ) ) + { + PCB_DISPLAY_OPTIONS opt = myframe->GetDisplayOptions(); + opt.m_ShowGlobalRatsnest = isEnabled; + myframe->GetCanvas()->GetView()->UpdateDisplayOptions( opt ); + } + } + else if( aId != LAYER_GRID ) + myframe->GetCanvas()->GetView()->SetLayerVisible( aId, isEnabled ); + + myframe->GetCanvas()->Refresh(); + myframe->GetCanvas()->Refresh(); +} + +//----------------------------------------------- diff --git a/pcbnew/pcb_layer_widget.h b/pcbnew/pcb_layer_widget.h new file mode 100644 index 0000000000..e46e124854 --- /dev/null +++ b/pcbnew/pcb_layer_widget.h @@ -0,0 +1,182 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010-2018 KiCad Developers, see cAUTHORS.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 + */ + + +/************************************************************/ +/* pcb_layer_widget.h : header for the layers manager */ +/************************************************************/ + +#ifndef PCB_LAYER_WIDGET_H +#define PCB_LAYER_WIDGET_H + +#include + +/** + * PCB_LAYER_WIDGET + * is here to implement the abstract functions of LAYER_WIDGET so they + * may be tied into the PCB_EDIT_FRAME's data and so we can add a popup + * menu which is specific to PCBNEW's needs. + */ +class PCB_LAYER_WIDGET : public LAYER_WIDGET +{ +public: + + /** + * Constructor + * @param aParent is the parent window + * @param aFocusOwner is the window that should be sent the focus after + * @param aFpEditorMode false for the board editor (default), true for fp editor + * when true, some options or layers which cannot be used in editor mode are not + * displayed + */ + PCB_LAYER_WIDGET( wxWindow* aParent, PCB_BASE_FRAME* aFrame, wxWindow* aFocusOwner, bool aFpEditorMode = false ); + + void ReFill(); + + /** + * Function ReFillRender + * rebuilds Render for instance after the config is read + */ + void ReFillRender(); + + /** + * Function SyncLayerVisibilities + * updates each "Layer" checkbox in this layer widget according + * to each layer's current visibility determined by IsLayerVisible(), and is + * helpful immediately after loading a BOARD which may have state information in it. + */ + void SyncLayerVisibilities(); + + /** + * Function SyncLayerAlphaIndicators + * updates each "Layer"s alpha indicator to show if the board is currently being + * rendered with more transparency or less. + */ + void SyncLayerAlphaIndicators(); + + /** + * Updates the color for each layer and item from the active color theme + */ + void SyncLayerColors(); + + /** + * Function SetLayersManagerTabsText + * Update the layer manager tabs labels + * Useful when changing Language or to set labels to a non default value + */ + void SetLayersManagerTabsText(); + + //---------------- + void OnLayerColorChange( int aLayer, COLOR4D aColor ) override; + bool OnLayerSelect( int aLayer ) override; + void OnLayerVisible( int aLayer, bool isVisible, bool isFinal ) override; + void OnLayerRightClick( wxMenu& aMenu ) override; + void OnRenderColorChange( int aId, COLOR4D aColor ) override; + void OnRenderEnable( int aId, bool isEnabled ) override; + //--------------- + + /** + * Function OnLayerSelected + * ensure the active layer is visible, and other layers not visible + * when m_alwaysShowActiveLayer is true + * Otherwise do nothing. + * @return true m_alwaysShowActiveLayer is true and the canvas is refreshed, + * and false if do nothing + */ + bool OnLayerSelected(); // postprocess after an active layer selection + // ensure active layer visible if + // m_alwaysShowActiveCopperLayer is true; + + /** + * Function addRightClickMenuItems + * add menu items to a menu that should be shown when right-clicking + * the PCB layer widget. + */ + void AddRightClickMenuItems( wxMenu& menu ); + + +protected: + + static const LAYER_WIDGET::ROW s_render_rows[]; + bool m_alwaysShowActiveCopperLayer; // If true: Only shows the current active layer + // even if it is changed + bool m_fp_editor_mode; + + PCB_BASE_FRAME* myframe; + + // popup menu ids. + enum POPUP_ID + { + ID_SHOW_ALL_COPPER_LAYERS = LAYER_WIDGET::ID_LAST_VALUE, + ID_HIDE_ALL_COPPER_LAYERS, + ID_HIDE_ALL_COPPER_LAYERS_BUT_ACTIVE, + ID_ALWAYS_HIDE_ALL_COPPER_LAYERS_BUT_ACTIVE, + ID_SHOW_NO_LAYERS, + ID_SHOW_ALL_LAYERS, + ID_SHOW_ONLY_FRONT, + ID_SHOW_ONLY_INNER, + ID_SHOW_ONLY_BACK, + ID_SHOW_ONLY_FRONT_ASSEMBLY, + ID_SHOW_ONLY_BACK_ASSEMBLY, + ID_HIDE_ALL_NON_COPPER, + ID_SHOW_ALL_NON_COPPER, + ID_LAST_VALUE + }; + + virtual COLOR4D getBackgroundLayerColor() override; + + /** + * Function isAllowedInFpMode + * @return true if item aId has meaning in footprint editor mode. + * and therefore is shown in render panel + */ + bool isAllowedInFpMode( int aId ); + + /** + * Function isLayerAllowedInFpMode + * + * User layers, which are not paired, are not shown in layers manager. However a not + * listed layer can be reachable in the graphic item properties dialog. + * + * @param aLayer is the layer id to test + * @return true if PCB_LAYER_ID aLayer has meaning in footprint editor mode. + * and therefore is shown in render panel + */ + bool isLayerAllowedInFpMode( PCB_LAYER_ID aLayer ); + + /** + * Function OnRightDownLayers + * puts up a popup menu for the layer panel. + */ + void onRightDownLayers( wxMouseEvent& event ); + + void onPopupSelection( wxCommandEvent& event ); + + /// this is for the popup menu, the right click handler has to be installed + /// on every child control within the layer panel. + void installRightLayerClickHandler(); +}; + +#endif // PCB_LAYER_WIDGET_H diff --git a/pcbnew/pcb_shape.cpp b/pcbnew/pcb_shape.cpp index 5dbe2b203f..43eed770bb 100644 --- a/pcbnew/pcb_shape.cpp +++ b/pcbnew/pcb_shape.cpp @@ -321,4 +321,3 @@ static struct PCB_SHAPE_DESC propMgr.InheritsAfter( TYPE_HASH( PCB_SHAPE ), TYPE_HASH( EDA_SHAPE ) ); } } _PCB_SHAPE_DESC; - diff --git a/pcbnew/pcbnew_settings.cpp b/pcbnew/pcbnew_settings.cpp index 8a741d3c4f..c5ba399aea 100644 --- a/pcbnew/pcbnew_settings.cpp +++ b/pcbnew/pcbnew_settings.cpp @@ -95,6 +95,9 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS() m_params.emplace_back( new PARAM( "aui.appearance_panel_tab", &m_AuiPanels.appearance_panel_tab, 0, 0, 2 ) ); + m_params.emplace_back( new PARAM( "aui.show_properties", + &m_AuiPanels.show_properties, true ) ); + m_params.emplace_back( new PARAM( "footprint_chooser.width", &m_FootprintChooser.width, -1 ) ); diff --git a/pcbnew/pcbnew_settings.h b/pcbnew/pcbnew_settings.h index c27951e413..ef90145c8d 100644 --- a/pcbnew/pcbnew_settings.h +++ b/pcbnew/pcbnew_settings.h @@ -126,6 +126,7 @@ public: int appearance_panel_tab; int right_panel_width; bool show_layer_manager; + bool show_properties; }; struct DIALOG_CLEANUP diff --git a/pcbnew/toolbars_pcb_editor.cpp b/pcbnew/toolbars_pcb_editor.cpp index becbafcefe..3db82cef98 100644 --- a/pcbnew/toolbars_pcb_editor.cpp +++ b/pcbnew/toolbars_pcb_editor.cpp @@ -378,6 +378,7 @@ void PCB_EDIT_FRAME::ReCreateOptToolbar() // Tools to show/hide toolbars: m_optionsToolBar->AddScaledSeparator( this ); m_optionsToolBar->Add( PCB_ACTIONS::showLayersManager, ACTION_TOOLBAR::TOGGLE ); + m_optionsToolBar->Add( PCB_ACTIONS::showProperties, ACTION_TOOLBAR::TOGGLE ); PCB_SELECTION_TOOL* selTool = m_toolManager->GetTool(); std::unique_ptr gridMenu = std::make_unique( false, selTool ); @@ -780,6 +781,13 @@ void PCB_EDIT_FRAME::ToggleLayersManager() } +void PCB_EDIT_FRAME::ToggleProperties() +{ + m_show_properties = !m_show_properties; + m_auimgr.Update(); +} + + void PCB_EDIT_FRAME::OnUpdateSelectTrackWidth( wxUpdateUIEvent& aEvent ) { if( aEvent.GetId() == ID_AUX_TOOLBAR_PCB_TRACK_WIDTH ) diff --git a/pcbnew/tools/board_editor_control.cpp b/pcbnew/tools/board_editor_control.cpp index c8d545a7c2..eddedc6677 100644 --- a/pcbnew/tools/board_editor_control.cpp +++ b/pcbnew/tools/board_editor_control.cpp @@ -669,6 +669,13 @@ int BOARD_EDITOR_CONTROL::ToggleLayersManager( const TOOL_EVENT& aEvent ) } +int BOARD_EDITOR_CONTROL::ToggleProperties( const TOOL_EVENT& aEvent ) +{ + getEditFrame()->ToggleProperties(); + return 0; +} + + int BOARD_EDITOR_CONTROL::TogglePythonConsole( const TOOL_EVENT& aEvent ) { m_frame->ScriptingConsoleEnableDisable(); @@ -1571,6 +1578,7 @@ void BOARD_EDITOR_CONTROL::setTransitions() ACTIONS::updateSchematicFromPcb.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::ShowEeschema, PCB_ACTIONS::showEeschema.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::ToggleLayersManager, PCB_ACTIONS::showLayersManager.MakeEvent() ); + Go( &BOARD_EDITOR_CONTROL::ToggleProperties, PCB_ACTIONS::showProperties.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::TogglePythonConsole, PCB_ACTIONS::showPythonConsole.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::RepairBoard, PCB_ACTIONS::repairBoard.MakeEvent() ); } diff --git a/pcbnew/tools/board_editor_control.h b/pcbnew/tools/board_editor_control.h index 2374ede631..4c1756df67 100644 --- a/pcbnew/tools/board_editor_control.h +++ b/pcbnew/tools/board_editor_control.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 CERN + * Copyright (C) 2014-2020 CERN * Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors. * * @author Maciej Suminski @@ -77,6 +77,7 @@ public: int UpdateSchematicFromPCB( const TOOL_EVENT& aEvent ); int ShowEeschema( const TOOL_EVENT& aEvent ); int ToggleLayersManager( const TOOL_EVENT& aEvent ); + int ToggleProperties( const TOOL_EVENT& aEvent ); int TogglePythonConsole( const TOOL_EVENT& aEvent ); // Track & via size control diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index 9e3c715744..9a896b0b32 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -819,6 +819,11 @@ TOOL_ACTION PCB_ACTIONS::showLayersManager( "pcbnew.Control.showLayersManager", _( "Show Appearance Manager" ), _( "Show/hide the appearance manager" ), BITMAPS::layers_manager ); +TOOL_ACTION PCB_ACTIONS::showProperties( "pcbnew.Control.showProperties", + AS_GLOBAL, 0, "", + _( "Show Properties" ), _( "Show/hide the properties panel" ), + BITMAPS::tools ); + TOOL_ACTION PCB_ACTIONS::flipBoard( "pcbnew.Control.flipBoard", AS_GLOBAL, 0, "", _( "Flip Board View" ), _( "View board from the opposite side" ), diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 46199aef57..b0468e7e45 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -355,6 +355,7 @@ public: static TOOL_ACTION editLibFpInFpEditor; static TOOL_ACTION showLayersManager; + static TOOL_ACTION showProperties; static TOOL_ACTION showPythonConsole; // Module editor tools diff --git a/pcbnew/tools/pcb_control.h b/pcbnew/tools/pcb_control.h index a2c8bda002..9ab308e968 100644 --- a/pcbnew/tools/pcb_control.h +++ b/pcbnew/tools/pcb_control.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014-2016 CERN + * Copyright (C) 2014-2020 CERN * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. * * @author Maciej Suminski diff --git a/pcbnew/tools/properties_tool.cpp b/pcbnew/tools/properties_tool.cpp new file mode 100644 index 0000000000..9d37f7e659 --- /dev/null +++ b/pcbnew/tools/properties_tool.cpp @@ -0,0 +1,45 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * @author Maciej Suminski + * + * 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 3 + * 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, see . + */ + +#include "properties_tool.h" +#include +#include + + +int PROPERTIES_TOOL::UpdateProperties( const TOOL_EVENT& aEvent ) +{ + PCB_EDIT_FRAME* editFrame = getEditFrame(); + + if( editFrame ) + editFrame->UpdateProperties(); + + return 0; +} + + +void PROPERTIES_TOOL::setTransitions() +{ + TOOL_EVENT undoRedoPostEvt = { TC_MESSAGE, TA_UNDO_REDO_POST, AS_GLOBAL }; + Go( &PROPERTIES_TOOL::UpdateProperties, undoRedoPostEvt ); + Go( &PROPERTIES_TOOL::UpdateProperties, EVENTS::SelectedEvent ); + Go( &PROPERTIES_TOOL::UpdateProperties, EVENTS::UnselectedEvent ); + Go( &PROPERTIES_TOOL::UpdateProperties, EVENTS::ClearedEvent ); + Go( &PROPERTIES_TOOL::UpdateProperties, EVENTS::SelectedItemsModified ); +} diff --git a/pcbnew/tools/properties_tool.h b/pcbnew/tools/properties_tool.h new file mode 100644 index 0000000000..84d26b9a0e --- /dev/null +++ b/pcbnew/tools/properties_tool.h @@ -0,0 +1,42 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * @author Maciej Suminski + * + * 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 3 + * 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, see . + */ + +#ifndef PROPERTIES_TOOL_H +#define PROPERTIES_TOOL_H + +#include + +/** + * Action handler for the Properties panel + */ +class PROPERTIES_TOOL : public PCB_TOOL_BASE +{ +public: + PROPERTIES_TOOL() + : PCB_TOOL_BASE( "pcbnew.Properties" ) + { + } + + int UpdateProperties( const TOOL_EVENT& aEvent ); + + void setTransitions() override; +}; + +#endif diff --git a/qa/tools/pcb_test_window/CMakeLists.txt b/qa/tools/pcb_test_window/CMakeLists.txt index e7f9123ec6..0038371ed4 100644 --- a/qa/tools/pcb_test_window/CMakeLists.txt +++ b/qa/tools/pcb_test_window/CMakeLists.txt @@ -2,7 +2,7 @@ # # This program source code file is part of KiCad, a free EDA CAD application. # -# Copyright (C) 2017 CERN +# Copyright (C) 2017-2020 CERN # @author Alejandro GarcĂ­a Montoro # # This program is free software; you can redistribute it and/or @@ -22,23 +22,23 @@ # or you may write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -find_package(Boost COMPONENTS unit_test_framework REQUIRED) -find_package( wxWidgets 3.0.0 COMPONENTS gl aui adv html core net base xml stc REQUIRED ) +find_package( Boost COMPONENTS unit_test_framework REQUIRED ) +find_package( wxWidgets 3.0.0 COMPONENTS gl aui adv html core net base xml propgrid stc REQUIRED ) add_definitions(-DBOOST_TEST_DYN_LINK -DPCBNEW) add_dependencies( pnsrouter pcbcommon ${PCBNEW_IO_LIBRARIES} ) add_executable(test_window WIN32 - test.cpp - ${CMAKE_SOURCE_DIR}/qa/qa_utils/pcb_test_frame.cpp - ${CMAKE_SOURCE_DIR}/qa/qa_utils/mocks.cpp + test.cpp + ${CMAKE_SOURCE_DIR}/qa/qa_utils/pcb_test_frame.cpp + ${CMAKE_SOURCE_DIR}/qa/qa_utils/mocks.cpp - ${CMAKE_SOURCE_DIR}/common/base_units.cpp - ${CMAKE_SOURCE_DIR}/pcbnew/tools/pcb_tool_base.cpp - ${CMAKE_SOURCE_DIR}/pcbnew/tools/pcbnew_selection.cpp - ${CMAKE_SOURCE_DIR}/pcbnew/tools/selection_tool.cpp - ${CMAKE_SOURCE_DIR}/pcbnew/tools/tool_event_utils.cpp + ${CMAKE_SOURCE_DIR}/common/base_units.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/tools/pcb_tool_base.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/tools/pcbnew_selection.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/tools/selection_tool.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/tools/tool_event_utils.cpp ) include_directories( BEFORE ${INC_BEFORE} )