Compare commits
276 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 567c5bc8db | |||
| 1fdf7d0cf4 | |||
| 5ffe28eec2 | |||
| 4e855b4cb0 | |||
| ae886c824c | |||
| 46b5442214 | |||
| c3deafd271 | |||
| de2da52941 | |||
| 8aa3d183ef | |||
| 6623b19b70 | |||
| 7a40b6e484 | |||
| d63dc32e71 | |||
| 54aa3bc5d4 | |||
| 6ebd616049 | |||
| c0439feef8 | |||
| 0e550322db | |||
| 7398d47728 | |||
| 9f0f7e8641 | |||
| f26e36440d | |||
| 8ff0aca6b4 | |||
| d4b564ee7a | |||
| 22a6bf999f | |||
| 09bae9bb14 | |||
| 874f7fbdff | |||
| 6d17d7d7a1 | |||
| 98dc21360a | |||
| 0d330051ed | |||
| f17c4cceac | |||
| a3072ffade | |||
| f60c544478 | |||
| fc320e0ab4 | |||
| 91c861e8d6 | |||
| 2640f4ad41 | |||
| 06f5828990 | |||
| 85604e1707 | |||
| ad7bc215d0 | |||
| f005676c90 | |||
| 17961165cf | |||
| 6ba2230804 | |||
| cacfaac52e | |||
| 4f09e18894 | |||
| 05f1912d19 | |||
| e15306464f | |||
| 28f75d5ad3 | |||
| 3021764401 | |||
| 2766e90fe0 | |||
| 10d5baa862 | |||
| 28a8997603 | |||
| 83d4771e6b | |||
| 0f4cd449b9 | |||
| 27843728d7 | |||
| 676ad491fe | |||
| 9a91537968 | |||
| 3eba0d9bab | |||
| b4995aa711 | |||
| 55353536e5 | |||
| e3d45fb37b | |||
| e3369608fd | |||
| 1c6390f829 | |||
| df64a6c583 | |||
| 59c638c64c | |||
| 9850541433 | |||
| 5140fd7819 | |||
| 5ae1b271e7 | |||
| c5cdff6213 | |||
| e05b3955a5 | |||
| e1c0bddff3 | |||
| 62297e63a2 | |||
| 54c325a631 | |||
| af99c9da34 | |||
| dbf5455656 | |||
| 4cb9edd9f0 | |||
| 60d23b14e7 | |||
| 12fdeac31c | |||
| 69a1a4611b | |||
| a46501b279 | |||
| bc1953dded | |||
| 789a695737 | |||
| 5f8a0b0728 | |||
| 9fdda223f5 | |||
| 1ff4b2b4eb | |||
| 0751a3ae7f | |||
| e6e08c111b | |||
| 004b96ec21 | |||
| 7cb98f6856 | |||
| fc86de34f8 | |||
| fe69da4cb8 | |||
| 27434e38f9 | |||
| 60ddafa4ff | |||
| ef8b6bf9e1 | |||
| 59cc7b2d3e | |||
| 6245bbff50 | |||
| 6331a0ab7a | |||
| c43ae314e0 | |||
| 250720ca4a | |||
| a5ac1fc34f | |||
| 1740aeca5e | |||
| 4f060d9384 | |||
| acd244f873 | |||
| dfef20658c | |||
| 8255e091f0 | |||
| 96037591c5 | |||
| 692949fd0a | |||
| 4bf75de6fd | |||
| 05890480e2 | |||
| 70d7bc2099 | |||
| e2d8d53a10 | |||
| 402c139957 | |||
| 31e79ef54f | |||
| 39788e7e6c | |||
| 932c908075 | |||
| 443da9943a | |||
| cc1071fe7a | |||
| 3ac4fd59c5 | |||
| 5e93814283 | |||
| d29c07a663 | |||
| a558a67fbd | |||
| 153e1190ea | |||
| a80a641427 | |||
| acd7d5ad2f | |||
| 81ba4fa9a6 | |||
| 57f007c46e | |||
| d513640572 | |||
| 8c695e5044 | |||
| 395a966802 | |||
| 643894c882 | |||
| c7c28c0471 | |||
| 20ada81d43 | |||
| 07736e59bd | |||
| 3195ba646f | |||
| 2deee01592 | |||
| 890b09499e | |||
| 01c5fab84b | |||
| e9b7737692 | |||
| fe1072a06b | |||
| 59f308850e | |||
| e775a7581a | |||
| ec99e10b31 | |||
| 240d7921ba | |||
| 9ac006b114 | |||
| c3fef1cae2 | |||
| ca1c99a0d1 | |||
| 06ae7a20df | |||
| f536ecdc00 | |||
| a4bdd38367 | |||
| 6fb6d3e444 | |||
| a3952c37bf | |||
| c24ee72fe3 | |||
| f988b807c4 | |||
| cb1a596b10 | |||
| c41cd75b62 | |||
| 0df48f3002 | |||
| 2d58184080 | |||
| 1ef6e69d83 | |||
| dbd4af16c6 | |||
| 2263535d3a | |||
| 3ce4a5bf7f | |||
| f62c3431ff | |||
| a652084922 | |||
| ed30599db8 | |||
| d8752970e9 | |||
| 57a4c93cf5 | |||
| a116f5783d | |||
| 2730098c42 | |||
| 836d17359f | |||
| a4406bb137 | |||
| bbb67b415a | |||
| 0842360dbb | |||
| e58b23a54b | |||
| 72342bd8a5 | |||
| fa77fc3310 | |||
| 53fe2a7203 | |||
| 480dfafb4f | |||
| f5e13c5ceb | |||
| eadc902f84 | |||
| b461a3b64d | |||
| 75c758e5f4 | |||
| 05912b0381 | |||
| fb387a2c09 | |||
| 1380feef72 | |||
| 6c91a3022e | |||
| e55989120e | |||
| 14f12ccf51 | |||
| 82a1b02b4a | |||
| e99a2fbc56 | |||
| d3d23d18fb | |||
| cbf1b2af47 | |||
| 4f5fca4e67 | |||
| e0158a8ed7 | |||
| 40e7ba67d1 | |||
| e664605c90 | |||
| 5a51a6b179 | |||
| eb7929ccb6 | |||
| e85eec2e6b | |||
| 121394c0c0 | |||
| 5ad74d58f8 | |||
| afe2516d57 | |||
| ccf6e78cd5 | |||
| fef91fc8b9 | |||
| 4156587abe | |||
| 629eccaf09 | |||
| f89803eb64 | |||
| da12746a3a | |||
| b023019b0d | |||
| 1fdaa1083e | |||
| 2f8e846b9e | |||
| e42db52d14 | |||
| d4ec455ce0 | |||
| 0547c7ba91 | |||
| 8f4b809599 | |||
| 8432fb4fea | |||
| 84df2c86ae | |||
| 49ced23ba8 | |||
| 00bf2ca36f | |||
| b92861c7e3 | |||
| a189102628 | |||
| 58a6eb653b | |||
| 9159f5a004 | |||
| f1c570d793 | |||
| 832af39f34 | |||
| 9260f58803 | |||
| 1a5c515e45 | |||
| 87c8688f70 | |||
| d13179f9e4 | |||
| 75de21314c | |||
| 239f8e0905 | |||
| f4ac624bb3 | |||
| 2be0b98135 | |||
| 36c5719535 | |||
| 1f870bf76c | |||
| d5cc334e20 | |||
| fd98188ee4 | |||
| c3446f9c2d | |||
| e6e29b6c4c | |||
| 6096b5c4d8 | |||
| 838eadd47f | |||
| afb43531e8 | |||
| 3533e8b119 | |||
| 0e6ad13db8 | |||
| 0d725fcc2c | |||
| 7e747085d3 | |||
| f1376396c2 | |||
| 4eb9281f4d | |||
| c895816cb0 | |||
| 9f814c0f6a | |||
| e14aef9bd5 | |||
| 2b106a2b34 | |||
| f6494d2980 | |||
| 78a6c1a909 | |||
| c858643100 | |||
| 17b0bdc9fe | |||
| 2e0cdebb0c | |||
| a5f8955d78 | |||
| 0eca698a39 | |||
| 16f259da81 | |||
| c3ee477a1b | |||
| 33da35db04 | |||
| 533be1ec70 | |||
| b64573f5d4 | |||
| 1d6caa9a35 | |||
| c74b0943f3 | |||
| bb579294a0 | |||
| ad9f5f4dd7 | |||
| bf2e34f32e | |||
| bd57957df7 | |||
| 093db600ff | |||
| 131013f291 | |||
| 909d199379 | |||
| 5f16f4ab99 | |||
| fff95fa4e6 | |||
| a38327a39c | |||
| 686048dcce | |||
| 330c0f86de | |||
| 83317f1b80 | |||
| a416eb2cf6 | |||
| 2959c94bd3 |
@@ -49,6 +49,7 @@
|
||||
#include <dialogs/dialog_color_picker.h>
|
||||
|
||||
class COLOR_SETTINGS;
|
||||
class PCB_TEXTBOX;
|
||||
|
||||
/// A type that stores a container of 2d objects for each layer id
|
||||
typedef std::map<PCB_LAYER_ID, BVH_CONTAINER_2D*> MAP_CONTAINER_2D_BASE;
|
||||
@@ -356,6 +357,9 @@ private:
|
||||
void addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aDstContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId );
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <pcb_painter.h> // for PCB_RENDER_SETTINGS
|
||||
#include <zone.h>
|
||||
#include <fp_text.h>
|
||||
#include <pcb_textbox.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <trigo.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
@@ -720,6 +721,11 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
|
||||
aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
|
||||
ERROR_INSIDE );
|
||||
|
||||
// Some polygons can be a bit complex (especially when coming from a
|
||||
// picture ot a text converted to a polygon
|
||||
// So call Simplify before calling ConvertPolygonToTriangles, just in case.
|
||||
polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
if( polyList.IsEmpty() ) // Just for caution
|
||||
break;
|
||||
|
||||
@@ -767,6 +773,32 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
addText( aTextBox, aContainer, aOwner );
|
||||
|
||||
if( !aTextBox->IsBorderEnabled() )
|
||||
return;
|
||||
|
||||
// We cannot use PCB_TEXTBOX::TransformShapeToPolygon because it convert the textbox
|
||||
// as filled polygon even if there's no background colour.
|
||||
// So for polygon, we use PCB_SHAPE::TransformShapeToPolygon
|
||||
|
||||
if( aTextBox->GetShape() == SHAPE_T::RECT )
|
||||
addShape( static_cast<const PCB_SHAPE*>( aTextBox ), aContainer, aOwner );
|
||||
else
|
||||
{
|
||||
SHAPE_POLY_SET polyList;
|
||||
|
||||
aTextBox->PCB_SHAPE::TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0,
|
||||
ARC_HIGH_DEF, ERROR_INSIDE );
|
||||
|
||||
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId )
|
||||
{
|
||||
@@ -792,7 +824,7 @@ void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BAS
|
||||
}
|
||||
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
|
||||
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
|
||||
|
||||
for( int j = 0; j < path.PointCount(); j++ )
|
||||
|
||||
@@ -604,9 +604,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
break;
|
||||
|
||||
case PCB_TEXTBOX_T:
|
||||
addText( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
if( static_cast<PCB_TEXTBOX*>( item )->IsBorderEnabled() )
|
||||
addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
break;
|
||||
|
||||
case PCB_DIM_ALIGNED_T:
|
||||
@@ -924,7 +922,6 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
break;
|
||||
|
||||
case PCB_TEXTBOX_T:
|
||||
addText( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
break;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ void BOARD_ADAPTER::buildPadOutlineAsPolygon( const PAD* aPad, SHAPE_POLY_SET& a
|
||||
}
|
||||
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
|
||||
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
|
||||
|
||||
for( int ii = 0; ii < path.PointCount(); ++ii )
|
||||
|
||||
@@ -637,6 +637,9 @@ void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
|
||||
|
||||
void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent& event )
|
||||
{
|
||||
if( m_3d_render && m_3d_render->IsReloadRequestPending() )
|
||||
return; // Prevents using invalid m_3d_render_raytracing data
|
||||
|
||||
if( m_camera_is_moving )
|
||||
return;
|
||||
|
||||
|
||||
@@ -483,23 +483,21 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||
|
||||
// Sort from back to front
|
||||
std::sort( materialsSorted.begin(), materialsSorted.end(),
|
||||
[&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
|
||||
std::pair<const MODEL_3D::MATERIAL*, float>& b ) {
|
||||
// If A is inside B, then A is rendered first
|
||||
if( b.first->m_bbox.Inside( a.first->m_bbox ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( a.first->m_bbox.Inside( b.first->m_bbox ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
[&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
|
||||
std::pair<const MODEL_3D::MATERIAL*, float>& b )
|
||||
{
|
||||
bool aInsideB = a.first->m_bbox.Inside( b.first->m_bbox );
|
||||
bool bInsideA = b.first->m_bbox.Inside( a.first->m_bbox );
|
||||
|
||||
return a.second > b.second;
|
||||
} );
|
||||
// If A is inside B, then A is rendered first
|
||||
if( aInsideB != bInsideA )
|
||||
return bInsideA;
|
||||
|
||||
if( a.second != b.second )
|
||||
return a.second > b.second;
|
||||
|
||||
return a.first > b.first; // compare pointers as a last resort
|
||||
} );
|
||||
|
||||
for( const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
|
||||
{
|
||||
|
||||
@@ -1388,10 +1388,14 @@ void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatr
|
||||
|
||||
// Sort from back to front
|
||||
std::sort( transparentModelList.begin(), transparentModelList.end(),
|
||||
[&]( std::pair<const MODELTORENDER *, float>& a,
|
||||
std::pair<const MODELTORENDER *, float>& b ) {
|
||||
return a.second > b.second;
|
||||
} );
|
||||
[&]( std::pair<const MODELTORENDER *, float>& a,
|
||||
std::pair<const MODELTORENDER *, float>& b )
|
||||
{
|
||||
if( a.second != b.second )
|
||||
return a.second > b.second;
|
||||
|
||||
return a.first > b.first; // use pointers as a last resort
|
||||
} );
|
||||
|
||||
// Start rendering calls
|
||||
glPushMatrix();
|
||||
|
||||
@@ -1911,9 +1911,19 @@ void RENDER_3D_RAYTRACE::initializeBlockPositions()
|
||||
|
||||
const SFVEC2UI center( m_realBufferSize.x / 2, m_realBufferSize.y / 2 );
|
||||
std::sort( m_blockPositions.begin(), m_blockPositions.end(),
|
||||
[&]( const SFVEC2UI& a, const SFVEC2UI& b ) {
|
||||
[&]( const SFVEC2UI& a, const SFVEC2UI& b )
|
||||
{
|
||||
// Sort order: inside out.
|
||||
return distance( a, center ) < distance( b, center );
|
||||
float distanceA = distance( a, center );
|
||||
float distanceB = distance( b, center );
|
||||
|
||||
if( distanceA != distanceB )
|
||||
return distanceA < distanceB;
|
||||
|
||||
if( a[0] != b[0] )
|
||||
return a[0] < b[0];
|
||||
|
||||
return a[1] < b[1];
|
||||
} );
|
||||
|
||||
// Create m_shader buffer
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# KiCad.
|
||||
#
|
||||
# Note: This version string should follow the semantic versioning system
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.8" )
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.10" )
|
||||
|
||||
# Default the version to the semantic version.
|
||||
# This is overridden by the git repository tag though (if using git)
|
||||
|
||||
@@ -83,6 +83,8 @@
|
||||
/// Allows scripts install directory to be referenced by the program code.
|
||||
#define PYTHON_DEST "@PYTHON_DEST@"
|
||||
|
||||
#define PYTHON_SITE_PACKAGE_PATH "@PYTHON_SITE_PACKAGE_PATH@"
|
||||
|
||||
/// Allows scripts install directory to be referenced by the program code.
|
||||
#define KICAD_DATA "@KICAD_DATA@"
|
||||
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ long KIDIALOG::getStyle( KD_TYPE aType )
|
||||
}
|
||||
|
||||
|
||||
bool OverrideLock( wxWindow* aParent, const wxString& aMessage )
|
||||
bool AskOverrideLock( wxWindow* aParent, const wxString& aMessage )
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// wxMessageDialog gets the button spacing wrong on Mac so we have to use wxRichMessageDialog.
|
||||
|
||||
@@ -435,7 +435,31 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
|
||||
for( short i = 0; i < results.columns(); ++i )
|
||||
{
|
||||
std::string column = toUTF8( results.column_name( i ) );
|
||||
aResult[ column ] = toUTF8( results.get<nanodbc::string>( i, NANODBC_TEXT( "" ) ) );
|
||||
|
||||
switch( results.column_datatype( i ) )
|
||||
{
|
||||
case SQL_DOUBLE:
|
||||
case SQL_FLOAT:
|
||||
case SQL_REAL:
|
||||
case SQL_DECIMAL:
|
||||
case SQL_NUMERIC:
|
||||
{
|
||||
try
|
||||
{
|
||||
aResult[column] = fmt::format( "{:G}", results.get<double>( i ) );
|
||||
}
|
||||
catch( nanodbc::null_access_error& e )
|
||||
{
|
||||
// Column was empty (null)
|
||||
aResult[column] = std::string();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
aResult[column] = toUTF8( results.get<nanodbc::string>( i, NANODBC_TEXT( "" ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( nanodbc::database_error& e )
|
||||
@@ -525,27 +549,92 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
|
||||
|
||||
timer.Stop();
|
||||
|
||||
try
|
||||
{
|
||||
while( results.next() )
|
||||
{
|
||||
ROW result;
|
||||
|
||||
for( short j = 0; j < results.columns(); ++j )
|
||||
auto handleException =
|
||||
[&]( std::runtime_error& aException, const std::string& aExtraContext = "" )
|
||||
{
|
||||
std::string column = toUTF8( results.column_name( j ) );
|
||||
result[column] = toUTF8( results.get<nanodbc::string>( j, NANODBC_TEXT( "" ) ) );
|
||||
m_lastError = aException.what();
|
||||
std::string extra = aExtraContext.empty() ? "" : ": " + aExtraContext;
|
||||
wxLogTrace( traceDatabase,
|
||||
wxT( "Exception while parsing result %d from SelectAll: %s%s" ),
|
||||
aResults.size(), m_lastError, extra );
|
||||
};
|
||||
|
||||
while( results.next() )
|
||||
{
|
||||
short columnCount = 0;
|
||||
ROW result;
|
||||
|
||||
try
|
||||
{
|
||||
columnCount = results.columns();
|
||||
}
|
||||
catch( nanodbc::database_error& e )
|
||||
{
|
||||
handleException( e );
|
||||
return false;
|
||||
}
|
||||
|
||||
for( short j = 0; j < columnCount; ++j )
|
||||
{
|
||||
std::string column;
|
||||
std::string columnExtraDbgInfo;
|
||||
int datatype = SQL_UNKNOWN_TYPE;
|
||||
|
||||
try
|
||||
{
|
||||
column = toUTF8( results.column_name( j ) );
|
||||
datatype = results.column_datatype( j );
|
||||
columnExtraDbgInfo = fmt::format( "column index {}, name '{}', type {}", j, column,
|
||||
datatype );
|
||||
}
|
||||
catch( nanodbc::index_range_error& e )
|
||||
{
|
||||
handleException( e, columnExtraDbgInfo );
|
||||
return false;
|
||||
}
|
||||
|
||||
aResults.emplace_back( std::move( result ) );
|
||||
switch( datatype )
|
||||
{
|
||||
case SQL_DOUBLE:
|
||||
case SQL_FLOAT:
|
||||
case SQL_REAL:
|
||||
case SQL_DECIMAL:
|
||||
case SQL_NUMERIC:
|
||||
{
|
||||
try
|
||||
{
|
||||
result[column] = fmt::format( "{:G}", results.get<double>( j ) );
|
||||
}
|
||||
catch( nanodbc::null_access_error& e )
|
||||
{
|
||||
// Column was empty (null)
|
||||
result[column] = std::string();
|
||||
}
|
||||
catch( std::runtime_error& e )
|
||||
{
|
||||
handleException( e, columnExtraDbgInfo );
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
try
|
||||
{
|
||||
result[column] = toUTF8( results.get<nanodbc::string>( j,
|
||||
NANODBC_TEXT( "" ) ) );
|
||||
}
|
||||
catch( std::runtime_error& e )
|
||||
{
|
||||
handleException( e, columnExtraDbgInfo );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( nanodbc::database_error& e )
|
||||
{
|
||||
m_lastError = e.what();
|
||||
wxLogTrace( traceDatabase, wxT( "Exception while parsing results from SelectAll: %s" ),
|
||||
m_lastError );
|
||||
return false;
|
||||
|
||||
aResults.emplace_back( std::move( result ) );
|
||||
}
|
||||
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll from %s completed in %0.1f ms" ), aTable,
|
||||
|
||||
+44
-1
@@ -133,12 +133,41 @@ DIALOG_SHIM::DIALOG_SHIM( wxWindow* aParent, wxWindowID id, const wxString& titl
|
||||
Pgm().App().SetTopWindow( (EDA_BASE_FRAME*) kiwayHolder );
|
||||
#endif
|
||||
|
||||
Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_SHIM::OnPaint ) );
|
||||
Bind( wxEVT_PAINT, &DIALOG_SHIM::OnPaint, this );
|
||||
}
|
||||
|
||||
|
||||
DIALOG_SHIM::~DIALOG_SHIM()
|
||||
{
|
||||
Unbind( wxEVT_CLOSE_WINDOW, &DIALOG_SHIM::OnCloseWindow, this );
|
||||
Unbind( wxEVT_BUTTON, &DIALOG_SHIM::OnButton, this );
|
||||
Unbind( wxEVT_PAINT, &DIALOG_SHIM::OnPaint, this );
|
||||
|
||||
std::function<void( wxWindowList& )> disconnectFocusHandlers = [&]( wxWindowList& children )
|
||||
{
|
||||
for( wxWindow* child : children )
|
||||
{
|
||||
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
|
||||
{
|
||||
textCtrl->Disconnect( wxEVT_SET_FOCUS,
|
||||
wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ), nullptr,
|
||||
this );
|
||||
}
|
||||
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
|
||||
{
|
||||
scintilla->Disconnect( wxEVT_SET_FOCUS,
|
||||
wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ), nullptr,
|
||||
this );
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnectFocusHandlers( child->GetChildren() );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
disconnectFocusHandlers( GetChildren() );
|
||||
|
||||
// if the dialog is quasi-modal, this will end its event loop
|
||||
if( IsQuasiModal() )
|
||||
EndQuasiModal( wxID_CANCEL );
|
||||
@@ -259,6 +288,14 @@ bool DIALOG_SHIM::Show( bool show )
|
||||
std::max( wxDialog::GetSize().y, savedDialogRect.GetSize().y ),
|
||||
0 );
|
||||
}
|
||||
#ifdef __WXMAC__
|
||||
if( m_parent != nullptr )
|
||||
{
|
||||
if( wxDisplay::GetFromPoint( m_parent->GetPosition() )
|
||||
!= wxDisplay::GetFromPoint( savedDialogRect.GetPosition() ) )
|
||||
Centre();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if( m_initialSize != wxDefaultSize )
|
||||
SetSize( m_initialSize );
|
||||
@@ -282,6 +319,9 @@ bool DIALOG_SHIM::Show( bool show )
|
||||
ret = wxDialog::Show( show );
|
||||
}
|
||||
|
||||
if( m_parent )
|
||||
m_parent->SetFocus();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -483,6 +523,9 @@ int DIALOG_SHIM::ShowQuasiModal()
|
||||
|
||||
m_qmodal_showing = false;
|
||||
|
||||
if( parent )
|
||||
parent->SetFocus();
|
||||
|
||||
return GetReturnCode();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ static PASTE_MODE g_paste_mode = PASTE_MODE::UNIQUE_ANNOTATIONS;
|
||||
|
||||
DIALOG_PASTE_SPECIAL::DIALOG_PASTE_SPECIAL( wxWindow* aParent,
|
||||
PASTE_MODE* aMode,
|
||||
wxString aReplacement ) :
|
||||
const wxString& aReplacement ) :
|
||||
DIALOG_PASTE_SPECIAL_BASE( aParent ),
|
||||
m_mode( aMode )
|
||||
{
|
||||
@@ -45,7 +45,7 @@ DIALOG_PASTE_SPECIAL::DIALOG_PASTE_SPECIAL( wxWindow* aParent,
|
||||
"with '%s'." ),
|
||||
aReplacement ) );
|
||||
|
||||
m_sdbSizerOK->SetFocus();
|
||||
m_pasteOptions->SetFocus();
|
||||
|
||||
// Now all widgets have the size fixed, call FinishDialogSettings
|
||||
finishDialogSettings();
|
||||
@@ -64,3 +64,11 @@ bool DIALOG_PASTE_SPECIAL::TransferDataFromWindow()
|
||||
g_paste_mode = *m_mode = static_cast<PASTE_MODE>( m_pasteOptions->GetSelection() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PASTE_SPECIAL::onRadioBoxEvent( wxCommandEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
m_sdbSizerOK->SetFocus();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
@@ -45,12 +45,12 @@ DIALOG_PASTE_SPECIAL_BASE::DIALOG_PASTE_SPECIAL_BASE( wxWindow* parent, wxWindow
|
||||
this->Centre( wxBOTH );
|
||||
|
||||
// Connect Events
|
||||
m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PASTE_SPECIAL_BASE::onOKButton ), NULL, this );
|
||||
m_pasteOptions->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_PASTE_SPECIAL_BASE::onRadioBoxEvent ), NULL, this );
|
||||
}
|
||||
|
||||
DIALOG_PASTE_SPECIAL_BASE::~DIALOG_PASTE_SPECIAL_BASE()
|
||||
{
|
||||
// Disconnect Events
|
||||
m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PASTE_SPECIAL_BASE::onOKButton ), NULL, this );
|
||||
m_pasteOptions->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_PASTE_SPECIAL_BASE::onRadioBoxEvent ), NULL, this );
|
||||
|
||||
}
|
||||
|
||||
@@ -1,163 +1,165 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="16" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file">dialog_paste_special_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="image_path_wrapper_function_name"></property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">dialog_paste_special</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_array_enum">0</property>
|
||||
<property name="use_enum">0</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Dialog" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="center">wxBOTH</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="extra_style"></property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size">-1,-1</property>
|
||||
<property name="name">DIALOG_PASTE_SPECIAL_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">-1,-1</property>
|
||||
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
|
||||
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
|
||||
<property name="title">Paste Special</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<FileVersion major="1" minor="17"/>
|
||||
<object class="Project" expanded="true">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file">dialog_paste_special_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="image_path_wrapper_function_name"></property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">dialog_paste_special</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_array_enum">0</property>
|
||||
<property name="use_enum">0</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Dialog" expanded="true">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="center">wxBOTH</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="extra_style"></property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size">-1,-1</property>
|
||||
<property name="name">DIALOG_PASTE_SPECIAL_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">-1,-1</property>
|
||||
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
|
||||
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
|
||||
<property name="title">Paste Special</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<object class="wxBoxSizer" expanded="true">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_mainSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">10</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="true">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">optionsSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxRadioBox" expanded="true">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="choices">"Assign unique reference designators to pasted symbols" "Keep existing reference designators, even if they are duplicated" "Clear reference designators on all pasted symbols"</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Paste Options</property>
|
||||
<property name="majorDimension">1</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_mainSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">10</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">optionsSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxRadioBox" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="choices">"Assign unique reference designators to pasted symbols" "Keep existing reference designators, even if they are duplicated" "Clear reference designators on all pasted symbols"</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Paste Options</property>
|
||||
<property name="majorDimension">1</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_pasteOptions</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="selection">1</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxRA_SPECIFY_COLS</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">6</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStdDialogButtonSizer" expanded="1">
|
||||
<property name="Apply">0</property>
|
||||
<property name="Cancel">1</property>
|
||||
<property name="ContextHelp">0</property>
|
||||
<property name="Help">0</property>
|
||||
<property name="No">0</property>
|
||||
<property name="OK">1</property>
|
||||
<property name="Save">0</property>
|
||||
<property name="Yes">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_sdbSizer</property>
|
||||
<property name="permission">protected</property>
|
||||
<event name="OnOKButtonClick">onOKButton</event>
|
||||
</object>
|
||||
</object>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_pasteOptions</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="selection">1</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxRA_SPECIFY_COLS</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnRadioBox">onRadioBoxEvent</event>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">6</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStdDialogButtonSizer" expanded="true">
|
||||
<property name="Apply">0</property>
|
||||
<property name="Cancel">1</property>
|
||||
<property name="ContextHelp">0</property>
|
||||
<property name="Help">0</property>
|
||||
<property name="No">0</property>
|
||||
<property name="OK">1</property>
|
||||
<property name="Save">0</property>
|
||||
<property name="Yes">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_sdbSizer</property>
|
||||
<property name="permission">protected</property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
@@ -38,7 +38,7 @@ class DIALOG_PASTE_SPECIAL_BASE : public DIALOG_SHIM
|
||||
wxButton* m_sdbSizerCancel;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
virtual void onOKButton( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onRadioBoxEvent( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
@@ -356,5 +356,6 @@ void KIGFX::DS_PAINTER::DrawBorder( const PAGE_INFO* aPageInfo, int aScaleFactor
|
||||
// Use a gray color for the border color
|
||||
m_gal->SetStrokeColor( m_renderSettings.m_pageBorderColor );
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetLineWidth( m_renderSettings.GetDefaultPenWidth() );
|
||||
m_gal->DrawRectangle( origin, end );
|
||||
}
|
||||
|
||||
@@ -106,14 +106,22 @@ void DS_PROXY_VIEW_ITEM::ViewDraw( int aLayer, VIEW* aView ) const
|
||||
|
||||
buildDrawList( aView, m_properties, &drawList );
|
||||
|
||||
BOX2I viewport( aView->GetViewport().GetOrigin(), aView->GetViewport().GetSize() );
|
||||
|
||||
// Draw the title block normally even if the view is flipped
|
||||
bool flipped = gal->IsFlippedX();
|
||||
|
||||
if( flipped )
|
||||
{
|
||||
int pageWidth = m_pageInfo->GetWidthMils() * m_mils2IUscalefactor;
|
||||
|
||||
gal->Save();
|
||||
gal->Translate( VECTOR2D( m_pageInfo->GetWidthMils() * m_mils2IUscalefactor, 0 ) );
|
||||
gal->Translate( VECTOR2D( pageWidth, 0 ) );
|
||||
gal->Scale( VECTOR2D( -1.0, 1.0 ) );
|
||||
|
||||
int right = pageWidth - viewport.GetLeft();
|
||||
int left = right - viewport.GetWidth();
|
||||
viewport.SetOrigin( left, viewport.GetTop() );
|
||||
}
|
||||
|
||||
DS_PAINTER ws_painter( gal );
|
||||
@@ -126,8 +134,6 @@ void DS_PROXY_VIEW_ITEM::ViewDraw( int aLayer, VIEW* aView ) const
|
||||
ws_settings->SetDefaultFont( settings->GetDefaultFont() );
|
||||
|
||||
// Draw all the components that make the drawing sheet
|
||||
BOX2I viewport( aView->GetViewport().GetOrigin(), aView->GetViewport().GetSize() );
|
||||
|
||||
for( DS_DRAW_ITEM_BASE* item = drawList.GetFirst(); item; item = drawList.GetNext() )
|
||||
{
|
||||
if( viewport.Intersects( item->GetApproxBBox() ) )
|
||||
|
||||
@@ -230,6 +230,15 @@ bool EDA_DRAW_FRAME::LockFile( const wxString& aFileName )
|
||||
|
||||
m_file_checker = std::make_unique<LOCKFILE>( aFileName );
|
||||
|
||||
if( !m_file_checker->Valid() && m_file_checker->IsLockedByMe() )
|
||||
{
|
||||
// If we cannot acquire the lock but we appear to be the one who
|
||||
// locked it, check to see if there is another KiCad instance running.
|
||||
// If there is not, then we can override the lock. This could happen if
|
||||
// KiCad crashed or was interrupted
|
||||
if( !Pgm().SingleInstance()->IsAnotherRunning() )
|
||||
m_file_checker->OverrideLock();
|
||||
}
|
||||
// If the file is valid, return true. This could mean that the file is
|
||||
// locked or it could mean that the file is read-only
|
||||
return m_file_checker->Valid();
|
||||
|
||||
+10
-6
@@ -881,7 +881,8 @@ void EDA_TEXT::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControl
|
||||
|
||||
|
||||
std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangulate,
|
||||
bool aUseTextRotation ) const
|
||||
const BOX2I& aBBox,
|
||||
const EDA_ANGLE& aAngle ) const
|
||||
{
|
||||
std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
@@ -893,17 +894,20 @@ std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangula
|
||||
|
||||
std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
|
||||
|
||||
if( aUseTextRotation )
|
||||
if( aBBox.GetWidth() )
|
||||
{
|
||||
drawPos = aBBox.GetCenter();
|
||||
attrs.m_Halign = GR_TEXT_H_ALIGN_CENTER;
|
||||
attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER;
|
||||
attrs.m_Angle = aAngle;
|
||||
}
|
||||
else
|
||||
{
|
||||
attrs.m_Angle = GetDrawRotation();
|
||||
|
||||
if( font->IsOutline() )
|
||||
cache = GetRenderCache( font, shownText, VECTOR2I() );
|
||||
}
|
||||
else
|
||||
{
|
||||
attrs.m_Angle = ANGLE_0;
|
||||
}
|
||||
|
||||
if( aTriangulate )
|
||||
{
|
||||
|
||||
@@ -253,11 +253,6 @@ wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName, const wxStri
|
||||
// first attempt to use the name as specified:
|
||||
wxString tname = aFileName;
|
||||
|
||||
#ifdef _WIN32
|
||||
// translate from KiCad's internal UNIX-like path to MSWin paths
|
||||
tname.Replace( wxT( "/" ), wxT( "\\" ) );
|
||||
#endif
|
||||
|
||||
// Note: variable expansion must preferably be performed via a threadsafe wrapper for the
|
||||
// getenv() system call. If we allow the wxFileName::Normalize() routine to perform expansion
|
||||
// then we will have a race condition since wxWidgets does not assure a threadsafe wrapper
|
||||
|
||||
@@ -349,14 +349,14 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox,
|
||||
hb_buffer_guess_segment_properties( buf ); // guess direction, script, and language based on
|
||||
// contents
|
||||
|
||||
unsigned int glyphCount;
|
||||
hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
|
||||
hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
|
||||
|
||||
hb_font_t* referencedFont = hb_ft_font_create_referenced( face );
|
||||
hb_ft_font_set_funcs( referencedFont );
|
||||
hb_shape( referencedFont, buf, nullptr, 0 );
|
||||
|
||||
unsigned int glyphCount;
|
||||
hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
|
||||
hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
|
||||
|
||||
VECTOR2D scaleFactor( glyphSize.x / faceSize(), -glyphSize.y / faceSize() );
|
||||
scaleFactor = scaleFactor * m_outlineFontSizeCompensation;
|
||||
|
||||
|
||||
@@ -94,9 +94,10 @@ public:
|
||||
private:
|
||||
struct CACHED_BITMAP
|
||||
{
|
||||
GLuint id;
|
||||
int w, h;
|
||||
size_t size;
|
||||
GLuint id;
|
||||
int w, h;
|
||||
size_t size;
|
||||
long long int accessTime;
|
||||
};
|
||||
|
||||
GLuint cacheBitmap( const BITMAP_BASE* aBitmap );
|
||||
@@ -105,9 +106,9 @@ private:
|
||||
const size_t m_cacheMaxSize = 256 * 1024 * 1024;
|
||||
|
||||
std::map<const KIID, CACHED_BITMAP> m_bitmaps;
|
||||
std::list<KIID> m_cacheLru;
|
||||
size_t m_cacheSize;
|
||||
std::list<GLuint> m_freedTextureIds;
|
||||
std::list<KIID> m_cacheLru;
|
||||
size_t m_cacheSize;
|
||||
std::list<GLuint> m_freedTextureIds;
|
||||
};
|
||||
|
||||
}; // namespace KIGFX
|
||||
@@ -130,6 +131,7 @@ GLuint GL_BITMAP_CACHE::RequestBitmap( const BITMAP_BASE* aBitmap )
|
||||
// A bitmap is found in cache bitmap. Ensure the associated texture is still valid.
|
||||
if( glIsTexture( it->second.id ) )
|
||||
{
|
||||
it->second.accessTime = wxGetUTCTimeMillis().GetValue();
|
||||
return it->second.id;
|
||||
}
|
||||
else
|
||||
@@ -182,56 +184,115 @@ GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
|
||||
m_freedTextureIds.pop_front();
|
||||
}
|
||||
|
||||
bmp.size = bmp.w * bmp.h * 4;
|
||||
auto buf = std::make_unique<uint8_t[]>( bmp.size );
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
|
||||
for( int y = 0; y < bmp.h; y++ )
|
||||
if( imgData.HasAlpha() || imgData.HasMask() )
|
||||
{
|
||||
for( int x = 0; x < bmp.w; x++ )
|
||||
bmp.size = bmp.w * bmp.h * 4;
|
||||
auto buf = std::make_unique<uint8_t[]>( bmp.size );
|
||||
|
||||
uint8_t* dstP = buf.get();
|
||||
uint8_t* srcP = imgData.GetData();
|
||||
|
||||
long long pxCount = static_cast<long long>( bmp.w ) * bmp.h;
|
||||
|
||||
if( imgData.HasAlpha() )
|
||||
{
|
||||
uint8_t* p = buf.get() + ( bmp.w * y + x ) * 4;
|
||||
uint8_t* srcAlpha = imgData.GetAlpha();
|
||||
|
||||
p[0] = imgData.GetRed( x, y );
|
||||
p[1] = imgData.GetGreen( x, y );
|
||||
p[2] = imgData.GetBlue( x, y );
|
||||
for( long long px = 0; px < pxCount; px++ )
|
||||
{
|
||||
memcpy( dstP, srcP, 3 );
|
||||
dstP[3] = *srcAlpha;
|
||||
|
||||
if( imgData.HasAlpha() )
|
||||
p[3] = imgData.GetAlpha( x, y );
|
||||
else if( imgData.HasMask() && p[0] == imgData.GetMaskRed()
|
||||
&& p[1] == imgData.GetMaskGreen() && p[2] == imgData.GetMaskBlue() )
|
||||
p[3] = wxALPHA_TRANSPARENT;
|
||||
else
|
||||
p[3] = wxALPHA_OPAQUE;
|
||||
srcAlpha += 1;
|
||||
srcP += 3;
|
||||
dstP += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( imgData.HasMask() )
|
||||
{
|
||||
uint8_t maskRed = imgData.GetMaskRed();
|
||||
uint8_t maskGreen = imgData.GetMaskGreen();
|
||||
uint8_t maskBlue = imgData.GetMaskBlue();
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, textureID );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
buf.get() );
|
||||
for( long long px = 0; px < pxCount; px++ )
|
||||
{
|
||||
memcpy( dstP, srcP, 3 );
|
||||
|
||||
if( srcP[0] == maskRed && srcP[1] == maskGreen && srcP[2] == maskBlue )
|
||||
dstP[3] = wxALPHA_TRANSPARENT;
|
||||
else
|
||||
dstP[3] = wxALPHA_OPAQUE;
|
||||
|
||||
srcP += 3;
|
||||
dstP += 4;
|
||||
}
|
||||
}
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, textureID );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
buf.get() );
|
||||
}
|
||||
else
|
||||
{
|
||||
bmp.size = bmp.w * bmp.h * 3;
|
||||
|
||||
uint8_t* srcP = imgData.GetData();
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, textureID );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, bmp.w, bmp.h, 0, GL_RGB, GL_UNSIGNED_BYTE, srcP );
|
||||
}
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
|
||||
|
||||
long long currentTime = wxGetUTCTimeMillis().GetValue();
|
||||
|
||||
bmp.id = textureID;
|
||||
bmp.accessTime = currentTime;
|
||||
|
||||
#ifndef DISABLE_BITMAP_CACHE
|
||||
m_cacheLru.emplace_back( aBitmap->GetImageID() );
|
||||
m_cacheSize += bmp.size;
|
||||
m_bitmaps.emplace( aBitmap->GetImageID(), std::move( bmp ) );
|
||||
|
||||
if( m_cacheLru.size() > m_cacheMaxElements
|
||||
|| m_cacheSize > m_cacheMaxSize )
|
||||
if( m_cacheLru.size() + 1 > m_cacheMaxElements || m_cacheSize + bmp.size > m_cacheMaxSize )
|
||||
{
|
||||
KIID last = m_cacheLru.front();
|
||||
CACHED_BITMAP& cachedBitmap = m_bitmaps[last];
|
||||
KIID toRemove( 0 );
|
||||
auto toRemoveLru = m_cacheLru.end();
|
||||
|
||||
// Remove entries accessed > 1s ago first
|
||||
for( const auto& [kiid, cachedBmp] : m_bitmaps )
|
||||
{
|
||||
const int cacheTimeoutMillis = 1000L;
|
||||
|
||||
if( currentTime - cachedBmp.accessTime > cacheTimeoutMillis )
|
||||
{
|
||||
toRemove = kiid;
|
||||
toRemoveLru = std::find( m_cacheLru.begin(), m_cacheLru.end(), toRemove );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, remove the latest entry (it's less likely to be needed soon)
|
||||
if( toRemove == niluuid )
|
||||
{
|
||||
toRemoveLru = m_cacheLru.end();
|
||||
toRemoveLru--;
|
||||
|
||||
toRemove = *toRemoveLru;
|
||||
}
|
||||
|
||||
CACHED_BITMAP& cachedBitmap = m_bitmaps[toRemove];
|
||||
|
||||
m_cacheSize -= cachedBitmap.size;
|
||||
glDeleteTextures( 1, &cachedBitmap.id );
|
||||
m_freedTextureIds.emplace_back( cachedBitmap.id );
|
||||
|
||||
m_bitmaps.erase( last );
|
||||
m_cacheLru.pop_front();
|
||||
m_bitmaps.erase( toRemove );
|
||||
m_cacheLru.erase( toRemoveLru );
|
||||
}
|
||||
|
||||
m_cacheLru.emplace_back( aBitmap->GetImageID() );
|
||||
m_cacheSize += bmp.size;
|
||||
m_bitmaps.emplace( aBitmap->GetImageID(), std::move( bmp ) );
|
||||
#endif
|
||||
|
||||
return textureID;
|
||||
@@ -1111,13 +1172,21 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
|
||||
m_currentManager->Color( m_strokeColor.r, m_strokeColor.g, m_strokeColor.b,
|
||||
m_strokeColor.a );
|
||||
|
||||
std::deque<VECTOR2D> pointList;
|
||||
pointList.push_back( aStartPoint );
|
||||
pointList.push_back( diagonalPointA );
|
||||
pointList.push_back( aEndPoint );
|
||||
pointList.push_back( diagonalPointB );
|
||||
pointList.push_back( aStartPoint );
|
||||
DrawPolyline( pointList );
|
||||
// DrawLine (and DrawPolyline )
|
||||
// has problem with 0 length lines so enforce minimum
|
||||
if( aStartPoint == aEndPoint )
|
||||
DrawLine( aStartPoint + VECTOR2D( 1.0, 0.0 ), aEndPoint );
|
||||
else
|
||||
{
|
||||
std::deque<VECTOR2D> pointList;
|
||||
|
||||
pointList.push_back( aStartPoint );
|
||||
pointList.push_back( diagonalPointA );
|
||||
pointList.push_back( aEndPoint );
|
||||
pointList.push_back( diagonalPointB );
|
||||
pointList.push_back( aStartPoint );
|
||||
DrawPolyline( pointList );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+77
-17
@@ -38,6 +38,7 @@
|
||||
#include <gestfich.h>
|
||||
#include <string_utils.h>
|
||||
#include <launch_ext.h>
|
||||
#include "wx/tokenzr.h"
|
||||
|
||||
void QuoteString( wxString& string )
|
||||
{
|
||||
@@ -114,39 +115,98 @@ wxString FindKicadFile( const wxString& shortname )
|
||||
|
||||
int ExecuteFile( const wxString& aEditorName, const wxString& aFileName, wxProcess *aCallback )
|
||||
{
|
||||
wxString fullEditorName;
|
||||
wxString param;
|
||||
wxString fullEditorName;
|
||||
std::vector<wxString> params;
|
||||
|
||||
#ifdef __UNIX__
|
||||
int space = aEditorName.Find( ' ' );
|
||||
wxString param;
|
||||
bool inSingleQuotes = false;
|
||||
bool inDoubleQuotes = false;
|
||||
|
||||
if( space > 0 && !aEditorName.Contains( "\"" ) && !aEditorName.Contains( "\'" ) )
|
||||
auto pushParam =
|
||||
[&]()
|
||||
{
|
||||
if( !param.IsEmpty() )
|
||||
{
|
||||
params.push_back( param );
|
||||
param.clear();
|
||||
}
|
||||
};
|
||||
|
||||
for( wxUniChar ch : aEditorName )
|
||||
{
|
||||
fullEditorName = FindKicadFile( aEditorName.Mid( 0, space ) );
|
||||
param = aEditorName.Mid( space + 1 );
|
||||
if( inSingleQuotes )
|
||||
{
|
||||
if( ch == '\'' )
|
||||
{
|
||||
pushParam();
|
||||
inSingleQuotes = false;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
param += ch;
|
||||
}
|
||||
}
|
||||
else if( inDoubleQuotes )
|
||||
{
|
||||
if( ch == '"' )
|
||||
{
|
||||
pushParam();
|
||||
inDoubleQuotes = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
param += ch;
|
||||
}
|
||||
}
|
||||
else if( ch == '\'' )
|
||||
{
|
||||
pushParam();
|
||||
inSingleQuotes = true;
|
||||
}
|
||||
else if( ch == '"' )
|
||||
{
|
||||
pushParam();
|
||||
inDoubleQuotes = true;
|
||||
}
|
||||
else if( ch == ' ' )
|
||||
{
|
||||
pushParam();
|
||||
}
|
||||
else
|
||||
{
|
||||
param += ch;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
pushParam();
|
||||
|
||||
fullEditorName = FindKicadFile( params[0] );
|
||||
params.erase( params.begin() );
|
||||
#else
|
||||
fullEditorName = FindKicadFile( aEditorName );
|
||||
#endif
|
||||
{
|
||||
fullEditorName = FindKicadFile( aEditorName );
|
||||
}
|
||||
|
||||
if( wxFileExists( fullEditorName ) )
|
||||
{
|
||||
int i = 0;
|
||||
const wchar_t* args[4];
|
||||
std::vector<const wchar_t*> args;
|
||||
|
||||
args[i++] = fullEditorName.wc_str();
|
||||
args.emplace_back( fullEditorName.wc_str() );
|
||||
|
||||
if( !param.IsEmpty() )
|
||||
args[i++] = param.wc_str();
|
||||
if( !params.empty() )
|
||||
{
|
||||
for( const wxString& p : params )
|
||||
args.emplace_back( p.wc_str() );
|
||||
}
|
||||
|
||||
if( !aFileName.IsEmpty() )
|
||||
args[i++] = aFileName.wc_str();
|
||||
args.emplace_back( aFileName.wc_str() );
|
||||
|
||||
args[i] = nullptr;
|
||||
args.emplace_back( nullptr );
|
||||
|
||||
return wxExecute( const_cast<wchar_t**>( args ), wxEXEC_ASYNC, aCallback );
|
||||
return wxExecute( const_cast<wchar_t**>( args.data() ), wxEXEC_ASYNC, aCallback );
|
||||
}
|
||||
|
||||
wxString msg;
|
||||
|
||||
+5
-2
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2020 Ian McInerney <ian.s.mcinerney@ieee.org>
|
||||
* Copyright (C) 2007-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
* Copyright (C) 1992-2023 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
|
||||
@@ -324,8 +324,11 @@ bool KIID_PATH::MakeRelativeTo( const KIID_PATH& aPath )
|
||||
|
||||
for( size_t i = 0; i < aPath.size(); ++i )
|
||||
{
|
||||
if( copy.at( i ).AsString() != aPath.at( i ).AsString() )
|
||||
if( copy.at( i ) != aPath.at( i ) )
|
||||
{
|
||||
*this = copy;
|
||||
return false; // this path is not contained within aPath
|
||||
}
|
||||
}
|
||||
|
||||
for( size_t i = aPath.size(); i < copy.size(); ++i )
|
||||
|
||||
@@ -288,6 +288,24 @@ wxString PATHS::GetStockPlugins3DPath()
|
||||
fn.AppendDir( wxT( "plugins" ) );
|
||||
#elif defined( __WXMAC__ )
|
||||
fn.Assign( wxStandardPaths::Get().GetPluginsDir(), wxEmptyString );
|
||||
|
||||
// This must be mapped to main bundle for everything but kicad.app
|
||||
const wxArrayString dirs = fn.GetDirs();
|
||||
|
||||
// Check if we are the main kicad binary. in this case, the path will be
|
||||
// /path/to/bundlename.app/Contents/PlugIns
|
||||
// If we are an aux binary, the path will be something like
|
||||
// /path/to/bundlename.app/Contents/Applications/<standalone>.app/Contents/PlugIns
|
||||
if( dirs.GetCount() >= 6 &&
|
||||
dirs[dirs.GetCount() - 4] == wxT( "Applications" ) &&
|
||||
dirs[dirs.GetCount() - 6].Lower().EndsWith( wxT( "app" ) ) )
|
||||
{
|
||||
fn.RemoveLastDir();
|
||||
fn.RemoveLastDir();
|
||||
fn.RemoveLastDir();
|
||||
fn.RemoveLastDir();
|
||||
fn.AppendDir( wxT( "PlugIns" ) );
|
||||
}
|
||||
#else
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
{
|
||||
|
||||
@@ -161,6 +161,8 @@ void PGM_BASE::Destroy()
|
||||
// unlike a normal destructor, this is designed to be called more than once safely:
|
||||
delete m_locale;
|
||||
m_locale = nullptr;
|
||||
|
||||
m_pgm_checker.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -443,6 +445,8 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
m_pgm_checker = std::make_unique<wxSingleInstanceChecker>();
|
||||
m_pgm_checker->Create( pgm_name, wxStandardPaths::Get().GetTempDir() );
|
||||
|
||||
// Init KiCad environment
|
||||
// the environment variable KICAD (if exists) gives the kicad path:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <string_utils.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <trigo.h>
|
||||
#include <fmt/core.h>
|
||||
|
||||
/**
|
||||
* Oblique angle for DXF native text
|
||||
@@ -146,6 +147,26 @@ void DXF_PLOTTER::SetUnits( DXF_UNITS aUnit )
|
||||
}
|
||||
|
||||
|
||||
// convert aValue to a string, and remove trailing zeros
|
||||
// In DXF files coordinates need a high precision: at least 9 digits when given
|
||||
// in inches and 7 digits when in mm.
|
||||
// So we use 16 digits and remove trailing 0 (if any)
|
||||
static std::string formatCoord( double aValue )
|
||||
{
|
||||
std::string buf;
|
||||
|
||||
buf = fmt::format( "{:.16f}", aValue );
|
||||
|
||||
// remove trailing zeros
|
||||
while( !buf.empty() && buf[buf.size() - 1] == '0' )
|
||||
{
|
||||
buf.pop_back();
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void DXF_PLOTTER::SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil,
|
||||
double aScale, bool aMirror )
|
||||
{
|
||||
@@ -417,11 +438,24 @@ void DXF_PLOTTER::SetColor( const COLOR4D& color )
|
||||
void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
||||
{
|
||||
wxASSERT( m_outputFile );
|
||||
MoveTo( p1 );
|
||||
LineTo( VECTOR2I( p1.x, p2.y ) );
|
||||
LineTo( VECTOR2I( p2.x, p2.y ) );
|
||||
LineTo( VECTOR2I( p2.x, p1.y ) );
|
||||
FinishTo( VECTOR2I( p1.x, p1.y ) );
|
||||
|
||||
if( p1 != p2 )
|
||||
{
|
||||
MoveTo( p1 );
|
||||
LineTo( VECTOR2I( p1.x, p2.y ) );
|
||||
LineTo( VECTOR2I( p2.x, p2.y ) );
|
||||
LineTo( VECTOR2I( p2.x, p1.y ) );
|
||||
FinishTo( VECTOR2I( p1.x, p1.y ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw as a point
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
VECTOR2D point_dev = userToDeviceCoordinates( p1 );
|
||||
|
||||
fprintf( m_outputFile, "0\nPOINT\n8\n%s\n10\n%g\n20\n%g\n", TO_UTF8( cname ), point_dev.x,
|
||||
point_dev.y );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -431,31 +465,43 @@ void DXF_PLOTTER::Circle( const VECTOR2I& centre, int diameter, FILL_T fill, int
|
||||
double radius = userToDeviceSize( diameter / 2 );
|
||||
VECTOR2D centre_dev = userToDeviceCoordinates( centre );
|
||||
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
|
||||
if( radius > 0 )
|
||||
{
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
|
||||
if( fill == FILL_T::NO_FILL )
|
||||
{
|
||||
fprintf( m_outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n",
|
||||
fprintf( m_outputFile, "0\nCIRCLE\n8\n%s\n10\n%s\n20\n%s\n40\n%s\n",
|
||||
TO_UTF8( cname ),
|
||||
centre_dev.x, centre_dev.y, radius );
|
||||
formatCoord( centre_dev.x ).c_str(),
|
||||
formatCoord( centre_dev.y ).c_str(),
|
||||
formatCoord( radius ).c_str() );
|
||||
}
|
||||
else if( fill == FILL_T::FILLED_SHAPE )
|
||||
{
|
||||
double r = radius*0.5;
|
||||
double r = radius * 0.5;
|
||||
fprintf( m_outputFile, "0\nPOLYLINE\n" );
|
||||
fprintf( m_outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname ) );
|
||||
fprintf( m_outputFile, "40\n%g\n41\n%g\n", radius, radius);
|
||||
fprintf( m_outputFile, "40\n%s\n41\n%s\n",
|
||||
formatCoord( radius ).c_str(),
|
||||
formatCoord( radius ).c_str() );
|
||||
fprintf( m_outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ) );
|
||||
fprintf( m_outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
|
||||
centre_dev.x-r, centre_dev.y );
|
||||
fprintf( m_outputFile, "10\n%s\n 20\n%s\n42\n1.0\n",
|
||||
formatCoord( centre_dev.x-r ).c_str(),
|
||||
formatCoord( centre_dev.y ).c_str() );
|
||||
fprintf( m_outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ) );
|
||||
fprintf( m_outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
|
||||
centre_dev.x+r, centre_dev.y );
|
||||
fprintf( m_outputFile, "10\n%s\n 20\n%s\n42\n1.0\n",
|
||||
formatCoord( centre_dev.x+r ).c_str(),
|
||||
formatCoord( centre_dev.y ).c_str() );
|
||||
fprintf( m_outputFile, "0\nSEQEND\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw as a point
|
||||
fprintf( m_outputFile, "0\nPOINT\n8\n%s\n10\n%g\n20\n%g\n", TO_UTF8( cname ), centre_dev.x,
|
||||
centre_dev.y );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -578,9 +624,12 @@ void DXF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
|
||||
// DXF LINE
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
const char* lname = getDXFLineType( static_cast<PLOT_DASH_TYPE>( m_currentLineType ) );
|
||||
fprintf( m_outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n",
|
||||
fprintf( m_outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%s\n20\n%s\n11\n%s\n21\n%s\n",
|
||||
TO_UTF8( cname ), lname,
|
||||
pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y );
|
||||
formatCoord( pen_lastpos_dev.x ).c_str(),
|
||||
formatCoord( pen_lastpos_dev.y ).c_str(),
|
||||
formatCoord( pos_dev.x ).c_str(),
|
||||
formatCoord( pos_dev.y ).c_str() );
|
||||
}
|
||||
|
||||
m_penLastpos = pos;
|
||||
@@ -626,8 +675,8 @@ void DXF_PLOTTER::ThickSegment( const VECTOR2I& aStart, const VECTOR2I& aEnd, in
|
||||
}
|
||||
|
||||
|
||||
void DXF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void DXF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
wxASSERT( m_outputFile );
|
||||
|
||||
@@ -648,9 +697,11 @@ void DXF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
// Emit a DXF ARC entity
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
fprintf( m_outputFile,
|
||||
"0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n",
|
||||
"0\nARC\n8\n%s\n10\n%s\n20\n%s\n40\n%s\n50\n%.8f\n51\n%.8f\n",
|
||||
TO_UTF8( cname ),
|
||||
centre_device.x, centre_device.y, radius_device,
|
||||
formatCoord( centre_device.x ).c_str(),
|
||||
formatCoord( centre_device.y ).c_str(),
|
||||
formatCoord( radius_device ).c_str(),
|
||||
startAngle.AsDegrees(), endAngle.AsDegrees() );
|
||||
}
|
||||
|
||||
@@ -936,21 +987,21 @@ void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor
|
||||
" 8\n"
|
||||
"%s\n" // Layer name
|
||||
" 10\n"
|
||||
"%g\n" // First point X
|
||||
"%s\n" // First point X
|
||||
" 11\n"
|
||||
"%g\n" // Second point X
|
||||
"%s\n" // Second point X
|
||||
" 20\n"
|
||||
"%g\n" // First point Y
|
||||
"%s\n" // First point Y
|
||||
" 21\n"
|
||||
"%g\n" // Second point Y
|
||||
"%s\n" // Second point Y
|
||||
" 40\n"
|
||||
"%g\n" // Text height
|
||||
"%s\n" // Text height
|
||||
" 41\n"
|
||||
"%g\n" // Width factor
|
||||
"%s\n" // Width factor
|
||||
" 50\n"
|
||||
"%g\n" // Rotation
|
||||
"%.8f\n" // Rotation
|
||||
" 51\n"
|
||||
"%g\n" // Oblique angle
|
||||
"%.8f\n" // Oblique angle
|
||||
" 71\n"
|
||||
"%d\n" // Mirror flags
|
||||
" 72\n"
|
||||
@@ -960,9 +1011,9 @@ void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor
|
||||
aAttributes.m_Bold ?
|
||||
(aAttributes.m_Italic ? "KICADBI" : "KICADB")
|
||||
: (aAttributes.m_Italic ? "KICADI" : "KICAD"), TO_UTF8( cname ),
|
||||
origin_dev.x, origin_dev.x,
|
||||
origin_dev.y, origin_dev.y,
|
||||
size_dev.y, fabs( size_dev.x / size_dev.y ),
|
||||
formatCoord( origin_dev.x ).c_str(), formatCoord( origin_dev.x ).c_str(),
|
||||
formatCoord( origin_dev.y ).c_str(), formatCoord( origin_dev.y ).c_str(),
|
||||
formatCoord( size_dev.y ).c_str(), formatCoord( fabs( size_dev.x / size_dev.y ) ).c_str(),
|
||||
aAttributes.m_Angle.AsDegrees(),
|
||||
aAttributes.m_Italic ? DXF_OBLIQUE_ANGLE : 0,
|
||||
aAttributes.m_Mirrored ? 2 : 0, // X mirror flag
|
||||
|
||||
@@ -821,13 +821,14 @@ void GERBER_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill,
|
||||
|
||||
void GERBER_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill, int aWidth )
|
||||
{
|
||||
Arc( aCenter, ANGLE_0, ANGLE_360, aDiameter / 2, aFill, aWidth );
|
||||
Arc( aCenter, ANGLE_0, ANGLE_180, aDiameter / 2, aFill, aWidth );
|
||||
Arc( aCenter, ANGLE_180, ANGLE_360, aDiameter / 2, aFill, aWidth );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GERBER_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void GERBER_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
SetCurrentLineWidth( aWidth );
|
||||
|
||||
@@ -1149,8 +1150,8 @@ void GERBER_PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end, i
|
||||
}
|
||||
}
|
||||
|
||||
void GERBER_PLOTTER::ThickArc( const VECTOR2I& aCentre, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, int aWidth,
|
||||
void GERBER_PLOTTER::ThickArc( const VECTOR2D& aCentre, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, int aWidth,
|
||||
OUTLINE_MODE aTraceMode, void* aData )
|
||||
{
|
||||
GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
@@ -394,22 +394,16 @@ void HPGL_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T aFill, i
|
||||
VECTOR2D p1_device = userToDeviceCoordinates( p1 );
|
||||
VECTOR2D p2_device = userToDeviceCoordinates( p2 );
|
||||
|
||||
MoveTo( p1 );
|
||||
// EA command seems to always fill the rectangle, so plot as a polygon instead
|
||||
std::vector<VECTOR2I> cornerList;
|
||||
|
||||
if( aFill == FILL_T::FILLED_SHAPE )
|
||||
{
|
||||
startOrAppendItem( p1_device, wxString::Format( "RA %.0f,%.0f;",
|
||||
p2_device.x,
|
||||
p2_device.y ) );
|
||||
}
|
||||
cornerList.emplace_back( p1.x, p1.y );
|
||||
cornerList.emplace_back( p2.x, p1.y );
|
||||
cornerList.emplace_back( p2.x, p2.y );
|
||||
cornerList.emplace_back( p1.x, p2.y );
|
||||
cornerList.emplace_back( p1.x, p1.y );
|
||||
|
||||
startOrAppendItem( p1_device, wxString::Format( "EA %.0f,%.0f;",
|
||||
p2_device.x,
|
||||
p2_device.y ) );
|
||||
|
||||
m_current_item->loc_end = m_current_item->loc_start;
|
||||
m_current_item->bbox.Merge( p2_device );
|
||||
PenFinish();
|
||||
PlotPoly( cornerList, aFill, aWidth, nullptr );
|
||||
}
|
||||
|
||||
|
||||
@@ -435,7 +429,6 @@ void HPGL_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill,
|
||||
chord_angle.AsDegrees(),
|
||||
hpgl_end_polygon_cmd ) );
|
||||
m_current_item->lift_before = true;
|
||||
m_current_item->pen_returns = true;
|
||||
m_current_item->bbox.Merge( BOX2D( center_dev - radius,
|
||||
VECTOR2D( 2 * radius, 2 * radius ) ) );
|
||||
PenFinish();
|
||||
@@ -448,7 +441,6 @@ void HPGL_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill,
|
||||
radius,
|
||||
chord_angle.AsDegrees() ) );
|
||||
m_current_item->lift_before = true;
|
||||
m_current_item->pen_returns = true;
|
||||
m_current_item->bbox.Merge( BOX2D( center_dev - radius,
|
||||
VECTOR2D( 2 * radius, 2 * radius ) ) );
|
||||
PenFinish();
|
||||
@@ -567,8 +559,8 @@ void HPGL_PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end,
|
||||
}
|
||||
|
||||
|
||||
void HPGL_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void HPGL_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
if( aRadius <= 0 )
|
||||
return;
|
||||
|
||||
@@ -217,12 +217,43 @@ void PDF_PLOTTER::SetDash( int aLineWidth, PLOT_DASH_TYPE aLineStyle )
|
||||
void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
||||
{
|
||||
wxASSERT( m_workFile );
|
||||
|
||||
SetCurrentLineWidth( width );
|
||||
|
||||
VECTOR2I size = p2 - p1;
|
||||
|
||||
if( size.x == 0 && size.y == 0 )
|
||||
{
|
||||
// Can't draw zero-sized rectangles
|
||||
SetCurrentLineWidth( width );
|
||||
|
||||
MoveTo( VECTOR2I( p1.x, p1.y ) );
|
||||
FinishTo( VECTOR2I( p1.x, p1.y ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( std::min( std::abs( size.x ), std::abs( size.y ) ) < width )
|
||||
{
|
||||
// Too thick stroked rectangles are buggy, draw as polygon
|
||||
std::vector<VECTOR2I> cornerList;
|
||||
|
||||
cornerList.emplace_back( p1.x, p1.y );
|
||||
cornerList.emplace_back( p2.x, p1.y );
|
||||
cornerList.emplace_back( p2.x, p2.y );
|
||||
cornerList.emplace_back( p1.x, p2.y );
|
||||
cornerList.emplace_back( p1.x, p1.y );
|
||||
|
||||
PlotPoly( cornerList, fill, width, nullptr );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VECTOR2D p1_dev = userToDeviceCoordinates( p1 );
|
||||
VECTOR2D p2_dev = userToDeviceCoordinates( p2 );
|
||||
|
||||
SetCurrentLineWidth( width );
|
||||
fprintf( m_workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y,
|
||||
p2_dev.x - p1_dev.x, p2_dev.y - p1_dev.y, fill == FILL_T::NO_FILL ? 'S' : 'B' );
|
||||
fprintf( m_workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y, p2_dev.x - p1_dev.x,
|
||||
p2_dev.y - p1_dev.y, fill == FILL_T::NO_FILL ? 'S' : 'B' );
|
||||
}
|
||||
|
||||
|
||||
@@ -336,8 +367,8 @@ void PDF_PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VE
|
||||
}
|
||||
|
||||
|
||||
void PDF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void PDF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
wxASSERT( m_workFile );
|
||||
|
||||
@@ -1378,10 +1409,11 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
double wideningFactor, heightFactor;
|
||||
|
||||
VECTOR2I t_size( std::abs( aSize.x ), std::abs( aSize.y ) );
|
||||
bool textMirrored = aSize.x < 0;
|
||||
|
||||
computeTextParameters( aPos, aText, aOrient, t_size, m_plotMirror, aH_justify,
|
||||
aV_justify, aWidth, aItalic, aBold, &wideningFactor, &ctm_a,
|
||||
&ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor );
|
||||
computeTextParameters( aPos, aText, aOrient, t_size, textMirrored, aH_justify, aV_justify,
|
||||
aWidth, aItalic, aBold, &wideningFactor, &ctm_a, &ctm_b, &ctm_c, &ctm_d,
|
||||
&ctm_e, &ctm_f, &heightFactor );
|
||||
|
||||
SetColor( aColor );
|
||||
SetCurrentLineWidth( aWidth, aData );
|
||||
@@ -1393,6 +1425,10 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
VECTOR2I full_box( aFont->StringBoundaryLimits( aText, t_size, aWidth, aBold, aItalic ) );
|
||||
|
||||
if( textMirrored )
|
||||
full_box.x *= -1;
|
||||
|
||||
VECTOR2I box_x( full_box.x, 0 );
|
||||
VECTOR2I box_y( 0, full_box.y );
|
||||
|
||||
@@ -1413,13 +1449,17 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
{
|
||||
wxString word = str_tok.GetNextToken();
|
||||
|
||||
computeTextParameters( pos, word, aOrient, t_size, m_plotMirror, GR_TEXT_H_ALIGN_LEFT,
|
||||
GR_TEXT_V_ALIGN_BOTTOM, aWidth, aItalic, aBold, &wideningFactor, &ctm_a,
|
||||
&ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor );
|
||||
computeTextParameters( pos, word, aOrient, t_size, textMirrored, GR_TEXT_H_ALIGN_LEFT,
|
||||
GR_TEXT_V_ALIGN_BOTTOM, aWidth, aItalic, aBold, &wideningFactor,
|
||||
&ctm_a, &ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor );
|
||||
|
||||
// Extract the changed width and rotate by the orientation to get the offset for the
|
||||
// next word
|
||||
VECTOR2I bbox( aFont->StringBoundaryLimits( word, t_size, aWidth, aBold, aItalic ).x, 0 );
|
||||
|
||||
if( textMirrored )
|
||||
bbox.x *= -1;
|
||||
|
||||
RotatePoint( bbox, aOrient );
|
||||
pos += bbox;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-2023 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
|
||||
@@ -113,7 +113,7 @@ void PSLIKE_PLOTTER::FlashPadOval( const VECTOR2I& aPadPos, const VECTOR2I& aSiz
|
||||
if( aTraceMode == FILLED )
|
||||
ThickSegment( a + aPadPos, b + aPadPos, size.x, aTraceMode, nullptr );
|
||||
else
|
||||
sketchOval( aPadPos, size, orient, -1 );
|
||||
sketchOval( aPadPos, size, orient, USE_DEFAULT_LINE_WIDTH );
|
||||
}
|
||||
|
||||
|
||||
@@ -423,7 +423,7 @@ void PSLIKE_PLOTTER::computeTextParameters( const VECTOR2I& aPos,
|
||||
// This is an approximation of the text bounds (in IUs)
|
||||
int tw = returnPostscriptTextWidth( aText, aSize.x, aItalic, aWidth );
|
||||
int th = aSize.y;
|
||||
int dx, dy;
|
||||
int dx = 0, dy = 0;
|
||||
|
||||
switch( aH_justify )
|
||||
{
|
||||
@@ -450,7 +450,7 @@ void PSLIKE_PLOTTER::computeTextParameters( const VECTOR2I& aPos,
|
||||
*wideningFactor = sz_dev.x / sz_dev.y;
|
||||
|
||||
// Mirrored texts must be plotted as mirrored!
|
||||
if( m_plotMirror )
|
||||
if( m_plotMirror ^ aMirror )
|
||||
*wideningFactor = -*wideningFactor;
|
||||
|
||||
// The CTM transformation matrix
|
||||
|
||||
@@ -443,8 +443,8 @@ void SVG_PLOTTER::Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int wi
|
||||
}
|
||||
|
||||
|
||||
void SVG_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void SVG_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
/* Draws an arc of a circle, centered on (xc,yc), with starting point (x1, y1) and ending
|
||||
* at (x2, y2). The current pen is used for the outline and the current brush for filling
|
||||
@@ -825,16 +825,16 @@ void SVG_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
|
||||
if( !aOrient.IsZero() )
|
||||
{
|
||||
fprintf( m_outputFile,
|
||||
"<g transform=\"rotate(%f %.*f %.*f)\">\n",
|
||||
- aOrient.AsDegrees(), m_precision, anchor_pos_dev.x, m_precision, anchor_pos_dev.y );
|
||||
fprintf( m_outputFile, "<g transform=\"rotate(%f %.*f %.*f)\">\n",
|
||||
m_plotMirror ? aOrient.AsDegrees() : -aOrient.AsDegrees(), m_precision,
|
||||
anchor_pos_dev.x, m_precision, anchor_pos_dev.y );
|
||||
}
|
||||
|
||||
fprintf( m_outputFile, "<text x=\"%.*f\" y=\"%.*f\"\n",
|
||||
m_precision, text_pos_dev.x, m_precision, text_pos_dev.y );
|
||||
|
||||
/// If the text is mirrored, we should also mirror the hidden text to match
|
||||
if( aSize.x < 0 )
|
||||
if( m_plotMirror != ( aSize.x < 0 ) )
|
||||
fprintf( m_outputFile, "transform=\"scale(-1 1) translate(%f 0)\"\n", -2 * text_pos_dev.x );
|
||||
|
||||
fprintf( m_outputFile,
|
||||
|
||||
@@ -145,13 +145,31 @@ double PLOTTER::GetDashGapLenIU( int aLineWidth ) const
|
||||
return userToDeviceSize( m_renderSettings->GetGapLength( aLineWidth ) );
|
||||
}
|
||||
|
||||
|
||||
#include <wx/log.h>
|
||||
void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR2I& aEnd,
|
||||
FILL_T aFill, int aWidth, int aMaxError )
|
||||
{
|
||||
EDA_ANGLE startAngle( aStart - aCenter );
|
||||
EDA_ANGLE endAngle( aEnd - aCenter );
|
||||
int radius = ( aStart - aCenter ).EuclideanNorm();
|
||||
// Recalculate aCenter using double to be sure we will use a exact value, from aStart and aEnd
|
||||
// it must be on the line passing by the middle of segment {aStart, aEnd}
|
||||
// To simplify calculations, use aStart as origin in intermediate calculations
|
||||
VECTOR2D center = aCenter - aStart;
|
||||
VECTOR2D end = aEnd - aStart;
|
||||
EDA_ANGLE segAngle( end );
|
||||
|
||||
// Rotate end and center, to make segment {aStart, aEnd} horizontal
|
||||
RotatePoint( end, segAngle );
|
||||
RotatePoint( center, segAngle );
|
||||
|
||||
// center.x must be at end.x/2 coordinate
|
||||
center.x = end.x / 2;
|
||||
|
||||
// Now calculate the right center position
|
||||
RotatePoint( center, -segAngle );
|
||||
center += aStart;
|
||||
|
||||
EDA_ANGLE startAngle( VECTOR2D( aStart ) - center );
|
||||
EDA_ANGLE endAngle( VECTOR2D( aEnd ) - center );
|
||||
double radius = ( VECTOR2D( aStart ) - center ).EuclideanNorm();
|
||||
|
||||
if( startAngle > endAngle )
|
||||
{
|
||||
@@ -168,12 +186,12 @@ void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR
|
||||
startAngle = -startAngle;
|
||||
endAngle = -endAngle;
|
||||
|
||||
Arc( aCenter, startAngle, endAngle, radius, aFill, aWidth );
|
||||
Arc( center, startAngle, endAngle, radius, aFill, aWidth );
|
||||
}
|
||||
|
||||
|
||||
void PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
EDA_ANGLE startAngle( aStartAngle );
|
||||
EDA_ANGLE endAngle( aEndAngle );
|
||||
@@ -570,8 +588,8 @@ void PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end, int widt
|
||||
}
|
||||
|
||||
|
||||
void PLOTTER::ThickArc( const VECTOR2I& centre, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, int aWidth,
|
||||
void PLOTTER::ThickArc( const VECTOR2D& centre, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, int aWidth,
|
||||
OUTLINE_MODE aTraceMode, void* aData )
|
||||
{
|
||||
if( aTraceMode == FILLED )
|
||||
|
||||
@@ -177,8 +177,16 @@ bool PROJECT_ARCHIVER::Archive( const wxString& aSrcDir, const wxString& aDestFi
|
||||
|
||||
unsigned long uncompressedBytes = 0;
|
||||
|
||||
// Our filename collector can store duplicate filenames. for instance *.gm2
|
||||
// matches both *.g?? and *.gm??.
|
||||
// So skip duplicate filenames (they are sorted, so it is easy).
|
||||
wxString lastStoredFile;
|
||||
|
||||
for( unsigned ii = 0; ii < files.GetCount(); ii++ )
|
||||
{
|
||||
if( lastStoredFile == files[ii] ) // duplicate name: already stored
|
||||
continue;
|
||||
|
||||
wxFileSystem fsfile;
|
||||
|
||||
wxFileName curr_fn( files[ii] );
|
||||
|
||||
@@ -569,9 +569,42 @@ bool PROJECT_FILE::SaveToFile( const wxString& aDirectory, bool aForce )
|
||||
|
||||
bool PROJECT_FILE::SaveAs( const wxString& aDirectory, const wxString& aFile )
|
||||
{
|
||||
wxFileName oldFilename( GetFilename() );
|
||||
wxString oldProjectName = oldFilename.GetName();
|
||||
wxString oldProjectPath = oldFilename.GetPath();
|
||||
|
||||
Set( "meta.filename", aFile + "." + ProjectFileExtension );
|
||||
SetFilename( aFile );
|
||||
|
||||
auto updatePath =
|
||||
[&]( wxString& aPath )
|
||||
{
|
||||
if( aPath.StartsWith( oldProjectName + wxS( "." ) ) )
|
||||
aPath.Replace( oldProjectName, aFile, false );
|
||||
else if( aPath.StartsWith( oldProjectPath + wxS( "/" ) ) )
|
||||
aPath.Replace( oldProjectPath, aDirectory, false );
|
||||
};
|
||||
|
||||
updatePath( m_BoardDrawingSheetFile );
|
||||
|
||||
for( int ii = LAST_PATH_FIRST; ii < (int) LAST_PATH_SIZE; ++ii )
|
||||
updatePath( m_PcbLastPath[ ii ] );
|
||||
|
||||
auto updatePathByPtr =
|
||||
[&]( const std::string& aPtr )
|
||||
{
|
||||
if( std::optional<wxString> path = Get<wxString>( aPtr ) )
|
||||
{
|
||||
updatePath( path.value() );
|
||||
Set( aPtr, path.value() );
|
||||
}
|
||||
};
|
||||
|
||||
updatePathByPtr( "schematic.page_layout_descr_file" );
|
||||
updatePathByPtr( "schematic.plot_directory" );
|
||||
updatePathByPtr( "schematic.ngspice.workbook_filename" );
|
||||
updatePathByPtr( "pcbnew.page_layout_descr_file" );
|
||||
|
||||
// While performing Save As, we have already checked that we can write to the directory
|
||||
// so don't carry the previous flag
|
||||
SetReadOnly( false );
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@ void RC_ITEM::SetItems( const EDA_ITEM* aItem, const EDA_ITEM* bItem,
|
||||
{
|
||||
m_ids.clear();
|
||||
|
||||
m_ids.push_back( aItem->m_Uuid );
|
||||
if( aItem )
|
||||
m_ids.push_back( aItem->m_Uuid );
|
||||
|
||||
if( bItem )
|
||||
m_ids.push_back( bItem->m_Uuid );
|
||||
|
||||
+10
-28
@@ -48,35 +48,17 @@
|
||||
|
||||
static int vprint( std::string* result, const char* format, va_list ap )
|
||||
{
|
||||
char msg[512];
|
||||
// This function can call vsnprintf twice.
|
||||
// But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
|
||||
// va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
|
||||
// see: www.cplusplus.com/reference/cstdio/vsnprintf
|
||||
// we make a copy of va_list ap for the second call, if happens
|
||||
va_list tmp;
|
||||
va_copy( tmp, ap );
|
||||
size_t len = vsnprintf( nullptr, 0, format, tmp );
|
||||
va_end( tmp );
|
||||
|
||||
size_t len = vsnprintf( msg, sizeof(msg), format, ap );
|
||||
// Resize the output to hold the required data
|
||||
size_t size = result->size();
|
||||
result->resize( size + len );
|
||||
|
||||
if( len < sizeof(msg) ) // the output fit into msg
|
||||
{
|
||||
result->append( msg, msg + len );
|
||||
}
|
||||
else
|
||||
{
|
||||
// output was too big, so now incur the expense of allocating
|
||||
// a buf for holding suffient characters.
|
||||
|
||||
std::vector<char> buf;
|
||||
buf.reserve( len+1 ); // reserve(), not resize() which writes. +1 for trailing nul.
|
||||
|
||||
len = vsnprintf( &buf[0], len+1, format, tmp );
|
||||
|
||||
result->append( &buf[0], &buf[0] + len );
|
||||
}
|
||||
|
||||
va_end( tmp ); // Release the temporary va_list, initialised from ap
|
||||
// Now do the actual printing
|
||||
len = vsnprintf( result->data() + size, len + 1, format, ap );
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -443,18 +425,18 @@ int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap )
|
||||
// we make a copy of va_list ap for the second call, if happens
|
||||
va_list tmp;
|
||||
va_copy( tmp, ap );
|
||||
int ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, ap );
|
||||
int ret = vsnprintf( m_buffer.data(), m_buffer.size(), fmt, ap );
|
||||
|
||||
if( ret >= (int) m_buffer.size() )
|
||||
{
|
||||
m_buffer.resize( ret + 1000 );
|
||||
ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, tmp );
|
||||
ret = vsnprintf( m_buffer.data(), m_buffer.size(), fmt, tmp );
|
||||
}
|
||||
|
||||
va_end( tmp ); // Release the temporary va_list, initialised from ap
|
||||
|
||||
if( ret > 0 )
|
||||
write( &m_buffer[0], ret );
|
||||
write( m_buffer.data(), ret );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,20 @@ principle should be easily implemented by adapting the current STL containers.
|
||||
%ignore to_json;
|
||||
%ignore from_json;
|
||||
|
||||
%rename(GetEffectiveTextShapeNative) EDA_TEXT::GetEffectiveTextShape;
|
||||
|
||||
%extend EDA_TEXT
|
||||
{
|
||||
%pythoncode
|
||||
%{
|
||||
|
||||
# KiCad 7.0 API Compatibility
|
||||
def GetEffectiveTextShape(self, aTriangulate=True, aUseTextRotation=True):
|
||||
return self.GetEffectiveTextShapeNative(aTriangulate)
|
||||
|
||||
%}
|
||||
}
|
||||
|
||||
// headers/imports that must be included in the _wrapper.cpp at top
|
||||
|
||||
%{
|
||||
|
||||
@@ -59,6 +59,10 @@ ACTION_MENU::ACTION_MENU( bool isContextMenu, TOOL_INTERACTIVE* aTool ) :
|
||||
|
||||
ACTION_MENU::~ACTION_MENU()
|
||||
{
|
||||
Disconnect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ),
|
||||
nullptr, this );
|
||||
Disconnect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this );
|
||||
|
||||
// Set parent to NULL to prevent submenus from unregistering from a nonexistent object
|
||||
for( ACTION_MENU* menu : m_submenus )
|
||||
menu->SetParent( nullptr );
|
||||
|
||||
@@ -127,16 +127,9 @@ bool CONNECTION_SUBGRAPH::ResolveDrivers( bool aCheckMultipleDrivers )
|
||||
return a_name < b_name;
|
||||
};
|
||||
|
||||
auto strong_cmp = [this]( SCH_ITEM* a, SCH_ITEM* b ) -> bool
|
||||
{
|
||||
const wxString& a_name = GetNameForDriver( a );
|
||||
const wxString& b_name = GetNameForDriver( b );
|
||||
return a_name < b_name;
|
||||
};
|
||||
|
||||
PRIORITY highest_priority = PRIORITY::INVALID;
|
||||
std::set<SCH_ITEM*, decltype( candidate_cmp )> candidates( candidate_cmp );
|
||||
std::set<SCH_ITEM*, decltype( strong_cmp )> strong_drivers( strong_cmp );
|
||||
std::set<SCH_ITEM*> strong_drivers;
|
||||
|
||||
m_driver = nullptr;
|
||||
|
||||
@@ -239,7 +232,11 @@ void CONNECTION_SUBGRAPH::getAllConnectedItems( std::set<std::pair<SCH_SHEET_PAT
|
||||
sg = sg->m_absorbed_by;
|
||||
}
|
||||
|
||||
aSubgraphs.insert( sg );
|
||||
// If we are unable to insert the subgraph into the set, then we have already
|
||||
// visited it and don't need to add it again.
|
||||
if( aSubgraphs.insert( sg ).second == false )
|
||||
return;
|
||||
|
||||
aSubgraphs.insert( sg->m_absorbed_subgraphs.begin(), sg->m_absorbed_subgraphs.end() );
|
||||
|
||||
for( SCH_ITEM* item : sg->m_items )
|
||||
@@ -1345,11 +1342,15 @@ void CONNECTION_GRAPH::generateBusAliasMembers()
|
||||
wxString name = conn->FullLocalName();
|
||||
|
||||
CONNECTION_SUBGRAPH* new_sg = new CONNECTION_SUBGRAPH( this );
|
||||
|
||||
// This connection cannot form a part of the item because the item is not, itself
|
||||
// connected to this subgraph. It exists as part of a virtual item that may be connected
|
||||
// to other items but is not in the schematic.
|
||||
SCH_CONNECTION* new_conn = new SCH_CONNECTION( item, subgraph->m_sheet );
|
||||
new_conn->SetGraph( this );
|
||||
|
||||
new_conn->SetName( name );
|
||||
new_conn->SetType( CONNECTION_TYPE::NET );
|
||||
subgraph->StoreImplicitConnection( new_conn );
|
||||
int code = assignNewNetCode( *new_conn );
|
||||
|
||||
wxLogTrace( ConnTrace, wxS( "SG(%ld), Adding full local name (%s) with sg (%d) on subsheet %s" ), subgraph->m_code,
|
||||
@@ -3125,7 +3126,7 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
|
||||
bus_name = bus_wire->Connection( &sheet )->Name();
|
||||
|
||||
std::set<wxString> test_names;
|
||||
test_names.insert( bus_entry->Connection( &sheet )->Name() );
|
||||
test_names.insert( bus_entry->Connection( &sheet )->FullLocalName() );
|
||||
|
||||
wxString baseName = sheet.PathHumanReadable();
|
||||
|
||||
@@ -3138,11 +3139,11 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
|
||||
{
|
||||
for( const auto& sub_member : member->Members() )
|
||||
{
|
||||
if( test_names.count( sub_member->Name() ) )
|
||||
if( test_names.count( sub_member->FullLocalName() ) )
|
||||
conflict = false;
|
||||
}
|
||||
}
|
||||
else if( test_names.count( member->Name() ) )
|
||||
else if( test_names.count( member->FullLocalName() ) )
|
||||
{
|
||||
conflict = false;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,11 @@ public:
|
||||
m_hier_parent( nullptr )
|
||||
{}
|
||||
|
||||
~CONNECTION_SUBGRAPH() = default;
|
||||
~CONNECTION_SUBGRAPH()
|
||||
{
|
||||
for( SCH_CONNECTION* connection : m_bus_element_connections )
|
||||
delete connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which potential driver should drive the subgraph.
|
||||
@@ -162,6 +166,13 @@ public:
|
||||
|
||||
void RemoveItem( SCH_ITEM* aItem );
|
||||
|
||||
// Use this to keep a connection pointer that is not owned by any item
|
||||
// This will be destroyed with the subgraph
|
||||
void StoreImplicitConnection( SCH_CONNECTION* aConnection )
|
||||
{
|
||||
m_bus_element_connections.insert( aConnection );
|
||||
}
|
||||
|
||||
private:
|
||||
wxString driverName( SCH_ITEM* aItem ) const;
|
||||
|
||||
@@ -251,6 +262,10 @@ public:
|
||||
/// A cache of escaped netnames from schematic items
|
||||
mutable std::unordered_map<SCH_ITEM*, wxString> m_driver_name_cache;
|
||||
|
||||
/// A cache of connections that are part of this subgraph but that don't have
|
||||
/// an owning element (i.e. bus members)
|
||||
std::set<SCH_CONNECTION*> m_bus_element_connections;
|
||||
|
||||
};
|
||||
|
||||
struct NET_NAME_CODE_CACHE_KEY
|
||||
|
||||
@@ -361,6 +361,12 @@ bool DIALOG_LIB_SYMBOL_PROPERTIES::TransferDataFromWindow()
|
||||
wxString newName = EscapeString( m_SymbolNameCtrl->GetValue(), CTX_LIBID );
|
||||
wxString oldName = m_libEntry->GetName();
|
||||
|
||||
if( newName.IsEmpty() )
|
||||
{
|
||||
wxMessageBox( _( "Symbol must have a name." ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( oldName != newName )
|
||||
{
|
||||
wxString libName = m_Parent->GetCurLib();
|
||||
|
||||
@@ -49,19 +49,20 @@ using CATEGORY = SIM_MODEL::PARAM::CATEGORY;
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symbol& aSymbol,
|
||||
std::vector<T_field>& aFields )
|
||||
: DIALOG_SIM_MODEL_BASE( aParent ),
|
||||
m_symbol( aSymbol ),
|
||||
m_fields( aFields ),
|
||||
m_libraryModelsMgr( &Prj() ),
|
||||
m_builtinModelsMgr( &Prj() ),
|
||||
m_prevModel( nullptr ),
|
||||
m_curModelType( SIM_MODEL::TYPE::NONE ),
|
||||
m_scintillaTricks( nullptr ),
|
||||
m_firstCategory( nullptr ),
|
||||
m_prevParamGridSelection( nullptr ),
|
||||
m_lastParamGridWidth( 0 ),
|
||||
m_inKillFocus( false )
|
||||
std::vector<T_field>& aFields ) :\
|
||||
DIALOG_SIM_MODEL_BASE( aParent ),
|
||||
m_symbol( aSymbol ),
|
||||
m_fields( aFields ),
|
||||
m_libraryModelsMgr( &Prj() ),
|
||||
m_builtinModelsMgr( &Prj() ),
|
||||
m_prevModel( nullptr ),
|
||||
m_curModelType( SIM_MODEL::TYPE::NONE ),
|
||||
m_scintillaTricksCode( nullptr ),
|
||||
m_scintillaTricksSubckt( nullptr ),
|
||||
m_firstCategory( nullptr ),
|
||||
m_prevParamGridSelection( nullptr ),
|
||||
m_lastParamGridWidth( 0 ),
|
||||
m_inKillFocus( false )
|
||||
{
|
||||
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
|
||||
|
||||
@@ -81,7 +82,8 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symb
|
||||
|
||||
m_typeChoice->Clear();
|
||||
|
||||
m_scintillaTricks = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
|
||||
m_scintillaTricksCode = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
|
||||
m_scintillaTricksSubckt = new SCINTILLA_TRICKS( m_subckt, wxT( "()" ), false );
|
||||
|
||||
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this );
|
||||
|
||||
@@ -131,7 +133,8 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::~DIALOG_SIM_MODEL()
|
||||
// Delete the GRID_TRICKS.
|
||||
m_pinAssignmentsGrid->PopEventHandler( true );
|
||||
|
||||
delete m_scintillaTricks;
|
||||
delete m_scintillaTricksCode;
|
||||
delete m_scintillaTricksSubckt;
|
||||
}
|
||||
|
||||
|
||||
@@ -663,6 +666,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments( SIM_MODEL* aMode
|
||||
{
|
||||
SIM_MODEL_SUBCKT* subckt = static_cast<SIM_MODEL_SUBCKT*>( aModel );
|
||||
m_subckt->SetText( subckt->GetSpiceCode() );
|
||||
m_subckt->SetEditable( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -130,7 +130,8 @@ private:
|
||||
std::map<SIM_MODEL::DEVICE_T, SIM_MODEL::TYPE> m_curModelTypeOfDeviceType;
|
||||
SIM_MODEL::TYPE m_curModelType;
|
||||
|
||||
SCINTILLA_TRICKS* m_scintillaTricks;
|
||||
SCINTILLA_TRICKS* m_scintillaTricksCode;
|
||||
SCINTILLA_TRICKS* m_scintillaTricksSubckt;
|
||||
|
||||
wxPGProperty* m_firstCategory; // Used to add principal parameters to root.
|
||||
wxPGProperty* m_prevParamGridSelection;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2017-2023 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
|
||||
@@ -54,10 +54,16 @@ DIALOG_SYMBOL_REMAP::DIALOG_SYMBOL_REMAP( SCH_EDIT_FRAME* aParent ) :
|
||||
{
|
||||
m_remapped = false;
|
||||
|
||||
if( !wxFileName::IsDirWritable( Prj().GetProjectPath() ) )
|
||||
wxString projectPath = Prj().GetProjectPath();
|
||||
|
||||
if( !wxFileName::IsDirWritable( projectPath ) )
|
||||
{
|
||||
DisplayInfoMessage( this, _( "Remapping is not possible because you have insufficient "
|
||||
"privileges to the project folder '%s'." ) );
|
||||
wxString msg =
|
||||
wxString::Format( _( "Remapping is not possible because you have insufficient "
|
||||
"privileges to the project folder '%s'." ),
|
||||
projectPath );
|
||||
|
||||
DisplayInfoMessage( this, msg );
|
||||
|
||||
// Disable the remap button.
|
||||
m_remapped = true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
@@ -296,10 +296,10 @@ DIALOG_TEXT_PROPERTIES_BASE::DIALOG_TEXT_PROPERTIES_BASE( wxWindow* parent, wxWi
|
||||
bSizer11 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_hyperlinkCombo = new WX_COMBOBOX( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
|
||||
bSizer11->Add( m_hyperlinkCombo, 1, wxALIGN_CENTER_VERTICAL, 5 );
|
||||
bSizer11->Add( m_hyperlinkCombo, 1, wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE, 5 );
|
||||
|
||||
|
||||
m_textEntrySizer->Add( bSizer11, wxGBPosition( 9, 1 ), wxGBSpan( 1, 6 ), wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
m_textEntrySizer->Add( bSizer11, wxGBPosition( 9, 1 ), wxGBSpan( 1, 5 ), wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
m_textEntrySizer->AddGrowableCol( 3 );
|
||||
|
||||
@@ -2925,7 +2925,7 @@
|
||||
</object>
|
||||
<object class="gbsizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="colspan">6</property>
|
||||
<property name="colspan">5</property>
|
||||
<property name="column">1</property>
|
||||
<property name="flag">wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="row">9</property>
|
||||
@@ -2937,7 +2937,7 @@
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBitmapComboBox" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
||||
+4
-18
@@ -619,8 +619,6 @@ int ERC_TESTER::TestPinToPin()
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::pair<ERC_SCH_PIN_CONTEXT, ERC_SCH_PIN_CONTEXT>> tested;
|
||||
|
||||
ERC_SCH_PIN_CONTEXT needsDriver;
|
||||
bool hasDriver = false;
|
||||
|
||||
@@ -638,8 +636,9 @@ int ERC_TESTER::TestPinToPin()
|
||||
}
|
||||
}
|
||||
|
||||
for( ERC_SCH_PIN_CONTEXT& refPin : pins )
|
||||
for( auto refIt = pins.begin(); refIt != pins.end(); ++refIt )
|
||||
{
|
||||
ERC_SCH_PIN_CONTEXT& refPin = *refIt;
|
||||
ELECTRICAL_PINTYPE refType = refPin.Pin()->GetType();
|
||||
|
||||
if( DrivenPinTypes.count( refType ) )
|
||||
@@ -663,22 +662,9 @@ int ERC_TESTER::TestPinToPin()
|
||||
else
|
||||
hasDriver |= ( DrivingPinTypes.count( refType ) != 0 );
|
||||
|
||||
for( ERC_SCH_PIN_CONTEXT& testPin : pins )
|
||||
for( auto testIt = refIt + 1; testIt != pins.end(); ++testIt )
|
||||
{
|
||||
if( testPin == refPin )
|
||||
continue;
|
||||
|
||||
ERC_SCH_PIN_CONTEXT first_pin = refPin;
|
||||
ERC_SCH_PIN_CONTEXT second_pin = testPin;
|
||||
|
||||
if( second_pin < first_pin )
|
||||
std::swap( first_pin, second_pin );
|
||||
|
||||
std::pair<ERC_SCH_PIN_CONTEXT, ERC_SCH_PIN_CONTEXT> pair =
|
||||
std::make_pair( first_pin, second_pin );
|
||||
|
||||
if( auto [ins_pin, inserted ] = tested.insert( pair ); !inserted )
|
||||
continue;
|
||||
ERC_SCH_PIN_CONTEXT& testPin = *testIt;
|
||||
|
||||
// Multiple pins in the same symbol that share a type,
|
||||
// name and position are considered
|
||||
|
||||
@@ -580,7 +580,7 @@ wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
|
||||
return StringFromBool( field.IsNameShown() );
|
||||
|
||||
case FDC_H_ALIGN:
|
||||
switch ( field.GetHorizJustify() )
|
||||
switch ( field.GetEffectiveHorizJustify() )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: return _( "Left" );
|
||||
case GR_TEXT_H_ALIGN_CENTER: return _( "Center" );
|
||||
@@ -590,7 +590,7 @@ wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
|
||||
break;
|
||||
|
||||
case FDC_V_ALIGN:
|
||||
switch ( field.GetVertJustify() )
|
||||
switch ( field.GetEffectiveVertJustify() )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: return _( "Top" );
|
||||
case GR_TEXT_V_ALIGN_CENTER: return _( "Center" );
|
||||
@@ -727,28 +727,52 @@ void FIELDS_GRID_TABLE<T>::SetValue( int aRow, int aCol, const wxString &aValue
|
||||
break;
|
||||
|
||||
case FDC_H_ALIGN:
|
||||
{
|
||||
GR_TEXT_H_ALIGN_T horizontalJustification;
|
||||
|
||||
if( value == _( "Left" ) )
|
||||
field.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
||||
horizontalJustification = GR_TEXT_H_ALIGN_LEFT;
|
||||
else if( value == _( "Center" ) )
|
||||
field.SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
horizontalJustification = GR_TEXT_H_ALIGN_CENTER;
|
||||
else if( value == _( "Right" ) )
|
||||
field.SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
|
||||
horizontalJustification = GR_TEXT_H_ALIGN_RIGHT;
|
||||
else
|
||||
wxFAIL_MSG( wxT( "unknown horizontal alignment: " ) + value );
|
||||
|
||||
// Note that we must set justifications before we can ask if they're flipped. If the old
|
||||
// justification is center then it won't know (whereas if the new justification is center
|
||||
// the we don't care).
|
||||
field.SetHorizJustify( horizontalJustification );
|
||||
|
||||
if( field.IsHorizJustifyFlipped() )
|
||||
field.SetHorizJustify( EDA_TEXT::MapHorizJustify( - horizontalJustification ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FDC_V_ALIGN:
|
||||
{
|
||||
GR_TEXT_V_ALIGN_T verticalJustification;
|
||||
|
||||
if( value == _( "Top" ) )
|
||||
field.SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
||||
verticalJustification = GR_TEXT_V_ALIGN_TOP;
|
||||
else if( value == _( "Center" ) )
|
||||
field.SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
verticalJustification = GR_TEXT_V_ALIGN_CENTER;
|
||||
else if( value == _( "Bottom" ) )
|
||||
field.SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
||||
verticalJustification = GR_TEXT_V_ALIGN_BOTTOM;
|
||||
else
|
||||
wxFAIL_MSG( wxT( "unknown vertical alignment: " ) + value);
|
||||
|
||||
// Note that we must set justifications before we can ask if they're flipped. If the old
|
||||
// justification is center then it won't know (whereas if the new justification is center
|
||||
// the we don't care).
|
||||
field.SetVertJustify( verticalJustification );
|
||||
|
||||
if( field.IsVertJustifyFlipped() )
|
||||
field.SetVertJustify( EDA_TEXT::MapVertJustify( -verticalJustification ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FDC_ITALIC:
|
||||
field.SetItalic( BoolFromString( value ) );
|
||||
|
||||
+13
-2
@@ -103,7 +103,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
||||
{
|
||||
msg.Printf( _( "Schematic '%s' is already open." ), wx_filename.GetFullName() );
|
||||
|
||||
if( !OverrideLock( this, msg ) )
|
||||
if( !AskOverrideLock( this, msg ) )
|
||||
return false;
|
||||
|
||||
m_file_checker->OverrideLock( false );
|
||||
@@ -465,6 +465,8 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
||||
screen->MigrateSimModels();
|
||||
}
|
||||
|
||||
schematic.PruneOrphanedSymbolInstances( Prj().GetProjectName(), Schematic().GetSheets() );
|
||||
|
||||
Schematic().ConnectionGraph()->Reset();
|
||||
|
||||
SetScreen( GetCurrentSheet().LastScreen() );
|
||||
@@ -590,6 +592,15 @@ void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
|
||||
if( !AskToSaveChanges() )
|
||||
return;
|
||||
|
||||
if( Schematic().RootScreen() && !Schematic().RootScreen()->Items().empty() )
|
||||
{
|
||||
wxString msg = _( "This operation replaces the contents of the current project.\n\n"
|
||||
"Do you want to proceed?" );
|
||||
|
||||
if( !IsOK( this, msg ) )
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the project location if none is set or if we are running in standalone mode
|
||||
bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
|
||||
wxString path = wxPathOnly( Prj().GetProjectFullName() );
|
||||
@@ -1234,7 +1245,7 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
|
||||
msg.Printf( _( "Schematic '%s' is already open by '%s' at '%s'." ), aFileName,
|
||||
m_file_checker->GetUsername(), m_file_checker->GetHostname() );
|
||||
|
||||
if( !OverrideLock( this, msg ) )
|
||||
if( !AskOverrideLock( this, msg ) )
|
||||
return false;
|
||||
|
||||
m_file_checker->OverrideLock();
|
||||
|
||||
@@ -118,6 +118,12 @@ public:
|
||||
|
||||
KIFONT::FONT* getDrawFont() const override;
|
||||
|
||||
bool IsHorizJustifyFlipped() const { return false; }
|
||||
bool IsVertJustifyFlipped() const { return false; }
|
||||
|
||||
GR_TEXT_H_ALIGN_T GetEffectiveHorizJustify() const { return GetHorizJustify(); }
|
||||
GR_TEXT_V_ALIGN_T GetEffectiveVertJustify() const { return GetVertJustify(); }
|
||||
|
||||
/**
|
||||
* Copy parameters of this field to another field. Pointers are not copied.
|
||||
*
|
||||
|
||||
@@ -465,7 +465,7 @@ void LIB_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOf
|
||||
|
||||
text.GetLinePositions( positions, (int) strings_list.Count() );
|
||||
|
||||
TEXT_ATTRIBUTES attrs = GetAttributes();
|
||||
TEXT_ATTRIBUTES attrs = text.GetAttributes();
|
||||
attrs.m_StrokeWidth = penWidth;
|
||||
attrs.m_Multiline = false;
|
||||
|
||||
|
||||
@@ -106,10 +106,14 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
|
||||
ACTION_MENU* submenuImport = new ACTION_MENU( false, selTool );
|
||||
submenuImport->SetTitle( _( "Import" ) );
|
||||
submenuImport->SetIcon( BITMAPS::import );
|
||||
submenuImport->Add( _( "Non-KiCad Schematic..." ),
|
||||
|
||||
if( Kiface().IsSingle() )
|
||||
{
|
||||
submenuImport->Add( _( "Non-KiCad Schematic..." ),
|
||||
_( "Replace current schematic sheet with one imported from another application" ),
|
||||
ID_IMPORT_NON_KICAD_SCH,
|
||||
BITMAPS::import_document );
|
||||
}
|
||||
|
||||
submenuImport->Add( EE_ACTIONS::importFPAssignments, ACTION_MENU::NORMAL, _( "Footprint Assignments..." ) );
|
||||
fileMenu->Add( submenuImport );
|
||||
|
||||
@@ -180,7 +180,7 @@ void SCH_CONNECTION::ConfigureFromLabel( const wxString& aLabel )
|
||||
auto member = std::make_shared< SCH_CONNECTION >( m_parent, m_sheet );
|
||||
member->SetPrefix( prefix );
|
||||
member->SetGraph( m_graph );
|
||||
member->ConfigureFromLabel( alias_member );
|
||||
member->ConfigureFromLabel( EscapeString( alias_member, CTX_NETNAME ) );
|
||||
m_members.push_back( member );
|
||||
}
|
||||
}
|
||||
|
||||
+40
-4
@@ -1037,8 +1037,27 @@ void SCH_LABEL_BASE::Plot( PLOTTER* aPlotter, bool aBackground ) const
|
||||
{
|
||||
aPlotter->PlotText( textpos, color, GetShownText( true ), attrs, font );
|
||||
|
||||
if( s_poly.size() )
|
||||
aPlotter->PlotPoly( s_poly, FILL_T::NO_FILL, penWidth );
|
||||
if( GetShape() == LABEL_FLAG_SHAPE::F_DOT )
|
||||
{
|
||||
aPlotter->MoveTo( s_poly[0] );
|
||||
aPlotter->LineTo( s_poly[1] );
|
||||
|
||||
int diameter = ( s_poly[2] - s_poly[1] ).EuclideanNorm() * 2;
|
||||
aPlotter->FilledCircle( s_poly[2], diameter , FILLED, nullptr );
|
||||
}
|
||||
else if( GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
|
||||
{
|
||||
aPlotter->MoveTo( s_poly[0] );
|
||||
aPlotter->LineTo( s_poly[1] );
|
||||
|
||||
int diameter = ( s_poly[2] - s_poly[1] ).EuclideanNorm() * 2;
|
||||
aPlotter->ThickCircle( s_poly[2], diameter, penWidth, FILLED, nullptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !s_poly.empty() )
|
||||
aPlotter->PlotPoly( s_poly, FILL_T::NO_FILL, penWidth );
|
||||
}
|
||||
|
||||
// Plot attributes to a hypertext menu
|
||||
std::vector<wxString> properties;
|
||||
@@ -1092,8 +1111,25 @@ void SCH_LABEL_BASE::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aO
|
||||
|
||||
CreateGraphicShape( aSettings, s_poly, GetTextPos() + aOffset );
|
||||
|
||||
if( !s_poly.empty() )
|
||||
GRPoly( DC, s_poly.size(), &s_poly[0], false, penWidth, color, color );
|
||||
if( GetShape() == LABEL_FLAG_SHAPE::F_DOT )
|
||||
{
|
||||
GRLine( DC, s_poly[0], s_poly[1], penWidth, color );
|
||||
|
||||
int radius = ( s_poly[2] - s_poly[1] ).EuclideanNorm();
|
||||
GRFilledCircle( DC, s_poly[2], radius, penWidth, color, color );
|
||||
}
|
||||
else if( GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
|
||||
{
|
||||
GRLine( DC, s_poly[0], s_poly[1], penWidth, color );
|
||||
|
||||
int radius = ( s_poly[2] - s_poly[1] ).EuclideanNorm();
|
||||
GRCircle( DC, s_poly[2], radius, penWidth, color );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !s_poly.empty() )
|
||||
GRPoly( DC, s_poly.size(), &s_poly[0], false, penWidth, color, color );
|
||||
}
|
||||
|
||||
for( SCH_FIELD& field : m_fields )
|
||||
field.Print( aSettings, aOffset );
|
||||
|
||||
@@ -110,6 +110,8 @@ public:
|
||||
|
||||
void SetIsDangling( bool isDangling ) { m_isDangling = isDangling; }
|
||||
|
||||
void SetLibPin( LIB_PIN* aLibPin ) { m_libPin = aLibPin; }
|
||||
|
||||
/**
|
||||
* @param aPin Comparison Pin
|
||||
* @return True if aPin is stacked with this pin
|
||||
|
||||
@@ -499,8 +499,17 @@ LIB_SYMBOL* SCH_DATABASE_PLUGIN::loadSymbolFromRow( const wxString& aSymbolName,
|
||||
continue;
|
||||
}
|
||||
|
||||
wxString value( std::any_cast<std::string>( aRow.at( mapping.column ) ).c_str(),
|
||||
wxConvUTF8 );
|
||||
std:: string strValue;
|
||||
|
||||
try
|
||||
{
|
||||
strValue = std::any_cast<std::string>( aRow.at( mapping.column ) );
|
||||
}
|
||||
catch( std::bad_any_cast& e )
|
||||
{
|
||||
}
|
||||
|
||||
wxString value( strValue.c_str(), wxConvUTF8 );
|
||||
|
||||
if( mapping.name == wxT( "Value" ) )
|
||||
{
|
||||
|
||||
@@ -192,6 +192,11 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
|
||||
|
||||
name = FromUTF8();
|
||||
|
||||
// Some symbol LIB_IDs have the '/' character escaped which can break derived symbol links.
|
||||
// The '/' character is no longer an illegal LIB_ID character so it doesn't need to be
|
||||
// escaped.
|
||||
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
|
||||
|
||||
LIB_ID id;
|
||||
int bad_pos = id.Parse( name );
|
||||
|
||||
@@ -268,6 +273,12 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
|
||||
}
|
||||
|
||||
name = FromUTF8();
|
||||
|
||||
// Some symbol LIB_IDs have the '/' character escaped which can break derived
|
||||
// symbol links. The '/' character is no longer an illegal LIB_ID character so
|
||||
// it doesn't need to be escaped.
|
||||
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
|
||||
|
||||
auto it = aSymbolLibMap.find( name );
|
||||
|
||||
if( it == aSymbolLibMap.end() )
|
||||
@@ -293,6 +304,11 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
|
||||
|
||||
name = FromUTF8();
|
||||
|
||||
// Some symbol LIB_IDs have the '/' character escaped which can break derived
|
||||
// symbol links. The '/' character is no longer an illegal LIB_ID character so
|
||||
// it doesn't need to be escaped.
|
||||
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
|
||||
|
||||
if( !name.StartsWith( m_symbolName ) )
|
||||
{
|
||||
error.Printf( _( "Invalid symbol unit name prefix %s" ), name.c_str() );
|
||||
@@ -1678,6 +1694,8 @@ LIB_TEXTBOX* SCH_SEXPR_PARSER::parseTextBox()
|
||||
FILL_PARAMS fill;
|
||||
std::unique_ptr<LIB_TEXTBOX> textBox = std::make_unique<LIB_TEXTBOX>( nullptr );
|
||||
|
||||
textBox->SetUnit( m_unit );
|
||||
textBox->SetConvert( m_convert );
|
||||
token = NextTok();
|
||||
|
||||
if( token == T_private )
|
||||
@@ -2593,6 +2611,11 @@ SCH_SYMBOL* SCH_SEXPR_PARSER::parseSchematicSymbol()
|
||||
}
|
||||
|
||||
libName = FromUTF8();
|
||||
// Some symbol LIB_IDs or lib_name have the '/' character escaped which can break
|
||||
// symbol links. The '/' character is no longer an illegal LIB_ID character so
|
||||
// it doesn't need to be escaped.
|
||||
libName.Replace( "{slash}", "/" );
|
||||
|
||||
NeedRIGHT();
|
||||
break;
|
||||
}
|
||||
@@ -2606,6 +2629,11 @@ SCH_SYMBOL* SCH_SEXPR_PARSER::parseSchematicSymbol()
|
||||
|
||||
LIB_ID libId;
|
||||
wxString name = FromUTF8();
|
||||
// Some symbol LIB_IDs have the '/' character escaped which can break
|
||||
// symbol links. The '/' character is no longer an illegal LIB_ID character so
|
||||
// it doesn't need to be escaped.
|
||||
name.Replace( "{slash}", "/" );
|
||||
|
||||
int bad_pos = libId.Parse( name );
|
||||
|
||||
if( bad_pos >= 0 )
|
||||
|
||||
@@ -550,10 +550,6 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
|
||||
m_out->Print( 0, ")\n\n" );
|
||||
}
|
||||
|
||||
// Store the selected sheets instance information
|
||||
SCH_SHEET_LIST selectedSheets;
|
||||
SCH_REFERENCE_LIST selectedSymbols;
|
||||
|
||||
for( i = 0; i < aSelection->GetSize(); ++i )
|
||||
{
|
||||
item = (SCH_ITEM*) aSelection->GetItem( i );
|
||||
@@ -561,10 +557,8 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
|
||||
switch( item->Type() )
|
||||
{
|
||||
case SCH_SYMBOL_T:
|
||||
saveSymbol( static_cast<SCH_SYMBOL*>( item ), aSchematic, 0, aForClipboard );
|
||||
|
||||
aSelectionPath->AppendSymbol( selectedSymbols, static_cast<SCH_SYMBOL*>( item ),
|
||||
true, true );
|
||||
saveSymbol( static_cast<SCH_SYMBOL*>( item ), aSchematic, 0, aForClipboard,
|
||||
aSelectionPath );
|
||||
break;
|
||||
|
||||
case SCH_BITMAP_T:
|
||||
@@ -573,15 +567,6 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
|
||||
|
||||
case SCH_SHEET_T:
|
||||
saveSheet( static_cast< SCH_SHEET* >( item ), 0 );
|
||||
|
||||
{
|
||||
SCH_SHEET_PATH subSheetPath = *aSelectionPath;
|
||||
subSheetPath.push_back( static_cast<SCH_SHEET*>( item ) );
|
||||
|
||||
fullHierarchy.GetSheetsWithinPath( selectedSheets, subSheetPath );
|
||||
fullHierarchy.GetSymbolsWithinPath( selectedSymbols, subSheetPath, true, true );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SCH_JUNCTION_T:
|
||||
@@ -621,33 +606,12 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
|
||||
wxASSERT( "Unexpected schematic object type in SCH_SEXPR_PLUGIN::Format()" );
|
||||
}
|
||||
}
|
||||
|
||||
// Make all instance information relative to the selection path
|
||||
KIID_PATH selectionPath = aSelectionPath->Path();
|
||||
|
||||
selectedSheets.SortByPageNumbers();
|
||||
std::vector<SCH_SHEET_INSTANCE> sheetinstances = selectedSheets.GetSheetInstances();
|
||||
|
||||
for( SCH_SHEET_INSTANCE& sheetInstance : sheetinstances )
|
||||
{
|
||||
wxASSERT_MSG( sheetInstance.m_Path.MakeRelativeTo( selectionPath ),
|
||||
"Sheet is not inside the selection path?" );
|
||||
}
|
||||
|
||||
selectionPath = aSelectionPath->Path();
|
||||
selectedSymbols.SortByReferenceOnly();
|
||||
std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = selectedSymbols.GetSymbolInstances();
|
||||
|
||||
for( SCH_SYMBOL_INSTANCE& symbolInstance : symbolInstances )
|
||||
{
|
||||
wxASSERT_MSG( symbolInstance.m_Path.MakeRelativeTo( selectionPath ),
|
||||
"Symbol is not inside the selection path?" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchematic,
|
||||
int aNestLevel, bool aForClipboard )
|
||||
int aNestLevel, bool aForClipboard,
|
||||
const SCH_SHEET_PATH* aRelativePath )
|
||||
{
|
||||
wxCHECK_RET( aSymbol != nullptr && m_out != nullptr, "" );
|
||||
|
||||
@@ -717,6 +681,14 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
|
||||
aSymbol->GetUnit() :
|
||||
aSymbol->GetInstanceReferences()[0].m_Unit;
|
||||
|
||||
if( aForClipboard && aRelativePath )
|
||||
{
|
||||
SCH_SYMBOL_INSTANCE unitInstance;
|
||||
|
||||
if( aSymbol->GetInstance( unitInstance, aRelativePath->Path() ) )
|
||||
unit = unitInstance.m_Unit;
|
||||
}
|
||||
|
||||
m_out->Print( 0, " (unit %d)", unit );
|
||||
|
||||
if( aSymbol->GetConvert() == LIB_ITEM::LIB_CONVERT::DEMORGAN )
|
||||
@@ -759,6 +731,14 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
|
||||
field.SetText( aSymbol->GetField( FOOTPRINT_FIELD )->GetText() );
|
||||
}
|
||||
}
|
||||
else if( aForClipboard && aSymbol->GetInstanceReferences().size() && aRelativePath
|
||||
&& ( id == REFERENCE_FIELD ) )
|
||||
{
|
||||
SCH_SYMBOL_INSTANCE instance;
|
||||
|
||||
if( aSymbol->GetInstance( instance, aRelativePath->Path() ) )
|
||||
field.SetText( instance.m_Reference );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -805,6 +785,9 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
|
||||
|
||||
for( size_t i = 0; i < aSymbol->GetInstanceReferences().size(); i++ )
|
||||
{
|
||||
// Zero length KIID_PATH objects are not valid and will cause a crash below.
|
||||
wxCHECK2( aSymbol->GetInstanceReferences()[i].m_Path.size(), continue );
|
||||
|
||||
// If the instance data is part of this design but no longer has an associated sheet
|
||||
// path, don't save it. This prevents large amounts of orphaned instance data for the
|
||||
// current project from accumulating in the schematic files.
|
||||
@@ -839,7 +822,13 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
|
||||
project_open = true;
|
||||
}
|
||||
|
||||
wxString path = aSymbol->GetInstanceReferences()[i].m_Path.AsString();
|
||||
wxString path;
|
||||
KIID_PATH tmp = aSymbol->GetInstanceReferences()[i].m_Path;
|
||||
|
||||
if( aForClipboard && aRelativePath )
|
||||
tmp.MakeRelativeTo( aRelativePath->Path() );
|
||||
|
||||
path = tmp.AsString();
|
||||
|
||||
m_out->Print( aNestLevel + 3, "(path %s\n",
|
||||
m_out->Quotew( path ).c_str() );
|
||||
|
||||
@@ -146,7 +146,7 @@ private:
|
||||
void loadFile( const wxString& aFileName, SCH_SHEET* aSheet );
|
||||
|
||||
void saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchematic, int aNestLevel,
|
||||
bool aForClipboard );
|
||||
bool aForClipboard, const SCH_SHEET_PATH* aRelativePath = nullptr );
|
||||
void saveField( SCH_FIELD* aField, int aNestLevel );
|
||||
void saveBitmap( SCH_BITMAP* aBitmap, int aNestLevel );
|
||||
void saveSheet( SCH_SHEET* aSheet, int aNestLevel );
|
||||
|
||||
@@ -95,12 +95,23 @@ void SCH_LEGACY_PLUGIN_CACHE::Load()
|
||||
|
||||
m_versionMajor = parseInt( reader, line, &line );
|
||||
|
||||
if( *line != '.' )
|
||||
SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
|
||||
if( *line == '/' )
|
||||
{
|
||||
// Some old libraries use a version syntax like
|
||||
// EESchema-LIBRARY Version 2/10/2006-18:49:15
|
||||
// use 2.3 version numer to read the file
|
||||
m_versionMajor = 2;
|
||||
m_versionMinor = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( *line != '.' )
|
||||
SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
|
||||
|
||||
line++;
|
||||
line++;
|
||||
|
||||
m_versionMinor = parseInt( reader, line, &line );
|
||||
m_versionMinor = parseInt( reader, line, &line );
|
||||
}
|
||||
|
||||
if( m_versionMajor < 1 || m_versionMinor < 0 || m_versionMinor > 99 )
|
||||
SCH_PARSE_ERROR( "invalid file version in header", reader, line );
|
||||
@@ -746,6 +757,68 @@ FILL_T SCH_LEGACY_PLUGIN_CACHE::parseFillMode( LINE_READER& aReader, const char*
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function based on version 6.0 is required for reading legacy arcs.
|
||||
* Changing it in any way will likely break arcs.
|
||||
*/
|
||||
static bool MapAnglesV6( int* aAngle1, int* aAngle2 )
|
||||
{
|
||||
auto DECIDEG2RAD = []( double deg ) -> double
|
||||
{
|
||||
return deg * M_PI / 1800.0;
|
||||
};
|
||||
|
||||
int angle, delta;
|
||||
double x, y;
|
||||
bool swap = false;
|
||||
|
||||
delta = *aAngle2 - *aAngle1;
|
||||
|
||||
if( delta >= 1800 )
|
||||
{
|
||||
*aAngle1 -= 1;
|
||||
*aAngle2 += 1;
|
||||
}
|
||||
|
||||
x = cos( DECIDEG2RAD( *aAngle1 ) );
|
||||
y = -sin( DECIDEG2RAD( *aAngle1 ) );
|
||||
*aAngle1 = KiROUND( RAD2DECIDEG( atan2( y, x ) ) );
|
||||
|
||||
x = cos( DECIDEG2RAD( *aAngle2 ) );
|
||||
y = -sin( DECIDEG2RAD( *aAngle2 ) );
|
||||
*aAngle2 = KiROUND( RAD2DECIDEG( atan2( y, x ) ) );
|
||||
|
||||
NORMALIZE_ANGLE_POS( *aAngle1 );
|
||||
NORMALIZE_ANGLE_POS( *aAngle2 );
|
||||
|
||||
if( *aAngle2 < *aAngle1 )
|
||||
*aAngle2 += 3600;
|
||||
|
||||
if( *aAngle2 - *aAngle1 > 1800 ) // Need to swap the two angles
|
||||
{
|
||||
angle = ( *aAngle1 );
|
||||
*aAngle1 = ( *aAngle2 );
|
||||
*aAngle2 = angle;
|
||||
|
||||
NORMALIZE_ANGLE_POS( *aAngle1 );
|
||||
NORMALIZE_ANGLE_POS( *aAngle2 );
|
||||
|
||||
if( *aAngle2 < *aAngle1 )
|
||||
*aAngle2 += 3600;
|
||||
|
||||
swap = true;
|
||||
}
|
||||
|
||||
if( delta >= 1800 )
|
||||
{
|
||||
*aAngle1 += 1;
|
||||
*aAngle2 -= 1;
|
||||
}
|
||||
|
||||
return swap;
|
||||
}
|
||||
|
||||
|
||||
LIB_SHAPE* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_SYMBOL>& aSymbol,
|
||||
LINE_READER& aReader )
|
||||
{
|
||||
@@ -762,10 +835,12 @@ LIB_SHAPE* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_SYMBOL>& aSymbo
|
||||
|
||||
arc->SetPosition( center );
|
||||
|
||||
(void) schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
|
||||
int radius = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
|
||||
int angle1 = parseInt( aReader, line, &line );
|
||||
int angle2 = parseInt( aReader, line, &line );
|
||||
|
||||
EDA_ANGLE angle1( parseInt( aReader, line, &line ), TENTHS_OF_A_DEGREE_T );
|
||||
EDA_ANGLE angle2( parseInt( aReader, line, &line ), TENTHS_OF_A_DEGREE_T );
|
||||
NORMALIZE_ANGLE_POS( angle1 );
|
||||
NORMALIZE_ANGLE_POS( angle2 );
|
||||
|
||||
arc->SetUnit( parseInt( aReader, line, &line ) );
|
||||
arc->SetConvert( parseInt( aReader, line, &line ) );
|
||||
@@ -792,38 +867,33 @@ LIB_SHAPE* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_SYMBOL>& aSymbo
|
||||
arc->SetStart( arcStart );
|
||||
arc->SetEnd( arcEnd );
|
||||
}
|
||||
// Actual Coordinates of arc ends are not read from file (old library), calculate them
|
||||
else
|
||||
{
|
||||
arc->SetArcAngleAndEnd( angle2 - angle1, true );
|
||||
// Actual Coordinates of arc ends are not read from file
|
||||
// (old library), calculate them
|
||||
VECTOR2I arcStart( radius, 0 );
|
||||
VECTOR2I arcEnd( radius, 0 );
|
||||
|
||||
RotatePoint( arcStart, EDA_ANGLE( -angle1, EDA_ANGLE_T::TENTHS_OF_A_DEGREE_T ) );
|
||||
arcStart += arc->GetCenter();
|
||||
arc->SetStart( arcStart );
|
||||
RotatePoint( arcEnd, EDA_ANGLE( -angle2, EDA_ANGLE_T::TENTHS_OF_A_DEGREE_T ) );
|
||||
arcEnd += arc->GetCenter();
|
||||
arc->SetEnd( arcEnd );
|
||||
}
|
||||
|
||||
/*
|
||||
* Current file format stores start-mid-end and so doesn't care about winding. We
|
||||
* store start-end with an implied winding internally though.
|
||||
* This issue is only for 180 deg arcs, because 180 deg are a limit to handle arcs in
|
||||
* legacy libs.
|
||||
*
|
||||
* So a workaround is to slightly change the arc angle to
|
||||
* avoid 180 deg arc after correction
|
||||
/**
|
||||
* This accounts for an oddity in the old library format, where the symbol is overdefined.
|
||||
* The previous draw (based on wxwidgets) used start point and end point and always drew
|
||||
* counter-clockwise. The new GAL draw takes center, radius and start/end angles. All of
|
||||
* these points were stored in the file, so we need to mimic the swapping of start/end
|
||||
* points rather than using the stored angles in order to properly map edge cases.
|
||||
*/
|
||||
EDA_ANGLE arc_angle = arc->GetArcAngle();
|
||||
|
||||
if( arc_angle == ANGLE_180 )
|
||||
if( !MapAnglesV6( &angle1, &angle2 ) )
|
||||
{
|
||||
VECTOR2I new_center = CalcArcCenter( arc->GetStart(), arc->GetEnd(),
|
||||
EDA_ANGLE( 179.5, DEGREES_T ) );
|
||||
arc->SetCenter( new_center );
|
||||
}
|
||||
|
||||
// In legacy libraries, an arc angle is always <= 180.0 degrees
|
||||
// So if the created arc is > 180 degrees, swap arc ends to have a < 180 deg arc.
|
||||
if( arc->GetArcAngle() > ANGLE_180 )
|
||||
{
|
||||
VECTOR2I new_end = arc->GetStart();
|
||||
VECTOR2I new_start = arc->GetEnd();
|
||||
arc->SetStart( new_start );
|
||||
arc->SetEnd( new_end );
|
||||
VECTOR2I temp = arc->GetStart();
|
||||
arc->SetStart( arc->GetEnd() );
|
||||
arc->SetEnd( temp );
|
||||
}
|
||||
|
||||
return arc;
|
||||
|
||||
@@ -353,6 +353,8 @@ void SCH_LEGACY_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen,
|
||||
aScreen->Append( loadText( aReader ) );
|
||||
else if( strCompare( "BusAlias", line ) )
|
||||
aScreen->AddBusAlias( loadBusAlias( aReader, aScreen ) );
|
||||
else if( strCompare( "Kmarq", line ) )
|
||||
continue; // Ignore legacy (until 2009) ERC marker entry
|
||||
else if( strCompare( "$EndSCHEMATC", line ) )
|
||||
return;
|
||||
else
|
||||
|
||||
+64
-1
@@ -34,6 +34,7 @@
|
||||
#include <project.h>
|
||||
#include <reporter.h>
|
||||
#include <sch_draw_panel.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <sch_item.h>
|
||||
|
||||
@@ -1029,7 +1030,8 @@ void SCH_SCREEN::UpdateSymbolLinks( REPORTER* aReporter )
|
||||
}
|
||||
}
|
||||
|
||||
symbol->SetLibSymbol( libSymbol.release() );
|
||||
if( libSymbol.get() ) // Only change the old link if the new link exists
|
||||
symbol->SetLibSymbol( libSymbol.release() );
|
||||
}
|
||||
|
||||
// Changing the symbol may adjust the bbox of the symbol. This re-inserts the
|
||||
@@ -1174,12 +1176,14 @@ void SCH_SCREEN::Plot( PLOTTER* aPlotter ) const
|
||||
item->Plot( aPlotter, background );
|
||||
}
|
||||
|
||||
// Plot the background items
|
||||
for( const SCH_ITEM* item : other )
|
||||
{
|
||||
aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
|
||||
item->Plot( aPlotter, background );
|
||||
}
|
||||
|
||||
// Plot the foreground items
|
||||
for( const SCH_ITEM* item : other )
|
||||
{
|
||||
aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
|
||||
@@ -1193,7 +1197,10 @@ void SCH_SCREEN::Plot( PLOTTER* aPlotter ) const
|
||||
aPlotter->SetCurrentLineWidth( std::max( sym->GetPenWidth(), defaultPenWidth ) );
|
||||
|
||||
for( SCH_FIELD field : sym->GetFields() )
|
||||
{
|
||||
field.ClearRenderCache();
|
||||
field.Plot( aPlotter, false );
|
||||
}
|
||||
|
||||
sym->PlotPins( aPlotter );
|
||||
|
||||
@@ -1621,6 +1628,51 @@ size_t SCH_SCREEN::getLibSymbolNameMatches( const SCH_SYMBOL& aSymbol,
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREEN::PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
// The project name cannot be empty. Projects older than 7.0 did not save project names
|
||||
// when saving instance data. Running this algorithm with an empty project name would
|
||||
// clobber all instance data for projects other than the current one when a schematic
|
||||
// file is shared across multiple projects.
|
||||
wxCHECK( !aProjectName.IsEmpty(), /* void */ );
|
||||
|
||||
for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
|
||||
{
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
|
||||
wxCHECK2( symbol, continue );
|
||||
|
||||
std::set<KIID_PATH> pathsToPrune;
|
||||
const std::vector<SCH_SYMBOL_INSTANCE> instances = symbol->GetInstanceReferences();
|
||||
|
||||
for( const SCH_SYMBOL_INSTANCE& instance : instances )
|
||||
{
|
||||
// Ignore instance paths from other projects.
|
||||
if( aProjectName != instance.m_ProjectName )
|
||||
continue;
|
||||
|
||||
std::optional<SCH_SHEET_PATH> pathFound =
|
||||
aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
|
||||
|
||||
// Check for paths that do not exist in the current project and paths that do
|
||||
// not contain the current symbol.
|
||||
if( !pathFound )
|
||||
pathsToPrune.emplace( instance.m_Path );
|
||||
else if( pathFound.value().LastScreen() != this )
|
||||
pathsToPrune.emplace( pathFound.value().Path() );
|
||||
}
|
||||
|
||||
for( const KIID_PATH& sheetPath : pathsToPrune )
|
||||
{
|
||||
wxLogTrace( traceSchSheetPaths, wxS( "Pruning project '%s' symbol instance %s." ),
|
||||
aProjectName, sheetPath.AsString() );
|
||||
symbol->RemoveInstance( sheetPath );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const
|
||||
{
|
||||
@@ -2037,3 +2089,14 @@ void SCH_SCREEN::MigrateSimModels()
|
||||
SIM_MODEL::MigrateSimModel<SCH_SYMBOL, SCH_FIELD>( *symbol, &Schematic()->Prj() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREENS::PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
wxCHECK( !aProjectName.IsEmpty(), /* void */ );
|
||||
|
||||
for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
|
||||
screen->PruneOrphanedSymbolInstances( aProjectName, aValidSheetPaths );
|
||||
}
|
||||
|
||||
@@ -545,6 +545,21 @@ public:
|
||||
*/
|
||||
void MigrateSimModels();
|
||||
|
||||
/**
|
||||
* Remove all invalid symbol instance data in this screen object for the project defined
|
||||
* by \a aProjectName and the list of \a aValidSheetPaths.
|
||||
*
|
||||
* @warning This method will assert and exit on debug builds when \a aProjectName is empty.
|
||||
*
|
||||
* @note This method does not affect instance data for any other projects.
|
||||
*
|
||||
* @param aProjectName is the name of the current project.
|
||||
* @param aValidSheetPaths is the list of valid #SCH_SHEET_PATH objects for the current
|
||||
* project.
|
||||
*/
|
||||
void PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
private:
|
||||
friend SCH_EDIT_FRAME; // Only to populate m_symbolInstances.
|
||||
friend SCH_SEXPR_PARSER; // Only to load instance information from schematic file.
|
||||
@@ -793,6 +808,9 @@ public:
|
||||
*/
|
||||
void SetLegacySymbolInstanceData();
|
||||
|
||||
void PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
private:
|
||||
void addScreenToList( SCH_SCREEN* aScreen, SCH_SHEET* aSheet );
|
||||
void buildScreenList( SCH_SHEET* aSheet);
|
||||
|
||||
@@ -1222,6 +1222,39 @@ bool SCH_SHEET::operator <( const SCH_ITEM& aItem ) const
|
||||
}
|
||||
|
||||
|
||||
void SCH_SHEET::RemoveInstance( const KIID_PATH& aInstancePath )
|
||||
{
|
||||
// Search for an existing path and remove it if found (should not occur)
|
||||
for( unsigned ii = 0; ii < m_instances.size(); ii++ )
|
||||
{
|
||||
if( m_instances[ii].m_Path == aInstancePath )
|
||||
{
|
||||
wxLogTrace( traceSchSheetPaths, "Removing sheet instance:\n"
|
||||
" sheet path %s\n"
|
||||
" page %s, from project %s.",
|
||||
aInstancePath.AsString(),
|
||||
m_instances[ii].m_PageNumber,
|
||||
m_instances[ii].m_ProjectName );
|
||||
|
||||
m_instances.erase( m_instances.begin() + ii );
|
||||
ii--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_SHEET::AddInstance( const SCH_SHEET_INSTANCE& aInstance )
|
||||
{
|
||||
SCH_SHEET_INSTANCE oldInstance;
|
||||
|
||||
if( getInstance( oldInstance, aInstance.m_Path ) )
|
||||
RemoveInstance( aInstance.m_Path );
|
||||
|
||||
m_instances.emplace_back( aInstance );
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool SCH_SHEET::addInstance( const SCH_SHEET_PATH& aSheetPath )
|
||||
{
|
||||
wxCHECK( aSheetPath.IsFullPath(), false );
|
||||
|
||||
@@ -409,6 +409,10 @@ public:
|
||||
*/
|
||||
const SCH_SHEET_INSTANCE& GetRootInstance() const;
|
||||
|
||||
void RemoveInstance( const KIID_PATH& aInstancePath );
|
||||
|
||||
void AddInstance( const SCH_SHEET_INSTANCE& aInstance );
|
||||
|
||||
/**
|
||||
* Compares page numbers of schematic sheets.
|
||||
*
|
||||
|
||||
@@ -698,6 +698,11 @@ void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity )
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are not performing a full recursion test, at least check if we are in
|
||||
// a simple recursion scenario to prevent stack overflow crashes
|
||||
wxCHECK2_MSG( sheet->GetFileName() != aSheet->GetFileName(), continue,
|
||||
wxT( "Recursion prevented in SCH_SHEET_LIST::BuildSheetList" ) );
|
||||
|
||||
BuildSheetList( sheet, false );
|
||||
}
|
||||
}
|
||||
|
||||
+134
-23
@@ -177,9 +177,6 @@ SCH_SYMBOL::SCH_SYMBOL( const SCH_SYMBOL& aSymbol ) :
|
||||
m_onBoard = aSymbol.m_onBoard;
|
||||
m_DNP = aSymbol.m_DNP;
|
||||
|
||||
if( aSymbol.m_part )
|
||||
SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part.get() ) );
|
||||
|
||||
const_cast<KIID&>( m_Uuid ) = aSymbol.m_Uuid;
|
||||
|
||||
m_transform = aSymbol.m_transform;
|
||||
@@ -191,6 +188,18 @@ SCH_SYMBOL::SCH_SYMBOL( const SCH_SYMBOL& aSymbol ) :
|
||||
for( SCH_FIELD& field : m_fields )
|
||||
field.SetParent( this );
|
||||
|
||||
m_pins.clear();
|
||||
|
||||
// Copy (and re-parent) the pins
|
||||
for( const std::unique_ptr<SCH_PIN>& pin : aSymbol.m_pins )
|
||||
{
|
||||
m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
|
||||
m_pins.back()->SetParent( this );
|
||||
}
|
||||
|
||||
if( aSymbol.m_part )
|
||||
SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part ) );
|
||||
|
||||
m_fieldsAutoplaced = aSymbol.m_fieldsAutoplaced;
|
||||
m_schLibSymbolName = aSymbol.m_schLibSymbolName;
|
||||
}
|
||||
@@ -333,49 +342,104 @@ wxString SCH_SYMBOL::GetDatasheet() const
|
||||
|
||||
void SCH_SYMBOL::UpdatePins()
|
||||
{
|
||||
std::map<wxString, wxString> altPinMap;
|
||||
std::map<wxString, KIID> pinUuidMap;
|
||||
std::map<wxString, wxString> altPinMap;
|
||||
std::map<wxString, std::set<SCH_PIN*>> pinUuidMap;
|
||||
std::set<SCH_PIN*> unassignedSchPins;
|
||||
std::set<LIB_PIN*> unassignedLibPins;
|
||||
|
||||
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
|
||||
{
|
||||
pinUuidMap[ pin->GetNumber() ] = pin->m_Uuid;
|
||||
pinUuidMap[ pin->GetNumber() ].insert( pin.get() );
|
||||
|
||||
unassignedSchPins.insert( pin.get() );
|
||||
|
||||
if( !pin->GetAlt().IsEmpty() )
|
||||
altPinMap[ pin->GetNumber() ] = pin->GetAlt();
|
||||
}
|
||||
|
||||
m_pins.clear();
|
||||
m_pinMap.clear();
|
||||
|
||||
if( !m_part )
|
||||
return;
|
||||
|
||||
unsigned i = 0;
|
||||
|
||||
std::vector<LIB_PIN*> pins = m_part->GetAllLibPins();
|
||||
|
||||
for( LIB_PIN* libPin : pins )
|
||||
{
|
||||
// NW: Don't filter by unit: this data-structure is used for all instances,
|
||||
// some if which might have different units.
|
||||
// some of which might have different units.
|
||||
if( libPin->GetConvert() && m_convert && m_convert != libPin->GetConvert() )
|
||||
continue;
|
||||
|
||||
m_pins.push_back( std::make_unique<SCH_PIN>( libPin, this ) );
|
||||
SCH_PIN* pin = nullptr;
|
||||
|
||||
auto ii = pinUuidMap.find( libPin->GetNumber() );
|
||||
|
||||
if( ii != pinUuidMap.end() )
|
||||
const_cast<KIID&>( m_pins.back()->m_Uuid ) = ii->second;
|
||||
if( ii == pinUuidMap.end() || ii->second.empty() )
|
||||
{
|
||||
unassignedLibPins.insert( libPin );
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = ii->second.begin();
|
||||
pin = *it;
|
||||
ii->second.erase( it );
|
||||
pin->SetLibPin( libPin );
|
||||
pin->SetPosition( libPin->GetPosition() );
|
||||
|
||||
unassignedSchPins.erase( pin );
|
||||
|
||||
auto iii = altPinMap.find( libPin->GetNumber() );
|
||||
|
||||
if( iii != altPinMap.end() )
|
||||
m_pins.back()->SetAlt( iii->second );
|
||||
pin->SetAlt( iii->second );
|
||||
|
||||
m_pinMap[ libPin ] = i;
|
||||
m_pinMap[ libPin ] = pin;
|
||||
}
|
||||
|
||||
++i;
|
||||
// Add any pins that were not found in the symbol
|
||||
for( LIB_PIN* libPin : unassignedLibPins )
|
||||
{
|
||||
SCH_PIN* pin = nullptr;
|
||||
|
||||
// First try to re-use an existing pin
|
||||
if( !unassignedSchPins.empty() )
|
||||
{
|
||||
auto it = unassignedSchPins.begin();
|
||||
pin = *it;
|
||||
unassignedSchPins.erase( it );
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a pin that was not found in the symbol, so create a new one.
|
||||
pin = m_pins.emplace_back( std::make_unique<SCH_PIN>( SCH_PIN( libPin, this ) ) ).get();
|
||||
}
|
||||
|
||||
m_pinMap[ libPin ] = pin;
|
||||
pin->SetLibPin( libPin );
|
||||
pin->SetPosition( libPin->GetPosition() );
|
||||
pin->SetNumber( libPin->GetNumber() );
|
||||
|
||||
auto iii = altPinMap.find( libPin->GetNumber() );
|
||||
|
||||
if( iii != altPinMap.end() )
|
||||
pin->SetAlt( iii->second );
|
||||
}
|
||||
|
||||
// If we have any pins left in the symbol that were not found in the library, remove them.
|
||||
for( auto it1 = m_pins.begin(); it1 != m_pins.end() && !unassignedSchPins.empty(); )
|
||||
{
|
||||
auto it2 = unassignedSchPins.find( it1->get() );
|
||||
|
||||
if( it2 != unassignedSchPins.end() )
|
||||
{
|
||||
it1 = m_pins.erase( it1 );
|
||||
unassignedSchPins.erase( it2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
++it1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,6 +547,17 @@ void SCH_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffse
|
||||
tempPin->SetShape( symbolPin->GetShape() );
|
||||
}
|
||||
|
||||
for( LIB_ITEM& item : tempSymbol.GetDrawItems() )
|
||||
{
|
||||
if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
|
||||
{
|
||||
// Use SCH_FIELD's text resolver
|
||||
SCH_FIELD dummy( (SCH_ITEM*) this, -1 );
|
||||
dummy.SetText( text->GetText() );
|
||||
text->SetText( dummy.GetShownText( false ) );
|
||||
}
|
||||
}
|
||||
|
||||
tempSymbol.Print( aSettings, m_pos + aOffset, m_unit, m_convert, opts, GetDNP() );
|
||||
}
|
||||
else // Use dummy() part if the actual cannot be found.
|
||||
@@ -536,16 +611,22 @@ bool SCH_SYMBOL::GetInstance( SCH_SYMBOL_INSTANCE& aInstance,
|
||||
|
||||
|
||||
void SCH_SYMBOL::RemoveInstance( const SCH_SHEET_PATH& aInstancePath )
|
||||
{
|
||||
RemoveInstance( aInstancePath.Path() );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SYMBOL::RemoveInstance( const KIID_PATH& aInstancePath )
|
||||
{
|
||||
// Search for an existing path and remove it if found (should not occur)
|
||||
for( unsigned ii = 0; ii < m_instanceReferences.size(); ii++ )
|
||||
{
|
||||
if( m_instanceReferences[ii].m_Path == aInstancePath.Path() )
|
||||
if( m_instanceReferences[ii].m_Path == aInstancePath )
|
||||
{
|
||||
wxLogTrace( traceSchSheetPaths, "Removing symbol instance:\n"
|
||||
" sheet path %s\n"
|
||||
" reference %s, unit %d from symbol %s.",
|
||||
aInstancePath.Path().AsString(),
|
||||
aInstancePath.AsString(),
|
||||
m_instanceReferences[ii].m_Reference,
|
||||
m_instanceReferences[ii].m_Unit,
|
||||
m_Uuid.AsString() );
|
||||
@@ -560,7 +641,8 @@ void SCH_SYMBOL::RemoveInstance( const SCH_SHEET_PATH& aInstancePath )
|
||||
void SCH_SYMBOL::SortInstances( bool (*aSortFunction)( const SCH_SYMBOL_INSTANCE& aLhs,
|
||||
const SCH_SYMBOL_INSTANCE& aRhs ) )
|
||||
{
|
||||
std::sort( m_instanceReferences.begin(), m_instanceReferences.end(), aSortFunction );
|
||||
if( m_instanceReferences.size() > 1 )
|
||||
std::sort( m_instanceReferences.begin(), m_instanceReferences.end(), aSortFunction );
|
||||
}
|
||||
|
||||
|
||||
@@ -1057,8 +1139,13 @@ std::vector<LIB_PIN*> SCH_SYMBOL::GetAllLibPins() const
|
||||
|
||||
SCH_PIN* SCH_SYMBOL::GetPin( LIB_PIN* aLibPin ) const
|
||||
{
|
||||
wxASSERT( m_pinMap.count( aLibPin ) );
|
||||
return m_pins[ m_pinMap.at( aLibPin ) ].get();
|
||||
auto it = m_pinMap.find( aLibPin );
|
||||
|
||||
if( it != m_pinMap.end() )
|
||||
return it->second;
|
||||
|
||||
wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1666,7 +1753,17 @@ BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) con
|
||||
|
||||
BOX2I SCH_SYMBOL::GetBodyBoundingBox() const
|
||||
{
|
||||
return doGetBoundingBox( false, false );
|
||||
try
|
||||
{
|
||||
return doGetBoundingBox( false, false );
|
||||
}
|
||||
catch( const boost::bad_pointer& exc )
|
||||
{
|
||||
// This may be overkill and could be an assertion but we are more likely to
|
||||
// find any boost pointer container errors this way.
|
||||
wxLogError( wxT( "Boost bad pointer exception '%s' occurred." ), exc.what() );
|
||||
return BOX2I();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2202,6 +2299,17 @@ void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground ) const
|
||||
tempPin->SetFlags( IS_DANGLING );
|
||||
}
|
||||
|
||||
for( LIB_ITEM& item : tempSymbol.GetDrawItems() )
|
||||
{
|
||||
if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
|
||||
{
|
||||
// Use SCH_FIELD's text resolver
|
||||
SCH_FIELD dummy( (SCH_ITEM*) this, -1 );
|
||||
dummy.SetText( text->GetText() );
|
||||
text->SetText( dummy.GetShownText( false ) );
|
||||
}
|
||||
}
|
||||
|
||||
TRANSFORM temp = GetTransform();
|
||||
aPlotter->StartBlock( nullptr );
|
||||
|
||||
@@ -2210,8 +2318,11 @@ void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground ) const
|
||||
tempSymbol.Plot( aPlotter, GetUnit(), GetConvert(), local_background, m_pos, temp,
|
||||
GetDNP() );
|
||||
|
||||
for( const SCH_FIELD& field : m_fields )
|
||||
for( SCH_FIELD field : m_fields )
|
||||
{
|
||||
field.ClearRenderCache();
|
||||
field.Plot( aPlotter, local_background );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_DNP )
|
||||
|
||||
@@ -146,6 +146,7 @@ public:
|
||||
const KIID_PATH& aSheetPath, bool aTestFromEnd = false ) const;
|
||||
|
||||
void RemoveInstance( const SCH_SHEET_PATH& aInstancePath );
|
||||
void RemoveInstance( const KIID_PATH& aInstancePath );
|
||||
|
||||
void RemoveAllInstances() { m_instanceReferences.clear(); }
|
||||
|
||||
@@ -800,7 +801,7 @@ private:
|
||||
std::unique_ptr< LIB_SYMBOL > m_part; ///< a flattened copy of the LIB_SYMBOL
|
||||
///< from the PROJECT's libraries.
|
||||
std::vector<std::unique_ptr<SCH_PIN>> m_pins; ///< a SCH_PIN for every LIB_PIN (all units)
|
||||
std::unordered_map<LIB_PIN*, unsigned> m_pinMap; ///< library pin pointer : SCH_PIN's index
|
||||
std::unordered_map<LIB_PIN*, SCH_PIN*> m_pinMap; ///< library pin pointer : SCH_PIN's index
|
||||
|
||||
bool m_isInNetlist; ///< True if the symbol should appear in the netlist
|
||||
bool m_inBom; ///< True to include in bill of materials export.
|
||||
|
||||
@@ -1135,8 +1135,8 @@ bool IbisParser::readString( std::string& aDest )
|
||||
|
||||
if( len < 1 )
|
||||
{
|
||||
Report( _( "Unable to read string, input is empty." ), RPT_SEVERITY_ERROR );
|
||||
return false;
|
||||
// The data is likely on the next line. Skip.
|
||||
return true;
|
||||
}
|
||||
|
||||
char c = aDest[len - 1];
|
||||
@@ -1436,6 +1436,20 @@ bool IbisParser::readRamp()
|
||||
}
|
||||
|
||||
|
||||
bool IbisParser::readModelSpec()
|
||||
{
|
||||
bool status = true;
|
||||
|
||||
m_continue = IBIS_PARSER_CONTINUE::MODEL_SPEC;
|
||||
|
||||
// TODO
|
||||
// readTypMinMaxValueSubparam( std::string( "Vmeas" ), m_currentModel->... )
|
||||
// ...
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
bool IbisParser::parseModel( std::string& aKeyword )
|
||||
{
|
||||
bool status = false;
|
||||
@@ -1458,6 +1472,8 @@ bool IbisParser::parseModel( std::string& aKeyword )
|
||||
status = readWaveform( nullptr, IBIS_WAVEFORM_TYPE::FALLING );
|
||||
else if( compareIbisWord( aKeyword.c_str(), "Ramp" ) )
|
||||
status = readRamp();
|
||||
else if( compareIbisWord( aKeyword.c_str(), "Model_Spec" ) )
|
||||
status = readModelSpec();
|
||||
else if( compareIbisWord( aKeyword.c_str(), "Pullup_Reference" ) )
|
||||
status = readTypMinMaxValue( m_currentModel->m_pullupReference );
|
||||
else if( compareIbisWord( aKeyword.c_str(), "Pulldown_Reference" ) )
|
||||
@@ -1930,39 +1946,39 @@ bool IbisParser::readModel()
|
||||
{
|
||||
if( readWord( subparam ) )
|
||||
{
|
||||
if( !compareIbisWord( subparam.c_str(), "Input" ) )
|
||||
if( compareIbisWord( subparam.c_str(), "Input" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::INPUT_STD;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Output" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Output" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::OUTPUT;
|
||||
else if( !compareIbisWord( subparam.c_str(), "I/O" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "I/O" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::IO;
|
||||
else if( !compareIbisWord( subparam.c_str(), "3-state" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "3-state" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::THREE_STATE;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Open_drain" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Open_drain" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::OPEN_DRAIN;
|
||||
else if( !compareIbisWord( subparam.c_str(), "I/O_Open_drain" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "I/O_Open_drain" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::IO_OPEN_DRAIN;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Open_sink" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Open_sink" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::OPEN_SINK;
|
||||
else if( !compareIbisWord( subparam.c_str(), "I/O_open_sink" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "I/O_open_sink" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::IO_OPEN_SINK;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Open_source" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Open_source" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::OPEN_SOURCE;
|
||||
else if( !compareIbisWord( subparam.c_str(), "I/O_open_source" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "I/O_open_source" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::IO_OPEN_SOURCE;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Input_ECL" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Input_ECL" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::INPUT_ECL;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Output_ECL" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Output_ECL" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::OUTPUT_ECL;
|
||||
else if( !compareIbisWord( subparam.c_str(), "I/O_ECL" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "I/O_ECL" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::IO_ECL;
|
||||
else if( !compareIbisWord( subparam.c_str(), "3-state_ECL" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "3-state_ECL" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::THREE_STATE_ECL;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Terminator" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Terminator" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::TERMINATOR;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Series" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Series" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::SERIES;
|
||||
else if( !compareIbisWord( subparam.c_str(), "Series_switch" ) )
|
||||
else if( compareIbisWord( subparam.c_str(), "Series_switch" ) )
|
||||
m_currentModel->m_type = IBIS_MODEL_TYPE::SERIES_SWITCH;
|
||||
else
|
||||
{
|
||||
@@ -2577,6 +2593,7 @@ bool IbisParser::onNewLine()
|
||||
status &= readWaveform( m_currentWaveform, m_currentWaveform->m_type );
|
||||
break;
|
||||
case IBIS_PARSER_CONTINUE::RAMP: status &= readRamp(); break;
|
||||
case IBIS_PARSER_CONTINUE::MODEL_SPEC: status &= readModelSpec(); break;
|
||||
case IBIS_PARSER_CONTINUE::PACKAGEMODEL_PINS: status &= readPackageModelPins(); break;
|
||||
case IBIS_PARSER_CONTINUE::MATRIX: status &= readMatrix( m_currentMatrix ); break;
|
||||
case IBIS_PARSER_CONTINUE::NONE:
|
||||
|
||||
@@ -632,6 +632,7 @@ enum class IBIS_PARSER_CONTINUE
|
||||
MATRIX,
|
||||
MODELSELECTOR,
|
||||
MODEL,
|
||||
MODEL_SPEC,
|
||||
IV_TABLE,
|
||||
VT_TABLE,
|
||||
RAMP,
|
||||
@@ -772,6 +773,7 @@ private:
|
||||
bool readMatrixSparse( std::string, IBIS_MATRIX_SPARSE& aDest );
|
||||
bool readRampdvdt( dvdtTypMinMax& aDest );
|
||||
bool readRamp();
|
||||
bool readModelSpec();
|
||||
bool readWaveform( IbisWaveform* aDest, IBIS_WAVEFORM_TYPE aType );
|
||||
bool readString( std::string& aDest );
|
||||
bool storeString( std::string& aDest, bool aMultiline );
|
||||
|
||||
@@ -617,6 +617,7 @@ std::string NGSPICE::findCmPath() const
|
||||
"/../../../../../Contents/PlugIns/sim/ngspice",
|
||||
"../Plugins/sim/ngspice",
|
||||
#endif
|
||||
"../eeschema/ngspice",
|
||||
"../lib/ngspice",
|
||||
"../../lib/ngspice",
|
||||
"lib/ngspice",
|
||||
|
||||
@@ -73,10 +73,11 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
|
||||
}
|
||||
|
||||
if( m_model.GetSpiceInfo().inlineTypeString != ""
|
||||
&& m_model.GetType() != SIM_MODEL::TYPE::V ) // DC-only sources are already processed
|
||||
&& m_model.GetType() != SIM_MODEL::TYPE::V // DC-only sources are already processed
|
||||
&& m_model.GetType() != SIM_MODEL::TYPE::I )
|
||||
{
|
||||
std::string args = "";
|
||||
|
||||
|
||||
switch( m_model.GetType() )
|
||||
{
|
||||
case SIM_MODEL::TYPE::V_PWL:
|
||||
@@ -136,31 +137,30 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
|
||||
args.append( getParamValueString( "tcapt", "0" ) + " " );
|
||||
args.append( getParamValueString( "temit", "0" ) + " " );
|
||||
break;
|
||||
|
||||
|
||||
case SIM_MODEL::TYPE::V_RANDUNIFORM:
|
||||
case SIM_MODEL::TYPE::I_RANDUNIFORM:
|
||||
{
|
||||
/* JEY TODO
|
||||
args.append( "1 " );
|
||||
args.append( getParamValueString( "dt", "0" ) + " " );
|
||||
args.append( getParamValueString( "td", "0" ) + " " );
|
||||
std::string min = getParamValueString( "min", "0" );
|
||||
std::string max = getParamValueString( "max", "0" );
|
||||
|
||||
SIM_VALUE_FLOAT min = dynamic_cast<SIM_VALUE_FLOAT&>( m_model.FindParam( "max" )->value );
|
||||
args.append( min + " " );
|
||||
args.append( max + " " );
|
||||
|
||||
if( !min.ToString().empty() )
|
||||
min.FromString( "0" );
|
||||
double minVal = std::stod( min );
|
||||
double maxVal = std::stod( max );
|
||||
|
||||
SIM_VALUE_FLOAT max = dynamic_cast<SIM_VALUE_FLOAT&>( m_model.FindParam( "min" )->value );
|
||||
double rangeVal = maxVal - minVal;
|
||||
double offsetVal = ( maxVal + minVal ) / 2;
|
||||
|
||||
if( !max.ToString().empty() )
|
||||
max.FromString( "0" );
|
||||
std::string range = std::to_string( rangeVal );
|
||||
std::string offset = std::to_string( offsetVal );
|
||||
|
||||
SIM_VALUE_FLOAT range = max - min;
|
||||
SIM_VALUE_FLOAT offset = ( max + min ) / SIM_VALUE_FLOAT( 2 );
|
||||
|
||||
args.append( range.ToSpiceString() + " " );
|
||||
args.append( offset.ToSpiceString() + " " );
|
||||
*/
|
||||
args.append( range + " " );
|
||||
args.append( offset + " " );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -790,7 +790,7 @@ std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_SOURCE::makeWhiteNoiseParamInfos(
|
||||
}
|
||||
|
||||
|
||||
std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_SOURCE::makePinkNoiseParamInfos( std::string aPrefix,
|
||||
std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_SOURCE::makePinkNoiseParamInfos( std::string aPrefix,
|
||||
std::string aUnit )
|
||||
{
|
||||
std::vector<PARAM::INFO> paramInfos;
|
||||
|
||||
@@ -92,29 +92,32 @@ bool SIM_STRING_PROPERTY::OnEvent( wxPropertyGrid* propgrid, wxWindow* wnd_prima
|
||||
{
|
||||
wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wnd_primary );
|
||||
|
||||
if( textEntry )
|
||||
wxCHECK( textEntry, false );
|
||||
|
||||
wxString oldStr = m_eval.OriginalText();
|
||||
|
||||
if( oldStr.length() && oldStr != textEntry->GetValue() )
|
||||
{
|
||||
wxString oldStr = m_eval.OriginalText();
|
||||
|
||||
if( oldStr.length() && oldStr != textEntry->GetValue() )
|
||||
{
|
||||
SetValueInEvent( oldStr );
|
||||
textEntry->SetValue( oldStr );
|
||||
}
|
||||
|
||||
m_needsEval = true;
|
||||
return true;
|
||||
SetValueInEvent( oldStr );
|
||||
textEntry->SetValue( oldStr );
|
||||
}
|
||||
|
||||
m_needsEval = true;
|
||||
return true;
|
||||
}
|
||||
else if( event.GetEventType() == wxEVT_KILL_FOCUS && allowEval() )
|
||||
{
|
||||
wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wnd_primary );
|
||||
|
||||
if( textEntry && m_eval.Process( textEntry->GetValue() ) )
|
||||
wxCHECK( textEntry, false );
|
||||
|
||||
wxString strValue = textEntry->GetValue();
|
||||
|
||||
if( !strValue.IsEmpty() && m_eval.Process( strValue ) )
|
||||
{
|
||||
double value = SIM_VALUE::ToDouble( m_eval.Result().ToStdString() );
|
||||
|
||||
if( isnan( value ) || SIM_VALUE::Equal( value, textEntry->GetValue().ToStdString() ) )
|
||||
if( std::isnan( value ) || SIM_VALUE::Equal( value, strValue.ToStdString() ) )
|
||||
{
|
||||
// Don't mess up user formatting if eval'ing didn't actually change the value.
|
||||
}
|
||||
@@ -122,10 +125,10 @@ bool SIM_STRING_PROPERTY::OnEvent( wxPropertyGrid* propgrid, wxWindow* wnd_prima
|
||||
{
|
||||
SetValueInEvent( m_eval.Result() );
|
||||
}
|
||||
|
||||
m_needsEval = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_needsEval = false;
|
||||
return true;
|
||||
}
|
||||
else if( event.GetEventType() == wxEVT_KEY_DOWN )
|
||||
{
|
||||
@@ -184,17 +187,20 @@ bool SIM_STRING_PROPERTY::StringToValue( wxVariant& aVariant, const wxString& aT
|
||||
|
||||
wxString text = aText;
|
||||
|
||||
if( !aText.IsEmpty() && allowEval() && m_needsEval && m_eval.Process( aText ) )
|
||||
if( allowEval() && m_needsEval && m_eval.Process( aText ) )
|
||||
{
|
||||
double value = SIM_VALUE::ToDouble( m_eval.Result().ToStdString() );
|
||||
if( !aText.IsEmpty() )
|
||||
{
|
||||
double value = SIM_VALUE::ToDouble( m_eval.Result().ToStdString() );
|
||||
|
||||
if( isnan( value ) || SIM_VALUE::Equal( value, aText.ToStdString() ) )
|
||||
{
|
||||
// Don't mess up user formatting if eval'ing didn't actually change the value.
|
||||
}
|
||||
else
|
||||
{
|
||||
text = SIM_VALUE::Normalize( value );
|
||||
if( std::isnan( value ) || SIM_VALUE::Equal( value, aText.ToStdString() ) )
|
||||
{
|
||||
// Don't mess up user formatting if eval'ing didn't actually change the value.
|
||||
}
|
||||
else
|
||||
{
|
||||
text = SIM_VALUE::Normalize( value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -193,9 +193,10 @@ namespace SPICE_GRAMMAR
|
||||
spiceUnit>>> {};
|
||||
|
||||
|
||||
struct modelUnit : sor<dotModelAko,
|
||||
dotModel,
|
||||
dotSubckt> {};
|
||||
struct modelUnit : seq<star<commentLine>,
|
||||
sor<dotModelAko,
|
||||
dotModel,
|
||||
dotSubckt>> {};
|
||||
|
||||
|
||||
// Intentionally no if_must<>.
|
||||
|
||||
@@ -125,6 +125,14 @@ std::vector<SYMBOL_ASYNC_LOADER::LOADED_PAIR> SYMBOL_ASYNC_LOADER::worker()
|
||||
std::lock_guard<std::mutex> lock( m_errorMutex );
|
||||
m_errors += msg;
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
wxString msg = wxString::Format( _( "Error loading symbol library %s.\n\n%s\n" ),
|
||||
nickname, e.what() );
|
||||
|
||||
std::lock_guard<std::mutex> lock( m_errorMutex );
|
||||
m_errors += msg;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -170,7 +170,7 @@ SYMBOL_EDIT_FRAME::SYMBOL_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
ReCreateVToolbar();
|
||||
ReCreateOptToolbar();
|
||||
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
UpdateSymbolMsgPanelInfo();
|
||||
RebuildSymbolUnitsList();
|
||||
|
||||
@@ -558,7 +558,7 @@ bool SYMBOL_EDIT_FRAME::CanCloseSymbolFromSchematic( bool doClose )
|
||||
if( doClose )
|
||||
{
|
||||
SetCurSymbol( nullptr, false );
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -849,7 +849,7 @@ void SYMBOL_EDIT_FRAME::OnModify()
|
||||
m_treePane->GetLibTree()->RefreshLibTree();
|
||||
|
||||
if( !GetTitle().StartsWith( "*" ) )
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
|
||||
@@ -1224,7 +1224,7 @@ void SYMBOL_EDIT_FRAME::ShowChangedLanguage()
|
||||
GetCanvas()->Refresh();
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
|
||||
@@ -1518,7 +1518,7 @@ void SYMBOL_EDIT_FRAME::LoadSymbolFromSchematic( SCH_SYMBOL* aSymbol )
|
||||
OnToggleSymbolTree( evt );
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
RebuildSymbolUnitsList();
|
||||
SetShowDeMorgan( GetCurSymbol()->HasConversion() );
|
||||
UpdateSymbolMsgPanelInfo();
|
||||
|
||||
@@ -247,6 +247,12 @@ public:
|
||||
UpdateSymbolMsgPanelInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the main window title bar with the current library name and read only status
|
||||
* of the library.
|
||||
*/
|
||||
void UpdateTitle();
|
||||
|
||||
bool IsSymbolFromSchematic() const
|
||||
{
|
||||
// If we've already vetted closing this window, then we have no symbol anymore
|
||||
@@ -427,12 +433,6 @@ private:
|
||||
*/
|
||||
bool saveLibrary( const wxString& aLibrary, bool aNewFile );
|
||||
|
||||
/**
|
||||
* Update the main window title bar with the current library name and read only status
|
||||
* of the library.
|
||||
*/
|
||||
void updateTitle();
|
||||
|
||||
/**
|
||||
* Set the current active library to \a aLibrary.
|
||||
*
|
||||
|
||||
@@ -56,7 +56,7 @@ SYMBOL_SAVEAS_TYPE SYMBOL_LEGACYFILEDLG_SAVE_AS::m_option = SYMBOL_SAVEAS_TYPE::
|
||||
#endif
|
||||
|
||||
|
||||
void SYMBOL_EDIT_FRAME::updateTitle()
|
||||
void SYMBOL_EDIT_FRAME::UpdateTitle()
|
||||
{
|
||||
wxString title;
|
||||
|
||||
@@ -98,7 +98,7 @@ void SYMBOL_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
|
||||
if( !selectedLib.empty() )
|
||||
SetCurLib( selectedLib );
|
||||
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
|
||||
@@ -124,14 +124,20 @@ bool SYMBOL_EDIT_FRAME::saveCurrentSymbol()
|
||||
}
|
||||
else
|
||||
{
|
||||
LIB_ID libId = GetCurSymbol()->GetLibId();
|
||||
const wxString& libName = libId.GetLibNickname();
|
||||
const wxString& symbolName = libId.GetLibItemName();
|
||||
const wxString& libName = GetCurSymbol()->GetLibId().GetLibNickname();
|
||||
|
||||
if( m_libMgr->FlushSymbol( symbolName, libName ) )
|
||||
if( m_libMgr->IsLibraryReadOnly( libName ) )
|
||||
{
|
||||
m_libMgr->ClearSymbolModified( symbolName, libName );
|
||||
return true;
|
||||
wxString msg = wxString::Format( _( "Symbol library '%s' is not writable." ),
|
||||
libName );
|
||||
wxString msg2 = _( "You must save to a different location." );
|
||||
|
||||
if( OKOrCancelDialog( this, _( "Warning" ), msg, msg2 ) == wxID_OK )
|
||||
return saveLibrary( libName, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
return saveLibrary( libName, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,7 +304,7 @@ bool SYMBOL_EDIT_FRAME::LoadOneLibrarySymbolAux( LIB_SYMBOL* aEntry, const wxStr
|
||||
GetInfoBar()->Dismiss();
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
RebuildSymbolUnitsList();
|
||||
SetShowDeMorgan( GetCurSymbol()->HasConversion() );
|
||||
|
||||
@@ -493,7 +499,7 @@ void SYMBOL_EDIT_FRAME::Save()
|
||||
if( IsSymbolTreeShown() )
|
||||
m_treePane->GetLibTree()->RefreshLibTree();
|
||||
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
|
||||
@@ -605,6 +611,7 @@ void SYMBOL_EDIT_FRAME::saveSymbolAs()
|
||||
LIB_ID old_lib_id = symbol->GetLibId();
|
||||
wxString symbolName = old_lib_id.GetLibItemName();
|
||||
wxString libraryName = old_lib_id.GetLibNickname();
|
||||
bool valueFollowsName = symbol->GetValueField().GetText() == symbolName;
|
||||
bool done = false;
|
||||
|
||||
std::unique_ptr<EDA_LIST_DIALOG> dlg;
|
||||
@@ -677,6 +684,9 @@ void SYMBOL_EDIT_FRAME::saveSymbolAs()
|
||||
LIB_SYMBOL new_symbol( *symbol );
|
||||
new_symbol.SetName( symbolName );
|
||||
|
||||
if( valueFollowsName )
|
||||
new_symbol.GetValueField().SetText( symbolName );
|
||||
|
||||
m_libMgr->UpdateSymbol( &new_symbol, libraryName );
|
||||
SyncLibraries( false );
|
||||
m_treePane->GetLibTree()->SelectLibId( LIB_ID( libraryName, new_symbol.GetName() ) );
|
||||
@@ -713,7 +723,7 @@ void SYMBOL_EDIT_FRAME::UpdateAfterSymbolProperties( wxString* aOldName )
|
||||
|
||||
RebuildSymbolUnitsList();
|
||||
SetShowDeMorgan( GetCurSymbol()->Flatten()->HasConversion() );
|
||||
updateTitle();
|
||||
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
|
||||
@@ -1179,12 +1189,7 @@ bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
|
||||
{
|
||||
// If saving under existing name fails then do a Save As..., and if that
|
||||
// fails then cancel close action.
|
||||
if( !m_libMgr->IsLibraryReadOnly( libNickname ) )
|
||||
{
|
||||
if( saveLibrary( libNickname, false ) )
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if( m_libMgr->IsLibraryReadOnly( libNickname ) )
|
||||
{
|
||||
msg.Printf( _( "Symbol library '%s' is not writable." ), libNickname );
|
||||
msg2 = _( "You must save to a different location." );
|
||||
@@ -1210,6 +1215,10 @@ bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( saveLibrary( libNickname, false ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !saveLibrary( libNickname, true ) )
|
||||
retv = false;
|
||||
@@ -1217,7 +1226,7 @@ bool SYMBOL_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
|
||||
}
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromRedoList()
|
||||
|
||||
RebuildSymbolUnitsList();
|
||||
SetShowDeMorgan( symbol->HasConversion() );
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
|
||||
RebuildView();
|
||||
OnModify();
|
||||
@@ -145,7 +145,7 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromUndoList()
|
||||
|
||||
RebuildSymbolUnitsList();
|
||||
SetShowDeMorgan( symbol->HasConversion() );
|
||||
updateTitle();
|
||||
UpdateTitle();
|
||||
|
||||
RebuildView();
|
||||
OnModify();
|
||||
|
||||
@@ -884,8 +884,8 @@ void SYMBOL_VIEWER_FRAME::ClickOnLibList( wxCommandEvent& event )
|
||||
void SYMBOL_VIEWER_FRAME::SetSelectedLibrary( const wxString& aLibraryName,
|
||||
const wxString& aSubLibName )
|
||||
{
|
||||
if( m_currentSymbol.GetUniStringLibNickname() == aLibraryName &&
|
||||
wxString( m_currentSymbol.GetSubLibraryName() ) == aSubLibName )
|
||||
if( m_currentSymbol.GetUniStringLibNickname() == aLibraryName
|
||||
&& m_currentSymbol.GetSubLibraryName().wx_str() == aSubLibName )
|
||||
return;
|
||||
|
||||
m_currentSymbol.SetLibNickname( aLibraryName );
|
||||
|
||||
@@ -1127,6 +1127,7 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
|
||||
}
|
||||
|
||||
SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
|
||||
SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( item );
|
||||
EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
|
||||
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
|
||||
|
||||
@@ -1134,36 +1135,32 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
|
||||
{
|
||||
dist = DistanceLinePoint( line->GetStartPoint(), line->GetEndPoint(), pos );
|
||||
}
|
||||
else if( text )
|
||||
else if( field )
|
||||
{
|
||||
if( SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( text ) )
|
||||
BOX2I box = field->GetBoundingBox();
|
||||
EDA_ANGLE orient = field->GetTextAngle();
|
||||
|
||||
if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
if( field->GetParent() && field->GetParent()->Type() == SCH_SYMBOL_T )
|
||||
if( static_cast<SCH_SYMBOL*>( field->GetParent() )->GetTransform().y1 )
|
||||
{
|
||||
symbol = static_cast<SCH_SYMBOL*>( field->GetParent() );
|
||||
|
||||
VECTOR2I relPos = pos - symbol->GetPosition();
|
||||
relPos = symbol->GetTransform().InverseTransform().TransformCoordinate( relPos );
|
||||
pos = relPos + symbol->GetPosition();
|
||||
|
||||
poss = SEG( pos, pos );
|
||||
if( orient.IsHorizontal() )
|
||||
orient = ANGLE_VERTICAL;
|
||||
else
|
||||
orient = ANGLE_HORIZONTAL;
|
||||
}
|
||||
}
|
||||
|
||||
field->GetEffectiveTextShape( false, box, orient )->Collide( poss, INT_MAX / 2,
|
||||
&dist );
|
||||
}
|
||||
else if( text )
|
||||
{
|
||||
text->GetEffectiveTextShape( false )->Collide( poss, INT_MAX / 2, &dist );
|
||||
}
|
||||
else if( symbol )
|
||||
{
|
||||
try
|
||||
{
|
||||
bbox = symbol->GetBodyBoundingBox();
|
||||
}
|
||||
catch( const boost::bad_pointer& exc )
|
||||
{
|
||||
// This may be overkill and could be an assertion but we are more likely to
|
||||
// find any boost pointer container errors this way.
|
||||
wxLogError( wxT( "Boost bad pointer exception '%s' occurred." ), exc.what() );
|
||||
}
|
||||
bbox = symbol->GetBodyBoundingBox();
|
||||
|
||||
SHAPE_RECT rect( bbox.GetPosition(), bbox.GetWidth(), bbox.GetHeight() );
|
||||
|
||||
@@ -1959,6 +1956,9 @@ void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGro
|
||||
aChild->ClearSelected();
|
||||
else if( aMode == BRIGHTENED )
|
||||
aChild->ClearBrightened();
|
||||
|
||||
if( aGroup )
|
||||
aGroup->Remove( aChild );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@@ -76,12 +76,7 @@ SCH_DRAWING_TOOLS::SCH_DRAWING_TOOLS() :
|
||||
m_lastTextboxStroke( 0, PLOT_DASH_TYPE::DEFAULT, COLOR4D::UNSPECIFIED ),
|
||||
m_mruPath( wxEmptyString ),
|
||||
m_lastAutoLabelRotateOnPlacement( false ),
|
||||
m_inPlaceSymbol( false ),
|
||||
m_inDrawShape( false ),
|
||||
m_inPlaceImage( false ),
|
||||
m_inSingleClickPlace( false ),
|
||||
m_inTwoClickPlace( false ),
|
||||
m_inDrawSheet( false )
|
||||
m_inDrawingTool( false )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -112,10 +107,10 @@ int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
|
||||
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
|
||||
EE_GRID_HELPER grid( m_toolMgr );
|
||||
|
||||
if( m_inPlaceSymbol )
|
||||
if( m_inDrawingTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inPlaceSymbol );
|
||||
REENTRANCY_GUARD guard( &m_inDrawingTool );
|
||||
|
||||
// First we need to get all instances of this sheet so we can annotate
|
||||
// whatever symbols we place on all copies
|
||||
@@ -473,10 +468,10 @@ int SCH_DRAWING_TOOLS::PlaceImage( const TOOL_EVENT& aEvent )
|
||||
bool ignorePrimePosition = false;
|
||||
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
|
||||
|
||||
if( m_inPlaceImage )
|
||||
if( m_inDrawingTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inPlaceImage );
|
||||
REENTRANCY_GUARD guard( &m_inDrawingTool );
|
||||
|
||||
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
|
||||
|
||||
@@ -709,10 +704,10 @@ int SCH_DRAWING_TOOLS::SingleClickPlace( const TOOL_EVENT& aEvent )
|
||||
SCH_ITEM* previewItem;
|
||||
bool loggedInfoBarError = false;
|
||||
|
||||
if( m_inSingleClickPlace )
|
||||
if( m_inDrawingTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inSingleClickPlace );
|
||||
REENTRANCY_GUARD guard( &m_inDrawingTool );
|
||||
|
||||
if( type == SCH_JUNCTION_T && aEvent.HasPosition() )
|
||||
{
|
||||
@@ -1129,10 +1124,10 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
|
||||
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
|
||||
SCH_SHEET* sheet = nullptr;
|
||||
|
||||
if( m_inTwoClickPlace )
|
||||
if( m_inDrawingTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inTwoClickPlace );
|
||||
REENTRANCY_GUARD guard( &m_inDrawingTool );
|
||||
|
||||
bool isText = aEvent.IsAction( &EE_ACTIONS::placeSchematicText );
|
||||
bool isGlobalLabel = aEvent.IsAction( &EE_ACTIONS::placeGlobalLabel );
|
||||
@@ -1520,10 +1515,10 @@ int SCH_DRAWING_TOOLS::DrawShape( const TOOL_EVENT& aEvent )
|
||||
bool isTextBox = aEvent.IsAction( &EE_ACTIONS::drawTextBox );
|
||||
SHAPE_T type = aEvent.Parameter<SHAPE_T>();
|
||||
|
||||
if( m_inDrawShape )
|
||||
if( m_inDrawingTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inDrawShape );
|
||||
REENTRANCY_GUARD guard( &m_inDrawingTool );
|
||||
|
||||
// We might be running as the same shape in another co-routine. Make sure that one
|
||||
// gets whacked.
|
||||
@@ -1739,10 +1734,10 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
SCH_SHEET* sheet = nullptr;
|
||||
|
||||
if( m_inDrawSheet )
|
||||
if( m_inDrawingTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inDrawSheet );
|
||||
REENTRANCY_GUARD guard( &m_inDrawingTool );
|
||||
|
||||
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
|
||||
|
||||
|
||||
@@ -94,14 +94,7 @@ private:
|
||||
wxString m_mruPath;
|
||||
bool m_lastAutoLabelRotateOnPlacement;
|
||||
|
||||
///< Re-entrancy guards
|
||||
bool m_inPlaceSymbol;
|
||||
bool m_inDrawShape;
|
||||
bool m_inPlaceImage;
|
||||
bool m_inSingleClickPlace;
|
||||
bool m_inTwoClickPlace;
|
||||
bool m_inDrawSheet;
|
||||
|
||||
bool m_inDrawingTool; // Re-entrancy guard
|
||||
std::unique_ptr<STATUS_TEXT_POPUP> m_statusPopup;
|
||||
};
|
||||
|
||||
|
||||
@@ -1119,7 +1119,28 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
|
||||
schIUScale.MilsToIU( cfg->m_Drawing.default_repeat_offset_y ) ) );
|
||||
}
|
||||
|
||||
// If cloning a sheet, check that we aren't going to create recursion
|
||||
if( newItem->Type() == SCH_SHEET_T )
|
||||
{
|
||||
SCH_SHEET_PATH* currentSheet = &m_frame->GetCurrentSheet();
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( newItem );
|
||||
|
||||
if( m_frame->CheckSheetForRecursion( sheet, currentSheet ) )
|
||||
{
|
||||
// Clear out the filename so that the user can pick a new one
|
||||
sheet->SetFileName( wxEmptyString );
|
||||
|
||||
if( !m_frame->EditSheetProperties( sheet, currentSheet, nullptr ) )
|
||||
{
|
||||
// User canceled renaming the sheet; skip it
|
||||
delete newItem;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_toolMgr->RunAction( EE_ACTIONS::addItemToSel, true, newItem );
|
||||
|
||||
newItem->SetFlags( IS_NEW );
|
||||
m_frame->AddToScreen( newItem, m_frame->GetScreen() );
|
||||
m_frame->SaveCopyInUndoList( m_frame->GetScreen(), newItem, UNDO_REDO::NEWITEM, appendUndo );
|
||||
|
||||
@@ -332,10 +332,13 @@ void SCH_EDITOR_CONTROL::doCrossProbeSchToPcb( const TOOL_EVENT& aEvent, bool aF
|
||||
|
||||
int SCH_EDITOR_CONTROL::ExportSymbolsToLibrary( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
bool savePowerSymbols = IsOK( m_frame,
|
||||
_( "Include power symbols in schematic to the library?" ) );
|
||||
|
||||
bool createNew = aEvent.IsAction( &EE_ACTIONS::exportSymbolsToNewLibrary );
|
||||
|
||||
SCH_REFERENCE_LIST symbols;
|
||||
m_frame->Schematic().GetSheets().GetSymbols( symbols, false );
|
||||
m_frame->Schematic().GetSheets().GetSymbols( symbols, savePowerSymbols );
|
||||
|
||||
std::map<LIB_ID, LIB_SYMBOL*> libSymbols;
|
||||
std::map<LIB_ID, std::vector<SCH_SYMBOL*>> symbolMap;
|
||||
@@ -423,17 +426,29 @@ int SCH_EDITOR_CONTROL::ExportSymbolsToLibrary( const TOOL_EVENT& aEvent )
|
||||
LIB_SYMBOL* origSym = it.second;
|
||||
LIB_SYMBOL* newSym = origSym->Flatten().release();
|
||||
|
||||
pi->SaveSymbol( dest.GetFullPath(), newSym );
|
||||
try
|
||||
{
|
||||
pi->SaveSymbol( dest.GetFullPath(), newSym );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "Error saving symbol %s to library '%s'." ),
|
||||
newSym->GetName(), row->GetNickName() );
|
||||
msg += wxS( "\n\n" ) + ioe.What();
|
||||
wxLogWarning( msg );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( map )
|
||||
{
|
||||
LIB_ID id = it.first;
|
||||
id.SetLibNickname( targetLib );
|
||||
|
||||
|
||||
for( SCH_SYMBOL* symbol : symbolMap[it.first] )
|
||||
{
|
||||
m_frame->SaveCopyInUndoList( m_frame->GetScreen(), symbol, UNDO_REDO::CHANGED, append, false);
|
||||
m_frame->SaveCopyInUndoList( m_frame->GetScreen(), symbol, UNDO_REDO::CHANGED,
|
||||
append, false );
|
||||
symbol->SetLibId( id );
|
||||
append = true;
|
||||
}
|
||||
@@ -487,6 +502,7 @@ int SCH_EDITOR_CONTROL::ExportSymbolsToLibrary( const TOOL_EVENT& aEvent )
|
||||
for( SCH_SHEET_PATH& sheet : sheets )
|
||||
{
|
||||
SCH_SCREEN* screen = sheet.LastScreen();
|
||||
|
||||
if( processedScreens.find( ( screen ) ) == processedScreens.end() )
|
||||
{
|
||||
processedScreens.insert( screen );
|
||||
@@ -806,18 +822,27 @@ static bool highlightNet( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition )
|
||||
}
|
||||
}
|
||||
|
||||
wxString connectionName = ( conn ) ? conn->Name() : wxS( "" );
|
||||
wxString connectionName = ( conn ) ? conn->Name() : wxString( wxS( "" ) );
|
||||
|
||||
if( !conn || connectionName == editFrame->GetHighlightedConnection() )
|
||||
if( !conn )
|
||||
{
|
||||
editFrame->SetStatusText( wxT( "" ) );
|
||||
editFrame->SendCrossProbeClearHighlight();
|
||||
editFrame->SetHighlightedConnection( wxEmptyString );
|
||||
editorControl->SetHighlightBusMembers( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
editFrame->SetCrossProbeConnection( conn );
|
||||
editFrame->SetHighlightedConnection( connectionName );
|
||||
if( connectionName != editFrame->GetHighlightedConnection() )
|
||||
{
|
||||
editorControl->SetHighlightBusMembers( false );
|
||||
editFrame->SetCrossProbeConnection( conn );
|
||||
editFrame->SetHighlightedConnection( connectionName );
|
||||
}
|
||||
else
|
||||
{
|
||||
editorControl->SetHighlightBusMembers( !editorControl->GetHighlightBusMembers() );
|
||||
}
|
||||
}
|
||||
|
||||
editFrame->UpdateNetHighlightStatus();
|
||||
@@ -1014,155 +1039,162 @@ int SCH_EDITOR_CONTROL::AssignNetclass( const TOOL_EVENT& aEvent )
|
||||
|
||||
int SCH_EDITOR_CONTROL::UpdateNetHighlighting( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
wxCHECK( m_frame, 0 );
|
||||
|
||||
const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
|
||||
SCH_SCREEN* screen = m_frame->GetCurrentSheet().LastScreen();
|
||||
CONNECTION_GRAPH* connectionGraph = m_frame->Schematic().ConnectionGraph();
|
||||
wxString selectedName = m_frame->GetHighlightedConnection();
|
||||
|
||||
std::set<wxString> connNames;
|
||||
std::vector<EDA_ITEM*> itemsToRedraw;
|
||||
|
||||
wxCHECK( screen && connectionGraph, 0 );
|
||||
|
||||
bool selectedIsBus = false;
|
||||
wxString selectedName = m_frame->GetHighlightedConnection();
|
||||
|
||||
bool selectedIsNoNet = false;
|
||||
CONNECTION_SUBGRAPH* selectedSubgraph = nullptr;
|
||||
|
||||
for( SCH_ITEM* item : screen->Items() )
|
||||
if( !selectedName.IsEmpty() )
|
||||
{
|
||||
bool redraw = item->IsBrightened();
|
||||
bool highlight = false;
|
||||
connNames.emplace( selectedName );
|
||||
|
||||
if( !selectedName.IsEmpty() )
|
||||
CONNECTION_SUBGRAPH* sg = connectionGraph->FindSubgraphByName( selectedName, sheetPath );
|
||||
|
||||
if( sg && m_highlightBusMembers )
|
||||
{
|
||||
SCH_CONNECTION* itemConn = nullptr;
|
||||
SCH_SYMBOL* symbol = nullptr;
|
||||
|
||||
if( item->Type() == SCH_SYMBOL_T )
|
||||
symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
|
||||
if( symbol && symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->IsPower() )
|
||||
itemConn = symbol->Connection();
|
||||
else
|
||||
itemConn = item->Connection();
|
||||
|
||||
if( itemConn && ( selectedName == itemConn->Name() ) )
|
||||
for( const SCH_ITEM* item : sg->GetItems() )
|
||||
{
|
||||
selectedIsBus = itemConn->IsBus();
|
||||
wxCHECK2( item, continue );
|
||||
|
||||
if( itemConn->Driver() == nullptr )
|
||||
{
|
||||
selectedIsNoNet = true;
|
||||
selectedSubgraph = connectionGraph->GetSubgraphForItem( itemConn->Parent() );
|
||||
}
|
||||
SCH_CONNECTION* connection = item->Connection();
|
||||
|
||||
if( selectedIsNoNet && selectedSubgraph )
|
||||
wxCHECK2( connection, continue );
|
||||
|
||||
for( const std::shared_ptr<SCH_CONNECTION>& member : connection->AllMembers() )
|
||||
{
|
||||
for( SCH_ITEM* subgraphItem : selectedSubgraph->GetItems() )
|
||||
{
|
||||
if( item == subgraphItem )
|
||||
{
|
||||
highlight = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( selectedIsBus && itemConn && itemConn->IsNet() )
|
||||
{
|
||||
for( const std::shared_ptr<SCH_CONNECTION>& member : itemConn->Members() )
|
||||
{
|
||||
if( member->Name() == itemConn->Name() )
|
||||
{
|
||||
highlight = true;
|
||||
break;
|
||||
}
|
||||
else if( member->IsBus() )
|
||||
{
|
||||
for( const std::shared_ptr<SCH_CONNECTION>& bus_member :
|
||||
member->Members() )
|
||||
{
|
||||
if( bus_member->Name() == itemConn->Name() )
|
||||
{
|
||||
highlight = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( !selectedName.IsEmpty() && itemConn
|
||||
&& ( selectedName == itemConn->Name() ) )
|
||||
{
|
||||
highlight = true;
|
||||
if( member )
|
||||
connNames.emplace( member->Name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( highlight )
|
||||
item->SetBrightened();
|
||||
else
|
||||
item->ClearBrightened();
|
||||
for( SCH_ITEM* item : screen->Items() )
|
||||
{
|
||||
wxCHECK2( item, continue );
|
||||
|
||||
redraw |= item->IsBrightened();
|
||||
if( !item->IsConnectable() )
|
||||
continue;
|
||||
|
||||
SCH_ITEM* redrawItem = nullptr;
|
||||
|
||||
if( item->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
|
||||
redraw |= symbol->HasBrightenedPins();
|
||||
|
||||
symbol->ClearBrightenedPins();
|
||||
wxCHECK2( symbol, continue );
|
||||
|
||||
for( SCH_PIN* pin : symbol->GetPins() )
|
||||
{
|
||||
SCH_CONNECTION* pin_conn = pin->Connection();
|
||||
|
||||
if( pin_conn && pin_conn->Name() == selectedName )
|
||||
wxCHECK2( pin_conn, continue );
|
||||
|
||||
if( !pin->IsBrightened() && connNames.count( pin_conn->Name() ) )
|
||||
{
|
||||
pin->SetBrightened();
|
||||
redraw = true;
|
||||
redrawItem = symbol;
|
||||
}
|
||||
else if( pin->IsBrightened() && !connNames.count( pin_conn->Name() ) )
|
||||
{
|
||||
pin->ClearBrightened();
|
||||
redrawItem = symbol;
|
||||
}
|
||||
}
|
||||
|
||||
if( symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->IsPower() )
|
||||
if( symbol->IsPower() )
|
||||
{
|
||||
wxCHECK2( symbol->GetPins().size(), continue );
|
||||
|
||||
SCH_CONNECTION* pinConn = symbol->GetPins()[0]->Connection();
|
||||
|
||||
wxCHECK2( pinConn, continue );
|
||||
|
||||
std::vector<SCH_FIELD>& fields = symbol->GetFields();
|
||||
|
||||
for( int id : { REFERENCE_FIELD, VALUE_FIELD } )
|
||||
{
|
||||
if( item->IsBrightened() && fields[id].IsVisible() )
|
||||
if( !fields[id].IsVisible() )
|
||||
continue;
|
||||
|
||||
if( !fields[id].IsBrightened() && connNames.count( pinConn->Name() ) )
|
||||
{
|
||||
fields[id].SetBrightened();
|
||||
else
|
||||
redrawItem = symbol;
|
||||
}
|
||||
else if( fields[id].IsBrightened() && !connNames.count( pinConn->Name() ) )
|
||||
{
|
||||
fields[id].ClearBrightened();
|
||||
redrawItem = symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( item->Type() == SCH_SHEET_T )
|
||||
{
|
||||
for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
|
||||
wxCHECK2( sheet, continue );
|
||||
|
||||
for( SCH_SHEET_PIN* pin : sheet->GetPins() )
|
||||
{
|
||||
wxCHECK2( pin, continue );
|
||||
|
||||
SCH_CONNECTION* pin_conn = pin->Connection();
|
||||
bool redrawPin = pin->IsBrightened();
|
||||
|
||||
if( pin_conn && pin_conn->Name() == selectedName )
|
||||
wxCHECK2( pin_conn, continue );
|
||||
|
||||
if( !pin->IsBrightened() && connNames.count( pin_conn->Name() ) )
|
||||
{
|
||||
pin->SetBrightened();
|
||||
else
|
||||
redrawItem = sheet;
|
||||
}
|
||||
else if( pin->IsBrightened() && !connNames.count( pin_conn->Name() ) )
|
||||
{
|
||||
pin->ClearBrightened();
|
||||
redrawItem = sheet;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SCH_CONNECTION* itemConn = item->Connection();
|
||||
|
||||
redrawPin ^= pin->IsBrightened();
|
||||
redraw |= redrawPin;
|
||||
wxCHECK2( itemConn, continue );
|
||||
|
||||
if( !item->IsBrightened() && connNames.count( itemConn->Name() ) )
|
||||
{
|
||||
item->SetBrightened();
|
||||
redrawItem = item;
|
||||
}
|
||||
else if( item->IsBrightened() && !connNames.count( itemConn->Name() ) )
|
||||
{
|
||||
item->ClearBrightened();
|
||||
redrawItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
if( redraw )
|
||||
itemsToRedraw.push_back( item );
|
||||
if( redrawItem )
|
||||
itemsToRedraw.push_back( redrawItem );
|
||||
}
|
||||
|
||||
// Be sure highlight change will be redrawn
|
||||
KIGFX::VIEW* view = getView();
|
||||
if( itemsToRedraw.size() )
|
||||
{
|
||||
// Be sure highlight change will be redrawn
|
||||
KIGFX::VIEW* view = getView();
|
||||
|
||||
for( EDA_ITEM* redrawItem : itemsToRedraw )
|
||||
view->Update( (KIGFX::VIEW_ITEM*)redrawItem, KIGFX::VIEW_UPDATE_FLAGS::REPAINT );
|
||||
for( EDA_ITEM* redrawItem : itemsToRedraw )
|
||||
view->Update( (KIGFX::VIEW_ITEM*)redrawItem, KIGFX::VIEW_UPDATE_FLAGS::REPAINT );
|
||||
|
||||
m_frame->GetCanvas()->Refresh();
|
||||
m_frame->GetCanvas()->Refresh();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1374,19 +1406,19 @@ void SCH_EDITOR_CONTROL::updatePastedSymbol( SCH_SYMBOL* aSymbol, SCH_SCREEN* aP
|
||||
const KIID_PATH& aClipPath,
|
||||
bool aForceKeepAnnotations )
|
||||
{
|
||||
wxCHECK( aSymbol && aPasteScreen, /* void */ );
|
||||
wxCHECK( m_frame && aSymbol && aPasteScreen, /* void */ );
|
||||
|
||||
KIID_PATH clipItemPath = aClipPath;
|
||||
SCH_SYMBOL_INSTANCE instance;
|
||||
KIID_PATH pasteLookupPath = aClipPath;
|
||||
|
||||
wxString reference, value, footprint;
|
||||
int unit;
|
||||
m_pastedSymbols.insert( aSymbol );
|
||||
|
||||
if( m_clipboardSymbolInstances.count( clipItemPath ) > 0 )
|
||||
// The pasted symbol look up paths include the symbol UUID.
|
||||
pasteLookupPath.push_back( aSymbol->m_Uuid );
|
||||
|
||||
if( m_clipboardSymbolInstances.count( pasteLookupPath ) > 0 )
|
||||
{
|
||||
SCH_SYMBOL_INSTANCE instance = m_clipboardSymbolInstances.at( clipItemPath );
|
||||
|
||||
unit = instance.m_Unit;
|
||||
reference = instance.m_Reference;
|
||||
instance = m_clipboardSymbolInstances.at( pasteLookupPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1397,20 +1429,20 @@ void SCH_EDITOR_CONTROL::updatePastedSymbol( SCH_SYMBOL* aSymbol, SCH_SCREEN* aP
|
||||
|
||||
// Pasted from notepad or an older instance of eeschema. Use the values in the fields
|
||||
// instead.
|
||||
reference = aSymbol->GetField( REFERENCE_FIELD )->GetText();
|
||||
value = aSymbol->GetField( VALUE_FIELD )->GetText();
|
||||
footprint = aSymbol->GetField( FOOTPRINT_FIELD )->GetText();
|
||||
unit = aSymbol->GetUnit();
|
||||
instance.m_Reference = aSymbol->GetField( REFERENCE_FIELD )->GetText();
|
||||
instance.m_Unit = aSymbol->GetUnit();
|
||||
}
|
||||
|
||||
if( aForceKeepAnnotations && !reference.IsEmpty() )
|
||||
aSymbol->SetRef( &aPastePath, reference );
|
||||
else
|
||||
instance.m_Path = aPastePath.Path() + aClipPath;
|
||||
instance.m_ProjectName = m_frame->Prj().GetProjectName();
|
||||
|
||||
aSymbol->AddHierarchicalReference( instance );
|
||||
|
||||
if( !aForceKeepAnnotations )
|
||||
aSymbol->ClearAnnotation( &aPastePath, false );
|
||||
|
||||
// We might clear annotations but always leave the original unit number from the paste.
|
||||
aSymbol->SetUnitSelection( &aPastePath, unit );
|
||||
aSymbol->SetUnit( unit );
|
||||
aSymbol->SetUnit( instance.m_Unit );
|
||||
}
|
||||
|
||||
|
||||
@@ -1460,17 +1492,82 @@ SCH_SHEET_PATH SCH_EDITOR_CONTROL::updatePastedSheet( const SCH_SHEET_PATH& aPas
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDITOR_CONTROL::setClipboardInstances( const SCH_SCREEN* aPastedScreen )
|
||||
void SCH_EDITOR_CONTROL::setPastedSheetInstances( const SCH_SHEET* aPastedSheet )
|
||||
{
|
||||
m_clipboardSheetInstances.clear();
|
||||
wxCHECK( aPastedSheet, /* void */ );
|
||||
|
||||
for( const SCH_SHEET_INSTANCE& sheet : aPastedScreen->GetSheetInstances() )
|
||||
m_clipboardSheetInstances[sheet.m_Path] = sheet;
|
||||
for( const SCH_SHEET_INSTANCE& sheetInstance : aPastedSheet->GetInstances() )
|
||||
{
|
||||
KIID_PATH pathWithSheet = sheetInstance.m_Path;
|
||||
|
||||
m_clipboardSymbolInstances.clear();
|
||||
pathWithSheet.push_back( aPastedSheet->m_Uuid );
|
||||
m_clipboardSheetInstances[pathWithSheet] = sheetInstance;
|
||||
}
|
||||
|
||||
for( const SCH_SYMBOL_INSTANCE& symbol : aPastedScreen->GetSymbolInstances() )
|
||||
m_clipboardSymbolInstances[symbol.m_Path] = symbol;
|
||||
const SCH_SCREEN* screen = aPastedSheet->GetScreen();
|
||||
|
||||
wxCHECK( screen, /* void */ );
|
||||
|
||||
for( SCH_ITEM* item : screen->Items() )
|
||||
{
|
||||
if( item->Type() == SCH_SHEET_T )
|
||||
{
|
||||
const SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
|
||||
wxCHECK2( sheet, continue );
|
||||
|
||||
setPastedSheetInstances( sheet );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDITOR_CONTROL::setPastedSymbolInstances( SCH_SCREENS& aScreenList )
|
||||
{
|
||||
for( SCH_SCREEN* screen = aScreenList.GetFirst(); screen; screen = aScreenList.GetNext() )
|
||||
{
|
||||
for( SCH_ITEM* item : screen->Items() )
|
||||
{
|
||||
if( item->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
|
||||
wxCHECK2( symbol, continue );
|
||||
|
||||
for( const SCH_SYMBOL_INSTANCE& symbolInstance : symbol->GetInstanceReferences() )
|
||||
{
|
||||
KIID_PATH pathWithSymbol = symbolInstance.m_Path;
|
||||
|
||||
pathWithSymbol.push_back( symbol->m_Uuid );
|
||||
|
||||
m_clipboardSymbolInstances[pathWithSymbol] = symbolInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDITOR_CONTROL::prunePastedSymbolInstances()
|
||||
{
|
||||
wxCHECK( m_frame, /* void */ );
|
||||
|
||||
for( SCH_SYMBOL* symbol : m_pastedSymbols )
|
||||
{
|
||||
wxCHECK2( symbol, continue );
|
||||
|
||||
std::vector<KIID_PATH> instancePathsToRemove;
|
||||
|
||||
for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstanceReferences() )
|
||||
{
|
||||
if( ( instance.m_ProjectName != m_frame->Prj().GetProjectName() )
|
||||
|| instance.m_Path.empty() )
|
||||
instancePathsToRemove.emplace_back( instance.m_Path );
|
||||
}
|
||||
|
||||
for( const KIID_PATH& path : instancePathsToRemove )
|
||||
symbol->RemoveInstance( path );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1523,8 +1620,15 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
tempScreen->Append( text_item );
|
||||
}
|
||||
|
||||
// Save loaded screen instances to m_clipboardSheetInstances
|
||||
setClipboardInstances( tempScreen );
|
||||
SCH_SCREENS tempScreens( tempSheet );
|
||||
|
||||
m_pastedSymbols.clear();
|
||||
m_clipboardSheetInstances.clear();
|
||||
m_clipboardSymbolInstances.clear();
|
||||
|
||||
// Save pasted sheet and symbol instances.
|
||||
setPastedSheetInstances( &tempSheet );
|
||||
setPastedSymbolInstances( tempScreens );
|
||||
|
||||
tempScreen->MigrateSimModels();
|
||||
|
||||
@@ -1870,6 +1974,16 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
|
||||
m_frame->GetCurrentSheet().UpdateAllScreenReferences();
|
||||
|
||||
prunePastedSymbolInstances();
|
||||
|
||||
// The copy operation creates instance paths that are not valid for the current project or
|
||||
// saved as part of another project. Prune them now so they do not accumulate in the saved
|
||||
// schematic file.
|
||||
SCH_SCREENS allScreens( m_frame->Schematic().Root() );
|
||||
|
||||
allScreens.PruneOrphanedSymbolInstances( m_frame->Prj().GetProjectName(),
|
||||
m_frame->Schematic().GetSheets() );
|
||||
|
||||
// Now clear the previous selection, select the pasted items, and fire up the "move" tool.
|
||||
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
|
||||
m_toolMgr->RunAction( EE_ACTIONS::addItemsToSel, true, &loadedItems );
|
||||
|
||||
@@ -42,7 +42,8 @@ public:
|
||||
EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.EditorControl" ),
|
||||
m_probingPcbToSch( false ),
|
||||
m_pickerItem( nullptr ),
|
||||
m_duplicateIsHoverSelection( false )
|
||||
m_duplicateIsHoverSelection( false ),
|
||||
m_highlightBusMembers( false )
|
||||
{ }
|
||||
|
||||
~SCH_EDITOR_CONTROL() { }
|
||||
@@ -157,6 +158,13 @@ public:
|
||||
bool aSearchHierarchy, SCH_SEARCH_T aSearchType,
|
||||
const wxString& aSearchText );
|
||||
|
||||
void SetHighlightBusMembers( bool aHighlightBusMembers )
|
||||
{
|
||||
m_highlightBusMembers = aHighlightBusMembers;
|
||||
}
|
||||
|
||||
bool GetHighlightBusMembers() const { return m_highlightBusMembers; }
|
||||
|
||||
private:
|
||||
///< copy selection to clipboard or to m_duplicateClipboard
|
||||
bool doCopy( bool aUseDuplicateClipboard = false );
|
||||
@@ -176,7 +184,18 @@ private:
|
||||
SCH_SHEET_LIST* aPastedSheetsSoFar,
|
||||
SCH_REFERENCE_LIST* aPastedSymbolsSoFar );
|
||||
|
||||
void setClipboardInstances( const SCH_SCREEN* aPastedScreen );
|
||||
void setPastedSheetInstances( const SCH_SHEET* aPastedSheet );
|
||||
void setPastedSymbolInstances( SCH_SCREENS& aScreenList );
|
||||
|
||||
/**
|
||||
* Remove all pasted symbol instances that do not belong to the current project.
|
||||
*
|
||||
* @warning This should **only** be called when cleaning up after a paste. Otherwise it
|
||||
* could clobber symbol instances for schematics shared across projects. Use
|
||||
* SCH_SCREENS::PruneOrphanedSymbolInstances() to clean up invalid instance for
|
||||
* the current project.
|
||||
*/
|
||||
void prunePastedSymbolInstances();
|
||||
|
||||
/**
|
||||
* Read the footprint info from each line in the stuff file by reference designator.
|
||||
@@ -211,6 +230,8 @@ private:
|
||||
std::string m_duplicateClipboard; // Temporary storage for Duplicate action
|
||||
bool m_duplicateIsHoverSelection;
|
||||
|
||||
bool m_highlightBusMembers;
|
||||
|
||||
// A map of sheet filename --> screens for the clipboard contents. We use these to hook up
|
||||
// cut/paste operations for unsaved sheet content.
|
||||
std::map<wxString, SCH_SCREEN*> m_supplementaryClipboard;
|
||||
@@ -220,6 +241,8 @@ private:
|
||||
|
||||
// A map of KIID_PATH --> sheet instances for the clipboard contents.
|
||||
std::map<KIID_PATH, SCH_SHEET_INSTANCE> m_clipboardSheetInstances;
|
||||
|
||||
std::set<SCH_SYMBOL*> m_pastedSymbols;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -937,6 +937,11 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, int aType,
|
||||
m_view->AddToPreview( wire->Clone() );
|
||||
}
|
||||
}
|
||||
else if( evt->IsAction( &ACTIONS::undo ) )
|
||||
{
|
||||
// Dispatch as normal undo event
|
||||
evt->SetPassEvent();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxBell();
|
||||
|
||||
@@ -823,7 +823,7 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
else if( evt->IsAction( &ACTIONS::duplicate ) )
|
||||
{
|
||||
if( selection.Front()->IsNew() )
|
||||
if( selection.Front() && selection.Front()->IsNew() )
|
||||
{
|
||||
// This doesn't really make sense; we'll just end up dragging a stack of
|
||||
// objects so we ignore the duplicate and just carry on.
|
||||
|
||||
@@ -355,41 +355,34 @@ int SYMBOL_EDITOR_CONTROL::RenameSymbol( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
|
||||
wxString oldName = symbolName;
|
||||
LIB_SYMBOL* libSymbol = nullptr;
|
||||
LIB_SYMBOL* libSymbol = libMgr.GetBufferedSymbol( oldName, libName );
|
||||
bool isCurrentSymbol = editFrame->IsCurrentSymbol( libId );
|
||||
|
||||
if( editFrame->IsCurrentSymbol( libId ) )
|
||||
{
|
||||
// Update buffered copy
|
||||
libSymbol = libMgr.GetBufferedSymbol( oldName, libName );
|
||||
libSymbol->SetName( newName );
|
||||
|
||||
libSymbol->SetName( newName );
|
||||
if( libSymbol->GetFieldById( VALUE_FIELD )->GetText() == oldName )
|
||||
libSymbol->GetFieldById( VALUE_FIELD )->SetText( newName );
|
||||
|
||||
libMgr.UpdateSymbolAfterRename( libSymbol, newName, libName );
|
||||
libMgr.UpdateSymbolAfterRename( libSymbol, newName, libName );
|
||||
libMgr.SetSymbolModified( newName, libName );
|
||||
|
||||
// Now update canvasy copy
|
||||
if( isCurrentSymbol )
|
||||
{
|
||||
libSymbol = editFrame->GetCurSymbol();
|
||||
|
||||
libSymbol->SetName( newName );
|
||||
libSymbol->GetFieldById( VALUE_FIELD )->SetText( newName );
|
||||
|
||||
if( libSymbol->GetFieldById( VALUE_FIELD )->GetText() == oldName )
|
||||
libSymbol->GetFieldById( VALUE_FIELD )->SetText( newName );
|
||||
|
||||
editFrame->RebuildView();
|
||||
editFrame->OnModify();
|
||||
editFrame->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
|
||||
editFrame->UpdateMsgPanel();
|
||||
}
|
||||
else
|
||||
{
|
||||
libSymbol = libMgr.GetBufferedSymbol( oldName, libName );
|
||||
|
||||
libSymbol->SetName( newName );
|
||||
libSymbol->GetFieldById( VALUE_FIELD )->SetText( newName );
|
||||
|
||||
libMgr.UpdateSymbolAfterRename( libSymbol, newName, libName );
|
||||
libMgr.SetSymbolModified( newName, libName );
|
||||
}
|
||||
|
||||
wxDataViewItem treeItem = libMgr.GetAdapter()->FindItem( libId );
|
||||
editFrame->UpdateLibraryTree( treeItem, libSymbol );
|
||||
|
||||
@@ -92,6 +92,7 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
|
||||
SHAPE_POLY_SET& aShapeBuffer )
|
||||
{
|
||||
// Draw the primitive shape for flashed items.
|
||||
// Note: rotation of primitives inside a macro must be always done around the macro origin.
|
||||
// Create a static buffer to avoid a lot of memory reallocation.
|
||||
static std::vector<VECTOR2I> polybuffer;
|
||||
polybuffer.clear();
|
||||
@@ -218,15 +219,17 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
|
||||
for( int ii = 0; ii < 4; ii++ )
|
||||
{
|
||||
polybuffer = subshape_poly;
|
||||
EDA_ANGLE sub_rotation = rotation + ANGLE_90 * ii;
|
||||
EDA_ANGLE sub_rotation = ANGLE_90 * ii;
|
||||
|
||||
for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
|
||||
RotatePoint( polybuffer[jj], -sub_rotation );
|
||||
|
||||
// Move to center position given by the tool:
|
||||
// Move to center position given by the tool, and rotate the full shape around
|
||||
// the center position (origin of the macro):
|
||||
for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
|
||||
{
|
||||
polybuffer[jj] += center;
|
||||
RotatePoint( polybuffer[jj], -rotation );
|
||||
}
|
||||
|
||||
aShapeBuffer.NewOutline();
|
||||
@@ -264,6 +267,8 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
|
||||
VECTOR2I center( mapPt( m_Params[0].GetValueFromMacro( aApertMacro ),
|
||||
m_Params[1].GetValueFromMacro( aApertMacro ), m_GerbMetric ) );
|
||||
|
||||
EDA_ANGLE rotation( m_Params[8].GetValueFromMacro( aApertMacro ), DEGREES_T );
|
||||
|
||||
// adjust outerDiam by this on each nested circle
|
||||
int diamAdjust = ( gap + penThickness ) * 2;
|
||||
|
||||
@@ -272,17 +277,21 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
|
||||
if( outerDiam <= 0 )
|
||||
break;
|
||||
|
||||
// calculate the rotated position of the center:
|
||||
VECTOR2I circle_center = center;
|
||||
RotatePoint( circle_center, -rotation );
|
||||
|
||||
// Note: outerDiam is the outer diameter of the ring.
|
||||
// the ring graphic diameter is (outerDiam - penThickness)
|
||||
if( outerDiam <= penThickness )
|
||||
{ // No room to draw a ring (no room for the hole):
|
||||
// draw a circle instead (with no hole), with the right diameter
|
||||
TransformCircleToPolygon( aShapeBuffer, center, outerDiam / 2, arc_to_seg_error,
|
||||
TransformCircleToPolygon( aShapeBuffer, circle_center, outerDiam / 2, arc_to_seg_error,
|
||||
ERROR_INSIDE );
|
||||
}
|
||||
else
|
||||
{
|
||||
TransformRingToPolygon( aShapeBuffer, center, ( outerDiam - penThickness ) / 2,
|
||||
TransformRingToPolygon( aShapeBuffer, circle_center, ( outerDiam - penThickness ) / 2,
|
||||
penThickness, arc_to_seg_error, ERROR_INSIDE );
|
||||
}
|
||||
}
|
||||
@@ -290,13 +299,11 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
|
||||
// Draw the cross:
|
||||
ConvertShapeToPolygon( aApertMacro, polybuffer );
|
||||
|
||||
EDA_ANGLE rotation( m_Params[8].GetValueFromMacro( aApertMacro ), DEGREES_T );
|
||||
|
||||
for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
|
||||
{
|
||||
// move crossair shape to center and rotate shape:
|
||||
RotatePoint( polybuffer[ii], -rotation );
|
||||
polybuffer[ii] += center;
|
||||
RotatePoint( polybuffer[ii], -rotation );
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -375,13 +382,13 @@ void AM_PRIMITIVE::ConvertBasicShapeToPolygon( APERTURE_MACRO* aApertMacro,
|
||||
// Creates the shape:
|
||||
ConvertShapeToPolygon( aApertMacro, polybuffer );
|
||||
|
||||
// rotate polygon
|
||||
// move and rotate polygonal shape
|
||||
EDA_ANGLE rotation( m_Params[5].GetValueFromMacro( aApertMacro ), DEGREES_T );
|
||||
|
||||
for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
|
||||
{
|
||||
RotatePoint( polybuffer[ii], -rotation );
|
||||
polybuffer[ii] += curPos;
|
||||
RotatePoint( polybuffer[ii], -rotation );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
+13
-13
@@ -199,24 +199,24 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFileName )
|
||||
* Now (2014) Ucamco (the company which manages the Gerber format) encourages use of .gbr
|
||||
* only and the Gerber X2 file format.
|
||||
*/
|
||||
filetypes = _( "Gerber files" ) + AddFileExtListToFilter( { "G*", "PHO" } ) + wxT( "|" );
|
||||
filetypes = _( "Gerber files" ) + AddFileExtListToFilter( { "g*", "pho" } ) + wxT( "|" );
|
||||
|
||||
/* Special gerber filetypes */
|
||||
filetypes += _( "Top layer" ) + AddFileExtListToFilter( { "GTL" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom layer" ) + AddFileExtListToFilter( { "GBL" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom solder resist" ) + AddFileExtListToFilter( { "GBS" } ) + wxT( "|" );
|
||||
filetypes += _( "Top solder resist" ) + AddFileExtListToFilter( { "GTS" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom overlay" ) + AddFileExtListToFilter( { "GBO" } ) + wxT( "|" );
|
||||
filetypes += _( "Top overlay" ) + AddFileExtListToFilter( { "GTO" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom paste" ) + AddFileExtListToFilter( { "GBP" } ) + wxT( "|" );
|
||||
filetypes += _( "Top paste" ) + AddFileExtListToFilter( { "GTP" } ) + wxT( "|" );
|
||||
filetypes += _( "Keep-out layer" ) + AddFileExtListToFilter( { "GKO" } ) + wxT( "|" );
|
||||
filetypes += _( "Top layer" ) + AddFileExtListToFilter( { "gtl" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom layer" ) + AddFileExtListToFilter( { "gbl" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom solder resist" ) + AddFileExtListToFilter( { "gbs" } ) + wxT( "|" );
|
||||
filetypes += _( "Top solder resist" ) + AddFileExtListToFilter( { "gts" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom overlay" ) + AddFileExtListToFilter( { "gbo" } ) + wxT( "|" );
|
||||
filetypes += _( "Top overlay" ) + AddFileExtListToFilter( { "gto" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom paste" ) + AddFileExtListToFilter( { "gbp" } ) + wxT( "|" );
|
||||
filetypes += _( "Top paste" ) + AddFileExtListToFilter( { "gtp" } ) + wxT( "|" );
|
||||
filetypes += _( "Keep-out layer" ) + AddFileExtListToFilter( { "gko" } ) + wxT( "|" );
|
||||
filetypes += _( "Mechanical layers" )
|
||||
+ AddFileExtListToFilter(
|
||||
{ "GM1", "GM2", "GM3", "GM4", "GM5", "GM6", "GM7", "GM8", "GM9" } )
|
||||
{ "gm1", "gm2", "gm3", "gm4", "gm5", "gm6", "gm7", "gm8", "gm9" } )
|
||||
+ wxT( "|" );
|
||||
filetypes += _( "Top Pad Master" ) + AddFileExtListToFilter( { "GPT" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom Pad Master" ) + AddFileExtListToFilter( { "GPB" } ) + wxT( "|" );
|
||||
filetypes += _( "Top Pad Master" ) + AddFileExtListToFilter( { "gpt" } ) + wxT( "|" );
|
||||
filetypes += _( "Bottom Pad Master" ) + AddFileExtListToFilter( { "gpb" } ) + wxT( "|" );
|
||||
|
||||
// All filetypes
|
||||
filetypes += AllFilesWildcard();
|
||||
|
||||
@@ -99,6 +99,10 @@ public:
|
||||
// and the actual coordinates calculation must handle this
|
||||
};
|
||||
|
||||
// size of a single line of text from a gerber file.
|
||||
// warning: some files can have *very long* lines, so the buffer must be large.
|
||||
#define GERBER_BUFZ 1000000
|
||||
|
||||
/**
|
||||
* Hold the image data and parameters for one gerber file and layer parameters.
|
||||
*
|
||||
@@ -455,6 +459,9 @@ public:
|
||||
GERBER_LAYER m_GBRLayerParams; // hold params for the current gerber layer
|
||||
GERBER_DRAW_ITEMS m_drawings; // linked list of Gerber Items to draw
|
||||
|
||||
// A large buffer to store one line
|
||||
static char m_LineBuffer[GERBER_BUFZ+1];
|
||||
|
||||
private:
|
||||
wxArrayString m_messagesList; // A list of messages created when reading a file
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2007-2016 Jean-Pierre Charras jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2023 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
|
||||
@@ -223,11 +223,9 @@ bool GERBER_FILE_IMAGE::TestFileIsRS274( const wxString& aFullFileName )
|
||||
return false;
|
||||
}
|
||||
|
||||
// size of a single line of text from a gerber file.
|
||||
// warning: some files can have *very long* lines, so the buffer must be large.
|
||||
#define GERBER_BUFZ 1000000
|
||||
|
||||
// A large buffer to store one line
|
||||
static char lineBuffer[GERBER_BUFZ+1];
|
||||
char GERBER_FILE_IMAGE::m_LineBuffer[GERBER_BUFZ+1];
|
||||
|
||||
bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
|
||||
{
|
||||
@@ -252,11 +250,11 @@ bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( fgets( lineBuffer, GERBER_BUFZ, m_Current_File ) == nullptr )
|
||||
if( fgets( m_LineBuffer, GERBER_BUFZ, m_Current_File ) == nullptr )
|
||||
break;
|
||||
|
||||
m_LineNum++;
|
||||
text = StrPurge( lineBuffer );
|
||||
text = StrPurge( m_LineBuffer );
|
||||
|
||||
while( text && *text )
|
||||
{
|
||||
@@ -313,7 +311,7 @@ bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
|
||||
if( m_CommandState != ENTER_RS274X_CMD )
|
||||
{
|
||||
m_CommandState = ENTER_RS274X_CMD;
|
||||
ReadRS274XCommand( lineBuffer, GERBER_BUFZ, text );
|
||||
ReadRS274XCommand( m_LineBuffer, GERBER_BUFZ, text );
|
||||
}
|
||||
else //Error
|
||||
{
|
||||
|
||||
+6
-7
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* @file rs274d.cpp
|
||||
* @brief functions to read the rs274d commands from a rs274d/rs274x file
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
@@ -26,6 +21,11 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief functions to read the rs274d commands from a rs274d/rs274x file
|
||||
*/
|
||||
|
||||
|
||||
#include <gerbview.h>
|
||||
#include <gerbview_frame.h>
|
||||
#include <trigo.h>
|
||||
@@ -464,8 +464,7 @@ bool GERBER_FILE_IMAGE::Execute_G_Command( char*& text, int G_command )
|
||||
ExecuteRS274XCommand( code_command, nullptr, 0, cptr );
|
||||
}
|
||||
|
||||
while( *text && (*text != '*') )
|
||||
text++;
|
||||
GetEndOfBlock( m_LineBuffer, GERBER_BUFZ, text, m_Current_File );
|
||||
|
||||
break;
|
||||
|
||||
|
||||
+2
-6
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2007-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2023 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
|
||||
@@ -22,9 +22,6 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file rs274x.cpp
|
||||
*/
|
||||
|
||||
#include <base_units.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
@@ -1049,8 +1046,7 @@ bool GERBER_FILE_IMAGE::ReadApertureMacro( char *aBuff, unsigned int aBuffSize,
|
||||
is_comment = true;
|
||||
|
||||
// Skip comment
|
||||
while( *aText && ( *aText != '*' ) )
|
||||
aText++;
|
||||
GetEndOfBlock( m_LineBuffer, GERBER_BUFZ, aText, m_Current_File );
|
||||
|
||||
break;
|
||||
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ protected:
|
||||
* Display a dialog indicating the file is already open, with an option to reset the lock.
|
||||
* @return true if the lock was reset.
|
||||
*/
|
||||
bool OverrideLock( wxWindow* aParent, const wxString& aMessage );
|
||||
bool AskOverrideLock( wxWindow* aParent, const wxString& aMessage );
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user