From 132a0ada732bfeef364c58e73f812f5382d15797 Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Sun, 23 Jul 2023 13:51:42 -0400 Subject: [PATCH] Grid Overrides: support grids-per-type that override the current grid. Schematic only at this point while we test and refine. PCB support is a future addition. Fixes: https://gitlab.com/kicad/code/kicad/-/issues/14756 --- common/bitmap_info.cpp | 2 + common/dialogs/dialog_grid_settings.cpp | 56 +- common/dialogs/dialog_grid_settings_base.cpp | 76 +- common/dialogs/dialog_grid_settings_base.fbp | 1082 ++++++++++++++++- common/dialogs/dialog_grid_settings_base.h | 20 +- common/eda_draw_frame.cpp | 16 + common/settings/app_settings.cpp | 53 + common/tool/actions.cpp | 18 +- common/tool/common_tools.cpp | 9 + common/tool/editor_conditions.cpp | 17 + common/tool/grid_helper.cpp | 28 +- eeschema/sch_edit_frame.cpp | 1 + eeschema/toolbars_sch_editor.cpp | 1 + eeschema/tools/ee_grid_helper.cpp | 136 ++- eeschema/tools/ee_grid_helper.h | 31 +- eeschema/tools/ee_selection_tool.cpp | 5 +- eeschema/tools/sch_drawing_tools.cpp | 9 +- eeschema/tools/sch_line_wire_bus_tool.cpp | 4 +- eeschema/tools/sch_move_tool.cpp | 21 +- include/bitmaps/bitmaps_list.h | 1 + include/dialogs/dialog_grid_settings.h | 4 + include/eda_draw_frame.h | 3 + include/settings/app_settings.h | 10 + include/tool/actions.h | 1 + include/tool/common_tools.h | 1 + include/tool/editor_conditions.h | 12 + include/tool/grid_helper.h | 7 + resources/bitmaps_png/CMakeLists.txt | 1 + .../bitmaps_png/png/grid_override_24.png | Bin 0 -> 663 bytes .../bitmaps_png/png/grid_override_dark_24.png | Bin 0 -> 685 bytes .../sources/dark/grid_override.svg | 223 ++++ .../sources/light/grid_override.svg | 223 ++++ 32 files changed, 1975 insertions(+), 96 deletions(-) create mode 100644 resources/bitmaps_png/png/grid_override_24.png create mode 100644 resources/bitmaps_png/png/grid_override_dark_24.png create mode 100644 resources/bitmaps_png/sources/dark/grid_override.svg create mode 100644 resources/bitmaps_png/sources/light/grid_override.svg diff --git a/common/bitmap_info.cpp b/common/bitmap_info.cpp index a35d189c59..aab7460a22 100644 --- a/common/bitmap_info.cpp +++ b/common/bitmap_info.cpp @@ -316,6 +316,7 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::general_ratsnest].emplace_back( BITMAPS::general_ratsnest, wxT( "general_ratsnest_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::grid_select].emplace_back( BITMAPS::grid_select, wxT( "grid_select_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::grid_select_axis].emplace_back( BITMAPS::grid_select_axis, wxT( "grid_select_axis_24.png" ), 24, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::grid_override].emplace_back( BITMAPS::grid_override, wxT( "grid_override_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::grid].emplace_back( BITMAPS::grid, wxT( "grid_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::group].emplace_back( BITMAPS::group, wxT( "group_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::group_enter].emplace_back( BITMAPS::group_enter, wxT( "group_enter_24.png" ), 24, wxT( "light" ) ); @@ -704,6 +705,7 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::general_ratsnest].emplace_back( BITMAPS::general_ratsnest, wxT( "general_ratsnest_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::grid_select].emplace_back( BITMAPS::grid_select, wxT( "grid_select_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::grid_select_axis].emplace_back( BITMAPS::grid_select_axis, wxT( "grid_select_axis_dark_24.png" ), 24, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::grid_override].emplace_back( BITMAPS::grid_override, wxT( "grid_override_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::grid].emplace_back( BITMAPS::grid, wxT( "grid_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::group].emplace_back( BITMAPS::group, wxT( "group_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::group_enter].emplace_back( BITMAPS::group_enter, wxT( "group_enter_dark_24.png" ), 24, wxT( "dark" ) ); diff --git a/common/dialogs/dialog_grid_settings.cpp b/common/dialogs/dialog_grid_settings.cpp index 724fa303c3..ed271d7e22 100644 --- a/common/dialogs/dialog_grid_settings.cpp +++ b/common/dialogs/dialog_grid_settings.cpp @@ -32,13 +32,20 @@ #include #include -DIALOG_GRID_SETTINGS::DIALOG_GRID_SETTINGS( EDA_DRAW_FRAME* aParent ): - DIALOG_GRID_SETTINGS_BASE( aParent ), - m_parent( aParent ), - m_gridOriginX( aParent, m_staticTextGridPosX, m_GridOriginXCtrl, m_TextPosXUnits ), - m_gridOriginY( aParent, m_staticTextGridPosY, m_GridOriginYCtrl, m_TextPosYUnits ), - m_userGridX( aParent, m_staticTextSizeX, m_OptGridSizeX, m_TextSizeXUnits ), - m_userGridY( aParent, m_staticTextSizeY, m_OptGridSizeY, m_TextSizeYUnits ) +DIALOG_GRID_SETTINGS::DIALOG_GRID_SETTINGS( EDA_DRAW_FRAME* aParent ) : + DIALOG_GRID_SETTINGS_BASE( aParent ), m_parent( aParent ), + m_gridOriginX( aParent, m_staticTextGridPosX, m_GridOriginXCtrl, m_TextPosXUnits ), + m_gridOriginY( aParent, m_staticTextGridPosY, m_GridOriginYCtrl, m_TextPosYUnits ), + m_userGridX( aParent, m_staticTextSizeX, m_OptGridSizeX, m_TextSizeXUnits ), + m_userGridY( aParent, m_staticTextSizeY, m_OptGridSizeY, m_TextSizeYUnits ), + m_gridOverrideConnectables( aParent, m_staticTextConnectables, + m_GridOverrideConnectablesSize, m_staticTextConnectablesUnits ), + m_gridOverrideWires( aParent, m_staticTextWires, m_GridOverrideWiresSize, + m_staticTextWiresUnits ), + m_gridOverrideText( aParent, m_staticTextText, m_GridOverrideTextSize, + m_staticTextTextUnits ), + m_gridOverrideGraphics( aParent, m_staticTextGraphics, m_GridOverrideGraphicsSize, + m_staticTextGraphicsUnits ) { // Configure display origin transforms m_gridOriginX.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD ); @@ -58,6 +65,7 @@ DIALOG_GRID_SETTINGS::DIALOG_GRID_SETTINGS( EDA_DRAW_FRAME* aParent ): else { m_book->SetSelection( 0 ); + sbGridOverridesSizer->ShowItems( false ); } int hk1 = ACTIONS::gridFast1.GetHotKey(); @@ -108,11 +116,13 @@ void DIALOG_GRID_SETTINGS::RebuildGridSizes() bool DIALOG_GRID_SETTINGS::TransferDataFromWindow() { // Validate new settings - if( !m_userGridX.Validate( 0.001, 1000.0, EDA_UNITS::MILLIMETRES ) ) - return false; - - if( !m_userGridY.Validate( 0.001, 1000.0, EDA_UNITS::MILLIMETRES ) ) - return false; + for( UNIT_BINDER* entry : + { &m_userGridX, &m_userGridY, &m_gridOverrideConnectables, &m_gridOverrideWires, + &m_gridOverrideText, &m_gridOverrideGraphics } ) + { + if( !entry->Validate( 0.001, 1000.0, EDA_UNITS::MILLIMETRES ) ) + return false; + } // Apply the new settings APP_SETTINGS_BASE* cfg = m_parent->config(); @@ -125,6 +135,17 @@ bool DIALOG_GRID_SETTINGS::TransferDataFromWindow() gridCfg.fast_grid_1 = m_grid1Ctrl->GetSelection(); gridCfg.fast_grid_2 = m_grid2Ctrl->GetSelection(); + gridCfg.override_connectables = m_checkGridOverrideConnectables->GetValue(); + gridCfg.override_connectables_size = + m_parent->StringFromValue( m_gridOverrideConnectables.GetValue(), true ); + gridCfg.override_wires = m_checkGridOverrideWires->GetValue(); + gridCfg.override_wires_size = m_parent->StringFromValue( m_gridOverrideWires.GetValue(), true ); + gridCfg.override_text = m_checkGridOverrideText->GetValue(); + gridCfg.override_text_size = m_parent->StringFromValue( m_gridOverrideText.GetValue(), true ); + gridCfg.override_graphics = m_checkGridOverrideGraphics->GetValue(); + gridCfg.override_graphics_size = + m_parent->StringFromValue( m_gridOverrideGraphics.GetValue(), true ); + // Notify TOOLS TOOL_MANAGER* mgr = m_parent->GetToolManager(); mgr->ResetTools( TOOL_BASE::REDRAW ); @@ -153,6 +174,17 @@ bool DIALOG_GRID_SETTINGS::TransferDataToWindow() m_userGridX.SetValue( m_parent->ValueFromString( gridCfg.user_grid_x ) ); m_userGridY.SetValue( m_parent->ValueFromString( gridCfg.user_grid_y ) ); + m_gridOverrideConnectables.SetValue( + m_parent->ValueFromString( gridCfg.override_connectables_size ) ); + m_gridOverrideWires.SetValue( m_parent->ValueFromString( gridCfg.override_wires_size ) ); + m_gridOverrideText.SetValue( m_parent->ValueFromString( gridCfg.override_text_size ) ); + m_gridOverrideGraphics.SetValue( m_parent->ValueFromString( gridCfg.override_graphics_size ) ); + + m_checkGridOverrideConnectables->SetValue( gridCfg.override_connectables ); + m_checkGridOverrideWires->SetValue( gridCfg.override_wires ); + m_checkGridOverrideText->SetValue( gridCfg.override_text ); + m_checkGridOverrideGraphics->SetValue( gridCfg.override_graphics ); + m_gridOriginX.SetValue( m_parent->GetGridOrigin().x ); m_gridOriginY.SetValue( m_parent->GetGridOrigin().y ); diff --git a/common/dialogs/dialog_grid_settings_base.cpp b/common/dialogs/dialog_grid_settings_base.cpp index a33236788c..bb18000c58 100644 --- a/common/dialogs/dialog_grid_settings_base.cpp +++ b/common/dialogs/dialog_grid_settings_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b) +// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -135,8 +135,6 @@ DIALOG_GRID_SETTINGS_BASE::DIALOG_GRID_SETTINGS_BASE( wxWindow* parent, wxWindow wxArrayString m_grid1CtrlChoices; m_grid1Ctrl = new wxChoice( sbFastSwitchSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_grid1CtrlChoices, 0 ); m_grid1Ctrl->SetSelection( 0 ); - m_grid1Ctrl->SetMinSize( wxSize( 240,-1 ) ); - fgSizer3->Add( m_grid1Ctrl, 1, wxALL|wxEXPAND, 5 ); m_grid1HotKey = new wxStaticText( sbFastSwitchSizer->GetStaticBox(), wxID_ANY, _("(hotkey)"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -150,8 +148,6 @@ DIALOG_GRID_SETTINGS_BASE::DIALOG_GRID_SETTINGS_BASE( wxWindow* parent, wxWindow wxArrayString m_grid2CtrlChoices; m_grid2Ctrl = new wxChoice( sbFastSwitchSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_grid2CtrlChoices, 0 ); m_grid2Ctrl->SetSelection( 0 ); - m_grid2Ctrl->SetMinSize( wxSize( 240,-1 ) ); - fgSizer3->Add( m_grid2Ctrl, 1, wxALL|wxEXPAND, 5 ); m_grid2HotKey = new wxStaticText( sbFastSwitchSizer->GetStaticBox(), wxID_ANY, _("(hotkey)"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -164,6 +160,76 @@ DIALOG_GRID_SETTINGS_BASE::DIALOG_GRID_SETTINGS_BASE( wxWindow* parent, wxWindow bSizerMain->Add( sbFastSwitchSizer, 0, wxEXPAND|wxALL, 10 ); + sbGridOverridesSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Grid Overrides") ), wxVERTICAL ); + + wxFlexGridSizer* fgGridOverrides; + fgGridOverrides = new wxFlexGridSizer( 4, 4, 0, 0 ); + fgGridOverrides->AddGrowableCol( 2 ); + fgGridOverrides->SetFlexibleDirection( wxBOTH ); + fgGridOverrides->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_checkGridOverrideConnectables = new wxCheckBox( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgGridOverrides->Add( m_checkGridOverrideConnectables, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 ); + + m_staticTextConnectables = new wxStaticText( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, _("Connectable Items:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT ); + m_staticTextConnectables->Wrap( -1 ); + fgGridOverrides->Add( m_staticTextConnectables, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 ); + + m_GridOverrideConnectablesSize = new wxTextCtrl( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgGridOverrides->Add( m_GridOverrideConnectablesSize, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + m_staticTextConnectablesUnits = new wxStaticText( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextConnectablesUnits->Wrap( -1 ); + fgGridOverrides->Add( m_staticTextConnectablesUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + + m_checkGridOverrideWires = new wxCheckBox( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgGridOverrides->Add( m_checkGridOverrideWires, 0, wxALIGN_CENTER|wxALIGN_CENTER_HORIZONTAL|wxALL|wxLEFT|wxRIGHT, 5 ); + + m_staticTextWires = new wxStaticText( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, _("Wires:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT ); + m_staticTextWires->Wrap( -1 ); + fgGridOverrides->Add( m_staticTextWires, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_GridOverrideWiresSize = new wxTextCtrl( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgGridOverrides->Add( m_GridOverrideWiresSize, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + m_staticTextWiresUnits = new wxStaticText( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextWiresUnits->Wrap( -1 ); + fgGridOverrides->Add( m_staticTextWiresUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxRIGHT, 5 ); + + m_checkGridOverrideText = new wxCheckBox( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgGridOverrides->Add( m_checkGridOverrideText, 0, wxALIGN_CENTER|wxALL|wxLEFT|wxRIGHT, 5 ); + + m_staticTextText = new wxStaticText( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, _("Text:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT ); + m_staticTextText->Wrap( -1 ); + fgGridOverrides->Add( m_staticTextText, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 ); + + m_GridOverrideTextSize = new wxTextCtrl( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgGridOverrides->Add( m_GridOverrideTextSize, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + m_staticTextTextUnits = new wxStaticText( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT ); + m_staticTextTextUnits->Wrap( -1 ); + fgGridOverrides->Add( m_staticTextTextUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxRIGHT, 5 ); + + m_checkGridOverrideGraphics = new wxCheckBox( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgGridOverrides->Add( m_checkGridOverrideGraphics, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 ); + + m_staticTextGraphics = new wxStaticText( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, _("Graphics:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT ); + m_staticTextGraphics->Wrap( -1 ); + fgGridOverrides->Add( m_staticTextGraphics, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_GridOverrideGraphicsSize = new wxTextCtrl( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgGridOverrides->Add( m_GridOverrideGraphicsSize, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); + + m_staticTextGraphicsUnits = new wxStaticText( sbGridOverridesSizer->GetStaticBox(), wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT ); + m_staticTextGraphicsUnits->Wrap( -1 ); + fgGridOverrides->Add( m_staticTextGraphicsUnits, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + sbGridOverridesSizer->Add( fgGridOverrides, 1, wxBOTTOM|wxEXPAND, 5 ); + + + bSizerMain->Add( sbGridOverridesSizer, 0, wxALL|wxEXPAND, 10 ); + wxBoxSizer* bButtonSizer; bButtonSizer = new wxBoxSizer( wxHORIZONTAL ); diff --git a/common/dialogs/dialog_grid_settings_base.fbp b/common/dialogs/dialog_grid_settings_base.fbp index cdb9e69d43..046f7bcb7b 100644 --- a/common/dialogs/dialog_grid_settings_base.fbp +++ b/common/dialogs/dialog_grid_settings_base.fbp @@ -188,11 +188,11 @@ wxVERTICAL 1 none - + 5 wxEXPAND|wxALL 0 - + 3 wxBOTH 1 @@ -643,11 +643,11 @@ wxVERTICAL 1 none - + 5 wxALL|wxEXPAND 0 - + 1 1 1 @@ -724,11 +724,11 @@ wxVERTICAL 1 none - + 5 wxEXPAND|wxALL 0 - + 3 wxBOTH 1 @@ -1118,11 +1118,11 @@ - + 10 wxEXPAND|wxALL 0 - + wxID_ANY Fast Switching @@ -1130,11 +1130,11 @@ wxVERTICAL 1 none - + 5 wxEXPAND|wxBOTTOM|wxLEFT 0 - + 3 wxBOTH 1 @@ -1207,11 +1207,11 @@ -1 - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -1245,7 +1245,7 @@ 0 - 240,-1 + -1,-1 1 m_grid1Ctrl 1 @@ -1271,11 +1271,11 @@ - + 5 wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT 0 - + 1 1 1 @@ -1393,11 +1393,11 @@ -1 - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -1431,7 +1431,7 @@ 0 - 240,-1 + -1,-1 1 m_grid2Ctrl 1 @@ -1457,11 +1457,11 @@ - + 5 wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT 0 - + 1 1 1 @@ -1523,10 +1523,1042 @@ + 10 + wxALL|wxEXPAND + 0 + + wxID_ANY + Grid Overrides + + sbGridOverridesSizer + wxVERTICAL + 1 + protected + + 5 + wxBOTTOM|wxEXPAND + 1 + + 4 + wxBOTH + 2 + + 0 + + fgGridOverrides + wxFLEX_GROWMODE_SPECIFIED + none + 4 + 0 + + 10 + wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_checkGridOverrideConnectables + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Connectable Items: + 0 + + 0 + + + 0 + + 1 + m_staticTextConnectables + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_LEFT + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_GridOverrideConnectablesSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + + 1 + m_staticTextConnectablesUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER|wxALIGN_CENTER_HORIZONTAL|wxALL|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_checkGridOverrideWires + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Wires: + 0 + + 0 + + + 0 + + 1 + m_staticTextWires + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_LEFT + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_GridOverrideWiresSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + + 1 + m_staticTextWiresUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER|wxALL|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_checkGridOverrideText + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Text: + 0 + + 0 + + + 0 + + 1 + m_staticTextText + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_LEFT + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_GridOverrideTextSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + + 1 + m_staticTextTextUnits + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_LEFT + ; ; forward_declare + 0 + + + + + -1 + + + + 10 + wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_checkGridOverrideGraphics + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Graphics: + 0 + + 0 + + + 0 + + 1 + m_staticTextGraphics + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_LEFT + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_GridOverrideGraphicsSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + + 1 + m_staticTextGraphicsUnits + 1 + + + protected + 1 + + Resizable + 1 + + wxALIGN_LEFT + ; ; forward_declare + 0 + + + + + -1 + + + + + + + 10 wxEXPAND|wxLEFT 0 - + bButtonSizer wxHORIZONTAL @@ -1605,11 +2637,11 @@ OnResetGridOriginClick - + 5 wxALL|wxALIGN_CENTER_VERTICAL 0 - + 1 1 1 @@ -1678,11 +2710,11 @@ - + 5 wxALL|wxEXPAND 1 - + 0 1 0 diff --git a/common/dialogs/dialog_grid_settings_base.h b/common/dialogs/dialog_grid_settings_base.h index 166d1fab1a..c9dff02c5d 100644 --- a/common/dialogs/dialog_grid_settings_base.h +++ b/common/dialogs/dialog_grid_settings_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b) +// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,23 @@ class DIALOG_GRID_SETTINGS_BASE : public DIALOG_SHIM wxStaticText* m_staticTextGrid2; wxChoice* m_grid2Ctrl; wxStaticText* m_grid2HotKey; + wxStaticBoxSizer* sbGridOverridesSizer; + wxCheckBox* m_checkGridOverrideConnectables; + wxStaticText* m_staticTextConnectables; + wxTextCtrl* m_GridOverrideConnectablesSize; + wxStaticText* m_staticTextConnectablesUnits; + wxCheckBox* m_checkGridOverrideWires; + wxStaticText* m_staticTextWires; + wxTextCtrl* m_GridOverrideWiresSize; + wxStaticText* m_staticTextWiresUnits; + wxCheckBox* m_checkGridOverrideText; + wxStaticText* m_staticTextText; + wxTextCtrl* m_GridOverrideTextSize; + wxStaticText* m_staticTextTextUnits; + wxCheckBox* m_checkGridOverrideGraphics; + wxStaticText* m_staticTextGraphics; + wxTextCtrl* m_GridOverrideGraphicsSize; + wxStaticText* m_staticTextGraphicsUnits; wxButton* m_buttonResetOrigin; wxButton* m_buttonResetSizes; wxStdDialogButtonSizer* m_sdbSizer; diff --git a/common/eda_draw_frame.cpp b/common/eda_draw_frame.cpp index 4681613839..5a471ff5eb 100644 --- a/common/eda_draw_frame.cpp +++ b/common/eda_draw_frame.cpp @@ -531,6 +531,22 @@ void EDA_DRAW_FRAME::SetGridVisibility( bool aVisible ) } +bool EDA_DRAW_FRAME::IsGridOverridden() const +{ + wxCHECK( config(), false ); + + return config()->m_Window.grid.overrides_enabled; +} + + +void EDA_DRAW_FRAME::SetGridOverrides( bool aOverride ) +{ + wxCHECK( config(), /* void */ ); + + config()->m_Window.grid.overrides_enabled = aOverride; +} + + void EDA_DRAW_FRAME::UpdateZoomSelectBox() { if( m_zoomSelectBox == nullptr ) diff --git a/common/settings/app_settings.cpp b/common/settings/app_settings.cpp index da726f96e8..50bf4b02fa 100644 --- a/common/settings/app_settings.cpp +++ b/common/settings/app_settings.cpp @@ -354,6 +354,59 @@ void APP_SETTINGS_BASE::addParamsForWindow( WINDOW_SETTINGS* aWindow, const std: m_params.emplace_back( new PARAM( aJsonPath + ".grid.user_grid_y", &aWindow->grid.user_grid_y, "10 mil" ) ); + // for grid overrides, give just the schematic and symbol editors sane values + if( m_filename == wxS( "eeschema" ) || m_filename == wxS( "symbol_editor" ) ) + { + m_params.emplace_back( new PARAM( aJsonPath + ".grid.overrides_enabled", + &aWindow->grid.overrides_enabled, true ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_connectables", + &aWindow->grid.override_connectables, true ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_wires", + &aWindow->grid.override_wires, true ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_text", + &aWindow->grid.override_text, false ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_graphics", + &aWindow->grid.override_graphics, false ) ); + + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_connectables_size", + &aWindow->grid.override_connectables_size, + "50 mil" ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_wires_size", + &aWindow->grid.override_wires_size, + "50 mil" ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_text_size", + &aWindow->grid.override_text_size, "10 mil" ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_graphics_size", + &aWindow->grid.override_graphics_size, + "25 mil" ) ); + } + else + { + m_params.emplace_back( new PARAM( aJsonPath + ".grid.overrides_enabled", + &aWindow->grid.overrides_enabled, false ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_connectables", + &aWindow->grid.override_connectables, false ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_wires", + &aWindow->grid.override_wires, false ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_text", + &aWindow->grid.override_text, false ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_graphics", + &aWindow->grid.override_graphics, false ) ); + + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_connectables_size", + &aWindow->grid.override_connectables_size, + "100 mil" ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_text_size", + &aWindow->grid.override_text_size, "10 mil" ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_wires_size", + &aWindow->grid.override_wires_size, + "10 mil" ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".grid.override_graphics_size", + &aWindow->grid.override_graphics_size, + "10 mil" ) ); + } + + m_params.emplace_back( new PARAM( aJsonPath + ".grid.line_width", &aWindow->grid.line_width, 1.0 ) ); diff --git a/common/tool/actions.cpp b/common/tool/actions.cpp index 8a5df60f8f..d236dfcad2 100644 --- a/common/tool/actions.cpp +++ b/common/tool/actions.cpp @@ -551,10 +551,20 @@ TOOL_ACTION ACTIONS::gridPreset( TOOL_ACTION_ARGS() .Scope( AS_GLOBAL ) .Parameter( 0 ) ); // Default to the 1st element of the list -TOOL_ACTION ACTIONS::toggleGrid( "common.Control.toggleGrid", - AS_GLOBAL, 0, "", - _( "Show Grid" ), _( "Display background grid in the edit window" ), - BITMAPS::grid ); +TOOL_ACTION ACTIONS::toggleGrid( TOOL_ACTION_ARGS() + .Name("common.Control.toggleGrid") + .Scope( AS_GLOBAL) + .MenuText( _( "Show Grid" ) ) + .Tooltip( _( "Display background grid in the edit window" ) ) + .Icon( BITMAPS::grid ) ); + +TOOL_ACTION ACTIONS::toggleGridOverrides( TOOL_ACTION_ARGS() + .Name("common.Control.toggleGridOverrides") + .DefaultHotkey( MD_CTRL + MD_SHIFT + 'G' ) + .Scope( AS_GLOBAL) + .MenuText( _( "Grid Overrides" ) ) + .Tooltip( _( "Enables item-specific grids that override the current grid" ) ) + .Icon( BITMAPS::grid_override ) ); TOOL_ACTION ACTIONS::gridProperties( "common.Control.gridProperties", AS_GLOBAL, 0, "", diff --git a/common/tool/common_tools.cpp b/common/tool/common_tools.cpp index 990da1e1f7..4c86914a83 100644 --- a/common/tool/common_tools.cpp +++ b/common/tool/common_tools.cpp @@ -517,6 +517,14 @@ int COMMON_TOOLS::ToggleGrid( const TOOL_EVENT& aEvent ) } +int COMMON_TOOLS::ToggleGridOverrides( const TOOL_EVENT& aEvent ) +{ + m_frame->SetGridOverrides( !m_frame->IsGridOverridden() ); + + return 0; +} + + int COMMON_TOOLS::GridProperties( const TOOL_EVENT& aEvent ) { wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); @@ -664,6 +672,7 @@ void COMMON_TOOLS::setTransitions() Go( &COMMON_TOOLS::GridFast1, ACTIONS::gridFast1.MakeEvent() ); Go( &COMMON_TOOLS::GridFast2, ACTIONS::gridFast2.MakeEvent() ); Go( &COMMON_TOOLS::ToggleGrid, ACTIONS::toggleGrid.MakeEvent() ); + Go( &COMMON_TOOLS::ToggleGridOverrides, ACTIONS::toggleGridOverrides.MakeEvent() ); Go( &COMMON_TOOLS::GridProperties, ACTIONS::gridProperties.MakeEvent() ); // Units and coordinates diff --git a/common/tool/editor_conditions.cpp b/common/tool/editor_conditions.cpp index a780f37a56..9b7064afc6 100644 --- a/common/tool/editor_conditions.cpp +++ b/common/tool/editor_conditions.cpp @@ -84,6 +84,17 @@ SELECTION_CONDITION EDITOR_CONDITIONS::GridVisible() } +SELECTION_CONDITION EDITOR_CONDITIONS::GridOverrides() +{ + // The grid lock check requires a draw frame + EDA_DRAW_FRAME* drwFrame = dynamic_cast( m_frame ); + + wxASSERT( drwFrame ); + + return std::bind( &EDITOR_CONDITIONS::gridOverridesFunc, _1, drwFrame ); +} + + SELECTION_CONDITION EDITOR_CONDITIONS::PolarCoordinates() { // The polar coordinates require a draw frame @@ -170,6 +181,12 @@ bool EDITOR_CONDITIONS::gridFunc( const SELECTION& aSelection, EDA_DRAW_FRAME* a } +bool EDITOR_CONDITIONS::gridOverridesFunc( const SELECTION& aSelection, EDA_DRAW_FRAME* aFrame ) +{ + return aFrame->IsGridOverridden(); +} + + bool EDITOR_CONDITIONS::polarCoordFunc( const SELECTION& aSelection, EDA_DRAW_FRAME* aFrame ) { return aFrame->GetShowPolarCoords(); diff --git a/common/tool/grid_helper.cpp b/common/tool/grid_helper.cpp index 7b6f99c228..f01718e2aa 100644 --- a/common/tool/grid_helper.cpp +++ b/common/tool/grid_helper.cpp @@ -90,22 +90,38 @@ void GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin ) VECTOR2I GRID_HELPER::AlignGrid( const VECTOR2I& aPoint ) const { - const VECTOR2D gridOffset( GetOrigin() ); - const VECTOR2D grid( GetGrid() ); + return computeNearest( aPoint, GetGrid(), GetOrigin() ); +} - VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / grid.x ) * grid.x + gridOffset.x, - KiROUND( ( aPoint.y - gridOffset.y ) / grid.y ) * grid.y + gridOffset.y ); - return nearest; +VECTOR2I GRID_HELPER::AlignGrid( const VECTOR2I& aPoint, const VECTOR2D& aGrid, + const VECTOR2D& aOffset ) const +{ + return computeNearest( aPoint, aGrid, aOffset ); +} + + +VECTOR2I GRID_HELPER::computeNearest( const VECTOR2I& aPoint, const VECTOR2I& aGrid, + const VECTOR2I& aOffset ) const +{ + return VECTOR2I( KiROUND( ( aPoint.x - aOffset.x ) / aGrid.x ) * aGrid.x + aOffset.x, + KiROUND( ( aPoint.y - aOffset.y ) / aGrid.y ) * aGrid.y + aOffset.y ); } VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint ) const +{ + return Align( aPoint, GetGrid(), GetOrigin() ); +} + + +VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint, const VECTOR2D& aGrid, + const VECTOR2D& aOffset ) const { if( !canUseGrid() ) return aPoint; - VECTOR2I nearest = AlignGrid( aPoint ); + VECTOR2I nearest = AlignGrid( aPoint, aGrid, aOffset ); if( !m_auxAxis ) return nearest; diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index 775ce51c46..f3e4a14737 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -542,6 +542,7 @@ void SCH_EDIT_FRAME::setupUIConditions() mgr->SetConditions( EE_ACTIONS::showNetNavigator, CHECK( netNavigatorCond ) ); mgr->SetConditions( ACTIONS::showProperties, CHECK( propertiesCond ) ); mgr->SetConditions( ACTIONS::toggleGrid, CHECK( cond.GridVisible() ) ); + mgr->SetConditions( ACTIONS::toggleGridOverrides, CHECK( cond.GridOverrides() ) ); mgr->SetConditions( ACTIONS::toggleCursorStyle, CHECK( cond.FullscreenCursor() ) ); mgr->SetConditions( ACTIONS::millimetersUnits, CHECK( cond.Units( EDA_UNITS::MILLIMETRES ) ) ); diff --git a/eeschema/toolbars_sch_editor.cpp b/eeschema/toolbars_sch_editor.cpp index 263d588a7c..512c9f6bc6 100644 --- a/eeschema/toolbars_sch_editor.cpp +++ b/eeschema/toolbars_sch_editor.cpp @@ -196,6 +196,7 @@ void SCH_EDIT_FRAME::ReCreateOptToolbar() } m_optionsToolBar->Add( ACTIONS::toggleGrid, ACTION_TOOLBAR::TOGGLE ); + m_optionsToolBar->Add( ACTIONS::toggleGridOverrides, ACTION_TOOLBAR::TOGGLE ); m_optionsToolBar->Add( ACTIONS::inchesUnits, ACTION_TOOLBAR::TOGGLE ); m_optionsToolBar->Add( ACTIONS::milsUnits, ACTION_TOOLBAR::TOGGLE ); m_optionsToolBar->Add( ACTIONS::millimetersUnits, ACTION_TOOLBAR::TOGGLE ); diff --git a/eeschema/tools/ee_grid_helper.cpp b/eeschema/tools/ee_grid_helper.cpp index f0472d49af..5e3a71ce52 100644 --- a/eeschema/tools/ee_grid_helper.cpp +++ b/eeschema/tools/ee_grid_helper.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include "ee_grid_helper.h" @@ -60,7 +61,13 @@ EE_GRID_HELPER::EE_GRID_HELPER( TOOL_MANAGER* aToolMgr ) : } -VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I& aMousePos, int aLayer, +VECTOR2I EE_GRID_HELPER::Align( const VECTOR2I& aPoint, GRID_HELPER_GRIDS aGrid ) const +{ + return Align( aPoint, GetGridSize( aGrid ), GetOrigin() ); +} + + +VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I& aMousePos, GRID_HELPER_GRIDS aGrid, const EE_SELECTION& aItems ) { clearAnchors(); @@ -77,9 +84,9 @@ VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I& aMousePos, int aLayer, double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale(); double lineSnapMinCornerDistance = 50.0 / worldScale; - ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, aLayer ); - ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, aLayer ); - ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, aLayer ); + ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, aGrid ); + ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, aGrid ); + ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, aGrid ); ANCHOR* best = nullptr; double minDist = std::numeric_limits::max(); @@ -112,16 +119,17 @@ VECTOR2I EE_GRID_HELPER::BestDragOrigin( const VECTOR2I& aMousePos, int aLayer, } -VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, SCH_ITEM* aSkip ) +VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, GRID_HELPER_GRIDS aGrid, + SCH_ITEM* aSkip ) { EE_SELECTION skipItems; skipItems.Add( aSkip ); - return BestSnapAnchor( aOrigin, aLayer, skipItems ); + return BestSnapAnchor( aOrigin, aGrid, skipItems ); } -VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, +VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, GRID_HELPER_GRIDS aGrid, const EE_SELECTION& aSkip ) { constexpr int snapRange = SNAP_RANGE * schIUScale.IU_PER_MILS; @@ -141,8 +149,8 @@ VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, for( SCH_ITEM* item : queryVisible( bb, aSkip ) ) computeAnchors( item, aOrigin ); - ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayer ); - VECTOR2I nearestGrid = Align( aOrigin ); + ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aGrid ); + VECTOR2I nearestGrid = Align( aOrigin, aGrid ); if( m_enableSnapLine && m_snapItem && m_skipPoint != VECTOR2I( m_viewSnapLine.GetPosition() ) ) { @@ -233,6 +241,50 @@ VECTOR2I EE_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, return pt; } + +VECTOR2D EE_GRID_HELPER::GetGridSize( GRID_HELPER_GRIDS aGrid ) const +{ + const GRID_SETTINGS& grid = m_toolMgr->GetSettings()->m_Window.grid; + + VECTOR2D g = m_toolMgr->GetView()->GetGAL()->GetGridSize(); + + if( !grid.overrides_enabled ) + return g; + + switch( aGrid ) + { + case GRID_CONNECTABLE: + if( grid.override_connectables ) + g.x = g.y = EDA_UNIT_UTILS::UI::DoubleValueFromString( + schIUScale, EDA_UNITS::MILS, grid.override_connectables_size ); + + break; + case GRID_WIRES: + if( grid.override_wires ) + g.x = g.y = EDA_UNIT_UTILS::UI::DoubleValueFromString( schIUScale, EDA_UNITS::MILS, + grid.override_wires_size ); + + break; + case GRID_TEXT: + if( grid.override_text ) + g.x = g.y = EDA_UNIT_UTILS::UI::DoubleValueFromString( schIUScale, EDA_UNITS::MILS, + grid.override_text_size ); + + break; + case GRID_GRAPHICS: + if( grid.override_graphics ) + g.x = g.y = EDA_UNIT_UTILS::UI::DoubleValueFromString( schIUScale, EDA_UNITS::MILS, + grid.override_graphics_size ); + + break; + case GRID_CURRENT: + break; + } + + return g; +} + + SCH_ITEM* EE_GRID_HELPER::GetSnapped() const { if( !m_snapItem ) @@ -268,6 +320,68 @@ std::set EE_GRID_HELPER::queryVisible( const BOX2I& aArea, } +GRID_HELPER_GRIDS EE_GRID_HELPER::GetSelectionGrid( const EE_SELECTION& aSelection ) +{ + GRID_HELPER_GRIDS grid = GetItemGrid( static_cast( aSelection.Front() ) ); + + // Find the largest grid of all the items and use that + for( EDA_ITEM* item : aSelection ) + { + GRID_HELPER_GRIDS itemGrid = GetItemGrid( static_cast( item ) ); + + if( GetGridSize( itemGrid ) > GetGridSize( grid ) ) + grid = itemGrid; + } + + return grid; +} + + +GRID_HELPER_GRIDS EE_GRID_HELPER::GetItemGrid( const SCH_ITEM* aItem ) +{ + if( !aItem ) + return GRID_CURRENT; + + switch( aItem->Type() ) + { + case SCH_SYMBOL_T: + case SCH_PIN_T: + case SCH_SHEET_PIN_T: + case SCH_SHEET_T: + case SCH_NO_CONNECT_T: + case SCH_GLOBAL_LABEL_T: + case SCH_HIER_LABEL_T: + case SCH_LABEL_T: + case SCH_DIRECTIVE_LABEL_T: + return GRID_CONNECTABLE; + + case SCH_TEXT_T: + case SCH_TEXTBOX_T: + case SCH_FIELD_T: + return GRID_TEXT; + + case SCH_SHAPE_T: + case SCH_BITMAP_T: + return GRID_GRAPHICS; + + case SCH_JUNCTION_T: + return GRID_WIRES; + + case SCH_LINE_T: + if( aItem->IsConnectable() ) + return GRID_WIRES; + else + return GRID_GRAPHICS; + + case SCH_BUS_BUS_ENTRY_T: + case SCH_BUS_WIRE_ENTRY_T: + return GRID_WIRES; + + default: + return GRID_CURRENT; + } +} + void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom, bool aIncludeText ) { @@ -346,9 +460,9 @@ EE_GRID_HELPER::ANCHOR* EE_GRID_HELPER::nearestAnchor( const VECTOR2I& aPos, int if( ( aFlags & a.flags ) != aFlags ) continue; - if( aMatchLayer == LAYER_CONNECTABLE && !item->IsConnectable() ) + if( aMatchLayer == LAYER_NOCONNECT && !item->IsConnectable() ) continue; - else if( aMatchLayer == LAYER_GRAPHICS && item->IsConnectable() ) + else if( aMatchLayer == GRID_GRAPHICS && item->IsConnectable() ) continue; double dist = a.Distance( aPos ); diff --git a/eeschema/tools/ee_grid_helper.h b/eeschema/tools/ee_grid_helper.h index 56578dccc2..c6464e5ce2 100644 --- a/eeschema/tools/ee_grid_helper.h +++ b/eeschema/tools/ee_grid_helper.h @@ -34,11 +34,15 @@ class SCH_ITEM; -enum EE_GRID_HELPER_LAYERS : int +enum GRID_HELPER_GRIDS : int { - LAYER_ANY = SCH_LAYER_ID_END + 1, - LAYER_CONNECTABLE, - LAYER_GRAPHICS + // When the item doesn't match an override, use the current user grid + GRID_CURRENT, + + GRID_CONNECTABLE, + GRID_WIRES, + GRID_TEXT, + GRID_GRAPHICS }; @@ -48,6 +52,10 @@ public: EE_GRID_HELPER( TOOL_MANAGER* aToolMgr ); + using GRID_HELPER::Align; + using GRID_HELPER::AlignGrid; + VECTOR2I Align( const VECTOR2I& aPoint, GRID_HELPER_GRIDS aGrid ) const; + /** * Function GetSnapped * If the EE_GRID_HELPER has highlighted a snap point (target shown), this function @@ -57,10 +65,19 @@ public: */ SCH_ITEM* GetSnapped() const; - VECTOR2I BestDragOrigin( const VECTOR2I& aMousePos, int aLayer, const EE_SELECTION& aItems ); + VECTOR2D GetGridSize( GRID_HELPER_GRIDS aGrid ) const; + using GRID_HELPER::GetGrid; - VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, SCH_ITEM* aDraggedItem ); - VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, int aLayer, const EE_SELECTION& aSkip = {} ); + GRID_HELPER_GRIDS GetSelectionGrid( const EE_SELECTION& aItem ); + GRID_HELPER_GRIDS GetItemGrid( const SCH_ITEM* aItem ); + + VECTOR2I BestDragOrigin( const VECTOR2I& aMousePos, GRID_HELPER_GRIDS aGrid, + const EE_SELECTION& aItems ); + + VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, GRID_HELPER_GRIDS aGrid, + SCH_ITEM* aDraggedItem ); + VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, GRID_HELPER_GRIDS aGrid, + const EE_SELECTION& aSkip = {} ); private: std::set queryVisible( const BOX2I& aArea, const EE_SELECTION& aSkipList ) const; diff --git a/eeschema/tools/ee_selection_tool.cpp b/eeschema/tools/ee_selection_tool.cpp index 0a241c748b..46315eabcc 100644 --- a/eeschema/tools/ee_selection_tool.cpp +++ b/eeschema/tools/ee_selection_tool.cpp @@ -729,7 +729,7 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) OPT_TOOL_EVENT EE_SELECTION_TOOL::autostartEvent( TOOL_EVENT* aEvent, EE_GRID_HELPER& aGrid, SCH_ITEM* aItem ) { - VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), LAYER_CONNECTABLE ); + VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), aGrid.GetItemGrid( aItem ) ); if( m_frame->eeconfig()->m_Drawing.auto_start_wires && !m_toolMgr->GetTool()->HasPoint() @@ -1826,7 +1826,8 @@ bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos, { EE_GRID_HELPER grid( m_toolMgr ); - if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( *aPos, LAYER_CONNECTABLE ) ) ) + if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( + *aPos, grid.GetItemGrid( static_cast( aItem ) ) ) ) ) return true; } diff --git a/eeschema/tools/sch_drawing_tools.cpp b/eeschema/tools/sch_drawing_tools.cpp index 04a68faa85..ace916a038 100644 --- a/eeschema/tools/sch_drawing_tools.cpp +++ b/eeschema/tools/sch_drawing_tools.cpp @@ -803,7 +803,7 @@ int SCH_DRAWING_TOOLS::SingleClickPlace( const TOOL_EVENT& aEvent ) grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() ); cursorPos = evt->IsPrime() ? evt->Position() : controls->GetMousePosition(); - cursorPos = grid.BestSnapAnchor( cursorPos, LAYER_CONNECTABLE, nullptr ); + cursorPos = grid.BestSnapAnchor( cursorPos, grid.GetItemGrid( previewItem ), nullptr ); controls->ForceCursorPosition( true, cursorPos ); if( evt->IsCancelInteractive() ) @@ -1151,7 +1151,8 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent ) bool isClassLabel = aEvent.IsAction( &EE_ACTIONS::placeClassLabel ); bool isNetLabel = aEvent.IsAction( &EE_ACTIONS::placeLabel ); bool isSheetPin = aEvent.IsAction( &EE_ACTIONS::importSheetPin ); - int snapLayer = isText ? LAYER_GRAPHICS : LAYER_CONNECTABLE; + + GRID_HELPER_GRIDS snapGrid = isText ? GRID_TEXT : GRID_CONNECTABLE; // If we have a selected sheet use it, otherwise try to get one under the cursor if( isSheetPin ) @@ -1228,7 +1229,7 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent ) grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() ); VECTOR2I cursorPos = controls->GetMousePosition(); - cursorPos = grid.BestSnapAnchor( cursorPos, snapLayer, item ); + cursorPos = grid.BestSnapAnchor( cursorPos, snapGrid, item ); controls->ForceCursorPosition( true, cursorPos ); // The tool hotkey is interpreted as a click when drawing @@ -1362,7 +1363,7 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent ) { getViewControls()->PinCursorInsideNonAutoscrollArea( true ); cursorPos = getViewControls()->GetMousePosition(); - cursorPos = grid.BestSnapAnchor( cursorPos, snapLayer, item ); + cursorPos = grid.BestSnapAnchor( cursorPos, snapGrid, item ); } if( item ) diff --git a/eeschema/tools/sch_line_wire_bus_tool.cpp b/eeschema/tools/sch_line_wire_bus_tool.cpp index fd36734b5b..0a73c054d8 100644 --- a/eeschema/tools/sch_line_wire_bus_tool.cpp +++ b/eeschema/tools/sch_line_wire_bus_tool.cpp @@ -298,7 +298,7 @@ int SCH_LINE_WIRE_BUS_TOOL::DrawSegments( const TOOL_EVENT& aEvent ) grid.SetSnap( !aEvent.Modifier( MD_SHIFT ) ); grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !aEvent.DisableGridSnapping() ); - VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), LAYER_CONNECTABLE, nullptr ); + VECTOR2D cursorPos = grid.BestSnapAnchor( aEvent.Position(), GRID_WIRES, nullptr ); startSegments( params->layer, cursorPos, params->sourceSegment ); } @@ -652,7 +652,7 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, int aType, VECTOR2D eventPosition = evt->HasPosition() ? evt->Position() : controls->GetMousePosition(); - VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, LAYER_CONNECTABLE, segment ); + VECTOR2I cursorPos = grid.BestSnapAnchor( eventPosition, GRID_WIRES, segment ); controls->ForceCursorPosition( true, cursorPos ); // Need to handle change in H/V mode while drawing diff --git a/eeschema/tools/sch_move_tool.cpp b/eeschema/tools/sch_move_tool.cpp index 87165380a6..920e55aa44 100644 --- a/eeschema/tools/sch_move_tool.cpp +++ b/eeschema/tools/sch_move_tool.cpp @@ -458,7 +458,7 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm TOOL_EVENT copy = aEvent; TOOL_EVENT* evt = © VECTOR2I prevPos; - int snapLayer = UNDEFINED_LAYER; + GRID_HELPER_GRIDS snapLayer = GRID_CURRENT; m_cursor = controls->GetCursorPosition(); @@ -577,25 +577,12 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm static_cast( item )->UpdateDanglingState( internalPoints ); } + // Generic setup - // + snapLayer = grid.GetSelectionGrid( selection ); + for( EDA_ITEM* item : selection ) { - if( static_cast( item )->IsConnectable() ) - { - if( snapLayer == LAYER_GRAPHICS ) - snapLayer = LAYER_ANY; - else - snapLayer = LAYER_CONNECTABLE; - } - else - { - if( snapLayer == LAYER_CONNECTABLE ) - snapLayer = LAYER_ANY; - else - snapLayer = LAYER_GRAPHICS; - } - if( item->IsNew() ) { // Item was added to commit in a previous command diff --git a/include/bitmaps/bitmaps_list.h b/include/bitmaps/bitmaps_list.h index 477cb80089..e01f7c2ded 100644 --- a/include/bitmaps/bitmaps_list.h +++ b/include/bitmaps/bitmaps_list.h @@ -221,6 +221,7 @@ enum class BITMAPS : unsigned int go_down, go_up, grid, + grid_override, grid_select, grid_select_axis, group, diff --git a/include/dialogs/dialog_grid_settings.h b/include/dialogs/dialog_grid_settings.h index 10dc9b5552..985da09833 100644 --- a/include/dialogs/dialog_grid_settings.h +++ b/include/dialogs/dialog_grid_settings.h @@ -48,6 +48,10 @@ private: UNIT_BINDER m_gridOriginY; UNIT_BINDER m_userGridX; UNIT_BINDER m_userGridY; + UNIT_BINDER m_gridOverrideConnectables; + UNIT_BINDER m_gridOverrideWires; + UNIT_BINDER m_gridOverrideText; + UNIT_BINDER m_gridOverrideGraphics; }; #endif // DIALOG_GRID_SETTINGS_H diff --git a/include/eda_draw_frame.h b/include/eda_draw_frame.h index 6dbda113e6..59a6340510 100644 --- a/include/eda_draw_frame.h +++ b/include/eda_draw_frame.h @@ -217,6 +217,9 @@ public: bool IsGridVisible() const; virtual void SetGridVisibility( bool aVisible ); + bool IsGridOverridden() const; + virtual void SetGridOverrides( bool aOverride ); + virtual COLOR4D GetGridColor() { return m_gridColor; } virtual void SetGridColor( const COLOR4D& aColor ) { m_gridColor = aColor; } diff --git a/include/settings/app_settings.h b/include/settings/app_settings.h index 197d0b9d9b..ca2b7bb0a0 100644 --- a/include/settings/app_settings.h +++ b/include/settings/app_settings.h @@ -61,6 +61,16 @@ struct GRID_SETTINGS bool show; int style; int snap; + bool force_component_snap; + bool overrides_enabled; + bool override_connectables; + wxString override_connectables_size; + bool override_wires; + wxString override_wires_size; + bool override_text; + wxString override_text_size; + bool override_graphics; + wxString override_graphics_size; }; /** diff --git a/include/tool/actions.h b/include/tool/actions.h index 80741f619e..98e72e8f44 100644 --- a/include/tool/actions.h +++ b/include/tool/actions.h @@ -142,6 +142,7 @@ public: static TOOL_ACTION gridResetOrigin; static TOOL_ACTION gridPreset; static TOOL_ACTION toggleGrid; + static TOOL_ACTION toggleGridOverrides; static TOOL_ACTION gridProperties; // Units diff --git a/include/tool/common_tools.h b/include/tool/common_tools.h index 7fc2b59156..4825ea4c1c 100644 --- a/include/tool/common_tools.h +++ b/include/tool/common_tools.h @@ -83,6 +83,7 @@ public: int GridFast1( const TOOL_EVENT& aEvent ); int GridFast2( const TOOL_EVENT& aEvent ); int ToggleGrid( const TOOL_EVENT& aEvent ); + int ToggleGridOverrides( const TOOL_EVENT& aEvent ); int GridProperties( const TOOL_EVENT& aEvent ); int GridPreset( int idx ); int OnGridChanged( bool aFromHotkey = true ); diff --git a/include/tool/editor_conditions.h b/include/tool/editor_conditions.h index a3eacfdda9..7c56fc7646 100644 --- a/include/tool/editor_conditions.h +++ b/include/tool/editor_conditions.h @@ -100,6 +100,15 @@ public: */ SELECTION_CONDITION GridVisible(); + /** + * Create a functor testing if the grid overrides wires is enabled in a frame. + * + * @note This requires the frame passed into the constructor be be derived from EDA_DRAW_FRAME. + * + * @return Functor testing if grid overrides are enabled + */ + SELECTION_CONDITION GridOverrides(); + /** * Create a functor testing if polar coordinates are current being used. * @@ -152,6 +161,9 @@ protected: ///< Helper function used by GridVisible(). static bool gridFunc( const SELECTION& aSelection, EDA_DRAW_FRAME* aFrame ); + ///< Helper function used by GridOverrides(). + static bool gridOverridesFunc( const SELECTION& aSelection, EDA_DRAW_FRAME* aFrame ); + ///< Helper function used by PolarCoordinates(). static bool polarCoordFunc( const SELECTION& aSelection, EDA_DRAW_FRAME* aFrame ); diff --git a/include/tool/grid_helper.h b/include/tool/grid_helper.h index f967847f92..045b7360e6 100644 --- a/include/tool/grid_helper.h +++ b/include/tool/grid_helper.h @@ -46,8 +46,12 @@ public: void SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin = VECTOR2I( 0, 0 ) ); virtual VECTOR2I Align( const VECTOR2I& aPoint ) const; + virtual VECTOR2I Align( const VECTOR2I& aPoint, const VECTOR2D& aGrid, + const VECTOR2D& aOffset ) const; VECTOR2I AlignGrid( const VECTOR2I& aPoint ) const; + VECTOR2I AlignGrid( const VECTOR2I& aPoint, const VECTOR2D& aGrid, + const VECTOR2D& aOffset ) const; void SetSkipPoint( const VECTOR2I& aPoint ) { @@ -125,6 +129,9 @@ protected: return m_enableGrid && m_toolMgr->GetView()->GetGAL()->GetGridSnapping(); } + VECTOR2I computeNearest( const VECTOR2I& aPoint, const VECTOR2I& aGrid, + const VECTOR2I& aOffset ) const; + protected: std::vector m_anchors; diff --git a/resources/bitmaps_png/CMakeLists.txt b/resources/bitmaps_png/CMakeLists.txt index 5aee8b993b..6854d99f3e 100644 --- a/resources/bitmaps_png/CMakeLists.txt +++ b/resources/bitmaps_png/CMakeLists.txt @@ -293,6 +293,7 @@ set( BMAPS_MID general_ratsnest grid_select grid_select_axis + grid_override grid group group_enter diff --git a/resources/bitmaps_png/png/grid_override_24.png b/resources/bitmaps_png/png/grid_override_24.png new file mode 100644 index 0000000000000000000000000000000000000000..904e3af36693d3e02e080023c98a3d84d7c454d7 GIT binary patch literal 663 zcmV;I0%-k-P)`b^Qu5Xsxd6 z-9hD<<{$zK*PY64 zVgxJzn+L=~$myCNpQhbPE^_e1py8l^Pc6(ml2Q>c`5i=3cZj4^L~Jr8RUO;{V3?Hw zaV^1A1S*~pMKr!R0GkJ^lgo%nMNoVJivJUnih%J@2g+oPFo9i~E?+6lWVOAtC;O1+<&4_zJ`V;zk7oQWp(ipb~krV zRex6AG_x;P-IP*vWu@bTjhhQER;uO7J6+e$h1Mnh1zVoGAv}ad6Mj8ow zZq2KG-7N7UBA-Mxs$zg{(Pb?By}mwb&#deN(O%~HLF3u$`S$I(QGmVtDr0AI2foNm zuG@I~=_2-te7zumpQa;c9|q*PRz3e?LRXD>Tr=dbj*s(vzFXLaY?zvv=S8rQ zBh;+PR)f zO7tviE<_24e16c-jB$W_Cp#9NSjud=190yzHQe-~1+o7CG04eEGX%s7j;vlszC$iz z1$x}69RihDn;rxCAx8y{*tV_#j!OXfd;xSYwz zn^LbN)gs@pF52MgJ`d%hL2Wv0-9MXd85xrp*?x_1J#$xdyiG&C;7x{)0bJx`QYriB zZ`0roBUF*tyZIOc&fO>bM?GYWqtknn34MxJ>=M99DYsZr_Xq-A_CDW4KH&ZfTD*h+ Tm2kBa00000NkvXXu0mjf$Xq%U literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/sources/dark/grid_override.svg b/resources/bitmaps_png/sources/dark/grid_override.svg new file mode 100644 index 0000000000..6f6a862a49 --- /dev/null +++ b/resources/bitmaps_png/sources/dark/grid_override.svg @@ -0,0 +1,223 @@ + + + + + + + + + + image/svg+xml + + grid + + + + + + + + + + + + + + + grid + + + + + + + + + + + + + + + + + + + diff --git a/resources/bitmaps_png/sources/light/grid_override.svg b/resources/bitmaps_png/sources/light/grid_override.svg new file mode 100644 index 0000000000..b7ccb7b1c8 --- /dev/null +++ b/resources/bitmaps_png/sources/light/grid_override.svg @@ -0,0 +1,223 @@ + + + + + + + + + + image/svg+xml + + grid + + + + + + + + + + + + + + + grid + + + + + + + + + + + + + + + + + + +