diff --git a/common/preview_items/polygon_geom_manager.cpp b/common/preview_items/polygon_geom_manager.cpp index ec732d6fc7..e487e74db2 100644 --- a/common/preview_items/polygon_geom_manager.cpp +++ b/common/preview_items/polygon_geom_manager.cpp @@ -228,6 +228,20 @@ static SHAPE_LINE_CHAIN build45DegLeader( const VECTOR2I& aEndPoint, const SHAPE return SHAPE_LINE_CHAIN( std::vector{ lastPt, midInt, aEndPoint } ); } +static SHAPE_LINE_CHAIN build90DegLeader( const VECTOR2I& aEndPoint, const SHAPE_LINE_CHAIN& aLastPoints ) +{ + if( aLastPoints.PointCount() < 1 ) + return SHAPE_LINE_CHAIN(); + + const VECTOR2I lastPt = aLastPoints.CLastPoint(); + + if( lastPt.x == aEndPoint.x || lastPt.y == aEndPoint.y ) + return SHAPE_LINE_CHAIN( std::vector{ lastPt, aEndPoint } ); + + VECTOR2I mid( aEndPoint.x, lastPt.y ); + return SHAPE_LINE_CHAIN( std::vector{ lastPt, mid, aEndPoint } ); +} + void POLYGON_GEOM_MANAGER::updateTemporaryLines( const VECTOR2I& aEndPoint, LEADER_MODE aModifier ) { @@ -242,6 +256,14 @@ void POLYGON_GEOM_MANAGER::updateTemporaryLines( const VECTOR2I& aEndPoint, LEAD m_loopPts = build45DegLeader( aEndPoint, m_lockedPoints.Reverse() ).Reverse(); } } + else if( m_leaderMode == LEADER_MODE::DEG90 || aModifier == LEADER_MODE::DEG90 ) + { + if( m_lockedPoints.PointCount() > 0 ) + { + m_leaderPts = build90DegLeader( aEndPoint, m_lockedPoints ); + m_loopPts = build90DegLeader( aEndPoint, m_lockedPoints.Reverse() ).Reverse(); + } + } else { // direct segment diff --git a/common/settings/cvpcb_settings.cpp b/common/settings/cvpcb_settings.cpp index 35027e073d..dc92054887 100644 --- a/common/settings/cvpcb_settings.cpp +++ b/common/settings/cvpcb_settings.cpp @@ -24,6 +24,7 @@ #include #include #include +#include ///! Update the schema version whenever a migration is required @@ -54,8 +55,9 @@ CVPCB_SETTINGS::CVPCB_SETTINGS() : m_params.emplace_back( new PARAM( "footprint_viewer.autozoom", &m_FootprintViewerAutoZoomOnSelect, true ) ); - m_params.emplace_back( new PARAM( "footprint_viewer.use_45_limit", - &m_ViewersDisplay.m_Use45Limit, true ) ); + m_params.emplace_back( new PARAM( "footprint_viewer.angle_snap_mode", + reinterpret_cast( &m_ViewersDisplay.m_AngleSnapMode ), + static_cast( LEADER_MODE::DEG45 ) ) ); m_params.emplace_back( new PARAM( "footprint_viewer.show_pad_fill", &m_ViewersDisplay.m_DisplayPadFill, true ) ); diff --git a/eeschema/tools/rule_area_create_helper.cpp b/eeschema/tools/rule_area_create_helper.cpp index de445c0c9d..ae15fb7cab 100644 --- a/eeschema/tools/rule_area_create_helper.cpp +++ b/eeschema/tools/rule_area_create_helper.cpp @@ -93,7 +93,7 @@ bool RULE_AREA_CREATE_HELPER::OnFirstPoint( POLYGON_GEOM_MANAGER& aMgr ) m_parentView.SetVisible( &m_previewItem, true ); - aMgr.SetLeaderMode( POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 ); + aMgr.SetLeaderMode( LEADER_MODE::DEG45 ); } return m_rule_area != nullptr; @@ -138,7 +138,7 @@ void RULE_AREA_CREATE_HELPER::OnComplete( const POLYGON_GEOM_MANAGER& aMgr ) // In DEG45 mode, we may have intermediate points in the leader that should be included // as they are shown in the preview. These typically maintain the 45 constraint - if( aMgr.GetLeaderMode() == POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 ) + if( aMgr.GetLeaderMode() == LEADER_MODE::DEG45 || aMgr.GetLeaderMode() == LEADER_MODE::DEG90 ) { const SHAPE_LINE_CHAIN leaderPts = aMgr.GetLeaderLinePoints(); for( int i = 1; i < leaderPts.PointCount(); i++ ) diff --git a/eeschema/tools/sch_drawing_tools.cpp b/eeschema/tools/sch_drawing_tools.cpp index e6471aa049..2181bde5e0 100644 --- a/eeschema/tools/sch_drawing_tools.cpp +++ b/eeschema/tools/sch_drawing_tools.cpp @@ -2617,8 +2617,8 @@ int SCH_DRAWING_TOOLS::DrawRuleArea( const TOOL_EVENT& aEvent ) controls->ForceCursorPosition( true, cursorPos ); polyGeomMgr.SetLeaderMode( m_frame->eeconfig()->m_Drawing.line_mode == LINE_MODE_FREE - ? POLYGON_GEOM_MANAGER::LEADER_MODE::DIRECT - : POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 ); + ? LEADER_MODE::DIRECT + : LEADER_MODE::DEG45 ); if( evt->IsCancelInteractive() ) { diff --git a/gerbview/tools/gerbview_inspection_tool.cpp b/gerbview/tools/gerbview_inspection_tool.cpp index 1a8cbab811..d226f1eba1 100644 --- a/gerbview/tools/gerbview_inspection_tool.cpp +++ b/gerbview/tools/gerbview_inspection_tool.cpp @@ -286,7 +286,8 @@ int GERBVIEW_INSPECTION_TOOL::MeasureTool( const TOOL_EVENT& aEvent ) else if( originSet && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) ) { // move or drag when origin set updates rules - twoPtMgr.SetAngleSnap( evt->Modifier( MD_SHIFT ) ); + twoPtMgr.SetAngleSnap( evt->Modifier( MD_SHIFT ) ? LEADER_MODE::DEG45 + : LEADER_MODE::DIRECT ); twoPtMgr.SetEnd( cursorPos ); getView()->SetVisible( &ruler, true ); diff --git a/include/footprint_editor_settings.h b/include/footprint_editor_settings.h index 0f7847dfc9..702fd97a62 100644 --- a/include/footprint_editor_settings.h +++ b/include/footprint_editor_settings.h @@ -74,7 +74,7 @@ public: EDA_ANGLE m_RotationAngle; - bool m_Use45Limit; + LEADER_MODE m_AngleSnapMode; ARC_EDIT_MODE m_ArcEditMode; diff --git a/include/preview_items/polygon_geom_manager.h b/include/preview_items/polygon_geom_manager.h index aeeab47fe1..679711c073 100644 --- a/include/preview_items/polygon_geom_manager.h +++ b/include/preview_items/polygon_geom_manager.h @@ -25,6 +25,7 @@ #define PREVIEW_POLYGON_GEOM_MANAGER__H_ #include +#include /** * Class that handles the drawing of a polygon, including management of last corner deletion @@ -63,15 +64,6 @@ public: } }; - /** - * The kind of the leader line - */ - enum class LEADER_MODE - { - DIRECT, ///< Unconstrained point-to-point - DEG45, ///< 45 Degree only - }; - /** * @param aClient is the client to pass the results onto */ diff --git a/include/preview_items/two_point_geom_manager.h b/include/preview_items/two_point_geom_manager.h index f062a679a7..58eacb798c 100644 --- a/include/preview_items/two_point_geom_manager.h +++ b/include/preview_items/two_point_geom_manager.h @@ -40,7 +40,6 @@ namespace PREVIEW class TWO_POINT_GEOMETRY_MANAGER { public: - ///< Set the origin of the ruler (the fixed end) void SetOrigin( const VECTOR2I& aOrigin ) { @@ -58,10 +57,12 @@ public: */ void SetEnd( const VECTOR2I& aEnd ) { - if( m_angleSnap ) - m_end = GetVectorSnapped45( aEnd - m_origin ) + m_origin; - else - m_end = aEnd; + switch( m_angleSnap ) + { + case LEADER_MODE::DEG45: m_end = GetVectorSnapped45( aEnd - m_origin ) + m_origin; break; + case LEADER_MODE::DEG90: m_end = GetVectorSnapped90( aEnd - m_origin ) + m_origin; break; + default: m_end = aEnd; break; + } } VECTOR2I GetEnd() const @@ -69,15 +70,9 @@ public: return m_end; } - void SetAngleSnap( bool aSnap ) - { - m_angleSnap = aSnap; - } + void SetAngleSnap( LEADER_MODE aSnap ) { m_angleSnap = aSnap; } - bool GetAngleSnap() const - { - return m_angleSnap; - } + LEADER_MODE GetAngleSnap() const { return m_angleSnap; } /** * @return true if the manager is in the initial state @@ -101,11 +96,10 @@ public: } private: - - VECTOR2I m_origin; - VECTOR2I m_end; - bool m_angleSnap = false; - bool m_originSet = false; + VECTOR2I m_origin; + VECTOR2I m_end; + LEADER_MODE m_angleSnap = LEADER_MODE::DIRECT; + bool m_originSet = false; }; } // PREVIEW diff --git a/libs/kimath/include/geometry/geometry_utils.h b/libs/kimath/include/geometry/geometry_utils.h index 882a8d987b..7784d3381a 100644 --- a/libs/kimath/include/geometry/geometry_utils.h +++ b/libs/kimath/include/geometry/geometry_utils.h @@ -39,6 +39,16 @@ #include #include +/** + * The kind of the leader line + */ +enum class LEADER_MODE +{ + DIRECT, ///< Unconstrained point-to-point + DEG45, ///< 45 Degree only + DEG90 ///< 90 Degree only +}; + /** * @return the number of segments to approximate a arc by segments * with a given max error (this number is >= 1) @@ -131,6 +141,30 @@ VECTOR2 GetVectorSnapped45( const VECTOR2& aVec, bool only45 = false ) } +/** + * Snap a vector onto the nearest horizontal or vertical line. + * + * The magnitude of the vector is NOT kept; instead one of the coordinates is + * set to zero as needed. If the starting vector is on a square grid, the + * resulting snapped vector will remain on the same grid. + * + * @param aVec vector to be snapped + * @return the snapped vector + */ +template +VECTOR2 GetVectorSnapped90( const VECTOR2& aVec ) +{ + auto newVec = aVec; + const VECTOR2 absVec{ std::abs( aVec.x ), std::abs( aVec.y ) }; + + if( absVec.x >= absVec.y ) + newVec.y = 0; + else + newVec.x = 0; + + return newVec; +} + /** * Clamps a vector to values that can be negated, respecting numeric limits * of coordinates data type with specified padding. diff --git a/pcbnew/dialogs/panel_edit_options.cpp b/pcbnew/dialogs/panel_edit_options.cpp index a2d33290f2..5c87baa7e7 100644 --- a/pcbnew/dialogs/panel_edit_options.cpp +++ b/pcbnew/dialogs/panel_edit_options.cpp @@ -28,6 +28,7 @@ #include #include #include +#include PANEL_EDIT_OPTIONS::PANEL_EDIT_OPTIONS( wxWindow* aParent, UNITS_PROVIDER* aUnitsProvider, @@ -104,7 +105,7 @@ static ARC_EDIT_MODE arcEditModeToEnum( int aIndex ) void PANEL_EDIT_OPTIONS::loadPCBSettings( PCBNEW_SETTINGS* aCfg ) { - m_cbConstrainHV45Mode->SetValue( aCfg->m_Use45DegreeLimit ); + m_cbConstrainHV45Mode->SetValue( aCfg->m_AngleSnapMode != LEADER_MODE::DIRECT ); m_rotationAngle.SetAngleValue( aCfg->m_RotationAngle ); m_arcEditMode->SetSelection( arcEditModeToComboIndex( aCfg->m_ArcEditMode ) ); m_trackMouseDragCtrl->SetSelection( (int) aCfg->m_TrackDragAction ); @@ -150,7 +151,7 @@ void PANEL_EDIT_OPTIONS::loadFPSettings( FOOTPRINT_EDITOR_SETTINGS* aCfg ) m_rotationAngle.SetAngleValue( aCfg->m_RotationAngle ); m_magneticPads->SetValue( aCfg->m_MagneticItems.pads == MAGNETIC_OPTIONS::CAPTURE_ALWAYS ); m_magneticGraphics->SetValue( aCfg->m_MagneticItems.graphics ); - m_cbConstrainHV45Mode->SetValue( aCfg->m_Use45Limit ); + m_cbConstrainHV45Mode->SetValue( aCfg->m_AngleSnapMode != LEADER_MODE::DIRECT ); m_arcEditMode->SetSelection( arcEditModeToComboIndex( aCfg->m_ArcEditMode ) ); } @@ -178,7 +179,8 @@ bool PANEL_EDIT_OPTIONS::TransferDataFromWindow() : MAGNETIC_OPTIONS::NO_EFFECT; cfg->m_MagneticItems.graphics = m_magneticGraphics->GetValue(); - cfg->m_Use45Limit = m_cbConstrainHV45Mode->GetValue(); + cfg->m_AngleSnapMode = m_cbConstrainHV45Mode->GetValue() ? LEADER_MODE::DEG45 + : LEADER_MODE::DIRECT; cfg->m_ArcEditMode = arcEditModeToEnum( m_arcEditMode->GetSelection() ); } } @@ -190,7 +192,8 @@ bool PANEL_EDIT_OPTIONS::TransferDataFromWindow() cfg->m_Display.m_ShowModuleRatsnest = m_showSelectedRatsnest->GetValue(); cfg->m_Display.m_RatsnestThickness = m_ratsnestThickness->GetValue(); - cfg->m_Use45DegreeLimit = m_cbConstrainHV45Mode->GetValue(); + cfg->m_AngleSnapMode = m_cbConstrainHV45Mode->GetValue() ? LEADER_MODE::DEG45 + : LEADER_MODE::DIRECT; cfg->m_RotationAngle = m_rotationAngle.GetAngleValue(); cfg->m_ArcEditMode = arcEditModeToEnum( m_arcEditMode->GetSelection() ); cfg->m_TrackDragAction = (TRACK_DRAG_ACTION) m_trackMouseDragCtrl->GetSelection(); diff --git a/pcbnew/footprint_edit_frame.cpp b/pcbnew/footprint_edit_frame.cpp index 0c76e03cf8..9735b7459b 100644 --- a/pcbnew/footprint_edit_frame.cpp +++ b/pcbnew/footprint_edit_frame.cpp @@ -30,6 +30,7 @@ #include "tools/pcb_actions.h" #include "tools/pcb_control.h" #include "tools/pcb_picker_tool.h" +#include #include "tools/align_distribute_tool.h" #include "tools/pcb_point_editor.h" #include "tools/pcb_selection_tool.h" @@ -1337,7 +1338,7 @@ void FOOTPRINT_EDIT_FRAME::setupUIConditions() auto constrainedDrawingModeCond = [this]( const SELECTION& ) { - return GetSettings()->m_Use45Limit; + return GetSettings()->m_AngleSnapMode != LEADER_MODE::DIRECT; }; auto highContrastCond = diff --git a/pcbnew/footprint_editor_settings.cpp b/pcbnew/footprint_editor_settings.cpp index e8482d6b84..3f0eb5e920 100644 --- a/pcbnew/footprint_editor_settings.cpp +++ b/pcbnew/footprint_editor_settings.cpp @@ -50,7 +50,7 @@ FOOTPRINT_EDITOR_SETTINGS::FOOTPRINT_EDITOR_SETTINGS() : m_DisplayInvertXAxis( false ), m_DisplayInvertYAxis( false ), m_RotationAngle( ANGLE_90 ), - m_Use45Limit( true ), + m_AngleSnapMode( LEADER_MODE::DEG45 ), m_ArcEditMode( ARC_EDIT_MODE::KEEP_CENTER_ADJUST_ANGLE_RADIUS ), m_LibWidth( 250 ), m_LastExportPath(), @@ -138,8 +138,9 @@ FOOTPRINT_EDITOR_SETTINGS::FOOTPRINT_EDITOR_SETTINGS() : }, 900 ) ); - m_params.emplace_back( new PARAM( "editing.fp_use_45_degree_limit", - &m_Use45Limit, false ) ); + m_params.emplace_back( new PARAM( "editing.fp_angle_snap_mode", + reinterpret_cast( &m_AngleSnapMode ), + static_cast( LEADER_MODE::DEG45 ) ) ); m_params.emplace_back( new PARAM_LAYER_PRESET( "pcb_display.layer_presets", &m_LayerPresets ) ); diff --git a/pcbnew/microwave/microwave_tool.cpp b/pcbnew/microwave/microwave_tool.cpp index 2fb747a289..8819a49c82 100644 --- a/pcbnew/microwave/microwave_tool.cpp +++ b/pcbnew/microwave/microwave_tool.cpp @@ -209,7 +209,7 @@ int MICROWAVE_TOOL::drawMicrowaveInductor( const TOOL_EVENT& aEvent ) // the end point else if( originSet && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) ) { - tpGeomMgr.SetAngleSnap( Is45Limited() ); + tpGeomMgr.SetAngleSnap( GetAngleSnapMode() ); tpGeomMgr.SetEnd( cursorPos ); view.SetVisible( &previewRect, true ); diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 5624fbb9ab..213d187c76 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -30,6 +30,7 @@ #include <3d_viewer/eda_3d_viewer_frame.h> #include #include +#include #include #include #include @@ -888,7 +889,7 @@ void PCB_EDIT_FRAME::setupUIConditions() auto constrainedDrawingModeCond = [this]( const SELECTION& ) { - return GetPcbNewSettings()->m_Use45DegreeLimit; + return GetPcbNewSettings()->m_AngleSnapMode != LEADER_MODE::DIRECT; }; auto boardFlippedCond = diff --git a/pcbnew/pcbnew_settings.cpp b/pcbnew/pcbnew_settings.cpp index 9d31b0c487..66dec21daa 100644 --- a/pcbnew/pcbnew_settings.cpp +++ b/pcbnew/pcbnew_settings.cpp @@ -58,7 +58,7 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS() m_TrackDragAction( TRACK_DRAG_ACTION::DRAG ), m_ArcEditMode( ARC_EDIT_MODE::KEEP_CENTER_ADJUST_ANGLE_RADIUS ), m_CtrlClickHighlight( false ), - m_Use45DegreeLimit( false ), + m_AngleSnapMode( LEADER_MODE::DIRECT ), m_FlipDirection( FLIP_DIRECTION::TOP_BOTTOM ), m_ESCClearsNetHighlight( true ), m_PolarCoords( false ), @@ -190,8 +190,9 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS() m_params.emplace_back( new PARAM( "editing.ctrl_click_highlight", &m_CtrlClickHighlight, false ) ); - m_params.emplace_back( new PARAM( "editing.pcb_use_45_degree_limit", - &m_Use45DegreeLimit, false ) ); + m_params.emplace_back( new PARAM( "editing.pcb_angle_snap_mode", + reinterpret_cast( &m_AngleSnapMode ), + static_cast( LEADER_MODE::DIRECT ) ) ); m_params.emplace_back( new PARAM( "editing.auto_fill_zones", &m_AutoRefillZones, false ) ); diff --git a/pcbnew/pcbnew_settings.h b/pcbnew/pcbnew_settings.h index dcebdacbc9..6de61781eb 100644 --- a/pcbnew/pcbnew_settings.h +++ b/pcbnew/pcbnew_settings.h @@ -22,6 +22,7 @@ #include // for FLIP_DIRECTION #include +#include #include #include @@ -108,7 +109,7 @@ class PCB_VIEWERS_SETTINGS_BASE : public APP_SETTINGS_BASE public: struct VIEWERS_DISPLAY_OPTIONS { - bool m_Use45Limit; + LEADER_MODE m_AngleSnapMode; bool m_DisplayGraphicsFill; bool m_DisplayTextFill; bool m_DisplayPadNumbers; @@ -125,7 +126,7 @@ public: m_FootprintViewerZoom( 1.0 ), m_FootprintViewerAutoZoomOnSelect( true ) { - m_ViewersDisplay.m_Use45Limit = false; + m_ViewersDisplay.m_AngleSnapMode = LEADER_MODE::DIRECT; m_ViewersDisplay.m_DisplayGraphicsFill = true; m_ViewersDisplay.m_DisplayTextFill = true; m_ViewersDisplay.m_DisplayPadNumbers = true; @@ -246,7 +247,7 @@ public: bool m_CtrlClickHighlight; - bool m_Use45DegreeLimit; // Constrain tool actions to horizontal, vertical and 45deg + LEADER_MODE m_AngleSnapMode; // Constrain tool actions to horizontal/vertical or 45°/90° FLIP_DIRECTION m_FlipDirection; bool m_ESCClearsNetHighlight; diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index 4f44ceb032..84a7ff5ccc 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -333,7 +333,18 @@ DRAWING_TOOL::MODE DRAWING_TOOL::GetDrawingMode() const void DRAWING_TOOL::UpdateStatusBar() const { if( m_frame ) - m_frame->DisplayConstraintsMsg( Is45Limited() ? _( "Constrain to H, V, 45" ) : wxString( "" ) ); + { + switch( GetAngleSnapMode() ) + { + case LEADER_MODE::DEG45: + m_frame->DisplayConstraintsMsg( _( "Constrain to H, V, 45" ) ); + break; + case LEADER_MODE::DEG90: + m_frame->DisplayConstraintsMsg( _( "Constrain to H, V" ) ); + break; + default: m_frame->DisplayConstraintsMsg( wxString( "" ) ); break; + } + } } @@ -1407,7 +1418,10 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) setCursor(); grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); - bool is45Limited = Is45Limited() && !evt->Modifier( MD_CTRL ); + auto angleSnap = GetAngleSnapMode(); + if( evt->Modifier( MD_CTRL ) ) + angleSnap = LEADER_MODE::DIRECT; + bool constrained = angleSnap != LEADER_MODE::DIRECT; grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() ); if( step == SET_HEIGHT && t != PCB_DIM_ORTHOGONAL_T ) @@ -1615,7 +1629,7 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) case SET_END: dimension->SetEnd( cursorPos ); - if( is45Limited || t == PCB_DIM_CENTER_T ) + if( constrained || t == PCB_DIM_CENTER_T ) constrainDimension( dimension ); if( t == PCB_DIM_ORTHOGONAL_T ) @@ -2187,11 +2201,13 @@ bool DRAWING_TOOL::drawShape( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic, m_frame->SetMsgPanel( graphic ); grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); - bool is45Limited = Is45Limited() && !evt->Modifier( MD_CTRL ); + auto angleSnap = GetAngleSnapMode(); + if( evt->Modifier( MD_CTRL ) ) + angleSnap = LEADER_MODE::DIRECT; - // Rectangular shapes never get 45-degree snapping + // Rectangular shapes never get diagonal snapping if( shape == SHAPE_T::RECTANGLE ) - is45Limited = false; + angleSnap = LEADER_MODE::DIRECT; grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() ); cursorPos = GetClampedCoords( @@ -2370,21 +2386,25 @@ bool DRAWING_TOOL::drawShape( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic, else clampedCursorPos = getClampedDifferenceEnd( twoPointMgr.GetOrigin(), cursorPos ); - // 45 degree lines - if( started && is45Limited ) + // constrained lines + if( started && angleSnap != LEADER_MODE::DIRECT ) { const VECTOR2I lineVector( clampedCursorPos - VECTOR2I( twoPointMgr.GetOrigin() ) ); - // get a restricted 45/H/V line from the last fixed point to the cursor - VECTOR2I newEnd = GetVectorSnapped45( lineVector, ( shape == SHAPE_T::RECTANGLE ) ); + VECTOR2I newEnd; + if( angleSnap == LEADER_MODE::DEG90 ) + newEnd = GetVectorSnapped90( lineVector ); + else + newEnd = GetVectorSnapped45( lineVector, ( shape == SHAPE_T::RECTANGLE ) ); + m_controls->ForceCursorPosition( true, VECTOR2I( twoPointMgr.GetEnd() ) ); twoPointMgr.SetEnd( twoPointMgr.GetOrigin() + newEnd ); - twoPointMgr.SetAngleSnap( true ); + twoPointMgr.SetAngleSnap( angleSnap ); } else { twoPointMgr.SetEnd( clampedCursorPos ); - twoPointMgr.SetAngleSnap( false ); + twoPointMgr.SetAngleSnap( LEADER_MODE::DIRECT ); } updateSegmentFromGeometryMgr( twoPointMgr, graphic ); @@ -2580,7 +2600,9 @@ bool DRAWING_TOOL::drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic, graphic->SetLayer( m_layer ); grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); - bool is45Limited = Is45Limited() && !evt->Modifier( MD_CTRL ); + auto angleSnap = GetAngleSnapMode(); + if( evt->Modifier( MD_CTRL ) ) + angleSnap = LEADER_MODE::DIRECT; grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() ); VECTOR2I cursorPos = GetClampedCoords( grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic, GRID_GRAPHICS ), @@ -2656,7 +2678,7 @@ bool DRAWING_TOOL::drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic, else if( evt->IsMotion() ) { // set angle snap - arcManager.SetAngleSnap( is45Limited ); + arcManager.SetAngleSnap( angleSnap != LEADER_MODE::DIRECT ); // update, but don't step the manager state arcManager.AddPoint( cursorPos, false ); @@ -3230,7 +3252,9 @@ int DRAWING_TOOL::DrawZone( const TOOL_EVENT& aEvent ) LSET layers( { m_frame->GetActiveLayer() } ); grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); - bool is45Limited = Is45Limited() && !evt->Modifier( MD_CTRL ); + auto angleSnap = GetAngleSnapMode(); + if( evt->Modifier( MD_CTRL ) ) + angleSnap = LEADER_MODE::DIRECT; grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() ); VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition(); @@ -3239,8 +3263,7 @@ int DRAWING_TOOL::DrawZone( const TOOL_EVENT& aEvent ) m_controls->ForceCursorPosition( true, cursorPos ); - polyGeomMgr.SetLeaderMode( is45Limited ? POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 - : POLYGON_GEOM_MANAGER::LEADER_MODE::DIRECT ); + polyGeomMgr.SetLeaderMode( angleSnap ); if( evt->IsCancelInteractive() ) { diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index ddad6e311f..d9917618cd 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -1399,8 +1399,8 @@ TOOL_ACTION PCB_ACTIONS::toggleHV45Mode( TOOL_ACTION_ARGS() .Name( "pcbnew.EditorControl.toggle45" ) .Scope( AS_GLOBAL ) .DefaultHotkey( MD_SHIFT + ' ' ) - .FriendlyName( _( "Constrain to H, V, 45" ) ) - .Tooltip( _( "Limit actions to horizontal, vertical, or 45 degrees from the starting point" ) ) + .FriendlyName( _( "Cycle H/V/45 constraint" ) ) + .Tooltip( _( "Cycle between no angle constraint, 45 degrees, or horizontal/vertical only" ) ) .ToolbarState( TOOLBAR_STATE::TOGGLE ) .Icon( BITMAPS::hv45mode ) ); diff --git a/pcbnew/tools/pcb_editor_conditions.cpp b/pcbnew/tools/pcb_editor_conditions.cpp index 52a18cc7ee..1721ad52f0 100644 --- a/pcbnew/tools/pcb_editor_conditions.cpp +++ b/pcbnew/tools/pcb_editor_conditions.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -200,11 +201,11 @@ bool PCB_EDITOR_CONDITIONS::zoneDisplayModeFunc( const SELECTION& aSelection, PC bool PCB_EDITOR_CONDITIONS::get45degModeFunc( const SELECTION& aSelection, PCB_BASE_FRAME* aFrame ) { if( aFrame->IsType( FRAME_PCB_EDITOR ) ) - return GetAppSettings( "pcbnew" )->m_Use45DegreeLimit; + return GetAppSettings( "pcbnew" )->m_AngleSnapMode != LEADER_MODE::DIRECT; else if( aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) ) - return GetAppSettings( "fpedit" )->m_Use45Limit; + return GetAppSettings( "fpedit" )->m_AngleSnapMode != LEADER_MODE::DIRECT; else - return aFrame->GetViewerSettingsBase()->m_ViewersDisplay.m_Use45Limit; + return aFrame->GetViewerSettingsBase()->m_ViewersDisplay.m_AngleSnapMode != LEADER_MODE::DIRECT; } diff --git a/pcbnew/tools/pcb_editor_conditions.h b/pcbnew/tools/pcb_editor_conditions.h index 6649dee3ef..028ce8dd46 100644 --- a/pcbnew/tools/pcb_editor_conditions.h +++ b/pcbnew/tools/pcb_editor_conditions.h @@ -103,9 +103,9 @@ public: SELECTION_CONDITION ZoneDisplayMode( ZONE_DISPLAY_MODE aMode ); /** - * Create a functor that tests whether only 45 degree lines should be allowed + * Create a functor that tests whether angle constraints are enabled * - * @return Functor returning true if only 45 degree lines should be allowed + * @return Functor returning true if angle constraints are enabled */ SELECTION_CONDITION Get45degMode(); @@ -142,7 +142,7 @@ protected: static bool zoneDisplayModeFunc( const SELECTION& aSelection, PCB_BASE_FRAME* aFrame, ZONE_DISPLAY_MODE aMode ); - ///< Helper function used by Line45degMode() + ///< Helper function used by Get45degMode() static bool get45degModeFunc( const SELECTION& aSelection, PCB_BASE_FRAME* aFrame ); /// Helper function used by FootprintViewerAutoZoom() diff --git a/pcbnew/tools/pcb_tool_base.cpp b/pcbnew/tools/pcb_tool_base.cpp index 9eb3f1349a..dd981ce364 100644 --- a/pcbnew/tools/pcb_tool_base.cpp +++ b/pcbnew/tools/pcb_tool_base.cpp @@ -329,11 +329,21 @@ PCB_SELECTION& PCB_TOOL_BASE::selection() bool PCB_TOOL_BASE::Is45Limited() const +{ + return GetAngleSnapMode() != LEADER_MODE::DIRECT; +} + +bool PCB_TOOL_BASE::Is90Limited() const +{ + return GetAngleSnapMode() == LEADER_MODE::DEG90; +} + +LEADER_MODE PCB_TOOL_BASE::GetAngleSnapMode() const { if( frame()->IsType( FRAME_PCB_EDITOR ) ) - return GetAppSettings( "pcbnew" )->m_Use45DegreeLimit; + return GetAppSettings( "pcbnew" )->m_AngleSnapMode; else - return GetAppSettings( "fpedit" )->m_Use45Limit; + return GetAppSettings( "fpedit" )->m_AngleSnapMode; } diff --git a/pcbnew/tools/pcb_tool_base.h b/pcbnew/tools/pcb_tool_base.h index edd7f78e4d..a19075f51a 100644 --- a/pcbnew/tools/pcb_tool_base.h +++ b/pcbnew/tools/pcb_tool_base.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -114,6 +115,16 @@ public: */ virtual bool Is45Limited() const; + /** + * Should the tool limit drawing to horizontal and vertical only? + */ + virtual bool Is90Limited() const; + + /** + * Get the current angle snapping mode. + */ + LEADER_MODE GetAngleSnapMode() const; + protected: /** * Options for placing items interactively. diff --git a/pcbnew/tools/pcb_viewer_tools.cpp b/pcbnew/tools/pcb_viewer_tools.cpp index 50c7045d03..ddab766f8b 100644 --- a/pcbnew/tools/pcb_viewer_tools.cpp +++ b/pcbnew/tools/pcb_viewer_tools.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -108,11 +109,38 @@ template void Flip( T& aValue ) int PCB_VIEWER_TOOLS::ToggleHV45Mode( const TOOL_EVENT& toolEvent ) { if( frame()->IsType( FRAME_PCB_EDITOR ) ) - Flip( GetAppSettings( "pcbnew" )->m_Use45DegreeLimit ); + { + PCBNEW_SETTINGS* settings = GetAppSettings( "pcbnew" ); + + switch( settings->m_AngleSnapMode ) + { + case LEADER_MODE::DIRECT: settings->m_AngleSnapMode = LEADER_MODE::DEG45; break; + case LEADER_MODE::DEG45: settings->m_AngleSnapMode = LEADER_MODE::DEG90; break; + default: settings->m_AngleSnapMode = LEADER_MODE::DIRECT; break; + } + } else if( frame()->IsType( FRAME_FOOTPRINT_EDITOR ) ) - Flip( GetAppSettings( "fpedit" )->m_Use45Limit ); + { + FOOTPRINT_EDITOR_SETTINGS* settings = GetAppSettings( "fpedit" ); + + switch( settings->m_AngleSnapMode ) + { + case LEADER_MODE::DIRECT: settings->m_AngleSnapMode = LEADER_MODE::DEG45; break; + case LEADER_MODE::DEG45: settings->m_AngleSnapMode = LEADER_MODE::DEG90; break; + default: settings->m_AngleSnapMode = LEADER_MODE::DIRECT; break; + } + } else - Flip( frame()->GetViewerSettingsBase()->m_ViewersDisplay.m_Use45Limit ); + { + LEADER_MODE& mode = frame()->GetViewerSettingsBase()->m_ViewersDisplay.m_AngleSnapMode; + + switch( mode ) + { + case LEADER_MODE::DIRECT: mode = LEADER_MODE::DEG45; break; + case LEADER_MODE::DEG45: mode = LEADER_MODE::DEG90; break; + default: mode = LEADER_MODE::DIRECT; break; + } + } frame()->UpdateStatusBar(); @@ -340,16 +368,22 @@ int PCB_VIEWER_TOOLS::MeasureTool( const TOOL_EVENT& aEvent ) // move or drag when origin set updates rules else if( originSet && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) ) { - bool force45Deg; + auto snap = LEADER_MODE::DIRECT; if( frame()->IsType( FRAME_PCB_EDITOR ) ) - force45Deg = GetAppSettings( "pcbnew" )->m_Use45DegreeLimit; + { + snap = GetAppSettings( "pcbnew" )->m_AngleSnapMode; + } else if( frame()->IsType( FRAME_FOOTPRINT_EDITOR ) ) - force45Deg = GetAppSettings( "fpedit" )->m_Use45Limit; + { + snap = GetAppSettings( "fpedit" )->m_AngleSnapMode; + } else - force45Deg = frame()->GetViewerSettingsBase()->m_ViewersDisplay.m_Use45Limit; + { + snap = frame()->GetViewerSettingsBase()->m_ViewersDisplay.m_AngleSnapMode; + } - twoPtMgr.SetAngleSnap( force45Deg ); + twoPtMgr.SetAngleSnap( snap ); twoPtMgr.SetEnd( cursorPos ); view.SetVisible( &ruler, true ); diff --git a/pcbnew/tools/position_relative_tool.cpp b/pcbnew/tools/position_relative_tool.cpp index c1d410bf26..34da9f17ff 100644 --- a/pcbnew/tools/position_relative_tool.cpp +++ b/pcbnew/tools/position_relative_tool.cpp @@ -348,14 +348,18 @@ int POSITION_RELATIVE_TOOL::PositionRelativeInteractively( const TOOL_EVENT& aEv // move or drag when origin set updates rules else if( originSet && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) ) { - bool force45Deg; + auto snap = LEADER_MODE::DIRECT; if( frame()->IsType( FRAME_PCB_EDITOR ) ) - force45Deg = GetAppSettings( "pcbnew" )->m_Use45DegreeLimit; + { + snap = GetAppSettings( "pcbnew" )->m_AngleSnapMode; + } else - force45Deg = GetAppSettings( "fpedit" )->m_Use45Limit; + { + snap = GetAppSettings( "fpedit" )->m_AngleSnapMode; + } - twoPtMgr.SetAngleSnap( force45Deg ); + twoPtMgr.SetAngleSnap( snap ); twoPtMgr.SetEnd( cursorPos ); view.SetVisible( &ruler, true ); diff --git a/pcbnew/tools/zone_create_helper.cpp b/pcbnew/tools/zone_create_helper.cpp index 3c1f9c2b6f..092e60c993 100644 --- a/pcbnew/tools/zone_create_helper.cpp +++ b/pcbnew/tools/zone_create_helper.cpp @@ -281,8 +281,9 @@ bool ZONE_CREATE_HELPER::OnFirstPoint( POLYGON_GEOM_MANAGER& aMgr ) m_parentView.SetVisible( &m_previewItem, true ); - aMgr.SetLeaderMode( m_tool.Is45Limited() ? POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 - : POLYGON_GEOM_MANAGER::LEADER_MODE::DIRECT ); + LEADER_MODE mode = m_tool.GetAngleSnapMode(); + + aMgr.SetLeaderMode( mode ); } } @@ -328,7 +329,7 @@ void ZONE_CREATE_HELPER::OnComplete( const POLYGON_GEOM_MANAGER& aMgr ) // In DEG45 mode, we may have intermediate points in the leader that should be included // as they are shown in the preview. These typically maintain the 45 constraint - if( aMgr.GetLeaderMode() == POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45 ) + if( aMgr.GetLeaderMode() == LEADER_MODE::DEG45 || aMgr.GetLeaderMode() == LEADER_MODE::DEG90 ) { const SHAPE_LINE_CHAIN leaderPts = aMgr.GetLeaderLinePoints(); diff --git a/pcbnew/tools/zone_create_helper.h b/pcbnew/tools/zone_create_helper.h index 1bf542c8db..dcc4328a9d 100644 --- a/pcbnew/tools/zone_create_helper.h +++ b/pcbnew/tools/zone_create_helper.h @@ -60,7 +60,7 @@ public: ZONE* m_sourceZone; ///< Zone leader mode - POLYGON_GEOM_MANAGER::LEADER_MODE m_leaderMode; + LEADER_MODE m_leaderMode; }; /**