Compare commits
186 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d87537dd2 | |||
| 862d975c2c | |||
| 45d58fbefc | |||
| 7b7e4e1ae5 | |||
| 3f04b80ff4 | |||
| 5830cdd1c0 | |||
| 2416b28cda | |||
| 729cf7a39d | |||
| 4d56690a7e | |||
| e30128f6f5 | |||
| c4a42f28c8 | |||
| bdbbba54f9 | |||
| 80c2fb39b1 | |||
| 63506cf777 | |||
| 6c1d615f66 | |||
| c0ca2f1830 | |||
| cf5f36aac5 | |||
| cc51807241 | |||
| e1865c1178 | |||
| b81ba520f8 | |||
| edbb9c5194 | |||
| cda6aed408 | |||
| 74172612fa | |||
| 7209239a62 | |||
| 16edde8611 | |||
| 33f8bcb7c7 | |||
| fb6505d8cb | |||
| 39935311fc | |||
| 851f893e8e | |||
| bfa1661edf | |||
| 110663d214 | |||
| 847fa7f2c4 | |||
| ef798f446f | |||
| 2de1bd7a4a | |||
| 250942264b | |||
| 6818eff90e | |||
| b2eb1f829e | |||
| a60e7e27b6 | |||
| 601995c759 | |||
| 63ce2307c8 | |||
| 03bc9551c7 | |||
| c8cd214cb0 | |||
| fe11bc8330 | |||
| d0796399a2 | |||
| c2d72180f8 | |||
| 57729414e3 | |||
| b664fb7a7d | |||
| fe1a8bea8c | |||
| 3606ad725c | |||
| e8e24b372f | |||
| 3bfa5807c8 | |||
| b797735c24 | |||
| d0af5fb5fc | |||
| 5ca91c404a | |||
| 6ba7967adc | |||
| 9dfc492cb9 | |||
| 0876fed91b | |||
| 651f50a26d | |||
| 99456d4351 | |||
| 529048dac1 | |||
| be2e0cc272 | |||
| 48a776f7c5 | |||
| 43929781a2 | |||
| e02229a234 | |||
| 821fe6ea42 | |||
| e740db61f5 | |||
| a700531aba | |||
| 7d9cf00fd9 | |||
| 6127ae92a5 | |||
| f8c92e355b | |||
| f7f6ea54fe | |||
| fdfe5a813e | |||
| 636d009860 | |||
| 7d96d5940d | |||
| d3a60f7d83 | |||
| 604871518f | |||
| 5a68077f60 | |||
| 8054f1a948 | |||
| 80bf1048d0 | |||
| d85e52e9fd | |||
| e21f0ec9fb | |||
| 1adfca8f2d | |||
| f89256e51e | |||
| e98e9f72df | |||
| f8ff9705ff | |||
| e3e52d055a | |||
| 6de8b99cf2 | |||
| c9829cf9a8 | |||
| 0fc4ccf8d9 | |||
| 330b1fd733 | |||
| 455ec428f2 | |||
| 39959844e5 | |||
| d5de4bb5c7 | |||
| 6706a5c462 | |||
| 15fe2f2fd0 | |||
| c23679d9bd | |||
| f226772938 | |||
| 6a53e318e5 | |||
| 776a28a10e | |||
| 3a98eacdb9 | |||
| a8004cb161 | |||
| f00222b3a6 | |||
| 96dded48d4 | |||
| 950cccdc1c | |||
| 5b7a1a8177 | |||
| 96aa472ff9 | |||
| 0ec50e9096 | |||
| 6bc48e9ca8 | |||
| 5505add08e | |||
| 4d8297a1f6 | |||
| e1cd74dd78 | |||
| 2567f45c1d | |||
| 0ea7dabc12 | |||
| bf8c7d7697 | |||
| 891c919c23 | |||
| 375a7303c5 | |||
| e14e9cf8a9 | |||
| 4e98ce87c7 | |||
| 207820e112 | |||
| dbbecefcb9 | |||
| df8f166847 | |||
| 79ef8e14aa | |||
| 5081165611 | |||
| 3bfcaf2455 | |||
| 9e2416d2c9 | |||
| 49eecf66fe | |||
| bc3a4e4ede | |||
| 3645c3c0cc | |||
| 7902c1cc58 | |||
| 2a2781e1bc | |||
| 9510b07807 | |||
| 072c0f06cd | |||
| b75e782aef | |||
| d9fe48171b | |||
| eeee5afdfd | |||
| 790b810621 | |||
| e33bf78d96 | |||
| bd86999615 | |||
| 1b108afd0b | |||
| a8384beb6f | |||
| c44d31fcfb | |||
| d801a8689c | |||
| 4a1abd239a | |||
| 423732910d | |||
| e4ce5e5262 | |||
| 2998d31f2c | |||
| da98413f82 | |||
| f562466189 | |||
| 0deae6bdd2 | |||
| 31f8e73cf8 | |||
| e58f50602d | |||
| c870505141 | |||
| c20e81fbdd | |||
| 58d0c4112d | |||
| 1cb80e1ad0 | |||
| 2584c46c28 | |||
| 2ce96415a6 | |||
| 8eded13d96 | |||
| 069143dc05 | |||
| 9d09ce0538 | |||
| d9dd691108 | |||
| f69ebe55ad | |||
| ff604cc6a3 | |||
| 8ccc5bd8f2 | |||
| 02b1f552fd | |||
| f058dc9ed8 | |||
| 2c061ed67a | |||
| 9bfbe3acd8 | |||
| 40bdd26e39 | |||
| b0f8055377 | |||
| 33f4fc9873 | |||
| c90842dd08 | |||
| 310b4cdf75 | |||
| 2208e0db16 | |||
| cf4c403094 | |||
| dd55ffb75c | |||
| d34faf30cc | |||
| 3720a52ecb | |||
| 47de9f8f04 | |||
| 14378812be | |||
| 0070a4686e | |||
| 5c63df28e4 | |||
| e5ea37507c | |||
| 53bd87d792 | |||
| 02252be29d | |||
| 9e9598af5f |
+1
-1
@@ -40,6 +40,6 @@ include:
|
||||
- local: '/.gitlab/templates.yml'
|
||||
- local: '/.gitlab/Fedora-Linux-CI.yml'
|
||||
- local: '/.gitlab/Ubuntu-20.04-CI.yml'
|
||||
- local: '/.gitlab/Windows-CI.yml'
|
||||
# - local: '/.gitlab/Windows-CI.yml'
|
||||
- local: '/.gitlab/coverity.yml'
|
||||
- local: '/.gitlab/linux-metadata-validate.yml'
|
||||
|
||||
@@ -493,15 +493,10 @@ void BOARD_ADAPTER::addPadsWithClearance( const FOOTPRINT* aFootprint,
|
||||
{
|
||||
for( PAD* pad : aFootprint->Pads() )
|
||||
{
|
||||
if( !pad->IsOnLayer( aLayerId ) )
|
||||
if( !pad->FlashLayer( aLayerId ) )
|
||||
continue;
|
||||
|
||||
// Skip pad annulus when not connected on this layer (if removing is enabled)
|
||||
if( !pad->FlashLayer( aLayerId ) && IsCopperLayer( aLayerId ) )
|
||||
continue;
|
||||
|
||||
// NPTH pads are not drawn on layers if the
|
||||
// shape size and pos is the same as their hole:
|
||||
// NPTH pads are not drawn on layers if the shape size and pos is the same as their hole:
|
||||
if( aSkipNPTHPadsWihNoCopper && ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
|
||||
{
|
||||
if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == wxPoint( 0, 0 ) )
|
||||
@@ -526,19 +521,28 @@ void BOARD_ADAPTER::addPadsWithClearance( const FOOTPRINT* aFootprint,
|
||||
}
|
||||
}
|
||||
|
||||
const bool isPlated = ( ( aLayerId == F_Cu ) && pad->FlashLayer( F_Mask ) ) ||
|
||||
( ( aLayerId == B_Cu ) && pad->FlashLayer( B_Mask ) );
|
||||
|
||||
if( aSkipPlatedPads && isPlated )
|
||||
continue;
|
||||
|
||||
if( aSkipNonPlatedPads && !isPlated )
|
||||
continue;
|
||||
|
||||
wxSize margin( aInflateValue, aInflateValue );
|
||||
|
||||
switch( aLayerId )
|
||||
{
|
||||
case F_Cu:
|
||||
if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
|
||||
continue;
|
||||
|
||||
if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
case B_Cu:
|
||||
if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
|
||||
continue;
|
||||
|
||||
if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
case F_Mask:
|
||||
case B_Mask:
|
||||
margin.x += pad->GetSolderMaskMargin();
|
||||
|
||||
@@ -549,7 +549,6 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
for( FOOTPRINT* footprint : m_board->Footprints() )
|
||||
{
|
||||
addPadsWithClearance( footprint, m_platedPadsFront, F_Cu, 0, true, false, true );
|
||||
|
||||
addPadsWithClearance( footprint, m_platedPadsBack, B_Cu, 0, true, false, true );
|
||||
}
|
||||
|
||||
@@ -569,8 +568,8 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
// Add pads to polygon list
|
||||
for( FOOTPRINT* footprint : m_board->Footprints() )
|
||||
{
|
||||
// Note: NPTH pads are not drawn on copper layers when the pad
|
||||
// has same shape as its hole
|
||||
// Note: NPTH pads are not drawn on copper layers when the pad has same shape as
|
||||
// its hole
|
||||
footprint->TransformPadsWithClearanceToPolygon( *layerPoly, curr_layer_id,
|
||||
0, ARC_HIGH_DEF, ERROR_INSIDE,
|
||||
true, renderPlatedPadsAsPlated,
|
||||
|
||||
@@ -374,6 +374,22 @@ OPENGL_RENDER_LIST* RENDER_3D_OPENGL::generateLayerList( const BVH_CONTAINER_2D*
|
||||
}
|
||||
|
||||
|
||||
OPENGL_RENDER_LIST* RENDER_3D_OPENGL::generateEmptyLayerList( PCB_LAYER_ID aLayerId )
|
||||
{
|
||||
float layer_z_bot = 0.0f;
|
||||
float layer_z_top = 0.0f;
|
||||
|
||||
getLayerZPos( aLayerId, layer_z_top, layer_z_bot );
|
||||
|
||||
TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( 1 );
|
||||
|
||||
// store in a list so it will be latter deleted
|
||||
m_triangles.push_back( layerTriangles );
|
||||
|
||||
return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, layer_z_bot, layer_z_top );
|
||||
}
|
||||
|
||||
|
||||
OPENGL_RENDER_LIST* RENDER_3D_OPENGL::createBoard( const SHAPE_POLY_SET& aBoardPoly,
|
||||
const BVH_CONTAINER_2D* aThroughHoles )
|
||||
{
|
||||
@@ -388,9 +404,8 @@ OPENGL_RENDER_LIST* RENDER_3D_OPENGL::createBoard( const SHAPE_POLY_SET& aBoardP
|
||||
|
||||
if( listBoardObject2d.size() > 0 )
|
||||
{
|
||||
// We will set a unitary Z so it will in future used with transformations
|
||||
// since the board poly will be used not only to draw itself but also the
|
||||
// solder mask layers.
|
||||
// We will set a unitary Z so it will in future used with transformations since the
|
||||
// board poly will be used not only to draw itself but also the solder mask layers.
|
||||
const float layer_z_top = 1.0f;
|
||||
const float layer_z_bot = 0.0f;
|
||||
|
||||
@@ -563,7 +578,7 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
|
||||
const BVH_CONTAINER_2D* container2d = ii.second;
|
||||
|
||||
SHAPE_POLY_SET polyListSubtracted;
|
||||
SHAPE_POLY_SET* aPolyList = nullptr;
|
||||
SHAPE_POLY_SET* polyList = nullptr;
|
||||
|
||||
// Load the vertical (Z axis) component of shapes
|
||||
|
||||
@@ -580,9 +595,8 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
|
||||
{
|
||||
polyListSubtracted.BooleanSubtract( m_boardAdapter.GetThroughHoleOdPolys(),
|
||||
SHAPE_POLY_SET::PM_FAST );
|
||||
polyListSubtracted.BooleanSubtract(
|
||||
m_boardAdapter.GetOuterNonPlatedThroughHolePoly(),
|
||||
SHAPE_POLY_SET::PM_FAST );
|
||||
polyListSubtracted.BooleanSubtract( m_boardAdapter.GetOuterNonPlatedThroughHolePoly(),
|
||||
SHAPE_POLY_SET::PM_FAST );
|
||||
}
|
||||
|
||||
if( m_boardAdapter.GetFlag( FL_SUBTRACT_MASK_FROM_SILK ) )
|
||||
@@ -600,10 +614,10 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
|
||||
}
|
||||
}
|
||||
|
||||
aPolyList = &polyListSubtracted;
|
||||
polyList = &polyListSubtracted;
|
||||
}
|
||||
|
||||
OPENGL_RENDER_LIST* oglList = generateLayerList( container2d, aPolyList, layer_id,
|
||||
OPENGL_RENDER_LIST* oglList = generateLayerList( container2d, polyList, layer_id,
|
||||
&m_boardAdapter.GetThroughHoleIds() );
|
||||
|
||||
if( oglList != nullptr )
|
||||
@@ -626,6 +640,10 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
|
||||
|
||||
m_platedPadsFront = generateLayerList( m_boardAdapter.GetPlatedPadsFront(),
|
||||
&polySubtracted, F_Cu );
|
||||
|
||||
// An entry for F_Cu must exist in m_layers or we'll never look at m_platedPadsFront
|
||||
if( m_layers.count( F_Cu ) == 0 )
|
||||
m_layers[F_Cu] = generateEmptyLayerList( F_Cu );
|
||||
}
|
||||
|
||||
if( m_boardAdapter.GetBackPlatedPadPolys() )
|
||||
@@ -640,6 +658,10 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
|
||||
|
||||
m_platedPadsBack = generateLayerList( m_boardAdapter.GetPlatedPadsBack(),
|
||||
&polySubtracted, B_Cu );
|
||||
|
||||
// An entry for B_Cu must exist in m_layers or we'll never look at m_platedPadsBack
|
||||
if( m_layers.count( B_Cu ) == 0 )
|
||||
m_layers[B_Cu] = generateEmptyLayerList( B_Cu );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -650,6 +650,7 @@ GLuint OPENGL_RENDER_LIST::generate_top_or_bot_seg_ends(
|
||||
|
||||
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, 0 );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
glDisable( GL_ALPHA_TEST );
|
||||
glDisable( GL_BLEND );
|
||||
|
||||
@@ -504,7 +504,7 @@ void RENDER_3D_OPENGL::setCopperMaterial()
|
||||
void RENDER_3D_OPENGL::setPlatedCopperAndDepthOffset( PCB_LAYER_ID aLayer_id )
|
||||
{
|
||||
glEnable( GL_POLYGON_OFFSET_FILL );
|
||||
glPolygonOffset(-0.1f, -2.0f );
|
||||
glPolygonOffset( -0.1f, -2.0f );
|
||||
setLayerMaterial( aLayer_id );
|
||||
}
|
||||
|
||||
@@ -704,18 +704,16 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
{
|
||||
pLayerDispList->DrawAllCameraCulled( m_camera.GetPos().z, drawMiddleSegments );
|
||||
|
||||
// Draw copper plated pads
|
||||
if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
|
||||
( m_platedPadsFront || m_platedPadsBack ) )
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
|
||||
// Draw plated pads
|
||||
if( layer_id == F_Cu && m_platedPadsFront )
|
||||
{
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
m_platedPadsFront->DrawAllCameraCulled( m_camera.GetPos().z,
|
||||
drawMiddleSegments );
|
||||
}
|
||||
else if( layer_id == B_Cu && m_platedPadsBack )
|
||||
{
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
m_platedPadsBack->DrawAllCameraCulled( m_camera.GetPos().z,
|
||||
drawMiddleSegments );
|
||||
}
|
||||
@@ -751,16 +749,10 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
viasHolesLayer,
|
||||
m_antiBoard );
|
||||
|
||||
// Draw copper plated pads
|
||||
|
||||
if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
|
||||
( m_platedPadsFront || m_platedPadsBack ) )
|
||||
{
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
}
|
||||
|
||||
// Draw plated pads
|
||||
if( layer_id == F_Cu && m_platedPadsFront )
|
||||
{
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
m_platedPadsFront->DrawAllCameraCulledSubtractLayer(
|
||||
drawMiddleSegments,
|
||||
m_outerThroughHoles,
|
||||
@@ -769,6 +761,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
}
|
||||
else if( layer_id == B_Cu && m_platedPadsBack )
|
||||
{
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
m_platedPadsBack->DrawAllCameraCulledSubtractLayer(
|
||||
drawMiddleSegments,
|
||||
m_outerThroughHoles,
|
||||
@@ -785,21 +778,16 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
m_outerThroughHoles,
|
||||
m_antiBoard );
|
||||
|
||||
// Draw copper plated pads
|
||||
if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
|
||||
( m_platedPadsFront || m_platedPadsBack ) )
|
||||
{
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
}
|
||||
|
||||
if( layer_id == F_Cu && m_platedPadsFront )
|
||||
{
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
m_platedPadsFront->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
|
||||
m_outerThroughHoles,
|
||||
m_antiBoard );
|
||||
}
|
||||
else if( layer_id == B_Cu && m_platedPadsBack )
|
||||
{
|
||||
setPlatedCopperAndDepthOffset( layer_id );
|
||||
m_platedPadsBack->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
|
||||
m_outerThroughHoles,
|
||||
m_antiBoard );
|
||||
|
||||
@@ -84,6 +84,8 @@ private:
|
||||
PCB_LAYER_ID aLayerId,
|
||||
const BVH_CONTAINER_2D* aThroughHoles = nullptr );
|
||||
|
||||
OPENGL_RENDER_LIST* generateEmptyLayerList( PCB_LAYER_ID aLayerId );
|
||||
|
||||
void addTopAndBottomTriangles( TRIANGLE_DISPLAY_LIST* aDst, const SFVEC2F& v0,
|
||||
const SFVEC2F& v1, const SFVEC2F& v2, float top, float bot );
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <kiface_base.h>
|
||||
#include <tools/eda_3d_controller.h>
|
||||
#include "eda_3d_actions.h"
|
||||
#include "dialogs/panel_preview_3d_model.h"
|
||||
#include <3d_rendering/opengl/render_3d_opengl.h>
|
||||
|
||||
|
||||
@@ -113,10 +114,36 @@ int EDA_3D_CONTROLLER::Main( const TOOL_EVENT& aEvent )
|
||||
// Main loop: keep receiving events
|
||||
while( TOOL_EVENT* evt = Wait() )
|
||||
{
|
||||
if( evt->IsClick( BUT_RIGHT ) )
|
||||
if( evt->IsCancelInteractive() )
|
||||
{
|
||||
wxWindow* canvas = m_toolMgr->GetToolHolder()->GetToolCanvas();
|
||||
wxWindow* topLevelParent = canvas->GetParent();
|
||||
|
||||
while( topLevelParent && !topLevelParent->IsTopLevel() )
|
||||
topLevelParent = topLevelParent->GetParent();
|
||||
|
||||
if( topLevelParent && dynamic_cast<DIALOG_SHIM*>( topLevelParent ) )
|
||||
{
|
||||
DIALOG_SHIM* dialog = static_cast<DIALOG_SHIM*>( topLevelParent );
|
||||
|
||||
if( dialog->IsQuasiModal() )
|
||||
dialog->EndQuasiModal( wxID_CANCEL );
|
||||
else
|
||||
dialog->EndModal( wxID_CANCEL );
|
||||
}
|
||||
else
|
||||
{
|
||||
evt->SetPassEvent();
|
||||
}
|
||||
}
|
||||
else if( evt->IsClick( BUT_RIGHT ) )
|
||||
{
|
||||
m_menu.ShowContextMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
evt->SetPassEvent();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -124,8 +124,10 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
|
||||
m_SizerPanelView->Add( m_previewPane, 1, wxEXPAND, 5 );
|
||||
|
||||
for( wxEventType eventType : { wxEVT_MENU_OPEN, wxEVT_MENU_CLOSE, wxEVT_MENU_HIGHLIGHT } )
|
||||
{
|
||||
Connect( eventType, wxMenuEventHandler( PANEL_PREVIEW_3D_MODEL::OnMenuEvent ), nullptr,
|
||||
this );
|
||||
}
|
||||
|
||||
#ifdef __WXOSX__
|
||||
// Call layout once to get the proper button sizes after the bitmaps have been set
|
||||
|
||||
+5
-3
@@ -848,9 +848,11 @@ if( UNIX AND NOT APPLE AND KICAD_SCRIPTING_WXPYTHON )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message( STATUS "Found ${WXPYTHON_FLAVOR} "
|
||||
"${WXPYTHON_VERSION}/${WXPYTHON_TOOLKIT} "
|
||||
"(wxWidgets ${WXPYTHON_WXVERSION})" )
|
||||
if( WXPYTHON_FLAVOR )
|
||||
message( STATUS "Found wxPython ${WXPYTHON_FLAVOR} "
|
||||
"${WXPYTHON_VERSION}/${WXPYTHON_TOOLKIT} "
|
||||
"(wxWidgets ${WXPYTHON_WXVERSION})" )
|
||||
endif()
|
||||
|
||||
#
|
||||
# Find wxWidgets library, required
|
||||
|
||||
@@ -231,11 +231,7 @@ endif()
|
||||
#=====================================================================
|
||||
if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
# Useful common wx libs needed by almost all components.
|
||||
if(VCPKG_TOOLCHAIN)
|
||||
set(wxWidgets_COMMON_LIBRARIES libpng16 tiff jpeg zlib libexpat)
|
||||
else()
|
||||
set(wxWidgets_COMMON_LIBRARIES png tiff jpeg zlib regex expat)
|
||||
endif()
|
||||
set(wxWidgets_COMMON_LIBRARIES png tiff jpeg zlib regex expat)
|
||||
|
||||
# DEPRECATED: Use find_package(wxWidgets COMPONENTS mono) instead.
|
||||
if(NOT wxWidgets_FIND_COMPONENTS)
|
||||
@@ -258,22 +254,24 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
#-------------------------------------------------------------------
|
||||
#
|
||||
# Get filename components for a configuration. For example,
|
||||
# if _CONFIGURATION = mswunivud, then _UNV=univ, _UCD=u _DBG=d
|
||||
# if _CONFIGURATION = mswu, then _UNV="", _UCD=u _DBG=""
|
||||
# if _CONFIGURATION = mswunivud, then _PF="msw", _UNV=univ, _UCD=u _DBG=d
|
||||
# if _CONFIGURATION = mswu, then _PF="msw", _UNV="", _UCD=u _DBG=""
|
||||
#
|
||||
macro(WX_GET_NAME_COMPONENTS _CONFIGURATION _UNV _UCD _DBG)
|
||||
macro(WX_GET_NAME_COMPONENTS _CONFIGURATION _PF _UNV _UCD _DBG)
|
||||
DBG_MSG_V(${_CONFIGURATION})
|
||||
string(REGEX MATCH "univ" ${_UNV} "${_CONFIGURATION}")
|
||||
string(REGEX REPLACE "msw.*(u)[d]*$" "u" ${_UCD} "${_CONFIGURATION}")
|
||||
string(REGEX REPLACE "[msw|qt].*(u)[d]*$" "u" ${_UCD} "${_CONFIGURATION}")
|
||||
if(${_UCD} STREQUAL ${_CONFIGURATION})
|
||||
set(${_UCD} "")
|
||||
endif()
|
||||
string(REGEX MATCH "d$" ${_DBG} "${_CONFIGURATION}")
|
||||
string(REGEX MATCH "^[msw|qt]*" ${_PF} "${_CONFIGURATION}")
|
||||
endmacro()
|
||||
|
||||
#
|
||||
# Find libraries associated to a configuration.
|
||||
#
|
||||
macro(WX_FIND_LIBS _UNV _UCD _DBG)
|
||||
macro(WX_FIND_LIBS _PF _UNV _UCD _DBG)
|
||||
DBG_MSG_V("m_unv = ${_UNV}")
|
||||
DBG_MSG_V("m_ucd = ${_UCD}")
|
||||
DBG_MSG_V("m_dbg = ${_DBG}")
|
||||
@@ -286,7 +284,6 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
NAMES
|
||||
wx${LIB}${_UCD}${_DBG} # for regex
|
||||
wx${LIB}${_DBG}
|
||||
${LIB}${_DBG} # vcpkg libraries aren't specific to wx
|
||||
PATHS ${WX_LIB_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
@@ -326,13 +323,13 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
# Find wxWidgets monolithic library.
|
||||
find_library(WX_mono${_DBG}
|
||||
NAMES
|
||||
wxmsw${_UNV}31${_UCD}${_DBG}
|
||||
wxmsw${_UNV}30${_UCD}${_DBG}
|
||||
wxmsw${_UNV}29${_UCD}${_DBG}
|
||||
wxmsw${_UNV}28${_UCD}${_DBG}
|
||||
wxmsw${_UNV}27${_UCD}${_DBG}
|
||||
wxmsw${_UNV}26${_UCD}${_DBG}
|
||||
wxmsw${_UNV}25${_UCD}${_DBG}
|
||||
wx${_PF}${_UNV}31${_UCD}${_DBG}
|
||||
wx${_PF}${_UNV}30${_UCD}${_DBG}
|
||||
wx${_PF}${_UNV}29${_UCD}${_DBG}
|
||||
wx${_PF}${_UNV}28${_UCD}${_DBG}
|
||||
wx${_PF}${_UNV}27${_UCD}${_DBG}
|
||||
wx${_PF}${_UNV}26${_UCD}${_DBG}
|
||||
wx${_PF}${_UNV}25${_UCD}${_DBG}
|
||||
PATHS ${WX_LIB_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
@@ -340,16 +337,16 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
|
||||
# Find wxWidgets multilib libraries.
|
||||
foreach(LIB core adv aui html media xrc dbgrid gl qa richtext
|
||||
webview stc ribbon propgrid)
|
||||
stc ribbon propgrid webview)
|
||||
find_library(WX_${LIB}${_DBG}
|
||||
NAMES
|
||||
wxmsw${_UNV}31${_UCD}${_DBG}_${LIB}
|
||||
wxmsw${_UNV}30${_UCD}${_DBG}_${LIB}
|
||||
wxmsw${_UNV}29${_UCD}${_DBG}_${LIB}
|
||||
wxmsw${_UNV}28${_UCD}${_DBG}_${LIB}
|
||||
wxmsw${_UNV}27${_UCD}${_DBG}_${LIB}
|
||||
wxmsw${_UNV}26${_UCD}${_DBG}_${LIB}
|
||||
wxmsw${_UNV}25${_UCD}${_DBG}_${LIB}
|
||||
wx${_PF}${_UNV}31${_UCD}${_DBG}_${LIB}
|
||||
wx${_PF}${_UNV}30${_UCD}${_DBG}_${LIB}
|
||||
wx${_PF}${_UNV}29${_UCD}${_DBG}_${LIB}
|
||||
wx${_PF}${_UNV}28${_UCD}${_DBG}_${LIB}
|
||||
wx${_PF}${_UNV}27${_UCD}${_DBG}_${LIB}
|
||||
wx${_PF}${_UNV}26${_UCD}${_DBG}_${LIB}
|
||||
wx${_PF}${_UNV}25${_UCD}${_DBG}_${LIB}
|
||||
PATHS ${WX_LIB_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
@@ -515,74 +512,6 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
set(WX_LIB_DIR_PREFIX vc)
|
||||
endif()
|
||||
|
||||
if(VCPKG_TOOLCHAIN)
|
||||
set(wxWidgets_FOUND TRUE)
|
||||
find_path(wxWidgets_ROOT_DIR
|
||||
NAMES include/wx/wx.h
|
||||
PATHS
|
||||
ENV wxWidgets_ROOT_DIR
|
||||
DOC "wxWidgets base/installation directory"
|
||||
)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(wxWidgets_LIB_DIR ${wxWidgets_ROOT_DIR}/debug/lib)
|
||||
set(wxWidgets_CONFIGURATION mswud)
|
||||
else()
|
||||
set(wxWidgets_LIB_DIR ${wxWidgets_ROOT_DIR}/lib)
|
||||
set(wxWidgets_CONFIGURATION mswu)
|
||||
endif()
|
||||
|
||||
set(wxWidgets_BIN_DIR ${wxWidgets_ROOT_DIR}/bin)
|
||||
set(wxWidgets_INCLUDE_DIR ${wxWidgets_ROOT_DIR}/include)
|
||||
file(GLOB DLL ${wxWidgets_BIN_DIR}/wxmsw*.dll)
|
||||
if (DLL)
|
||||
set(wxWidgets_DEFINITIONS WXUSINGDLL)
|
||||
DBG_MSG_V("detected SHARED/DLL tree wxWidgets_LIB_DIR=${wxWidgets_LIB_DIR}")
|
||||
endif ()
|
||||
set(WX_ROOT_DIR ${wxWidgets_ROOT_DIR})
|
||||
set(WX_LIB_DIR ${wxWidgets_LIB_DIR}) # needed by macro
|
||||
set(WX_CONFIGURATION_LIST ${wxWidgets_CONFIGURATION})
|
||||
|
||||
# Set wxWidgets lib setup include directory.
|
||||
if (EXISTS ${wxWidgets_INCLUDE_DIR}/wx/setup.h)
|
||||
set(wxWidgets_INCLUDE_DIRS ${wxWidgets_INCLUDE_DIR})
|
||||
else ()
|
||||
DBG_MSG("wxWidgets_FOUND FALSE because ${wxWidgets_INCLUDE_DIR}/wx/setup.h does not exists.")
|
||||
set(wxWidgets_FOUND FALSE)
|
||||
endif ()
|
||||
|
||||
# Set wxWidgets main include directory.
|
||||
if (EXISTS ${wxWidgets_ROOT_DIR}/include/wx/wx.h)
|
||||
list(APPEND wxWidgets_INCLUDE_DIRS ${wxWidgets_ROOT_DIR}/include)
|
||||
else ()
|
||||
DBG_MSG("wxWidgets_FOUND FALSE because wxWidgets_ROOT_DIR=${wxWidgets_ROOT_DIR} has no ${wxWidgets_ROOT_DIR}/include/wx/wx.h")
|
||||
set(wxWidgets_FOUND FALSE)
|
||||
endif ()
|
||||
|
||||
DBG_MSG_V("WX_CONFIGURATION_LIST=${WX_CONFIGURATION_LIST}")
|
||||
|
||||
|
||||
# Get configuration parameters from the name.
|
||||
WX_GET_NAME_COMPONENTS(${wxWidgets_CONFIGURATION} UNV UCD DBG)
|
||||
|
||||
|
||||
# Find wxWidgets libraries.
|
||||
WX_FIND_LIBS("${UNV}" "${UCD}" "${DBG}")
|
||||
if (WX_USE_REL_AND_DBG)
|
||||
WX_FIND_LIBS("${UNV}" "${UCD}" "d")
|
||||
endif ()
|
||||
|
||||
# Settings for requested libs (i.e., include dir, libraries, etc.).
|
||||
WX_SET_LIBRARIES(wxWidgets_FIND_COMPONENTS "${DBG}")
|
||||
|
||||
# Add necessary definitions for unicode builds
|
||||
if ("${UCD}" STREQUAL "u")
|
||||
list(APPEND wxWidgets_DEFINITIONS UNICODE _UNICODE)
|
||||
endif ()
|
||||
|
||||
# Add necessary definitions for debug builds
|
||||
set(wxWidgets_DEFINITIONS_DEBUG _DEBUG __WXDEBUG__)
|
||||
|
||||
else()
|
||||
if(BUILD_SHARED_LIBS)
|
||||
find_path(wxWidgets_LIB_DIR
|
||||
NAMES
|
||||
@@ -617,7 +546,6 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
DOC "Path to wxWidgets libraries"
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# If wxWidgets_LIB_DIR changed, clear all libraries.
|
||||
@@ -675,7 +603,7 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
endif()
|
||||
|
||||
# Get configuration parameters from the name.
|
||||
WX_GET_NAME_COMPONENTS(${wxWidgets_CONFIGURATION} UNV UCD DBG)
|
||||
WX_GET_NAME_COMPONENTS(${wxWidgets_CONFIGURATION} PF UNV UCD DBG)
|
||||
|
||||
# Set wxWidgets lib setup include directory.
|
||||
if(EXISTS ${WX_LIB_DIR}/${wxWidgets_CONFIGURATION}/wx/setup.h)
|
||||
@@ -695,9 +623,9 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
|
||||
endif()
|
||||
|
||||
# Find wxWidgets libraries.
|
||||
WX_FIND_LIBS("${UNV}" "${UCD}" "${DBG}")
|
||||
WX_FIND_LIBS("${PF}" "${UNV}" "${UCD}" "${DBG}")
|
||||
if(WX_USE_REL_AND_DBG)
|
||||
WX_FIND_LIBS("${UNV}" "${UCD}" "d")
|
||||
WX_FIND_LIBS("${PF}" "${UNV}" "${UCD}" "d")
|
||||
endif()
|
||||
|
||||
# Settings for requested libs (i.e., include dir, libraries, etc.).
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# KiCad.
|
||||
#
|
||||
# Note: This version string should follow the semantic versioning system
|
||||
set( KICAD_SEMANTIC_VERSION "6.0.3" )
|
||||
set( KICAD_SEMANTIC_VERSION "6.0.5" )
|
||||
|
||||
# Default the version to the semantic version.
|
||||
# This is overridden by the git repository tag though (if using git)
|
||||
|
||||
@@ -158,7 +158,6 @@ wxImage BITMAP_STORE::getImage( BITMAPS aBitmapId, int aHeight )
|
||||
|
||||
wxMemoryInputStream is( data, count );
|
||||
wxImage image( is, wxBITMAP_TYPE_PNG );
|
||||
wxBitmap bitmap( image );
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -152,9 +152,8 @@ wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
|
||||
}
|
||||
else if( m_titleBlock )
|
||||
{
|
||||
m_titleBlock->TextVarResolver( token, m_project );
|
||||
// no need for tokenUpdated; TextVarResolver() did a full resolve
|
||||
return true;
|
||||
return m_titleBlock->TextVarResolver( token, m_project );
|
||||
}
|
||||
|
||||
if( tokenUpdated )
|
||||
|
||||
@@ -694,7 +694,7 @@ void EDA_DRAW_FRAME::SetMsgPanel( EDA_ITEM* aItem )
|
||||
|
||||
void EDA_DRAW_FRAME::UpdateMsgPanel()
|
||||
{
|
||||
GetToolManager()->PostEvent( EVENTS::SelectedItemsModified );
|
||||
GetToolManager()->ProcessEvent( EVENTS::SelectedItemsModified );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ static struct EDA_ITEM_DESC
|
||||
.Map( PCB_FP_SHAPE_T, _HKI( "Graphic" ) )
|
||||
.Map( PCB_FP_ZONE_T, _HKI( "Zone" ) )
|
||||
.Map( PCB_TRACE_T, _HKI( "Track" ) )
|
||||
.Map( PCB_ARC_T, _HKI( "Track" ) )
|
||||
.Map( PCB_VIA_T, _HKI( "Via" ) )
|
||||
.Map( PCB_MARKER_T, _HKI( "Marker" ) )
|
||||
.Map( PCB_DIM_ALIGNED_T, _HKI( "Dimension" ) )
|
||||
|
||||
+13
-1
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 Ian McInerney <Ian.S.McInerney@ieee.org>
|
||||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -165,6 +165,18 @@ void FILE_HISTORY::doAddClearItem( wxMenu* aMenu )
|
||||
}
|
||||
|
||||
|
||||
void FILE_HISTORY::UpdateClearText( wxMenu* aMenu, wxString aClearText )
|
||||
{
|
||||
size_t itemPos;
|
||||
wxMenuItem* clearItem = aMenu->FindChildItem( m_clearId, &itemPos );
|
||||
|
||||
if( clearItem && itemPos > 1 ) // clearItem is the last menu, after a separator
|
||||
{
|
||||
clearItem->SetItemLabel( aClearText );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FILE_HISTORY::ClearFileHistory()
|
||||
{
|
||||
while( GetCount() > 0 )
|
||||
|
||||
+8
-2
@@ -40,8 +40,14 @@
|
||||
// boost:mt19937 is not thread-safe
|
||||
static std::mutex rng_mutex;
|
||||
|
||||
// Create only once, as seeding is *very* expensive
|
||||
static boost::mt19937 rng;
|
||||
// Static rng and generators are used because the overhead of constant seeding is expensive
|
||||
// We break out the rng separately from the generator because we want to control seeding in cases like unit tests
|
||||
#if BOOST_VERSION >= 106700
|
||||
static boost::uuids::detail::random_provider seeder; // required to ensure the rng has a random initial seed
|
||||
#else
|
||||
static boost::uuids::detail::seed_rng seeder; // required to ensure the rng has a random initial seed
|
||||
#endif
|
||||
static boost::mt19937 rng( seeder );
|
||||
static boost::uuids::basic_random_generator<boost::mt19937> randomGenerator( rng );
|
||||
|
||||
// These don't have the same performance penalty, but we might as well be consistent
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -842,18 +842,6 @@ void GERBER_PLOTTER::plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion )
|
||||
wxPoint start( aArc.GetP0() );
|
||||
wxPoint end( aArc.GetP1() );
|
||||
wxPoint center( aArc.GetCenter() );
|
||||
double startAngle = aArc.GetStartAngle();
|
||||
double endAngle = aArc.GetEndAngle();
|
||||
|
||||
if( startAngle > endAngle )
|
||||
{
|
||||
if( endAngle < 0.0 )
|
||||
endAngle = NormalizeAnglePos( endAngle ) ;
|
||||
else
|
||||
{
|
||||
startAngle = NormalizeAnglePos( startAngle ) - 3600.0;
|
||||
}
|
||||
}
|
||||
|
||||
if( !aPlotInRegion )
|
||||
MoveTo( start);
|
||||
@@ -861,14 +849,20 @@ void GERBER_PLOTTER::plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion )
|
||||
LineTo( start );
|
||||
|
||||
DPOINT devEnd = userToDeviceCoordinates( end );
|
||||
DPOINT devCenter = userToDeviceCoordinates( center ) - userToDeviceCoordinates( start );
|
||||
DPOINT devCenter = userToDeviceCoordinates( center - start );
|
||||
VECTOR2I arcMidPoint = aArc.GetArcMid();
|
||||
|
||||
// We need to know if the arc is CW or CCW in device coordinates, so build this arc.
|
||||
SHAPE_ARC deviceArc( userToDeviceCoordinates( start ),
|
||||
userToDeviceCoordinates( wxPoint( arcMidPoint.x, arcMidPoint.y ) ),
|
||||
devEnd, 0 );
|
||||
|
||||
fprintf( m_outputFile, "G75*\n" ); // Multiquadrant (360 degrees) mode
|
||||
|
||||
if( startAngle > endAngle )
|
||||
fprintf( m_outputFile, "G03*\n" ); // Active circular interpolation, CCW
|
||||
else
|
||||
if( deviceArc.IsClockwise() )
|
||||
fprintf( m_outputFile, "G02*\n" ); // Active circular interpolation, CW
|
||||
else
|
||||
fprintf( m_outputFile, "G03*\n" ); // Active circular interpolation, CCW
|
||||
|
||||
fprintf( m_outputFile, "X%dY%dI%dJ%dD01*\n",
|
||||
KiROUND( devEnd.x ), KiROUND( devEnd.y ),
|
||||
|
||||
@@ -93,12 +93,6 @@ DPOINT PLOTTER::userToDeviceCoordinates( const wxPoint& aCoordinate )
|
||||
{
|
||||
wxPoint pos = aCoordinate - m_plotOffset;
|
||||
|
||||
// Don't allow overflows; they can cause rendering failures in some file viewers
|
||||
// (such as Acrobat)
|
||||
int clampSize = MAX_PAGE_SIZE_MILS * m_IUsPerDecimil * 10 / 2;
|
||||
pos.x = std::max( -clampSize, std::min( pos.x, clampSize ) );
|
||||
pos.y = std::max( -clampSize, std::min( pos.y, clampSize ) );
|
||||
|
||||
double x = pos.x * m_plotScale;
|
||||
double y = ( m_paperSize.y - pos.y * m_plotScale );
|
||||
|
||||
|
||||
@@ -538,18 +538,20 @@ EDIMENSION::EDIMENSION( wxXmlNode* aDimension )
|
||||
y2 %Coord; #REQUIRED
|
||||
x3 %Coord; #REQUIRED
|
||||
y3 %Coord; #REQUIRED
|
||||
textsize %Coord;
|
||||
layer %Layer; #REQUIRED
|
||||
dtype %DimensionType; "parallel"
|
||||
>
|
||||
*/
|
||||
|
||||
x1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x1" ) );
|
||||
y1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y1" ) );
|
||||
x2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x2" ) );
|
||||
y2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y2" ) );
|
||||
x3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x3" ) );
|
||||
y3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y3" ) );
|
||||
layer = parseRequiredAttribute<int>( aDimension, wxT( "layer" ) );
|
||||
x1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x1" ) );
|
||||
y1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y1" ) );
|
||||
x2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x2" ) );
|
||||
y2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y2" ) );
|
||||
x3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x3" ) );
|
||||
y3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y3" ) );
|
||||
textsize = parseOptionalAttribute<ECOORD>( aDimension, wxT( "textsize" ) );
|
||||
layer = parseRequiredAttribute<int>( aDimension, wxT( "layer" ) );
|
||||
dimensionType = parseOptionalAttribute<wxString>( aDimension, wxT( "dtype" ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -531,13 +531,13 @@ struct EJUNCTION
|
||||
/// Eagle label
|
||||
struct ELABEL
|
||||
{
|
||||
ECOORD x;
|
||||
ECOORD y;
|
||||
ECOORD size;
|
||||
LAYER_NUM layer;
|
||||
opt_erot rot;
|
||||
ECOORD x;
|
||||
ECOORD y;
|
||||
ECOORD size;
|
||||
LAYER_NUM layer;
|
||||
opt_erot rot;
|
||||
opt_wxString xref;
|
||||
wxString netname;
|
||||
wxString netname;
|
||||
|
||||
ELABEL( wxXmlNode* aLabel, const wxString& aNetName );
|
||||
};
|
||||
@@ -619,14 +619,14 @@ struct EATTR
|
||||
/// Eagle dimension element
|
||||
struct EDIMENSION
|
||||
{
|
||||
ECOORD x1;
|
||||
ECOORD y1;
|
||||
ECOORD x2;
|
||||
ECOORD y2;
|
||||
ECOORD x3;
|
||||
ECOORD y3;
|
||||
int layer;
|
||||
|
||||
ECOORD x1;
|
||||
ECOORD y1;
|
||||
ECOORD x2;
|
||||
ECOORD y2;
|
||||
ECOORD x3;
|
||||
ECOORD y3;
|
||||
opt_ecoord textsize;
|
||||
int layer;
|
||||
opt_wxString dimensionType;
|
||||
|
||||
EDIMENSION( wxXmlNode* aDimension );
|
||||
|
||||
@@ -37,6 +37,8 @@ SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString
|
||||
m_te( aScintilla ),
|
||||
m_braces( aBraces ),
|
||||
m_lastCaretPos( -1 ),
|
||||
m_lastSelStart( -1 ),
|
||||
m_lastSelEnd( -1 ),
|
||||
m_suppressAutocomplete( false ),
|
||||
m_singleLine( aSingleLine ),
|
||||
m_returnCallback( aReturnCallback )
|
||||
@@ -337,10 +339,14 @@ void SCINTILLA_TRICKS::onScintillaUpdateUI( wxStyledTextEvent& aEvent )
|
||||
|
||||
// Has the caret changed position?
|
||||
int caretPos = m_te->GetCurrentPos();
|
||||
int selStart = m_te->GetSelectionStart();
|
||||
int selEnd = m_te->GetSelectionEnd();
|
||||
|
||||
if( m_lastCaretPos != caretPos )
|
||||
if( m_lastCaretPos != caretPos || m_lastSelStart != selStart || m_lastSelEnd != selEnd )
|
||||
{
|
||||
m_lastCaretPos = caretPos;
|
||||
m_lastSelStart = selStart;
|
||||
m_lastSelEnd = selEnd;
|
||||
int bracePos1 = -1;
|
||||
int bracePos2 = -1;
|
||||
|
||||
|
||||
+12
-2
@@ -142,7 +142,15 @@ bool ConvertSmartQuotesAndDashes( wxString* aString )
|
||||
|
||||
wxString EscapeString( const wxString& aSource, ESCAPE_CONTEXT aContext )
|
||||
{
|
||||
wxString converted;
|
||||
wxString converted;
|
||||
std::vector<bool> braceStack; // true == formatting construct
|
||||
|
||||
auto hasFormattingPrefix =
|
||||
[&]()
|
||||
{
|
||||
static wxString prefixes = wxT( "~_^" );
|
||||
return !converted.IsEmpty() && prefixes.Find( converted.Last() ) >= 0;
|
||||
};
|
||||
|
||||
converted.reserve( aSource.length() );
|
||||
|
||||
@@ -159,7 +167,7 @@ wxString EscapeString( const wxString& aSource, ESCAPE_CONTEXT aContext )
|
||||
}
|
||||
else if( aContext == CTX_LIBID )
|
||||
{
|
||||
if( c == '{' )
|
||||
if( c == '{' && !hasFormattingPrefix() )
|
||||
converted += wxT( "{brace}" );
|
||||
else if( c == '/' )
|
||||
converted += wxT( "{slash}" );
|
||||
@@ -227,7 +235,9 @@ wxString EscapeString( const wxString& aSource, ESCAPE_CONTEXT aContext )
|
||||
converted += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
converted += c;
|
||||
}
|
||||
}
|
||||
|
||||
return converted;
|
||||
|
||||
@@ -183,21 +183,20 @@ wxMenuItem* ACTION_MENU::Add( const TOOL_ACTION& aAction, bool aIsCheckmarkEntry
|
||||
|
||||
wxMenuItem* ACTION_MENU::Add( ACTION_MENU* aMenu )
|
||||
{
|
||||
ACTION_MENU* menuCopy = aMenu->Clone();
|
||||
m_submenus.push_back( menuCopy );
|
||||
m_submenus.push_back( aMenu );
|
||||
|
||||
wxASSERT_MSG( !menuCopy->m_title.IsEmpty(), wxT( "Set a title for ACTION_MENU using SetTitle()" ) );
|
||||
wxASSERT_MSG( !aMenu->m_title.IsEmpty(), wxT( "Set a title for ACTION_MENU using SetTitle()" ) );
|
||||
|
||||
if( !!aMenu->m_icon )
|
||||
{
|
||||
wxMenuItem* newItem = new wxMenuItem( this, -1, menuCopy->m_title );
|
||||
wxMenuItem* newItem = new wxMenuItem( this, -1, aMenu->m_title );
|
||||
AddBitmapToMenuItem( newItem, KiBitmap( aMenu->m_icon ) );
|
||||
newItem->SetSubMenu( menuCopy );
|
||||
newItem->SetSubMenu( aMenu );
|
||||
return Append( newItem );
|
||||
}
|
||||
else
|
||||
{
|
||||
return AppendSubMenu( menuCopy, menuCopy->m_title );
|
||||
return AppendSubMenu( aMenu, aMenu->m_title );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ void CONDITIONAL_MENU::Evaluate( SELECTION& aSelection )
|
||||
|
||||
case ENTRY::MENU:
|
||||
entry.Menu()->UpdateTitle();
|
||||
Add( entry.Menu() );
|
||||
Add( entry.Menu()->Clone() );
|
||||
menu_count++;
|
||||
break;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <trace_helpers.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <widgets/ui_common.h>
|
||||
#include <class_draw_panel_gal.h>
|
||||
#include <kiplatform/ui.h>
|
||||
@@ -300,7 +301,7 @@ void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent )
|
||||
}
|
||||
|
||||
if( m_updateCursor ) // do not update the cursor position if it was explicitly set
|
||||
m_cursorPos = m_view->ToWorld( mousePos );
|
||||
m_cursorPos = GetClampedCoords( m_view->ToWorld( mousePos ) );
|
||||
else
|
||||
m_updateCursor = true;
|
||||
|
||||
@@ -648,7 +649,7 @@ VECTOR2D WX_VIEW_CONTROLS::GetMousePosition( bool aWorldCoordinates ) const
|
||||
wxPoint msp = getMouseScreenPosition();
|
||||
VECTOR2D screenPos( msp.x, msp.y );
|
||||
|
||||
return aWorldCoordinates ? m_view->ToWorld( screenPos ) : screenPos;
|
||||
return aWorldCoordinates ? GetClampedCoords( m_view->ToWorld( screenPos ) ) : screenPos;
|
||||
}
|
||||
|
||||
|
||||
@@ -675,7 +676,7 @@ VECTOR2D WX_VIEW_CONTROLS::GetCursorPosition( bool aEnableSnapping ) const
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetRawCursorPosition( aEnableSnapping );
|
||||
return GetClampedCoords( GetRawCursorPosition( aEnableSnapping ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,10 +686,12 @@ void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpV
|
||||
{
|
||||
m_updateCursor = false;
|
||||
|
||||
VECTOR2D clampedPosition = GetClampedCoords( aPosition );
|
||||
|
||||
if( aTriggeredByArrows )
|
||||
{
|
||||
m_settings.m_lastKeyboardCursorPositionValid = true;
|
||||
m_settings.m_lastKeyboardCursorPosition = aPosition;
|
||||
m_settings.m_lastKeyboardCursorPosition = clampedPosition;
|
||||
m_settings.m_lastKeyboardCursorCommand = aArrowCommand;
|
||||
m_cursorWarped = false;
|
||||
}
|
||||
@@ -700,8 +703,8 @@ void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpV
|
||||
m_cursorWarped = true;
|
||||
}
|
||||
|
||||
WarpCursor( aPosition, true, aWarpView );
|
||||
m_cursorPos = aPosition;
|
||||
WarpCursor( clampedPosition, true, aWarpView );
|
||||
m_cursorPos = clampedPosition;
|
||||
}
|
||||
|
||||
|
||||
@@ -710,14 +713,16 @@ void WX_VIEW_CONTROLS::SetCrossHairCursorPosition( const VECTOR2D& aPosition,
|
||||
{
|
||||
m_updateCursor = false;
|
||||
|
||||
VECTOR2D clampedPosition = GetClampedCoords( aPosition );
|
||||
|
||||
const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
|
||||
BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
|
||||
VECTOR2D screenPos = m_view->ToScreen( aPosition );
|
||||
BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
|
||||
VECTOR2D screenPos = m_view->ToScreen( clampedPosition );
|
||||
|
||||
if( aWarpView && !screen.Contains( screenPos ) )
|
||||
m_view->SetCenter( aPosition );
|
||||
m_view->SetCenter( clampedPosition );
|
||||
|
||||
m_cursorPos = aPosition;
|
||||
m_cursorPos = clampedPosition;
|
||||
}
|
||||
|
||||
|
||||
@@ -727,14 +732,15 @@ void WX_VIEW_CONTROLS::WarpCursor( const VECTOR2D& aPosition, bool aWorldCoordin
|
||||
if( aWorldCoordinates )
|
||||
{
|
||||
const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
|
||||
BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
|
||||
VECTOR2D screenPos = m_view->ToScreen( aPosition );
|
||||
BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
|
||||
VECTOR2D clampedPosition = GetClampedCoords( aPosition );
|
||||
VECTOR2D screenPos = m_view->ToScreen( clampedPosition );
|
||||
|
||||
if( !screen.Contains( screenPos ) )
|
||||
{
|
||||
if( aWarpView )
|
||||
{
|
||||
m_view->SetCenter( aPosition );
|
||||
m_view->SetCenter( clampedPosition );
|
||||
m_parentPanel->WarpPointer( screenSize.x / 2, screenSize.y / 2 );
|
||||
}
|
||||
}
|
||||
@@ -889,7 +895,7 @@ void WX_VIEW_CONTROLS::refreshMouse()
|
||||
moveEvent.SetShiftDown( wxGetKeyState( WXK_SHIFT ) );
|
||||
moveEvent.SetAltDown( wxGetKeyState( WXK_ALT ) );
|
||||
|
||||
m_cursorPos = m_view->ToWorld( VECTOR2D( msp.x, msp.y ) );
|
||||
m_cursorPos = GetClampedCoords( m_view->ToWorld( VECTOR2D( msp.x, msp.y ) ) );
|
||||
wxPostEvent( m_parentPanel, moveEvent );
|
||||
}
|
||||
|
||||
@@ -943,6 +949,8 @@ void WX_VIEW_CONTROLS::UpdateScrollbars()
|
||||
|
||||
void WX_VIEW_CONTROLS::ForceCursorPosition( bool aEnabled, const VECTOR2D& aPosition )
|
||||
{
|
||||
VECTOR2D clampedPosition = GetClampedCoords( aPosition );
|
||||
|
||||
m_settings.m_forceCursorPosition = aEnabled;
|
||||
m_settings.m_forcedPosition = aPosition;
|
||||
m_settings.m_forcedPosition = clampedPosition;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ WX_GRID::WX_GRID( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxS
|
||||
|
||||
// Make sure the GUI font scales properly on GTK
|
||||
SetDefaultCellFont( KIUI::GetControlFont( this ) );
|
||||
|
||||
#if wxCHECK_VERSION( 3, 1, 0 )
|
||||
Connect( wxEVT_DPI_CHANGED, wxDPIChangedEventHandler( WX_GRID::onDPIChanged ), nullptr, this );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -47,9 +52,25 @@ WX_GRID::~WX_GRID()
|
||||
{
|
||||
if( m_weOwnTable )
|
||||
DestroyTable( GetTable() );
|
||||
|
||||
#if wxCHECK_VERSION( 3, 1, 0 )
|
||||
Disconnect( wxEVT_DPI_CHANGED, wxDPIChangedEventHandler( WX_GRID::onDPIChanged ), nullptr, this );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if wxCHECK_VERSION( 3, 1, 0 )
|
||||
void WX_GRID::onDPIChanged(wxDPIChangedEvent& aEvt)
|
||||
{
|
||||
/// This terrible hack is a way to avoid the incredibly disruptive resizing of grids that happens on Macs
|
||||
/// when moving a window between monitors of different DPIs.
|
||||
#ifndef __WXMAC__
|
||||
aEvt.Skip();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void WX_GRID::SetColLabelSize( int aHeight )
|
||||
{
|
||||
if( aHeight == 0 )
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -94,7 +94,10 @@ int CVPCB_MAINFRAME::buildEquivalenceList( FOOTPRINT_EQUIVALENCE_LIST& aList,
|
||||
{
|
||||
fn = wxExpandEnvVars( equfile );
|
||||
|
||||
tmp = search.FindValidPath( fn.GetFullPath() );
|
||||
if( fn.IsAbsolute() || fn.FileExists() )
|
||||
tmp = fn.GetFullPath();
|
||||
else
|
||||
tmp = search.FindValidPath( fn.GetFullPath() );
|
||||
|
||||
if( !tmp )
|
||||
{
|
||||
@@ -102,8 +105,7 @@ int CVPCB_MAINFRAME::buildEquivalenceList( FOOTPRINT_EQUIVALENCE_LIST& aList,
|
||||
|
||||
if( aErrorMessages )
|
||||
{
|
||||
error_msg.Printf( _( "Equivalence file '%s' could not be found in the "
|
||||
"default search paths." ),
|
||||
error_msg.Printf( _( "Equivalence file '%s' could not be found." ),
|
||||
fn.GetFullName() );
|
||||
|
||||
if( ! aErrorMessages->IsEmpty() )
|
||||
|
||||
+138
-95
@@ -588,112 +588,140 @@ void CONNECTION_GRAPH::updateItemConnectivity( const SCH_SHEET_PATH& aSheet,
|
||||
// Pre-scan to see if we have a bus at this location
|
||||
SCH_LINE* busLine = aSheet.LastScreen()->GetBus( it.first );
|
||||
|
||||
for( auto primary_it = connection_vec.begin(); primary_it != connection_vec.end(); primary_it++ )
|
||||
// We don't want to spin up a new thread for fewer than 4 items (overhead costs)
|
||||
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
|
||||
( connection_vec.size() + 3 ) / 4 );
|
||||
|
||||
std::atomic<size_t> nextItem( 0 );
|
||||
std::mutex update_mutex;
|
||||
std::vector<std::future<size_t>> returns( parallelThreadCount );
|
||||
|
||||
auto update_lambda = [&]() -> size_t
|
||||
{
|
||||
SCH_ITEM* connected_item = *primary_it;
|
||||
|
||||
// Bus entries are special: they can have connection points in the
|
||||
// middle of a wire segment, because the junction algo doesn't split
|
||||
// the segment in two where you place a bus entry. This means that
|
||||
// bus entries that don't land on the end of a line segment need to
|
||||
// have "virtual" connection points to the segments they graphically
|
||||
// touch.
|
||||
if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
|
||||
for( size_t ii = nextItem++; ii < connection_vec.size(); ii = nextItem++ )
|
||||
{
|
||||
// If this location only has the connection point of the bus
|
||||
// entry itself, this means that either the bus entry is not
|
||||
// connected to anything graphically, or that it is connected to
|
||||
// a segment at some point other than at one of the endpoints.
|
||||
if( connection_vec.size() == 1 )
|
||||
{
|
||||
if( busLine )
|
||||
{
|
||||
auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
|
||||
bus_entry->m_connected_bus_item = busLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bus-to-bus entries are treated just like bus wires
|
||||
else if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
|
||||
{
|
||||
if( connection_vec.size() < 2 )
|
||||
{
|
||||
if( busLine )
|
||||
{
|
||||
auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
|
||||
|
||||
if( it.first == bus_entry->GetPosition() )
|
||||
bus_entry->m_connected_bus_items[0] = busLine;
|
||||
else
|
||||
bus_entry->m_connected_bus_items[1] = busLine;
|
||||
|
||||
bus_entry->AddConnectionTo( aSheet, busLine );
|
||||
busLine->AddConnectionTo( aSheet, bus_entry );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change junctions to be on bus junction layer if they are touching a bus
|
||||
else if( connected_item->Type() == SCH_JUNCTION_T )
|
||||
{
|
||||
connected_item->SetLayer( busLine ? LAYER_BUS_JUNCTION : LAYER_JUNCTION );
|
||||
}
|
||||
|
||||
for( auto test_it = primary_it + 1; test_it != connection_vec.end(); test_it++ )
|
||||
{
|
||||
bool bus_connection_ok = true;
|
||||
SCH_ITEM* test_item = *test_it;
|
||||
|
||||
wxASSERT( test_item != connected_item );
|
||||
|
||||
// Set up the link between the bus entry net and the bus
|
||||
SCH_ITEM* connected_item = connection_vec[ii];
|
||||
// Bus entries are special: they can have connection points in the
|
||||
// middle of a wire segment, because the junction algo doesn't split
|
||||
// the segment in two where you place a bus entry. This means that
|
||||
// bus entries that don't land on the end of a line segment need to
|
||||
// have "virtual" connection points to the segments they graphically
|
||||
// touch.
|
||||
if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
|
||||
{
|
||||
if( test_item->GetLayer() == LAYER_BUS )
|
||||
// If this location only has the connection point of the bus
|
||||
// entry itself, this means that either the bus entry is not
|
||||
// connected to anything graphically, or that it is connected to
|
||||
// a segment at some point other than at one of the endpoints.
|
||||
if( connection_vec.size() == 1 )
|
||||
{
|
||||
auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
|
||||
bus_entry->m_connected_bus_item = test_item;
|
||||
if( busLine )
|
||||
{
|
||||
auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
|
||||
bus_entry->m_connected_bus_item = busLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bus entries only connect to bus lines on the end that is touching a bus line.
|
||||
// If the user has overlapped another net line with the endpoint of the bus entry
|
||||
// where the entry connects to a bus, we don't want to short-circuit it.
|
||||
// Bus-to-bus entries are treated just like bus wires
|
||||
else if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
|
||||
{
|
||||
if( connection_vec.size() < 2 )
|
||||
{
|
||||
if( busLine )
|
||||
{
|
||||
auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
|
||||
|
||||
if( it.first == bus_entry->GetPosition() )
|
||||
bus_entry->m_connected_bus_items[0] = busLine;
|
||||
else
|
||||
bus_entry->m_connected_bus_items[1] = busLine;
|
||||
|
||||
std::lock_guard<std::mutex> lock( update_mutex );
|
||||
bus_entry->AddConnectionTo( aSheet, busLine );
|
||||
busLine->AddConnectionTo( aSheet, bus_entry );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change junctions to be on bus junction layer if they are touching a bus
|
||||
else if( connected_item->Type() == SCH_JUNCTION_T )
|
||||
{
|
||||
connected_item->SetLayer( busLine ? LAYER_BUS_JUNCTION : LAYER_JUNCTION );
|
||||
}
|
||||
|
||||
SCH_ITEM_SET& connected_set = connected_item->ConnectedItems( aSheet );
|
||||
connected_set.reserve( connection_vec.size() );
|
||||
|
||||
for( SCH_ITEM* test_item : connection_vec )
|
||||
{
|
||||
bool bus_connection_ok = true;
|
||||
|
||||
if( test_item == connected_item )
|
||||
continue;
|
||||
|
||||
// Set up the link between the bus entry net and the bus
|
||||
if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
|
||||
{
|
||||
if( test_item->GetLayer() == LAYER_BUS )
|
||||
{
|
||||
auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
|
||||
bus_entry->m_connected_bus_item = test_item;
|
||||
}
|
||||
}
|
||||
|
||||
// Bus entries only connect to bus lines on the end that is touching a bus line.
|
||||
// If the user has overlapped another net line with the endpoint of the bus entry
|
||||
// where the entry connects to a bus, we don't want to short-circuit it.
|
||||
if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
|
||||
{
|
||||
bus_connection_ok = !busLine || test_item->GetLayer() == LAYER_BUS;
|
||||
}
|
||||
else if( test_item->Type() == SCH_BUS_WIRE_ENTRY_T )
|
||||
{
|
||||
bus_connection_ok = !busLine || connected_item->GetLayer() == LAYER_BUS;
|
||||
}
|
||||
|
||||
if( connected_item->ConnectionPropagatesTo( test_item ) &&
|
||||
test_item->ConnectionPropagatesTo( connected_item ) &&
|
||||
bus_connection_ok )
|
||||
{
|
||||
connected_set.push_back( test_item );
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far and did not find a connected bus item for a bus entry,
|
||||
// we should do a manual scan in case there is a bus item on this connection
|
||||
// point but we didn't pick it up earlier because there is *also* a net item here.
|
||||
if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
|
||||
{
|
||||
bus_connection_ok = !busLine || test_item->GetLayer() == LAYER_BUS;
|
||||
}
|
||||
else if( test_item->Type() == SCH_BUS_WIRE_ENTRY_T )
|
||||
{
|
||||
bus_connection_ok = !busLine || connected_item->GetLayer() == LAYER_BUS;
|
||||
}
|
||||
auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
|
||||
|
||||
if( connected_item->ConnectionPropagatesTo( test_item ) &&
|
||||
test_item->ConnectionPropagatesTo( connected_item ) &&
|
||||
bus_connection_ok )
|
||||
{
|
||||
connected_item->AddConnectionTo( aSheet, test_item );
|
||||
test_item->AddConnectionTo( aSheet, connected_item );
|
||||
if( !bus_entry->m_connected_bus_item )
|
||||
{
|
||||
SCH_SCREEN* screen = aSheet.LastScreen();
|
||||
SCH_LINE* bus = screen->GetBus( it.first );
|
||||
|
||||
if( bus )
|
||||
bus_entry->m_connected_bus_item = bus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far and did not find a connected bus item for a bus entry,
|
||||
// we should do a manual scan in case there is a bus item on this connection
|
||||
// point but we didn't pick it up earlier because there is *also* a net item here.
|
||||
if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
|
||||
{
|
||||
auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
|
||||
return 1;
|
||||
};
|
||||
|
||||
if( !bus_entry->m_connected_bus_item )
|
||||
{
|
||||
SCH_SCREEN* screen = aSheet.LastScreen();
|
||||
SCH_LINE* bus = screen->GetBus( it.first );
|
||||
|
||||
if( bus )
|
||||
bus_entry->m_connected_bus_item = bus;
|
||||
}
|
||||
}
|
||||
if( parallelThreadCount == 1 )
|
||||
update_lambda();
|
||||
else
|
||||
{
|
||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||
returns[ii] = std::async( std::launch::async, update_lambda );
|
||||
|
||||
// Finalize the threads
|
||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||
returns[ii].wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -730,12 +758,12 @@ void CONNECTION_GRAPH::buildItemSubGraphs()
|
||||
SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet, this );
|
||||
bool unique = !( aItem->GetFlags() & CANDIDATE );
|
||||
|
||||
aItem->SetFlags( CANDIDATE );
|
||||
if( conn && !conn->SubgraphCode() )
|
||||
aItem->SetFlags( CANDIDATE );
|
||||
|
||||
return ( unique && conn && ( conn->SubgraphCode() == 0 ) );
|
||||
};
|
||||
|
||||
|
||||
std::copy_if( item->ConnectedItems( sheet ).begin(),
|
||||
item->ConnectedItems( sheet ).end(),
|
||||
std::back_inserter( memberlist ), get_items );
|
||||
@@ -754,10 +782,16 @@ void CONNECTION_GRAPH::buildItemSubGraphs()
|
||||
connected_conn->SetSubgraphCode( subgraph->m_code );
|
||||
m_item_to_subgraph_map[connected_item] = subgraph;
|
||||
subgraph->AddItem( connected_item );
|
||||
SCH_ITEM_SET citemset = connected_item->ConnectedItems( sheet );
|
||||
SCH_ITEM_SET& citemset = connected_item->ConnectedItems( sheet );
|
||||
|
||||
std::copy_if( citemset.begin(), citemset.end(),
|
||||
std::back_inserter( memberlist ), get_items );
|
||||
for( SCH_ITEM* citem : citemset )
|
||||
{
|
||||
if( citem->HasFlag( CANDIDATE ) )
|
||||
continue;
|
||||
|
||||
if( get_items( citem ) )
|
||||
memberlist.push_back( citem );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1332,8 +1366,13 @@ void CONNECTION_GRAPH::buildConnectionGraph()
|
||||
m_bus_alias_cache[ alias->GetName() ] = alias;
|
||||
}
|
||||
|
||||
PROF_TIMER sub_graph( "buildItemSubGraphs" );
|
||||
buildItemSubGraphs();
|
||||
|
||||
if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
|
||||
sub_graph.Show();
|
||||
|
||||
|
||||
/**
|
||||
* TODO(JE): Net codes are non-deterministic. Fortunately, they are also not really used for
|
||||
* anything. We should consider removing them entirely and just using net names everywhere.
|
||||
@@ -1345,8 +1384,12 @@ void CONNECTION_GRAPH::buildConnectionGraph()
|
||||
|
||||
generateInvisiblePinSubGraphs();
|
||||
|
||||
PROF_TIMER proc_sub_graph( "ProcessSubGraphs" );
|
||||
processSubGraphs();
|
||||
|
||||
if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
|
||||
proc_sub_graph.Show();
|
||||
|
||||
// Absorbed subgraphs should no longer be considered
|
||||
alg::delete_if( m_driver_subgraphs, [&]( const CONNECTION_SUBGRAPH* candidate ) -> bool
|
||||
{
|
||||
|
||||
@@ -396,7 +396,7 @@ void DIALOG_ERC::testErc()
|
||||
|| settings.IsTestEnabled( ERCE_POWERPIN_NOT_DRIVEN )
|
||||
|| settings.IsTestEnabled( ERCE_PIN_NOT_DRIVEN ) )
|
||||
{
|
||||
tester.TestPinToPin();
|
||||
tester.TestPinToPin();
|
||||
}
|
||||
|
||||
// Test similar labels (i;e. labels which are identical when
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <sch_line.h>
|
||||
#include <sch_junction.h>
|
||||
#include <sch_sheet.h>
|
||||
#include <sch_sheet_pin.h>
|
||||
#include <schematic.h>
|
||||
#include <advanced_config.h>
|
||||
#include <tool/tool_manager.h>
|
||||
@@ -412,6 +413,12 @@ void DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS::visitItem( const SCH_SHEET_PATH& aShe
|
||||
if( m_setBgColor->GetValue() )
|
||||
sheet->SetBackgroundColor( m_bgColorSwatch->GetSwatchColor() );
|
||||
}
|
||||
|
||||
if( m_sheetPins->GetValue() )
|
||||
{
|
||||
for( SCH_SHEET_PIN* pin : sheet->GetPins() )
|
||||
processItem( aSheetPath, pin );
|
||||
}
|
||||
}
|
||||
else if( aItem->Type() == SCH_JUNCTION_T )
|
||||
{
|
||||
@@ -439,8 +446,6 @@ void DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS::visitItem( const SCH_SHEET_PATH& aShe
|
||||
processItem( aSheetPath, aItem );
|
||||
else if( m_hierLabels->GetValue() && aItem->Type() == SCH_HIER_LABEL_T )
|
||||
processItem( aSheetPath, aItem );
|
||||
else if( m_sheetPins->GetValue() && aItem->Type() == SCH_SHEET_PIN_T )
|
||||
processItem( aSheetPath, aItem );
|
||||
else if( m_schTextAndGraphics->GetValue() && aItem->IsType( schTextAndGraphics ) )
|
||||
processItem( aSheetPath, aItem );
|
||||
}
|
||||
|
||||
@@ -75,10 +75,10 @@ bool DIALOG_LIB_SHAPE_PROPERTIES::TransferDataToWindow()
|
||||
|
||||
bool enblConvOptStyle = symbol && symbol->HasConversion();
|
||||
|
||||
// if a symbol contains no graphic items, symbol->HasConversion() returns false.
|
||||
// but when creating a new symbol, with DeMorgan option set, the ApplyToAllConversions
|
||||
// must be enabled even if symbol->HasConversion() returns false in order to be able
|
||||
// to create graphic items shared by all body styles
|
||||
// If a symbol contains no conversion-specific pins or graphic items, symbol->HasConversion()
|
||||
// will return false.
|
||||
// But when creating a new symbol, with DeMorgan option set, the ApplyToAllConversions
|
||||
// must be enabled in order to be able to create graphic items shared by all body styles.
|
||||
if( m_frame->GetShowDeMorgan() )
|
||||
enblConvOptStyle = true;
|
||||
|
||||
|
||||
@@ -174,7 +174,13 @@ bool DIALOG_LIB_SYMBOL_PROPERTIES::TransferDataToWindow()
|
||||
m_SelNumberOfUnits->SetValue( m_libEntry->GetUnitCount() );
|
||||
m_OptionPartsInterchangeable->SetValue( !m_libEntry->UnitsLocked() ||
|
||||
m_libEntry->GetUnitCount() == 1 );
|
||||
m_AsConvertButt->SetValue( m_libEntry->HasConversion() );
|
||||
|
||||
// If a symbol contains no conversion-specific pins or graphic items, symbol->HasConversion()
|
||||
// will return false. But when editing a symbol with DeMorgan option set, we don't want to
|
||||
// keep turning it off just because there aren't any conversion-specific items yet, so we force
|
||||
// it to on if the parent frame has it enabled.
|
||||
m_AsConvertButt->SetValue( m_Parent->GetShowDeMorgan() );
|
||||
|
||||
m_OptionPower->SetValue( m_libEntry->IsPower() );
|
||||
m_excludeFromBomCheckBox->SetValue( !m_libEntry->GetIncludeInBom() );
|
||||
m_excludeFromBoardCheckBox->SetValue( !m_libEntry->GetIncludeOnBoard() );
|
||||
@@ -367,6 +373,7 @@ bool DIALOG_LIB_SYMBOL_PROPERTIES::TransferDataFromWindow()
|
||||
m_libEntry->LockUnits( m_libEntry->GetUnitCount() > 1 &&
|
||||
!m_OptionPartsInterchangeable->GetValue() );
|
||||
m_libEntry->SetConversion( m_AsConvertButt->GetValue() );
|
||||
m_Parent->SetShowDeMorgan( m_AsConvertButt->GetValue() );
|
||||
|
||||
if( m_OptionPower->GetValue() )
|
||||
m_libEntry->SetPower();
|
||||
@@ -448,7 +455,7 @@ void DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanging( wxGridEvent& event )
|
||||
|
||||
void DIALOG_LIB_SYMBOL_PROPERTIES::OnSymbolNameText( wxCommandEvent& event )
|
||||
{
|
||||
if( !m_Parent->IsSymbolFromSchematic() )
|
||||
if( !m_Parent->IsSymbolFromSchematic() || m_OptionPower->IsChecked() )
|
||||
m_grid->SetCellValue( VALUE_FIELD, FDC_VALUE, m_SymbolNameCtrl->GetValue() );
|
||||
}
|
||||
|
||||
|
||||
@@ -1250,7 +1250,15 @@ wxString DIALOG_PLOT_SCHEMATIC::getOutputPath()
|
||||
wxStandardPaths::Get().GetDocumentsDir() );
|
||||
|
||||
// Build the absolute path of current output directory to preselect it in the file browser.
|
||||
wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
|
||||
std::function<bool( wxString* )> textResolver =
|
||||
[&]( wxString* token ) -> bool
|
||||
{
|
||||
return m_parent->Schematic().ResolveTextVar( token, 0 );
|
||||
};
|
||||
|
||||
wxString path = m_outputDirectoryName->GetValue();
|
||||
path = ExpandTextVars( path, &textResolver, nullptr, &Prj() );
|
||||
path = ExpandEnvVarSubstitutions( path, &Prj() );
|
||||
|
||||
fn.SetPath( path );
|
||||
|
||||
|
||||
@@ -208,8 +208,17 @@ public:
|
||||
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
|
||||
{
|
||||
SCH_SYMBOL* symbol = m_symbolsList[ i ].GetSymbol();
|
||||
m_dataStore[ symbol->m_Uuid ][ aFieldName ] = symbol->GetFieldText( aFieldName,
|
||||
m_frame );
|
||||
|
||||
wxCHECK( symbol && ( symbol->GetInstanceReferences().size() != 0 ), /* void */ );
|
||||
|
||||
wxString val = symbol->GetFieldText( aFieldName, m_frame );
|
||||
|
||||
if( aFieldName == wxT( "Value" ) )
|
||||
val = symbol->GetInstanceReferences()[0].m_Value;
|
||||
else if( aFieldName == wxT( "Footprint" ) )
|
||||
val = symbol->GetInstanceReferences()[0].m_Footprint;
|
||||
|
||||
m_dataStore[ symbol->m_Uuid ][ aFieldName ] = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -439,9 +439,13 @@ int ERC_TESTER::TestPinToPin()
|
||||
{
|
||||
std::vector<SCH_PIN*> pins;
|
||||
std::unordered_map<EDA_ITEM*, SCH_SCREEN*> pinToScreenMap;
|
||||
bool has_noconnect = false;
|
||||
|
||||
for( CONNECTION_SUBGRAPH* subgraph: net.second )
|
||||
{
|
||||
if( subgraph->m_no_connect )
|
||||
has_noconnect = true;
|
||||
|
||||
for( EDA_ITEM* item : subgraph->m_items )
|
||||
{
|
||||
if( item->Type() == SCH_PIN_T )
|
||||
@@ -452,10 +456,6 @@ int ERC_TESTER::TestPinToPin()
|
||||
}
|
||||
}
|
||||
|
||||
// Single-pin nets are handled elsewhere
|
||||
if( pins.size() < 2 )
|
||||
continue;
|
||||
|
||||
std::set<std::pair<SCH_PIN*, SCH_PIN*>> tested;
|
||||
|
||||
SCH_PIN* needsDriver = nullptr;
|
||||
@@ -542,7 +542,7 @@ int ERC_TESTER::TestPinToPin()
|
||||
}
|
||||
}
|
||||
|
||||
if( needsDriver && !hasDriver )
|
||||
if( needsDriver && !hasDriver && !has_noconnect )
|
||||
{
|
||||
int err_code = ispowerNet ? ERCE_POWERPIN_NOT_DRIVEN : ERCE_PIN_NOT_DRIVEN;
|
||||
|
||||
|
||||
@@ -502,7 +502,7 @@ void FIELDS_GRID_TABLE<T>::SetValue( int aRow, int aCol, const wxString &aValue
|
||||
value = fn.GetFullPath();
|
||||
}
|
||||
}
|
||||
else if( m_frame->IsType( FRAME_SCH_SYMBOL_EDITOR ) && aRow == VALUE_FIELD )
|
||||
else if( m_parentType == SCH_SYMBOL_T && aRow == VALUE_FIELD )
|
||||
{
|
||||
value = EscapeString( value, CTX_LIBID );
|
||||
}
|
||||
|
||||
@@ -632,6 +632,10 @@ void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
|
||||
if( dlg.ShowModal() == wxID_CANCEL )
|
||||
return;
|
||||
|
||||
// Don't leave dangling pointers to previously-opened document.
|
||||
m_toolManager->GetTool<EE_SELECTION_TOOL>()->ClearSelection();
|
||||
ClearUndoRedoList();
|
||||
|
||||
if( setProject )
|
||||
{
|
||||
Schematic().SetProject( nullptr );
|
||||
@@ -665,8 +669,6 @@ void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
|
||||
return;
|
||||
}
|
||||
|
||||
m_toolManager->GetTool<EE_SELECTION_TOOL>()->ClearSelection();
|
||||
|
||||
importFile( dlg.GetPath(), pluginType );
|
||||
|
||||
RefreshCanvas();
|
||||
|
||||
+19
-7
@@ -214,15 +214,20 @@ int LIB_SYMBOL::Compare( const LIB_SYMBOL& aRhs, int aCompareFlags ) const
|
||||
if( m_me == aRhs.m_me )
|
||||
return 0;
|
||||
|
||||
int retv = m_name.Cmp( aRhs.m_name );
|
||||
int retv = 0;
|
||||
|
||||
if( retv )
|
||||
return retv;
|
||||
if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 )
|
||||
{
|
||||
retv = m_name.Cmp( aRhs.m_name );
|
||||
|
||||
retv = m_libId.compare( aRhs.m_libId );
|
||||
if( retv )
|
||||
return retv;
|
||||
|
||||
if( retv )
|
||||
return retv;
|
||||
retv = m_libId.compare( aRhs.m_libId );
|
||||
|
||||
if( retv )
|
||||
return retv;
|
||||
}
|
||||
|
||||
if( m_parent.lock() < aRhs.m_parent.lock() )
|
||||
return -1;
|
||||
@@ -258,8 +263,15 @@ int LIB_SYMBOL::Compare( const LIB_SYMBOL& aRhs, int aCompareFlags ) const
|
||||
{
|
||||
const LIB_FIELD* lhsField = static_cast<const LIB_FIELD*>( lhsItem );
|
||||
|
||||
if( lhsField->IsMandatory() )
|
||||
if( lhsField->GetId() == VALUE_FIELD )
|
||||
{
|
||||
if( ( aCompareFlags & LIB_ITEM::COMPARE_FLAGS::ERC ) == 0 || IsPower() )
|
||||
retv = lhsItem->compare( *rhsItem, aCompareFlags );
|
||||
}
|
||||
else if( lhsField->IsMandatory() )
|
||||
{
|
||||
retv = lhsItem->compare( *rhsItem, aCompareFlags );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -62,17 +62,20 @@ void SCH_EDIT_FRAME::ReCreateMenuBar()
|
||||
if( !openRecentMenu )
|
||||
{
|
||||
openRecentMenu = new ACTION_MENU( false, selTool );
|
||||
openRecentMenu->SetTitle( _( "Open Recent" ) );
|
||||
openRecentMenu->SetIcon( BITMAPS::recent );
|
||||
|
||||
fileHistory.UseMenu( openRecentMenu );
|
||||
fileHistory.AddFilesToMenu( openRecentMenu );
|
||||
}
|
||||
|
||||
// Ensure the title is up to date after changing language
|
||||
openRecentMenu->SetTitle( _( "Open Recent" ) );
|
||||
fileHistory.UpdateClearText( openRecentMenu, _( "Clear Recent Files" ) );
|
||||
|
||||
fileMenu->Add( ACTIONS::doNew );
|
||||
fileMenu->Add( ACTIONS::open );
|
||||
|
||||
wxMenuItem* item = fileMenu->Add( openRecentMenu );
|
||||
wxMenuItem* item = fileMenu->Add( openRecentMenu->Clone() );
|
||||
|
||||
// Add the file menu condition here since it needs the item ID for the submenu
|
||||
ACTION_CONDITIONS cond;
|
||||
|
||||
@@ -209,12 +209,12 @@ wxString NETLIST_EXPORTER_PSPICE::GetSpiceFieldDefVal( SPICE_FIELD aField, SCH_S
|
||||
wxString value = aSymbol->GetField( VALUE_FIELD )->GetShownText();
|
||||
|
||||
// Is it a passive component?
|
||||
if( aCtl & NET_ADJUST_PASSIVE_VALS && ( prim == 'C' || prim == 'L' || prim == 'R' ) )
|
||||
if( ( aCtl & NET_ADJUST_PASSIVE_VALS ) && ( prim == 'C' || prim == 'L' || prim == 'R' ) )
|
||||
{
|
||||
// Regular expression to match common formats used for passive parts description
|
||||
// (e.g. 100k, 2k3, 1 uF)
|
||||
wxRegEx passiveVal(
|
||||
"^([0-9\\. ]+)([fFpPnNuUmMkKgGtT]|M(e|E)(g|G))?([fFhH]|ohm)?([-1-9 ]*)$" );
|
||||
wxT( "^([0-9\\. ]+)([fFpPnNuUmMkKgGtTμµ𝛍𝜇𝝁 ]|M(e|E)(g|G))?([fFhHΩΩ𝛀𝛺𝝮]|ohm)?([-1-9 ]*)$" ) );
|
||||
|
||||
if( passiveVal.Matches( value ) )
|
||||
{
|
||||
|
||||
+11
-13
@@ -25,9 +25,8 @@
|
||||
#include "pin_numbers.h"
|
||||
#include <wx/crt.h>
|
||||
|
||||
namespace {
|
||||
|
||||
wxString GetNextSymbol( const wxString& str, wxString::size_type& cursor )
|
||||
wxString PIN_NUMBERS::getNextSymbol( const wxString& str, wxString::size_type& cursor )
|
||||
{
|
||||
if( str.size() <= cursor )
|
||||
return wxEmptyString;
|
||||
@@ -36,14 +35,15 @@ wxString GetNextSymbol( const wxString& str, wxString::size_type& cursor )
|
||||
|
||||
wxChar c = str[cursor];
|
||||
|
||||
if( wxIsdigit( c ) || c == '+' || c == '-' )
|
||||
// Need to check that there is a digit in the string before we parse it as a numeric
|
||||
if( ( wxIsdigit( c ) || ( ( c == '+' || c == '-' ) && ( cursor < str.size() - 1 ) && wxIsdigit( str[cursor + 1] ) ) ) )
|
||||
{
|
||||
// number, possibly with sign
|
||||
while( ++cursor < str.size() )
|
||||
{
|
||||
c = str[cursor];
|
||||
|
||||
if( wxIsdigit( c ) || c == 'v' || c == 'V' )
|
||||
if( wxIsdigit( c ) || c == 'v' || c == 'V' || c == '.' )
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
@@ -65,8 +65,6 @@ wxString GetNextSymbol( const wxString& str, wxString::size_type& cursor )
|
||||
return str.substr( begin, cursor - begin );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
wxString PIN_NUMBERS::GetSummary() const
|
||||
{
|
||||
@@ -117,8 +115,8 @@ int PIN_NUMBERS::Compare( const wxString& lhs, const wxString& rhs )
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
symbol1 = GetNextSymbol( lhs, cursor1 );
|
||||
symbol2 = GetNextSymbol( rhs, cursor2 );
|
||||
symbol1 = getNextSymbol( lhs, cursor1 );
|
||||
symbol2 = getNextSymbol( rhs, cursor2 );
|
||||
|
||||
if( symbol1.empty() && symbol2.empty() )
|
||||
return 0;
|
||||
@@ -129,12 +127,12 @@ int PIN_NUMBERS::Compare( const wxString& lhs, const wxString& rhs )
|
||||
if( symbol2.empty() )
|
||||
return 2;
|
||||
|
||||
wxChar c1 = symbol1[0];
|
||||
wxChar c2 = symbol2[0];
|
||||
bool sym1_isnumeric = symbol1.find_first_of( "0123456789" ) != wxString::npos;
|
||||
bool sym2_isnumeric = symbol2.find_first_of( "0123456789" ) != wxString::npos;
|
||||
|
||||
if( wxIsdigit( c1 ) || c1 == '-' || c1 == '+' )
|
||||
if( sym1_isnumeric )
|
||||
{
|
||||
if( wxIsdigit( c2 ) || c2 == '-' || c2 == '+' )
|
||||
if( sym2_isnumeric )
|
||||
{
|
||||
// numeric comparison
|
||||
wxString::size_type v1 = symbol1.find_first_of( wxT( "vV" ) );
|
||||
@@ -173,7 +171,7 @@ int PIN_NUMBERS::Compare( const wxString& lhs, const wxString& rhs )
|
||||
}
|
||||
else
|
||||
{
|
||||
if( wxIsdigit( c2 ) || c2 == '-' || c2 == '+' )
|
||||
if( sym2_isnumeric )
|
||||
return 2;
|
||||
|
||||
int res = symbol1.Cmp( symbol2 );
|
||||
|
||||
@@ -47,6 +47,8 @@ private:
|
||||
|
||||
typedef std::set<wxString, less> container_type;
|
||||
|
||||
static wxString getNextSymbol( const wxString& str, wxString::size_type& cursor );
|
||||
|
||||
public:
|
||||
typedef container_type::value_type value_type;
|
||||
typedef container_type::iterator iterator;
|
||||
|
||||
+29
-8
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004-2021 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2004-2022 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
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <core/arraydim.h>
|
||||
#include <lib_pin.h>
|
||||
#include <pin_type.h>
|
||||
#include "pgm_base.h"
|
||||
|
||||
|
||||
// These are true singletons so it's OK for them to be globals.
|
||||
@@ -46,8 +47,8 @@ struct pinTypeStruct
|
||||
BITMAPS bitmap;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
const std::map<ELECTRICAL_PINTYPE, struct pinTypeStruct> pinTypes = {
|
||||
|
||||
std::map<ELECTRICAL_PINTYPE, struct pinTypeStruct> g_pinTypes = {
|
||||
{ ELECTRICAL_PINTYPE::PT_INPUT, { _( "Input" ), BITMAPS::pintype_input } },
|
||||
{ ELECTRICAL_PINTYPE::PT_OUTPUT, { _( "Output" ), BITMAPS::pintype_output } },
|
||||
{ ELECTRICAL_PINTYPE::PT_BIDI, { _( "Bidirectional" ), BITMAPS::pintype_bidi } },
|
||||
@@ -61,7 +62,9 @@ const std::map<ELECTRICAL_PINTYPE, struct pinTypeStruct> pinTypes = {
|
||||
{ ELECTRICAL_PINTYPE::PT_OPENEMITTER, { _( "Open emitter" ), BITMAPS::pintype_openemit } },
|
||||
{ ELECTRICAL_PINTYPE::PT_NC, { _( "Unconnected" ), BITMAPS::pintype_noconnect } },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
int g_pinTypesLanguage = wxLANGUAGE_UNKNOWN;
|
||||
|
||||
|
||||
struct pinShapeStruct
|
||||
@@ -236,9 +239,27 @@ const std::vector<BITMAPS>& PinOrientationIcons()
|
||||
|
||||
wxString ElectricalPinTypeGetText( ELECTRICAL_PINTYPE aType )
|
||||
{
|
||||
auto findIt = pinTypes.find( aType );
|
||||
if( g_pinTypesLanguage != Pgm().GetSelectedLanguageIdentifier() )
|
||||
{
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_INPUT].name = _( "Input" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_OUTPUT].name = _( "Output" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_BIDI].name = _( "Bidirectional" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_TRISTATE].name = _( "Tri-state" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_PASSIVE].name = _( "Passive" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_NIC].name = _( "Free" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_UNSPECIFIED].name = _( "Unspecified" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_POWER_IN].name = _( "Power input" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_POWER_OUT].name = _( "Power output" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR].name = _( "Open collector" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_OPENEMITTER].name = _( "Open emitter" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_NC].name = _( "Unconnected" );
|
||||
|
||||
wxCHECK_MSG( findIt != pinTypes.end(), wxT( "???" ), "Could not find pin type in lookup map" );
|
||||
g_pinTypesLanguage = Pgm().GetSelectedLanguageIdentifier();
|
||||
}
|
||||
|
||||
auto findIt = g_pinTypes.find( aType );
|
||||
|
||||
wxCHECK_MSG( findIt != g_pinTypes.end(), wxT( "???" ), wxT( "Pin type not found!" ) );
|
||||
|
||||
return findIt->second.name;
|
||||
}
|
||||
@@ -246,9 +267,9 @@ wxString ElectricalPinTypeGetText( ELECTRICAL_PINTYPE aType )
|
||||
|
||||
BITMAPS ElectricalPinTypeGetBitmap( ELECTRICAL_PINTYPE aType )
|
||||
{
|
||||
auto findIt = pinTypes.find( aType );
|
||||
auto findIt = g_pinTypes.find( aType );
|
||||
|
||||
wxCHECK_MSG( findIt != pinTypes.end(), BITMAPS::INVALID_BITMAP,
|
||||
wxCHECK_MSG( findIt != g_pinTypes.end(), BITMAPS::INVALID_BITMAP,
|
||||
wxT( "Could not find pin type in lookup map" ) );
|
||||
|
||||
return findIt->second.bitmap;
|
||||
|
||||
@@ -1502,6 +1502,8 @@ void SCH_EDIT_FRAME::ShowChangedLanguage()
|
||||
// status bar
|
||||
UpdateMsgPanel();
|
||||
|
||||
UpdateTitle();
|
||||
|
||||
// This ugly hack is to fix an option(left) toolbar update bug that seems to only affect
|
||||
// windows. See https://bugs.launchpad.net/kicad/+bug/1816492. For some reason, calling
|
||||
// wxWindow::Refresh() does not resolve the issue. Only a resize event seems to force the
|
||||
|
||||
@@ -1013,10 +1013,10 @@ void SCH_PAINTER::draw( LIB_PIN *aPin, int aLayer )
|
||||
c = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows );
|
||||
}
|
||||
|
||||
float insideOffset = textOffset - thickness[INSIDE] / 2.0;
|
||||
float outsideOffset = 2 * Mils2iu( PIN_TEXT_MARGIN ) - thickness[OUTSIDE] / 2.0;
|
||||
float aboveOffset = Mils2iu( PIN_TEXT_MARGIN ) + ( thickness[ABOVE] + penWidth ) / 2.0;
|
||||
float belowOffset = Mils2iu( PIN_TEXT_MARGIN ) + ( thickness[BELOW] + penWidth ) / 2.0;
|
||||
float insideOffset = textOffset - thickness[INSIDE] / 2.0;
|
||||
float outsideOffset = Mils2iu( PIN_TEXT_MARGIN ) + TARGET_PIN_RADIUS - thickness[OUTSIDE] / 2.0;
|
||||
float aboveOffset = Mils2iu( PIN_TEXT_MARGIN ) + penWidth / 2.0 + thickness[ABOVE] / 2.0;
|
||||
float belowOffset = Mils2iu( PIN_TEXT_MARGIN ) + penWidth / 2.0 + thickness[BELOW] / 2.0;
|
||||
|
||||
if( isDangling )
|
||||
outsideOffset += TARGET_PIN_RADIUS / 2.0;
|
||||
|
||||
@@ -1308,6 +1308,13 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSymDefIntoLibrary( const SYMDEF_ID& aSymdef
|
||||
SYMDEF_SCM symbol = Library.SymbolDefinitions.at( aSymdefID );
|
||||
int gateNumber = getKiCadUnitNumberFromGate( aGateID );
|
||||
|
||||
// Ensure there are no items on this unit (e.g. if we already previously loaded the symbol from
|
||||
// the part definition)
|
||||
std::vector<LIB_ITEM*> drawItems = aSymbol->GetUnitDrawItems( gateNumber, 0 );
|
||||
|
||||
for( LIB_ITEM* item : drawItems )
|
||||
aSymbol->RemoveDrawItem( item );
|
||||
|
||||
for( std::pair<FIGURE_ID, FIGURE> figPair : symbol.Figures )
|
||||
{
|
||||
FIGURE fig = figPair.second;
|
||||
|
||||
@@ -1569,15 +1569,15 @@ void SCH_SEXPR_PARSER::parsePAGE_INFO( PAGE_INFO& aPageInfo )
|
||||
// Perform some controls to avoid crashes if the size is edited by hands
|
||||
if( width < MIN_PAGE_SIZE_MILS )
|
||||
width = MIN_PAGE_SIZE_MILS;
|
||||
else if( width > MAX_PAGE_SIZE_MILS )
|
||||
width = MAX_PAGE_SIZE_MILS;
|
||||
else if( width > MAX_PAGE_SIZE_EESCHEMA_MILS )
|
||||
width = MAX_PAGE_SIZE_EESCHEMA_MILS;
|
||||
|
||||
int height = Mm2mils( parseDouble( "height" ) ); // height stored in mm so we convert to mils
|
||||
|
||||
if( height < MIN_PAGE_SIZE_MILS )
|
||||
height = MIN_PAGE_SIZE_MILS;
|
||||
else if( height > MAX_PAGE_SIZE_MILS )
|
||||
height = MAX_PAGE_SIZE_MILS;
|
||||
else if( height > MAX_PAGE_SIZE_EESCHEMA_MILS )
|
||||
height = MAX_PAGE_SIZE_EESCHEMA_MILS;
|
||||
|
||||
aPageInfo.SetWidthMils( width );
|
||||
aPageInfo.SetHeightMils( height );
|
||||
|
||||
+25
-4
@@ -237,6 +237,27 @@ void SCH_SYMBOL::ViewGetLayers( int aLayers[], int& aCount ) const
|
||||
}
|
||||
|
||||
|
||||
bool SCH_SYMBOL::IsMovableFromAnchorPoint() const
|
||||
{
|
||||
// If a symbol's anchor is not grid-aligned to its pins then moving from the anchor is
|
||||
// going to end up moving the symbol's pins off-grid.
|
||||
|
||||
// The minimal grid size allowed to place a pin is 25 mils
|
||||
const int min_grid_size = Mils2iu( 25 );
|
||||
|
||||
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
|
||||
{
|
||||
if( ( ( pin->GetPosition().x - m_pos.x ) % min_grid_size ) != 0 )
|
||||
return false;
|
||||
|
||||
if( ( ( pin->GetPosition().y - m_pos.y ) % min_grid_size ) != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SCH_SYMBOL::SetLibId( const LIB_ID& aLibId )
|
||||
{
|
||||
if( m_lib_id != aLibId )
|
||||
@@ -604,9 +625,9 @@ void SCH_SYMBOL::SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue )
|
||||
{
|
||||
if( sheet == nullptr )
|
||||
{
|
||||
// Clear instance overrides and set primary field value
|
||||
// Set all instances to the updated value
|
||||
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
|
||||
instance.m_Value = wxEmptyString;
|
||||
instance.m_Value = aValue;
|
||||
|
||||
m_fields[ VALUE_FIELD ].SetText( aValue );
|
||||
return;
|
||||
@@ -655,9 +676,9 @@ void SCH_SYMBOL::SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFoo
|
||||
{
|
||||
if( sheet == nullptr )
|
||||
{
|
||||
// Clear instance overrides and set primary field value
|
||||
// Set all instances to new footprint value
|
||||
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
|
||||
instance.m_Footprint = wxEmptyString;
|
||||
instance.m_Footprint = aFootprint;
|
||||
|
||||
m_fields[ FOOTPRINT_FIELD ].SetText( aFootprint );
|
||||
return;
|
||||
|
||||
@@ -138,9 +138,10 @@ public:
|
||||
* they are big. However, this annoyed some users and we now have a preference which
|
||||
* controls warping on move in general, so this was switched to true for symbols.
|
||||
*
|
||||
* @return true for a symbol.
|
||||
* @note We now use this to keep poorly-formed symbols from getting dragged off-grid. If
|
||||
* the symbol contains off-grid pins we will not allow it to be moved from its anchor.
|
||||
*/
|
||||
bool IsMovableFromAnchorPoint() const override { return true; }
|
||||
bool IsMovableFromAnchorPoint() const override;
|
||||
|
||||
void SetLibId( const LIB_ID& aName );
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ SCH_VIEW::SCH_VIEW( bool aIsDynamic, SCH_BASE_FRAME* aFrame ) :
|
||||
// Set m_boundary to define the max working area size. The default value is acceptable for
|
||||
// Pcbnew and Gerbview, but too large for Eeschema due to very different internal units.
|
||||
// A full size = 3 * MAX_PAGE_SIZE_MILS size allows a wide margin around the drawing-sheet.
|
||||
double max_size = Mils2iu( MAX_PAGE_SIZE_MILS ) * 3.0;
|
||||
double max_size = Mils2iu( MAX_PAGE_SIZE_EESCHEMA_MILS ) * 3.0;
|
||||
m_boundary.SetOrigin( -max_size/4, -max_size/4 );
|
||||
m_boundary.SetSize( max_size, max_size );
|
||||
}
|
||||
|
||||
+192
-189
@@ -206,229 +206,232 @@ bool SCH_EDIT_FRAME::LoadSheetFromFile( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHier
|
||||
wxMessageDialog::ButtonLabel okButtonLabel( _( "Continue Load" ) );
|
||||
wxMessageDialog::ButtonLabel cancelButtonLabel( _( "Cancel Load" ) );
|
||||
|
||||
if( fileName.GetPathWithSep() == Prj().GetProjectPath()
|
||||
&& !prjScreens.HasSchematic( fullFilename ) )
|
||||
if( !prjScreens.HasSchematic( fullFilename ) )
|
||||
{
|
||||
// A schematic in the current project path that isn't part of the current project.
|
||||
// It's possible the user copied this schematic from another project so the library
|
||||
// links may not be available. Even this is check is no guarantee that all symbol
|
||||
// library links are valid but it's better than nothing.
|
||||
for( const wxString& name : names )
|
||||
if( fileName.GetPathWithSep() == Prj().GetProjectPath() )
|
||||
{
|
||||
if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
|
||||
newLibNames.Add( name );
|
||||
}
|
||||
|
||||
if( !newLibNames.IsEmpty() )
|
||||
{
|
||||
msg = _( "There are library names in the loaded schematic that are missing "
|
||||
"from the project library table. This may result in broken symbol "
|
||||
"library links for the loaded schematic. Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg3( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg3.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg3.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( fileName.GetPathWithSep() != Prj().GetProjectPath() )
|
||||
{
|
||||
// A schematic loaded from a path other than the current project path.
|
||||
|
||||
// If there are symbol libraries in the imported schematic that are not in the
|
||||
// symbol library table of this project, there could be a lot of broken symbol
|
||||
// library links. Attempt to add the missing libraries to the project symbol
|
||||
// library table.
|
||||
wxArrayString duplicateLibNames;
|
||||
|
||||
for( const wxString& name : names )
|
||||
{
|
||||
if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
|
||||
newLibNames.Add( name );
|
||||
else
|
||||
duplicateLibNames.Add( name );
|
||||
}
|
||||
|
||||
SYMBOL_LIB_TABLE table;
|
||||
wxFileName symLibTableFn( fileName.GetPath(),
|
||||
SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
|
||||
|
||||
// If there are any new or duplicate libraries, check to see if it's possible that
|
||||
// there could be any missing libraries that would cause broken symbol library links.
|
||||
if( !newLibNames.IsEmpty() || !duplicateLibNames.IsEmpty() )
|
||||
{
|
||||
if( !symLibTableFn.Exists() || !symLibTableFn.IsFileReadable() )
|
||||
// A schematic in the current project path that isn't part of the current project.
|
||||
// It's possible the user copied this schematic from another project so the library
|
||||
// links may not be available. Even this is check is no guarantee that all symbol
|
||||
// library links are valid but it's better than nothing.
|
||||
for( const wxString& name : names )
|
||||
{
|
||||
msg.Printf( _( "The project library table '%s' does not exist or cannot "
|
||||
"be read. This may result in broken symbol links for the "
|
||||
"schematic. Do you wish to continue?" ),
|
||||
symLibTableFn.GetFullPath() );
|
||||
wxMessageDialog msgDlg4( this, msg, _( "Continue Load Schematic" ),
|
||||
if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
|
||||
newLibNames.Add( name );
|
||||
}
|
||||
|
||||
if( !newLibNames.IsEmpty() )
|
||||
{
|
||||
msg = _( "There are library names in the selected schematic that are missing "
|
||||
"from the current project library table. This may result in broken "
|
||||
"symbol library references for the loaded schematic.\n\n"
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg3( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg4.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
msgDlg3.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg4.ShowModal() == wxID_CANCEL )
|
||||
if( msgDlg3.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
table.Load( symLibTableFn.GetFullPath() );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "Error loading the symbol library table '%s'." ),
|
||||
symLibTableFn.GetFullPath() );
|
||||
DisplayErrorMessage( nullptr, msg, ioe.What() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if any of the symbol libraries found in the appended schematic do
|
||||
// not exist in the current project are missing from the appended project symbol
|
||||
// library table.
|
||||
if( !newLibNames.IsEmpty() )
|
||||
else if( fileName.GetPathWithSep() != Prj().GetProjectPath() )
|
||||
{
|
||||
bool missingLibNames = table.IsEmpty();
|
||||
// A schematic loaded from a path other than the current project path.
|
||||
|
||||
if( !missingLibNames )
|
||||
// If there are symbol libraries in the imported schematic that are not in the
|
||||
// symbol library table of this project, there could be a lot of broken symbol
|
||||
// library links. Attempt to add the missing libraries to the project symbol
|
||||
// library table.
|
||||
wxArrayString duplicateLibNames;
|
||||
|
||||
for( const wxString& name : names )
|
||||
{
|
||||
for( const wxString& newLibName : newLibNames )
|
||||
if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
|
||||
newLibNames.Add( name );
|
||||
else
|
||||
duplicateLibNames.Add( name );
|
||||
}
|
||||
|
||||
SYMBOL_LIB_TABLE table;
|
||||
wxFileName symLibTableFn( fileName.GetPath(),
|
||||
SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
|
||||
|
||||
// If there are any new or duplicate libraries, check to see if it's possible that
|
||||
// there could be any missing libraries that would cause broken symbol library links.
|
||||
if( !newLibNames.IsEmpty() || !duplicateLibNames.IsEmpty() )
|
||||
{
|
||||
if( !symLibTableFn.Exists() || !symLibTableFn.IsFileReadable() )
|
||||
{
|
||||
if( !table.HasLibrary( newLibName ) )
|
||||
msg = _( "The selected file was created as part of a different project. "
|
||||
"Linking the file to this project may result in missing or "
|
||||
"incorrect symbol library references.\n\n"
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg4( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg4.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg4.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
missingLibNames = true;
|
||||
break;
|
||||
table.Load( symLibTableFn.GetFullPath() );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "Error loading the symbol library table '%s'." ),
|
||||
symLibTableFn.GetFullPath() );
|
||||
DisplayErrorMessage( nullptr, msg, ioe.What() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( missingLibNames )
|
||||
// Check to see if any of the symbol libraries found in the appended schematic do
|
||||
// not exist in the current project are missing from the appended project symbol
|
||||
// library table.
|
||||
if( !newLibNames.IsEmpty() )
|
||||
{
|
||||
msg = _( "There are library names in the loaded schematic that are missing "
|
||||
"from the loaded schematic project library table. This may result "
|
||||
"in broken symbol library links for the schematic. "
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg5( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg5.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
bool missingLibNames = table.IsEmpty();
|
||||
|
||||
if( msgDlg5.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The library name already exists in the current project. Check to see if the
|
||||
// duplicate name is the same library in the current project. If it's not, it's
|
||||
// most likely that the symbol library links will be broken.
|
||||
if( !duplicateLibNames.IsEmpty() && !table.IsEmpty() )
|
||||
{
|
||||
bool libNameConflict = false;
|
||||
|
||||
for( const wxString& duplicateLibName : duplicateLibNames )
|
||||
{
|
||||
const SYMBOL_LIB_TABLE_ROW* thisRow = nullptr;
|
||||
const SYMBOL_LIB_TABLE_ROW* otherRow = nullptr;
|
||||
|
||||
if( Prj().SchSymbolLibTable()->HasLibrary( duplicateLibName ) )
|
||||
thisRow = Prj().SchSymbolLibTable()->FindRow( duplicateLibName );
|
||||
|
||||
if( table.HasLibrary( duplicateLibName ) )
|
||||
otherRow = table.FindRow( duplicateLibName );
|
||||
|
||||
// It's in the global library table so there is no conflict.
|
||||
if( thisRow && !otherRow )
|
||||
continue;
|
||||
|
||||
if( !thisRow || !otherRow )
|
||||
continue;
|
||||
|
||||
wxFileName otherUriFileName;
|
||||
wxString thisURI = thisRow->GetFullURI( true );
|
||||
wxString otherURI = otherRow->GetFullURI( false);
|
||||
|
||||
if( otherURI.Contains( wxT( "${KIPRJMOD}" ) ) || otherURI.Contains( wxT( "$(KIPRJMOD)" ) ) )
|
||||
if( !missingLibNames )
|
||||
{
|
||||
// Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
|
||||
// not expand to a valid symbol library path.
|
||||
otherUriFileName.SetPath( fileName.GetPath() );
|
||||
otherUriFileName.SetFullName( otherURI.AfterLast( '}' ) );
|
||||
otherURI = otherUriFileName.GetFullPath();
|
||||
for( const wxString& newLibName : newLibNames )
|
||||
{
|
||||
if( !table.HasLibrary( newLibName ) )
|
||||
{
|
||||
missingLibNames = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( thisURI != otherURI )
|
||||
if( missingLibNames )
|
||||
{
|
||||
libNameConflict = true;
|
||||
break;
|
||||
msg = _( "There are symbol library names in the selected schematic that "
|
||||
"are missing from the selected schematic project library table. "
|
||||
"This may result in broken symbol library references.\n\n"
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg5( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg5.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg5.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( libNameConflict )
|
||||
// The library name already exists in the current project. Check to see if the
|
||||
// duplicate name is the same library in the current project. If it's not, it's
|
||||
// most likely that the symbol library links will be broken.
|
||||
if( !duplicateLibNames.IsEmpty() && !table.IsEmpty() )
|
||||
{
|
||||
msg = _( "A duplicate library name that references a different library exists "
|
||||
"in the current library table. This conflict cannot be resolved and "
|
||||
"may result in broken symbol library links for the schematic. "
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg6( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg6.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
bool libNameConflict = false;
|
||||
|
||||
if( msgDlg6.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
for( const wxString& duplicateLibName : duplicateLibNames )
|
||||
{
|
||||
const SYMBOL_LIB_TABLE_ROW* thisRow = nullptr;
|
||||
const SYMBOL_LIB_TABLE_ROW* otherRow = nullptr;
|
||||
|
||||
if( Prj().SchSymbolLibTable()->HasLibrary( duplicateLibName ) )
|
||||
thisRow = Prj().SchSymbolLibTable()->FindRow( duplicateLibName );
|
||||
|
||||
if( table.HasLibrary( duplicateLibName ) )
|
||||
otherRow = table.FindRow( duplicateLibName );
|
||||
|
||||
// It's in the global library table so there is no conflict.
|
||||
if( thisRow && !otherRow )
|
||||
continue;
|
||||
|
||||
if( !thisRow || !otherRow )
|
||||
continue;
|
||||
|
||||
wxFileName otherUriFileName;
|
||||
wxString thisURI = thisRow->GetFullURI( true );
|
||||
wxString otherURI = otherRow->GetFullURI( false);
|
||||
|
||||
if( otherURI.Contains( "${KIPRJMOD}" ) || otherURI.Contains( "$(KIPRJMOD)" ) )
|
||||
{
|
||||
// Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
|
||||
// not expand to a valid symbol library path.
|
||||
otherUriFileName.SetPath( fileName.GetPath() );
|
||||
otherUriFileName.SetFullName( otherURI.AfterLast( '}' ) );
|
||||
otherURI = otherUriFileName.GetFullPath();
|
||||
}
|
||||
|
||||
if( thisURI != otherURI )
|
||||
{
|
||||
libNameConflict = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( libNameConflict )
|
||||
{
|
||||
msg = _( "A duplicate library name that references a different library exists "
|
||||
"in the current library table. This conflict cannot be resolved and "
|
||||
"may result in broken symbol library references.\n\n"
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg6( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg6.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg6.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All (most?) of the possible broken symbol library link cases are covered. Map the
|
||||
// new appended schematic project symbol library table entries to the current project
|
||||
// symbol library table.
|
||||
if( !newLibNames.IsEmpty() && !table.IsEmpty() )
|
||||
{
|
||||
for( const wxString& libName : newLibNames )
|
||||
// All (most?) of the possible broken symbol library link cases are covered. Map the
|
||||
// new appended schematic project symbol library table entries to the current project
|
||||
// symbol library table.
|
||||
if( !newLibNames.IsEmpty() && !table.IsEmpty() )
|
||||
{
|
||||
if( !table.HasLibrary( libName )
|
||||
|| Prj().SchSymbolLibTable()->HasLibrary( libName ) )
|
||||
for( const wxString& libName : newLibNames )
|
||||
{
|
||||
continue;
|
||||
if( !table.HasLibrary( libName )
|
||||
|| Prj().SchSymbolLibTable()->HasLibrary( libName ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't expand environment variable because KIPRJMOD will not be correct
|
||||
// for a different project.
|
||||
wxString uri = table.GetFullURI( libName, false );
|
||||
wxFileName newLib;
|
||||
|
||||
if( uri.Contains( "${KIPRJMOD}" ) || uri.Contains( "$(KIPRJMOD)" ) )
|
||||
{
|
||||
// Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
|
||||
// not expand to a valid symbol library path.
|
||||
newLib.SetPath( fileName.GetPath() );
|
||||
newLib.SetFullName( uri.AfterLast( '}' ) );
|
||||
uri = newLib.GetFullPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = table.GetFullURI( libName );
|
||||
}
|
||||
|
||||
// Add the library from the imported project to the current project
|
||||
// symbol library table.
|
||||
const SYMBOL_LIB_TABLE_ROW* row = table.FindRow( libName );
|
||||
|
||||
wxCHECK( row, false );
|
||||
|
||||
SYMBOL_LIB_TABLE_ROW* newRow = new SYMBOL_LIB_TABLE_ROW( libName, uri,
|
||||
row->GetType(),
|
||||
row->GetOptions(),
|
||||
row->GetDescr() );
|
||||
|
||||
Prj().SchSymbolLibTable()->InsertRow( newRow );
|
||||
libTableChanged = true;
|
||||
}
|
||||
|
||||
// Don't expand environment variable because KIPRJMOD will not be correct
|
||||
// for a different project.
|
||||
wxString uri = table.GetFullURI( libName, false );
|
||||
wxFileName newLib;
|
||||
|
||||
if( uri.Contains( wxT( "${KIPRJMOD}" ) ) || uri.Contains( wxT( "$(KIPRJMOD)" ) ) )
|
||||
{
|
||||
// Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
|
||||
// not expand to a valid symbol library path.
|
||||
newLib.SetPath( fileName.GetPath() );
|
||||
newLib.SetFullName( uri.AfterLast( '}' ) );
|
||||
uri = newLib.GetFullPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = table.GetFullURI( libName );
|
||||
}
|
||||
|
||||
// Add the library from the imported project to the current project
|
||||
// symbol library table.
|
||||
const SYMBOL_LIB_TABLE_ROW* row = table.FindRow( libName );
|
||||
|
||||
wxCHECK( row, false );
|
||||
|
||||
SYMBOL_LIB_TABLE_ROW* newRow = new SYMBOL_LIB_TABLE_ROW( libName, uri,
|
||||
row->GetType(),
|
||||
row->GetOptions(),
|
||||
row->GetDescr() );
|
||||
|
||||
Prj().SchSymbolLibTable()->InsertRow( newRow );
|
||||
libTableChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,10 +375,11 @@ void SYMBOL_EDIT_FRAME::setupUIConditions()
|
||||
return IsSymbolEditable() && !IsSymbolAlias();
|
||||
};
|
||||
|
||||
auto libModifiedCondition =
|
||||
auto symbolModifiedCondition =
|
||||
[this]( const SELECTION& sel )
|
||||
{
|
||||
return m_libMgr->HasModifications();
|
||||
return m_libMgr->IsSymbolModified( GetTargetLibId().GetLibItemName(),
|
||||
GetTargetLibId().GetLibNickname() );
|
||||
};
|
||||
|
||||
auto libSelectedCondition =
|
||||
@@ -408,7 +409,7 @@ void SYMBOL_EDIT_FRAME::setupUIConditions()
|
||||
|
||||
mgr->SetConditions( ACTIONS::undo, ENABLE( haveSymbolCond && cond.UndoAvailable() ) );
|
||||
mgr->SetConditions( ACTIONS::redo, ENABLE( haveSymbolCond && cond.RedoAvailable() ) );
|
||||
mgr->SetConditions( ACTIONS::revert, ENABLE( haveSymbolCond && libModifiedCondition ) );
|
||||
mgr->SetConditions( ACTIONS::revert, ENABLE( symbolModifiedCondition ) );
|
||||
|
||||
mgr->SetConditions( ACTIONS::toggleGrid, CHECK( cond.GridVisible() ) );
|
||||
mgr->SetConditions( ACTIONS::toggleCursorStyle, CHECK( cond.FullscreenCursor() ) );
|
||||
@@ -813,7 +814,9 @@ SYMBOL_LIBRARY_MANAGER& SYMBOL_EDIT_FRAME::GetLibManager()
|
||||
void SYMBOL_EDIT_FRAME::OnModify()
|
||||
{
|
||||
GetScreen()->SetContentModified();
|
||||
storeCurrentSymbol();
|
||||
|
||||
if( !IsSymbolFromSchematic() )
|
||||
storeCurrentSymbol();
|
||||
|
||||
m_treePane->GetLibTree()->RefreshLibTree();
|
||||
|
||||
@@ -1136,6 +1139,14 @@ void SYMBOL_EDIT_FRAME::ShowChangedLanguage()
|
||||
|
||||
// status bar
|
||||
UpdateMsgPanel();
|
||||
|
||||
if( GetRenderSettings()->m_ShowPinsElectricalType )
|
||||
{
|
||||
GetCanvas()->GetView()->UpdateAllItems( KIGFX::ALL );
|
||||
GetCanvas()->Refresh();
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -234,14 +234,33 @@ bool SYMBOL_EDIT_FRAME::saveCurrentSymbol()
|
||||
{
|
||||
if( GetCurSymbol() )
|
||||
{
|
||||
LIB_ID libId = GetCurSymbol()->GetLibId();
|
||||
const wxString& libName = libId.GetLibNickname();
|
||||
const wxString& symbolName = libId.GetLibItemName();
|
||||
|
||||
if( m_libMgr->FlushSymbol( symbolName, libName ) )
|
||||
if( IsSymbolFromSchematic() )
|
||||
{
|
||||
m_libMgr->ClearSymbolModified( symbolName, libName );
|
||||
return true;
|
||||
SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
|
||||
|
||||
if( !schframe ) // happens when the schematic editor has been closed
|
||||
{
|
||||
DisplayErrorMessage( this, _( "No schematic currently open." ) );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
schframe->SaveSymbolToSchematic( *m_symbol, m_schematicSymbolUUID );
|
||||
GetScreen()->SetContentModified( false );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LIB_ID libId = GetCurSymbol()->GetLibId();
|
||||
const wxString& libName = libId.GetLibNickname();
|
||||
const wxString& symbolName = libId.GetLibItemName();
|
||||
|
||||
if( m_libMgr->FlushSymbol( symbolName, libName ) )
|
||||
{
|
||||
m_libMgr->ClearSymbolModified( symbolName, libName );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,14 +270,15 @@ bool SYMBOL_EDIT_FRAME::saveCurrentSymbol()
|
||||
|
||||
bool SYMBOL_EDIT_FRAME::LoadSymbol( const LIB_ID& aLibId, int aUnit, int aConvert )
|
||||
{
|
||||
if( !IsSymbolFromSchematic()
|
||||
&& GetCurSymbol() && GetCurSymbol()->GetLibId() == aLibId
|
||||
&& GetUnit() == aUnit && GetConvert() == aConvert )
|
||||
if( GetCurSymbol() && !IsSymbolFromSchematic()
|
||||
&& GetCurSymbol()->GetLibId() == aLibId
|
||||
&& GetUnit() == aUnit
|
||||
&& GetConvert() == aConvert )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( GetScreen()->IsContentModified() && GetCurSymbol() )
|
||||
if( GetCurSymbol() && IsSymbolFromSchematic() && GetScreen()->IsContentModified() )
|
||||
{
|
||||
if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
|
||||
[&]() -> bool
|
||||
@@ -318,7 +338,7 @@ bool SYMBOL_EDIT_FRAME::LoadSymbolFromCurrentLib( const wxString& aAliasName, in
|
||||
return false;
|
||||
|
||||
// Enable synchronized pin edit mode for symbols with interchangeable units
|
||||
m_SyncPinEdit = !GetCurSymbol()->UnitsLocked();
|
||||
m_SyncPinEdit = GetCurSymbol()->IsMulti() && !GetCurSymbol()->UnitsLocked();
|
||||
|
||||
ClearUndoRedoList();
|
||||
m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
|
||||
@@ -489,10 +509,6 @@ void SYMBOL_EDIT_FRAME::CreateNewSymbol()
|
||||
new_symbol.LockUnits( false );
|
||||
|
||||
new_symbol.SetConversion( dlg.GetAlternateBodyStyle() );
|
||||
|
||||
// must be called after loadSymbol, that calls SetShowDeMorgan, but
|
||||
// because the symbol is empty,it looks like it has no alternate body
|
||||
SetShowDeMorgan( dlg.GetAlternateBodyStyle() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -540,6 +556,10 @@ void SYMBOL_EDIT_FRAME::CreateNewSymbol()
|
||||
m_libMgr->UpdateSymbol( &new_symbol, lib );
|
||||
SyncLibraries( false );
|
||||
LoadSymbol( name, lib, 1 );
|
||||
|
||||
// must be called after loadSymbol, that calls SetShowDeMorgan, but
|
||||
// because the symbol is empty,it looks like it has no alternate body
|
||||
SetShowDeMorgan( dlg.GetAlternateBodyStyle() );
|
||||
}
|
||||
|
||||
|
||||
@@ -749,9 +769,12 @@ void SYMBOL_EDIT_FRAME::UpdateAfterSymbolProperties( wxString* aOldName )
|
||||
RebuildSymbolUnitsList();
|
||||
SetShowDeMorgan( GetCurSymbol()->Flatten()->HasConversion() );
|
||||
updateTitle();
|
||||
|
||||
// N.B. The view needs to be rebuilt first as the Symbol Properties change may invalidate
|
||||
// the view pointers by rebuilting the field table
|
||||
RebuildView();
|
||||
UpdateMsgPanel();
|
||||
|
||||
RebuildView();
|
||||
OnModify();
|
||||
}
|
||||
|
||||
@@ -986,16 +1009,25 @@ void SYMBOL_EDIT_FRAME::RevertAll()
|
||||
|
||||
void SYMBOL_EDIT_FRAME::LoadSymbol( const wxString& aAlias, const wxString& aLibrary, int aUnit )
|
||||
{
|
||||
if( GetCurSymbol() && IsSymbolFromSchematic() && GetScreen()->IsContentModified() )
|
||||
{
|
||||
if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
|
||||
[&]() -> bool
|
||||
{
|
||||
return saveCurrentSymbol();
|
||||
} ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aAlias, aLibrary );
|
||||
|
||||
if( !symbol )
|
||||
{
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( _( "Symbol %s not found in library '%s'." ),
|
||||
aAlias,
|
||||
aLibrary );
|
||||
DisplayError( this, msg );
|
||||
DisplayError( this, wxString::Format( _( "Symbol %s not found in library '%s'." ),
|
||||
aAlias,
|
||||
aLibrary ) );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "sch_drawing_tools.h"
|
||||
#include "ee_selection_tool.h"
|
||||
#include "ee_grid_helper.h"
|
||||
#include <tools/sch_drawing_tools.h>
|
||||
#include <tools/ee_selection_tool.h>
|
||||
#include <tools/ee_grid_helper.h>
|
||||
#include <ee_actions.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <project.h>
|
||||
@@ -192,6 +192,8 @@ int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
|
||||
|
||||
if( evt->IsCancelInteractive() )
|
||||
{
|
||||
m_frame->GetInfoBar()->Dismiss();
|
||||
|
||||
if( symbol )
|
||||
{
|
||||
cleanup();
|
||||
@@ -430,6 +432,8 @@ int SCH_DRAWING_TOOLS::PlaceImage( const TOOL_EVENT& aEvent )
|
||||
|
||||
if( evt->IsCancelInteractive() )
|
||||
{
|
||||
m_frame->GetInfoBar()->Dismiss();
|
||||
|
||||
if( image )
|
||||
{
|
||||
cleanup();
|
||||
@@ -983,6 +987,7 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
SCH_ITEM* item = nullptr;
|
||||
KIGFX::VIEW_CONTROLS* controls = getViewControls();
|
||||
EE_GRID_HELPER grid( m_toolMgr );
|
||||
bool ignorePrimePosition = false;
|
||||
|
||||
if( m_inTwoClickPlace )
|
||||
return 0;
|
||||
@@ -1044,10 +1049,17 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
setCursor();
|
||||
|
||||
// Prime the pump if the tool isn't being re-activated
|
||||
if( aEvent.HasPosition() || ( !aEvent.IsReactivate()
|
||||
&& ( isText || isGlobalLabel || isHierLabel || isNetLabel ) ) )
|
||||
if( aEvent.HasPosition() )
|
||||
{
|
||||
m_toolMgr->RunAction( ACTIONS::cursorClick );
|
||||
m_toolMgr->PrimeTool( aEvent.Position() );
|
||||
}
|
||||
else if( !aEvent.IsReactivate() && ( isText
|
||||
|| isGlobalLabel
|
||||
|| isHierLabel
|
||||
|| isNetLabel ) )
|
||||
{
|
||||
m_toolMgr->PrimeTool( { 0, 0 } );
|
||||
ignorePrimePosition = true;
|
||||
}
|
||||
|
||||
// Main loop: keep receiving events
|
||||
@@ -1063,6 +1075,8 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
|
||||
if( evt->IsCancelInteractive() )
|
||||
{
|
||||
m_frame->GetInfoBar()->Dismiss();
|
||||
|
||||
if( item )
|
||||
{
|
||||
cleanup();
|
||||
@@ -1164,11 +1178,17 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
}
|
||||
|
||||
// Restore cursor after dialog
|
||||
controls->WarpCursor( controls->GetCursorPosition(), true );
|
||||
// If we started with a click on a tool button or menu then continue with the
|
||||
// current mouse position. Otherwise warp back to the original click position.
|
||||
if( evt->IsPrime() && ignorePrimePosition )
|
||||
cursorPos = grid.Align( controls->GetMousePosition() );
|
||||
else
|
||||
controls->WarpCursor( cursorPos, true );
|
||||
|
||||
if( item )
|
||||
{
|
||||
item->SetPosition( (wxPoint) cursorPos );
|
||||
|
||||
item->SetFlags( IS_NEW | IS_MOVING );
|
||||
item->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
|
||||
updatePreview();
|
||||
@@ -1290,6 +1310,8 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
|
||||
|
||||
if( evt->IsCancelInteractive() )
|
||||
{
|
||||
m_frame->GetInfoBar()->Dismiss();
|
||||
|
||||
if( sheet )
|
||||
{
|
||||
cleanup();
|
||||
@@ -1430,8 +1452,8 @@ void SCH_DRAWING_TOOLS::sizeSheet( SCH_SHEET* aSheet, const VECTOR2I& aPos )
|
||||
wxPoint pos = aSheet->GetPosition();
|
||||
wxPoint size = (wxPoint) aPos - pos;
|
||||
|
||||
size.x = std::max( size.x, MIN_SHEET_WIDTH );
|
||||
size.y = std::max( size.y, MIN_SHEET_HEIGHT );
|
||||
size.x = std::max( size.x, Mils2iu( MIN_SHEET_WIDTH ) );
|
||||
size.y = std::max( size.y, Mils2iu( MIN_SHEET_HEIGHT ) );
|
||||
|
||||
wxPoint grid = m_frame->GetNearestGridPosition( pos + size );
|
||||
aSheet->Resize( wxSize( grid.x - pos.x, grid.y - pos.y ) );
|
||||
|
||||
@@ -671,6 +671,10 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
|
||||
if( selection.IsHover() )
|
||||
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
|
||||
|
||||
EE_SELECTION selectionCopy = selection;
|
||||
m_toolMgr->RunAction( EE_ACTIONS::trimOverlappingWires, true, &selectionCopy );
|
||||
m_toolMgr->RunAction( EE_ACTIONS::addNeededJunctions, true, &selectionCopy );
|
||||
|
||||
m_frame->RecalculateConnections( LOCAL_CLEANUP );
|
||||
m_frame->TestDanglingEnds();
|
||||
|
||||
|
||||
@@ -129,7 +129,8 @@ int SCH_EDITOR_CONTROL::PageSetup( const TOOL_EVENT& aEvent )
|
||||
undoCmd.PushItem( wrapper );
|
||||
m_frame->SaveCopyInUndoList( undoCmd, UNDO_REDO::PAGESETTINGS, false );
|
||||
|
||||
DIALOG_EESCHEMA_PAGE_SETTINGS dlg( m_frame, wxSize( MAX_PAGE_SIZE_MILS, MAX_PAGE_SIZE_MILS ) );
|
||||
DIALOG_EESCHEMA_PAGE_SETTINGS dlg( m_frame, wxSize( MAX_PAGE_SIZE_EESCHEMA_MILS,
|
||||
MAX_PAGE_SIZE_EESCHEMA_MILS ) );
|
||||
dlg.SetWksFileName( BASE_SCREEN::m_DrawingSheetFileName );
|
||||
|
||||
if( dlg.ShowModal() )
|
||||
@@ -1534,19 +1535,16 @@ void SCH_EDITOR_CONTROL::updatePastedSymbol( SCH_SYMBOL* aSymbol, SCH_SCREEN* aP
|
||||
}
|
||||
|
||||
if( aForceKeepAnnotations && !reference.IsEmpty() )
|
||||
{
|
||||
aSymbol->SetRef( &aPastePath, reference );
|
||||
aSymbol->SetValue( &aPastePath, value );
|
||||
aSymbol->SetFootprint( &aPastePath, footprint );
|
||||
}
|
||||
else
|
||||
{
|
||||
aSymbol->ClearAnnotation( &aPastePath );
|
||||
}
|
||||
|
||||
// We might clear annotations but always leave the original unit number from the paste
|
||||
// We might clear annotations but always leave the original unit number, value and footprint
|
||||
// from the paste
|
||||
aSymbol->SetUnitSelection( &aPastePath, unit );
|
||||
aSymbol->SetUnit( unit );
|
||||
aSymbol->SetValue( &aPastePath, value );
|
||||
aSymbol->SetFootprint( &aPastePath, footprint );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -164,7 +164,8 @@ private:
|
||||
|
||||
|
||||
SCH_LINE_WIRE_BUS_TOOL::SCH_LINE_WIRE_BUS_TOOL() :
|
||||
EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" )
|
||||
EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawingLineWireBus" ),
|
||||
m_inDrawingTool( false )
|
||||
{
|
||||
m_busUnfold = {};
|
||||
m_wires.reserve( 16 );
|
||||
@@ -278,6 +279,11 @@ bool SCH_LINE_WIRE_BUS_TOOL::IsDrawingLineWireOrBus( const SELECTION& aSelection
|
||||
|
||||
int SCH_LINE_WIRE_BUS_TOOL::DrawSegments( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
if( m_inDrawingTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inDrawingTool );
|
||||
|
||||
DRAW_SEGMENT_EVENT_PARAMS* params = aEvent.Parameter<DRAW_SEGMENT_EVENT_PARAMS*>();
|
||||
|
||||
std::string tool = aEvent.GetCommandStr().get();
|
||||
@@ -300,6 +306,11 @@ int SCH_LINE_WIRE_BUS_TOOL::DrawSegments( const TOOL_EVENT& aEvent )
|
||||
|
||||
int SCH_LINE_WIRE_BUS_TOOL::UnfoldBus( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
if( m_inDrawingTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inDrawingTool );
|
||||
|
||||
wxString* netPtr = aEvent.Parameter<wxString*>();
|
||||
wxString net;
|
||||
SCH_LINE* segment = nullptr;
|
||||
@@ -591,6 +602,8 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType,
|
||||
//
|
||||
if( evt->IsCancelInteractive() )
|
||||
{
|
||||
m_frame->GetInfoBar()->Dismiss();
|
||||
|
||||
if( segment || m_busUnfold.in_progress )
|
||||
{
|
||||
cleanup();
|
||||
|
||||
@@ -133,11 +133,10 @@ private:
|
||||
void computeBreakPoint( const std::pair<SCH_LINE*, SCH_LINE*>& aSegments, wxPoint& aPosition );
|
||||
|
||||
private:
|
||||
/// Data related to bus unfolding tool.
|
||||
BUS_UNFOLDING_T m_busUnfold;
|
||||
bool m_inDrawingTool; // Reentrancy guard
|
||||
|
||||
/// Storage for the line segments while drawing
|
||||
std::vector<SCH_LINE*> m_wires;
|
||||
BUS_UNFOLDING_T m_busUnfold;
|
||||
std::vector<SCH_LINE*> m_wires; // Lines being drawn
|
||||
};
|
||||
|
||||
#endif /* SCH_LINE_WIRE_BUS_TOOL_H */
|
||||
|
||||
@@ -384,6 +384,9 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
//
|
||||
else if( evt->IsCancelInteractive() || evt->IsActivate() )
|
||||
{
|
||||
if( evt->IsCancelInteractive() )
|
||||
m_frame->GetInfoBar()->Dismiss();
|
||||
|
||||
if( m_moveInProgress )
|
||||
{
|
||||
if( evt->IsActivate() )
|
||||
@@ -750,8 +753,8 @@ void SCH_MOVE_TOOL::moveItem( EDA_ITEM* aItem, const VECTOR2I& aDelta )
|
||||
if( aItem->HasFlag( ENDPOINT ) )
|
||||
line->MoveEnd( (wxPoint) aDelta );
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SCH_PIN_T:
|
||||
case SCH_FIELD_T:
|
||||
@@ -775,13 +778,16 @@ void SCH_MOVE_TOOL::moveItem( EDA_ITEM* aItem, const VECTOR2I& aDelta )
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SCH_SHEET_PIN_T:
|
||||
{
|
||||
SCH_SHEET_PIN* pin = (SCH_SHEET_PIN*) aItem;
|
||||
|
||||
pin->SetStoredPos( pin->GetStoredPos() + (wxPoint) aDelta );
|
||||
pin->ConstrainOnEdge( pin->GetStoredPos() );
|
||||
break;
|
||||
}
|
||||
|
||||
case SCH_LABEL_T:
|
||||
{
|
||||
SCH_TEXT* label = static_cast<SCH_TEXT*>( aItem );
|
||||
@@ -799,6 +805,7 @@ void SCH_MOVE_TOOL::moveItem( EDA_ITEM* aItem, const VECTOR2I& aDelta )
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
static_cast<SCH_ITEM*>( aItem )->Move( (wxPoint) aDelta );
|
||||
break;
|
||||
@@ -815,6 +822,17 @@ int SCH_MOVE_TOOL::AlignElements( const TOOL_EVENT& aEvent )
|
||||
EE_SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::MovableItems );
|
||||
bool append_undo = false;
|
||||
|
||||
auto doMoveItem =
|
||||
[&]( EDA_ITEM* item, const VECTOR2I& delta )
|
||||
{
|
||||
saveCopyInUndoList( item, UNDO_REDO::CHANGED, append_undo );
|
||||
append_undo = true;
|
||||
|
||||
moveItem( item, delta );
|
||||
item->ClearFlags( IS_MOVING );
|
||||
updateItem( item, true );
|
||||
};
|
||||
|
||||
for( SCH_ITEM* it : m_frame->GetScreen()->Items() )
|
||||
{
|
||||
if( !it->IsSelected() )
|
||||
@@ -858,12 +876,7 @@ int SCH_MOVE_TOOL::AlignElements( const TOOL_EVENT& aEvent )
|
||||
if( dragItem->GetParent() && dragItem->GetParent()->IsSelected() )
|
||||
continue;
|
||||
|
||||
saveCopyInUndoList( dragItem, UNDO_REDO::CHANGED, append_undo );
|
||||
append_undo = true;
|
||||
|
||||
moveItem( dragItem, gridpt );
|
||||
dragItem->ClearFlags( IS_MOVING );
|
||||
updateItem( dragItem, true );
|
||||
doMoveItem( dragItem, gridpt );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -873,13 +886,49 @@ int SCH_MOVE_TOOL::AlignElements( const TOOL_EVENT& aEvent )
|
||||
VECTOR2I gridpt = grid.AlignGrid( item->GetPosition() ) - item->GetPosition();
|
||||
|
||||
if( gridpt != VECTOR2I( 0, 0 ) )
|
||||
{
|
||||
saveCopyInUndoList( item, UNDO_REDO::CHANGED, append_undo );
|
||||
append_undo = true;
|
||||
doMoveItem( item, gridpt );
|
||||
}
|
||||
else if( item->Type() == SCH_SHEET_T )
|
||||
{
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
VECTOR2I topRight = sheet->GetPosition();
|
||||
VECTOR2I bottomRight = topRight + sheet->GetSize();
|
||||
VECTOR2I tl_gridpt = grid.AlignGrid( topRight ) - topRight;
|
||||
VECTOR2I br_gridpt = grid.AlignGrid( bottomRight ) - bottomRight;
|
||||
|
||||
moveItem( item, gridpt );
|
||||
updateItem( item, true );
|
||||
item->ClearFlags( IS_MOVING );
|
||||
if( tl_gridpt != VECTOR2I( 0, 0 ) || br_gridpt != VECTOR2I( 0, 0 ) )
|
||||
{
|
||||
doMoveItem( sheet, tl_gridpt );
|
||||
|
||||
VECTOR2I newSize = (VECTOR2I) sheet->GetSize() - tl_gridpt + br_gridpt;
|
||||
sheet->SetSize( wxSize( newSize.x, newSize.y ) );
|
||||
updateItem( sheet, true );
|
||||
|
||||
for( SCH_SHEET_PIN* pin : sheet->GetPins() )
|
||||
{
|
||||
VECTOR2I gridpt;
|
||||
|
||||
if( pin->GetSide() == SHEET_SIDE::TOP || pin->GetSide() == SHEET_SIDE::LEFT )
|
||||
gridpt = tl_gridpt;
|
||||
else
|
||||
gridpt = br_gridpt;
|
||||
|
||||
if( gridpt != VECTOR2I( 0, 0 ) )
|
||||
{
|
||||
EDA_ITEMS drag_items;
|
||||
getConnectedDragItems( pin, pin->GetConnectionPoints()[0], drag_items );
|
||||
|
||||
doMoveItem( pin, gridpt );
|
||||
|
||||
for( EDA_ITEM* dragItem : drag_items )
|
||||
{
|
||||
if( dragItem->GetParent() && dragItem->GetParent()->IsSelected() )
|
||||
continue;
|
||||
|
||||
doMoveItem( dragItem, gridpt );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -915,12 +964,7 @@ int SCH_MOVE_TOOL::AlignElements( const TOOL_EVENT& aEvent )
|
||||
if( dragItem->GetParent() && dragItem->GetParent()->IsSelected() )
|
||||
continue;
|
||||
|
||||
saveCopyInUndoList( dragItem, UNDO_REDO::CHANGED, append_undo );
|
||||
append_undo = true;
|
||||
|
||||
moveItem( dragItem, most_common );
|
||||
dragItem->ClearFlags( IS_MOVING );
|
||||
updateItem( dragItem, true );
|
||||
doMoveItem( dragItem, most_common );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,10 +256,14 @@ int SYMBOL_EDITOR_CONTROL::DuplicateSymbol( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
SYMBOL_EDIT_FRAME* editFrame = static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
|
||||
LIB_ID sel = editFrame->GetTargetLibId();
|
||||
// DuplicateSymbol() is called to duplicate a symbol, or to paste a previously
|
||||
// saved symbol in clipboard
|
||||
bool isPasteAction = aEvent.IsAction( &EE_ACTIONS::pasteSymbol );
|
||||
wxString msg;
|
||||
|
||||
if( !sel.IsValid() )
|
||||
if( !sel.IsValid() && !isPasteAction )
|
||||
{
|
||||
// When duplicating a symbol, a source symbol must exists.
|
||||
msg.Printf( _( "No symbol selected" ) );
|
||||
m_frame->ShowInfoBarError( msg );
|
||||
return 0;
|
||||
@@ -274,7 +278,7 @@ int SYMBOL_EDITOR_CONTROL::DuplicateSymbol( const TOOL_EVENT& aEvent )
|
||||
return 0;
|
||||
}
|
||||
|
||||
editFrame->DuplicateSymbol( aEvent.IsAction( &EE_ACTIONS::pasteSymbol ) );
|
||||
editFrame->DuplicateSymbol( isPasteAction );
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <symbol_edit_frame.h>
|
||||
#include <tools/symbol_editor_drawing_tools.h>
|
||||
#include <tools/symbol_editor_pin_tool.h>
|
||||
#include <tools/ee_grid_helper.h>
|
||||
#include <bitmaps.h>
|
||||
#include <lib_text.h>
|
||||
#include <dialogs/dialog_lib_text_properties.h>
|
||||
@@ -67,12 +68,16 @@ bool SYMBOL_EDITOR_DRAWING_TOOLS::Init()
|
||||
|
||||
int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
KICAD_T type = aEvent.Parameter<KICAD_T>();
|
||||
auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
|
||||
auto* pinTool = type == LIB_PIN_T ? m_toolMgr->GetTool<SYMBOL_EDITOR_PIN_TOOL>() : nullptr;
|
||||
VECTOR2I cursorPos;
|
||||
EDA_ITEM* item = nullptr;
|
||||
bool isText = aEvent.IsAction( &EE_ACTIONS::placeSymbolText );
|
||||
KICAD_T type = aEvent.Parameter<KICAD_T>();
|
||||
auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
|
||||
auto* pinTool = type == LIB_PIN_T ? m_toolMgr->GetTool<SYMBOL_EDITOR_PIN_TOOL>() : nullptr;
|
||||
|
||||
KIGFX::VIEW_CONTROLS* controls = getViewControls();
|
||||
EE_GRID_HELPER grid( m_toolMgr );
|
||||
VECTOR2I cursorPos;
|
||||
bool ignorePrimePosition = false;
|
||||
LIB_ITEM* item = nullptr;
|
||||
bool isText = aEvent.IsAction( &EE_ACTIONS::placeSymbolText );
|
||||
|
||||
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
|
||||
|
||||
@@ -92,20 +97,30 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
|
||||
Activate();
|
||||
// Must be done after Activate() so that it gets set into the correct context
|
||||
getViewControls()->ShowCursor( true );
|
||||
controls->ShowCursor( true );
|
||||
// Set initial cursor
|
||||
setCursor();
|
||||
|
||||
// Prime the pump
|
||||
if( aEvent.HasPosition() || ( isText && !aEvent.IsReactivate() ) )
|
||||
m_toolMgr->RunAction( ACTIONS::cursorClick );
|
||||
if( aEvent.HasPosition() )
|
||||
{
|
||||
m_toolMgr->PrimeTool( aEvent.Position() );
|
||||
}
|
||||
else if( !aEvent.IsReactivate() && isText )
|
||||
{
|
||||
m_toolMgr->PrimeTool( { 0, 0 } );
|
||||
ignorePrimePosition = true;
|
||||
}
|
||||
|
||||
// Main loop: keep receiving events
|
||||
while( TOOL_EVENT* evt = Wait() )
|
||||
{
|
||||
setCursor();
|
||||
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
|
||||
grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
|
||||
|
||||
cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
|
||||
cursorPos = grid.Align( controls->GetMousePosition() );
|
||||
controls->ForceCursorPosition( true, cursorPos );
|
||||
|
||||
auto cleanup =
|
||||
[&] ()
|
||||
@@ -118,6 +133,8 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
|
||||
if( evt->IsCancelInteractive() )
|
||||
{
|
||||
m_frame->GetInfoBar()->Dismiss();
|
||||
|
||||
if( item )
|
||||
{
|
||||
cleanup();
|
||||
@@ -130,12 +147,26 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
else if( evt->IsActivate() )
|
||||
{
|
||||
if( item )
|
||||
cleanup();
|
||||
|
||||
if( evt->IsMoveTool() )
|
||||
if( item && evt->IsMoveTool() )
|
||||
{
|
||||
// we're already moving our own item; ignore the move tool
|
||||
evt->SetPassEvent( false );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( item )
|
||||
{
|
||||
m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel item creation." ) );
|
||||
evt->SetPassEvent( false );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( evt->IsPointEditor() )
|
||||
{
|
||||
// don't exit (the point editor runs in the background)
|
||||
}
|
||||
else if( evt->IsMoveTool() )
|
||||
{
|
||||
// leave ourselves on the stack so we come back after the move
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -186,11 +217,17 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
wxFAIL_MSG( wxT( "TwoClickPlace(): unknown type" ) );
|
||||
}
|
||||
|
||||
// Restore cursor after dialog
|
||||
getViewControls()->WarpCursor( getViewControls()->GetCursorPosition(), true );
|
||||
// If we started with a click on a tool button or menu then continue with the
|
||||
// current mouse position. Otherwise warp back to the original click position.
|
||||
if( evt->IsPrime() && ignorePrimePosition )
|
||||
cursorPos = grid.Align( controls->GetMousePosition() );
|
||||
else
|
||||
controls->WarpCursor( cursorPos, true );
|
||||
|
||||
if( item )
|
||||
{
|
||||
item->SetPosition( wxPoint( cursorPos.x, -cursorPos.y ) );
|
||||
|
||||
item->SetFlags( IS_NEW | IS_MOVING );
|
||||
m_view->ClearPreview();
|
||||
m_view->AddToPreview( item->Clone() );
|
||||
@@ -200,7 +237,7 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
setCursor();
|
||||
}
|
||||
|
||||
getViewControls()->SetCursorPosition( cursorPos, false );
|
||||
controls->SetCursorPosition( cursorPos, false );
|
||||
}
|
||||
// ... and second click places:
|
||||
else
|
||||
@@ -237,7 +274,7 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
|
||||
{
|
||||
static_cast<LIB_ITEM*>( item )->SetPosition( wxPoint( cursorPos.x, -cursorPos.y ) );
|
||||
item->SetPosition( wxPoint( cursorPos.x, -cursorPos.y ) );
|
||||
m_view->ClearPreview();
|
||||
m_view->AddToPreview( item->Clone() );
|
||||
}
|
||||
@@ -247,12 +284,12 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
|
||||
// Enable autopanning and cursor capture only when there is an item to be placed
|
||||
getViewControls()->SetAutoPan( item != nullptr );
|
||||
getViewControls()->CaptureCursor( item != nullptr );
|
||||
controls->SetAutoPan( item != nullptr );
|
||||
controls->CaptureCursor( item != nullptr );
|
||||
}
|
||||
|
||||
getViewControls()->SetAutoPan( false );
|
||||
getViewControls()->CaptureCursor( false );
|
||||
controls->SetAutoPan( false );
|
||||
controls->CaptureCursor( false );
|
||||
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -814,7 +814,6 @@ SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* a
|
||||
const wxPoint& aShapePos )
|
||||
{
|
||||
SHAPE_POLY_SET holeBuffer;
|
||||
bool hasHole = false;
|
||||
|
||||
m_shape.RemoveAllContours();
|
||||
|
||||
@@ -836,18 +835,17 @@ SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* a
|
||||
{
|
||||
m_shape.BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
|
||||
holeBuffer.RemoveAllContours();
|
||||
hasHole = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge and cleanup basic shape polygons
|
||||
m_shape.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
// If a hole is defined inside a polygon, we must fracture the polygon
|
||||
// to be able to drawn it (i.e link holes by overlapping edges)
|
||||
if( hasHole )
|
||||
m_shape.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
// A hole can be is defined inside a polygon, or the polygons themselve can create
|
||||
// a hole when merged, so we must fracture the polygon to be able to drawn it
|
||||
// (i.e link holes by overlapping edges)
|
||||
m_shape.Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
m_boundingBox = EDA_RECT( wxPoint( 0, 0 ), wxSize( 1, 1 ) );
|
||||
auto bb = m_shape.BBox();
|
||||
|
||||
+23
-10
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2009 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -64,16 +64,19 @@ void GERBVIEW_FRAME::ReCreateMenuBar()
|
||||
if( !openRecentGbrMenu )
|
||||
{
|
||||
openRecentGbrMenu = new ACTION_MENU( false, selTool );
|
||||
openRecentGbrMenu->SetTitle( _( "Open Recent Gerber File" ) );
|
||||
openRecentGbrMenu->SetIcon( BITMAPS::recent );
|
||||
|
||||
recentGbrFiles.UseMenu( openRecentGbrMenu );
|
||||
recentGbrFiles.SetClearText( _( "Clear Recent Gerber Files" ) );
|
||||
recentGbrFiles.UseMenu( openRecentGbrMenu );
|
||||
recentGbrFiles.AddFilesToMenu();
|
||||
}
|
||||
|
||||
// Ensure the title is up to date after changing language
|
||||
openRecentGbrMenu->SetTitle( _( "Open Recent Gerber File" ) );
|
||||
recentGbrFiles.UpdateClearText( openRecentGbrMenu, _( "Clear Recent Gerber Files" ) );
|
||||
|
||||
fileMenu->Add( GERBVIEW_ACTIONS::openGerber );
|
||||
wxMenuItem* gbrItem = fileMenu->Add( openRecentGbrMenu );
|
||||
wxMenuItem* gbrItem = fileMenu->Add( openRecentGbrMenu->Clone() );
|
||||
RegisterUIUpdateHandler( gbrItem->GetId(), FileHistoryCond( recentGbrFiles) );
|
||||
|
||||
|
||||
@@ -90,8 +93,12 @@ void GERBVIEW_FRAME::ReCreateMenuBar()
|
||||
m_drillFileHistory.AddFilesToMenu();
|
||||
}
|
||||
|
||||
// Ensure the title is up to date after changing language
|
||||
openRecentGbrMenu->SetTitle( _( "Open Recent Gerber File" ) );
|
||||
m_drillFileHistory.UpdateClearText( openRecentDrlMenu, _( "Clear Recent Drill Files" ) );
|
||||
|
||||
fileMenu->Add( GERBVIEW_ACTIONS::openDrillFile );
|
||||
wxMenuItem* drillItem = fileMenu->Add( openRecentDrlMenu );
|
||||
wxMenuItem* drillItem = fileMenu->Add( openRecentDrlMenu->Clone() );
|
||||
RegisterUIUpdateHandler( drillItem->GetId(), FileHistoryCond( m_drillFileHistory ) );
|
||||
|
||||
|
||||
@@ -100,16 +107,19 @@ void GERBVIEW_FRAME::ReCreateMenuBar()
|
||||
if( !openRecentJobMenu )
|
||||
{
|
||||
openRecentJobMenu = new ACTION_MENU( false, selTool );
|
||||
openRecentJobMenu->SetTitle( _( "Open Recent Job File" ) );
|
||||
openRecentJobMenu->SetIcon( BITMAPS::recent );
|
||||
|
||||
m_jobFileHistory.UseMenu( openRecentJobMenu );
|
||||
m_jobFileHistory.SetClearText( _( "Clear Recent Job Files" ) );
|
||||
m_jobFileHistory.UseMenu( openRecentJobMenu );
|
||||
m_jobFileHistory.AddFilesToMenu();
|
||||
}
|
||||
|
||||
// Ensure the title is up to date after changing language
|
||||
openRecentJobMenu->SetTitle( _( "Open Recent Job File" ) );
|
||||
m_jobFileHistory.UpdateClearText( openRecentJobMenu, _( "Clear Recent Job Files" ) );
|
||||
|
||||
fileMenu->Add( GERBVIEW_ACTIONS::openJobFile );
|
||||
wxMenuItem* jobItem = fileMenu->Add( openRecentJobMenu );
|
||||
wxMenuItem* jobItem = fileMenu->Add( openRecentJobMenu->Clone() );
|
||||
RegisterUIUpdateHandler( jobItem->GetId(), FileHistoryCond( m_jobFileHistory ) );
|
||||
|
||||
|
||||
@@ -118,7 +128,6 @@ void GERBVIEW_FRAME::ReCreateMenuBar()
|
||||
if( !openRecentZipMenu )
|
||||
{
|
||||
openRecentZipMenu = new ACTION_MENU( false, selTool );
|
||||
openRecentZipMenu->SetTitle( _( "Open Recent Zip File" ) );
|
||||
openRecentZipMenu->SetIcon( BITMAPS::recent );
|
||||
|
||||
m_zipFileHistory.UseMenu( openRecentZipMenu );
|
||||
@@ -126,8 +135,12 @@ void GERBVIEW_FRAME::ReCreateMenuBar()
|
||||
m_zipFileHistory.AddFilesToMenu();
|
||||
}
|
||||
|
||||
// Ensure the title is up to date after changing language
|
||||
openRecentZipMenu->SetTitle( _( "Open Recent Zip File" ) );
|
||||
m_zipFileHistory.UpdateClearText( openRecentZipMenu, _( "Clear Recent Zip Files" ) );
|
||||
|
||||
fileMenu->Add( GERBVIEW_ACTIONS::openZipFile );
|
||||
wxMenuItem* zipItem = fileMenu->Add( openRecentZipMenu );
|
||||
wxMenuItem* zipItem = fileMenu->Add( openRecentZipMenu->Clone() );
|
||||
RegisterUIUpdateHandler( zipItem->GetId(), FileHistoryCond( m_zipFileHistory ) );
|
||||
|
||||
#undef FileHistoryCond
|
||||
|
||||
@@ -130,7 +130,8 @@ public:
|
||||
* @param aLayer in case of items spanning multiple layers, only the shapes belonging to aLayer
|
||||
* will be returned. Pass UNDEFINED_LAYER to return shapes for all layers.
|
||||
*/
|
||||
virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const;
|
||||
virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
|
||||
FLASHING aFlash = FLASHING::DEFAULT ) const;
|
||||
|
||||
BOARD_ITEM_CONTAINER* GetParent() const { return (BOARD_ITEM_CONTAINER*) m_parent; }
|
||||
|
||||
|
||||
@@ -50,6 +50,15 @@ public:
|
||||
m_init( true )
|
||||
{ }
|
||||
|
||||
template<class T>
|
||||
EDA_RECT( const BOX2<T> aBox )
|
||||
{
|
||||
m_pos = (wxPoint) aBox.GetPosition();
|
||||
m_size.x = aBox.GetWidth();
|
||||
m_size.y = aBox.GetHeight();
|
||||
m_init = true;
|
||||
}
|
||||
|
||||
virtual ~EDA_RECT() { };
|
||||
|
||||
wxPoint Centre() const
|
||||
|
||||
+11
-2
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 Ian McInerney <Ian.S.McInerney@ieee.org>
|
||||
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
/**
|
||||
* Add the files to the specified menu
|
||||
*
|
||||
* @aMenu is the menu to operate on.
|
||||
* @param aMenu is the menu to operate on.
|
||||
*/
|
||||
void AddFilesToMenu( wxMenu* aMenu ) override;
|
||||
|
||||
@@ -125,6 +125,15 @@ public:
|
||||
m_clearText = aClearText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the text displayed on the menu item that clears the entire menu.
|
||||
* useful after language change.
|
||||
*
|
||||
* @param aMenu is the menu to operate on.
|
||||
* @param aClearText is the new text to use for the menu item
|
||||
*/
|
||||
void UpdateClearText( wxMenu* aMenu, wxString aClearText );
|
||||
|
||||
/**
|
||||
* Clear all entries from the file history.
|
||||
*/
|
||||
|
||||
@@ -146,6 +146,17 @@ enum PCB_LAYER_ID: int
|
||||
|
||||
#define MAX_CU_LAYERS (B_Cu - F_Cu + 1)
|
||||
|
||||
/**
|
||||
* Enum used during connectivity building to ensure we do not query connectivity while building
|
||||
* the database
|
||||
*/
|
||||
enum class FLASHING
|
||||
{
|
||||
DEFAULT, // Flashing follows connectivity
|
||||
ALWAYS_FLASHED, // Always flashed for connectivity
|
||||
NEVER_FLASHED, // Never flashed for connectivity
|
||||
};
|
||||
|
||||
/// Dedicated layers for net names used in Pcbnew
|
||||
enum NETNAMES_LAYER_ID: int
|
||||
{
|
||||
|
||||
+3
-3
@@ -36,9 +36,9 @@
|
||||
#include <base_units.h> // for IU_PER_MILS
|
||||
|
||||
/// Min and max page sizes for clamping, in mils.
|
||||
#define MIN_PAGE_SIZE_MILS 100
|
||||
#define MAX_PAGE_SIZE_PCBNEW_MILS 48000
|
||||
#define MAX_PAGE_SIZE_MILS 120000
|
||||
#define MIN_PAGE_SIZE_MILS 100
|
||||
#define MAX_PAGE_SIZE_PCBNEW_MILS 48000
|
||||
#define MAX_PAGE_SIZE_EESCHEMA_MILS 120000
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -218,6 +218,7 @@ public:
|
||||
EDA_ITEM* GetItem( const KIID& aId ) const override;
|
||||
|
||||
void FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer = UNDEFINED_LAYER );
|
||||
void FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID aLayer = UNDEFINED_LAYER );
|
||||
|
||||
// General
|
||||
virtual void ReCreateOptToolbar() override { }
|
||||
|
||||
+6
-4
@@ -117,10 +117,12 @@ public:
|
||||
m_ids.push_back( dItem );
|
||||
}
|
||||
|
||||
KIID GetMainItemID() const { return m_ids.size() > 0 ? m_ids[0] : niluuid; }
|
||||
KIID GetAuxItemID() const { return m_ids.size() > 1 ? m_ids[1] : niluuid;; }
|
||||
KIID GetAuxItem2ID() const { return m_ids.size() > 2 ? m_ids[2] : niluuid;; }
|
||||
KIID GetAuxItem3ID() const { return m_ids.size() > 3 ? m_ids[3] : niluuid;; }
|
||||
virtual KIID GetMainItemID() const { return m_ids.size() > 0 ? m_ids[0] : niluuid; }
|
||||
virtual KIID GetAuxItemID() const { return m_ids.size() > 1 ? m_ids[1] : niluuid; }
|
||||
virtual KIID GetAuxItem2ID() const { return m_ids.size() > 2 ? m_ids[2] : niluuid; }
|
||||
virtual KIID GetAuxItem3ID() const { return m_ids.size() > 3 ? m_ids[3] : niluuid; }
|
||||
|
||||
std::vector<KIID> GetIDs() const { return m_ids; }
|
||||
|
||||
void SetParent( MARKER_BASE* aMarker ) { m_parent = aMarker; }
|
||||
MARKER_BASE* GetParent() const { return m_parent; }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2020-2022 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
|
||||
@@ -56,6 +56,8 @@ protected:
|
||||
wxStyledTextCtrl* m_te;
|
||||
wxString m_braces;
|
||||
int m_lastCaretPos;
|
||||
int m_lastSelStart;
|
||||
int m_lastSelEnd;
|
||||
bool m_suppressAutocomplete;
|
||||
bool m_singleLine; // Treat <return> as OK, and skip special tab
|
||||
// stop handling (including monospaced font).
|
||||
|
||||
@@ -104,7 +104,8 @@ public:
|
||||
* The difference between this function and wxMenu::AppendSubMenu() is the capability to
|
||||
* handle icons.
|
||||
*
|
||||
* @param aMenu is the submenu to be added.
|
||||
* @param aMenu is the submenu to be added. This should be a new instance (use Clone()) if required
|
||||
* as the menu is destructed after use.
|
||||
*/
|
||||
wxMenuItem* Add( ACTION_MENU* aMenu );
|
||||
|
||||
|
||||
@@ -204,6 +204,8 @@ public:
|
||||
* @note The position may be different from the cursor position if snapping is
|
||||
* enabled (@see GetCursorPosition()).
|
||||
*
|
||||
* @note The position is clamped if outside of coordinates representation limits.
|
||||
*
|
||||
* @param aWorldCoordinates if true, the result is given in world coordinates, otherwise
|
||||
* it is given in screen coordinates.
|
||||
* @return The current mouse pointer position in either world or screen coordinates.
|
||||
@@ -216,6 +218,8 @@ public:
|
||||
* @note The position may be different from the mouse pointer position if snapping is
|
||||
* enabled or cursor position is forced to a specific point.
|
||||
*
|
||||
* @note The position is clamped if outside of coordinates representation limits.
|
||||
*
|
||||
* @return The current cursor position in world coordinates.
|
||||
*/
|
||||
VECTOR2D GetCursorPosition() const
|
||||
@@ -237,6 +241,8 @@ public:
|
||||
* @note The position may be different from the mouse pointer position if snapping is
|
||||
* enabled or cursor position is forced to a specific point.
|
||||
*
|
||||
* @note The position is clamped if outside of coordinates representation limits.
|
||||
*
|
||||
* @param aEnableSnapping selects whether cursor position should be snapped to the grid.
|
||||
* @return The current cursor position in world coordinates.
|
||||
*/
|
||||
@@ -245,6 +251,8 @@ public:
|
||||
/**
|
||||
* Place the cursor immediately at a given point. Mouse movement is ignored.
|
||||
*
|
||||
* @note The position is clamped if outside of coordinates representation limits.
|
||||
*
|
||||
* @param aEnabled enable forced cursor position
|
||||
* @param aPosition the position (world coordinates).
|
||||
*/
|
||||
@@ -260,6 +268,8 @@ public:
|
||||
* The position is not forced and will be overridden with the next mouse motion event.
|
||||
* Mouse cursor follows the world cursor.
|
||||
*
|
||||
* @note The position is clamped if outside of coordinates representation limits.
|
||||
*
|
||||
* @param aPosition is the requested cursor position in the world coordinates.
|
||||
* @param aWarpView enables/disables view warp if the cursor is outside the current viewport.
|
||||
*/
|
||||
@@ -270,6 +280,8 @@ public:
|
||||
/**
|
||||
* Move the graphic crosshair cursor to the requested position expressed in world coordinates.
|
||||
*
|
||||
* @note The position is clamped if outside of coordinates representation limits.
|
||||
*
|
||||
* @param aPosition is the requested cursor position in the world coordinates.
|
||||
* @param aWarpView enables/disables view warp if the cursor is outside the current viewport.
|
||||
*/
|
||||
@@ -303,6 +315,8 @@ public:
|
||||
* If enabled (@see SetEnableCursorWarping(), warps the cursor to the specified position,
|
||||
* expressed either in the screen coordinates or the world coordinates.
|
||||
*
|
||||
* @note The position is clamped if outside of coordinates representation limits.
|
||||
*
|
||||
* @param aPosition is the position where the cursor should be warped.
|
||||
* @param aWorldCoordinates if true treats aPosition as the world coordinates, otherwise it
|
||||
* uses it as the screen coordinates.
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
#ifndef KICAD_WX_GRID_H
|
||||
#define KICAD_WX_GRID_H
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/grid.h>
|
||||
#include <wx/version.h>
|
||||
|
||||
|
||||
class WX_GRID : public wxGrid
|
||||
{
|
||||
@@ -119,6 +122,10 @@ protected:
|
||||
void onGridColMove( wxGridEvent& aEvent );
|
||||
void onGridCellSelect( wxGridEvent& aEvent );
|
||||
|
||||
#if wxCHECK_VERSION( 3, 1, 0 )
|
||||
void onDPIChanged(wxDPIChangedEvent& event);
|
||||
#endif
|
||||
|
||||
bool m_weOwnTable;
|
||||
};
|
||||
|
||||
|
||||
+4
-2
@@ -62,13 +62,15 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar()
|
||||
if( !openRecentMenu )
|
||||
{
|
||||
openRecentMenu = new ACTION_MENU( false, controlTool );
|
||||
openRecentMenu->SetTitle( _( "Open Recent" ) );
|
||||
openRecentMenu->SetIcon( BITMAPS::recent );
|
||||
|
||||
fileHistory.UseMenu( openRecentMenu );
|
||||
fileHistory.AddFilesToMenu();
|
||||
}
|
||||
|
||||
// Ensure the title is up to date after changing language
|
||||
openRecentMenu->SetTitle( _( "Open Recent" ) );
|
||||
|
||||
fileMenu->Add( KICAD_MANAGER_ACTIONS::newProject );
|
||||
fileMenu->Add( KICAD_MANAGER_ACTIONS::newFromTemplate );
|
||||
|
||||
@@ -79,7 +81,7 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar()
|
||||
|
||||
fileMenu->Add( KICAD_MANAGER_ACTIONS::openProject );
|
||||
|
||||
wxMenuItem* item = fileMenu->Add( openRecentMenu );
|
||||
wxMenuItem* item = fileMenu->Add( openRecentMenu->Clone() );
|
||||
|
||||
// Add the file menu condition here since it needs the item ID for the submenu
|
||||
ACTION_CONDITIONS cond;
|
||||
|
||||
@@ -133,6 +133,47 @@ VECTOR2<T> GetVectorSnapped45( const VECTOR2<T>& aVec, bool only45 = false )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clamps a vector to values that can be negated, respecting numeric limits
|
||||
* of coordinates data type with specified padding.
|
||||
*
|
||||
* Numeric limits are (-2^31 + 1) to (2^31 - 1).
|
||||
*
|
||||
* Takes care of rounding in case of floating point to integer conversion.
|
||||
*
|
||||
* @param aCoord - vector to clamp.
|
||||
* @param aPadding - padding from the limits. Must not be negative.
|
||||
* @return clamped vector.
|
||||
*/
|
||||
template <typename in_type, typename ret_type = in_type, typename pad_type = unsigned int,
|
||||
typename = typename std::enable_if<std::is_unsigned<pad_type>::value>::type>
|
||||
VECTOR2<ret_type> GetClampedCoords( const VECTOR2<in_type>& aCoords, pad_type aPadding = 0u )
|
||||
{
|
||||
typedef std::numeric_limits<int> coord_limits;
|
||||
|
||||
long max = coord_limits::max() - aPadding;
|
||||
long min = -max;
|
||||
|
||||
in_type x = aCoords.x;
|
||||
in_type y = aCoords.y;
|
||||
|
||||
if( x < min )
|
||||
x = min;
|
||||
else if( x > max )
|
||||
x = max;
|
||||
|
||||
if( y < min )
|
||||
y = min;
|
||||
else if( y > max )
|
||||
y = max;
|
||||
|
||||
if( !std::is_integral<in_type>() && std::is_integral<ret_type>() )
|
||||
return VECTOR2<ret_type>( KiROUND( x ), KiROUND( y ) );
|
||||
|
||||
return VECTOR2<ret_type>( x, y );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if any part of a line falls within the bounds of a rectangle.
|
||||
*
|
||||
|
||||
@@ -420,7 +420,7 @@ void TransformTrapezoidToPolygon( SHAPE_POLY_SET& aCornerBuffer, const wxPoint&
|
||||
corners.push_back( ROUNDED_CORNER( size.x + aDeltaY, size.y - aDeltaX ) );
|
||||
corners.push_back( ROUNDED_CORNER( -size.x - aDeltaY, size.y + aDeltaX ) );
|
||||
|
||||
if( aDeltaY == size.x || aDeltaX == size.y )
|
||||
if( std::abs( aDeltaY ) == std::abs( size.x ) || std::abs( aDeltaX ) == std::abs( size.y ) )
|
||||
CornerListRemoveDuplicates( corners );
|
||||
}
|
||||
|
||||
@@ -536,6 +536,17 @@ void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, const wxPoint& aStart
|
||||
const wxPoint& aMid, const wxPoint& aEnd, int aWidth,
|
||||
int aError, ERROR_LOC aErrorLoc )
|
||||
{
|
||||
SEG startToEnd( aStart, aEnd );
|
||||
int distanceToMid = startToEnd.Distance( aMid );
|
||||
|
||||
if( distanceToMid <= 1 )
|
||||
{
|
||||
// Not an arc but essentially a straight line with a small error
|
||||
TransformOvalToPolygon( aCornerBuffer, aStart, aEnd, aWidth + distanceToMid, aError,
|
||||
aErrorLoc );
|
||||
return;
|
||||
}
|
||||
|
||||
SHAPE_ARC arc( aStart, aMid, aEnd, aWidth );
|
||||
// Currentlye have currently 2 algos:
|
||||
// the first approximates the thick arc from its outlines
|
||||
|
||||
@@ -1518,7 +1518,7 @@ bool SHAPE_POLY_SET::Collide( const SHAPE* aShape, int aClearance, int* aActual,
|
||||
return false;
|
||||
}
|
||||
|
||||
const_cast<SHAPE_POLY_SET*>( this )->CacheTriangulation( true );
|
||||
const_cast<SHAPE_POLY_SET*>( this )->CacheTriangulation( false );
|
||||
|
||||
int actual = INT_MAX;
|
||||
VECTOR2I location;
|
||||
|
||||
@@ -54,13 +54,16 @@ void PL_EDITOR_FRAME::ReCreateMenuBar()
|
||||
if( !openRecentMenu )
|
||||
{
|
||||
openRecentMenu = new ACTION_MENU( false, selTool );
|
||||
openRecentMenu->SetTitle( _( "Open Recent" ) );
|
||||
openRecentMenu->SetIcon( BITMAPS::recent );
|
||||
|
||||
recentFiles.UseMenu( openRecentMenu );
|
||||
recentFiles.AddFilesToMenu();
|
||||
}
|
||||
|
||||
// Ensure the title is up to date after changing language
|
||||
openRecentMenu->SetTitle( _( "Open Recent" ) );
|
||||
recentFiles.UpdateClearText( openRecentMenu, _( "Clear Recent Files" ) );
|
||||
|
||||
//-- File menu -------------------------------------------------------
|
||||
//
|
||||
ACTION_MENU* fileMenu = new ACTION_MENU( false, selTool );
|
||||
@@ -68,7 +71,7 @@ void PL_EDITOR_FRAME::ReCreateMenuBar()
|
||||
fileMenu->Add( ACTIONS::doNew );
|
||||
fileMenu->Add( ACTIONS::open );
|
||||
|
||||
wxMenuItem* item = fileMenu->Add( openRecentMenu );
|
||||
wxMenuItem* item = fileMenu->Add( openRecentMenu->Clone() );
|
||||
|
||||
// Add the file menu condition here since it needs the item ID for the submenu
|
||||
ACTION_CONDITIONS cond;
|
||||
|
||||
@@ -204,6 +204,9 @@ int PL_EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
//
|
||||
else if( evt->IsCancelInteractive() || evt->IsActivate() )
|
||||
{
|
||||
if( evt->IsCancelInteractive() )
|
||||
m_frame->GetInfoBar()->Dismiss();
|
||||
|
||||
if( m_moveInProgress )
|
||||
{
|
||||
if( evt->IsActivate() )
|
||||
|
||||
@@ -89,7 +89,9 @@ int PL_EDITOR_CONTROL::PageSetup( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
m_frame->SaveCopyInUndoList();
|
||||
|
||||
DIALOG_PAGES_SETTINGS dlg( m_frame, IU_PER_MILS, wxSize( MAX_PAGE_SIZE_MILS, MAX_PAGE_SIZE_MILS ) );
|
||||
DIALOG_PAGES_SETTINGS dlg( m_frame, IU_PER_MILS,
|
||||
wxSize( MAX_PAGE_SIZE_EESCHEMA_MILS,
|
||||
MAX_PAGE_SIZE_EESCHEMA_MILS ) );
|
||||
dlg.SetWksFileName( m_frame->GetCurrentFileName() );
|
||||
dlg.EnableWksFileNamePicker( false );
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ bool BOARD_ITEM::ptr_cmp::operator() ( const BOARD_ITEM* a, const BOARD_ITEM* b
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<SHAPE> BOARD_ITEM::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
|
||||
std::shared_ptr<SHAPE> BOARD_ITEM::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
|
||||
{
|
||||
std::shared_ptr<SHAPE> shape;
|
||||
|
||||
|
||||
@@ -798,7 +798,33 @@ bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
|
||||
|
||||
for( PCB_LAYER_ID layer : commonLayers.Seq() )
|
||||
{
|
||||
if( parentA->GetEffectiveShape( layer )->Collide( parentB->GetEffectiveShape( layer ).get() ) )
|
||||
FLASHING flashingA = FLASHING::NEVER_FLASHED;
|
||||
FLASHING flashingB = FLASHING::NEVER_FLASHED;
|
||||
|
||||
if( const PAD* pad = dyn_cast<const PAD*>( parentA ) )
|
||||
{
|
||||
if( !pad->GetRemoveUnconnected() || ( ( layer == F_Cu || layer == B_Cu ) && pad->GetKeepTopBottom() ) )
|
||||
flashingA = FLASHING::ALWAYS_FLASHED;
|
||||
}
|
||||
else if( const PCB_VIA* via = dyn_cast<const PCB_VIA*>( parentA ) )
|
||||
{
|
||||
if( !via->GetRemoveUnconnected() || ( ( layer == F_Cu || layer == B_Cu ) && via->GetKeepTopBottom() ) )
|
||||
flashingA = FLASHING::ALWAYS_FLASHED;
|
||||
}
|
||||
|
||||
if( const PAD* pad = dyn_cast<const PAD*>( parentB ) )
|
||||
{
|
||||
if( !pad->GetRemoveUnconnected() || ( ( layer == F_Cu || layer == B_Cu ) && pad->GetKeepTopBottom() ) )
|
||||
flashingB = FLASHING::ALWAYS_FLASHED;
|
||||
}
|
||||
else if( const PCB_VIA* via = dyn_cast<const PCB_VIA*>( parentB ) )
|
||||
{
|
||||
if( !via->GetRemoveUnconnected() || ( ( layer == F_Cu || layer == B_Cu ) && via->GetKeepTopBottom() ) )
|
||||
flashingB = FLASHING::ALWAYS_FLASHED;
|
||||
}
|
||||
|
||||
if( parentA->GetEffectiveShape( layer, flashingA )->Collide(
|
||||
parentB->GetEffectiveShape( layer, flashingB ).get() ) )
|
||||
{
|
||||
m_item->Connect( aCandidate );
|
||||
aCandidate->Connect( m_item );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Brian Piccioni brian@documenteddesigns.com
|
||||
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Brian Piccioni <brian@documenteddesigns.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -30,14 +30,10 @@
|
||||
#include <confirm.h>
|
||||
#include <ctype.h>
|
||||
#include <dialog_board_reannotate.h>
|
||||
#include <fstream>
|
||||
#include <string_utils.h> // StrNumCmp
|
||||
#include <kiface_base.h>
|
||||
#include <mail_type.h>
|
||||
#include <pcbnew_settings.h>
|
||||
#include <refdes_utils.h>
|
||||
#include <sstream>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tool/grid_menu.h>
|
||||
#include <wx/valtext.h>
|
||||
|
||||
@@ -136,16 +132,12 @@ DIALOG_BOARD_REANNOTATE::DIALOG_BOARD_REANNOTATE( PCB_EDIT_FRAME* aParentFrame )
|
||||
m_selection = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
|
||||
|
||||
if( !m_selection.Empty() )
|
||||
m_annotationChoice = AnnotationChoice::AnnotateSelected;
|
||||
m_annotationScope = AnnotateSelected;
|
||||
|
||||
for( wxRadioButton* button : AnnotateWhat )
|
||||
for( wxRadioButton* button : m_scopeRadioButtons )
|
||||
button->SetValue( false );
|
||||
|
||||
m_annotationChoice = ( m_sortCode >= (int) AnnotateWhat.size() ) ?
|
||||
AnnotationChoice::AnnotateAll :
|
||||
m_annotationChoice;
|
||||
|
||||
AnnotateWhat[m_annotationChoice]->SetValue( true );
|
||||
m_scopeRadioButtons[m_annotationScope]->SetValue( true );
|
||||
|
||||
reannotate_down_right_bitmap->SetBitmap( KiBitmap( BITMAPS::reannotate_right_down ) );
|
||||
reannotate_right_down_bitmap->SetBitmap( KiBitmap( BITMAPS::reannotate_left_down ) );
|
||||
@@ -176,7 +168,7 @@ DIALOG_BOARD_REANNOTATE::~DIALOG_BOARD_REANNOTATE()
|
||||
|
||||
cfg->m_Reannotate.grid_index = m_gridIndex;
|
||||
cfg->m_Reannotate.sort_code = m_sortCode;
|
||||
cfg->m_Reannotate.annotation_choice = m_annotationChoice;
|
||||
cfg->m_Reannotate.annotation_choice = m_annotationScope;
|
||||
cfg->m_Reannotate.report_severity = m_severity;
|
||||
|
||||
cfg->m_Reannotate.front_refdes_start = m_FrontRefDesStart->GetValue();
|
||||
@@ -198,7 +190,7 @@ void DIALOG_BOARD_REANNOTATE::InitValues( void )
|
||||
|
||||
m_gridIndex = cfg->m_Reannotate.grid_index ;
|
||||
m_sortCode = cfg->m_Reannotate.sort_code ;
|
||||
m_annotationChoice = cfg->m_Reannotate.annotation_choice ;
|
||||
m_annotationScope = cfg->m_Reannotate.annotation_choice ;
|
||||
m_severity = cfg->m_Reannotate.report_severity;
|
||||
|
||||
m_FrontRefDesStart->SetValue( cfg->m_Reannotate.front_refdes_start );
|
||||
@@ -311,7 +303,7 @@ void DIALOG_BOARD_REANNOTATE::MakeSampleText( wxString& aMessage )
|
||||
wxString tmp;
|
||||
|
||||
aMessage.Printf( _( "\n%s footprints will be reannotated." ),
|
||||
_( AnnotateString[m_annotationChoice] ) );
|
||||
_( AnnotateString[m_annotationScope] ) );
|
||||
|
||||
if( !m_ExcludeList->GetValue().empty() )
|
||||
{
|
||||
@@ -418,18 +410,16 @@ void DIALOG_BOARD_REANNOTATE::GetParameters()
|
||||
m_sortGridy = m_sortGridx;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
m_annotationScope = AnnotateAll;
|
||||
|
||||
for( wxRadioButton* button : AnnotateWhat )
|
||||
for( wxRadioButton* button : m_scopeRadioButtons )
|
||||
{
|
||||
if( button->GetValue() )
|
||||
break;
|
||||
else
|
||||
i++;
|
||||
m_annotationScope++;
|
||||
}
|
||||
|
||||
m_annotationChoice = ( i >= (int) AnnotateWhat.size() ) ? AnnotationChoice::AnnotateAll : i;
|
||||
|
||||
m_MessageWindow->SetLazyUpdate( true );
|
||||
}
|
||||
|
||||
@@ -642,7 +632,7 @@ bool DIALOG_BOARD_REANNOTATE::ReannotateBoard()
|
||||
|
||||
bool DIALOG_BOARD_REANNOTATE::BuildFootprintList( std::vector<RefDesInfo>& aBadRefDes )
|
||||
{
|
||||
bool annotateSelected;
|
||||
bool annotateSelected = m_AnnotateSelection->GetValue();
|
||||
bool annotateFront = m_AnnotateFront->GetValue(); // Unless only doing back
|
||||
bool annotateBack = m_AnnotateBack->GetValue(); // Unless only doing front
|
||||
bool skipLocked = m_ExcludeLocked->GetValue();
|
||||
@@ -657,7 +647,7 @@ bool DIALOG_BOARD_REANNOTATE::BuildFootprintList( std::vector<RefDesInfo>& aBadR
|
||||
|
||||
std::vector<KIID> selected;
|
||||
|
||||
if( m_AnnotateSelection->GetValue() )
|
||||
if( annotateSelected )
|
||||
{
|
||||
for( EDA_ITEM* item : m_selection )
|
||||
{
|
||||
@@ -667,8 +657,6 @@ bool DIALOG_BOARD_REANNOTATE::BuildFootprintList( std::vector<RefDesInfo>& aBadR
|
||||
}
|
||||
}
|
||||
|
||||
annotateSelected = !selected.empty();
|
||||
|
||||
wxString exclude;
|
||||
|
||||
// Break exclude list into words.
|
||||
@@ -799,7 +787,8 @@ bool DIALOG_BOARD_REANNOTATE::BuildFootprintList( std::vector<RefDesInfo>& aBadR
|
||||
{
|
||||
if( m_changeArray[i].NewRefDes == m_changeArray[j].NewRefDes )
|
||||
{
|
||||
ShowReport( wxString::Format( _( "Duplicate instances of %s" ), m_changeArray[j].NewRefDes ),
|
||||
ShowReport( wxString::Format( _( "Duplicate instances of %s" ),
|
||||
m_changeArray[j].NewRefDes ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
|
||||
if( errorcount++ > MAXERROR )
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Brian Piccioni brian@documenteddesigns.com
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Brian Piccioni <brian@documenteddesigns.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -23,8 +23,8 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef DIALOG_BOARD_REANNOTATE_H_
|
||||
#define DIALOG_BOARD_REANNOTATE_H_
|
||||
#ifndef DIALOG_BOARD_REANNOTATE_H
|
||||
#define DIALOG_BOARD_REANNOTATE_H
|
||||
|
||||
#include <board.h>
|
||||
#include <footprint.h>
|
||||
@@ -60,9 +60,9 @@ enum ActionCode
|
||||
Exclude
|
||||
};
|
||||
|
||||
enum AnnotationChoice
|
||||
enum AnnotationScope
|
||||
{
|
||||
AnnotateAll,
|
||||
AnnotateAll = 0,
|
||||
AnnotateFront,
|
||||
AnnotateBack,
|
||||
AnnotateSelected
|
||||
@@ -115,7 +115,7 @@ private:
|
||||
m_Left_Up
|
||||
};
|
||||
|
||||
std::vector<wxRadioButton*> AnnotateWhat = {
|
||||
std::vector<wxRadioButton*> m_scopeRadioButtons = {
|
||||
m_AnnotateAll,
|
||||
m_AnnotateFront,
|
||||
m_AnnotateBack,
|
||||
@@ -200,7 +200,7 @@ private:
|
||||
|
||||
int m_sortCode;
|
||||
int m_gridIndex;
|
||||
int m_annotationChoice;
|
||||
int m_annotationScope;
|
||||
int m_severity;
|
||||
|
||||
double m_sortGridx;
|
||||
@@ -215,4 +215,4 @@ private:
|
||||
APP_SETTINGS_BASE* m_Config;
|
||||
};
|
||||
|
||||
#endif /* DIALOG_BOARD_REANNOTATECLASSES_H_ */
|
||||
#endif /* DIALOG_BOARD_REANNOTATE_H */
|
||||
|
||||
@@ -396,7 +396,31 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
|
||||
if( board->GetVisibleLayers().test( principalLayer ) )
|
||||
m_frame->SetActiveLayer( principalLayer );
|
||||
|
||||
if( m_centerMarkerOnIdle )
|
||||
if( rc_item->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG )
|
||||
{
|
||||
PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item );
|
||||
|
||||
if( track )
|
||||
{
|
||||
int net = track->GetNetCode();
|
||||
std::vector<BOARD_ITEM*> segs;
|
||||
|
||||
for( const KIID& id : rc_item->GetIDs() )
|
||||
{
|
||||
PCB_TRACK* candidate = dynamic_cast<PCB_TRACK*>( board->GetItem( id ) );
|
||||
|
||||
if( candidate && candidate->GetNetCode() == net )
|
||||
segs.push_back( candidate );
|
||||
}
|
||||
|
||||
m_frame->FocusOnItems( segs, principalLayer );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frame->FocusOnItem( item, principalLayer );
|
||||
}
|
||||
}
|
||||
else if( m_centerMarkerOnIdle )
|
||||
{
|
||||
// we already came from a cross-probe of the marker in the document; don't go
|
||||
// around in circles
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -160,6 +160,7 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks()
|
||||
|
||||
void DIALOG_FOOTPRINT_CHECKER::SetMarkersProvider( RC_ITEMS_PROVIDER* aProvider )
|
||||
{
|
||||
m_markersProvider = aProvider;
|
||||
m_markersTreeModel->SetProvider( aProvider );
|
||||
updateDisplayedCounts();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 Jean-Pierre Charras jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -267,9 +267,12 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
|
||||
if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataFromWindow() )
|
||||
return false;
|
||||
|
||||
LAYER_NUM layer = m_LayerSelectionCtrl->GetLayerSelection();
|
||||
if( !m_item )
|
||||
return true;
|
||||
|
||||
int layer = m_LayerSelectionCtrl->GetLayerSelection();
|
||||
BOARD_COMMIT commit( m_parent );
|
||||
|
||||
commit.Modify( m_item );
|
||||
|
||||
if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
|
||||
@@ -311,16 +314,17 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
|
||||
|
||||
m_item->SetCenter( wxPoint( KiROUND( center.x ), KiROUND( center.y ) ) );
|
||||
}
|
||||
|
||||
if( m_fp_item )
|
||||
{
|
||||
// We are editing a footprint; init the item coordinates relative to the footprint anchor.
|
||||
m_fp_item->SetStart0( m_fp_item->GetStart() );
|
||||
m_fp_item->SetEnd0( m_fp_item->GetEnd() );
|
||||
|
||||
if( m_item->GetShape() == SHAPE_T::ARC )
|
||||
if( m_fp_item->GetShape() == SHAPE_T::ARC )
|
||||
m_fp_item->SetCenter0( m_fp_item->GetCenter() );
|
||||
|
||||
if( m_item->GetShape() == SHAPE_T::BEZIER )
|
||||
if( m_fp_item->GetShape() == SHAPE_T::BEZIER )
|
||||
{
|
||||
m_fp_item->SetBezierC1_0( m_fp_item->GetBezierC1() );
|
||||
m_fp_item->SetBezierC2_0( m_fp_item->GetBezierC2() );
|
||||
|
||||
@@ -1749,25 +1749,25 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( PAD* aPad )
|
||||
else
|
||||
delta.y = m_trapDelta.GetValue();
|
||||
|
||||
if( delta.x < 0 && delta.x <= -aPad->GetSize().y )
|
||||
if( delta.x < 0 && delta.x < -aPad->GetSize().y )
|
||||
{
|
||||
delta.x = -aPad->GetSize().y + 2;
|
||||
error = true;
|
||||
}
|
||||
|
||||
if( delta.x > 0 && delta.x >= aPad->GetSize().y )
|
||||
if( delta.x > 0 && delta.x > aPad->GetSize().y )
|
||||
{
|
||||
delta.x = aPad->GetSize().y - 2;
|
||||
error = true;
|
||||
}
|
||||
|
||||
if( delta.y < 0 && delta.y <= -aPad->GetSize().x )
|
||||
if( delta.y < 0 && delta.y < -aPad->GetSize().x )
|
||||
{
|
||||
delta.y = -aPad->GetSize().x + 2;
|
||||
error = true;
|
||||
}
|
||||
|
||||
if( delta.y > 0 && delta.y >= aPad->GetSize().x )
|
||||
if( delta.y > 0 && delta.y > aPad->GetSize().x )
|
||||
{
|
||||
delta.y = aPad->GetSize().x - 2;
|
||||
error = true;
|
||||
|
||||
@@ -814,8 +814,8 @@ void DIALOG_PLOT::Plot( wxCommandEvent& event )
|
||||
};
|
||||
|
||||
wxString path = m_plotOpts.GetOutputDirectory();
|
||||
path = ExpandTextVars( path, &textResolver, nullptr, nullptr );
|
||||
path = ExpandEnvVarSubstitutions( path, nullptr );
|
||||
path = ExpandTextVars( path, &textResolver, nullptr, board->GetProject() );
|
||||
path = ExpandEnvVarSubstitutions( path, board->GetProject() );
|
||||
|
||||
wxFileName outputDir = wxFileName::DirName( path );
|
||||
wxString boardFilename = m_parent->GetBoard()->GetFileName();
|
||||
|
||||
@@ -76,8 +76,12 @@ void DIALOG_PNS_SETTINGS::OnOkClick( wxCommandEvent& aEvent )
|
||||
m_settings.SetOptimizeEntireDraggedTrack( m_optimizeEntireDraggedTrack->GetValue() );
|
||||
m_settings.SetAutoPosture( m_autoPosture->GetValue() );
|
||||
m_settings.SetFixAllSegments( m_fixAllSegments->GetValue() );
|
||||
m_settings.SetAllowDRCViolations( m_violateDrc->GetValue() );
|
||||
m_settings.SetFreeAngleMode( m_freeAngleMode->GetValue() );
|
||||
|
||||
if( m_violateDrc->IsEnabled() )
|
||||
m_settings.SetAllowDRCViolations( m_violateDrc->GetValue() );
|
||||
|
||||
if( m_freeAngleMode->IsEnabled() )
|
||||
m_settings.SetFreeAngleMode( m_freeAngleMode->GetValue() );
|
||||
|
||||
aEvent.Skip(); // ends returning wxID_OK (default behavior)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2004-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2014 Dick Hollenbeck, dick@softplc.com
|
||||
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -1055,7 +1055,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
||||
EscapeHTML( c->condition->GetExpression() ) ) )
|
||||
}
|
||||
|
||||
if( c->condition->EvaluateFor( a, b, aLayer, aReporter ) )
|
||||
if( c->condition->EvaluateFor( a, b, c->constraint.m_Type, aLayer, aReporter ) )
|
||||
{
|
||||
REPORT( implicit ? _( "Constraint applied." )
|
||||
: _( "Rule applied; overrides previous constraints." ) )
|
||||
@@ -1133,6 +1133,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
||||
|
||||
if( localA > global || localB > global )
|
||||
{
|
||||
constraint.SetParentRule( nullptr );
|
||||
constraint.SetName( m_msg );
|
||||
constraint.m_Value.SetMin( clearance );
|
||||
return constraint;
|
||||
|
||||
+26
-2
@@ -309,7 +309,7 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
|
||||
case DRCE_FOOTPRINT_TYPE_MISMATCH: return std::make_shared<DRC_ITEM>( footprintTypeMismatch );
|
||||
case DRCE_PAD_TH_WITH_NO_HOLE: return std::make_shared<DRC_ITEM>( footprintTHPadhasNoHole );
|
||||
default:
|
||||
wxFAIL_MSG( "Unknown DRC error code" );
|
||||
wxFAIL_MSG( wxT( "Unknown DRC error code" ) );
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -328,11 +328,35 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( const wxString& aErrorKey )
|
||||
}
|
||||
|
||||
|
||||
KIID DRC_ITEM::GetAuxItem2ID() const
|
||||
{
|
||||
if( m_errorCode == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG )
|
||||
{
|
||||
// we have lots of segments, but it's enough to show the first P and the first N
|
||||
return niluuid;
|
||||
}
|
||||
|
||||
return m_ids.size() > 2 ? m_ids[2] : niluuid;
|
||||
}
|
||||
|
||||
|
||||
KIID DRC_ITEM::GetAuxItem3ID() const
|
||||
{
|
||||
if( m_errorCode == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG )
|
||||
{
|
||||
// we have lots of segments, but it's enough to show the first P and the first N
|
||||
return niluuid;
|
||||
}
|
||||
|
||||
return m_ids.size() > 3 ? m_ids[3] : niluuid;
|
||||
}
|
||||
|
||||
|
||||
wxString DRC_ITEM::GetViolatingRuleDesc() const
|
||||
{
|
||||
if( m_violatingRule )
|
||||
return wxString::Format( _( "Rule: %s" ), m_violatingRule->m_Name );
|
||||
else
|
||||
return _("Local override" );
|
||||
return _( "Local override" );
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,9 @@ public:
|
||||
void SetViolatingTest( DRC_TEST_PROVIDER *aProvider ) { m_violatingTest = aProvider; }
|
||||
DRC_TEST_PROVIDER* GetViolatingTest() const { return m_violatingTest; }
|
||||
|
||||
KIID GetAuxItem2ID() const override;
|
||||
KIID GetAuxItem3ID() const override;
|
||||
|
||||
private:
|
||||
DRC_ITEM( int aErrorCode = 0, const wxString& aTitle = "", const wxString& aSettingsKey = "" )
|
||||
{
|
||||
|
||||
+31
-2
@@ -310,11 +310,37 @@ public:
|
||||
*/
|
||||
bool QueryColliding( EDA_RECT aBox, SHAPE* aRefShape, PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
SHAPE_POLY_SET* poly = dynamic_cast<SHAPE_POLY_SET*>( aRefShape );
|
||||
|
||||
int min[2] = { aBox.GetX(), aBox.GetY() };
|
||||
int max[2] = { aBox.GetRight(), aBox.GetBottom() };
|
||||
bool collision = false;
|
||||
|
||||
auto visit =
|
||||
// Special case the polygon case. Otherwise we'll call its Collide() method which will
|
||||
// triangulate it as well and then do triangle/triangle collisions. This ends up being
|
||||
// slower than 4 calls to PointInside().
|
||||
auto polyVisitor =
|
||||
[&]( ITEM_WITH_SHAPE* aItem ) -> bool
|
||||
{
|
||||
SHAPE* shape = aItem->shape;
|
||||
wxASSERT( dynamic_cast<SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI*>( shape ) );
|
||||
auto tri = static_cast<SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI*>( shape );
|
||||
|
||||
const SHAPE_LINE_CHAIN& outline = poly->Outline( 0 );
|
||||
|
||||
if( outline.PointInside( tri->GetPoint( 0 ) )
|
||||
|| outline.PointInside( tri->GetPoint( 1 ) )
|
||||
|| outline.PointInside( tri->GetPoint( 2 ) )
|
||||
|| tri->PointInside( outline.CPoint( 0 ) ) )
|
||||
{
|
||||
collision = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto visitor =
|
||||
[&]( ITEM_WITH_SHAPE* aItem ) -> bool
|
||||
{
|
||||
if( aRefShape->Collide( aItem->shape, 0 ) )
|
||||
@@ -326,7 +352,10 @@ public:
|
||||
return true;
|
||||
};
|
||||
|
||||
this->m_tree[aLayer]->Search( min, max, visit );
|
||||
if( poly && poly->OutlineCount() == 1 )
|
||||
this->m_tree[aLayer]->Search( min, max, polyVisitor );
|
||||
else
|
||||
this->m_tree[aLayer]->Search( min, max, visitor );
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2020-2022 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
|
||||
@@ -41,7 +41,7 @@ DRC_RULE_CONDITION::~DRC_RULE_CONDITION()
|
||||
|
||||
|
||||
bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB,
|
||||
PCB_LAYER_ID aLayer, REPORTER* aReporter )
|
||||
int aConstraint, PCB_LAYER_ID aLayer, REPORTER* aReporter )
|
||||
{
|
||||
if( GetExpression().IsEmpty() )
|
||||
return true;
|
||||
@@ -54,7 +54,7 @@ bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM
|
||||
return false;
|
||||
}
|
||||
|
||||
PCB_EXPR_CONTEXT ctx( aLayer );
|
||||
PCB_EXPR_CONTEXT ctx( aConstraint, aLayer );
|
||||
|
||||
if( aReporter )
|
||||
{
|
||||
@@ -109,7 +109,7 @@ bool DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSou
|
||||
|
||||
m_ucode = std::make_unique<PCB_EXPR_UCODE>();
|
||||
|
||||
PCB_EXPR_CONTEXT preflightContext( F_Cu );
|
||||
PCB_EXPR_CONTEXT preflightContext( 0, F_Cu );
|
||||
|
||||
bool ok = compiler.Compile( GetExpression().ToUTF8().data(), m_ucode.get(), &preflightContext );
|
||||
return ok;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2020-2022 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
|
||||
@@ -38,8 +38,8 @@ public:
|
||||
DRC_RULE_CONDITION( const wxString& aExpression = "" );
|
||||
~DRC_RULE_CONDITION();
|
||||
|
||||
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, PCB_LAYER_ID aLayer,
|
||||
REPORTER* aReporter = nullptr );
|
||||
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, int aConstraint,
|
||||
PCB_LAYER_ID aLayer, REPORTER* aReporter = nullptr );
|
||||
|
||||
bool Compile( REPORTER* aReporter, int aSourceLine = 0, int aSourceOffset = 0 );
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020-2021 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2020-2022 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
|
||||
@@ -154,7 +154,7 @@ void DRC_RULES_PARSER::Parse( std::vector<DRC_RULE*>& aRules, REPORTER* aReporte
|
||||
|
||||
default:
|
||||
msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
|
||||
"'rule', 'version'" );
|
||||
wxT( "rule or version" ) );
|
||||
reportError( msg );
|
||||
parseUnknown();
|
||||
}
|
||||
@@ -231,7 +231,7 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
|
||||
|
||||
default:
|
||||
msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
|
||||
"constraint, condition or disallow" );
|
||||
wxT( "constraint, condition, or disallow" ) );
|
||||
reportError( msg );
|
||||
parseUnknown();
|
||||
}
|
||||
@@ -255,9 +255,10 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
||||
if( (int) token == DSN_RIGHT || token == T_EOF )
|
||||
{
|
||||
msg.Printf( _( "Missing constraint type.| Expected %s." ),
|
||||
"clearance, hole_clearance, edge_clearance, hole, hole_to_hole, "
|
||||
"courtyard_clearance, silk_clearance, track_width, annular_width, via_diameter, "
|
||||
"disallow, length, skew, via_count, diff_pair_gap or diff_pair_uncoupled" );
|
||||
wxT( "clearance, hole_clearance, edge_clearance, hole, hole_to_hole, "
|
||||
"courtyard_clearance, silk_clearance, track_width, annular_width, "
|
||||
"via_diameter, disallow, length, skew, via_count, diff_pair_gap, or "
|
||||
"diff_pair_uncoupled" ) );
|
||||
reportError( msg );
|
||||
return;
|
||||
}
|
||||
@@ -283,9 +284,10 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
||||
case T_diff_pair_uncoupled: c.m_Type = DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT; break;
|
||||
default:
|
||||
msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
|
||||
"clearance, hole_clearance, edge_clearance, hole_size, hole_to_hole, "
|
||||
"courtyard_clearance, silk_clearance, track_width, annular_width, via_diameter, "
|
||||
"disallow, length, skew, diff_pair_gap or diff_pair_uncoupled." );
|
||||
wxT( "clearance, hole_clearance, edge_clearance, hole_size, hole_to_hole, "
|
||||
"courtyard_clearance, silk_clearance, track_width, annular_width, "
|
||||
"via_diameter, disallow, length, skew, diff_pair_gap, or "
|
||||
"diff_pair_uncoupled" ) );
|
||||
reportError( msg );
|
||||
}
|
||||
|
||||
@@ -321,8 +323,8 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
||||
|
||||
default:
|
||||
msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
|
||||
"track, via, micro_via, buried_via, pad, zone, text, graphic, hole "
|
||||
"or footprint." );
|
||||
wxT( "track, via, micro_via, buried_via, pad, zone, text, graphic, "
|
||||
"hole, or footprint." ) );
|
||||
reportError( msg );
|
||||
break;
|
||||
}
|
||||
@@ -411,7 +413,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
||||
default:
|
||||
msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ),
|
||||
FromUTF8(),
|
||||
"min, max or opt" );
|
||||
wxT( "min, max, or opt" ) );
|
||||
reportError( msg );
|
||||
parseUnknown();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user