Compare commits
233 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f5d3fa0c6 | |||
| 51dc2b109e | |||
| 2358ff6f07 | |||
| 11788d2f39 | |||
| 541f7467c6 | |||
| 411c9707ee | |||
| ee0ba17c03 | |||
| 64bc850d8f | |||
| 154f64dae3 | |||
| 7fa758358f | |||
| f135881bd6 | |||
| 839301f81e | |||
| 04f4ca9772 | |||
| 525328fba1 | |||
| 471c125c1a | |||
| 8ef99137c6 | |||
| 404cad062a | |||
| d4be813f2e | |||
| ab3c0b2f03 | |||
| defcfc2962 | |||
| 267cfdf54b | |||
| a7b0231b3c | |||
| 7c19958840 | |||
| 34c3bb7d2c | |||
| b37545ee6c | |||
| c1e924c894 | |||
| 200e9e28ea | |||
| b95f958890 | |||
| fe9666bdaf | |||
| 948de5dc79 | |||
| 8800fd8250 | |||
| b1e5d8c915 | |||
| 02aec8b091 | |||
| 50517f6aa6 | |||
| a752473280 | |||
| 7e1972d483 | |||
| de48bf04bc | |||
| 228bf66cac | |||
| c986c1d26a | |||
| b0f7ea5b16 | |||
| 8b2e2ff1f8 | |||
| d00166223f | |||
| 4701b4bfc2 | |||
| e4c74c727f | |||
| f626ce29c4 | |||
| 768d8e5811 | |||
| 2ac3a4a103 | |||
| bb512f3fc0 | |||
| d6e7a89c97 | |||
| a5455da909 | |||
| 8dadc698cc | |||
| 2127712115 | |||
| d5b635027e | |||
| 9b2aeda51e | |||
| 5aba9b539f | |||
| b82020722b | |||
| b62a8fe65a | |||
| a5d85e3281 | |||
| e699bcf5a3 | |||
| 7ef5e079fd | |||
| 4076461347 | |||
| d610486c1e | |||
| 1891e2ad68 | |||
| f1e060902b | |||
| 7dbd920912 | |||
| 05ab9e3836 | |||
| a4e0f1f7aa | |||
| a8f27d13e6 | |||
| 05d425ea88 | |||
| 3cb12b5a60 | |||
| 8f1237e629 | |||
| 2c7f44f78d | |||
| a9447aa8c7 | |||
| 9b61b350fe | |||
| e3cf65fbdf | |||
| e51d43568e | |||
| 1bb6b7acdd | |||
| adc7a3ba4a | |||
| 94ec6cc362 | |||
| bbdb5eb6e3 | |||
| e487ca8bd8 | |||
| f5b0e20f78 | |||
| 6116eebbad | |||
| 8619705e44 | |||
| c216ed2d1f | |||
| e17dc25bba | |||
| d311915f9d | |||
| 3a95826b42 | |||
| dcc1009162 | |||
| d61e01ff4f | |||
| 51b9d8e7ad | |||
| 90eb5e9c31 | |||
| 17c34c88dc | |||
| ff6f658f9d | |||
| fb798a4150 | |||
| 4213bb3a62 | |||
| 8a34f91172 | |||
| 764ddd4773 | |||
| ea0dcc8ebd | |||
| 3f5db9f7f9 | |||
| a6a0bba1b7 | |||
| 5ec785e2f7 | |||
| f7d9f1f69d | |||
| 42efd2d005 | |||
| d32e13daee | |||
| e82c21e944 | |||
| 33f835a437 | |||
| 59d8110801 | |||
| d028b381fa | |||
| a1a3f810f0 | |||
| c96f0f2396 | |||
| 46c8985661 | |||
| c588639503 | |||
| b3c6f559b2 | |||
| 85544d109c | |||
| 4aba595b2b | |||
| b2241dca72 | |||
| 4ffe742b69 | |||
| 5979b8e385 | |||
| 955bd5a6d1 | |||
| 1eb8191519 | |||
| 396bda5611 | |||
| cb334be8c4 | |||
| 8845cc0556 | |||
| e34800ad49 | |||
| 5b574901b3 | |||
| 59b68154e1 | |||
| 5a501c8e48 | |||
| f927c15adf | |||
| d08157f7db | |||
| 8a9ac4f01f | |||
| 39df5f3b15 | |||
| 981bf328ae | |||
| 1f8e9727b0 | |||
| f604bcb557 | |||
| eccf9eb4a4 | |||
| 39403fa885 | |||
| 5e7cc30564 | |||
| f942b4c657 | |||
| f5aeb5b068 | |||
| 7f6cb9b07b | |||
| db3657d411 | |||
| 38e5da724d | |||
| 24a63eb304 | |||
| c1f5ae1c5a | |||
| 009211c740 | |||
| 1a208a1612 | |||
| b867e51c6c | |||
| 7693b93c50 | |||
| c3d7158669 | |||
| 9f5e50f25e | |||
| a091ab76d7 | |||
| d5eb242295 | |||
| b21e65fc5f | |||
| 1b07e81936 | |||
| 962b2d45ef | |||
| 7894b41277 | |||
| 51d0b8d2b5 | |||
| 7b992a1dc4 | |||
| 2f8615c6c4 | |||
| aee6d9d01c | |||
| fd4a0dbedf | |||
| 14381ac68a | |||
| c00a98fed4 | |||
| aab7581909 | |||
| 74dcc1b9d5 | |||
| 17241b3543 | |||
| a4a859f47b | |||
| b66ed8bc41 | |||
| 754feff5e7 | |||
| cd1b425a80 | |||
| 187947e8d8 | |||
| 6b38927123 | |||
| f46e4049b6 | |||
| 0ea8299fa7 | |||
| 5d793193e0 | |||
| 62337f75b8 | |||
| 4d4fdfff70 | |||
| b63d0a3138 | |||
| 7949c09183 | |||
| 3f535aca8c | |||
| 9f44809164 | |||
| f7ccb18af5 | |||
| cca9945867 | |||
| f23c6b0c2f | |||
| 6d22b8c6ed | |||
| 245ce7259c | |||
| f36cd60fdb | |||
| 8467e2d376 | |||
| 2529918d5f | |||
| e2711a6121 | |||
| 89d22e5f94 | |||
| f13fda9be5 | |||
| 49f6a63a06 | |||
| e078fea846 | |||
| 048c8b1670 | |||
| 3b5c38d861 | |||
| 90fb075e34 | |||
| 08c6d9ce96 | |||
| 76ccb8c31f | |||
| 3dfc502814 | |||
| df0f626283 | |||
| 1909ce9220 | |||
| 15bef82e1e | |||
| 60a45241e6 | |||
| d403e92315 | |||
| eed7ede376 | |||
| d20f49b58b | |||
| 37091df142 | |||
| 21081cf80f | |||
| c213b37e96 | |||
| d1ca84aa43 | |||
| 0f7fbc411a | |||
| f4b2b1b03f | |||
| 0ecc36c4a5 | |||
| a48eace90a | |||
| 7a2a51ad44 | |||
| f56fcb0a14 | |||
| 7816652078 | |||
| 20aacc7026 | |||
| 49938cfd09 | |||
| 53a4ed6b24 | |||
| 534000b49d | |||
| 7e2ccbf909 | |||
| b0b6968185 | |||
| 94963b5b3a | |||
| 77fa61e6fc | |||
| 94c450ad16 | |||
| a292bf7c83 | |||
| b24ee1c44f | |||
| 981b22ba49 | |||
| e1eedd3bba | |||
| b949fd4d43 |
@@ -0,0 +1,20 @@
|
||||
<!-- --------Before Creating a New Issue-----------
|
||||
* Limit report to a single issue.
|
||||
* Search the issue tracker to verify the issue has not already been reported.
|
||||
* Complete all instructions between `template comment markers <>.
|
||||
* Keep report contents limited to the necessary information required to fix the issue.
|
||||
* When creating an issue against the stable version of KiCad, make sure the latest available stable version is installed as issues may have already been resolved in later stable versions. -->
|
||||
# Description
|
||||
<!-- What is the current behavior and what is the expected behavior? -->
|
||||
<!-- If the issue is visual/graphical, please attach screenshots of the problem. -->
|
||||
<!-- Add the issue details below this line and before the "Steps to reproduce" heading. -->
|
||||
|
||||
# Steps to reproduce
|
||||
<!-- If there are multiple steps to reproduce it or it is a visual issue, then providing a screen recording as an attachment to this report is recommended. -->
|
||||
<!-- If this issue is specific to a project, please attach the necessary files to this issue. -->
|
||||
<!-- Add the steps to reproduce using the numbers below -->
|
||||
<!-- Add new step numbers before the "KiCad Version" heading. -->
|
||||
1.
|
||||
|
||||
# KiCad Version
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2022 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* 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
|
||||
@@ -671,7 +671,8 @@ bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
|
||||
return false;
|
||||
}
|
||||
|
||||
int chainingEpsilon = pcbIUScale.mmToIU( 0.02 ); // max dist from one endPt to next startPt
|
||||
// max dist from one endPt to next startPt
|
||||
int chainingEpsilon = m_board->GetOutlinesChainingEpsilon();
|
||||
|
||||
success = BuildFootprintPolygonOutlines( m_board, m_board_poly,
|
||||
m_board->GetDesignSettings().m_MaxError,
|
||||
|
||||
@@ -383,6 +383,15 @@ void EDA_3D_CANVAS::DoRePaint()
|
||||
if( m_glRC == nullptr )
|
||||
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
|
||||
|
||||
// CreateCtx could and does fail per sentry crash events, lets be graceful
|
||||
if( m_glRC == nullptr )
|
||||
{
|
||||
warningReporter.Report( _( "OpenGL context creation error" ), RPT_SEVERITY_ERROR );
|
||||
warningReporter.Finalize();
|
||||
m_is_currently_painting.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
|
||||
|
||||
// Set the OpenGL viewport according to the client size of this canvas.
|
||||
|
||||
@@ -257,6 +257,13 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
|
||||
if( m_glRC == nullptr )
|
||||
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
|
||||
|
||||
// CreateCtx could and does fail per sentry crash events, lets be graceful
|
||||
if( m_glRC == nullptr )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint creating gl context failed" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
|
||||
|
||||
// Set the OpenGL viewport according to the client size of this canvas.
|
||||
@@ -323,8 +330,16 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
|
||||
m_ogl_3dmodel->BeginDrawMulti( true );
|
||||
|
||||
m_ogl_3dmodel->DrawOpaque( false );
|
||||
|
||||
glDepthMask( GL_FALSE );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
m_ogl_3dmodel->DrawTransparent( 1.0f, false );
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
glDepthMask( GL_TRUE );
|
||||
|
||||
m_ogl_3dmodel->EndDrawMulti();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
* @file c_ogl_3dmodel.cpp
|
||||
* @brief
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
|
||||
#include "3d_model.h"
|
||||
#include "opengl_utils.h"
|
||||
#include "../common_ogl/ogl_utils.h"
|
||||
#include "../3d_math.h"
|
||||
#include <utility>
|
||||
#include <wx/debug.h>
|
||||
#include <wx/log.h>
|
||||
#include <chrono>
|
||||
@@ -177,9 +178,11 @@ MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode )
|
||||
// use material color for mesh bounding box or some sort of average vertex color.
|
||||
glm::vec3 avg_color = material.m_Diffuse;
|
||||
|
||||
BBOX_3D &mesh_bbox = m_meshes_bbox[mesh_i];
|
||||
|
||||
for( unsigned int vtx_i = 0; vtx_i < mesh.m_VertexSize; ++vtx_i )
|
||||
{
|
||||
m_meshes_bbox[mesh_i].Union( mesh.m_Positions[vtx_i] );
|
||||
mesh_bbox.Union( mesh.m_Positions[vtx_i] );
|
||||
|
||||
VERTEX& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i];
|
||||
|
||||
@@ -222,16 +225,19 @@ MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode )
|
||||
}
|
||||
}
|
||||
|
||||
if( m_meshes_bbox[mesh_i].IsInitialized() )
|
||||
if( mesh_bbox.IsInitialized() )
|
||||
{
|
||||
// generate geometry for the bounding box
|
||||
MakeBbox( m_meshes_bbox[mesh_i], ( mesh_i + 1 ) * bbox_vtx_count,
|
||||
MakeBbox( mesh_bbox, ( mesh_i + 1 ) * bbox_vtx_count,
|
||||
&bbox_tmp_vertices[( mesh_i + 1 ) * bbox_vtx_count],
|
||||
&bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count],
|
||||
{ avg_color, 1.0f } );
|
||||
|
||||
// bump the outer bounding box
|
||||
m_model_bbox.Union( m_meshes_bbox[mesh_i] );
|
||||
m_model_bbox.Union( mesh_bbox );
|
||||
|
||||
// add to the material group
|
||||
material.m_bbox.Union( mesh_bbox );
|
||||
}
|
||||
|
||||
|
||||
@@ -410,7 +416,9 @@ void MODEL_3D::EndDrawMulti()
|
||||
|
||||
|
||||
void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
||||
SFVEC3F& aSelectionColor ) const
|
||||
const SFVEC3F& aSelectionColor,
|
||||
const glm::mat4 *aModelWorldMatrix,
|
||||
const SFVEC3F *aCameraWorldPos ) const
|
||||
{
|
||||
if( aOpacity <= FLT_EPSILON )
|
||||
return;
|
||||
@@ -439,27 +447,102 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||
|
||||
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)¶m.x );
|
||||
|
||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||
std::vector<const MODEL_3D::MATERIAL *> materialsToRender;
|
||||
|
||||
materialsToRender.reserve( m_materials.size() );
|
||||
|
||||
if( aModelWorldMatrix && aCameraWorldPos )
|
||||
{
|
||||
if( ( mat.IsTransparent() != aTransparent )
|
||||
// Sort Material groups
|
||||
|
||||
std::vector<std::pair<const MODEL_3D::MATERIAL*, float>> materialsSorted;
|
||||
|
||||
// Calculate the distance to the camera for each material group
|
||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||
{
|
||||
if( mat.m_render_idx_count == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( mat.IsTransparent() != aTransparent )
|
||||
&& ( aOpacity >= 1.0f )
|
||||
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
||||
{
|
||||
continue;
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const BBOX_3D& bBox = mat.m_bbox;
|
||||
const SFVEC3F& bBoxCenter = bBox.GetCenter();
|
||||
const SFVEC3F bBoxWorld = *aModelWorldMatrix * glm::vec4( bBoxCenter, 1.0f );
|
||||
|
||||
const float distanceToCamera = glm::length( *aCameraWorldPos - bBoxWorld );
|
||||
|
||||
materialsSorted.emplace_back( &mat, distanceToCamera );
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
return a.second > b.second;
|
||||
} );
|
||||
|
||||
for( const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
|
||||
{
|
||||
materialsToRender.push_back( mat.first );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||
{
|
||||
// There is at least one default material created in case a mesh has no declared materials.
|
||||
// Most meshes have a material, so usually the first material will have nothing to render and is skip.
|
||||
// See S3D::GetModel for more details.
|
||||
if( mat.m_render_idx_count == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( mat.IsTransparent() != aTransparent )
|
||||
&& ( aOpacity >= 1.0f )
|
||||
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
materialsToRender.push_back( &mat );
|
||||
}
|
||||
}
|
||||
|
||||
for( const MODEL_3D::MATERIAL* mat : materialsToRender )
|
||||
{
|
||||
switch( m_materialMode )
|
||||
{
|
||||
case MATERIAL_MODE::NORMAL:
|
||||
OglSetMaterial( mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
OglSetMaterial( *mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
case MATERIAL_MODE::DIFFUSE_ONLY:
|
||||
OglSetDiffuseMaterial( mat.m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
OglSetDiffuseMaterial( mat->m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
case MATERIAL_MODE::CAD_MODE:
|
||||
OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat.m_Diffuse ), aOpacity,
|
||||
OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat->m_Diffuse ), aOpacity,
|
||||
aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
@@ -467,9 +550,9 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||
break;
|
||||
}
|
||||
|
||||
glDrawElements( GL_TRIANGLES, mat.m_render_idx_count, m_index_buffer_type,
|
||||
glDrawElements( GL_TRIANGLES, mat->m_render_idx_count, m_index_buffer_type,
|
||||
reinterpret_cast<const void*>(
|
||||
static_cast<uintptr_t>( mat.m_render_idx_buffer_offset ) ) );
|
||||
static_cast<uintptr_t>( mat->m_render_idx_buffer_offset ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
*/
|
||||
void DrawOpaque( bool aUseSelectedMaterial, SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
|
||||
{
|
||||
Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor );
|
||||
Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,9 +63,19 @@ public:
|
||||
void DrawTransparent( float aOpacity, bool aUseSelectedMaterial,
|
||||
SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
|
||||
{
|
||||
Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the model into the current context.
|
||||
* if aModelWorldMatrix and aCameraWorldPos is provided,
|
||||
* it renders the material groups sorted.
|
||||
*/
|
||||
void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
||||
const SFVEC3F& aSelectionColor,
|
||||
const glm::mat4 *aModelWorldMatrix,
|
||||
const SFVEC3F *aCameraWorldPos ) const;
|
||||
|
||||
/**
|
||||
* Return true if have opaque meshes to render.
|
||||
*/
|
||||
@@ -136,6 +146,8 @@ private:
|
||||
unsigned int m_render_idx_buffer_offset = 0;
|
||||
unsigned int m_render_idx_count = 0;
|
||||
|
||||
BBOX_3D m_bbox; ///< bounding box for this material group, used for transparent material ordering
|
||||
|
||||
MATERIAL( const SMATERIAL& aOther ) : SMATERIAL( aOther ) { }
|
||||
bool IsTransparent() const { return m_Transparency > FLT_EPSILON; }
|
||||
};
|
||||
@@ -159,9 +171,6 @@ private:
|
||||
|
||||
static void MakeBbox( const BBOX_3D& aBox, unsigned int aIdxOffset, VERTEX* aVtxOut,
|
||||
GLuint* aIdxOut, const glm::vec4& aColor );
|
||||
|
||||
void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
||||
SFVEC3F& aSelectionColor ) const;
|
||||
};
|
||||
|
||||
#endif // _MODEL_3D_H_
|
||||
|
||||
@@ -22,14 +22,19 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
|
||||
#include "plugins/3dapi/xv3d_types.h"
|
||||
#include "render_3d_opengl.h"
|
||||
#include "opengl_utils.h"
|
||||
#include "common_ogl/ogl_utils.h"
|
||||
#include <footprint.h>
|
||||
#include <3d_math.h>
|
||||
#include <glm/geometric.hpp>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include <base_units.h>
|
||||
@@ -858,9 +863,12 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glm::mat4 cameraViewMatrix;
|
||||
|
||||
glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
|
||||
|
||||
// Render 3D Models (Non-transparent)
|
||||
render3dModels( false, false );
|
||||
render3dModels( true, false );
|
||||
renderOpaqueModels( cameraViewMatrix );
|
||||
|
||||
// Display board body
|
||||
if( m_boardAdapter.m_Cfg->m_Render.show_board_body )
|
||||
@@ -922,8 +930,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
|
||||
|
||||
render3dModels( false, true );
|
||||
render3dModels( true, true );
|
||||
renderTransparentModels( cameraViewMatrix );
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
OglResetTextureState();
|
||||
@@ -1143,14 +1150,15 @@ void RENDER_3D_OPENGL::renderSolderMaskLayer( PCB_LAYER_ID aLayerID, float aZPos
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly,
|
||||
bool aRenderSelectedOnly )
|
||||
void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList,
|
||||
bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
|
||||
bool aRenderSelectedOnly )
|
||||
{
|
||||
wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
|
||||
|
||||
if( !m_boardAdapter.GetBoard() )
|
||||
return;
|
||||
|
||||
MODEL_3D::BeginDrawMulti( !aRenderSelectedOnly );
|
||||
|
||||
// Go for all footprints
|
||||
for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
|
||||
{
|
||||
@@ -1175,54 +1183,52 @@ void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRende
|
||||
{
|
||||
if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
|
||||
{
|
||||
if( aRenderTopOrBot == !fp->IsFlipped() )
|
||||
renderFootprint( fp, aRenderTransparentOnly, highlight );
|
||||
const bool isFlipped = fp->IsFlipped();
|
||||
|
||||
if( ( aGetTop == !isFlipped ) ||
|
||||
( aGetBot == isFlipped ) )
|
||||
get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly, highlight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MODEL_3D::EndDrawMulti();
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly )
|
||||
{
|
||||
if( m_boardAdapter.m_IsBoardView )
|
||||
render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, true );
|
||||
|
||||
render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, false );
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||
bool aIsSelected )
|
||||
void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
|
||||
const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||
bool aIsSelected )
|
||||
{
|
||||
if( !aFootprint->Models().empty() )
|
||||
{
|
||||
const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
|
||||
SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
VECTOR2I pos = aFootprint->GetPosition();
|
||||
|
||||
glTranslatef( pos.x * m_boardAdapter.BiuTo3dUnits(), -pos.y * m_boardAdapter.BiuTo3dUnits(),
|
||||
zpos );
|
||||
glm::mat4 fpMatrix( 1.0f );
|
||||
|
||||
fpMatrix = glm::translate( fpMatrix,
|
||||
SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
|
||||
-pos.y * m_boardAdapter.BiuTo3dUnits(),
|
||||
zpos ) );
|
||||
|
||||
if( !aFootprint->GetOrientation().IsZero() )
|
||||
glRotated( aFootprint->GetOrientation().AsDegrees(), 0.0, 0.0, 1.0 );
|
||||
{
|
||||
fpMatrix = glm::rotate( fpMatrix,
|
||||
(float) aFootprint->GetOrientation().AsRadians(),
|
||||
SFVEC3F( 0.0f, 0.0f, 1.0f ) );
|
||||
}
|
||||
|
||||
if( aFootprint->IsFlipped() )
|
||||
{
|
||||
glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
|
||||
glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
|
||||
fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
|
||||
fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
|
||||
}
|
||||
|
||||
double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
|
||||
const double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() *
|
||||
UNITS3D_TO_UNITSPCB;
|
||||
|
||||
glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
|
||||
modelunit_to_3d_units_factor );
|
||||
fpMatrix = glm::scale( fpMatrix,
|
||||
SFVEC3F( modelunit_to_3d_units_factor ) );
|
||||
|
||||
// Get the list of model files for this model
|
||||
for( const FP_3DMODEL& sM : aFootprint->Models() )
|
||||
@@ -1243,66 +1249,232 @@ void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRende
|
||||
if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
|
||||
( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
|
||||
{
|
||||
glPushMatrix();
|
||||
glm::mat4 modelworldMatrix = fpMatrix;
|
||||
|
||||
std::vector<double> key = { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z,
|
||||
sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z,
|
||||
sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z };
|
||||
const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
|
||||
const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z );
|
||||
const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
|
||||
|
||||
std::vector<float> key = { offset.x, offset.y, offset.z,
|
||||
rotation.x, rotation.y, rotation.z,
|
||||
scale.x, scale.y, scale.z };
|
||||
|
||||
auto it = m_3dModelMatrixMap.find( key );
|
||||
|
||||
if( it != m_3dModelMatrixMap.end() )
|
||||
{
|
||||
glMultMatrixf( glm::value_ptr( it->second ) );
|
||||
modelworldMatrix *= it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
glm::mat4 mtx( 1 );
|
||||
mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } );
|
||||
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.z ), { 0.0f, 0.0f, 1.0f } );
|
||||
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.y ), { 0.0f, 1.0f, 0.0f } );
|
||||
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.x ), { 1.0f, 0.0f, 0.0f } );
|
||||
mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } );
|
||||
glm::mat4 mtx( 1.0f );
|
||||
mtx = glm::translate( mtx, offset );
|
||||
mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } );
|
||||
mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } );
|
||||
mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
|
||||
mtx = glm::scale( mtx, scale );
|
||||
m_3dModelMatrixMap[ key ] = mtx;
|
||||
|
||||
glMultMatrixf( glm::value_ptr( mtx ) );
|
||||
modelworldMatrix *= mtx;
|
||||
}
|
||||
|
||||
|
||||
if( aRenderTransparentOnly )
|
||||
{
|
||||
modelPtr->DrawTransparent( sM.m_Opacity,
|
||||
aFootprint->IsSelected() || aIsSelected,
|
||||
selColor );
|
||||
aDstRenderList.emplace_back( modelworldMatrix,
|
||||
modelPtr,
|
||||
sM.m_Opacity,
|
||||
true,
|
||||
aFootprint->IsSelected() || aIsSelected );
|
||||
}
|
||||
else
|
||||
{
|
||||
modelPtr->DrawOpaque( aFootprint->IsSelected() || aIsSelected, selColor );
|
||||
aDstRenderList.emplace_back( modelworldMatrix,
|
||||
modelPtr,
|
||||
1.0f,
|
||||
false,
|
||||
aFootprint->IsSelected() || aIsSelected );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox )
|
||||
{
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
|
||||
{
|
||||
const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
|
||||
|
||||
glLineWidth( 1 );
|
||||
modelPtr->DrawBboxes();
|
||||
glPushMatrix();
|
||||
|
||||
glLineWidth( 4 );
|
||||
modelPtr->DrawBbox();
|
||||
std::list<MODELTORENDER> renderList;
|
||||
|
||||
glEnable( GL_LIGHTING );
|
||||
glDisable( GL_BLEND );
|
||||
}
|
||||
if( m_boardAdapter.m_IsBoardView )
|
||||
{
|
||||
renderList.clear();
|
||||
|
||||
glPopMatrix();
|
||||
get3dModelsSelected( renderList, true, true, false, true );
|
||||
|
||||
if( !renderList.empty() )
|
||||
{
|
||||
MODEL_3D::BeginDrawMulti( false );
|
||||
|
||||
for( const MODELTORENDER& mtr : renderList )
|
||||
{
|
||||
renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
|
||||
}
|
||||
|
||||
MODEL_3D::EndDrawMulti();
|
||||
}
|
||||
}
|
||||
|
||||
renderList.clear();
|
||||
get3dModelsSelected( renderList, true, true, false, false );
|
||||
|
||||
if( !renderList.empty() )
|
||||
{
|
||||
MODEL_3D::BeginDrawMulti( true );
|
||||
|
||||
for( const MODELTORENDER& mtr : renderList )
|
||||
{
|
||||
renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
|
||||
}
|
||||
|
||||
MODEL_3D::EndDrawMulti();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix )
|
||||
{
|
||||
const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
|
||||
|
||||
std::list<MODELTORENDER> renderListModels; // do not clear it until this function returns
|
||||
|
||||
if( m_boardAdapter.m_IsBoardView )
|
||||
{
|
||||
// Get Transparent Selected
|
||||
get3dModelsSelected( renderListModels, true, true, true, true );
|
||||
}
|
||||
|
||||
// Get Transparent Not Selected
|
||||
get3dModelsSelected( renderListModels, true, true, true, false );
|
||||
|
||||
if( renderListModels.empty() )
|
||||
return;
|
||||
|
||||
std::vector<std::pair<const MODELTORENDER *, float>> transparentModelList;
|
||||
|
||||
transparentModelList.reserve( renderListModels.size() );
|
||||
|
||||
// Calculate the distance to the camera for each model
|
||||
const SFVEC3F &cameraPos = m_camera.GetPos();
|
||||
|
||||
for( const MODELTORENDER& mtr : renderListModels )
|
||||
{
|
||||
const BBOX_3D& bBox = mtr.m_model->GetBBox();
|
||||
const SFVEC3F& bBoxCenter = bBox.GetCenter();
|
||||
const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f );
|
||||
|
||||
const float distanceToCamera = glm::length( cameraPos - bBoxWorld );
|
||||
|
||||
transparentModelList.emplace_back( &mtr, distanceToCamera );
|
||||
}
|
||||
|
||||
// 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;
|
||||
} );
|
||||
|
||||
// Start rendering calls
|
||||
glPushMatrix();
|
||||
|
||||
bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected &&
|
||||
m_boardAdapter.m_IsBoardView );
|
||||
|
||||
MODEL_3D::BeginDrawMulti( isUsingColorInformation );
|
||||
|
||||
for( const std::pair<const MODELTORENDER *, float>& mtr : transparentModelList )
|
||||
{
|
||||
if( m_boardAdapter.m_IsBoardView )
|
||||
{
|
||||
// Toggle between using model color or the select color
|
||||
if( !isUsingColorInformation && !mtr.first->m_isSelected )
|
||||
{
|
||||
isUsingColorInformation = true;
|
||||
|
||||
glEnableClientState( GL_COLOR_ARRAY );
|
||||
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( isUsingColorInformation && mtr.first->m_isSelected )
|
||||
{
|
||||
isUsingColorInformation = false;
|
||||
|
||||
glDisableClientState( GL_COLOR_ARRAY );
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glDisable( GL_COLOR_MATERIAL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
// Render model, sort each individuall material group
|
||||
// by passing cameraPos
|
||||
renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos );
|
||||
}
|
||||
|
||||
MODEL_3D::EndDrawMulti();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix,
|
||||
const MODELTORENDER &aModelToRender,
|
||||
const SFVEC3F &aSelColor,
|
||||
const SFVEC3F *aCameraWorldPos )
|
||||
{
|
||||
const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat;
|
||||
|
||||
glLoadMatrixf( glm::value_ptr( modelviewMatrix ) );
|
||||
|
||||
aModelToRender.m_model->Draw( aModelToRender.m_isTransparent,
|
||||
aModelToRender.m_opacity,
|
||||
aModelToRender.m_isSelected,
|
||||
aSelColor,
|
||||
&aModelToRender.m_modelWorldMat,
|
||||
aCameraWorldPos );
|
||||
|
||||
if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox )
|
||||
{
|
||||
const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
|
||||
|
||||
if( !wasBlendEnabled )
|
||||
{
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
}
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
|
||||
glLineWidth( 1 );
|
||||
aModelToRender.m_model->DrawBboxes();
|
||||
|
||||
glLineWidth( 4 );
|
||||
aModelToRender.m_model->DrawBbox();
|
||||
|
||||
glEnable( GL_LIGHTING );
|
||||
|
||||
if( !wasBlendEnabled )
|
||||
{
|
||||
glDisable( GL_BLEND );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,18 +129,44 @@ private:
|
||||
*/
|
||||
void load3dModels( REPORTER* aStatusReporter );
|
||||
|
||||
/**
|
||||
* @param aRenderTopOrBot true will render Top, false will render bottom
|
||||
* @param aRenderTransparentOnly true will render only the transparent objects, false will
|
||||
* render opaque
|
||||
*/
|
||||
void render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly );
|
||||
struct MODELTORENDER
|
||||
{
|
||||
glm::mat4 m_modelWorldMat;
|
||||
const MODEL_3D* m_model;
|
||||
float m_opacity;
|
||||
bool m_isTransparent;
|
||||
bool m_isSelected;
|
||||
|
||||
void render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly,
|
||||
bool aRenderSelectedOnly );
|
||||
MODELTORENDER( glm::mat4 aModelWorldMat,
|
||||
const MODEL_3D* aNodel,
|
||||
float aOpacity,
|
||||
bool aIsTransparent,
|
||||
bool aIsSelected ) :
|
||||
m_modelWorldMat( std::move( aModelWorldMat ) ),
|
||||
m_model( aNodel ),
|
||||
m_opacity( aOpacity ),
|
||||
m_isTransparent( aIsTransparent ),
|
||||
m_isSelected( aIsSelected )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||
bool aIsSelected );
|
||||
void renderOpaqueModels( const glm::mat4 &aCameraViewMatrix );
|
||||
void renderTransparentModels( const glm::mat4 &aCameraViewMatrix );
|
||||
|
||||
void renderModel( const glm::mat4 &aCameraViewMatrix,
|
||||
const MODELTORENDER &aModelToRender,
|
||||
const SFVEC3F &aSelColor,
|
||||
const SFVEC3F *aCameraWorldPos );
|
||||
|
||||
|
||||
void get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList,
|
||||
bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
|
||||
bool aRenderSelectedOnly );
|
||||
|
||||
void get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
|
||||
const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||
bool aIsSelected );
|
||||
|
||||
void setLightFront( bool enabled );
|
||||
void setLightTop( bool enabled );
|
||||
@@ -210,7 +236,7 @@ private:
|
||||
|
||||
// Caches
|
||||
std::map< wxString, MODEL_3D* > m_3dModelMap;
|
||||
std::map< std::vector<double>, glm::mat4 > m_3dModelMatrixMap;
|
||||
std::map< std::vector<float>, glm::mat4 > m_3dModelMatrixMap;
|
||||
|
||||
BOARD_ITEM* m_currentRollOverItem;
|
||||
|
||||
|
||||
@@ -229,6 +229,16 @@ bool BBOX_2D::Inside( const SFVEC2F& aPoint ) const
|
||||
}
|
||||
|
||||
|
||||
bool BBOX_2D::Inside( const BBOX_2D& aBBox ) const
|
||||
{
|
||||
wxASSERT( IsInitialized() );
|
||||
wxASSERT( aBBox.IsInitialized() );
|
||||
|
||||
return Inside( aBBox.Min() ) &&
|
||||
Inside( aBBox.Max() );
|
||||
}
|
||||
|
||||
|
||||
float BBOX_2D::Area() const
|
||||
{
|
||||
SFVEC2F extent = GetExtent();
|
||||
|
||||
@@ -132,6 +132,14 @@ public:
|
||||
*/
|
||||
bool Inside( const SFVEC2F& aPoint ) const;
|
||||
|
||||
/**
|
||||
* Check if a bounding box is inside this bounding box.
|
||||
*
|
||||
* @param aBBox the bounding box to test if it is inside
|
||||
* @return true if aBBox is smaller and all points are inside
|
||||
*/
|
||||
bool Inside( const BBOX_2D& aBBox ) const;
|
||||
|
||||
/**
|
||||
* Calculate the area of a bounding box.
|
||||
*
|
||||
|
||||
@@ -238,6 +238,16 @@ bool BBOX_3D::Inside( const SFVEC3F& aPoint ) const
|
||||
}
|
||||
|
||||
|
||||
bool BBOX_3D::Inside( const BBOX_3D& aBBox ) const
|
||||
{
|
||||
wxASSERT( IsInitialized() );
|
||||
wxASSERT( aBBox.IsInitialized() );
|
||||
|
||||
return Inside( aBBox.Min() ) &&
|
||||
Inside( aBBox.Max() );
|
||||
}
|
||||
|
||||
|
||||
float BBOX_3D::Volume() const
|
||||
{
|
||||
wxASSERT( IsInitialized() );
|
||||
|
||||
@@ -125,6 +125,14 @@ public:
|
||||
*/
|
||||
bool Inside( const SFVEC3F& aPoint ) const;
|
||||
|
||||
/**
|
||||
* Check if a bounding box is inside this bounding box.
|
||||
*
|
||||
* @param aBBox the bounding box to test if it is inside
|
||||
* @return true if aBBox is smaller and all points are inside
|
||||
*/
|
||||
bool Inside( const BBOX_3D& aBBox ) const;
|
||||
|
||||
/**
|
||||
* Apply a transformation matrix to the box points.
|
||||
*
|
||||
|
||||
@@ -70,6 +70,8 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
|
||||
|
||||
m_selected = -1;
|
||||
|
||||
m_previewLabel->SetFont( KIUI::GetStatusFont( this ) );
|
||||
|
||||
// Set the bitmap of 3D view buttons:
|
||||
m_bpvTop->SetBitmap( KiBitmap( BITMAPS::axis3d_top ) );
|
||||
m_bpvFront->SetBitmap( KiBitmap( BITMAPS::axis3d_front ) );
|
||||
@@ -140,6 +142,9 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
|
||||
this );
|
||||
}
|
||||
|
||||
aFrame->Connect( UNITS_CHANGED, wxCommandEventHandler( PANEL_PREVIEW_3D_MODEL::onUnitsChanged ),
|
||||
nullptr, this );
|
||||
|
||||
#ifdef __WXOSX__
|
||||
// Call layout once to get the proper button sizes after the bitmaps have been set
|
||||
Layout();
|
||||
@@ -538,6 +543,29 @@ void PANEL_PREVIEW_3D_MODEL::onMouseWheelOffset( wxMouseEvent& event )
|
||||
}
|
||||
|
||||
|
||||
void PANEL_PREVIEW_3D_MODEL::onUnitsChanged( wxCommandEvent& aEvent )
|
||||
{
|
||||
double xoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
|
||||
xoff->GetValue() )
|
||||
/ pcbIUScale.IU_PER_MM;
|
||||
double yoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
|
||||
yoff->GetValue() )
|
||||
/ pcbIUScale.IU_PER_MM;
|
||||
double zoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
|
||||
zoff->GetValue() )
|
||||
/ pcbIUScale.IU_PER_MM;
|
||||
|
||||
PCB_BASE_FRAME* frame = static_cast<PCB_BASE_FRAME*>( aEvent.GetClientData() );
|
||||
m_userUnits = frame->GetUserUnits();
|
||||
|
||||
xoff->SetValue( formatOffsetValue( xoff_mm ) );
|
||||
yoff->SetValue( formatOffsetValue( yoff_mm ) );
|
||||
zoff->SetValue( formatOffsetValue( zoff_mm ) );
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
|
||||
void PANEL_PREVIEW_3D_MODEL::UpdateDummyFootprint( bool aReloadRequired )
|
||||
{
|
||||
m_dummyFootprint->Models().clear();
|
||||
|
||||
@@ -141,6 +141,8 @@ private:
|
||||
void doIncrementRotation( wxSpinEvent& aEvent, double aSign );
|
||||
void doIncrementOffset( wxSpinEvent& aEvent, double aSign );
|
||||
|
||||
void onUnitsChanged( wxCommandEvent& aEvent );
|
||||
|
||||
wxString formatScaleValue( double aValue );
|
||||
wxString formatRotationValue( double aValue );
|
||||
wxString formatOffsetValue( double aValue );
|
||||
|
||||
@@ -183,12 +183,11 @@ PANEL_PREVIEW_3D_MODEL_BASE::PANEL_PREVIEW_3D_MODEL_BASE( wxWindow* parent, wxWi
|
||||
wxBoxSizer* bSizer6;
|
||||
bSizer6 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
wxStaticText* staticPreviewLabel;
|
||||
staticPreviewLabel = new wxStaticText( this, wxID_ANY, _("Preview"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
staticPreviewLabel->Wrap( -1 );
|
||||
staticPreviewLabel->SetFont( wxFont( 11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
|
||||
m_previewLabel = new wxStaticText( this, wxID_ANY, _("Preview"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_previewLabel->Wrap( -1 );
|
||||
m_previewLabel->SetFont( wxFont( 11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
|
||||
|
||||
bSizer6->Add( staticPreviewLabel, 0, wxEXPAND|wxLEFT|wxRIGHT, 10 );
|
||||
bSizer6->Add( m_previewLabel, 1, wxEXPAND|wxLEFT|wxRIGHT, 10 );
|
||||
|
||||
|
||||
bSizerRight->Add( bSizer6, 0, wxEXPAND, 5 );
|
||||
@@ -207,7 +206,7 @@ PANEL_PREVIEW_3D_MODEL_BASE::PANEL_PREVIEW_3D_MODEL_BASE( wxWindow* parent, wxWi
|
||||
m_bpvISO = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 );
|
||||
m_bpvISO->SetToolTip( _("Enable/disable orthographic projection") );
|
||||
|
||||
bSizer3DButtons->Add( m_bpvISO, 0, wxTOP|wxBOTTOM, 5 );
|
||||
bSizer3DButtons->Add( m_bpvISO, 0, wxTOP, 14 );
|
||||
|
||||
|
||||
bSizer3DButtons->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
@@ -2089,7 +2089,7 @@
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">10</property>
|
||||
<property name="flag">wxEXPAND|wxLEFT|wxRIGHT</property>
|
||||
<property name="proportion">0</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
@@ -2127,11 +2127,11 @@
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">staticPreviewLabel</property>
|
||||
<property name="name">m_previewLabel</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">none</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
@@ -2172,8 +2172,8 @@
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxTOP|wxBOTTOM</property>
|
||||
<property name="border">14</property>
|
||||
<property name="flag">wxTOP</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBitmapButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
|
||||
@@ -68,6 +68,7 @@ class PANEL_PREVIEW_3D_MODEL_BASE : public wxPanel
|
||||
wxSlider* m_opacity;
|
||||
wxTextCtrl* m_boardThicknessCtrl;
|
||||
wxStaticText* m_boardThicknessUnits;
|
||||
wxStaticText* m_previewLabel;
|
||||
wxBoxSizer* m_SizerPanelView;
|
||||
wxBitmapButton* m_bpvISO;
|
||||
wxBitmapButton* m_bpvLeft;
|
||||
|
||||
+6
-2
@@ -350,12 +350,16 @@ endif(USE_DISTCC)
|
||||
# Set flags for GCC, or treat llvm as GCC
|
||||
#================================================
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
# Set 32-bit flag for GCC to prevent excess precision
|
||||
# clang des not know this flag, so keep this separate
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 4 )
|
||||
set( CMAKE_CXX_FLAGS "-ffloat-store ${CMAKE_CXX_FLAGS}" )
|
||||
endif()
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||
|
||||
# Link flags in Debug: -g1 and -ggdb1 or -g1 and -ggdb3 can be used.
|
||||
# Level 1 produces minimal information, enough for making basic backtraces.
|
||||
|
||||
@@ -66,7 +66,7 @@ macro( create_git_version_header _git_src_path )
|
||||
# Check to make sure 'git' command did not fail. Otherwise fallback
|
||||
# to KiCadVersion.cmake as the revision level.
|
||||
if( _git_describe_result EQUAL 0 )
|
||||
set( KICAD_VERSION "(${_git_DESCRIBE})" )
|
||||
set( KICAD_VERSION "${_git_DESCRIBE}" )
|
||||
endif()
|
||||
|
||||
if( _git_rev_parse_head_result EQUAL 0 )
|
||||
|
||||
@@ -926,8 +926,17 @@ if(wxWidgets_FOUND)
|
||||
"\\2" wxWidgets_VERSION_MINOR "${_wx_version_h}" )
|
||||
string(REGEX REPLACE "^(.*\n)?#define +wxRELEASE_NUMBER +([0-9]+).*"
|
||||
"\\2" wxWidgets_VERSION_PATCH "${_wx_version_h}" )
|
||||
set(wxWidgets_VERSION_STRING
|
||||
"${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}" )
|
||||
string(REGEX REPLACE "^(.*\n)?#define +wxSUBRELEASE_NUMBER +([0-9]+).*"
|
||||
"\\2" wxWidgets_VERSION_SUBRELEASE "${_wx_version_h}" )
|
||||
|
||||
if( ${wxWidgets_VERSION_SUBRELEASE} GREATER 0 )
|
||||
set(wxWidgets_VERSION_STRING
|
||||
"${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}.${wxWidgets_VERSION_SUBRELEASE}" )
|
||||
else()
|
||||
set(wxWidgets_VERSION_STRING
|
||||
"${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}" )
|
||||
endif()
|
||||
|
||||
DBG_MSG("wxWidgets_VERSION_STRING: ${wxWidgets_VERSION_STRING}")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# KiCad.
|
||||
#
|
||||
# Note: This version string should follow the semantic versioning system
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.0" )
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.1" )
|
||||
|
||||
# Default the version to the semantic version.
|
||||
# This is overridden by the git repository tag though (if using git)
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <eda_base_frame.h>
|
||||
#include <eda_draw_frame.h>
|
||||
#include <paths.h>
|
||||
#include <kiplatform/ui.h>
|
||||
|
||||
|
||||
static std::unique_ptr<BITMAP_STORE> s_BitmapStore;
|
||||
|
||||
+18
-11
@@ -75,6 +75,7 @@ void BITMAP_BASE::SetImage( wxImage* aImage )
|
||||
delete m_originalImage;
|
||||
m_originalImage = new wxImage( *aImage );
|
||||
rebuildBitmap();
|
||||
updatePPI();
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +91,21 @@ void BITMAP_BASE::rebuildBitmap( bool aResetID )
|
||||
}
|
||||
|
||||
|
||||
void BITMAP_BASE::updatePPI()
|
||||
{
|
||||
// Todo: eventually we need to support dpi / scaling in both dimensions
|
||||
int dpiX = m_originalImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
|
||||
|
||||
if( dpiX > 1 )
|
||||
{
|
||||
if( m_originalImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
|
||||
m_ppi = KiROUND( dpiX * 2.54 );
|
||||
else
|
||||
m_ppi = dpiX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BITMAP_BASE::ImportData( BITMAP_BASE* aItem )
|
||||
{
|
||||
*m_image = *aItem->m_image;
|
||||
@@ -116,6 +132,7 @@ bool BITMAP_BASE::ReadImageFile( wxInputStream& aInStream )
|
||||
delete m_originalImage;
|
||||
m_originalImage = new wxImage( *m_image );
|
||||
rebuildBitmap();
|
||||
updatePPI();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -136,17 +153,7 @@ bool BITMAP_BASE::ReadImageFile( const wxString& aFullFilename )
|
||||
delete m_originalImage;
|
||||
m_originalImage = new wxImage( *m_image );
|
||||
rebuildBitmap();
|
||||
|
||||
// Todo: eventually we need to support dpi / scaling in both dimensions
|
||||
int dpiX = m_originalImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
|
||||
|
||||
if( dpiX > 1 )
|
||||
{
|
||||
if( m_originalImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
|
||||
m_ppi = KiROUND( dpiX * 2.54 );
|
||||
else
|
||||
m_ppi = dpiX;
|
||||
}
|
||||
updatePPI();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022-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
|
||||
@@ -178,7 +178,15 @@ bool DATABASE_CONNECTION::Disconnect()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_conn->disconnect();
|
||||
try
|
||||
{
|
||||
m_conn->disconnect();
|
||||
}
|
||||
catch( boost::locale::conv::conversion_error& exc )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "Disconnect() error \"%s\" occured." ), exc.what() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return !m_conn->connected();
|
||||
}
|
||||
|
||||
@@ -1129,7 +1129,7 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
|
||||
#define SYMBOL_LIB_CONTRIBUTION _( "Symbols by" )
|
||||
aInfo.AddLibrarian( new CONTRIBUTOR( wxS( "GitLab contributors" ),
|
||||
wxEmptyString,
|
||||
wxS( "https://gitlab.com/kicad/libraries/kicad-symbols/-/graphs/v7" ),
|
||||
wxS( "https://gitlab.com/kicad/libraries/kicad-symbols/-/graphs/master" ),
|
||||
SYMBOL_LIB_CONTRIBUTION,
|
||||
aInfo.CreateKiBitmap( BITMAPS::add_component ) ) );
|
||||
|
||||
|
||||
@@ -262,8 +262,11 @@ void PANEL_COLOR_SETTINGS::createSwatch( int aLayer, const wxString& aName )
|
||||
defaultColor, SWATCH_MEDIUM );
|
||||
swatch->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
|
||||
|
||||
m_colorsGridSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxLEFT, 5 );
|
||||
// Display the swatches in the left column and the layer name in the right column
|
||||
// The right column is sometimes (depending on the translation) truncated for long texts.
|
||||
// We cannot allow swatches to be truncated or not shown
|
||||
m_colorsGridSizer->Add( swatch, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3 );
|
||||
m_colorsGridSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxLEFT, 5 );
|
||||
|
||||
m_labels[aLayer] = label;
|
||||
m_swatches[aLayer] = swatch;
|
||||
|
||||
@@ -58,7 +58,13 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||
const wxPoint& aPosition, const wxSize& aSize,
|
||||
KIGFX::GAL_DISPLAY_OPTIONS& aOptions, GAL_TYPE aGalType ) :
|
||||
wxScrolledCanvas( aParentWindow, aWindowId, aPosition, aSize ),
|
||||
m_MouseCapturedLost( false ),
|
||||
m_parent( aParentWindow ),
|
||||
m_edaFrame( nullptr ),
|
||||
m_lastRefresh( 0 ),
|
||||
m_pendingRefresh( false ),
|
||||
m_drawing( false ),
|
||||
m_drawingEnabled( false ),
|
||||
m_gal( nullptr ),
|
||||
m_view( nullptr ),
|
||||
m_painter( nullptr ),
|
||||
@@ -70,11 +76,10 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||
m_stealsFocus( true ),
|
||||
m_statusPopup( nullptr )
|
||||
{
|
||||
m_parent = aParentWindow;
|
||||
m_MouseCapturedLost = false;
|
||||
|
||||
m_PaintEventCounter = std::make_unique<PROF_COUNTER>( "Draw panel paint events" );
|
||||
|
||||
m_minRefreshPeriod = 13; // 77 FPS (minus render time) by default
|
||||
|
||||
SetLayoutDirection( wxLayout_LeftToRight );
|
||||
|
||||
m_edaFrame = dynamic_cast<EDA_DRAW_FRAME*>( m_parent );
|
||||
@@ -146,12 +151,6 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||
Connect( eventType, wxEventHandler( EDA_DRAW_PANEL_GAL::OnEvent ), nullptr,
|
||||
m_eventDispatcher );
|
||||
|
||||
m_pendingRefresh = false;
|
||||
m_drawing = false;
|
||||
m_drawingEnabled = false;
|
||||
|
||||
m_minRefreshPeriod = 13; // 77 FPS (minus render time) by default
|
||||
|
||||
// Set up timer that prevents too frequent redraw commands
|
||||
m_refreshTimer.SetOwner( this );
|
||||
Connect( m_refreshTimer.GetId(), wxEVT_TIMER,
|
||||
@@ -212,7 +211,7 @@ void EDA_DRAW_PANEL_GAL::DoRePaint()
|
||||
if( !m_drawingEnabled )
|
||||
return;
|
||||
|
||||
if( !m_gal->IsVisible() )
|
||||
if( !m_gal->IsInitialized() || !m_gal->IsVisible() )
|
||||
return;
|
||||
|
||||
m_pendingRefresh = false;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2004-2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2004-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
|
||||
@@ -78,12 +78,16 @@ BEGIN_EVENT_TABLE( EDA_DRAW_FRAME, KIWAY_PLAYER )
|
||||
EVT_ACTIVATE( EDA_DRAW_FRAME::onActivate )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
bool EDA_DRAW_FRAME::m_openGLFailureOccured = false;
|
||||
|
||||
|
||||
EDA_DRAW_FRAME::EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType,
|
||||
const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize,
|
||||
long aStyle, const wxString& aFrameName, const EDA_IU_SCALE& aIuScale ) :
|
||||
KIWAY_PLAYER( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName, aIuScale )
|
||||
long aStyle, const wxString& aFrameName,
|
||||
const EDA_IU_SCALE& aIuScale ) :
|
||||
KIWAY_PLAYER( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName, aIuScale ),
|
||||
m_socketServer( nullptr )
|
||||
{
|
||||
m_socketServer = nullptr;
|
||||
m_mainToolBar = nullptr;
|
||||
@@ -171,8 +175,8 @@ EDA_DRAW_FRAME::EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrame
|
||||
OnMove( dummy );
|
||||
|
||||
// we need to kludge the msg panel to the correct size again
|
||||
// especially important even for first launches as the constructor of the window here usually doesn't
|
||||
// have the correct dpi awareness yet
|
||||
// especially important even for first launches as the constructor of the window
|
||||
// here usually doesn't have the correct dpi awareness yet
|
||||
m_frameSize.y += m_msgFrameHeight;
|
||||
m_msgFrameHeight = EDA_MSG_PANEL::GetRequiredHeight( this );
|
||||
m_frameSize.y -= m_msgFrameHeight;
|
||||
@@ -609,7 +613,8 @@ void EDA_DRAW_FRAME::DisplayGridMsg()
|
||||
{
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( wxS( "grid %s" ), MessageTextFromValue( GetCanvas()->GetGAL()->GetGridSize().x, false ) );
|
||||
msg.Printf( wxS( "grid %s" ), MessageTextFromValue( GetCanvas()->GetGAL()->GetGridSize().x,
|
||||
false ) );
|
||||
|
||||
SetStatusText( msg, 4 );
|
||||
}
|
||||
|
||||
+3
-4
@@ -392,10 +392,9 @@ static struct EDA_ITEM_DESC
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( EDA_ITEM );
|
||||
|
||||
auto typeProp = new PROPERTY_ENUM<EDA_ITEM, KICAD_T>( wxS( "Type" ),
|
||||
NO_SETTER( EDA_ITEM, KICAD_T ), &EDA_ITEM::Type );
|
||||
typeProp->SetIsInternal( true );
|
||||
propMgr.AddProperty( typeProp );
|
||||
propMgr.AddProperty( new PROPERTY_ENUM<EDA_ITEM, KICAD_T>( wxS( "Type" ),
|
||||
NO_SETTER( EDA_ITEM, KICAD_T ), &EDA_ITEM::Type ) )
|
||||
.SetIsInternal();
|
||||
}
|
||||
} _EDA_ITEM_DESC;
|
||||
|
||||
|
||||
+19
-4
@@ -1687,21 +1687,36 @@ static struct EDA_SHAPE_DESC
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( EDA_SHAPE );
|
||||
|
||||
auto isNotPolygon =
|
||||
[]( INSPECTABLE* aItem ) -> bool
|
||||
{
|
||||
// Polygons, unlike other shapes, have no meaningful start or end coordinates
|
||||
if( EDA_SHAPE* shape = dynamic_cast<EDA_SHAPE*>( aItem ) )
|
||||
return shape->GetShape() != SHAPE_T::POLY;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto shape = new PROPERTY_ENUM<EDA_SHAPE, SHAPE_T>( _HKI( "Shape" ),
|
||||
NO_SETTER( EDA_SHAPE, SHAPE_T ), &EDA_SHAPE::GetShape );
|
||||
propMgr.AddProperty( shape );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Start X" ),
|
||||
&EDA_SHAPE::SetStartX, &EDA_SHAPE::GetStartX, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ) );
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ) )
|
||||
.SetAvailableFunc( isNotPolygon );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Start Y" ),
|
||||
&EDA_SHAPE::SetStartY, &EDA_SHAPE::GetStartY, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ) );
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ) )
|
||||
.SetAvailableFunc( isNotPolygon );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "End X" ),
|
||||
&EDA_SHAPE::SetEndX, &EDA_SHAPE::GetEndX, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ) );
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ) )
|
||||
.SetAvailableFunc( isNotPolygon );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "End Y" ),
|
||||
&EDA_SHAPE::SetEndY, &EDA_SHAPE::GetEndY, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ) );
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ) )
|
||||
.SetAvailableFunc( isNotPolygon );
|
||||
// TODO: m_arcCenter, m_bezierC1, m_bezierC2, m_poly
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Line Width" ),
|
||||
&EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth, PROPERTY_DISPLAY::PT_SIZE ) );
|
||||
|
||||
@@ -65,7 +65,7 @@ int EDA_UNIT_UTILS::Mils2mm( double aVal )
|
||||
}
|
||||
|
||||
|
||||
void EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
|
||||
bool EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
|
||||
{
|
||||
wxString buf( aTextValue.Strip( wxString::both ) );
|
||||
unsigned brk_point = 0;
|
||||
@@ -92,6 +92,9 @@ void EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS
|
||||
aUnits = EDA_UNITS::INCHES;
|
||||
else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad"
|
||||
aUnits = EDA_UNITS::DEGREES;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+143
-32
@@ -18,23 +18,25 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
#include <font/fontconfig.h>
|
||||
#include <pgm_base.h>
|
||||
#include <wx/log.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <string_utils.h>
|
||||
#include <macros.h>
|
||||
#include <font/fontconfig.h>
|
||||
|
||||
using namespace fontconfig;
|
||||
|
||||
static FONTCONFIG* g_config = nullptr;
|
||||
|
||||
|
||||
inline static FcChar8* wxStringToFcChar8( const wxString& str )
|
||||
/**
|
||||
* A simple wrapper to avoid exporing fontconfig in the header
|
||||
*/
|
||||
struct fontconfig::FONTCONFIG_PAT
|
||||
{
|
||||
wxScopedCharBuffer const fcBuffer = str.ToUTF8();
|
||||
return (FcChar8*) fcBuffer.data();
|
||||
}
|
||||
FcPattern* pat;
|
||||
};
|
||||
|
||||
|
||||
wxString FONTCONFIG::Version()
|
||||
@@ -61,19 +63,112 @@ FONTCONFIG* Fontconfig()
|
||||
}
|
||||
|
||||
|
||||
bool FONTCONFIG::isLanguageMatch( const wxString& aSearchLang, const wxString& aSupportedLang )
|
||||
{
|
||||
if( aSearchLang.Lower() == aSupportedLang.Lower() )
|
||||
return true;
|
||||
|
||||
if( aSupportedLang.empty() )
|
||||
return false;
|
||||
|
||||
if( aSearchLang.empty() )
|
||||
return false;
|
||||
|
||||
wxArrayString supportedLangBits;
|
||||
wxStringSplit( aSupportedLang.Lower(), supportedLangBits, wxS( '-' ) );
|
||||
|
||||
wxArrayString searhcLangBits;
|
||||
wxStringSplit( aSearchLang.Lower(), searhcLangBits, wxS( '-' ) );
|
||||
|
||||
// if either side of the comparison have only one section, then its a broad match but fine
|
||||
// i.e. the haystack is declaring broad support or the search language is broad
|
||||
if( searhcLangBits.size() == 1 || supportedLangBits.size() == 1 )
|
||||
{
|
||||
return searhcLangBits[0] == supportedLangBits[0];
|
||||
}
|
||||
|
||||
// the full two part comparison should have passed the initial shortcut
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string FONTCONFIG::getFcString( FONTCONFIG_PAT& aPat, const char* aObj, int aIdx )
|
||||
{
|
||||
FcChar8* str;
|
||||
std::string res;
|
||||
|
||||
if( FcPatternGetString( aPat.pat, aObj, aIdx, &str ) == FcResultMatch )
|
||||
res = std::string( reinterpret_cast<char*>( str ) );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void FONTCONFIG::getAllFamilyStrings( FONTCONFIG_PAT& aPat,
|
||||
std::unordered_map<std::string, std::string>& aFamStringMap )
|
||||
{
|
||||
std::string famLang;
|
||||
std::string fam;
|
||||
|
||||
int langIdx = 0;
|
||||
do
|
||||
{
|
||||
famLang = getFcString( aPat, FC_FAMILYLANG, langIdx );
|
||||
|
||||
if( famLang.empty() && langIdx != 0 )
|
||||
break;
|
||||
else
|
||||
{
|
||||
fam = getFcString( aPat, FC_FAMILY, langIdx );
|
||||
aFamStringMap.insert_or_assign( famLang, fam );
|
||||
}
|
||||
} while( langIdx++ < std::numeric_limits<
|
||||
int8_t>::max() ); //arbitrary to avoid getting stuck for any reason
|
||||
}
|
||||
|
||||
|
||||
std::string FONTCONFIG::getFamilyStringByLang( FONTCONFIG_PAT& aPat, const wxString& aDesiredLang )
|
||||
{
|
||||
std::unordered_map<std::string, std::string> famStrings;
|
||||
getAllFamilyStrings( aPat, famStrings );
|
||||
|
||||
if( famStrings.empty() )
|
||||
return "";
|
||||
|
||||
for( auto const& [key, val] : famStrings )
|
||||
{
|
||||
if( isLanguageMatch( aDesiredLang, FROM_UTF8( key.c_str() ) ) )
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to the first and maybe only available name
|
||||
// most fonts by review don't even bother declaring more than one font family name
|
||||
// and they don't even bother declare the language tag either, they just leave it blank
|
||||
return famStrings.begin()->second;
|
||||
}
|
||||
|
||||
|
||||
FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString &aFontFile,
|
||||
bool aBold, bool aItalic )
|
||||
{
|
||||
FF_RESULT retval = FF_RESULT::FF_ERROR;
|
||||
wxString qualifiedFontName = aFontName;
|
||||
|
||||
wxScopedCharBuffer const fcBuffer = qualifiedFontName.ToUTF8();
|
||||
|
||||
FcPattern* pat = FcPatternCreate();
|
||||
|
||||
if( aBold )
|
||||
qualifiedFontName << wxS( ":Bold" );
|
||||
FcPatternAddString( pat, FC_STYLE, (const FcChar8*) "Bold" );
|
||||
|
||||
if( aItalic )
|
||||
qualifiedFontName << wxS( ":Italic" );
|
||||
FcPatternAddString( pat, FC_STYLE, (const FcChar8*) "Italic" );
|
||||
|
||||
FcPatternAddString( pat, FC_FAMILY, (FcChar8*) fcBuffer.data() );
|
||||
|
||||
FcPattern* pat = FcNameParse( wxStringToFcChar8( qualifiedFontName ) );
|
||||
FcConfigSubstitute( nullptr, pat, FcMatchPattern );
|
||||
FcDefaultSubstitute( pat );
|
||||
|
||||
@@ -95,6 +190,9 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
|
||||
retval = FF_RESULT::FF_SUBSTITUTE;
|
||||
|
||||
std::unordered_map<std::string, std::string> famStrings;
|
||||
FONTCONFIG_PAT patHolder{ font };
|
||||
getAllFamilyStrings( patHolder, famStrings );
|
||||
if( FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch )
|
||||
{
|
||||
fontName = wxString::FromUTF8( (char*) family );
|
||||
@@ -129,19 +227,29 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
has_ital = true;
|
||||
}
|
||||
|
||||
if( fontName.Lower().StartsWith( aFontName.Lower() ) )
|
||||
for( auto const& [key, val] : famStrings )
|
||||
{
|
||||
if( ( aBold && !has_bold ) && ( aItalic && !has_ital ) )
|
||||
retval = FF_RESULT::FF_MISSING_BOLD_ITAL;
|
||||
else if( aBold && !has_bold )
|
||||
retval = FF_RESULT::FF_MISSING_BOLD;
|
||||
else if( aItalic && !has_ital )
|
||||
retval = FF_RESULT::FF_MISSING_ITAL;
|
||||
else if( ( aBold != has_bold ) || ( aItalic != has_ital ) )
|
||||
retval = FF_RESULT::FF_SUBSTITUTE;
|
||||
else
|
||||
retval = FF_RESULT::FF_OK;
|
||||
wxString searchFont;
|
||||
searchFont = wxString::FromUTF8( (char*) val.data() );
|
||||
|
||||
if( searchFont.Lower().StartsWith( aFontName.Lower() ) )
|
||||
{
|
||||
if( ( aBold && !has_bold ) && ( aItalic && !has_ital ) )
|
||||
retval = FF_RESULT::FF_MISSING_BOLD_ITAL;
|
||||
else if( aBold && !has_bold )
|
||||
retval = FF_RESULT::FF_MISSING_BOLD;
|
||||
else if( aItalic && !has_ital )
|
||||
retval = FF_RESULT::FF_MISSING_ITAL;
|
||||
else if( ( aBold != has_bold ) || ( aItalic != has_ital ) )
|
||||
retval = FF_RESULT::FF_SUBSTITUTE;
|
||||
else
|
||||
retval = FF_RESULT::FF_OK;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,13 +266,14 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
}
|
||||
|
||||
|
||||
void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts, const std::string& aDesiredLang )
|
||||
{
|
||||
if( m_fonts.empty() )
|
||||
// be sure to cache bust if the language changed
|
||||
if( m_fontInfoCache.empty() || m_fontCacheLastLang != aDesiredLang )
|
||||
{
|
||||
FcPattern* pat = FcPatternCreate();
|
||||
FcObjectSet* os = FcObjectSetBuild( FC_FAMILY, FC_STYLE, FC_LANG, FC_FILE, FC_OUTLINE,
|
||||
nullptr );
|
||||
FcObjectSet* os = FcObjectSetBuild( FC_FAMILY, FC_FAMILYLANG, FC_STYLE, FC_LANG, FC_FILE,
|
||||
FC_OUTLINE, nullptr );
|
||||
FcFontSet* fs = FcFontList( nullptr, pat, os );
|
||||
|
||||
for( int i = 0; fs && i < fs->nfont; ++i )
|
||||
@@ -172,12 +281,10 @@ void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
FcPattern* font = fs->fonts[i];
|
||||
FcChar8* file;
|
||||
FcChar8* style;
|
||||
FcChar8* family;
|
||||
FcLangSet* langSet;
|
||||
FcBool outline;
|
||||
|
||||
if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch
|
||||
&& FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch
|
||||
&& FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch
|
||||
&& FcPatternGetLangSet( font, FC_LANG, 0, &langSet ) == FcResultMatch
|
||||
&& FcPatternGetBool( font, FC_OUTLINE, 0, &outline ) == FcResultMatch )
|
||||
@@ -185,7 +292,9 @@ void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
if( !outline )
|
||||
continue;
|
||||
|
||||
std::string theFamily( reinterpret_cast<char *>( family ) );
|
||||
FONTCONFIG_PAT patHolder{ font };
|
||||
std::string theFamily =
|
||||
getFamilyStringByLang( patHolder, FROM_UTF8( aDesiredLang.c_str() ) );
|
||||
|
||||
#ifdef __WXMAC__
|
||||
// On Mac (at least) some of the font names are in their own language. If
|
||||
@@ -238,10 +347,10 @@ void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
if( theFamily.length() > 0 && theFamily.front() == '.' )
|
||||
continue;
|
||||
|
||||
std::map<std::string, FONTINFO>::iterator it = m_fonts.find( theFamily );
|
||||
std::map<std::string, FONTINFO>::iterator it = m_fontInfoCache.find( theFamily );
|
||||
|
||||
if( it == m_fonts.end() )
|
||||
m_fonts.emplace( theFamily, fontInfo );
|
||||
if( it == m_fontInfoCache.end() )
|
||||
m_fontInfoCache.emplace( theFamily, fontInfo );
|
||||
else
|
||||
it->second.Children().push_back( fontInfo );
|
||||
}
|
||||
@@ -249,8 +358,10 @@ void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
|
||||
if( fs )
|
||||
FcFontSetDestroy( fs );
|
||||
|
||||
m_fontCacheLastLang = aDesiredLang;
|
||||
}
|
||||
|
||||
for( const std::pair<const std::string, FONTINFO>& entry : m_fonts )
|
||||
for( const std::pair<const std::string, FONTINFO>& entry : m_fontInfoCache )
|
||||
aFonts.push_back( entry.second.Family() );
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ using namespace KIFONT;
|
||||
|
||||
|
||||
FT_Library OUTLINE_FONT::m_freeType = nullptr;
|
||||
std::mutex OUTLINE_FONT::m_freeTypeMutex;
|
||||
|
||||
OUTLINE_FONT::OUTLINE_FONT() :
|
||||
m_face(NULL),
|
||||
@@ -51,6 +52,8 @@ OUTLINE_FONT::OUTLINE_FONT() :
|
||||
m_fakeBold( false ),
|
||||
m_fakeItal( false )
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
if( !m_freeType )
|
||||
FT_Init_FreeType( &m_freeType );
|
||||
}
|
||||
@@ -58,6 +61,8 @@ OUTLINE_FONT::OUTLINE_FONT() :
|
||||
|
||||
wxString OUTLINE_FONT::FreeTypeVersion()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
if( !m_freeType )
|
||||
FT_Init_FreeType( &m_freeType );
|
||||
|
||||
@@ -90,31 +95,36 @@ wxString OUTLINE_FONT::FontLibraryVersion()
|
||||
|
||||
OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, bool aItalic )
|
||||
{
|
||||
OUTLINE_FONT* font = new OUTLINE_FONT();
|
||||
std::unique_ptr<OUTLINE_FONT> font = std::make_unique<OUTLINE_FONT>();
|
||||
|
||||
wxString fontFile;
|
||||
using fc = fontconfig::FONTCONFIG;
|
||||
|
||||
fc::FF_RESULT retval = Fontconfig()->FindFont( aFontName, fontFile, aBold, aItalic );
|
||||
|
||||
if( retval == fc::FF_RESULT::FF_ERROR )
|
||||
return nullptr;
|
||||
|
||||
if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
|
||||
font->SetFakeBold();
|
||||
|
||||
if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
|
||||
font->SetFakeItal();
|
||||
|
||||
if( retval != fc::FF_RESULT::FF_ERROR )
|
||||
(void) font->loadFace( fontFile );
|
||||
if( font->loadFace( fontFile ) != 0 )
|
||||
return nullptr;
|
||||
|
||||
font->m_fontName = aFontName; // Keep asked-for name, even if we substituted.
|
||||
font->m_fontFileName = fontFile;
|
||||
|
||||
return font;
|
||||
return font.release();
|
||||
}
|
||||
|
||||
|
||||
FT_Error OUTLINE_FONT::loadFace( const wxString& aFontFileName )
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
// TODO: check that going from wxString to char* with UTF-8
|
||||
// conversion for filename makes sense on any/all platforms
|
||||
FT_Error e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), 0, &m_face );
|
||||
@@ -323,6 +333,18 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
||||
bool aMirror, const VECTOR2I& aOrigin,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
return getTextAsGlyphsUnlocked( aBBox, aGlyphs, aText, aSize, aPosition, aAngle, aMirror,
|
||||
aOrigin, aTextStyle );
|
||||
}
|
||||
|
||||
VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||
const wxString& aText, const VECTOR2I& aSize,
|
||||
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
||||
bool aMirror, const VECTOR2I& aOrigin,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
VECTOR2D glyphSize = aSize;
|
||||
FT_Face face = m_face;
|
||||
@@ -366,7 +388,7 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||
{
|
||||
FT_Matrix matrix;
|
||||
// Create a 12 degree slant
|
||||
const float angle = ( -M_PI * 12 ) / 180.0f;
|
||||
const float angle = (float)( -M_PI * 12.0f ) / 180.0f;
|
||||
matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
|
||||
matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
|
||||
matrix.yx = (FT_Fixed) ( 0 * 0x10000L ); // Don't rotate in the y direction
|
||||
@@ -466,7 +488,7 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||
{
|
||||
std::vector<std::unique_ptr<GLYPH>> underscoreGlyphs;
|
||||
|
||||
getTextAsGlyphs( nullptr, &underscoreGlyphs, wxT( "_" ), aSize, { 0, 0 }, ANGLE_0, false,
|
||||
getTextAsGlyphsUnlocked( nullptr, &underscoreGlyphs, wxT( "_" ), aSize, { 0, 0 }, ANGLE_0, false,
|
||||
{ 0, 0 }, aTextStyle & ~TEXT_STYLE::OVERBAR );
|
||||
|
||||
OUTLINE_GLYPH* underscoreGlyph = static_cast<OUTLINE_GLYPH*>( underscoreGlyphs[0].get() );
|
||||
@@ -552,6 +574,9 @@ void OUTLINE_FONT::RenderToOpenGLCanvas( KIGFX::OPENGL_GAL& aGal, const wxString
|
||||
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 );
|
||||
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
hb_font_t* referencedFont = hb_ft_font_create_referenced( m_face );
|
||||
|
||||
hb_ft_font_set_funcs( referencedFont );
|
||||
|
||||
+20
-10
@@ -52,7 +52,8 @@ static constexpr double UNDERLINE_POSITION_FACTOR = -0.16;
|
||||
///< Scale factor for a glyph
|
||||
static constexpr double STROKE_FONT_SCALE = 1.0 / 21.0;
|
||||
|
||||
static constexpr int FONT_OFFSET = -10;
|
||||
///< Offset (in stroke font units) to move the origin to the baseline.
|
||||
static constexpr int FONT_OFFSET = -8;
|
||||
|
||||
|
||||
bool g_defaultFontInitialized = false;
|
||||
@@ -225,11 +226,8 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||
bool aMirror, const VECTOR2I& aOrigin,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
constexpr double SPACE_WIDTH = 0.6;
|
||||
constexpr int TAB_WIDTH = 4;
|
||||
constexpr double INTER_CHAR = 0.2;
|
||||
constexpr double TAB_WIDTH = 4 * 0.82; // Not quite as wide as 5.1/6.0 tab formatting, but
|
||||
// a better match for Scintilla, and closer to the
|
||||
// nominal SPACE_WIDTH + INTER_CHAR
|
||||
constexpr double SUPER_SUB_SIZE_MULTIPLIER = 0.7;
|
||||
constexpr double SUPER_HEIGHT_OFFSET = 0.5;
|
||||
constexpr double SUB_HEIGHT_OFFSET = 0.3;
|
||||
@@ -237,6 +235,8 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||
VECTOR2I cursor( aPosition );
|
||||
VECTOR2D glyphSize( aSize );
|
||||
double tilt = ( aTextStyle & TEXT_STYLE::ITALIC ) ? ITALIC_TILT : 0.0;
|
||||
double space_width = m_glyphBoundingBoxes->front().GetWidth(); // First char is space
|
||||
int char_count = 0;
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::SUBSCRIPT || aTextStyle & TEXT_STYLE::SUPERSCRIPT )
|
||||
{
|
||||
@@ -250,18 +250,26 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||
|
||||
for( wxUniChar c : aText )
|
||||
{
|
||||
// Handle tabs as locked to the nearest 4th column (in space-widths).
|
||||
// Handle tabs as locked to the next 4th column (in base-widths).
|
||||
if( c == '\t' )
|
||||
{
|
||||
int tabWidth = KiROUND( glyphSize.x * TAB_WIDTH );
|
||||
int currentIntrusion = ( cursor.x - aOrigin.x ) % tabWidth;
|
||||
char_count = ( char_count / TAB_WIDTH + 1 ) * TAB_WIDTH - 1;
|
||||
|
||||
cursor.x += tabWidth - currentIntrusion;
|
||||
int new_cursor = aPosition.x + aSize.x * char_count
|
||||
+ aSize.x * space_width;
|
||||
|
||||
while( new_cursor <= cursor.x )
|
||||
{
|
||||
char_count += TAB_WIDTH;
|
||||
new_cursor += aSize.x * TAB_WIDTH;
|
||||
}
|
||||
|
||||
cursor.x = new_cursor;
|
||||
}
|
||||
else if( c == ' ' )
|
||||
{
|
||||
// 'space' character - draw nothing, advance cursor position
|
||||
cursor.x += KiROUND( glyphSize.x * SPACE_WIDTH );
|
||||
cursor.x += KiROUND( glyphSize.x * space_width );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -292,6 +300,8 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||
|
||||
cursor.x += KiROUND( glyphExtents.x );
|
||||
}
|
||||
|
||||
++char_count;
|
||||
}
|
||||
|
||||
VECTOR2D barOffset( 0.0, 0.0 );
|
||||
|
||||
@@ -596,6 +596,7 @@ bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable )
|
||||
}
|
||||
}
|
||||
|
||||
aTable.Clear();
|
||||
aTable.Load( fn.GetFullPath() );
|
||||
|
||||
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
|
||||
|
||||
+47
-13
@@ -57,11 +57,6 @@ static std::optional<double> getKiCadConfiguredScale( const COMMON_SETTINGS& aCo
|
||||
scale = canvas_scale;
|
||||
}
|
||||
|
||||
if( scale )
|
||||
{
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (configured): %f" ), *scale );
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
@@ -83,11 +78,6 @@ static std::optional<double> getEnvironmentScale()
|
||||
scale = ENV_VAR::GetEnvVar<double>( wxS( "GDK_SCALE" ) );
|
||||
}
|
||||
|
||||
if( scale )
|
||||
{
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (environment): %f" ), *scale );
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
@@ -101,15 +91,18 @@ DPI_SCALING::DPI_SCALING( COMMON_SETTINGS* aConfig, const wxWindow* aWindow )
|
||||
double DPI_SCALING::GetScaleFactor() const
|
||||
{
|
||||
std::optional<double> val;
|
||||
wxString src;
|
||||
|
||||
if( m_config )
|
||||
{
|
||||
val = getKiCadConfiguredScale( *m_config );
|
||||
src = wxS( "config" );
|
||||
}
|
||||
|
||||
if( !val )
|
||||
{
|
||||
val = getEnvironmentScale();
|
||||
src = wxS( "env" );
|
||||
}
|
||||
|
||||
if( !val && m_window )
|
||||
@@ -117,17 +110,58 @@ double DPI_SCALING::GetScaleFactor() const
|
||||
// Use the native WX reporting.
|
||||
// On Linux, this will not work until WX 3.2 and GTK >= 3.10
|
||||
// Otherwise it returns 1.0
|
||||
val = KIPLATFORM::UI::GetSystemScaleFactor( m_window );
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (WX): %f" ), *val );
|
||||
val = KIPLATFORM::UI::GetPixelScaleFactor( m_window );
|
||||
src = wxS( "platform" );
|
||||
}
|
||||
|
||||
if( !val )
|
||||
{
|
||||
// Nothing else we can do, give it a default value
|
||||
val = GetDefaultScaleFactor();
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (default): %f" ), *val );
|
||||
src = wxS( "default" );
|
||||
}
|
||||
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (%s): %f" ), src, *val );
|
||||
|
||||
return *val;
|
||||
}
|
||||
|
||||
|
||||
double DPI_SCALING::GetContentScaleFactor() const
|
||||
{
|
||||
std::optional<double> val;
|
||||
wxString src;
|
||||
|
||||
if( m_config )
|
||||
{
|
||||
val = getKiCadConfiguredScale( *m_config );
|
||||
src = wxS( "config" );
|
||||
}
|
||||
|
||||
if( !val )
|
||||
{
|
||||
val = getEnvironmentScale();
|
||||
src = wxS( "env" );
|
||||
}
|
||||
|
||||
if( !val && m_window )
|
||||
{
|
||||
// Use the native WX reporting.
|
||||
// On Linux, this will not work until WX 3.2 and GTK >= 3.10
|
||||
// Otherwise it returns 1.0
|
||||
val = KIPLATFORM::UI::GetContentScaleFactor( m_window );
|
||||
src = wxS( "platform" );
|
||||
}
|
||||
|
||||
if( !val )
|
||||
{
|
||||
// Nothing else we can do, give it a default value
|
||||
val = GetDefaultScaleFactor();
|
||||
src = wxS( "default" );
|
||||
}
|
||||
|
||||
wxLogTrace( traceHiDpi, wxS( "Content scale factor (%s): %f" ), src, *val );
|
||||
|
||||
return *val;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,11 @@ void GRSetColorPen( wxDC* DC, const COLOR4D& Color, int width, wxPenStyle style
|
||||
if( s_ForceBlackPen )
|
||||
color = COLOR4D::BLACK;
|
||||
|
||||
// wxWidgets will enforce a minimum pen width when printing, so we have to make the pen
|
||||
// transparent when we don't want the object stroked.
|
||||
if( width == 0 )
|
||||
color = COLOR4D::UNSPECIFIED;
|
||||
|
||||
const wxPen& curr_pen = DC->GetPen();
|
||||
|
||||
if( !curr_pen.IsOk() || curr_pen.GetColour() != color.ToColour()
|
||||
|
||||
@@ -424,6 +424,7 @@ void GRID_TRICKS::onCharHook( wxKeyEvent& ev )
|
||||
{
|
||||
wxCommandEvent dummy;
|
||||
m_addHandler( dummy );
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'V' )
|
||||
|
||||
@@ -264,7 +264,7 @@ bool KICAD_CURL_EASY::SetTransferCallback( const TRANSFER_CALLBACK& aCallback, s
|
||||
{
|
||||
progress = std::make_unique<CURL_PROGRESS>( this, aCallback,
|
||||
static_cast<curl_off_t>( aInterval ) );
|
||||
#ifdef CURLOPT_XFERINFOFUNCTION
|
||||
#if LIBCURL_VERSION_NUM >= 0x072000 // 7.32.0
|
||||
setOption( CURLOPT_XFERINFOFUNCTION, xferinfo );
|
||||
setOption( CURLOPT_XFERINFODATA, progress.get() );
|
||||
#else
|
||||
@@ -286,7 +286,7 @@ bool KICAD_CURL_EASY::SetOutputStream( const std::ostream* aOutput )
|
||||
|
||||
int KICAD_CURL_EASY::GetTransferTotal( uint64_t& aDownloadedBytes ) const
|
||||
{
|
||||
#ifdef CURLINFO_SIZE_DOWNLOAD_T
|
||||
#if LIBCURL_VERSION_NUM >= 0x073700 // 7.55.0
|
||||
curl_off_t dl;
|
||||
int result = curl_easy_getinfo( m_CURL, CURLINFO_SIZE_DOWNLOAD_T, &dl );
|
||||
aDownloadedBytes = static_cast<uint64_t>( dl );
|
||||
|
||||
@@ -193,6 +193,8 @@ LIB_TABLE_ROW* LIB_TABLE::findRow( const wxString& aNickName, bool aCheckIfEnabl
|
||||
{
|
||||
cur->ensureIndex();
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock( cur->m_nickIndexMutex );
|
||||
|
||||
for( const std::pair<const wxString, int>& entry : cur->m_nickIndex )
|
||||
{
|
||||
if( entry.first == aNickName )
|
||||
@@ -303,7 +305,7 @@ bool LIB_TABLE::InsertRow( LIB_TABLE_ROW* aRow, bool doReplace )
|
||||
{
|
||||
ensureIndex();
|
||||
|
||||
std::lock_guard<std::mutex> lock( m_nickIndexMutex );
|
||||
std::lock_guard<std::shared_mutex> lock( m_nickIndexMutex );
|
||||
|
||||
INDEX_CITER it = m_nickIndex.find( aRow->GetNickName() );
|
||||
|
||||
|
||||
+21
-1
@@ -110,7 +110,7 @@ LANGUAGE_DESCR LanguagesList[] =
|
||||
{ wxLANGUAGE_SWEDISH, ID_LANGUAGE_SWEDISH, wxT( "Svenska" ), true },
|
||||
// { wxLANGUAGE_VIETNAMESE, ID_LANGUAGE_VIETNAMESE, wxT( "Tiếng Việt" ), true },
|
||||
// { wxLANGUAGE_TURKISH, ID_LANGUAGE_TURKISH, wxT( "Türkçe" ), true },
|
||||
{ wxLANGUAGE_UKRAINIAN, ID_LANGUAGE_UKRANIAN, wxT( "Українець" ), true },
|
||||
{ wxLANGUAGE_UKRAINIAN, ID_LANGUAGE_UKRANIAN, wxT( "Українська" ), true },
|
||||
{ wxLANGUAGE_CHINESE_SIMPLIFIED, ID_LANGUAGE_CHINESE_SIMPLIFIED,
|
||||
wxT( "简体中文" ), true },
|
||||
{ wxLANGUAGE_CHINESE_TRADITIONAL, ID_LANGUAGE_CHINESE_TRADITIONAL,
|
||||
@@ -775,6 +775,26 @@ void PGM_BASE::SetLanguageIdentifier( int menu_id )
|
||||
}
|
||||
|
||||
|
||||
wxString PGM_BASE::GetLanguageTag()
|
||||
{
|
||||
const wxLanguageInfo* langInfo = wxLocale::GetLanguageInfo( m_language_id );
|
||||
|
||||
if( !langInfo )
|
||||
return "";
|
||||
else
|
||||
{
|
||||
#if wxCHECK_VERSION( 3, 1, 6 )
|
||||
wxString str = langInfo->GetCanonicalWithRegion();
|
||||
#else
|
||||
wxString str = langInfo->CanonicalName;
|
||||
#endif
|
||||
str.Replace( "_", "-" );
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PGM_BASE::SetLanguagePath()
|
||||
{
|
||||
wxLocale::AddCatalogLookupPathPrefix( PATHS::GetLocaleDataPath() );
|
||||
|
||||
+180
-139
@@ -861,145 +861,186 @@ void DXF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Emit text as a text entity. This loses formatting and shape but it's
|
||||
more useful as a CAD object */
|
||||
VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
|
||||
SetColor( aColor );
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
VECTOR2D size_dev = userToDeviceSize( aSize );
|
||||
int h_code = 0, v_code = 0;
|
||||
|
||||
switch( aH_justify )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: h_code = 0; break;
|
||||
case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: h_code = 2; break;
|
||||
}
|
||||
|
||||
switch( aV_justify )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: v_code = 3; break;
|
||||
case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
|
||||
case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
|
||||
}
|
||||
|
||||
// Position, size, rotation and alignment
|
||||
// The two alignment point usages is somewhat idiot (see the DXF ref)
|
||||
// Anyway since we don't use the fit/aligned options, they're the same
|
||||
fprintf( m_outputFile,
|
||||
" 0\n"
|
||||
"TEXT\n"
|
||||
" 7\n"
|
||||
"%s\n" // Text style
|
||||
" 8\n"
|
||||
"%s\n" // Layer name
|
||||
" 10\n"
|
||||
"%g\n" // First point X
|
||||
" 11\n"
|
||||
"%g\n" // Second point X
|
||||
" 20\n"
|
||||
"%g\n" // First point Y
|
||||
" 21\n"
|
||||
"%g\n" // Second point Y
|
||||
" 40\n"
|
||||
"%g\n" // Text height
|
||||
" 41\n"
|
||||
"%g\n" // Width factor
|
||||
" 50\n"
|
||||
"%g\n" // Rotation
|
||||
" 51\n"
|
||||
"%g\n" // Oblique angle
|
||||
" 71\n"
|
||||
"%d\n" // Mirror flags
|
||||
" 72\n"
|
||||
"%d\n" // H alignment
|
||||
" 73\n"
|
||||
"%d\n", // V alignment
|
||||
aBold ? (aItalic ? "KICADBI" : "KICADB") : (aItalic ? "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 ),
|
||||
aOrient.AsDegrees(),
|
||||
aItalic ? DXF_OBLIQUE_ANGLE : 0,
|
||||
size_dev.x < 0 ? 2 : 0, // X mirror flag
|
||||
h_code, v_code );
|
||||
|
||||
/* There are two issue in emitting the text:
|
||||
- Our overline character (~) must be converted to the appropriate
|
||||
control sequence %%O or %%o
|
||||
- Text encoding in DXF is more or less unspecified since depends on
|
||||
the DXF declared version, the acad version reading it *and* some
|
||||
system variables to be put in the header handled only by newer acads
|
||||
Also before R15 unicode simply is not supported (you need to use
|
||||
bigfonts which are a massive PITA). Common denominator solution:
|
||||
use Latin1 (and however someone could choke on it, anyway). Sorry
|
||||
for the extended latin people. If somewant want to try fixing this
|
||||
recent version seems to use UTF-8 (and not UCS2 like the rest of
|
||||
Windows)
|
||||
|
||||
XXX Actually there is a *third* issue: older DXF formats are limited
|
||||
to 255 bytes records (it was later raised to 2048); since I'm lazy
|
||||
and text so long is not probable I just don't implement this rule.
|
||||
If someone is interested in fixing this, you have to emit the first
|
||||
partial lines with group code 3 (max 250 bytes each) and then finish
|
||||
with a group code 1 (less than 250 bytes). The DXF refs explains it
|
||||
in no more details...
|
||||
*/
|
||||
|
||||
int braceNesting = 0;
|
||||
int overbarDepth = -1;
|
||||
|
||||
fputs( " 1\n", m_outputFile );
|
||||
|
||||
for( unsigned int i = 0; i < aText.length(); i++ )
|
||||
{
|
||||
/* Here I do a bad thing: writing the output one byte at a time!
|
||||
but today I'm lazy and I have no idea on how to coerce a Unicode
|
||||
wxString to spit out latin1 encoded text ...
|
||||
|
||||
At least stdio is *supposed* to do output buffering, so there is
|
||||
hope is not too slow */
|
||||
wchar_t ch = aText[i];
|
||||
|
||||
if( ch > 255 )
|
||||
{
|
||||
// I can't encode this...
|
||||
putc( '?', m_outputFile );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
|
||||
{
|
||||
fputs( "%%o", m_outputFile );
|
||||
overbarDepth = braceNesting;
|
||||
|
||||
// Skip the '{'
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else if( aText[i] == '{' )
|
||||
{
|
||||
braceNesting++;
|
||||
}
|
||||
else if( aText[i] == '}' )
|
||||
{
|
||||
if( braceNesting > 0 )
|
||||
braceNesting--;
|
||||
|
||||
if( braceNesting == overbarDepth )
|
||||
{
|
||||
fputs( "%%O", m_outputFile );
|
||||
overbarDepth = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
putc( ch, m_outputFile );
|
||||
}
|
||||
}
|
||||
|
||||
putc( '\n', m_outputFile );
|
||||
TEXT_ATTRIBUTES attrs;
|
||||
attrs.m_Halign = aH_justify;
|
||||
attrs.m_Valign =aV_justify;
|
||||
attrs.m_StrokeWidth = aWidth;
|
||||
attrs.m_Angle = aOrient;
|
||||
attrs.m_Italic = aItalic;
|
||||
attrs.m_Bold = aBold;
|
||||
attrs.m_Mirrored = aSize.x < 0;
|
||||
attrs.m_Multiline = false;
|
||||
plotOneLineOfText( aPos, aColor, aText, attrs );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DXF_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
TEXT_ATTRIBUTES attrs = aAttributes;
|
||||
// Fix me: see how to use DXF text mode for multiline texts
|
||||
if( attrs.m_Multiline && !aText.Contains( wxT( "\n" ) ) )
|
||||
attrs.m_Multiline = false; // the text has only one line.
|
||||
|
||||
bool processSuperSub = aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) );
|
||||
|
||||
if( m_textAsLines || containsNonAsciiChars( aText ) || attrs.m_Multiline || processSuperSub )
|
||||
{
|
||||
// output text as graphics.
|
||||
// Perhaps multiline texts could be handled as DXF text entity
|
||||
// but I do not want spend time about that (JPC)
|
||||
PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
|
||||
}
|
||||
else
|
||||
plotOneLineOfText( aPos, aColor, aText, attrs );
|
||||
}
|
||||
|
||||
void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes )
|
||||
{
|
||||
/* Emit text as a text entity. This loses formatting and shape but it's
|
||||
more useful as a CAD object */
|
||||
VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
|
||||
SetColor( aColor );
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
VECTOR2D size_dev = userToDeviceSize( aAttributes.m_Size );
|
||||
int h_code = 0, v_code = 0;
|
||||
|
||||
switch( aAttributes.m_Halign )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: h_code = 0; break;
|
||||
case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: h_code = 2; break;
|
||||
}
|
||||
|
||||
switch( aAttributes.m_Valign )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: v_code = 3; break;
|
||||
case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
|
||||
case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
|
||||
}
|
||||
|
||||
// Position, size, rotation and alignment
|
||||
// The two alignment point usages is somewhat idiot (see the DXF ref)
|
||||
// Anyway since we don't use the fit/aligned options, they're the same
|
||||
fprintf( m_outputFile,
|
||||
" 0\n"
|
||||
"TEXT\n"
|
||||
" 7\n"
|
||||
"%s\n" // Text style
|
||||
" 8\n"
|
||||
"%s\n" // Layer name
|
||||
" 10\n"
|
||||
"%g\n" // First point X
|
||||
" 11\n"
|
||||
"%g\n" // Second point X
|
||||
" 20\n"
|
||||
"%g\n" // First point Y
|
||||
" 21\n"
|
||||
"%g\n" // Second point Y
|
||||
" 40\n"
|
||||
"%g\n" // Text height
|
||||
" 41\n"
|
||||
"%g\n" // Width factor
|
||||
" 50\n"
|
||||
"%g\n" // Rotation
|
||||
" 51\n"
|
||||
"%g\n" // Oblique angle
|
||||
" 71\n"
|
||||
"%d\n" // Mirror flags
|
||||
" 72\n"
|
||||
"%d\n" // H alignment
|
||||
" 73\n"
|
||||
"%d\n", // V alignment
|
||||
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 ),
|
||||
aAttributes.m_Angle.AsDegrees(),
|
||||
aAttributes.m_Italic ? DXF_OBLIQUE_ANGLE : 0,
|
||||
aAttributes.m_Mirrored ? 2 : 0, // X mirror flag
|
||||
h_code, v_code );
|
||||
|
||||
/* There are two issue in emitting the text:
|
||||
- Our overline character (~) must be converted to the appropriate
|
||||
control sequence %%O or %%o
|
||||
- Text encoding in DXF is more or less unspecified since depends on
|
||||
the DXF declared version, the acad version reading it *and* some
|
||||
system variables to be put in the header handled only by newer acads
|
||||
Also before R15 unicode simply is not supported (you need to use
|
||||
bigfonts which are a massive PITA). Common denominator solution:
|
||||
use Latin1 (and however someone could choke on it, anyway). Sorry
|
||||
for the extended latin people. If somewant want to try fixing this
|
||||
recent version seems to use UTF-8 (and not UCS2 like the rest of
|
||||
Windows)
|
||||
|
||||
XXX Actually there is a *third* issue: older DXF formats are limited
|
||||
to 255 bytes records (it was later raised to 2048); since I'm lazy
|
||||
and text so long is not probable I just don't implement this rule.
|
||||
If someone is interested in fixing this, you have to emit the first
|
||||
partial lines with group code 3 (max 250 bytes each) and then finish
|
||||
with a group code 1 (less than 250 bytes). The DXF refs explains it
|
||||
in no more details...
|
||||
*/
|
||||
|
||||
int braceNesting = 0;
|
||||
int overbarDepth = -1;
|
||||
|
||||
fputs( " 1\n", m_outputFile );
|
||||
|
||||
for( unsigned int i = 0; i < aText.length(); i++ )
|
||||
{
|
||||
/* Here I do a bad thing: writing the output one byte at a time!
|
||||
but today I'm lazy and I have no idea on how to coerce a Unicode
|
||||
wxString to spit out latin1 encoded text ...
|
||||
|
||||
At least stdio is *supposed* to do output buffering, so there is
|
||||
hope is not too slow */
|
||||
wchar_t ch = aText[i];
|
||||
|
||||
if( ch > 255 )
|
||||
{
|
||||
// I can't encode this...
|
||||
putc( '?', m_outputFile );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
|
||||
{
|
||||
fputs( "%%o", m_outputFile );
|
||||
overbarDepth = braceNesting;
|
||||
|
||||
// Skip the '{'
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else if( aText[i] == '{' )
|
||||
{
|
||||
braceNesting++;
|
||||
}
|
||||
else if( aText[i] == '}' )
|
||||
{
|
||||
if( braceNesting > 0 )
|
||||
braceNesting--;
|
||||
|
||||
if( braceNesting == overbarDepth )
|
||||
{
|
||||
fputs( "%%O", m_outputFile );
|
||||
overbarDepth = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
putc( ch, m_outputFile );
|
||||
}
|
||||
}
|
||||
|
||||
putc( '\n', m_outputFile );
|
||||
}
|
||||
|
||||
@@ -154,7 +154,6 @@ void GERBER_PLOTTER::SetGerberCoordinatesFormat( int aResolution, bool aUseInche
|
||||
|
||||
void GERBER_PLOTTER::emitDcode( const VECTOR2D& pt, int dcode )
|
||||
{
|
||||
|
||||
fprintf( m_outputFile, "X%dY%dD%02d*\n", KiROUND( pt.x ), KiROUND( pt.y ), dcode );
|
||||
}
|
||||
|
||||
@@ -902,18 +901,16 @@ void GERBER_PLOTTER::plotArc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAn
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, void* aData )
|
||||
void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, GBR_METADATA* aGbrMetadata )
|
||||
{
|
||||
if( aPoly.PointCount() <= 2 )
|
||||
return;
|
||||
|
||||
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
bool clearTA_AperFunction = false; // true if a TA.AperFunction is used
|
||||
|
||||
if( gbr_metadata )
|
||||
if( aGbrMetadata )
|
||||
{
|
||||
std::string attrib = gbr_metadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||
std::string attrib = aGbrMetadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||
|
||||
if( !attrib.empty() )
|
||||
{
|
||||
@@ -922,7 +919,7 @@ void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, void* aDat
|
||||
}
|
||||
}
|
||||
|
||||
PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0 , gbr_metadata );
|
||||
PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0 , aGbrMetadata );
|
||||
|
||||
// Clear the TA attribute, to avoid the next item to inherit it:
|
||||
if( clearTA_AperFunction )
|
||||
@@ -939,18 +936,17 @@ void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, void* aDat
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotGerberRegion( const std::vector<VECTOR2I>& aCornerList, void* aData )
|
||||
void GERBER_PLOTTER::PlotGerberRegion( const std::vector<VECTOR2I>& aCornerList,
|
||||
GBR_METADATA* aGbrMetadata )
|
||||
{
|
||||
if( aCornerList.size() <= 2 )
|
||||
return;
|
||||
|
||||
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
bool clearTA_AperFunction = false; // true if a TA.AperFunction is used
|
||||
|
||||
if( gbr_metadata )
|
||||
if( aGbrMetadata )
|
||||
{
|
||||
std::string attrib = gbr_metadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||
std::string attrib = aGbrMetadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||
|
||||
if( !attrib.empty() )
|
||||
{
|
||||
@@ -959,7 +955,7 @@ void GERBER_PLOTTER::PlotGerberRegion( const std::vector<VECTOR2I>& aCornerList,
|
||||
}
|
||||
}
|
||||
|
||||
PlotPoly( aCornerList, FILL_T::FILLED_SHAPE, 0, gbr_metadata );
|
||||
PlotPoly( aCornerList, FILL_T::FILLED_SHAPE, 0, aGbrMetadata );
|
||||
|
||||
// Clear the TA attribute, to avoid the next item to inherit it:
|
||||
if( clearTA_AperFunction )
|
||||
@@ -976,6 +972,19 @@ void GERBER_PLOTTER::PlotGerberRegion( const std::vector<VECTOR2I>& aCornerList,
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotPolyAsRegion( const SHAPE_LINE_CHAIN& aPoly, FILL_T aFill,
|
||||
int aWidth, GBR_METADATA* aGbrMetadata )
|
||||
{
|
||||
// plot a filled polygon using Gerber region, therefore adding X2 attributes
|
||||
// to the solid polygon
|
||||
if( aWidth )
|
||||
PlotPoly( aPoly, FILL_T::NO_FILL, aWidth, aGbrMetadata );
|
||||
|
||||
if( aFill != FILL_T::NO_FILL )
|
||||
PlotGerberRegion( aPoly, aGbrMetadata );
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aPoly, FILL_T aFill, int aWidth,
|
||||
void* aData )
|
||||
{
|
||||
@@ -1322,7 +1331,7 @@ void GERBER_PLOTTER::FlashPadOval( const VECTOR2I& aPos, const VECTOR2I& aSize,
|
||||
if( orient.IsCardinal90() )
|
||||
std::swap( size.x, size.y );
|
||||
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( aPos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( aPos );
|
||||
int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
|
||||
selectAperture( size, 0, ANGLE_0, APERTURE::AT_OVAL, aperture_attrib );
|
||||
|
||||
@@ -1353,7 +1362,7 @@ void GERBER_PLOTTER::FlashPadOval( const VECTOR2I& aPos, const VECTOR2I& aSize,
|
||||
orient -= ANGLE_180;
|
||||
}
|
||||
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( aPos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( aPos );
|
||||
int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
|
||||
selectAperture( size, 0, orient, APERTURE::AM_ROTATED_OVAL, aperture_attrib );
|
||||
|
||||
@@ -1416,7 +1425,7 @@ void GERBER_PLOTTER::FlashPadRect( const VECTOR2I& pos, const VECTOR2I& aSize,
|
||||
}
|
||||
else
|
||||
{
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( pos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( pos );
|
||||
int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
|
||||
selectAperture( size, 0, ANGLE_0, APERTURE::AT_RECT, aperture_attrib );
|
||||
|
||||
@@ -1433,7 +1442,7 @@ void GERBER_PLOTTER::FlashPadRect( const VECTOR2I& pos, const VECTOR2I& aSize,
|
||||
{
|
||||
m_hasApertureRotRect = true;
|
||||
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( pos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( pos );
|
||||
int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
|
||||
selectAperture( size, 0, aOrient, APERTURE::AM_ROT_RECT, aperture_attrib );
|
||||
|
||||
@@ -1755,7 +1764,7 @@ void GERBER_PLOTTER::FlashPadChamferRoundRect( const VECTOR2I& aShapePos, const
|
||||
if( aData )
|
||||
gbr_metadata = *static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( aShapePos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( aShapePos );
|
||||
SHAPE_POLY_SET outline;
|
||||
std::vector<VECTOR2I> cornerList;
|
||||
|
||||
@@ -1994,6 +2003,20 @@ void GERBER_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
if( gbr_metadata )
|
||||
formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
|
||||
|
||||
PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
|
||||
}
|
||||
|
||||
void GERBER_PLOTTER::SetLayerPolarity( bool aPositive )
|
||||
{
|
||||
if( aPositive )
|
||||
|
||||
@@ -1376,7 +1376,9 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
|
||||
double wideningFactor, heightFactor;
|
||||
|
||||
computeTextParameters( aPos, aText, aOrient, aSize, m_plotMirror, aH_justify,
|
||||
VECTOR2I t_size( std::abs( aSize.x ), std::abs( aSize.y ) );
|
||||
|
||||
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 );
|
||||
|
||||
@@ -1389,7 +1391,7 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
if( !aFont )
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
VECTOR2I full_box( aFont->StringBoundaryLimits( aText, aSize, aWidth, aBold, aItalic ) );
|
||||
VECTOR2I full_box( aFont->StringBoundaryLimits( aText, t_size, aWidth, aBold, aItalic ) );
|
||||
VECTOR2I box_x( full_box.x, 0 );
|
||||
VECTOR2I box_y( 0, full_box.y );
|
||||
|
||||
@@ -1410,13 +1412,13 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
{
|
||||
wxString word = str_tok.GetNextToken();
|
||||
|
||||
computeTextParameters( pos, word, aOrient, aSize, m_plotMirror, GR_TEXT_H_ALIGN_LEFT,
|
||||
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 );
|
||||
|
||||
// Extract the changed width and rotate by the orientation to get the offset for the
|
||||
// next word
|
||||
VECTOR2I bbox( aFont->StringBoundaryLimits( word, aSize, aWidth, aBold, aItalic ).x, 0 );
|
||||
VECTOR2I bbox( aFont->StringBoundaryLimits( word, t_size, aWidth, aBold, aItalic ).x, 0 );
|
||||
RotatePoint( bbox, aOrient );
|
||||
pos += bbox;
|
||||
|
||||
@@ -1444,6 +1446,30 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
}
|
||||
|
||||
|
||||
void PDF_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
VECTOR2I size = aAttributes.m_Size;
|
||||
|
||||
// PDF files do not like 0 sized texts which create broken files.
|
||||
if( size.x == 0 || size.y == 0 )
|
||||
return;
|
||||
|
||||
if( aAttributes.m_Mirrored )
|
||||
size.x = -size.x;
|
||||
|
||||
PDF_PLOTTER::Text( aPos, aColor, aText, aAttributes.m_Angle, size,
|
||||
aAttributes.m_Halign, aAttributes.m_Valign,
|
||||
aAttributes.m_StrokeWidth,
|
||||
aAttributes.m_Italic, aAttributes.m_Bold,
|
||||
aAttributes.m_Multiline,
|
||||
aFont, aData );
|
||||
}
|
||||
|
||||
|
||||
void PDF_PLOTTER::HyperlinkBox( const BOX2I& aBox, const wxString& aDestinationURL )
|
||||
{
|
||||
m_hyperlinksInPage.push_back( std::make_pair( aBox, aDestinationURL ) );
|
||||
|
||||
@@ -967,6 +967,28 @@ void PS_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
}
|
||||
|
||||
|
||||
void PS_PLOTTER::PlotText( const VECTOR2I& aPos,
|
||||
const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
SetCurrentLineWidth( aAttributes.m_StrokeWidth );
|
||||
SetColor( aColor );
|
||||
|
||||
// Draw the hidden postscript text (if requested)
|
||||
if( m_textMode == PLOT_TEXT_MODE::PHANTOM )
|
||||
{
|
||||
std::string ps_test = encodeStringForPlotter( aText );
|
||||
VECTOR2D pos_dev = userToDeviceCoordinates( aPos );
|
||||
fprintf( m_outputFile, "%s %g %g phantomshow\n", ps_test.c_str(), pos_dev.x, pos_dev.y );
|
||||
}
|
||||
|
||||
PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Character widths for Helvetica
|
||||
*/
|
||||
|
||||
@@ -633,7 +633,13 @@ void SVG_PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double
|
||||
{
|
||||
wxMemoryOutputStream img_stream;
|
||||
|
||||
aImage.SaveFile( img_stream, wxBITMAP_TYPE_PNG );
|
||||
if( m_colorMode )
|
||||
aImage.SaveFile( img_stream, wxBITMAP_TYPE_PNG );
|
||||
else // Plot in B&W
|
||||
{
|
||||
wxImage image = aImage.ConvertToGreyscale();
|
||||
image.SaveFile( img_stream, wxBITMAP_TYPE_PNG );
|
||||
}
|
||||
size_t input_len = img_stream.GetOutputStreamBuffer()->GetBufferSize();
|
||||
std::vector<uint8_t> buffer( input_len );
|
||||
std::vector<uint8_t> encoded;
|
||||
@@ -847,3 +853,23 @@ void SVG_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
|
||||
fputs( "</g>", m_outputFile );
|
||||
}
|
||||
|
||||
|
||||
void SVG_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
VECTOR2I size = aAttributes.m_Size;
|
||||
|
||||
if( aAttributes.m_Mirrored )
|
||||
size.x = -size.x;
|
||||
|
||||
SVG_PLOTTER::Text( aPos, aColor, aText, aAttributes.m_Angle, size,
|
||||
aAttributes.m_Halign, aAttributes.m_Valign,
|
||||
aAttributes.m_StrokeWidth,
|
||||
aAttributes.m_Italic, aAttributes.m_Bold,
|
||||
aAttributes.m_Multiline,
|
||||
aFont, aData );
|
||||
}
|
||||
|
||||
+50
-18
@@ -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) 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
|
||||
@@ -694,23 +694,6 @@ void PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int a
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Same as GRText, but plot graphic text instead of draw it.
|
||||
*
|
||||
* @param aPos is the text position (according to aH_justify, aV_justify).
|
||||
* @param aColor is the text color.
|
||||
* @param aText is the text to draw.
|
||||
* @param aOrient is the angle.
|
||||
* @param aSize is the text size (size.x or size.y can be < 0 for mirrored texts).
|
||||
* @param aH_justify is the horizontal justification (Left, center, right).
|
||||
* @param aV_justify is the vertical justification (bottom, center, top).
|
||||
* @param aPenWidth is the line width (if = 0, use plot default line width).
|
||||
* @param aItalic is the true to simulate an italic font.
|
||||
* @param aBold use true to use a bold font Useful only with default width value (aPenWidth = 0).
|
||||
* @param aMultilineAllowed use true to plot text as multiline, otherwise single line.
|
||||
* @param aData is a parameter used by some plotters in SetCurrentLineWidth(),
|
||||
* not directly used here.
|
||||
*/
|
||||
void PLOTTER::Text( const VECTOR2I& aPos,
|
||||
const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
@@ -759,6 +742,55 @@ void PLOTTER::Text( const VECTOR2I& aPos,
|
||||
attributes.m_Valign = aV_justify;
|
||||
attributes.m_Size = aSize;
|
||||
|
||||
// if Size.x is < 0, the text is mirrored (we have no other param to know a text is mirrored)
|
||||
if( attributes.m_Size.x < 0 )
|
||||
{
|
||||
attributes.m_Size.x = -attributes.m_Size.x;
|
||||
attributes.m_Mirrored = true;
|
||||
}
|
||||
|
||||
if( !aFont )
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
aFont->Draw( &callback_gal, aText, aPos, attributes );
|
||||
}
|
||||
|
||||
void PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
|
||||
TEXT_ATTRIBUTES attributes = aAttributes;
|
||||
int penWidth = attributes.m_StrokeWidth;
|
||||
|
||||
SetColor( aColor );
|
||||
SetCurrentLineWidth( penWidth, aData );
|
||||
|
||||
if( penWidth == 0 && attributes.m_Bold ) // Use default values if aPenWidth == 0
|
||||
penWidth = GetPenSizeForBold( std::min( attributes.m_Size.x, attributes.m_Size.y ) );
|
||||
|
||||
if( penWidth < 0 )
|
||||
penWidth = -penWidth;
|
||||
|
||||
attributes.m_StrokeWidth = penWidth;
|
||||
|
||||
CALLBACK_GAL callback_gal( empty_opts,
|
||||
// Stroke callback
|
||||
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
|
||||
{
|
||||
MoveTo( aPt1 );
|
||||
LineTo( aPt2 );
|
||||
PenFinish();
|
||||
},
|
||||
// Polygon callback
|
||||
[&]( const SHAPE_LINE_CHAIN& aPoly )
|
||||
{
|
||||
PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, aData );
|
||||
} );
|
||||
|
||||
if( !aFont )
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ void CADSTAR_ARCHIVE_PARSER::LINECODE::Parse( XNODE* aNode, PARSER_CONTEXT* aCon
|
||||
|
||||
XNODE* cNode = aNode->GetChildren();
|
||||
|
||||
if( cNode->GetName() != wxT( "STYLE" ) )
|
||||
if( !cNode || cNode->GetName() != wxT( "STYLE" ) )
|
||||
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxString::Format( "LINECODE -> %s", Name ) );
|
||||
|
||||
wxString styleStr = GetXmlAttributeIDString( cNode, 0 );
|
||||
@@ -486,18 +486,28 @@ void CADSTAR_ARCHIVE_PARSER::VERTEX::AppendToChain( SHAPE_LINE_CHAIN* aChainToAp
|
||||
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
|
||||
double aAccuracy ) const
|
||||
{
|
||||
VECTOR2I endPoint = aCadstarToKicadPointCallback( End );
|
||||
|
||||
if( Type == VERTEX_TYPE::POINT )
|
||||
{
|
||||
aChainToAppendTo->Append( endPoint );
|
||||
aChainToAppendTo->Append( aCadstarToKicadPointCallback( End ) );
|
||||
return;
|
||||
}
|
||||
|
||||
wxCHECK_MSG( aChainToAppendTo->PointCount() > 0, /*void*/,
|
||||
"Can't append an arc to vertex to an empty chain" );
|
||||
|
||||
VECTOR2I startPoint = aChainToAppendTo->GetPoint( -1 );
|
||||
aChainToAppendTo->Append( BuildArc( aChainToAppendTo->GetPoint( -1 ), aCadstarToKicadPointCallback),
|
||||
aAccuracy );
|
||||
}
|
||||
|
||||
|
||||
SHAPE_ARC CADSTAR_ARCHIVE_PARSER::VERTEX::BuildArc( const VECTOR2I& aPrevPoint,
|
||||
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback ) const
|
||||
{
|
||||
wxCHECK_MSG( Type != VERTEX_TYPE::POINT, SHAPE_ARC(),
|
||||
"Can't build an arc for a straight segment!" );
|
||||
|
||||
VECTOR2I startPoint = aPrevPoint;
|
||||
VECTOR2I endPoint = aCadstarToKicadPointCallback( End );
|
||||
VECTOR2I centerPoint;
|
||||
|
||||
if( Type == VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE || Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE )
|
||||
@@ -516,9 +526,8 @@ void CADSTAR_ARCHIVE_PARSER::VERTEX::AppendToChain( SHAPE_LINE_CHAIN* aChainToAp
|
||||
clockwise = !clockwise;
|
||||
|
||||
SHAPE_ARC arc;
|
||||
arc.ConstructFromStartEndCenter( startPoint, endPoint, centerPoint, clockwise );
|
||||
|
||||
aChainToAppendTo->Append( arc, aAccuracy );
|
||||
return arc.ConstructFromStartEndCenter( startPoint, endPoint, centerPoint, clockwise );
|
||||
}
|
||||
|
||||
|
||||
@@ -2419,7 +2428,9 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
const wxString& aFileTypeIdentifier, PROGRESS_REPORTER* aProgressReporter )
|
||||
{
|
||||
KEYWORD emptyKeywords[1] = {};
|
||||
XNODE * iNode = nullptr, *cNode = nullptr;
|
||||
XNODE* rootNode = nullptr;
|
||||
XNODE* cNode = nullptr;
|
||||
XNODE* iNode = nullptr;
|
||||
int tok;
|
||||
bool cadstarFileCheckDone = false;
|
||||
wxString str;
|
||||
@@ -2451,7 +2462,10 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
if( aProgressReporter && ( currentProgress() - previousReportedProgress ) > 0.01 )
|
||||
{
|
||||
if( !aProgressReporter->KeepRefreshing() )
|
||||
{
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "File import cancelled by user." ) );
|
||||
}
|
||||
|
||||
aProgressReporter->SetCurrentProgress( currentProgress() );
|
||||
previousReportedProgress = currentProgress();
|
||||
@@ -2467,6 +2481,7 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
else
|
||||
{
|
||||
//too many closing brackets
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
}
|
||||
@@ -2476,6 +2491,9 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
str = wxString( lexer.CurText(), *conv );
|
||||
cNode = new XNODE( wxXML_ELEMENT_NODE, str );
|
||||
|
||||
if( !rootNode )
|
||||
rootNode = cNode;
|
||||
|
||||
if( iNode )
|
||||
{
|
||||
//we will add it as attribute as well as child node
|
||||
@@ -2485,7 +2503,10 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
else if( !cadstarFileCheckDone )
|
||||
{
|
||||
if( cNode->GetName() != aFileTypeIdentifier )
|
||||
{
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
|
||||
cadstarFileCheckDone = true;
|
||||
}
|
||||
@@ -2501,19 +2522,28 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
else
|
||||
{
|
||||
//not enough closing brackets
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Not enough closing brackets
|
||||
if( iNode != nullptr )
|
||||
{
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
|
||||
// Throw if no data was parsed
|
||||
if( cNode )
|
||||
return cNode;
|
||||
if( rootNode )
|
||||
{
|
||||
return rootNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ class wxXmlAttribute;
|
||||
class PROGRESS_REPORTER;
|
||||
class SHAPE_LINE_CHAIN;
|
||||
class SHAPE_POLY_SET;
|
||||
class SHAPE_ARC;
|
||||
|
||||
/**
|
||||
* @brief Helper functions and common structures for CADSTAR PCB and Schematic archive files.
|
||||
@@ -92,6 +93,8 @@ class CADSTAR_ARCHIVE_PARSER
|
||||
public:
|
||||
CADSTAR_ARCHIVE_PARSER() { m_progressReporter = nullptr; }
|
||||
|
||||
virtual ~CADSTAR_ARCHIVE_PARSER() {}
|
||||
|
||||
|
||||
typedef wxString LINECODE_ID;
|
||||
typedef wxString HATCHCODE_ID;
|
||||
@@ -451,6 +454,10 @@ public:
|
||||
void AppendToChain( SHAPE_LINE_CHAIN* aChainToAppendTo,
|
||||
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
|
||||
double aAccuracy ) const;
|
||||
|
||||
SHAPE_ARC BuildArc( const VECTOR2I& aPrevPoint,
|
||||
const std::function<VECTOR2I( const VECTOR2I& )>
|
||||
aCadstarToKicadPointCallback ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -130,7 +130,7 @@ const void* PROPERTY_MANAGER::TypeCast( const void* aSource, TYPE_ID aBase, TYPE
|
||||
}
|
||||
|
||||
|
||||
void PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aGroup )
|
||||
PROPERTY_BASE& PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aGroup )
|
||||
{
|
||||
const wxString& name = aProperty->Name();
|
||||
TYPE_ID hash = aProperty->OwnerHash();
|
||||
@@ -147,15 +147,16 @@ void PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aG
|
||||
}
|
||||
|
||||
m_dirty = true;
|
||||
return *aProperty;
|
||||
}
|
||||
|
||||
|
||||
void PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName, PROPERTY_BASE* aNew,
|
||||
const wxString& aGroup )
|
||||
PROPERTY_BASE& PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName,
|
||||
PROPERTY_BASE* aNew, const wxString& aGroup )
|
||||
{
|
||||
CLASS_DESC& classDesc = getClass( aNew->OwnerHash() );
|
||||
classDesc.m_replaced.insert( std::make_pair( aBase, aName ) );
|
||||
AddProperty( aNew, aGroup );
|
||||
return AddProperty( aNew, aGroup );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <pgm_base.h>
|
||||
#include <settings/app_settings.h>
|
||||
#include <settings/json_settings_internals.h>
|
||||
#include <settings/color_settings.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <settings/parameters.h>
|
||||
|
||||
@@ -147,7 +148,7 @@ APP_SETTINGS_BASE::APP_SETTINGS_BASE( const std::string& aFilename, int aSchemaV
|
||||
&m_System.last_imperial_units, static_cast<int>( EDA_UNITS::INCHES ) ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "appearance.color_theme",
|
||||
&m_ColorTheme, wxS( "_builtin_default" ) ) );
|
||||
&m_ColorTheme, COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT ) );
|
||||
|
||||
addParamsForWindow( &m_Window, "window" );
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
///! Update the schema version whenever a migration is required
|
||||
const int colorsSchemaVersion = 5;
|
||||
const wxString COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT = "_builtin_default";
|
||||
const wxString COLOR_SETTINGS::COLOR_BUILTIN_CLASSIC = "_builtin_classic";
|
||||
|
||||
|
||||
COLOR_SETTINGS::COLOR_SETTINGS( const wxString& aFilename, bool aAbsolutePath ) :
|
||||
@@ -378,12 +380,12 @@ void COLOR_SETTINGS::SetColor( int aLayer, const COLOR4D& aColor )
|
||||
|
||||
std::vector<COLOR_SETTINGS*> COLOR_SETTINGS::CreateBuiltinColorSettings()
|
||||
{
|
||||
COLOR_SETTINGS* defaultTheme = new COLOR_SETTINGS( wxT( "_builtin_default" ) );
|
||||
COLOR_SETTINGS* defaultTheme = new COLOR_SETTINGS( COLOR_BUILTIN_DEFAULT );
|
||||
defaultTheme->SetName( _( "KiCad Default" ) );
|
||||
defaultTheme->m_writeFile = false;
|
||||
defaultTheme->Load(); // We can just get the colors out of the param defaults for this one
|
||||
|
||||
COLOR_SETTINGS* classicTheme = new COLOR_SETTINGS( wxT( "_builtin_classic" ) );
|
||||
COLOR_SETTINGS* classicTheme = new COLOR_SETTINGS( COLOR_BUILTIN_CLASSIC );
|
||||
classicTheme->SetName( _( "KiCad Classic" ) );
|
||||
classicTheme->m_writeFile = false;
|
||||
|
||||
|
||||
@@ -66,6 +66,10 @@ SETTINGS_MANAGER::SETTINGS_MANAGER( bool aHeadless ) :
|
||||
|
||||
// create the common settings shared by all applications. Not loaded immediately
|
||||
m_common_settings = RegisterSettings( new COMMON_SETTINGS, false );
|
||||
|
||||
// Create the built-in color settings
|
||||
// Here to allow the Python API to access the built-in colors
|
||||
registerBuiltinColorSettings();
|
||||
}
|
||||
|
||||
SETTINGS_MANAGER::~SETTINGS_MANAGER()
|
||||
@@ -203,7 +207,7 @@ COLOR_SETTINGS* SETTINGS_MANAGER::GetColorSettings( const wxString& aName )
|
||||
if( !ret )
|
||||
{
|
||||
ret = registerColorSettings( aName );
|
||||
*ret = *m_color_settings.at( "_builtin_default" );
|
||||
*ret = *m_color_settings.at( COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT );
|
||||
ret->SetFilename( wxT( "user" ) );
|
||||
ret->SetReadOnly( false );
|
||||
}
|
||||
@@ -212,7 +216,7 @@ COLOR_SETTINGS* SETTINGS_MANAGER::GetColorSettings( const wxString& aName )
|
||||
}
|
||||
|
||||
// This had better work
|
||||
return m_color_settings.at( "_builtin_default" );
|
||||
return m_color_settings.at( COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT );
|
||||
}
|
||||
|
||||
|
||||
@@ -305,11 +309,17 @@ COLOR_SETTINGS* SETTINGS_MANAGER::GetMigratedColorSettings()
|
||||
}
|
||||
|
||||
|
||||
void SETTINGS_MANAGER::registerBuiltinColorSettings()
|
||||
{
|
||||
for( COLOR_SETTINGS* settings : COLOR_SETTINGS::CreateBuiltinColorSettings() )
|
||||
m_color_settings[settings->GetFilename()] = RegisterSettings( settings, false );
|
||||
}
|
||||
|
||||
|
||||
void SETTINGS_MANAGER::loadAllColorSettings()
|
||||
{
|
||||
// Create the built-in color settings
|
||||
for( COLOR_SETTINGS* settings : COLOR_SETTINGS::CreateBuiltinColorSettings() )
|
||||
m_color_settings[settings->GetFilename()] = RegisterSettings( settings, false );
|
||||
registerBuiltinColorSettings();
|
||||
|
||||
wxFileName third_party_path;
|
||||
const ENV_VAR_MAP& env = Pgm().GetLocalEnvVariables();
|
||||
|
||||
+41
-1
@@ -34,13 +34,18 @@
|
||||
|
||||
%rename(getWxPoint) operator wxPoint;
|
||||
%rename(getWxSize) operator wxSize;
|
||||
%{
|
||||
#include <math/vector2d.h>
|
||||
%include <math/vector2d.h>
|
||||
#include <math/vector3.h>
|
||||
#include <math/box2.h>
|
||||
%}
|
||||
%include <math/vector2d.h>
|
||||
%include <math/vector3.h>
|
||||
%include <math/box2.h>
|
||||
|
||||
%template(VECTOR2I) VECTOR2<int>;
|
||||
%template(VECTOR2I_EXTENDED_TYPE) VECTOR2_TRAITS<int>;
|
||||
%template(VECTOR3D) VECTOR3<double>;
|
||||
%template(BOX2I) BOX2<VECTOR2I>;
|
||||
|
||||
%extend VECTOR2<int>
|
||||
@@ -74,3 +79,38 @@
|
||||
|
||||
%}
|
||||
}
|
||||
|
||||
%extend VECTOR3<double>
|
||||
{
|
||||
void Set(double x, double y, double z) { self->x = x; self->y = y; self->z = z; }
|
||||
|
||||
PyObject* Get()
|
||||
{
|
||||
PyObject* tup = PyTuple_New(3);
|
||||
PyTuple_SET_ITEM(tup, 0, PyFloat_FromDouble(self->x));
|
||||
PyTuple_SET_ITEM(tup, 1, PyFloat_FromDouble(self->y));
|
||||
PyTuple_SET_ITEM(tup, 2, PyFloat_FromDouble(self->z));
|
||||
return tup;
|
||||
}
|
||||
|
||||
%pythoncode
|
||||
%{
|
||||
def __eq__(self,other): return (self.x==other.x and self.y==other.y and self.z==other.z)
|
||||
def __ne__(self,other): return not (self==other)
|
||||
def __str__(self): return str(self.Get())
|
||||
def __repr__(self): return 'VECTOR3D'+str(self.Get())
|
||||
def __len__(self): return len(self.Get())
|
||||
def __getitem__(self, index): return self.Get()[index]
|
||||
def __setitem__(self, index, val):
|
||||
if index == 0:
|
||||
self.x = val
|
||||
elif index == 1:
|
||||
self.y = val
|
||||
elif index == 2:
|
||||
self.z = val
|
||||
else:
|
||||
raise IndexError
|
||||
def __nonzero__(self): return self.Get() != (0, 0, 0)
|
||||
|
||||
%}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
/// URL to launch a new issue with pre-populated description
|
||||
wxString COMMON_CONTROL::m_bugReportUrl =
|
||||
wxS( "https://gitlab.com/kicad/code/kicad/issues/new?issue[description]=%s" );
|
||||
wxS( "https://gitlab.com/kicad/code/kicad/issues/new?issuable_template=bare&issue[description]=%s" );
|
||||
|
||||
|
||||
/// Issue template to use for reporting bugs (this should not be translated)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <widgets/color_swatch.h>
|
||||
#include <wx/dcmemory.h>
|
||||
|
||||
#include <gal/dpi_scaling.h>
|
||||
#include <dialogs/dialog_color_picker.h>
|
||||
#include <memory>
|
||||
|
||||
@@ -133,6 +134,16 @@ COLOR_SWATCH::COLOR_SWATCH( wxWindow* aParent, const COLOR4D& aColor, int aID,
|
||||
m_checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
|
||||
m_checkerboardBg = aParent->GetBackgroundColour();
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// These need additional scaling on Windows because of some discrepancy between pixel and
|
||||
// content scaling that only affects certain widgets on Windows HiDPI. On other platforms, the
|
||||
// value returned by ConvertDialogToPixels appears to be correct.
|
||||
DPI_SCALING dpi( nullptr, aParent );
|
||||
|
||||
m_size /= dpi.GetContentScaleFactor();
|
||||
m_checkerboardSize /= dpi.GetContentScaleFactor();
|
||||
#endif
|
||||
|
||||
auto sizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
SetSizer( sizer );
|
||||
|
||||
@@ -300,4 +311,4 @@ void COLOR_SWATCH::OnDarkModeToggle()
|
||||
m_checkerboardBg = m_parent->GetBackgroundColour();
|
||||
wxBitmap bm = MakeBitmap( m_color, m_background, m_size, m_checkerboardSize, m_checkerboardBg );
|
||||
m_swatch->SetBitmap( bm );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <widgets/font_choice.h>
|
||||
#include <wx/fontenum.h>
|
||||
#include <font/fontconfig.h>
|
||||
#include <pgm_base.h>
|
||||
|
||||
// The "official" name of the building Kicad stroke font (always existing)
|
||||
#include <font/kicad_font_name.h>
|
||||
@@ -32,7 +33,7 @@ FONT_CHOICE::FONT_CHOICE( wxWindow* aParent, int aId, wxPoint aPosition, wxSize
|
||||
m_systemFontCount = wxChoice::GetCount();
|
||||
|
||||
std::vector<std::string> fontNames;
|
||||
Fontconfig()->ListFonts( fontNames );
|
||||
Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ) );
|
||||
|
||||
wxArrayString menuList;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <wx/odcombo.h>
|
||||
#include <wx/menuitem.h>
|
||||
|
||||
#include <gal/dpi_scaling.h>
|
||||
#include <layer_ids.h>
|
||||
#include <widgets/layer_box_selector.h>
|
||||
|
||||
@@ -140,9 +141,12 @@ int LAYER_BOX_SELECTOR::SetLayerSelection( int layer )
|
||||
|
||||
void LAYER_BOX_SELECTOR::ResyncBitmapOnly()
|
||||
{
|
||||
DPI_SCALING dpi( nullptr, this );
|
||||
int size = static_cast<int>( dpi.GetScaleFactor() * 14 );
|
||||
|
||||
for( int i = 0; i < (int) GetCount(); ++i )
|
||||
{
|
||||
wxBitmap layerbmp( 14, 14 );
|
||||
wxBitmap layerbmp( size, size );
|
||||
DrawColorSwatch( layerbmp, getLayerColor( LAYER_PCB_BACKGROUND ), getLayerColor( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
+197
-186
@@ -327,7 +327,7 @@ void mpInfoLegend::Plot( wxDC& dc, mpWindow& w )
|
||||
int plotCount = 0;
|
||||
int posY = 0;
|
||||
int tmpX = 0, tmpY = 0;
|
||||
mpLayer* ly = NULL;
|
||||
mpLayer* ly = nullptr;
|
||||
wxPen lpen;
|
||||
wxString label;
|
||||
|
||||
@@ -541,8 +541,8 @@ mpFXY::mpFXY( const wxString& name, int flags )
|
||||
SetName( name );
|
||||
m_flags = flags;
|
||||
m_type = mpLAYER_PLOT;
|
||||
m_scaleX = NULL;
|
||||
m_scaleY = NULL;
|
||||
m_scaleX = nullptr;
|
||||
m_scaleY = nullptr;
|
||||
|
||||
// Avoid not initialized members:
|
||||
maxDrawX = minDrawX = maxDrawY = minDrawY = 0;
|
||||
@@ -562,207 +562,218 @@ void mpFXY::UpdateViewBoundary( wxCoord xnew, wxCoord ynew )
|
||||
|
||||
void mpFXY::Plot( wxDC& dc, mpWindow& w )
|
||||
{
|
||||
if( m_visible )
|
||||
wxCHECK_RET( m_scaleX, wxS( "X scale was not set" ) );
|
||||
|
||||
wxCHECK_RET( m_scaleY, wxS( "Y scale was not set" ) );
|
||||
|
||||
if( !m_visible )
|
||||
return;
|
||||
|
||||
wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
|
||||
wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
|
||||
wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
|
||||
wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
|
||||
|
||||
// Check for a collapsed window before we try to allocate a negative number of points
|
||||
if( endPx <= startPx || minYpx >= maxYpx )
|
||||
return;
|
||||
|
||||
dc.SetPen( m_pen );
|
||||
|
||||
double x, y;
|
||||
// Do this to reset the counters to evaluate bounding box for label positioning
|
||||
Rewind();
|
||||
GetNextXY( x, y );
|
||||
maxDrawX = x;
|
||||
minDrawX = x;
|
||||
maxDrawY = y;
|
||||
minDrawY = y;
|
||||
// drawnPoints = 0;
|
||||
Rewind();
|
||||
|
||||
dc.SetClippingRegion( startPx, minYpx, endPx - startPx + 1, maxYpx - minYpx + 1 );
|
||||
|
||||
if( !m_continuous )
|
||||
{
|
||||
dc.SetPen( m_pen );
|
||||
bool first = true;
|
||||
wxCoord ix = 0;
|
||||
std::set<wxCoord> ys;
|
||||
|
||||
double x, y;
|
||||
// Do this to reset the counters to evaluate bounding box for label positioning
|
||||
Rewind(); GetNextXY( x, y );
|
||||
maxDrawX = x; minDrawX = x; maxDrawY = y; minDrawY = y;
|
||||
// drawnPoints = 0;
|
||||
Rewind();
|
||||
|
||||
wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
|
||||
wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
|
||||
wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
|
||||
wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
|
||||
|
||||
dc.SetClippingRegion( startPx, minYpx, endPx - startPx + 1, maxYpx - minYpx + 1 );
|
||||
|
||||
if( !m_continuous )
|
||||
while( GetNextXY( x, y ) )
|
||||
{
|
||||
bool first = true;
|
||||
wxCoord ix = 0;
|
||||
std::set<wxCoord> ys;
|
||||
double px = m_scaleX->TransformToPlot( x );
|
||||
double py = m_scaleY->TransformToPlot( y );
|
||||
wxCoord newX = w.x2p( px );
|
||||
|
||||
while( GetNextXY( x, y ) )
|
||||
if( first )
|
||||
{
|
||||
double px = m_scaleX->TransformToPlot( x );
|
||||
double py = m_scaleY->TransformToPlot( y );
|
||||
wxCoord newX = w.x2p( px );
|
||||
|
||||
if( first )
|
||||
{
|
||||
ix = newX;
|
||||
first = false;
|
||||
}
|
||||
|
||||
if( newX == ix ) // continue until a new X coordinate is reached
|
||||
{
|
||||
// collect all unique points
|
||||
ys.insert( w.y2p( py ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
for( auto& iy: ys )
|
||||
{
|
||||
if( m_drawOutsideMargins
|
||||
|| ( (ix >= startPx) && (ix <= endPx) && (iy >= minYpx)
|
||||
&& (iy <= maxYpx) ) )
|
||||
{
|
||||
// for some reason DrawPoint does not use the current pen,
|
||||
// so we use DrawLine for fat pens
|
||||
if( m_pen.GetWidth() <= 1 )
|
||||
{
|
||||
dc.DrawPoint( ix, iy );
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.DrawLine( ix, iy, ix, iy );
|
||||
}
|
||||
|
||||
UpdateViewBoundary( ix, iy );
|
||||
}
|
||||
}
|
||||
|
||||
ys.clear();
|
||||
ix = newX;
|
||||
first = false;
|
||||
}
|
||||
|
||||
if( newX == ix ) // continue until a new X coordinate is reached
|
||||
{
|
||||
// collect all unique points
|
||||
ys.insert( w.y2p( py ) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = 0;
|
||||
int x0=0; // X position of merged current vertical line
|
||||
int ymin0=0; // y min coord of merged current vertical line
|
||||
int ymax0=0; // y max coord of merged current vertical line
|
||||
int dupx0 = 0; // count of currently merged vertical lines
|
||||
wxPoint line_start; // starting point of the current line to draw
|
||||
|
||||
// A buffer to store coordinates of lines to draw
|
||||
std::vector<wxPoint>pointList;
|
||||
pointList.reserve( endPx - startPx + 1 );
|
||||
|
||||
// Note: we can use dc.DrawLines() only for a reasonable number or points (<10000),
|
||||
// because at least on Windows dc.DrawLines() can hang for a lot of points.
|
||||
// (> 10000 points) (can happens when a lot of points is calculated)
|
||||
// To avoid long draw time (and perhaps hanging) one plot only not redundant lines.
|
||||
// To avoid artifacts when skipping points to the same x coordinate, for each
|
||||
// group of points at a give, x coordinate we also draw a vertical line at this coord,
|
||||
// from the ymin to the ymax vertical coordinates of skipped points
|
||||
while( GetNextXY( x, y ) )
|
||||
for( auto& iy: ys )
|
||||
{
|
||||
double px = m_scaleX->TransformToPlot( x );
|
||||
double py = m_scaleY->TransformToPlot( y );
|
||||
|
||||
wxCoord x1 = w.x2p( px );
|
||||
wxCoord y1 = w.y2p( py );
|
||||
|
||||
// Store only points on the drawing area, to speed up the drawing time
|
||||
// Note: x1 is a value truncated from px by w.x2p(). So to be sure the
|
||||
// first point is drawn, the x1 low limit is startPx-1 in plot coordinates
|
||||
if( x1 >= startPx-1 && x1 <= endPx )
|
||||
if( m_drawOutsideMargins
|
||||
|| ( (ix >= startPx) && (ix <= endPx) && (iy >= minYpx) && (iy <= maxYpx) ) )
|
||||
{
|
||||
if( !count || line_start.x != x1 )
|
||||
{
|
||||
if( count && dupx0 > 1 && ymin0 != ymax0 )
|
||||
{
|
||||
// Vertical points are merged, draw the pending vertical line
|
||||
// However, if the line is one pixel length, it is not drawn,
|
||||
// because the main trace show this point
|
||||
dc.DrawLine( x0, ymin0, x0, ymax0 );
|
||||
}
|
||||
|
||||
x0 = x1;
|
||||
ymin0 = ymax0 = y1;
|
||||
dupx0 = 0;
|
||||
|
||||
pointList.emplace_back( wxPoint( x1, y1 ) );
|
||||
|
||||
line_start.x = x1;
|
||||
line_start.y = y1;
|
||||
count++;
|
||||
}
|
||||
// for some reason DrawPoint does not use the current pen, so we use
|
||||
// DrawLine for fat pens
|
||||
if( m_pen.GetWidth() <= 1 )
|
||||
dc.DrawPoint( ix, iy );
|
||||
else
|
||||
{
|
||||
ymin0 = std::min( ymin0, y1 );
|
||||
ymax0 = std::max( ymax0, y1 );
|
||||
x0 = x1;
|
||||
dupx0++;
|
||||
}
|
||||
dc.DrawLine( ix, iy, ix, iy );
|
||||
|
||||
UpdateViewBoundary( ix, iy );
|
||||
}
|
||||
}
|
||||
|
||||
if( pointList.size() > 1 )
|
||||
{
|
||||
// For a better look (when using dashed lines) and more optimization,
|
||||
// try to merge horizontal segments, in order to plot longer lines
|
||||
// we are merging horizontal segments because this is easy,
|
||||
// and horizontal segments are a frequent cases
|
||||
std::vector<wxPoint> drawPoints;
|
||||
drawPoints.reserve( endPx - startPx + 1 );
|
||||
|
||||
drawPoints.push_back( pointList[0] ); // push the first point in list
|
||||
|
||||
for( size_t ii = 1; ii < pointList.size()-1; ii++ )
|
||||
{
|
||||
// Skip intermediate points between the first point and the last
|
||||
// point of the segment candidate
|
||||
if( drawPoints.back().y == pointList[ii].y &&
|
||||
drawPoints.back().y == pointList[ii+1].y )
|
||||
continue;
|
||||
else
|
||||
drawPoints.push_back( pointList[ii] );
|
||||
}
|
||||
|
||||
// push the last point to draw in list
|
||||
if( drawPoints.back() != pointList.back() )
|
||||
drawPoints.push_back( pointList.back() );
|
||||
|
||||
dc.DrawLines( drawPoints.size(), &drawPoints[0] );
|
||||
}
|
||||
ys.clear();
|
||||
ix = newX;
|
||||
ys.insert( w.y2p( py ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = 0;
|
||||
int x0=0; // X position of merged current vertical line
|
||||
int ymin0=0; // y min coord of merged current vertical line
|
||||
int ymax0=0; // y max coord of merged current vertical line
|
||||
int dupx0 = 0; // count of currently merged vertical lines
|
||||
wxPoint line_start; // starting point of the current line to draw
|
||||
|
||||
if( !m_name.IsEmpty() && m_showName )
|
||||
// A buffer to store coordinates of lines to draw
|
||||
std::vector<wxPoint>pointList;
|
||||
pointList.reserve( endPx - startPx + 1 );
|
||||
|
||||
// Note: we can use dc.DrawLines() only for a reasonable number or points (<10000),
|
||||
// because at least on Windows dc.DrawLines() can hang for a lot of points.
|
||||
// (> 10000 points) (can happens when a lot of points is calculated)
|
||||
// To avoid long draw time (and perhaps hanging) one plot only not redundant lines.
|
||||
// To avoid artifacts when skipping points to the same x coordinate, for each group of
|
||||
// points at a give, x coordinate we also draw a vertical line at this coord, from the
|
||||
// ymin to the ymax vertical coordinates of skipped points
|
||||
while( GetNextXY( x, y ) )
|
||||
{
|
||||
dc.SetFont( m_font );
|
||||
double px = m_scaleX->TransformToPlot( x );
|
||||
double py = m_scaleY->TransformToPlot( y );
|
||||
|
||||
wxCoord tx, ty;
|
||||
dc.GetTextExtent( m_name, &tx, &ty );
|
||||
wxCoord x1 = w.x2p( px );
|
||||
wxCoord y1 = w.y2p( py );
|
||||
|
||||
// xxx implement else ... if (!HasBBox())
|
||||
// Store only points on the drawing area, to speed up the drawing time
|
||||
// Note: x1 is a value truncated from px by w.x2p(). So to be sure the first point
|
||||
// is drawn, the x1 low limit is startPx-1 in plot coordinates
|
||||
if( x1 >= startPx-1 && x1 <= endPx )
|
||||
{
|
||||
// const int sx = w.GetScrX();
|
||||
// const int sy = w.GetScrY();
|
||||
if( !count || line_start.x != x1 )
|
||||
{
|
||||
if( count && dupx0 > 1 && ymin0 != ymax0 )
|
||||
{
|
||||
// Vertical points are merged, draw the pending vertical line
|
||||
// However, if the line is one pixel length, it is not drawn, because
|
||||
// the main trace show this point
|
||||
dc.DrawLine( x0, ymin0, x0, ymax0 );
|
||||
}
|
||||
|
||||
if( (m_flags & mpALIGNMASK) == mpALIGN_NW )
|
||||
{
|
||||
tx = minDrawX + 8;
|
||||
ty = maxDrawY + 8;
|
||||
}
|
||||
else if( (m_flags & mpALIGNMASK) == mpALIGN_NE )
|
||||
{
|
||||
tx = maxDrawX - tx - 8;
|
||||
ty = maxDrawY + 8;
|
||||
}
|
||||
else if( (m_flags & mpALIGNMASK) == mpALIGN_SE )
|
||||
{
|
||||
tx = maxDrawX - tx - 8;
|
||||
ty = minDrawY - ty - 8;
|
||||
x0 = x1;
|
||||
ymin0 = ymax0 = y1;
|
||||
dupx0 = 0;
|
||||
|
||||
pointList.emplace_back( wxPoint( x1, y1 ) );
|
||||
|
||||
line_start.x = x1;
|
||||
line_start.y = y1;
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// mpALIGN_SW
|
||||
tx = minDrawX + 8;
|
||||
ty = minDrawY - ty - 8;
|
||||
ymin0 = std::min( ymin0, y1 );
|
||||
ymax0 = std::max( ymax0, y1 );
|
||||
x0 = x1;
|
||||
dupx0++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pointList.size() > 1 )
|
||||
{
|
||||
// For a better look (when using dashed lines) and more optimization, try to merge
|
||||
// horizontal segments, in order to plot longer lines
|
||||
// We are merging horizontal segments because this is easy, and horizontal segments
|
||||
// are a frequent cases
|
||||
std::vector<wxPoint> drawPoints;
|
||||
drawPoints.reserve( endPx - startPx + 1 );
|
||||
|
||||
drawPoints.push_back( pointList[0] ); // push the first point in list
|
||||
|
||||
for( size_t ii = 1; ii < pointList.size()-1; ii++ )
|
||||
{
|
||||
// Skip intermediate points between the first point and the last point of the
|
||||
// segment candidate
|
||||
if( drawPoints.back().y == pointList[ii].y &&
|
||||
drawPoints.back().y == pointList[ii+1].y )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawPoints.push_back( pointList[ii] );
|
||||
}
|
||||
}
|
||||
|
||||
dc.DrawText( m_name, tx, ty );
|
||||
// push the last point to draw in list
|
||||
if( drawPoints.back() != pointList.back() )
|
||||
drawPoints.push_back( pointList.back() );
|
||||
|
||||
dc.DrawLines( drawPoints.size(), &drawPoints[0] );
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_name.IsEmpty() && m_showName )
|
||||
{
|
||||
dc.SetFont( m_font );
|
||||
|
||||
wxCoord tx, ty;
|
||||
dc.GetTextExtent( m_name, &tx, &ty );
|
||||
|
||||
// xxx implement else ... if (!HasBBox())
|
||||
{
|
||||
// const int sx = w.GetScrX();
|
||||
// const int sy = w.GetScrY();
|
||||
|
||||
if( (m_flags & mpALIGNMASK) == mpALIGN_NW )
|
||||
{
|
||||
tx = minDrawX + 8;
|
||||
ty = maxDrawY + 8;
|
||||
}
|
||||
else if( (m_flags & mpALIGNMASK) == mpALIGN_NE )
|
||||
{
|
||||
tx = maxDrawX - tx - 8;
|
||||
ty = maxDrawY + 8;
|
||||
}
|
||||
else if( (m_flags & mpALIGNMASK) == mpALIGN_SE )
|
||||
{
|
||||
tx = maxDrawX - tx - 8;
|
||||
ty = minDrawY - ty - 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// mpALIGN_SW
|
||||
tx = minDrawX + 8;
|
||||
ty = minDrawY - ty - 8;
|
||||
}
|
||||
}
|
||||
|
||||
dc.DrawText( m_name, tx, ty );
|
||||
}
|
||||
|
||||
dc.DestroyClippingRegion();
|
||||
}
|
||||
|
||||
@@ -1395,7 +1406,7 @@ mpScaleY::mpScaleY( const wxString& name, int flags, bool ticks )
|
||||
m_flags = flags;
|
||||
m_ticks = ticks;
|
||||
m_type = mpLAYER_AXIS;
|
||||
m_masterScale = NULL;
|
||||
m_masterScale = nullptr;
|
||||
m_nameFlags = mpALIGN_BORDER_LEFT;
|
||||
}
|
||||
|
||||
@@ -1662,11 +1673,11 @@ mpWindow::mpWindow( wxWindow* parent,
|
||||
m_minX = m_minY = 0;
|
||||
m_maxX = m_maxY = 0;
|
||||
m_last_lx = m_last_ly = 0;
|
||||
m_buff_bmp = NULL;
|
||||
m_buff_bmp = nullptr;
|
||||
m_enableDoubleBuffer = false;
|
||||
m_enableMouseNavigation = true;
|
||||
m_enableLimitedView = false;
|
||||
m_movingInfoLayer = NULL;
|
||||
m_movingInfoLayer = nullptr;
|
||||
// Set margins to 0
|
||||
m_marginTop = 0; m_marginRight = 0; m_marginBottom = 0; m_marginLeft = 0;
|
||||
|
||||
@@ -1914,10 +1925,10 @@ void mpWindow::OnMouseLeftRelease( wxMouseEvent& event )
|
||||
|
||||
m_zooming = false;
|
||||
|
||||
if( m_movingInfoLayer != NULL )
|
||||
if( m_movingInfoLayer != nullptr )
|
||||
{
|
||||
m_movingInfoLayer->UpdateReference();
|
||||
m_movingInfoLayer = NULL;
|
||||
m_movingInfoLayer = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1953,7 +1964,7 @@ void mpWindow::Fit( double xMin, double xMax, double yMin, double yMax,
|
||||
yMin -= yExtra;
|
||||
yMax += yExtra;
|
||||
|
||||
if( printSizeX != NULL && printSizeY != NULL )
|
||||
if( printSizeX != nullptr && printSizeY != nullptr )
|
||||
{
|
||||
// Printer:
|
||||
m_scrX = *printSizeX;
|
||||
@@ -1994,7 +2005,7 @@ void mpWindow::Fit( double xMin, double xMax, double yMin, double yMax,
|
||||
|
||||
// It is VERY IMPORTANT to DO NOT call Refresh if we are drawing to the printer!!
|
||||
// Otherwise, the DC dimensions will be those of the window instead of the printer device
|
||||
if( printSizeX == NULL || printSizeY == NULL )
|
||||
if( printSizeX == nullptr || printSizeY == nullptr )
|
||||
UpdateAll();
|
||||
}
|
||||
|
||||
@@ -2634,7 +2645,7 @@ unsigned int mpWindow::CountLayers() const
|
||||
mpLayer* mpWindow::GetLayer( int position ) const
|
||||
{
|
||||
if( ( position >= (int) m_layers.size() ) || position < 0 )
|
||||
return NULL;
|
||||
return nullptr;
|
||||
|
||||
return m_layers[position];
|
||||
}
|
||||
@@ -2648,7 +2659,7 @@ const mpLayer* mpWindow::GetLayerByName( const wxString& name ) const
|
||||
return layer;
|
||||
}
|
||||
|
||||
return NULL; // Not found
|
||||
return nullptr; // Not found
|
||||
}
|
||||
|
||||
|
||||
@@ -2735,7 +2746,7 @@ mpInfoLayer* mpWindow::IsInsideInfoLayer( wxPoint& point )
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -3078,9 +3089,9 @@ bool mpPrintout::OnPrintPage( int page )
|
||||
// Restore colours
|
||||
plotWindow->SetColourTheme( oldBgColour, oldFgColour, oldAxColour );
|
||||
// Restore drawing
|
||||
plotWindow->Fit( plotWindow->GetDesiredXmin(),
|
||||
plotWindow->GetDesiredXmax(), plotWindow->GetDesiredYmin(),
|
||||
plotWindow->GetDesiredYmax(), NULL, NULL );
|
||||
plotWindow->Fit( plotWindow->GetDesiredXmin(), plotWindow->GetDesiredXmax(),
|
||||
plotWindow->GetDesiredYmin(), plotWindow->GetDesiredYmax(), nullptr,
|
||||
nullptr );
|
||||
plotWindow->UpdateAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -65,8 +65,6 @@ PROPERTIES_PANEL::PROPERTIES_PANEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame )
|
||||
delete wxPGGlobalVars->m_defaultRenderer;
|
||||
wxPGGlobalVars->m_defaultRenderer = new PG_CELL_RENDERER();
|
||||
|
||||
m_cachedSelection = std::make_unique<SELECTION>();
|
||||
|
||||
m_caption = new wxStaticText( this, wxID_ANY, _( "No objects selected" ) );
|
||||
mainSizer->Add( m_caption, 0, wxALL | wxEXPAND, 5 );
|
||||
|
||||
@@ -74,6 +72,7 @@ PROPERTIES_PANEL::PROPERTIES_PANEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame )
|
||||
wxPG_DEFAULT_STYLE );
|
||||
m_grid->SetUnspecifiedValueAppearance( wxPGCell( wxT( "<...>" ) ) );
|
||||
m_grid->SetExtraStyle( wxPG_EX_HELP_AS_TOOLTIPS );
|
||||
m_grid->SetValidationFailureBehavior( wxPG_VFB_MARK_CELL );
|
||||
m_grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_RETURN );
|
||||
m_grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_NUMPAD_ENTER );
|
||||
m_grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_DOWN );
|
||||
@@ -131,23 +130,20 @@ void PROPERTIES_PANEL::OnLanguageChanged()
|
||||
|
||||
void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
|
||||
{
|
||||
if( *m_cachedSelection == aSelection )
|
||||
{
|
||||
updatePropertyValues( aSelection );
|
||||
return;
|
||||
}
|
||||
auto reset =
|
||||
[&]()
|
||||
{
|
||||
if( m_grid->IsEditorFocused() )
|
||||
m_grid->CommitChangesFromEditor();
|
||||
|
||||
*m_cachedSelection = aSelection;
|
||||
|
||||
if( m_grid->IsEditorFocused() )
|
||||
m_grid->CommitChangesFromEditor();
|
||||
|
||||
m_grid->Clear();
|
||||
m_displayed.clear();
|
||||
m_grid->Clear();
|
||||
m_displayed.clear();
|
||||
};
|
||||
|
||||
if( aSelection.Empty() )
|
||||
{
|
||||
m_caption->SetLabel( _( "No objects selected" ) );
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,15 +155,6 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
|
||||
|
||||
wxCHECK( !types.empty(), /* void */ );
|
||||
|
||||
if( aSelection.Size() > 1 )
|
||||
{
|
||||
m_caption->SetLabel( wxString::Format( _( "%d objects selected" ), aSelection.Size() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_caption->SetLabel( aSelection.Front()->GetFriendlyName() );
|
||||
}
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
propMgr.SetUnits( m_frame->GetUserUnits() );
|
||||
propMgr.SetTransforms( &m_frame->GetOriginTransforms() );
|
||||
@@ -181,8 +168,7 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
|
||||
std::vector<wxString> groupDisplayOrder = propMgr.GetGroupDisplayOrder( *types.begin() );
|
||||
std::set<wxString> groups( groupDisplayOrder.begin(), groupDisplayOrder.end() );
|
||||
|
||||
std::map<wxPGProperty*, int> pgPropOrders;
|
||||
std::map<wxString, std::vector<wxPGProperty*>> pgPropGroups;
|
||||
std::set<PROPERTY_BASE*> availableProps;
|
||||
|
||||
// Get all possible properties
|
||||
for( const TYPE_ID& type : types )
|
||||
@@ -214,40 +200,77 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
|
||||
}
|
||||
}
|
||||
|
||||
EDA_ITEM* firstItem = aSelection.Front();
|
||||
|
||||
// Find a set of properties that is common to all selected items
|
||||
for( PROPERTY_BASE* property : commonProps )
|
||||
{
|
||||
if( property->IsInternal() )
|
||||
continue;
|
||||
|
||||
if( !propMgr.IsAvailableFor( TYPE_HASH( *aSelection.Front() ), property,
|
||||
aSelection.Front() ) )
|
||||
if( propMgr.IsAvailableFor( TYPE_HASH( *firstItem ), property, firstItem ) )
|
||||
availableProps.insert( property );
|
||||
}
|
||||
|
||||
bool writeable = true;
|
||||
std::set<PROPERTY_BASE*> existingProps;
|
||||
|
||||
for( wxPropertyGridIterator it = m_grid->GetIterator(); !it.AtEnd(); it.Next() )
|
||||
{
|
||||
wxPGProperty* pgProp = it.GetProperty();
|
||||
PROPERTY_BASE* property = propMgr.GetProperty( TYPE_HASH( *firstItem ), pgProp->GetName() );
|
||||
|
||||
// Switching item types? Property may no longer be valid
|
||||
if( !property )
|
||||
continue;
|
||||
|
||||
// Either determine the common value for a property or "<...>" to indicate multiple values
|
||||
bool available;
|
||||
bool writeable;
|
||||
wxVariant commonVal;
|
||||
|
||||
available = extractValueAndWritability( aSelection, property, commonVal, writeable );
|
||||
extractValueAndWritability( aSelection, property, commonVal, writeable );
|
||||
pgProp->SetValue( commonVal );
|
||||
pgProp->Enable( writeable );
|
||||
|
||||
if( available )
|
||||
existingProps.insert( property );
|
||||
}
|
||||
|
||||
if( existingProps == availableProps )
|
||||
return;
|
||||
|
||||
// Some difference exists: start from scratch
|
||||
reset();
|
||||
|
||||
std::map<wxPGProperty*, int> pgPropOrders;
|
||||
std::map<wxString, std::vector<wxPGProperty*>> pgPropGroups;
|
||||
|
||||
for( PROPERTY_BASE* property : availableProps )
|
||||
{
|
||||
wxPGProperty* pgProp = createPGProperty( property );
|
||||
wxVariant commonVal;
|
||||
|
||||
if( !extractValueAndWritability( aSelection, property, commonVal, writeable ) )
|
||||
continue;
|
||||
|
||||
if( pgProp )
|
||||
{
|
||||
wxPGProperty* pgProp = createPGProperty( property );
|
||||
pgProp->SetValue( commonVal );
|
||||
pgProp->Enable( writeable );
|
||||
m_displayed.push_back( property );
|
||||
|
||||
if( pgProp )
|
||||
{
|
||||
pgProp->SetValue( commonVal );
|
||||
pgProp->Enable( writeable );
|
||||
m_displayed.push_back( property );
|
||||
|
||||
wxASSERT( displayOrder.count( property ) );
|
||||
pgPropOrders[pgProp] = displayOrder[property];
|
||||
pgPropGroups[property->Group()].emplace_back( pgProp );
|
||||
}
|
||||
wxASSERT( displayOrder.count( property ) );
|
||||
pgPropOrders[pgProp] = displayOrder[property];
|
||||
pgPropGroups[property->Group()].emplace_back( pgProp );
|
||||
}
|
||||
}
|
||||
|
||||
if( aSelection.Size() > 1 )
|
||||
{
|
||||
m_caption->SetLabel( wxString::Format( _( "%d objects selected" ), aSelection.Size() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_caption->SetLabel( aSelection.Front()->GetFriendlyName() );
|
||||
}
|
||||
|
||||
const wxString unspecifiedGroupCaption = _( "Basic Properties" );
|
||||
|
||||
for( const wxString& groupName : groupDisplayOrder )
|
||||
|
||||
@@ -75,24 +75,10 @@ protected:
|
||||
/**
|
||||
* Generates the property grid for a given selection of items.
|
||||
*
|
||||
* Calling this will remove any existing properties shown, causing visible flicker on some
|
||||
* platforms and canceling any pending edits. Make sure to only call this when the group of
|
||||
* selected items has actually changed.
|
||||
*
|
||||
* @param aSelection is a set of items to show properties for.
|
||||
*/
|
||||
virtual void rebuildProperties( const SELECTION& aSelection );
|
||||
|
||||
/**
|
||||
* Updates the values shown in the property grid for the current selection.
|
||||
*
|
||||
* Does not add or remove properties from the display (@see rebuildProperties)
|
||||
* This implies that aSelection must have the same contents as m_cachedSelection.
|
||||
*
|
||||
* @param aSelection is the set of selected items.
|
||||
*/
|
||||
virtual void updatePropertyValues( const SELECTION& aSelection ) {}
|
||||
|
||||
virtual wxPGProperty* createPGProperty( const PROPERTY_BASE* aProperty ) const = 0;
|
||||
|
||||
// Event handlers
|
||||
@@ -128,9 +114,6 @@ protected:
|
||||
|
||||
/// Proportion of the grid column splitter that is used for the key column (0.0 - 1.0)
|
||||
float m_splitter_key_proportion;
|
||||
|
||||
/// A copy of the most recent selection passed to rebuildProperties
|
||||
std::unique_ptr<SELECTION> m_cachedSelection;
|
||||
};
|
||||
|
||||
#endif /* PROPERTIES_PANEL_H */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022-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
|
||||
@@ -42,6 +42,8 @@ void SEARCH_PANE::OnLanguageChange()
|
||||
wxWindow* page = m_notebook->GetPage( i );
|
||||
SEARCH_PANE_TAB* tab = dynamic_cast<SEARCH_PANE_TAB*>( page );
|
||||
|
||||
wxCHECK( tab, /* void */ );
|
||||
|
||||
tab->RefreshColumnNames();
|
||||
m_notebook->SetPageText( i, wxGetTranslation( tab->GetSearchHandler()->GetName() ) );
|
||||
}
|
||||
@@ -103,4 +105,4 @@ void SEARCH_PANE::OnNotebookPageChanged( wxBookCtrlEvent& aEvent )
|
||||
SEARCH_PANE_TAB* SEARCH_PANE::GetCurrentTab() const
|
||||
{
|
||||
return dynamic_cast<SEARCH_PANE_TAB*>( m_notebook->GetCurrentPage() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,8 @@ SYMBOLS_LISTBOX::SYMBOLS_LISTBOX( CVPCB_MAINFRAME* parent, wxWindowID id ) :
|
||||
ITEMS_LISTBOX_BASE( parent, id ),
|
||||
m_warningAttr( std::make_unique<wxListItemAttr>() )
|
||||
{
|
||||
m_warningAttr->SetBackgroundColour( KIPLATFORM::UI::IsDarkTheme()
|
||||
? wxColour( 112, 96, 32 )
|
||||
: *wxYELLOW );
|
||||
m_warningAttr->SetBackgroundColour( KIPLATFORM::UI::IsDarkTheme() ? wxColour( 112, 96, 32 )
|
||||
: wxColour( 255, 248, 212 ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -84,6 +84,9 @@ void CVPCB_MAINFRAME::ReCreateHToolbar()
|
||||
m_tcFilterString = new wxTextCtrl( m_mainToolBar, wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_PROCESS_ENTER );
|
||||
|
||||
// Min size on Mac is (a not very useful) single character
|
||||
m_tcFilterString->SetMinSize( wxSize( 150, -1 ) );
|
||||
|
||||
m_tcFilterString->Bind( wxEVT_TEXT_ENTER, &CVPCB_MAINFRAME::onTextFilterChanged, this );
|
||||
|
||||
m_mainToolBar->AddControl( m_tcFilterString );
|
||||
|
||||
@@ -947,6 +947,10 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
||||
m_toolManager->RunAction( ACTIONS::updateSchematicFromPcb, true );
|
||||
break;
|
||||
|
||||
case MAIL_RELOAD_LIB:
|
||||
SyncView();
|
||||
break;
|
||||
|
||||
default:;
|
||||
|
||||
}
|
||||
|
||||
@@ -512,21 +512,18 @@ int DIALOG_CHANGE_SYMBOLS::processMatchingSymbols()
|
||||
|
||||
|
||||
int DIALOG_CHANGE_SYMBOLS::processSymbols( const std::map<SCH_SYMBOL*,
|
||||
SYMBOL_CHANGE_INFO>& aSymbols )
|
||||
SYMBOL_CHANGE_INFO>& aSymbols )
|
||||
{
|
||||
wxCHECK( !aSymbols.empty(), 0 );
|
||||
|
||||
int matchesProcessed = 0;
|
||||
SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
|
||||
SCH_SCREEN* screen = nullptr;
|
||||
LIB_SYMBOL* libSymbol = nullptr;
|
||||
std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols = aSymbols;
|
||||
wxString msg;
|
||||
|
||||
wxCHECK( frame, 0 );
|
||||
|
||||
wxString msg;
|
||||
|
||||
auto it = symbols.begin();
|
||||
std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO> symbols = aSymbols;
|
||||
std::map<SCH_SYMBOL*, SYMBOL_CHANGE_INFO>::iterator it = symbols.begin();
|
||||
|
||||
// Remove all symbols that don't have a valid library symbol link or enough units to
|
||||
// satify the library symbol update.
|
||||
@@ -536,7 +533,7 @@ int DIALOG_CHANGE_SYMBOLS::processSymbols( const std::map<SCH_SYMBOL*,
|
||||
|
||||
wxCHECK2( symbol && it->second.m_LibId.IsValid(), continue );
|
||||
|
||||
libSymbol = frame->GetLibSymbol( it->second.m_LibId );
|
||||
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( it->second.m_LibId );
|
||||
|
||||
if( !libSymbol )
|
||||
{
|
||||
@@ -562,18 +559,21 @@ int DIALOG_CHANGE_SYMBOLS::processSymbols( const std::map<SCH_SYMBOL*,
|
||||
}
|
||||
}
|
||||
|
||||
bool appendUndo = false;
|
||||
|
||||
// Removing the symbol needs to be done before the LIB_SYMBOL is changed to prevent stale
|
||||
// library symbols in the schematic file.
|
||||
for( const auto& [ symbol, symbol_change_info ] : symbols )
|
||||
{
|
||||
wxCHECK( symbol && !symbol_change_info.m_Instances.empty(), 0 );
|
||||
|
||||
screen = symbol_change_info.m_Instances[0].LastScreen();
|
||||
SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
|
||||
|
||||
wxCHECK( screen, 0 );
|
||||
|
||||
screen->Remove( symbol );
|
||||
frame->SaveCopyInUndoList( screen, symbol, UNDO_REDO::CHANGED, true );
|
||||
frame->SaveCopyInUndoList( screen, symbol, UNDO_REDO::CHANGED, appendUndo );
|
||||
appendUndo = true;
|
||||
}
|
||||
|
||||
for( const auto& [ symbol, symbol_change_info ] : symbols )
|
||||
@@ -581,8 +581,9 @@ int DIALOG_CHANGE_SYMBOLS::processSymbols( const std::map<SCH_SYMBOL*,
|
||||
if( symbol_change_info.m_LibId != symbol->GetLibId() )
|
||||
symbol->SetLibId( symbol_change_info.m_LibId );
|
||||
|
||||
libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
|
||||
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
|
||||
std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
|
||||
SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
|
||||
|
||||
symbol->SetLibSymbol( flattenedSymbol.release() );
|
||||
|
||||
@@ -696,7 +697,6 @@ int DIALOG_CHANGE_SYMBOLS::processSymbols( const std::map<SCH_SYMBOL*,
|
||||
}
|
||||
|
||||
symbol->SetSchSymbolLibraryName( wxEmptyString );
|
||||
screen = symbol_change_info.m_Instances[0].LastScreen();
|
||||
screen->Append( symbol );
|
||||
frame->GetCanvas()->GetView()->Update( symbol );
|
||||
|
||||
|
||||
@@ -157,6 +157,8 @@ void DIALOG_FIELD_PROPERTIES::init()
|
||||
|
||||
// Predefined fields cannot contain some chars, or cannot be empty,
|
||||
// and need a SCH_FIELD_VALIDATOR (m_StyledTextCtrl cannot use a SCH_FIELD_VALIDATOR).
|
||||
// VALUE_FIELD does not use the validator so that it uses the Scintilla text control, since we
|
||||
// allow text replacement for this field (but not the other predefined fields)
|
||||
bool use_validator = m_fieldId == REFERENCE_FIELD
|
||||
|| m_fieldId == FOOTPRINT_FIELD
|
||||
|| m_fieldId == DATASHEET_FIELD
|
||||
@@ -189,10 +191,12 @@ void DIALOG_FIELD_PROPERTIES::init()
|
||||
"cannot be changed." ) ) );
|
||||
m_note->Show( true );
|
||||
m_TextCtrl->Enable( false );
|
||||
m_StyledTextCtrl->Enable( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_TextCtrl->Enable( true );
|
||||
m_StyledTextCtrl->Enable( true );
|
||||
}
|
||||
|
||||
GetSizer()->SetSizeHints( this );
|
||||
|
||||
@@ -489,6 +489,16 @@ void DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS::visitItem( const SCH_SHEET_PATH& aShe
|
||||
processItem( aSheetPath, pin );
|
||||
}
|
||||
}
|
||||
else if( m_wires->GetValue() && aItem->IsType( { SCH_ITEM_LOCATE_WIRE_T,
|
||||
SCH_LABEL_LOCATE_WIRE_T } ) )
|
||||
{
|
||||
processItem( aSheetPath, aItem );
|
||||
}
|
||||
else if( m_buses->GetValue() && aItem->IsType( { SCH_ITEM_LOCATE_BUS_T,
|
||||
SCH_LABEL_LOCATE_BUS_T } ) )
|
||||
{
|
||||
processItem( aSheetPath, aItem );
|
||||
}
|
||||
else if( aItem->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
|
||||
{
|
||||
if( m_globalLabels->GetValue() && aItem->Type() == SCH_GLOBAL_LABEL_T )
|
||||
@@ -529,16 +539,6 @@ void DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS::visitItem( const SCH_SHEET_PATH& aShe
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( m_wires->GetValue() && aItem->IsType( { SCH_ITEM_LOCATE_WIRE_T,
|
||||
SCH_LABEL_LOCATE_WIRE_T } ) )
|
||||
{
|
||||
processItem( aSheetPath, aItem );
|
||||
}
|
||||
else if( m_buses->GetValue() && aItem->IsType( { SCH_ITEM_LOCATE_BUS_T,
|
||||
SCH_LABEL_LOCATE_BUS_T } ) )
|
||||
{
|
||||
processItem( aSheetPath, aItem );
|
||||
}
|
||||
else if( m_schTextAndGraphics->GetValue() && aItem->IsType( { SCH_TEXT_T, SCH_TEXTBOX_T,
|
||||
SCH_ITEM_LOCATE_GRAPHIC_LINE_T,
|
||||
SCH_SHAPE_T } ) )
|
||||
|
||||
@@ -110,7 +110,11 @@ DIALOG_LABEL_PROPERTIES::DIALOG_LABEL_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH_L
|
||||
m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
|
||||
|
||||
m_grid->SetTable( m_fields );
|
||||
m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
|
||||
m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this,
|
||||
[&]( wxCommandEvent& aEvent )
|
||||
{
|
||||
OnAddField( aEvent );
|
||||
} ) );
|
||||
m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
|
||||
|
||||
// Show/hide columns according to user's preference
|
||||
@@ -603,7 +607,7 @@ void DIALOG_LABEL_PROPERTIES::OnAddField( wxCommandEvent& event )
|
||||
if( !m_grid->CommitPendingChanges() )
|
||||
return;
|
||||
|
||||
int fieldID = m_fields->size();
|
||||
int fieldID = (int) m_fields->size();
|
||||
wxString fieldName;
|
||||
|
||||
if( (int) fieldID == m_currentLabel->GetMandatoryFieldCount()
|
||||
@@ -637,8 +641,8 @@ void DIALOG_LABEL_PROPERTIES::OnAddField( wxCommandEvent& event )
|
||||
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
|
||||
m_grid->ProcessTableMessage( msg );
|
||||
|
||||
m_grid->MakeCellVisible( m_fields->size() - 1, 0 );
|
||||
m_grid->SetGridCursor( m_fields->size() - 1, fieldName == wxT( "Netclass" ) ? 1 : 0 );
|
||||
m_grid->MakeCellVisible( (int) m_fields->size() - 1, 0 );
|
||||
m_grid->SetGridCursor( (int) m_fields->size() - 1, 0 );
|
||||
|
||||
m_grid->EnableCellEditControl();
|
||||
m_grid->ShowCellEditControl();
|
||||
|
||||
@@ -119,7 +119,8 @@ bool DIALOG_LIB_SHAPE_PROPERTIES::TransferDataToWindow()
|
||||
wxFAIL_MSG( "Line type not found in the type lookup map" );
|
||||
|
||||
m_privateCheckbox->SetValue( m_shape->IsPrivate() );
|
||||
m_checkApplyToAllUnits->SetValue( m_shape->GetUnit() == 0 );
|
||||
m_checkApplyToAllUnits->SetValue(
|
||||
symbol && symbol->GetUnitCount() > 1 && m_shape->GetUnit() == 0 );
|
||||
m_checkApplyToAllUnits->Enable( symbol && symbol->GetUnitCount() > 1 );
|
||||
m_checkApplyToAllConversions->SetValue( m_shape->GetConvert() == 0 );
|
||||
|
||||
|
||||
@@ -65,7 +65,11 @@ DIALOG_LIB_SYMBOL_PROPERTIES::DIALOG_LIB_SYMBOL_PROPERTIES( SYMBOL_EDIT_FRAME* a
|
||||
m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
|
||||
m_fields = new FIELDS_GRID_TABLE<LIB_FIELD>( this, aParent, m_grid, m_libEntry );
|
||||
m_grid->SetTable( m_fields );
|
||||
m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
|
||||
m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this,
|
||||
[&]( wxCommandEvent& aEvent )
|
||||
{
|
||||
OnAddField( aEvent );
|
||||
} ) );
|
||||
m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
|
||||
|
||||
// Show/hide columns according to the user's preference
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2001 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
|
||||
* Copyright (C) 2004-2022 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2004-2023 KiCad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -122,8 +122,14 @@ DIALOG_LIB_TEXT_PROPERTIES::~DIALOG_LIB_TEXT_PROPERTIES()
|
||||
|
||||
bool DIALOG_LIB_TEXT_PROPERTIES::TransferDataToWindow()
|
||||
{
|
||||
LIB_SYMBOL* symbol = nullptr;
|
||||
|
||||
if( m_graphicText )
|
||||
{
|
||||
symbol = m_graphicText->GetParent();
|
||||
|
||||
wxCHECK( symbol, false );
|
||||
|
||||
m_textSize.SetValue( m_graphicText->GetTextWidth() );
|
||||
m_StyledTextCtrl->SetValue( m_graphicText->GetText() );
|
||||
m_StyledTextCtrl->EmptyUndoBuffer();
|
||||
@@ -135,7 +141,8 @@ bool DIALOG_LIB_TEXT_PROPERTIES::TransferDataToWindow()
|
||||
m_bold->Check( m_graphicText->IsBold() );
|
||||
|
||||
m_privateCheckbox->SetValue( m_graphicText->IsPrivate() );
|
||||
m_CommonUnit->SetValue( m_graphicText->GetUnit() == 0 );
|
||||
m_CommonUnit->SetValue(
|
||||
symbol && symbol->GetUnitCount() > 1 && m_graphicText->GetUnit() == 0 );
|
||||
m_CommonConvert->SetValue( m_graphicText->GetConvert() == 0 );
|
||||
|
||||
if( m_graphicText->GetTextAngle().IsHorizontal() )
|
||||
@@ -161,10 +168,12 @@ bool DIALOG_LIB_TEXT_PROPERTIES::TransferDataToWindow()
|
||||
{
|
||||
SYMBOL_EDITOR_SETTINGS* cfg = m_parent->GetSettings();
|
||||
auto* tools = m_parent->GetToolManager()->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
|
||||
symbol = m_parent->GetCurSymbol();
|
||||
|
||||
m_textSize.SetValue( schIUScale.MilsToIU( cfg->m_Defaults.text_size ) );
|
||||
|
||||
m_CommonUnit->SetValue( !tools->GetDrawSpecificUnit() );
|
||||
m_CommonUnit->SetValue(
|
||||
symbol && symbol->GetUnitCount() > 1 && !tools->GetDrawSpecificUnit() );
|
||||
m_CommonConvert->SetValue( !tools->GetDrawSpecificConvert() );
|
||||
|
||||
if( tools->GetLastTextAngle().IsHorizontal() )
|
||||
@@ -173,6 +182,8 @@ bool DIALOG_LIB_TEXT_PROPERTIES::TransferDataToWindow()
|
||||
m_vertical->Check();
|
||||
}
|
||||
|
||||
m_CommonUnit->Enable( symbol && symbol->GetUnitCount() > 1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +141,8 @@ bool DIALOG_LIB_TEXTBOX_PROPERTIES::TransferDataToWindow()
|
||||
if( !wxDialog::TransferDataToWindow() )
|
||||
return false;
|
||||
|
||||
LIB_SYMBOL* symbol = m_currentText->GetParent();
|
||||
|
||||
m_textCtrl->SetValue( m_currentText->GetText() );
|
||||
m_textCtrl->EmptyUndoBuffer();
|
||||
|
||||
@@ -204,7 +206,9 @@ bool DIALOG_LIB_TEXTBOX_PROPERTIES::TransferDataToWindow()
|
||||
m_fillColorSwatch->Enable( m_currentText->IsFilled() );
|
||||
|
||||
m_privateCheckbox->SetValue( m_currentText->IsPrivate() );
|
||||
m_CommonUnit->SetValue( m_currentText->GetUnit() == 0 );
|
||||
m_CommonUnit->SetValue(
|
||||
symbol && symbol->GetUnitCount() > 1 && m_currentText->GetUnit() == 0 );
|
||||
m_CommonUnit->Enable( symbol && symbol->GetUnitCount() > 1 );
|
||||
m_CommonConvert->SetValue( m_currentText->GetConvert() == 0 );
|
||||
|
||||
return true;
|
||||
|
||||
@@ -266,7 +266,7 @@ bool DIALOG_PIN_PROPERTIES::TransferDataToWindow()
|
||||
m_numberSize.SetValue( m_pin->GetNumberTextSize() );
|
||||
m_pinLength.SetValue( m_pin->GetLength() );
|
||||
m_checkApplyToAllParts->Enable( m_pin->GetParent()->IsMulti() );
|
||||
m_checkApplyToAllParts->SetValue( m_pin->GetUnit() == 0 );
|
||||
m_checkApplyToAllParts->SetValue( m_pin->GetParent()->IsMulti() && m_pin->GetUnit() == 0 );
|
||||
m_checkApplyToAllConversions->SetValue( m_pin->GetConvert() == 0 );
|
||||
m_checkShow->SetValue( m_pin->IsVisible() );
|
||||
|
||||
|
||||
@@ -338,7 +338,10 @@ COLOR_SETTINGS* DIALOG_PLOT_SCHEMATIC::getColorSettings()
|
||||
int selection = m_colorTheme->GetSelection();
|
||||
|
||||
if( selection < 0 )
|
||||
return m_parent->GetSettingsManager()->GetColorSettings( "_builtin_default" );
|
||||
{
|
||||
return m_parent->GetSettingsManager()->GetColorSettings(
|
||||
COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT );
|
||||
}
|
||||
|
||||
return static_cast<COLOR_SETTINGS*>( m_colorTheme->GetClientData( selection ) );
|
||||
}
|
||||
|
||||
@@ -61,7 +61,11 @@ DIALOG_SHEET_PROPERTIES::DIALOG_SHEET_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH_S
|
||||
m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
|
||||
|
||||
m_grid->SetTable( m_fields );
|
||||
m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
|
||||
m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this,
|
||||
[&]( wxCommandEvent& aEvent )
|
||||
{
|
||||
OnAddField( aEvent );
|
||||
} ) );
|
||||
m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
|
||||
|
||||
// Show/hide columns according to user's preference
|
||||
|
||||
@@ -74,26 +74,19 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symb
|
||||
return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
|
||||
} );
|
||||
|
||||
|
||||
m_typeChoice->Clear();
|
||||
|
||||
m_scintillaTricks = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
|
||||
|
||||
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this );
|
||||
|
||||
m_paramGrid->SetValidationFailureBehavior( wxPG_VFB_STAY_IN_PROPERTY
|
||||
| wxPG_VFB_BEEP
|
||||
| wxPG_VFB_MARK_CELL );
|
||||
|
||||
wxPropertyGrid* grid = m_paramGrid->GetGrid();
|
||||
|
||||
//grid->SetCellBackgroundColour( grid->GetPropertyDefaultCell().GetBgCol() );
|
||||
//grid->SetCellTextColour( grid->GetPropertyDefaultCell().GetFgCol();
|
||||
|
||||
// In wx 3.0 the color will be wrong sometimes.
|
||||
grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
|
||||
|
||||
grid->Bind( wxEVT_SET_FOCUS, &DIALOG_SIM_MODEL::onParamGridSetFocus, this );
|
||||
grid->Bind( wxEVT_UPDATE_UI, &DIALOG_SIM_MODEL::onUpdateUI, this );
|
||||
|
||||
grid->AddActionTrigger( wxPG_ACTION_EDIT, WXK_RETURN );
|
||||
grid->DedicateKey( WXK_RETURN );
|
||||
@@ -169,6 +162,14 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
|
||||
m_fields[ VALUE_FIELD ].SetText( wxT( "${SIM.PARAMS}" ) );
|
||||
}
|
||||
|
||||
std::vector<LIB_PIN*> sourcePins = m_symbol.GetAllLibPins();
|
||||
|
||||
std::sort( sourcePins.begin(), sourcePins.end(),
|
||||
[]( const LIB_PIN* lhs, const LIB_PIN* rhs )
|
||||
{
|
||||
return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
|
||||
} );
|
||||
|
||||
std::string libraryFilename = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::LIBRARY_FIELD );
|
||||
|
||||
if( libraryFilename != "" )
|
||||
@@ -179,8 +180,11 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
|
||||
if( !loadLibrary( libraryFilename ) )
|
||||
{
|
||||
m_libraryPathText->ChangeValue( libraryFilename );
|
||||
m_modelNameChoice->SetSelection( -1 );
|
||||
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
|
||||
m_libraryModelsMgr.CreateModel( nullptr, sourcePins, m_fields );
|
||||
|
||||
m_modelNameChoice->Append( _( "<unknown>" ) );
|
||||
m_modelNameChoice->SetSelection( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -255,14 +259,6 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
|
||||
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
|
||||
}
|
||||
|
||||
std::vector<LIB_PIN*> sourcePins = m_symbol.GetAllLibPins();
|
||||
|
||||
std::sort( sourcePins.begin(), sourcePins.end(),
|
||||
[]( const LIB_PIN* lhs, const LIB_PIN* rhs )
|
||||
{
|
||||
return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
|
||||
} );
|
||||
|
||||
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
|
||||
{
|
||||
wxString msg;
|
||||
@@ -302,33 +298,28 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataFromWindow()
|
||||
{
|
||||
m_pinAssignmentsGrid->CommitPendingChanges();
|
||||
|
||||
// This should have been done in wxPGTextCtrlEditor::OnTextCtrlEvent(), but something must
|
||||
// be clearing it before we get here, resulting in CommitChangesFromEditor() doing nothing
|
||||
m_paramGrid->GetGrid()->EditorsValueWasModified();
|
||||
m_paramGrid->GetGrid()->CommitChangesFromEditor();
|
||||
|
||||
if( !DIALOG_SIM_MODEL_BASE::TransferDataFromWindow() )
|
||||
return false;
|
||||
|
||||
if( !m_modelNameChoice->IsEmpty() )
|
||||
{
|
||||
std::string modelName = m_modelNameChoice->GetStringSelection().ToStdString();
|
||||
|
||||
SIM_MODEL::SetFieldValue( m_fields, SIM_LIBRARY::NAME_FIELD, modelName );
|
||||
}
|
||||
|
||||
std::string path;
|
||||
std::string name;
|
||||
|
||||
if( m_useLibraryModelRadioButton->GetValue() || isIbisLoaded() )
|
||||
if( m_useLibraryModelRadioButton->GetValue() )
|
||||
{
|
||||
path = m_libraryPathText->GetValue();
|
||||
wxFileName fn( path );
|
||||
|
||||
if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
|
||||
path = fn.GetFullPath();
|
||||
|
||||
if( !m_modelNameChoice->IsEmpty() )
|
||||
name = m_modelNameChoice->GetStringSelection().ToStdString();
|
||||
else if( dynamic_cast<SIM_MODEL_SPICE_FALLBACK*>( &curModel() ) )
|
||||
name = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD, false );
|
||||
}
|
||||
|
||||
SIM_MODEL::SetFieldValue( m_fields, SIM_LIBRARY::LIBRARY_FIELD, path );
|
||||
SIM_MODEL::SetFieldValue( m_fields, SIM_LIBRARY::NAME_FIELD, name );
|
||||
|
||||
if( isIbisLoaded() )
|
||||
{
|
||||
@@ -337,17 +328,19 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataFromWindow()
|
||||
|
||||
if( ibismodel )
|
||||
{
|
||||
SIM_MODEL::SetFieldValue(
|
||||
m_fields, SIM_LIBRARY_KIBIS::PIN_FIELD,
|
||||
ibismodel->GetIbisPins().at( m_ibisPinCombobox->GetSelection() ).first );
|
||||
std::string pins;
|
||||
std::string modelName = std::string( m_ibisModelCombobox->GetValue().c_str() );
|
||||
std::string differential;
|
||||
|
||||
SIM_MODEL::SetFieldValue(
|
||||
m_fields, SIM_LIBRARY_KIBIS::MODEL_FIELD,
|
||||
std::string( m_ibisModelCombobox->GetValue().c_str() ) );
|
||||
if( m_ibisPinCombobox->GetSelection() >= 0 )
|
||||
pins = ibismodel->GetIbisPins().at( m_ibisPinCombobox->GetSelection() ).first;
|
||||
|
||||
SIM_MODEL::SetFieldValue(
|
||||
m_fields, SIM_LIBRARY_KIBIS::DIFF_FIELD,
|
||||
ibismodel->CanDifferential() && m_differentialCheckbox->GetValue() ? "1" : "" );
|
||||
if( ibismodel->CanDifferential() && m_differentialCheckbox->GetValue() )
|
||||
differential = "1";
|
||||
|
||||
SIM_MODEL::SetFieldValue( m_fields, SIM_LIBRARY_KIBIS::PIN_FIELD, pins );
|
||||
SIM_MODEL::SetFieldValue( m_fields, SIM_LIBRARY_KIBIS::MODEL_FIELD, modelName );
|
||||
SIM_MODEL::SetFieldValue( m_fields, SIM_LIBRARY_KIBIS::DIFF_FIELD, differential );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,11 +361,13 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataFromWindow()
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateWidgets()
|
||||
{
|
||||
updateIbisWidgets();
|
||||
updateInstanceWidgets();
|
||||
updateModelParamsTab();
|
||||
updateModelCodeTab();
|
||||
updatePinAssignments();
|
||||
SIM_MODEL* model = &curModel();
|
||||
|
||||
updateIbisWidgets( model );
|
||||
updateInstanceWidgets( model );
|
||||
updateModelParamsTab( model );
|
||||
updateModelCodeTab( model );
|
||||
updatePinAssignments( model );
|
||||
|
||||
std::string ref = SIM_MODEL::GetFieldValue( &m_fields, SIM_REFERENCE_FIELD );
|
||||
|
||||
@@ -388,9 +383,9 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateWidgets()
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateIbisWidgets()
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateIbisWidgets( SIM_MODEL* aModel )
|
||||
{
|
||||
SIM_MODEL_KIBIS* modelkibis = isIbisLoaded() ? dynamic_cast<SIM_MODEL_KIBIS*>( &curModel() )
|
||||
SIM_MODEL_KIBIS* modelkibis = isIbisLoaded() ? dynamic_cast<SIM_MODEL_KIBIS*>( aModel )
|
||||
: nullptr;
|
||||
|
||||
m_ibisModelCombobox->Show( isIbisLoaded() );
|
||||
@@ -404,16 +399,16 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateIbisWidgets()
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateInstanceWidgets()
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateInstanceWidgets( SIM_MODEL* aModel )
|
||||
{
|
||||
// Change the Type choice to match the current device type.
|
||||
if( &curModel() != m_prevModel )
|
||||
if( aModel != m_prevModel )
|
||||
{
|
||||
m_deviceTypeChoice->Clear();
|
||||
|
||||
if( m_useLibraryModelRadioButton->GetValue() )
|
||||
{
|
||||
m_deviceTypeChoice->Append( curModel().GetDeviceInfo().description );
|
||||
m_deviceTypeChoice->Append( aModel->GetDeviceInfo().description );
|
||||
m_deviceTypeChoice->SetSelection( 0 );
|
||||
}
|
||||
else
|
||||
@@ -425,7 +420,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateInstanceWidgets()
|
||||
|
||||
m_deviceTypeChoice->Append( SIM_MODEL::DeviceInfo( deviceType ).description );
|
||||
|
||||
if( deviceType == curModel().GetDeviceType() )
|
||||
if( deviceType == aModel->GetDeviceType() )
|
||||
m_deviceTypeChoice->SetSelection( m_deviceTypeChoice->GetCount() - 1 );
|
||||
}
|
||||
}
|
||||
@@ -434,11 +429,11 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateInstanceWidgets()
|
||||
|
||||
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
|
||||
{
|
||||
if( SIM_MODEL::TypeInfo( type ).deviceType == curModel().GetDeviceType() )
|
||||
if( SIM_MODEL::TypeInfo( type ).deviceType == aModel->GetDeviceType() )
|
||||
{
|
||||
m_typeChoice->Append( SIM_MODEL::TypeInfo( type ).description );
|
||||
|
||||
if( type == curModel().GetType() )
|
||||
if( type == aModel->GetType() )
|
||||
m_typeChoice->SetSelection( m_typeChoice->GetCount() - 1 );
|
||||
}
|
||||
}
|
||||
@@ -446,19 +441,14 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateInstanceWidgets()
|
||||
|
||||
m_typeChoice->Enable( !m_useLibraryModelRadioButton->GetValue() || isIbisLoaded() );
|
||||
|
||||
if( dynamic_cast<SIM_MODEL_RAW_SPICE*>( &curModel() )
|
||||
|| dynamic_cast<SIM_MODEL_SPICE_FALLBACK*>( &curModel() ) )
|
||||
{
|
||||
if( dynamic_cast<SIM_MODEL_RAW_SPICE*>( aModel ) )
|
||||
m_modelNotebook->SetSelection( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_modelNotebook->SetSelection( 0 );
|
||||
}
|
||||
|
||||
if( curModel().HasPrimaryValue() )
|
||||
if( aModel->HasPrimaryValue() )
|
||||
{
|
||||
const SIM_MODEL::PARAM& primary = curModel().GetParam( 0 );
|
||||
const SIM_MODEL::PARAM& primary = aModel->GetParam( 0 );
|
||||
|
||||
m_saveInValueCheckbox->SetLabel( wxString::Format( _( "Save parameter '%s (%s)' in Value "
|
||||
"field" ),
|
||||
@@ -476,9 +466,9 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateInstanceWidgets()
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelParamsTab()
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelParamsTab( SIM_MODEL* aModel )
|
||||
{
|
||||
if( &curModel() != m_prevModel )
|
||||
if( aModel != m_prevModel )
|
||||
{
|
||||
// This wxPropertyGridManager column and header stuff has to be here because it segfaults in
|
||||
// the constructor.
|
||||
@@ -530,8 +520,8 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelParamsTab()
|
||||
|
||||
m_paramGrid->CollapseAll();
|
||||
|
||||
for( int i = 0; i < curModel().GetParamCount(); ++i )
|
||||
addParamPropertyIfRelevant( i );
|
||||
for( int i = 0; i < aModel->GetParamCount(); ++i )
|
||||
addParamPropertyIfRelevant( aModel, i );
|
||||
|
||||
m_paramGrid->CollapseAll();
|
||||
m_paramGrid->Expand( "AC" );
|
||||
@@ -563,15 +553,18 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelParamsTab()
|
||||
// Model values other than the currently edited value may have changed. Update them.
|
||||
// This feature is called "autofill" and present only in certain models. Don't do it for
|
||||
// models that don't have it for performance reasons.
|
||||
if( curModel().HasAutofill() )
|
||||
( *it )->SetValueFromString( param.value->ToString() );
|
||||
if( aModel->HasAutofill() )
|
||||
( *it )->SetValueFromString( param.value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelCodeTab()
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelCodeTab( SIM_MODEL* aModel )
|
||||
{
|
||||
if( dynamic_cast<SIM_MODEL_SPICE_FALLBACK*>( aModel ) )
|
||||
return;
|
||||
|
||||
wxString text;
|
||||
SPICE_ITEM item;
|
||||
|
||||
@@ -580,7 +573,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelCodeTab()
|
||||
if( m_useInstanceModelRadioButton->GetValue() || item.modelName == "" )
|
||||
item.modelName = m_fields.at( REFERENCE_FIELD ).GetText();
|
||||
|
||||
text << curModel().SpiceGenerator().Preview( item );
|
||||
text << aModel->SpiceGenerator().Preview( item );
|
||||
|
||||
m_codePreview->SetText( text );
|
||||
m_codePreview->SelectNone();
|
||||
@@ -588,9 +581,9 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelCodeTab()
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments()
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments( SIM_MODEL* aModel )
|
||||
{
|
||||
removeOrphanedPinAssignments();
|
||||
removeOrphanedPinAssignments( aModel );
|
||||
|
||||
// Reset the grid.
|
||||
|
||||
@@ -601,9 +594,9 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments()
|
||||
m_pinAssignmentsGrid->SetCellValue( row, PIN_COLUMN::MODEL, _( "Not Connected" ) );
|
||||
|
||||
// Now set up the grid values in the Model column.
|
||||
for( int modelPinIndex = 0; modelPinIndex < curModel().GetPinCount(); ++modelPinIndex )
|
||||
for( int modelPinIndex = 0; modelPinIndex < aModel->GetPinCount(); ++modelPinIndex )
|
||||
{
|
||||
wxString symbolPinNumber = curModel().GetPin( modelPinIndex ).symbolPinNumber;
|
||||
wxString symbolPinNumber = aModel->GetPin( modelPinIndex ).symbolPinNumber;
|
||||
|
||||
if( symbolPinNumber == "" )
|
||||
continue;
|
||||
@@ -613,7 +606,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments()
|
||||
if( symbolPinRow == -1 )
|
||||
continue;
|
||||
|
||||
wxString modelPinString = getModelPinString( modelPinIndex );
|
||||
wxString modelPinString = getModelPinString( aModel, modelPinIndex );
|
||||
m_pinAssignmentsGrid->SetCellValue( symbolPinRow, PIN_COLUMN::MODEL, modelPinString );
|
||||
}
|
||||
|
||||
@@ -630,14 +623,14 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments()
|
||||
std::vector<BITMAPS> modelPinIcons;
|
||||
wxArrayString modelPinChoices;
|
||||
|
||||
for( int jj = 0; jj < curModel().GetPinCount(); ++jj )
|
||||
for( int jj = 0; jj < aModel->GetPinCount(); ++jj )
|
||||
{
|
||||
if( curModel().GetPin( jj ).symbolPinNumber != "" )
|
||||
if( aModel->GetPin( jj ).symbolPinNumber != "" )
|
||||
modelPinIcons.push_back( PinShapeGetBitmap( GRAPHIC_PINSHAPE::LINE ) );
|
||||
else
|
||||
modelPinIcons.push_back( BITMAPS::INVALID_BITMAP );
|
||||
|
||||
modelPinChoices.Add( getModelPinString( jj ) );
|
||||
modelPinChoices.Add( getModelPinString( aModel, jj ) );
|
||||
}
|
||||
|
||||
modelPinIcons.push_back( BITMAPS::INVALID_BITMAP );
|
||||
@@ -652,11 +645,9 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments()
|
||||
|
||||
// TODO: Show a preview of the symbol with the pin numbers shown.
|
||||
|
||||
SIM_MODEL* model = &curModel();
|
||||
|
||||
if( model->GetType() == SIM_MODEL::TYPE::SUBCKT )
|
||||
if( aModel->GetType() == SIM_MODEL::TYPE::SUBCKT )
|
||||
{
|
||||
SIM_MODEL_SUBCKT* subckt = static_cast<SIM_MODEL_SUBCKT*>( model );
|
||||
SIM_MODEL_SUBCKT* subckt = static_cast<SIM_MODEL_SUBCKT*>( aModel );
|
||||
m_subckt->SetText( subckt->GetSpiceCode() );
|
||||
}
|
||||
else
|
||||
@@ -668,12 +659,12 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments()
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::removeOrphanedPinAssignments()
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::removeOrphanedPinAssignments( SIM_MODEL* aModel )
|
||||
{
|
||||
for( int i = 0; i < curModel().GetPinCount(); ++i )
|
||||
for( int i = 0; i < aModel->GetPinCount(); ++i )
|
||||
{
|
||||
if( !m_symbol.GetPin( curModel().GetPin( i ).symbolPinNumber ) )
|
||||
curModel().SetPinSymbolPinNumber( i, "" );
|
||||
if( !m_symbol.GetPin( aModel->GetPin( i ).symbolPinNumber ) )
|
||||
aModel->SetPinSymbolPinNumber( i, "" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,6 +673,9 @@ template <typename T_symbol, typename T_field>
|
||||
bool DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryPath,
|
||||
bool aForceReload )
|
||||
{
|
||||
if( m_prevLibrary == aLibraryPath && !aForceReload )
|
||||
return true;
|
||||
|
||||
wxString msg;
|
||||
WX_STRING_REPORTER reporter( &msg );
|
||||
|
||||
@@ -735,75 +729,77 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryP
|
||||
m_ibisPinCombobox->SetSelection( -1 );
|
||||
}
|
||||
|
||||
m_prevLibrary = aLibraryPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::addParamPropertyIfRelevant( int aParamIndex )
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::addParamPropertyIfRelevant( SIM_MODEL* aModel,
|
||||
int aParamIndex )
|
||||
{
|
||||
if( curModel().GetParam( aParamIndex ).info.dir == SIM_MODEL::PARAM::DIR_OUT )
|
||||
if( aModel->GetParam( aParamIndex ).info.dir == SIM_MODEL::PARAM::DIR_OUT )
|
||||
return;
|
||||
|
||||
switch( curModel().GetParam( aParamIndex ).info.category )
|
||||
switch( aModel->GetParam( aParamIndex ).info.category )
|
||||
{
|
||||
case CATEGORY::AC:
|
||||
m_paramGrid->HideProperty( "AC", false );
|
||||
m_paramGrid->AppendIn( "AC", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "AC", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::DC:
|
||||
m_paramGrid->HideProperty( "DC", false );
|
||||
m_paramGrid->AppendIn( "DC", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "DC", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::CAPACITANCE:
|
||||
m_paramGrid->HideProperty( "Capacitance", false );
|
||||
m_paramGrid->AppendIn( "Capacitance", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Capacitance", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::TEMPERATURE:
|
||||
m_paramGrid->HideProperty( "Temperature", false );
|
||||
m_paramGrid->AppendIn( "Temperature", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Temperature", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::NOISE:
|
||||
m_paramGrid->HideProperty( "Noise", false );
|
||||
m_paramGrid->AppendIn( "Noise", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Noise", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::DISTRIBUTED_QUANTITIES:
|
||||
m_paramGrid->HideProperty( "Distributed Quantities", false );
|
||||
m_paramGrid->AppendIn( "Distributed Quantities", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Distributed Quantities", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::WAVEFORM:
|
||||
m_paramGrid->HideProperty( "Waveform", false );
|
||||
m_paramGrid->AppendIn( "Waveform", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Waveform", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::GEOMETRY:
|
||||
m_paramGrid->HideProperty( "Geometry", false );
|
||||
m_paramGrid->AppendIn( "Geometry", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Geometry", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::LIMITING_VALUES:
|
||||
m_paramGrid->HideProperty( "Limiting Values", false );
|
||||
m_paramGrid->AppendIn( "Limiting Values", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Limiting Values", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::ADVANCED:
|
||||
m_paramGrid->HideProperty( "Advanced", false );
|
||||
m_paramGrid->AppendIn( "Advanced", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Advanced", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::FLAGS:
|
||||
m_paramGrid->HideProperty( "Flags", false );
|
||||
m_paramGrid->AppendIn( "Flags", newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->AppendIn( "Flags", newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
m_paramGrid->Insert( m_firstCategory, newParamProperty( aParamIndex ) );
|
||||
m_paramGrid->Insert( m_firstCategory, newParamProperty( aModel, aParamIndex ) );
|
||||
break;
|
||||
|
||||
case CATEGORY::INITIAL_CONDITIONS:
|
||||
@@ -814,9 +810,10 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::addParamPropertyIfRelevant( int aParam
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
wxPGProperty* DIALOG_SIM_MODEL<T_symbol, T_field>::newParamProperty( int aParamIndex ) const
|
||||
wxPGProperty* DIALOG_SIM_MODEL<T_symbol, T_field>::newParamProperty( SIM_MODEL* aModel ,
|
||||
int aParamIndex ) const
|
||||
{
|
||||
const SIM_MODEL::PARAM& param = curModel().GetParam( aParamIndex );
|
||||
const SIM_MODEL::PARAM& param = aModel->GetParam( aParamIndex );
|
||||
wxString paramDescription;
|
||||
|
||||
if( param.info.description == "" )
|
||||
@@ -830,18 +827,18 @@ wxPGProperty* DIALOG_SIM_MODEL<T_symbol, T_field>::newParamProperty( int aParamI
|
||||
{
|
||||
case SIM_VALUE::TYPE_BOOL:
|
||||
// TODO.
|
||||
prop = new SIM_BOOL_PROPERTY( paramDescription, param.info.name, curModel(), aParamIndex );
|
||||
prop = new SIM_BOOL_PROPERTY( paramDescription, param.info.name, *aModel, aParamIndex );
|
||||
prop->SetAttribute( wxPG_BOOL_USE_CHECKBOX, true );
|
||||
break;
|
||||
|
||||
case SIM_VALUE::TYPE_INT:
|
||||
prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, curModel(),
|
||||
aParamIndex, SIM_VALUE::TYPE_INT );
|
||||
prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, *aModel, aParamIndex,
|
||||
SIM_VALUE::TYPE_INT );
|
||||
break;
|
||||
|
||||
case SIM_VALUE::TYPE_FLOAT:
|
||||
prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, curModel(),
|
||||
aParamIndex, SIM_VALUE::TYPE_FLOAT );
|
||||
prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, *aModel, aParamIndex,
|
||||
SIM_VALUE::TYPE_FLOAT );
|
||||
break;
|
||||
|
||||
//case TYPE_COMPLEX:
|
||||
@@ -850,13 +847,12 @@ wxPGProperty* DIALOG_SIM_MODEL<T_symbol, T_field>::newParamProperty( int aParamI
|
||||
case SIM_VALUE::TYPE_STRING:
|
||||
if( param.info.enumValues.empty() )
|
||||
{
|
||||
prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, curModel(),
|
||||
prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, *aModel,
|
||||
aParamIndex, SIM_VALUE::TYPE_STRING );
|
||||
}
|
||||
else
|
||||
{
|
||||
prop = new SIM_ENUM_PROPERTY( paramDescription, param.info.name, curModel(),
|
||||
aParamIndex );
|
||||
prop = new SIM_ENUM_PROPERTY( paramDescription, param.info.name, *aModel, aParamIndex );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -869,15 +865,9 @@ wxPGProperty* DIALOG_SIM_MODEL<T_symbol, T_field>::newParamProperty( int aParamI
|
||||
|
||||
// Legacy due to the way we extracted the parameters from Ngspice.
|
||||
#if wxCHECK_VERSION( 3, 1, 0 )
|
||||
if( param.isOtherVariant )
|
||||
prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValueOfOtherVariant ) );
|
||||
else
|
||||
prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValue ) );
|
||||
prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValue ) );
|
||||
#else
|
||||
if( param.isOtherVariant )
|
||||
prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValueOfOtherVariant.c_str() ) );
|
||||
else
|
||||
prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValue.c_str() ) );
|
||||
prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValue.c_str() ) );
|
||||
#endif
|
||||
|
||||
wxString typeStr;
|
||||
@@ -967,9 +957,10 @@ wxString DIALOG_SIM_MODEL<T_symbol, T_field>::getSymbolPinString( int symbolPinI
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
wxString DIALOG_SIM_MODEL<T_symbol, T_field>::getModelPinString( int aModelPinIndex ) const
|
||||
wxString DIALOG_SIM_MODEL<T_symbol, T_field>::getModelPinString( SIM_MODEL* aModel,
|
||||
int aModelPinIndex ) const
|
||||
{
|
||||
const wxString& pinName = curModel().GetPin( aModelPinIndex ).name;
|
||||
const wxString& pinName = aModel->GetPin( aModelPinIndex ).name;
|
||||
|
||||
LOCALE_IO toggle;
|
||||
|
||||
@@ -1219,10 +1210,18 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::onTypeChoice( wxCommandEvent& aEvent )
|
||||
{
|
||||
int idx = m_modelNameChoice->GetSelection();
|
||||
|
||||
auto& kibisModel = static_cast<SIM_MODEL_KIBIS&>( m_libraryModelsMgr.GetModels().at( idx ).get() );
|
||||
auto& baseModel = static_cast<SIM_MODEL_KIBIS&>( m_libraryModelsMgr.GetModels().at( idx ).get() );
|
||||
|
||||
m_libraryModelsMgr.SetModel( idx, std::make_unique<SIM_MODEL_KIBIS>( type, kibisModel,
|
||||
m_fields, sourcePins ) );
|
||||
m_libraryModelsMgr.SetModel( idx, std::make_unique<SIM_MODEL_KIBIS>( type, baseModel ) );
|
||||
|
||||
try
|
||||
{
|
||||
m_libraryModelsMgr.GetModels().at( idx ).get().ReadDataFields( &m_fields, sourcePins );
|
||||
}
|
||||
catch( IO_ERROR& err )
|
||||
{
|
||||
DisplayErrorMessage( this, err.What() );
|
||||
}
|
||||
}
|
||||
|
||||
m_curModelType = type;
|
||||
@@ -1238,12 +1237,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::onTypeChoice( wxCommandEvent& aEvent )
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::onPageChanging( wxBookCtrlEvent& event )
|
||||
{
|
||||
// This should have been done in wxPGTextCtrlEditor::OnTextCtrlEvent(), but something must
|
||||
// be clearing it before we get here, resulting in CommitChangesFromEditor() doing nothing
|
||||
m_paramGrid->GetGrid()->EditorsValueWasModified();
|
||||
m_paramGrid->GetGrid()->CommitChangesFromEditor();
|
||||
|
||||
updateModelCodeTab();
|
||||
updateModelCodeTab( &curModel() );
|
||||
}
|
||||
|
||||
|
||||
@@ -1266,7 +1260,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::onPinAssignmentsGridCellChange( wxGrid
|
||||
std::string( m_sortedPartPins.at( symbolPinIndex )->GetShownNumber().ToUTF8() ) );
|
||||
}
|
||||
|
||||
updatePinAssignments();
|
||||
updatePinAssignments( &curModel() );
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
@@ -1292,10 +1286,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::onParamGridSetFocus( wxFocusEvent& aEv
|
||||
// Tab key is pressed. This is inconvenient, so we fix that here.
|
||||
|
||||
wxPropertyGrid* grid = m_paramGrid->GetGrid();
|
||||
|
||||
grid->CommitChangesFromEditor();
|
||||
|
||||
wxPGProperty* selected = grid->GetSelection();
|
||||
wxPGProperty* selected = grid->GetSelection();
|
||||
|
||||
if( !selected )
|
||||
selected = grid->wxPropertyGridInterface::GetFirst();
|
||||
@@ -1312,8 +1303,6 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::onParamGridSelectionChange( wxProperty
|
||||
{
|
||||
wxPropertyGrid* grid = m_paramGrid->GetGrid();
|
||||
|
||||
grid->CommitChangesFromEditor();
|
||||
|
||||
// Jump over categories.
|
||||
if( grid->GetSelection() && grid->GetSelection()->IsCategory() )
|
||||
{
|
||||
@@ -1359,6 +1348,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::onParamGridSelectionChange( wxProperty
|
||||
}
|
||||
|
||||
wxWindow* editorControl = grid->GetEditorControl();
|
||||
|
||||
if( !editorControl )
|
||||
{
|
||||
m_prevParamGridSelection = grid->GetSelection();
|
||||
@@ -1371,6 +1361,32 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::onParamGridSelectionChange( wxProperty
|
||||
}
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::onUpdateUI( wxUpdateUIEvent& aEvent )
|
||||
{
|
||||
// This is currently patched in wxPropertyGrid::ScrollWindow() in the Mac wxWidgets fork.
|
||||
// However, we may need this version if it turns out to be an issue on other platforms and
|
||||
// we can't get it upstreamed.
|
||||
#if 0
|
||||
// It's a shame to do this on the UpdateUI event, but neither the wxPropertyGridManager,
|
||||
// wxPropertyGridPage, wxPropertyGrid, nor the wxPropertyGrid's GetCanvas() window appear
|
||||
// to get scroll events.
|
||||
|
||||
wxPropertyGrid* grid = m_paramGrid->GetGrid();
|
||||
wxTextCtrl* ctrl = grid->GetEditorTextCtrl();
|
||||
|
||||
if( ctrl )
|
||||
{
|
||||
wxRect ctrlRect = ctrl->GetScreenRect();
|
||||
wxRect gridRect = grid->GetScreenRect();
|
||||
|
||||
if( ctrlRect.GetTop() < gridRect.GetTop() || ctrlRect.GetBottom() > gridRect.GetBottom() )
|
||||
grid->ClearSelection();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
void DIALOG_SIM_MODEL<T_symbol, T_field>::adjustParamGridColumns( int aWidth, bool aForce )
|
||||
{
|
||||
|
||||
@@ -70,18 +70,18 @@ private:
|
||||
bool TransferDataFromWindow() override;
|
||||
|
||||
void updateWidgets();
|
||||
void updateIbisWidgets();
|
||||
void updateInstanceWidgets();
|
||||
void updateModelParamsTab();
|
||||
void updateModelCodeTab();
|
||||
void updatePinAssignments();
|
||||
void updateIbisWidgets( SIM_MODEL* aModel );
|
||||
void updateInstanceWidgets( SIM_MODEL* aModel );
|
||||
void updateModelParamsTab( SIM_MODEL* aModel );
|
||||
void updateModelCodeTab( SIM_MODEL* aModel );
|
||||
void updatePinAssignments( SIM_MODEL* aModel );
|
||||
|
||||
void removeOrphanedPinAssignments();
|
||||
void removeOrphanedPinAssignments( SIM_MODEL* aModel );
|
||||
|
||||
bool loadLibrary( const wxString& aLibraryPath, bool aForceReload = false );
|
||||
|
||||
void addParamPropertyIfRelevant( int aParamIndex );
|
||||
wxPGProperty* newParamProperty( int aParamIndex ) const;
|
||||
void addParamPropertyIfRelevant( SIM_MODEL* aModel, int aParamIndex );
|
||||
wxPGProperty* newParamProperty( SIM_MODEL* aModel, int aParamIndex ) const;
|
||||
|
||||
int findSymbolPinRow( const wxString& aSymbolPinNumber ) const;
|
||||
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
const SIM_LIBRARY* library() const;
|
||||
|
||||
wxString getSymbolPinString( int aSymbolPinNumber ) const;
|
||||
wxString getModelPinString( int aModelPinIndex ) const;
|
||||
wxString getModelPinString( SIM_MODEL* aModel, int aModelPinIndex ) const;
|
||||
int getModelPinIndex( const wxString& aModelPinString ) const;
|
||||
|
||||
void onRadioButton( wxCommandEvent& aEvent ) override;
|
||||
@@ -111,6 +111,7 @@ private:
|
||||
|
||||
void onParamGridSetFocus( wxFocusEvent& aEvent );
|
||||
void onParamGridSelectionChange( wxPropertyGridEvent& aEvent );
|
||||
void onUpdateUI( wxUpdateUIEvent& aEvent );
|
||||
|
||||
void adjustParamGridColumns( int aWidth, bool aForce );
|
||||
|
||||
@@ -122,6 +123,7 @@ private:
|
||||
|
||||
SIM_LIB_MGR m_libraryModelsMgr;
|
||||
SIM_LIB_MGR m_builtinModelsMgr;
|
||||
wxString m_prevLibrary;
|
||||
const SIM_MODEL* m_prevModel;
|
||||
|
||||
std::vector<LIB_PIN*> m_sortedPartPins; //< Pins of the current part.
|
||||
|
||||
@@ -72,7 +72,7 @@ DIALOG_SIM_MODEL_BASE::DIALOG_SIM_MODEL_BASE( wxWindow* parent, wxWindowID id, c
|
||||
m_ibisPinCombobox = new wxComboBox( m_modelPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxTE_PROCESS_ENTER );
|
||||
m_ibisPinCombobox->Hide();
|
||||
|
||||
gbSizer1->Add( m_ibisPinCombobox, wxGBPosition( 2, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 );
|
||||
gbSizer1->Add( m_ibisPinCombobox, wxGBPosition( 2, 1 ), wxGBSpan( 1, 1 ), wxEXPAND|wxTOP|wxBOTTOM, 2 );
|
||||
|
||||
m_differentialCheckbox = new wxCheckBox( m_modelPanel, wxID_ANY, _("Differential"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_differentialCheckbox->Hide();
|
||||
@@ -88,7 +88,7 @@ DIALOG_SIM_MODEL_BASE::DIALOG_SIM_MODEL_BASE( wxWindow* parent, wxWindowID id, c
|
||||
m_ibisModelCombobox = new wxComboBox( m_modelPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxTE_PROCESS_ENTER );
|
||||
m_ibisModelCombobox->Hide();
|
||||
|
||||
gbSizer1->Add( m_ibisModelCombobox, wxGBPosition( 3, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 );
|
||||
gbSizer1->Add( m_ibisModelCombobox, wxGBPosition( 3, 1 ), wxGBSpan( 1, 1 ), wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM, 1 );
|
||||
|
||||
|
||||
gbSizer1->AddGrowableCol( 1 );
|
||||
|
||||
@@ -699,10 +699,10 @@
|
||||
</object>
|
||||
</object>
|
||||
<object class="gbsizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="border">2</property>
|
||||
<property name="colspan">1</property>
|
||||
<property name="column">1</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
|
||||
<property name="row">2</property>
|
||||
<property name="rowspan">1</property>
|
||||
<object class="wxComboBox" expanded="1">
|
||||
@@ -905,10 +905,10 @@
|
||||
</object>
|
||||
</object>
|
||||
<object class="gbsizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="border">1</property>
|
||||
<property name="colspan">1</property>
|
||||
<property name="column">1</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="flag">wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM</property>
|
||||
<property name="row">3</property>
|
||||
<property name="rowspan">1</property>
|
||||
<object class="wxComboBox" expanded="1">
|
||||
|
||||
@@ -880,9 +880,9 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent )
|
||||
int maxWidth = defaultDlgSize.x / 3;
|
||||
|
||||
if( col == m_grid->GetNumberCols() - 1 )
|
||||
m_grid->SetColSize( col, std::min( std::max( 50, textWidth ), maxWidth ) );
|
||||
m_grid->SetColSize( col, Clamp( 50, textWidth, maxWidth ) );
|
||||
else
|
||||
m_grid->SetColSize( col, std::min( std::max( 100, textWidth ), maxWidth ) );
|
||||
m_grid->SetColSize( col, Clamp( 100, textWidth, maxWidth ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,11 @@ DIALOG_SYMBOL_PROPERTIES::DIALOG_SYMBOL_PROPERTIES( SCH_EDIT_FRAME* aParent,
|
||||
m_pinGrid->SetDefaultRowSize( m_pinGrid->GetDefaultRowSize() + 4 );
|
||||
|
||||
m_fieldsGrid->SetTable( m_fields );
|
||||
m_fieldsGrid->PushEventHandler( new FIELDS_GRID_TRICKS( m_fieldsGrid, this ) );
|
||||
m_fieldsGrid->PushEventHandler( new FIELDS_GRID_TRICKS( m_fieldsGrid, this,
|
||||
[&]( wxCommandEvent& aEvent )
|
||||
{
|
||||
OnAddField( aEvent );
|
||||
} ) );
|
||||
m_fieldsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
|
||||
|
||||
// Show/hide columns according to user's preference
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
@@ -29,10 +29,10 @@ DIALOG_TEXT_PROPERTIES_BASE::DIALOG_TEXT_PROPERTIES_BASE( wxWindow* parent, wxWi
|
||||
|
||||
bMainSizer->Add( m_infoBar, 0, wxEXPAND|wxBOTTOM, 5 );
|
||||
|
||||
m_textEntrySizer = new wxGridBagSizer( 3, 3 );
|
||||
m_textEntrySizer = new wxGridBagSizer( 2, 3 );
|
||||
m_textEntrySizer->SetFlexibleDirection( wxBOTH );
|
||||
m_textEntrySizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
m_textEntrySizer->SetEmptyCellSize( wxSize( 0,0 ) );
|
||||
m_textEntrySizer->SetEmptyCellSize( wxSize( 0,10 ) );
|
||||
|
||||
m_textLabel = new wxStaticText( this, wxID_ANY, _("Text:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_textLabel->Wrap( -1 );
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxGridBagSizer" expanded="1">
|
||||
<property name="empty_cell_size">0,0</property>
|
||||
<property name="empty_cell_size">0,10</property>
|
||||
<property name="flexible_direction">wxBOTH</property>
|
||||
<property name="growablecols">3</property>
|
||||
<property name="growablerows"></property>
|
||||
@@ -135,7 +135,7 @@
|
||||
<property name="name">m_textEntrySizer</property>
|
||||
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="vgap">3</property>
|
||||
<property name="vgap">2</property>
|
||||
<object class="gbsizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="colspan">1</property>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
||||
@@ -891,7 +891,7 @@ bool PANEL_SYM_LIB_TABLE::TransferDataFromWindow()
|
||||
m_globalTable->Clear();
|
||||
m_globalTable->m_rows.transfer( m_globalTable->m_rows.end(), global_model()->m_rows.begin(),
|
||||
global_model()->m_rows.end(), global_model()->m_rows );
|
||||
m_globalTable->reindex();
|
||||
m_globalTable->reindex( true );
|
||||
}
|
||||
|
||||
if( project_model() && *project_model() != *m_projectTable )
|
||||
@@ -901,7 +901,7 @@ bool PANEL_SYM_LIB_TABLE::TransferDataFromWindow()
|
||||
m_projectTable->Clear();
|
||||
m_projectTable->m_rows.transfer( m_projectTable->m_rows.end(), project_model()->m_rows.begin(),
|
||||
project_model()->m_rows.end(), project_model()->m_rows );
|
||||
m_projectTable->reindex();
|
||||
m_projectTable->reindex( true );
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1014,9 +1014,7 @@ size_t PANEL_SYM_LIB_TABLE::m_pageNdx = 0;
|
||||
|
||||
void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
|
||||
{
|
||||
auto* schEditor = (SCH_EDIT_FRAME*) aKiway->Player( FRAME_SCH, false );
|
||||
auto* symbolEditor = (SYMBOL_EDIT_FRAME*) aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
|
||||
auto* symbolViewer = (SYMBOL_VIEWER_FRAME*) aKiway->Player( FRAME_SCH_VIEWER, false );
|
||||
|
||||
SYMBOL_LIB_TABLE* globalTable = &SYMBOL_LIB_TABLE::GetGlobalLibTable();
|
||||
wxString globalTablePath = SYMBOL_LIB_TABLE::GetGlobalTableFileName();
|
||||
@@ -1093,23 +1091,13 @@ void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
|
||||
}
|
||||
}
|
||||
|
||||
if( schEditor )
|
||||
schEditor->SyncView();
|
||||
|
||||
if( symbolEditor )
|
||||
{
|
||||
// Check if the currently selected symbol library been removed or disabled.
|
||||
if( !currentLib.empty() && projectTable && !projectTable->HasLibrary( currentLib, true ) )
|
||||
{
|
||||
symbolEditor->SetCurLib( wxEmptyString );
|
||||
symbolEditor->emptyScreen();
|
||||
}
|
||||
|
||||
symbolEditor->SyncLibraries( true );
|
||||
symbolEditor->ThawLibraryTree();
|
||||
symbolEditor->RefreshLibraryTree();
|
||||
}
|
||||
|
||||
if( symbolViewer )
|
||||
symbolViewer->ReCreateLibList();
|
||||
std::string payload = "";
|
||||
aKiway->ExpressMail( FRAME_SCH, MAIL_RELOAD_LIB, payload );
|
||||
aKiway->ExpressMail( FRAME_SCH_SYMBOL_EDITOR, MAIL_RELOAD_LIB, payload );
|
||||
aKiway->ExpressMail( FRAME_SCH_VIEWER, MAIL_RELOAD_LIB, payload );
|
||||
}
|
||||
|
||||
+22
-3
@@ -135,6 +135,8 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
|
||||
|
||||
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
|
||||
|
||||
void Reset() override;
|
||||
|
||||
void OnKifaceEnd() override;
|
||||
|
||||
wxWindow* CreateKiWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway,
|
||||
@@ -286,6 +288,8 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
|
||||
int HandleJob( JOB* aJob ) override;
|
||||
|
||||
private:
|
||||
bool loadGlobalLibTable();
|
||||
|
||||
std::unique_ptr<EESCHEMA_JOBS_HANDLER> m_jobHandler;
|
||||
|
||||
} kiface( "eeschema", KIWAY::FACE_SCH );
|
||||
@@ -332,11 +336,28 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
|
||||
start_common( aCtlBits );
|
||||
|
||||
if( !loadGlobalLibTable() )
|
||||
return false;
|
||||
|
||||
m_jobHandler = std::make_unique<EESCHEMA_JOBS_HANDLER>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void IFACE::Reset()
|
||||
{
|
||||
loadGlobalLibTable();
|
||||
}
|
||||
|
||||
|
||||
bool IFACE::loadGlobalLibTable()
|
||||
{
|
||||
wxFileName fn = SYMBOL_LIB_TABLE::GetGlobalTableFileName();
|
||||
|
||||
if( !fn.FileExists() )
|
||||
{
|
||||
if( !( aCtlBits & KFCTL_CLI ) )
|
||||
if( !( m_start_flags & KFCTL_CLI ) )
|
||||
{
|
||||
DIALOG_GLOBAL_SYM_LIB_TABLE_CONFIG fpDialog( nullptr );
|
||||
|
||||
@@ -366,8 +387,6 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
}
|
||||
}
|
||||
|
||||
m_jobHandler = std::make_unique<EESCHEMA_JOBS_HANDLER>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <wx/settings.h>
|
||||
#include <string_utils.h>
|
||||
#include <widgets/grid_combobox.h>
|
||||
#include <pgm_base.h>
|
||||
|
||||
|
||||
enum
|
||||
@@ -275,7 +276,7 @@ void FIELDS_GRID_TABLE<T>::initGrid( WX_GRID* aGrid )
|
||||
|
||||
wxArrayString fonts;
|
||||
std::vector<std::string> fontNames;
|
||||
Fontconfig()->ListFonts( fontNames );
|
||||
Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ) );
|
||||
|
||||
for( const std::string& name : fontNames )
|
||||
fonts.Add( wxString( name ) );
|
||||
|
||||
@@ -38,8 +38,9 @@ class SCH_LABEL_BASE;
|
||||
class FIELDS_GRID_TRICKS : public GRID_TRICKS
|
||||
{
|
||||
public:
|
||||
FIELDS_GRID_TRICKS( WX_GRID* aGrid, DIALOG_SHIM* aDialog ) :
|
||||
GRID_TRICKS( aGrid ),
|
||||
FIELDS_GRID_TRICKS( WX_GRID* aGrid, DIALOG_SHIM* aDialog,
|
||||
std::function<void( wxCommandEvent& )> aAddHandler ) :
|
||||
GRID_TRICKS( aGrid, std::move( aAddHandler ) ),
|
||||
m_dlg( aDialog )
|
||||
{}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ protected:
|
||||
wxString GetHtmlFieldRow( const LIB_FIELD& aField ) const
|
||||
{
|
||||
wxString name = aField.GetCanonicalName();
|
||||
wxString text = aField.GetFullText( m_unit > 0 ? m_unit : 1 );
|
||||
wxString text;
|
||||
wxString fieldhtml = FieldFormat;
|
||||
|
||||
fieldhtml.Replace( wxS( "__NAME__" ), EscapeHTML( name ) );
|
||||
@@ -166,7 +166,7 @@ protected:
|
||||
switch( aField.GetId() )
|
||||
{
|
||||
case DATASHEET_FIELD:
|
||||
text = m_symbol->GetDatasheetField().GetText();
|
||||
text = m_symbol->GetDatasheetField().GetShownText( 0, false );
|
||||
|
||||
if( text.IsEmpty() || text == wxT( "~" ) )
|
||||
{
|
||||
@@ -191,7 +191,13 @@ protected:
|
||||
// showing the value just repeats the name, so that's not much use...
|
||||
return wxEmptyString;
|
||||
|
||||
case REFERENCE_FIELD:
|
||||
text = aField.GetFullText( m_unit > 0 ? m_unit : 1 );
|
||||
fieldhtml.Replace( wxS( "__VALUE__" ), EscapeHTML( text ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
text = aField.GetShownText( 0, false );
|
||||
fieldhtml.Replace( wxS( "__VALUE__" ), EscapeHTML( text ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -383,8 +383,14 @@ void LIB_FIELD::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOffs
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( renderSettings->GetDefaultFont(), IsBold(), IsItalic() );
|
||||
|
||||
aPlotter->Text( textpos, color, GetShownText(), orient, GetTextSize(), hjustify, vjustify,
|
||||
penWidth, IsItalic(), IsBold(), false, font );
|
||||
TEXT_ATTRIBUTES attrs = GetAttributes();
|
||||
attrs.m_StrokeWidth = penWidth;
|
||||
attrs.m_Halign = hjustify;
|
||||
attrs.m_Valign = vjustify;
|
||||
attrs.m_Angle = orient;
|
||||
attrs.m_Multiline = false;
|
||||
|
||||
aPlotter->PlotText( textpos, color, GetShownText(), attrs, font );
|
||||
}
|
||||
|
||||
|
||||
|
||||
+49
-24
@@ -812,8 +812,15 @@ void LIB_PIN::PlotPinTexts( PLOTTER *aPlotter, const VECTOR2I &aPinPos, int aPin
|
||||
int size, GR_TEXT_H_ALIGN_T hJustify, GR_TEXT_V_ALIGN_T vJustify, int penWidth )
|
||||
|
||||
{
|
||||
aPlotter->Text( VECTOR2I( px, py ), color, text, angle, VECTOR2I( size, size ),
|
||||
hJustify, vJustify, penWidth, false, false, false, font );
|
||||
TEXT_ATTRIBUTES attrs;
|
||||
attrs.m_StrokeWidth = std::min( penWidth, size / 5 ); // Keep text readable
|
||||
attrs.m_Angle = angle;
|
||||
attrs.m_Size = VECTOR2I( size, size );
|
||||
attrs.m_Halign = hJustify;
|
||||
attrs.m_Valign = vJustify;
|
||||
attrs.m_Multiline = false;
|
||||
|
||||
aPlotter->PlotText( VECTOR2I( px, py ), color, text, attrs, font );
|
||||
};
|
||||
|
||||
/* Draw the text inside, but the pin numbers outside. */
|
||||
@@ -1205,7 +1212,7 @@ const BOX2I LIB_PIN::GetBoundingBox( bool aIncludeInvisiblePins, bool aIncludeNa
|
||||
BOX2I bbox;
|
||||
VECTOR2I begin;
|
||||
VECTOR2I end;
|
||||
int nameTextOffset = 0;
|
||||
int pinNameOffset = 0;
|
||||
int nameTextLength = 0;
|
||||
int nameTextHeight = 0;
|
||||
int numberTextLength = 0;
|
||||
@@ -1228,7 +1235,7 @@ const BOX2I LIB_PIN::GetBoundingBox( bool aIncludeInvisiblePins, bool aIncludeNa
|
||||
if( GetParent() )
|
||||
{
|
||||
if( GetParent()->ShowPinNames() )
|
||||
nameTextOffset = GetParent()->GetPinNameOffset();
|
||||
pinNameOffset = GetParent()->GetPinNameOffset();
|
||||
else
|
||||
includeName = false;
|
||||
|
||||
@@ -1236,30 +1243,42 @@ const BOX2I LIB_PIN::GetBoundingBox( bool aIncludeInvisiblePins, bool aIncludeNa
|
||||
includeNumber = false;
|
||||
}
|
||||
|
||||
// Get maximum height including ascenders and descenders
|
||||
wxString test = wxT( "Xg" );
|
||||
|
||||
if( includeNumber )
|
||||
{
|
||||
VECTOR2D fontSize( m_numTextSize, m_numTextSize );
|
||||
VECTOR2I numSize = font->StringBoundaryLimits( number, fontSize, penWidth, false, false );
|
||||
|
||||
numberTextLength = numSize.x;
|
||||
numberTextHeight = numSize.y;
|
||||
numberTextLength = font->StringBoundaryLimits( number, fontSize, penWidth, false, false ).x;
|
||||
numberTextHeight = font->StringBoundaryLimits( test, fontSize, penWidth, false, false ).y;
|
||||
}
|
||||
|
||||
if( includeName )
|
||||
{
|
||||
VECTOR2D fontSize( m_nameTextSize, m_nameTextSize );
|
||||
VECTOR2I nameSize = font->StringBoundaryLimits( name, fontSize, penWidth, false, false );
|
||||
|
||||
nameTextLength = nameSize.x + nameTextOffset;
|
||||
nameTextHeight = nameSize.y + schIUScale.MilsToIU( PIN_TEXT_MARGIN );
|
||||
nameTextLength = font->StringBoundaryLimits( name, fontSize, penWidth, false, false ).x
|
||||
+ pinNameOffset;
|
||||
nameTextHeight = font->StringBoundaryLimits( test, fontSize, penWidth, false, false ).y
|
||||
+ schIUScale.MilsToIU( PIN_TEXT_MARGIN );
|
||||
}
|
||||
|
||||
// KIFONT has to be rather tight on boundary limits for knockout text in PCBNew, but in truth
|
||||
// the stroke font returns a vertically under-sized bounding box (even though it *does* in fact
|
||||
// attempt to account for the font size being stroke centre-point to stroke centre-point).
|
||||
if( font->IsStroke() )
|
||||
{
|
||||
numberTextHeight += 2 * penWidth;
|
||||
nameTextHeight += 2 * penWidth;
|
||||
}
|
||||
|
||||
if( includeType )
|
||||
{
|
||||
double fontSize = std::max( m_nameTextSize * 3 / 4, schIUScale.mmToIU( 0.7 ) );
|
||||
double stroke = fontSize / 8.0;
|
||||
VECTOR2I typeTextSize = font->StringBoundaryLimits( GetElectricalTypeName(),
|
||||
VECTOR2D( fontSize, fontSize ),
|
||||
fontSize / 8.0, false, false );
|
||||
KiROUND( stroke ), false, false );
|
||||
|
||||
typeTextLength = typeTextSize.x + schIUScale.MilsToIU( PIN_TEXT_MARGIN ) + TARGET_PIN_RADIUS;
|
||||
minsizeV = std::max( minsizeV, typeTextSize.y / 2 );
|
||||
@@ -1269,24 +1288,30 @@ const BOX2I LIB_PIN::GetBoundingBox( bool aIncludeInvisiblePins, bool aIncludeNa
|
||||
if( m_shape == GRAPHIC_PINSHAPE::INVERTED || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK )
|
||||
minsizeV = std::max( TARGET_PIN_RADIUS, externalPinDecoSize( nullptr, *this ) );
|
||||
|
||||
// calculate top left corner position
|
||||
// for the default pin orientation (PIN_RIGHT)
|
||||
begin.y = std::max( minsizeV, numberTextHeight + schIUScale.MilsToIU( PIN_TEXT_MARGIN ) );
|
||||
begin.x = std::min( -typeTextLength, m_length - ( numberTextLength / 2) );
|
||||
// Attempt to mimic SCH_PAINTER's algorithm without actually knowing the schematic text
|
||||
// offset ratio.
|
||||
int PIN_TEXT_OFFSET = schIUScale.MilsToIU( 24 ) + 2 * penWidth;
|
||||
|
||||
// calculate bottom right corner position and adjust top left corner position
|
||||
if( nameTextOffset ) // for values > 0, pin name is inside the body
|
||||
// Calculate topLeft & bottomRight corner positions for the default pin orientation (PIN_RIGHT)
|
||||
if( pinNameOffset || !includeName )
|
||||
{
|
||||
// pin name is inside the body (or invisible)
|
||||
// pin number is above the line
|
||||
begin.y = std::max( minsizeV, numberTextHeight + PIN_TEXT_OFFSET );
|
||||
begin.x = std::min( -typeTextLength, m_length - ( numberTextLength / 2) );
|
||||
|
||||
end.x = m_length + nameTextLength;
|
||||
end.y = std::min( -minsizeV, -nameTextHeight / 2 );
|
||||
}
|
||||
else // if value == 0:
|
||||
// pin name is outside the body, and above the pin line
|
||||
// pin num is below the pin line
|
||||
else
|
||||
{
|
||||
end.x = std::max( m_length, nameTextLength );
|
||||
end.y = -begin.y;
|
||||
begin.y = std::max( minsizeV, nameTextHeight );
|
||||
// pin name is above pin line
|
||||
// pin number is below line
|
||||
begin.y = std::max( minsizeV, nameTextHeight + PIN_TEXT_OFFSET );
|
||||
begin.x = std::min( -typeTextLength, m_length - ( numberTextLength / 2) );
|
||||
|
||||
end.x = std::max( m_length, nameTextLength );
|
||||
end.y = std::min( -minsizeV, -numberTextHeight - PIN_TEXT_OFFSET );
|
||||
}
|
||||
|
||||
// Now, calculate boundary box corners position for the actual pin orientation
|
||||
|
||||
+48
-43
@@ -389,54 +389,59 @@ void LIB_SHAPE::print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
|
||||
penWidth = std::max( penWidth, aSettings->GetDefaultPenWidth() );
|
||||
|
||||
if( GetEffectiveLineStyle() == PLOT_DASH_TYPE::SOLID )
|
||||
{
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
GRArc( DC, pt1, pt2, c, penWidth, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::CIRCLE:
|
||||
GRCircle( DC, pt1, GetRadius(), penWidth, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECT:
|
||||
GRRect( DC, pt1, pt2, penWidth, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
GRPoly( DC, ptCount, buffer, false, penWidth, color, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
GRPoly( DC, ptCount, buffer, false, penWidth, color, color );
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<SHAPE*> shapes = MakeEffectiveShapes( true );
|
||||
penWidth = std::max( penWidth, aSettings->GetDefaultPenWidth() );
|
||||
}
|
||||
|
||||
for( SHAPE* shape : shapes )
|
||||
if( penWidth > 0 )
|
||||
{
|
||||
if( GetEffectiveLineStyle() == PLOT_DASH_TYPE::SOLID )
|
||||
{
|
||||
STROKE_PARAMS::Stroke( shape, GetEffectiveLineStyle(), penWidth, aSettings,
|
||||
[&]( const VECTOR2I& a, const VECTOR2I& b )
|
||||
{
|
||||
VECTOR2I pts = aTransform.TransformCoordinate( a ) + aOffset;
|
||||
VECTOR2I pte = aTransform.TransformCoordinate( b ) + aOffset;
|
||||
GRLine( DC, pts.x, pts.y, pte.x, pte.y, penWidth, color );
|
||||
} );
|
||||
}
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
GRArc( DC, pt1, pt2, c, penWidth, color );
|
||||
break;
|
||||
|
||||
for( SHAPE* shape : shapes )
|
||||
delete shape;
|
||||
case SHAPE_T::CIRCLE:
|
||||
GRCircle( DC, pt1, GetRadius(), penWidth, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECT:
|
||||
GRRect( DC, pt1, pt2, penWidth, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
GRPoly( DC, ptCount, buffer, false, penWidth, color, color );
|
||||
break;
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
GRPoly( DC, ptCount, buffer, false, penWidth, color, color );
|
||||
break;
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<SHAPE*> shapes = MakeEffectiveShapes( true );
|
||||
|
||||
for( SHAPE* shape : shapes )
|
||||
{
|
||||
STROKE_PARAMS::Stroke( shape, GetEffectiveLineStyle(), penWidth, aSettings,
|
||||
[&]( const VECTOR2I& a, const VECTOR2I& b )
|
||||
{
|
||||
VECTOR2I pts = aTransform.TransformCoordinate( a ) + aOffset;
|
||||
VECTOR2I pte = aTransform.TransformCoordinate( b ) + aOffset;
|
||||
GRLine( DC, pts.x, pts.y, pte.x, pte.y, penWidth, color );
|
||||
} );
|
||||
}
|
||||
|
||||
for( SHAPE* shape : shapes )
|
||||
delete shape;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
@@ -326,9 +326,10 @@ void LIB_TEXT::Plot( PLOTTER* plotter, bool aBackground, const VECTOR2I& offset,
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( settings->GetDefaultFont(), IsBold(), IsItalic() );
|
||||
|
||||
plotter->Text( pos, color, GetText(), t1 ? ANGLE_HORIZONTAL : ANGLE_VERTICAL, GetTextSize(),
|
||||
GetHorizJustify(), GetVertJustify(), penWidth, IsItalic(), IsBold(),
|
||||
true, font );
|
||||
attrs.m_StrokeWidth = penWidth;
|
||||
attrs.m_Angle = t1 ? ANGLE_HORIZONTAL : ANGLE_VERTICAL;
|
||||
|
||||
plotter->PlotText( pos, color, GetText(), attrs, font );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -465,11 +465,13 @@ void LIB_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOf
|
||||
|
||||
text.GetLinePositions( positions, (int) strings_list.Count() );
|
||||
|
||||
TEXT_ATTRIBUTES attrs = GetAttributes();
|
||||
attrs.m_StrokeWidth = penWidth;
|
||||
attrs.m_Multiline = false;
|
||||
|
||||
for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
|
||||
{
|
||||
aPlotter->Text( positions[ii], color, strings_list.Item( ii ), text.GetTextAngle(),
|
||||
text.GetTextSize(), text.GetHorizJustify(), text.GetVertJustify(),
|
||||
penWidth, text.IsItalic(), text.IsBold(), false, font );
|
||||
aPlotter->PlotText( positions[ii], color, strings_list.Item( ii ), attrs, font );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,16 +113,18 @@ SCH_SYMBOL* NETLIST_EXPORTER_BASE::findNextSymbol( EDA_ITEM* aItem, SCH_SHEET_PA
|
||||
}
|
||||
|
||||
|
||||
void NETLIST_EXPORTER_BASE::CreatePinList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheetPath,
|
||||
bool aKeepUnconnectedPins )
|
||||
std::vector<PIN_INFO> NETLIST_EXPORTER_BASE::CreatePinList( SCH_SYMBOL* aSymbol,
|
||||
SCH_SHEET_PATH* aSheetPath,
|
||||
bool aKeepUnconnectedPins )
|
||||
{
|
||||
wxString ref( aSymbol->GetRef( aSheetPath ) );
|
||||
wxString ref( aSymbol->GetRef( aSheetPath ) );
|
||||
std::vector<PIN_INFO> pins;
|
||||
|
||||
// Power symbols and other symbols which have the reference starting with "#" are not
|
||||
// included in netlist (pseudo or virtual symbols)
|
||||
|
||||
if( ref[0] == wxChar( '#' ) )
|
||||
return;
|
||||
return pins;
|
||||
|
||||
// if( aSymbol->m_FlagControlMulti == 1 )
|
||||
// continue; /* yes */
|
||||
@@ -130,9 +132,7 @@ void NETLIST_EXPORTER_BASE::CreatePinList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH*
|
||||
// 1 screen), this will be erroneously be toggled.
|
||||
|
||||
if( !aSymbol->GetLibSymbolRef() )
|
||||
return;
|
||||
|
||||
m_sortedSymbolPinList.clear();
|
||||
return pins;
|
||||
|
||||
// If symbol is a "multi parts per package" type
|
||||
if( aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
|
||||
@@ -140,7 +140,7 @@ void NETLIST_EXPORTER_BASE::CreatePinList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH*
|
||||
// Collect all pins for this reference designator by searching the entire design for
|
||||
// other parts with the same reference designator.
|
||||
// This is only done once, it would be too expensive otherwise.
|
||||
findAllUnitsOfSymbol( aSymbol, aSheetPath, aKeepUnconnectedPins );
|
||||
findAllUnitsOfSymbol( aSymbol, aSheetPath, pins, aKeepUnconnectedPins );
|
||||
}
|
||||
|
||||
else // GetUnitCount() <= 1 means one part per package
|
||||
@@ -161,31 +161,33 @@ void NETLIST_EXPORTER_BASE::CreatePinList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH*
|
||||
continue;
|
||||
}
|
||||
|
||||
m_sortedSymbolPinList.emplace_back( pin->GetShownNumber(), netName );
|
||||
pins.emplace_back( pin->GetShownNumber(), netName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort pins in m_SortedSymbolPinList by pin number
|
||||
std::sort( m_sortedSymbolPinList.begin(), m_sortedSymbolPinList.end(),
|
||||
std::sort( pins.begin(), pins.end(),
|
||||
[]( const PIN_INFO& lhs, const PIN_INFO& rhs )
|
||||
{
|
||||
return StrNumCmp( lhs.num, rhs.num, true ) < 0;
|
||||
} );
|
||||
|
||||
// Remove duplicate Pins in m_SortedSymbolPinList
|
||||
eraseDuplicatePins();
|
||||
eraseDuplicatePins( pins );
|
||||
|
||||
// record the usage of this library symbol
|
||||
m_libParts.insert( aSymbol->GetLibSymbolRef().get() ); // rejects non-unique pointers
|
||||
|
||||
return pins;
|
||||
}
|
||||
|
||||
|
||||
void NETLIST_EXPORTER_BASE::eraseDuplicatePins()
|
||||
void NETLIST_EXPORTER_BASE::eraseDuplicatePins( std::vector<PIN_INFO>& aPins )
|
||||
{
|
||||
for( unsigned ii = 0; ii < m_sortedSymbolPinList.size(); ii++ )
|
||||
for( unsigned ii = 0; ii < aPins.size(); ii++ )
|
||||
{
|
||||
if( m_sortedSymbolPinList[ii].num.empty() ) /* already deleted */
|
||||
if( aPins[ii].num.empty() ) /* already deleted */
|
||||
continue;
|
||||
|
||||
/* Search for duplicated pins
|
||||
@@ -198,17 +200,17 @@ void NETLIST_EXPORTER_BASE::eraseDuplicatePins()
|
||||
*/
|
||||
int idxref = ii;
|
||||
|
||||
for( unsigned jj = ii + 1; jj < m_sortedSymbolPinList.size(); jj++ )
|
||||
for( unsigned jj = ii + 1; jj < aPins.size(); jj++ )
|
||||
{
|
||||
if( m_sortedSymbolPinList[jj].num.empty() ) // Already removed
|
||||
if( aPins[jj].num.empty() ) // Already removed
|
||||
continue;
|
||||
|
||||
// if other pin num, stop search,
|
||||
// because all pins having the same number are consecutive in list.
|
||||
if( m_sortedSymbolPinList[idxref].num != m_sortedSymbolPinList[jj].num )
|
||||
if( aPins[idxref].num != aPins[jj].num )
|
||||
break;
|
||||
|
||||
m_sortedSymbolPinList[jj].num.clear();
|
||||
aPins[jj].num.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,6 +218,7 @@ void NETLIST_EXPORTER_BASE::eraseDuplicatePins()
|
||||
|
||||
void NETLIST_EXPORTER_BASE::findAllUnitsOfSymbol( SCH_SYMBOL* aSchSymbol,
|
||||
SCH_SHEET_PATH* aSheetPath,
|
||||
std::vector<PIN_INFO>& aPins,
|
||||
bool aKeepUnconnectedPins )
|
||||
{
|
||||
wxString ref = aSchSymbol->GetRef( aSheetPath );
|
||||
@@ -251,7 +254,7 @@ void NETLIST_EXPORTER_BASE::findAllUnitsOfSymbol( SCH_SYMBOL* aSchSymbol,
|
||||
continue;
|
||||
}
|
||||
|
||||
m_sortedSymbolPinList.emplace_back( pin->GetShownNumber(), netName );
|
||||
aPins.emplace_back( pin->GetShownNumber(), netName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public:
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Find a symbol from the DrawList and builds its pin list in m_sortedSymbolPinList.
|
||||
* Find a symbol from the DrawList and builds its pin list.
|
||||
*
|
||||
* This list is sorted by pin number. The symbol is the next actual symbol after \a aSymbol.
|
||||
* Power symbols and virtual symbols that have their reference designators starting with
|
||||
@@ -155,8 +155,8 @@ protected:
|
||||
* if aKeepUnconnectedPins = false, unconnected pins will be removed from list
|
||||
* but usually we need all pins in netlists.
|
||||
*/
|
||||
void CreatePinList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheetPath,
|
||||
bool aKeepUnconnectedPins );
|
||||
std::vector<PIN_INFO> CreatePinList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheetPath,
|
||||
bool aKeepUnconnectedPins );
|
||||
|
||||
/**
|
||||
* Check if the given symbol should be processed for netlisting.
|
||||
@@ -170,7 +170,7 @@ protected:
|
||||
SCH_SYMBOL* findNextSymbol( EDA_ITEM* aItem, SCH_SHEET_PATH* aSheetPath );
|
||||
|
||||
/**
|
||||
* Erase duplicate pins from m_sortedSymbolPinList (i.e. set pointer in this list to NULL).
|
||||
* Erase duplicate pins.
|
||||
*
|
||||
* (This is a list of pins found in the whole schematic, for a single symbol.) These
|
||||
* duplicate pins were put in list because some pins (power pins...) are found more than
|
||||
@@ -179,24 +179,18 @@ protected:
|
||||
* Note: this list *MUST* be sorted by pin number (.m_PinNum member value)
|
||||
* Also set the m_Flag member of "removed" NETLIST_OBJECT pin item to 1
|
||||
*/
|
||||
void eraseDuplicatePins();
|
||||
void eraseDuplicatePins( std::vector<PIN_INFO>& pins );
|
||||
|
||||
/**
|
||||
* Find all units for symbols with multiple symbols per package.
|
||||
*
|
||||
* Search the entire design for all units of \a aSymbol based on matching reference
|
||||
* designator, and for each unit, add all its pins to the temporary sorted pin list,
|
||||
* m_sortedSymbolPinList.
|
||||
* designator, and for each unit, add all its pins to the sorted pin list.
|
||||
* if aKeepUnconnectedPins = false, unconnected pins will be removed from list
|
||||
* but usually we need all pins in netlists.
|
||||
*/
|
||||
void findAllUnitsOfSymbol( SCH_SYMBOL* aSchSymbol, SCH_SHEET_PATH* aSheetPath,
|
||||
bool aKeepUnconnectedPins );
|
||||
|
||||
/// Used to temporarily store and filter the list of pins of a schematic symbol when
|
||||
/// generating schematic symbol data in netlist (comp section). No ownership of members.
|
||||
/// TODO(snh): Descope this object
|
||||
std::vector<PIN_INFO> m_sortedSymbolPinList;
|
||||
std::vector<PIN_INFO>& aPins, bool aKeepUnconnectedPins );
|
||||
|
||||
/// Used for "multiple symbols per package" symbols to avoid processing a lib symbol more than
|
||||
/// once
|
||||
|
||||
@@ -79,7 +79,7 @@ bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName,
|
||||
if( !symbol->GetIncludeOnBoard() )
|
||||
continue;
|
||||
|
||||
CreatePinList( symbol, &sheet, true );
|
||||
std::vector<PIN_INFO> pins = CreatePinList( symbol, &sheet, true );
|
||||
|
||||
if( symbol->GetLibSymbolRef()
|
||||
&& symbol->GetLibSymbolRef()->GetFPFilters().GetCount() != 0 )
|
||||
@@ -110,7 +110,7 @@ bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName,
|
||||
ret |= fprintf( f, "\n" );
|
||||
|
||||
// Write pin list:
|
||||
for( const PIN_INFO& pin : m_sortedSymbolPinList )
|
||||
for( const PIN_INFO& pin : pins )
|
||||
{
|
||||
if( pin.num.IsEmpty() ) // Erased pin in list
|
||||
continue;
|
||||
|
||||
@@ -148,7 +148,7 @@ bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsign
|
||||
|
||||
void NETLIST_EXPORTER_SPICE::WriteHead( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
|
||||
{
|
||||
aFormatter.Print( 0, "KiCad schematic\n" );
|
||||
aFormatter.Print( 0, ".title KiCad schematic\n" );
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
|
||||
if( !symbol || symbol->GetFieldText( SIM_ENABLE_FIELD ) == wxT( "0" ) )
|
||||
continue;
|
||||
|
||||
CreatePinList( symbol, &sheet, true );
|
||||
std::vector<PIN_INFO> pins = CreatePinList( symbol, &sheet, true );
|
||||
|
||||
SPICE_ITEM spiceItem;
|
||||
|
||||
@@ -267,8 +267,8 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
|
||||
{
|
||||
readRefName( sheet, *symbol, spiceItem, refNames );
|
||||
readModel( sheet, *symbol, spiceItem );
|
||||
readPinNumbers( *symbol, spiceItem );
|
||||
readPinNetNames( *symbol, spiceItem, ncCounter );
|
||||
readPinNumbers( *symbol, spiceItem, pins );
|
||||
readPinNetNames( *symbol, spiceItem, pins, ncCounter );
|
||||
|
||||
// TODO: transmission line handling?
|
||||
|
||||
@@ -387,49 +387,55 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions )
|
||||
wxStringTokenizer tokenizer( text, wxT( "\r\n" ), wxTOKEN_STRTOK );
|
||||
bool foundDirective = false;
|
||||
|
||||
auto isDirective =
|
||||
[]( const wxString& line, const wxString& dir )
|
||||
{
|
||||
return line == dir || line.StartsWith( dir + wxS( " " ) );
|
||||
};
|
||||
|
||||
while( tokenizer.HasMoreTokens() )
|
||||
{
|
||||
wxString line = tokenizer.GetNextToken().Upper();
|
||||
|
||||
if( line.StartsWith( wxT( "." ) ) )
|
||||
{
|
||||
if( line.StartsWith( wxT( ".AC" ) )
|
||||
|| line.StartsWith( wxT( ".CONTROL" ) )
|
||||
|| line.StartsWith( wxT( ".CSPARAM" ) )
|
||||
|| line.StartsWith( wxT( ".DISTO" ) )
|
||||
|| line.StartsWith( wxT( ".ELSE" ) )
|
||||
|| line.StartsWith( wxT( ".ELSEIF" ) )
|
||||
|| line.StartsWith( wxT( ".END" ) )
|
||||
|| line.StartsWith( wxT( ".ENDC" ) )
|
||||
|| line.StartsWith( wxT( ".ENDIF" ) )
|
||||
|| line.StartsWith( wxT( ".ENDS" ) )
|
||||
|| line.StartsWith( wxT( ".FOUR" ) )
|
||||
|| line.StartsWith( wxT( ".FUNC" ) )
|
||||
|| line.StartsWith( wxT( ".GLOBAL" ) )
|
||||
|| line.StartsWith( wxT( ".IC" ) )
|
||||
|| line.StartsWith( wxT( ".IF" ) )
|
||||
|| line.StartsWith( wxT( ".INCLUDE" ) )
|
||||
|| line.StartsWith( wxT( ".LIB" ) )
|
||||
|| line.StartsWith( wxT( ".MEAS" ) )
|
||||
|| line.StartsWith( wxT( ".MODEL" ) )
|
||||
|| line.StartsWith( wxT( ".NODESET" ) )
|
||||
|| line.StartsWith( wxT( ".NOISE" ) )
|
||||
|| line.StartsWith( wxT( ".OP" ) )
|
||||
|| line.StartsWith( wxT( ".OPTIONS" ) )
|
||||
|| line.StartsWith( wxT( ".PARAM" ) )
|
||||
|| line.StartsWith( wxT( ".PLOT" ) )
|
||||
|| line.StartsWith( wxT( ".PRINT" ) )
|
||||
|| line.StartsWith( wxT( ".PROBE" ) )
|
||||
|| line.StartsWith( wxT( ".PZ" ) )
|
||||
|| line.StartsWith( wxT( ".SAVE" ) )
|
||||
|| line.StartsWith( wxT( ".SENS" ) )
|
||||
|| line.StartsWith( wxT( ".SP" ) )
|
||||
|| line.StartsWith( wxT( ".SUBCKT" ) )
|
||||
|| line.StartsWith( wxT( ".TEMP" ) )
|
||||
|| line.StartsWith( wxT( ".TF" ) )
|
||||
|| line.StartsWith( wxT( ".TITLE" ) )
|
||||
|| line.StartsWith( wxT( ".TRAN" ) )
|
||||
|| line.StartsWith( wxT( ".WIDTH" ) ) )
|
||||
if( isDirective( line, wxS( ".AC" ) )
|
||||
|| isDirective( line, wxS( ".CONTROL" ) )
|
||||
|| isDirective( line, wxS( ".CSPARAM" ) )
|
||||
|| isDirective( line, wxS( ".DISTO" ) )
|
||||
|| isDirective( line, wxS( ".ELSE" ) )
|
||||
|| isDirective( line, wxS( ".ELSEIF" ) )
|
||||
|| isDirective( line, wxS( ".END" ) )
|
||||
|| isDirective( line, wxS( ".ENDC" ) )
|
||||
|| isDirective( line, wxS( ".ENDIF" ) )
|
||||
|| isDirective( line, wxS( ".ENDS" ) )
|
||||
|| isDirective( line, wxS( ".FOUR" ) )
|
||||
|| isDirective( line, wxS( ".FUNC" ) )
|
||||
|| isDirective( line, wxS( ".GLOBAL" ) )
|
||||
|| isDirective( line, wxS( ".IC" ) )
|
||||
|| isDirective( line, wxS( ".IF" ) )
|
||||
|| isDirective( line, wxS( ".INCLUDE" ) )
|
||||
|| isDirective( line, wxS( ".LIB" ) )
|
||||
|| isDirective( line, wxS( ".MEAS" ) )
|
||||
|| isDirective( line, wxS( ".MODEL" ) )
|
||||
|| isDirective( line, wxS( ".NODESET" ) )
|
||||
|| isDirective( line, wxS( ".NOISE" ) )
|
||||
|| isDirective( line, wxS( ".OP" ) )
|
||||
|| isDirective( line, wxS( ".OPTIONS" ) )
|
||||
|| isDirective( line, wxS( ".PARAM" ) )
|
||||
|| isDirective( line, wxS( ".PLOT" ) )
|
||||
|| isDirective( line, wxS( ".PRINT" ) )
|
||||
|| isDirective( line, wxS( ".PROBE" ) )
|
||||
|| isDirective( line, wxS( ".PZ" ) )
|
||||
|| isDirective( line, wxS( ".SAVE" ) )
|
||||
|| isDirective( line, wxS( ".SENS" ) )
|
||||
|| isDirective( line, wxS( ".SP" ) )
|
||||
|| isDirective( line, wxS( ".SUBCKT" ) )
|
||||
|| isDirective( line, wxS( ".TEMP" ) )
|
||||
|| isDirective( line, wxS( ".TF" ) )
|
||||
|| isDirective( line, wxS( ".TITLE" ) )
|
||||
|| isDirective( line, wxS( ".TRAN" ) )
|
||||
|| isDirective( line, wxS( ".WIDTH" ) ) )
|
||||
{
|
||||
foundDirective = true;
|
||||
break;
|
||||
@@ -495,7 +501,7 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
|
||||
if( auto rawSpiceModel = dynamic_cast<const SIM_MODEL_RAW_SPICE*>( aItem.model ) )
|
||||
{
|
||||
int libParamIndex = static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
|
||||
wxString path = rawSpiceModel->GetParam( libParamIndex ).value->ToString();
|
||||
wxString path = rawSpiceModel->GetParam( libParamIndex ).value;
|
||||
|
||||
if( !path.IsEmpty() )
|
||||
m_rawIncludes.insert( path );
|
||||
@@ -527,20 +533,20 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
|
||||
}
|
||||
|
||||
|
||||
void NETLIST_EXPORTER_SPICE::readPinNumbers( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem )
|
||||
void NETLIST_EXPORTER_SPICE::readPinNumbers( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
|
||||
const std::vector<PIN_INFO>& aPins )
|
||||
{
|
||||
for( const PIN_INFO& pin : m_sortedSymbolPinList )
|
||||
aItem.pinNumbers.emplace_back( std::string( pin.num.ToUTF8() ) );
|
||||
for( const PIN_INFO& pin : aPins )
|
||||
aItem.pinNumbers.emplace_back( pin.num.ToStdString() );
|
||||
}
|
||||
|
||||
|
||||
void NETLIST_EXPORTER_SPICE::readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
|
||||
int& aNcCounter )
|
||||
const std::vector<PIN_INFO>& aPins, int& aNcCounter )
|
||||
{
|
||||
for( const PIN_INFO& pinInfo : m_sortedSymbolPinList )
|
||||
for( const PIN_INFO& pinInfo : aPins )
|
||||
{
|
||||
std::string netName = GenerateItemPinNetName( std::string( pinInfo.netName.ToUTF8() ),
|
||||
aNcCounter );
|
||||
std::string netName = GenerateItemPinNetName( pinInfo.netName.ToStdString(), aNcCounter );
|
||||
|
||||
aItem.pinNetNames.push_back( netName );
|
||||
m_nets.insert( netName );
|
||||
@@ -632,6 +638,12 @@ void NETLIST_EXPORTER_SPICE::WriteDirectives( OUTPUTFORMATTER& aFormatter,
|
||||
if( aNetlistOptions & OPTION_SAVE_ALL_CURRENTS )
|
||||
aFormatter.Print( 0, ".probe alli\n" );
|
||||
|
||||
auto isSimCommand =
|
||||
[]( const wxString& candidate, const wxString& dir )
|
||||
{
|
||||
return candidate == dir || candidate.StartsWith( dir + wxS( " " ) );
|
||||
};
|
||||
|
||||
for( const wxString& directive : m_directives )
|
||||
{
|
||||
bool simCommand = false;
|
||||
@@ -640,15 +652,15 @@ void NETLIST_EXPORTER_SPICE::WriteDirectives( OUTPUTFORMATTER& aFormatter,
|
||||
{
|
||||
wxString candidate = directive.Upper();
|
||||
|
||||
simCommand = ( candidate.StartsWith( wxT( ".AC" ) )
|
||||
|| candidate.StartsWith( wxT( ".DC" ) )
|
||||
|| candidate.StartsWith( wxT( ".TRAN" ) )
|
||||
|| candidate.StartsWith( wxT( ".OP" ) )
|
||||
|| candidate.StartsWith( wxT( ".DISTO" ) )
|
||||
|| candidate.StartsWith( wxT( ".NOISE" ) )
|
||||
|| candidate.StartsWith( wxT( ".PZ" ) )
|
||||
|| candidate.StartsWith( wxT( ".SENS" ) )
|
||||
|| candidate.StartsWith( wxT( ".TF" ) ) );
|
||||
simCommand = ( isSimCommand( candidate, wxS( ".AC" ) )
|
||||
|| isSimCommand( candidate, wxS( ".DC" ) )
|
||||
|| isSimCommand( candidate, wxS( ".TRAN" ) )
|
||||
|| isSimCommand( candidate, wxS( ".OP" ) )
|
||||
|| isSimCommand( candidate, wxS( ".DISTO" ) )
|
||||
|| isSimCommand( candidate, wxS( ".NOISE" ) )
|
||||
|| isSimCommand( candidate, wxS( ".PZ" ) )
|
||||
|| isSimCommand( candidate, wxS( ".SENS" ) )
|
||||
|| isSimCommand( candidate, wxS( ".TF" ) ) );
|
||||
}
|
||||
|
||||
if( !simCommand || ( aNetlistOptions & OPTION_SIM_COMMAND ) )
|
||||
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
|
||||
protected:
|
||||
void ReadDirectives( unsigned aNetlistOptions );
|
||||
virtual void WriteDirectives( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) const;
|
||||
virtual void WriteDirectives( OUTPUTFORMATTER& candidate, unsigned aNetlistOptions ) const;
|
||||
|
||||
virtual std::string GenerateItemPinNetName( const std::string& aNetName,
|
||||
int& aNcCounter ) const;
|
||||
@@ -144,8 +144,10 @@ private:
|
||||
void readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
|
||||
std::set<std::string>& aRefNames );
|
||||
void readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem );
|
||||
void readPinNumbers( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem );
|
||||
void readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, int& aNcCounter );
|
||||
void readPinNumbers( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
|
||||
const std::vector<PIN_INFO>& aPins );
|
||||
void readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
|
||||
const std::vector<PIN_INFO>& aPins, int& aNcCounter );
|
||||
|
||||
void writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
|
||||
const wxString& aPath );
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user