Compare commits
189 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2a41bad09 | |||
| 1a13bed1c1 | |||
| 7b9c775cbd | |||
| e9bf1daa5f | |||
| d6727934a5 | |||
| a8df90762d | |||
| 7b4bb28307 | |||
| ee8744770f | |||
| ace480d3f6 | |||
| 154795d32a | |||
| ce20c6ec77 | |||
| 6380f29214 | |||
| 1aaf767c5d | |||
| bd4ffa493f | |||
| cf26b12478 | |||
| cdb26a9c97 | |||
| b5687b87bd | |||
| e581ba4c7b | |||
| a2064f85b1 | |||
| 2dbe4485cc | |||
| 6b7b6fa3e3 | |||
| be71f776ce | |||
| 51ba4763f0 | |||
| f9a9db6503 | |||
| 8d001a8031 | |||
| 88115e1dd2 | |||
| e914c0c1a0 | |||
| a1cd73e730 | |||
| cecc1a2ff1 | |||
| dc08cf3252 | |||
| e20a11cbb3 | |||
| c27ca33a2e | |||
| 1073ca0760 | |||
| 4440fe0935 | |||
| d1cd859765 | |||
| 36119b869c | |||
| 3e5ceaa319 | |||
| 78cd01038f | |||
| 7b4952df11 | |||
| 73acc80c1d | |||
| 8b41207351 | |||
| 5dbc1c7b18 | |||
| 5780a15468 | |||
| 15f6d5ad73 | |||
| 421bc27181 | |||
| afe41498c4 | |||
| 92c40f2761 | |||
| bb82d99a76 | |||
| 1d0e118294 | |||
| d40b12301d | |||
| 138d22b26f | |||
| 9c69ea9df3 | |||
| 3395738e55 | |||
| 6afc2e727b | |||
| f10864b3a7 | |||
| 892602c070 | |||
| d8f2a455e0 | |||
| 561b2d490d | |||
| 1869da0e7d | |||
| be2f317f6d | |||
| c248993a84 | |||
| 0a227ea916 | |||
| f75e6dae84 | |||
| 160a493885 | |||
| 625d241adf | |||
| 1264230973 | |||
| 6dfd417767 | |||
| 585f11a01d | |||
| d6a121d617 | |||
| dfd8aa402d | |||
| 5b1c84b5dd | |||
| 11586863cf | |||
| d52e50a97a | |||
| fee0028ee9 | |||
| a762311733 | |||
| e0581370e1 | |||
| 2cd0139cbf | |||
| 28cd2a203e | |||
| 33715143e3 | |||
| ba6fd2716e | |||
| 882ff06e24 | |||
| f52a51dce3 | |||
| a96e16b766 | |||
| 81e51b00ca | |||
| c01681a32e | |||
| eeb9133588 | |||
| d45769e508 | |||
| a499bc9f66 | |||
| 341f102d79 | |||
| 3e50a03ce7 | |||
| 1defa3872e | |||
| e66d25b6e8 | |||
| 76f38600af | |||
| 44b0ef64e8 | |||
| c3e7509823 | |||
| 3622a296be | |||
| 0b48913876 | |||
| 9000cfb9cd | |||
| c748645334 | |||
| 79443b7e59 | |||
| 02925fdecc | |||
| ef1e054bb6 | |||
| bb13ab2963 | |||
| 9c7fb0697c | |||
| c92b11900b | |||
| cde18d7ae7 | |||
| 1a932cb13b | |||
| cc75d8c0af | |||
| cb93d2940c | |||
| 88e0d373d1 | |||
| c2d59c6103 | |||
| f8f48f922e | |||
| eb7e781bec | |||
| 378300c733 | |||
| ddd7c35586 | |||
| 6482a322da | |||
| dc6d421fa2 | |||
| 7b19fb0c8d | |||
| f6480d67eb | |||
| 35c788a332 | |||
| a0cba3a9af | |||
| af6835e766 | |||
| 1f88d33c81 | |||
| 6aee6f857e | |||
| 6d69fee097 | |||
| c7dd993439 | |||
| 7e5dd02ef1 | |||
| ca16ff05df | |||
| b8fa10ab2b | |||
| 09736ebf2c | |||
| 897b9fe6a1 | |||
| 48f14d6dea | |||
| 1ef916086d | |||
| 0b44ba61d8 | |||
| 3c99a3797e | |||
| 76c98859bf | |||
| 57c8fbc9fe | |||
| bbac5430cf | |||
| 279ef4210d | |||
| 2ef18ad4ca | |||
| 1a76fce255 | |||
| ee75a50d84 | |||
| 99d8d0bc63 | |||
| f859fe37ca | |||
| 451cb7a194 | |||
| 17175fe71e | |||
| f8b02f99dd | |||
| 69fb86322c | |||
| 4d683232b7 | |||
| cb7e0e4383 | |||
| 90b62762d3 | |||
| 787a9ae4e4 | |||
| 83be5ba63d | |||
| e1cad6189e | |||
| f29fc2a025 | |||
| 43d4c8d801 | |||
| c179f4d4f1 | |||
| ac8b3989be | |||
| 9a7b1a20dc | |||
| cff58bae7f | |||
| 2ee2d7d5d9 | |||
| 743759578d | |||
| 9f1d1fc45e | |||
| b4ea25dccb | |||
| f15551a6b5 | |||
| 5c0a654e1e | |||
| edace908fb | |||
| ff966eaf62 | |||
| a39b9b8890 | |||
| 9f39420808 | |||
| 67b5e86cc4 | |||
| baaa8b6537 | |||
| 4f776050e6 | |||
| fa490644dd | |||
| 0363806e7e | |||
| c0a608bfdd | |||
| fe26628113 | |||
| c7ead70e0f | |||
| 31177be88f | |||
| 48fd6bab7b | |||
| 9fd2b32665 | |||
| 1ba05d4c9c | |||
| bae3ccdfb5 | |||
| dd2f15c96d | |||
| 7e04a1b8d3 | |||
| aea70a14ff | |||
| 8edfc23679 | |||
| 87f3d45109 | |||
| 2ca07b47af |
+1
-1
@@ -6,7 +6,7 @@ build_doxygen_docker:
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULED_JOB_NAME == "doxygen"
|
||||
tags:
|
||||
- docker
|
||||
- gitlab-org-docker
|
||||
before_script:
|
||||
- docker info
|
||||
- docker login -u gitlab-ci-token -p "$CI_JOB_TOKEN" "$CI_REGISTRY"
|
||||
|
||||
+1
-19
@@ -15,25 +15,7 @@ macos_build:
|
||||
- cd build/macos
|
||||
- cmake
|
||||
-G Ninja
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DDEFAULT_INSTALL_PATH=/Library/Application\ Support /kicad
|
||||
-DOCC_INCLUDE_DIR=/opt/homebrew/Cellar/opencascade/7.7.2_2/include/opencascade
|
||||
-DOCC_LIBRARY_DIR=/opt/homebrew/Cellar/opencascade/7.7.2_2/Lib
|
||||
-DCMAKE_INSTALL_PREFIX=/Users/ci/kicad-mac-builder/build/kicad-dest
|
||||
-DCMAKE_C_COMPILER=/usr/bin/clang
|
||||
-DCMAKE_CXX_COMPILER=/usr/bin/clang++
|
||||
-DwxWidgets_CONFIG_EXECUTABLE=/Users/ci/kicad-mac-builder/build/wxwidgets-dest/bin/wx-config
|
||||
-DKICAD_BUILD_I18N=ON
|
||||
-DKICAD_SCRIPTING_WXPYTHON=ON
|
||||
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON
|
||||
-DPYTHON_EXECUTABLE=/Users/ci/kicad-mac-builder/build/python-dest/Library/Frameworks/Python.framework/Versions/Current/bin/python3
|
||||
-DPYTHON_INCLUDE_DIR=/Users/ci/kicad-mac-builder/build/python-dest/Library/Frameworks/Python.framework/Versions/Current/include/python3.9/
|
||||
-DPYTHON_LIBRARY=/Users/ci/kicad-mac-builder/build/python-dest/Library/Frameworks/Python.framework/Versions/Current/lib/libpython3.9.dylib
|
||||
-DPYTHON_SITE_PACKAGE_PATH=/Users/ci/kicad-mac-builder/build/python-dest/Library/Frameworks/Python.framework/Versions/Current/lib/python3.9/site-packages
|
||||
-DPYTHON_FRAMEWORK=/Users/ci/kicad-mac-builder/build/python-dest/Library/Frameworks/Python.framework
|
||||
-DNGSPICE_INCLUDE_DIR=/Users/ci/kicad-mac-builder/build/ngspice-dest/include
|
||||
-DNGSPICE_LIBRARY=/Users/ci/kicad-mac-builder/build/ngspice-dest/lib/libngspice.dylib
|
||||
-DKICAD_USE_3DCONNEXION=ON
|
||||
-DCMAKE_TOOLCHAIN_FILE=/Users/ci/kicad-mac-builder/toolchain/kicad-mac-builder.cmake
|
||||
../../
|
||||
- cmake --build . 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
|
||||
@@ -708,6 +708,8 @@ void BOARD_ADAPTER::SetLayerColors( const std::map<int, COLOR4D>& aColors )
|
||||
|
||||
for( const auto& [ layer, color ] : aColors )
|
||||
settings->SetColor( layer, color );
|
||||
|
||||
Pgm().GetSettingsManager().SaveColorSettings( settings, "3d_viewer" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <3d_rendering/opengl/render_3d_opengl.h>
|
||||
#include <3d_viewer_id.h>
|
||||
#include <advanced_config.h>
|
||||
#include <build_version.h>
|
||||
#include <board.h>
|
||||
#include <reporter.h>
|
||||
#include <gal/opengl/gl_context_mgr.h>
|
||||
@@ -229,6 +230,9 @@ bool EDA_3D_CANVAS::initializeOpenGL()
|
||||
From_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
|
||||
}
|
||||
|
||||
SetOpenGLInfo( (const char*) glGetString( GL_VENDOR ), (const char*) glGetString( GL_RENDERER ),
|
||||
(const char*) glGetString( GL_VERSION ) );
|
||||
|
||||
wxString version = From_UTF8( (char *) glGetString( GL_VERSION ) );
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::%s OpenGL version string %s." ),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 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
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "../3d_cache/3d_cache.h"
|
||||
#include <wx/dcclient.h>
|
||||
#include <base_units.h>
|
||||
#include <build_version.h>
|
||||
#include <gal/opengl/gl_context_mgr.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <pgm_base.h>
|
||||
@@ -200,6 +201,9 @@ void EDA_3D_MODEL_VIEWER::ogl_initialize()
|
||||
From_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
|
||||
}
|
||||
|
||||
SetOpenGLInfo( (const char*) glGetString( GL_VENDOR ), (const char*) glGetString( GL_RENDERER ),
|
||||
(const char*) glGetString( GL_VERSION ) );
|
||||
|
||||
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
|
||||
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
|
||||
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
|
||||
|
||||
@@ -138,7 +138,7 @@ void IMAGE_SIZE::SetUnit( EDA_UNITS aUnit )
|
||||
}
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE( BITMAP2CMP_FRAME, EDA_BASE_FRAME )
|
||||
BEGIN_EVENT_TABLE( BITMAP2CMP_FRAME, KIWAY_PLAYER )
|
||||
EVT_MENU( wxID_CLOSE, BITMAP2CMP_FRAME::OnExit )
|
||||
EVT_MENU( wxID_EXIT, BITMAP2CMP_FRAME::OnExit )
|
||||
|
||||
@@ -193,6 +193,7 @@ BITMAP2CMP_FRAME::BITMAP2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
m_toolManager->InitTools();
|
||||
|
||||
ReCreateMenuBar();
|
||||
setupUIConditions();
|
||||
|
||||
GetSizer()->SetSizeHints( this );
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ unset(_Python_NAMES)
|
||||
|
||||
set(_PYTHON1_VERSIONS 1.6 1.5)
|
||||
set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
|
||||
set(_PYTHON3_VERSIONS 3.12 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
|
||||
set(_PYTHON3_VERSIONS 3.13 3.12 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
|
||||
|
||||
# Disabling the "search every possible place" code for now
|
||||
# see https://gitlab.com/kicad/code/kicad/-/issues/8553
|
||||
|
||||
@@ -44,7 +44,7 @@ cmake_find_frameworks(Python)
|
||||
|
||||
set(_PYTHON1_VERSIONS 1.6 1.5)
|
||||
set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
|
||||
set(_PYTHON3_VERSIONS 3.12 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
|
||||
set(_PYTHON3_VERSIONS 3.13 3.12 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
|
||||
|
||||
if(PythonLibs_FIND_VERSION)
|
||||
if(PythonLibs_FIND_VERSION MATCHES "^[0-9]+\\.[0-9]+(\\.[0-9]+.*)?$")
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# KiCad.
|
||||
#
|
||||
# Note: This version string should follow the semantic versioning system
|
||||
set( KICAD_SEMANTIC_VERSION "8.0.2" )
|
||||
set( KICAD_SEMANTIC_VERSION "8.0.3" )
|
||||
|
||||
# Default the version to the semantic version.
|
||||
# This is overridden by the git repository tag though (if using git)
|
||||
|
||||
@@ -51,6 +51,19 @@ extern std::string GetCurlLibVersion();
|
||||
#include <kicad_build_version.h>
|
||||
#undef INCLUDE_KICAD_VERSION
|
||||
|
||||
// Remember OpenGL info
|
||||
static wxString s_glVendor;
|
||||
static wxString s_glRenderer;
|
||||
static wxString s_glVersion;
|
||||
|
||||
void SetOpenGLInfo( const char* aVendor, const char* aRenderer, const char* aVersion )
|
||||
{
|
||||
s_glVendor = wxString::FromUTF8( aVendor );
|
||||
s_glRenderer = wxString::FromUTF8( aRenderer );
|
||||
s_glVersion = wxString::FromUTF8( aVersion );
|
||||
}
|
||||
|
||||
|
||||
wxString GetPlatformGetBitnessName()
|
||||
{
|
||||
wxPlatformInfo platform;
|
||||
@@ -200,6 +213,12 @@ wxString GetVersionInfoData( const wxString& aTitle, bool aHtml, bool aBrief )
|
||||
<< ", " << wxGetenv( "XDG_SESSION_TYPE" );
|
||||
#endif
|
||||
|
||||
if( !s_glVendor.empty() || !s_glRenderer.empty() || !s_glVersion.empty() )
|
||||
{
|
||||
aMsg << eol;
|
||||
aMsg << "OpenGL: " << s_glVendor << ", " << s_glRenderer << ", " << s_glVersion;
|
||||
}
|
||||
|
||||
aMsg << eol << eol;
|
||||
|
||||
if( !aBrief )
|
||||
|
||||
@@ -347,6 +347,24 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "SelectOne: table `%s` not in row cache; will SelectAll" ),
|
||||
tableName, aWhere.second );
|
||||
|
||||
selectAllAndCache( tableName, aWhere.first );
|
||||
|
||||
if( m_cache->Get( tableName, cacheEntry ) )
|
||||
{
|
||||
if( cacheEntry.count( aWhere.second ) )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "SelectOne: `%s` with parameter `%s` - cache hit" ),
|
||||
tableName, aWhere.second );
|
||||
aResult = cacheEntry.at( aWhere.second );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_columnCache.count( tableName ) )
|
||||
{
|
||||
@@ -372,15 +390,14 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
|
||||
columnsFor( tableName ),
|
||||
m_quoteChar, tableName, m_quoteChar,
|
||||
m_quoteChar, columnName, m_quoteChar );
|
||||
|
||||
nanodbc::statement statement( *m_conn );
|
||||
nanodbc::string query = fromUTF8( queryStr );
|
||||
|
||||
PROF_TIMER timer;
|
||||
nanodbc::statement statement;
|
||||
|
||||
try
|
||||
{
|
||||
statement.prepare( query );
|
||||
statement.prepare( *m_conn, query );
|
||||
statement.bind( 0, aWhere.second.c_str() );
|
||||
}
|
||||
catch( nanodbc::database_error& e )
|
||||
@@ -474,44 +491,14 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
|
||||
}
|
||||
|
||||
|
||||
bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::string& aKey,
|
||||
std::vector<ROW>& aResults )
|
||||
bool DATABASE_CONNECTION::selectAllAndCache( const std::string& aTable, const std::string& aKey )
|
||||
{
|
||||
if( !m_conn )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "Called SelectAll without valid connection!" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
auto tableMapIter = m_tables.find( aTable );
|
||||
|
||||
if( tableMapIter == m_tables.end() )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll: requested table %s not found in cache" ),
|
||||
aTable );
|
||||
return false;
|
||||
}
|
||||
|
||||
DB_CACHE_TYPE::CACHE_VALUE cacheEntry;
|
||||
|
||||
if( m_cache->Get( aTable, cacheEntry ) )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll: `%s` - cache hit" ), aTable );
|
||||
|
||||
aResults.reserve( cacheEntry.size() );
|
||||
|
||||
for( auto &[ key, row ] : cacheEntry )
|
||||
aResults.emplace_back( row );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nanodbc::statement statement( *m_conn );
|
||||
|
||||
nanodbc::string query = fromUTF8( fmt::format( "SELECT {} FROM {}{}{}", columnsFor( aTable ),
|
||||
m_quoteChar, aTable, m_quoteChar ) );
|
||||
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll: `%s`" ), toUTF8( query ) );
|
||||
wxLogTrace( traceDatabase, wxT( "selectAllAndCache: `%s`" ), toUTF8( query ) );
|
||||
|
||||
PROF_TIMER timer;
|
||||
|
||||
@@ -522,7 +509,8 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
|
||||
catch( nanodbc::database_error& e )
|
||||
{
|
||||
m_lastError = e.what();
|
||||
wxLogTrace( traceDatabase, wxT( "Exception while preparing query for SelectAll: %s" ),
|
||||
wxLogTrace( traceDatabase,
|
||||
wxT( "Exception while preparing query for selectAllAndCache: %s" ),
|
||||
m_lastError );
|
||||
|
||||
// Exception may be due to a connection error; nanodbc won't auto-reconnect
|
||||
@@ -540,7 +528,8 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
|
||||
catch( nanodbc::database_error& e )
|
||||
{
|
||||
m_lastError = e.what();
|
||||
wxLogTrace( traceDatabase, wxT( "Exception while executing query for SelectAll: %s" ),
|
||||
wxLogTrace( traceDatabase,
|
||||
wxT( "Exception while executing query for selectAllAndCache: %s" ),
|
||||
m_lastError );
|
||||
|
||||
// Exception may be due to a connection error; nanodbc won't auto-reconnect
|
||||
@@ -551,15 +540,17 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
|
||||
|
||||
timer.Stop();
|
||||
|
||||
DB_CACHE_TYPE::CACHE_VALUE cacheEntry;
|
||||
|
||||
auto handleException =
|
||||
[&]( std::runtime_error& aException, const std::string& aExtraContext = "" )
|
||||
{
|
||||
m_lastError = aException.what();
|
||||
std::string extra = aExtraContext.empty() ? "" : ": " + aExtraContext;
|
||||
wxLogTrace( traceDatabase,
|
||||
wxT( "Exception while parsing result %d from SelectAll: %s%s" ),
|
||||
aResults.size(), m_lastError, extra );
|
||||
};
|
||||
{
|
||||
m_lastError = aException.what();
|
||||
std::string extra = aExtraContext.empty() ? "" : ": " + aExtraContext;
|
||||
wxLogTrace( traceDatabase,
|
||||
wxT( "Exception while parsing result %d from selectAllAndCache: %s%s" ),
|
||||
cacheEntry.size(), m_lastError, extra );
|
||||
};
|
||||
|
||||
while( results.next() )
|
||||
{
|
||||
@@ -636,20 +627,65 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
|
||||
}
|
||||
}
|
||||
|
||||
aResults.emplace_back( std::move( result ) );
|
||||
m_cache->Put( aTable, cacheEntry );
|
||||
wxASSERT( result.count( aKey ) );
|
||||
std::string keyStr = std::any_cast<std::string>( result.at( aKey ) );
|
||||
cacheEntry[keyStr] = result;
|
||||
}
|
||||
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll from %s completed in %0.1f ms" ), aTable,
|
||||
wxLogTrace( traceDatabase, wxT( "selectAllAndCache from %s completed in %0.1f ms" ), aTable,
|
||||
timer.msecs() );
|
||||
|
||||
for( const ROW& row : aResults )
|
||||
m_cache->Put( aTable, cacheEntry );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::string& aKey,
|
||||
std::vector<ROW>& aResults )
|
||||
{
|
||||
if( !m_conn )
|
||||
{
|
||||
wxASSERT( row.count( aKey ) );
|
||||
std::string keyStr = std::any_cast<std::string>( row.at( aKey ) );
|
||||
cacheEntry[keyStr] = row;
|
||||
wxLogTrace( traceDatabase, wxT( "Called SelectAll without valid connection!" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cache->Put( aTable, cacheEntry );
|
||||
auto tableMapIter = m_tables.find( aTable );
|
||||
|
||||
if( tableMapIter == m_tables.end() )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll: requested table %s not found in cache" ),
|
||||
aTable );
|
||||
return false;
|
||||
}
|
||||
|
||||
DB_CACHE_TYPE::CACHE_VALUE cacheEntry;
|
||||
|
||||
if( !m_cache->Get( aTable, cacheEntry ) )
|
||||
{
|
||||
if( !selectAllAndCache( aTable, aKey ) )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll: `%s` cache fill failed" ), aTable );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now it should be filled
|
||||
m_cache->Get( aTable, cacheEntry );
|
||||
}
|
||||
|
||||
if( !m_cache->Get( aTable, cacheEntry ) )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll: `%s` failed to get results from cache!" ),
|
||||
aTable );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll: `%s` - returning cached results" ), aTable );
|
||||
|
||||
aResults.reserve( cacheEntry.size() );
|
||||
|
||||
for( auto &[ key, row ] : cacheEntry )
|
||||
aResults.emplace_back( row );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -681,6 +681,35 @@ void DS_DATA_ITEM_TEXT::SetConstrainedTextSize()
|
||||
|
||||
if( m_ConstrainedTextSize.y == 0 )
|
||||
m_ConstrainedTextSize.y = DS_DATA_MODEL::GetTheInstance().m_DefaultTextSize.y;
|
||||
|
||||
if( m_BoundingBoxSize.x > 0 || m_BoundingBoxSize.y > 0 )
|
||||
{
|
||||
// to know the X and Y size of the line, we should use EDA_TEXT::GetTextBox()
|
||||
// but this function uses integers
|
||||
// So, to avoid truncations with our unit in mm, use microns.
|
||||
VECTOR2I size_micron;
|
||||
#define FSCALE 1000.0
|
||||
int linewidth = 0;
|
||||
size_micron.x = KiROUND( m_ConstrainedTextSize.x * FSCALE );
|
||||
size_micron.y = KiROUND( m_ConstrainedTextSize.y * FSCALE );
|
||||
DS_DRAW_ITEM_TEXT dummy( unityScale, this, 0, m_FullText, VECTOR2I( 0, 0 ), size_micron,
|
||||
linewidth, m_Font, m_Italic, m_Bold, m_TextColor );
|
||||
dummy.SetMultilineAllowed( true );
|
||||
dummy.SetHorizJustify( m_Hjustify ) ;
|
||||
dummy.SetVertJustify( m_Vjustify );
|
||||
dummy.SetTextAngle( EDA_ANGLE( m_Orient, DEGREES_T ) );
|
||||
|
||||
BOX2I rect = dummy.GetTextBox();
|
||||
VECTOR2D size;
|
||||
size.x = KiROUND( (int) rect.GetWidth() / FSCALE );
|
||||
size.y = KiROUND( (int) rect.GetHeight() / FSCALE );
|
||||
|
||||
if( m_BoundingBoxSize.x > 0 && size.x > m_BoundingBoxSize.x )
|
||||
m_ConstrainedTextSize.x *= m_BoundingBoxSize.x / size.x;
|
||||
|
||||
if( m_BoundingBoxSize.y > 0 && size.y > m_BoundingBoxSize.y )
|
||||
m_ConstrainedTextSize.y *= m_BoundingBoxSize.y / size.y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1991,13 +1991,13 @@ static struct EDA_SHAPE_DESC
|
||||
.SetAvailableFunc( isNotPolygonOrCircle );
|
||||
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Center X" ),
|
||||
&EDA_SHAPE::SetStartX, &EDA_SHAPE::GetStartX, PROPERTY_DISPLAY::PT_COORD,
|
||||
&EDA_SHAPE::SetCenterX, &EDA_SHAPE::GetStartX, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ),
|
||||
shapeProps )
|
||||
.SetAvailableFunc( isCircle );
|
||||
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Center Y" ),
|
||||
&EDA_SHAPE::SetStartY, &EDA_SHAPE::GetStartY, PROPERTY_DISPLAY::PT_COORD,
|
||||
&EDA_SHAPE::SetCenterY, &EDA_SHAPE::GetStartY, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ),
|
||||
shapeProps )
|
||||
.SetAvailableFunc( isCircle );
|
||||
|
||||
+5
-1
@@ -528,10 +528,13 @@ EDA_TEXT::GetRenderCache( const KIFONT::FONT* aFont, const wxString& forResolved
|
||||
}
|
||||
|
||||
|
||||
void EDA_TEXT::SetupRenderCache( const wxString& aResolvedText, const EDA_ANGLE& aAngle )
|
||||
void EDA_TEXT::SetupRenderCache( const wxString& aResolvedText, const KIFONT::FONT* aFont,
|
||||
const EDA_ANGLE& aAngle, const VECTOR2I& aOffset )
|
||||
{
|
||||
m_render_cache_text = aResolvedText;
|
||||
m_render_cache_font = aFont;
|
||||
m_render_cache_angle = aAngle;
|
||||
m_render_cache_offset = aOffset;
|
||||
m_render_cache.clear();
|
||||
}
|
||||
|
||||
@@ -539,6 +542,7 @@ void EDA_TEXT::SetupRenderCache( const wxString& aResolvedText, const EDA_ANGLE&
|
||||
void EDA_TEXT::AddRenderCacheGlyph( const SHAPE_POLY_SET& aPoly )
|
||||
{
|
||||
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( aPoly ) );
|
||||
static_cast<KIFONT::OUTLINE_GLYPH*>( m_render_cache.back().get() )->CacheTriangulation();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -259,6 +259,7 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||
struct GLYPH_CACHE_KEY {
|
||||
FT_Face face;
|
||||
hb_codepoint_t codepoint;
|
||||
double scaler;
|
||||
bool fakeItalic;
|
||||
bool fakeBold;
|
||||
bool mirror;
|
||||
@@ -266,7 +267,7 @@ struct GLYPH_CACHE_KEY {
|
||||
|
||||
bool operator==(const GLYPH_CACHE_KEY& rhs ) const
|
||||
{
|
||||
return face == rhs.face && codepoint == rhs.codepoint
|
||||
return face == rhs.face && codepoint == rhs.codepoint && scaler == rhs.scaler
|
||||
&& fakeItalic == rhs.fakeItalic && fakeBold == rhs.fakeBold
|
||||
&& mirror == rhs.mirror && angle == rhs.angle;
|
||||
}
|
||||
@@ -280,6 +281,7 @@ namespace std
|
||||
std::size_t operator()( const GLYPH_CACHE_KEY& k ) const
|
||||
{
|
||||
return hash<const void*>()( k.face ) ^ hash<unsigned>()( k.codepoint )
|
||||
^ hash<double>()( k.scaler )
|
||||
^ hash<int>()( k.fakeItalic ) ^ hash<int>()( k.fakeBold )
|
||||
^ hash<int>()( k.mirror ) ^ hash<int>()( k.angle.AsTenthsOfADegree() );
|
||||
}
|
||||
@@ -339,7 +341,7 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox,
|
||||
|
||||
if( aGlyphs )
|
||||
{
|
||||
GLYPH_CACHE_KEY key = { face, glyphInfo[i].codepoint, m_fakeItal, m_fakeBold,
|
||||
GLYPH_CACHE_KEY key = { face, glyphInfo[i].codepoint, scaler, m_fakeItal, m_fakeBold,
|
||||
aMirror, aAngle };
|
||||
GLYPH_DATA& glyphData = s_glyphCache[ key ];
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2012-2023 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2012-2024 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2013-2017 CERN
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
@@ -33,6 +33,7 @@
|
||||
#endif
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <build_version.h>
|
||||
#include <gal/opengl/opengl_gal.h>
|
||||
#include <gal/opengl/utils.h>
|
||||
#include <gal/definitions.h>
|
||||
@@ -2678,6 +2679,9 @@ void OPENGL_GAL::init()
|
||||
|
||||
#endif // KICAD_USE_EGL
|
||||
|
||||
SetOpenGLInfo( (const char*) glGetString( GL_VENDOR ), (const char*) glGetString( GL_RENDERER ),
|
||||
(const char*) glGetString( GL_VERSION ) );
|
||||
|
||||
if( GLEW_OK != err )
|
||||
throw std::runtime_error( (const char*) glewGetErrorString( err ) );
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2023-2024 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
|
||||
@@ -246,7 +246,7 @@ EASYEDA_PARSER_BASE::ParseLineChains( const wxString& data, int aArcMinSegLen, b
|
||||
arc.ConstructFromStartEndCenter( RelPos( start ), RelPos( end ), RelPos( arcCenter ),
|
||||
!cw );
|
||||
|
||||
chain.Append( arc );
|
||||
chain.Append( arc, aArcMinSegLen );
|
||||
|
||||
prevPt = end;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <wx/debug.h>
|
||||
#include <wx/filename.h>
|
||||
#include <set>
|
||||
#include <common.h>
|
||||
@@ -198,7 +199,16 @@ LIB_TABLE_ROW* LIB_TABLE::findRow( const wxString& aNickName, bool aCheckIfEnabl
|
||||
|
||||
do
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock( cur->m_mutex );
|
||||
try
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock( cur->m_mutex );
|
||||
}
|
||||
catch( std::system_error& e )
|
||||
{
|
||||
wxASSERT_MSG( false, wxString::Format( wxS( "Failed to lock lib table mutex: %s" ),
|
||||
e.what() ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( cur->m_rowsMap.count( aNickName ) )
|
||||
row = &*cur->m_rowsMap.at( aNickName );
|
||||
|
||||
+3
-4
@@ -153,6 +153,9 @@ PGM_BASE::~PGM_BASE()
|
||||
}
|
||||
|
||||
delete[] m_argvUtf8;
|
||||
|
||||
delete m_locale;
|
||||
m_locale = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,10 +167,6 @@ void PGM_BASE::Destroy()
|
||||
sentry_close();
|
||||
#endif
|
||||
|
||||
// unlike a normal destructor, this is designed to be called more than once safely:
|
||||
delete m_locale;
|
||||
m_locale = nullptr;
|
||||
|
||||
m_pgm_checker.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -160,6 +160,9 @@ APP_SETTINGS_BASE::APP_SETTINGS_BASE( const std::string& aFilename, int aSchemaV
|
||||
m_params.emplace_back( new PARAM<int>( "system.last_imperial_units",
|
||||
&m_System.last_imperial_units, static_cast<int>( EDA_UNITS::MILS ) ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "system.show_import_issues",
|
||||
&m_System.show_import_issues, true ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "appearance.color_theme",
|
||||
&m_ColorTheme, COLOR_SETTINGS::COLOR_BUILTIN_DEFAULT ) );
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ const wxString COLOR_SETTINGS::COLOR_BUILTIN_CLASSIC = "_builtin_classic";
|
||||
|
||||
|
||||
COLOR_SETTINGS::COLOR_SETTINGS( const wxString& aFilename, bool aAbsolutePath ) :
|
||||
JSON_SETTINGS( std::move( aFilename ), SETTINGS_LOC::COLORS, colorsSchemaVersion ),
|
||||
JSON_SETTINGS( aFilename, SETTINGS_LOC::COLORS, colorsSchemaVersion ),
|
||||
m_overrideSchItemColors( false )
|
||||
{
|
||||
if( aAbsolutePath )
|
||||
|
||||
@@ -455,8 +455,11 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||
|
||||
if( isMouseClick( type ) )
|
||||
{
|
||||
if( m_toolMgr->GetToolHolder() && m_toolMgr->GetToolHolder()->GetToolCanvas() )
|
||||
if( m_toolMgr->GetToolHolder() && m_toolMgr->GetToolHolder()->GetToolCanvas() &&
|
||||
!m_toolMgr->GetToolHolder()->GetToolCanvas()->HasFocus() )
|
||||
{
|
||||
m_toolMgr->GetToolHolder()->GetToolCanvas()->SetFocus();
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse handling
|
||||
|
||||
@@ -362,7 +362,11 @@ bool TOOL_MANAGER::doRunAction( const TOOL_ACTION& aAction, bool aNow, const std
|
||||
|
||||
while( synchronousControl == STS_RUNNING )
|
||||
{
|
||||
wxYield();
|
||||
wxYield(); // Needed to honor mouse (and other) events during editing
|
||||
wxMilliSleep( 1 ); // Needed to avoid 100% use of one cpu core.
|
||||
// The sleeping time must be must be small to avoid
|
||||
// noticeable lag in mouse and editing events
|
||||
// (1 to 5 ms is a good value)
|
||||
}
|
||||
|
||||
retVal = synchronousControl != STS_CANCELLED;
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#include <wx/log.h>
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#define USE_MOUSE_CAPTURE
|
||||
#define USE_MOUSE_CAPTURE
|
||||
#endif
|
||||
|
||||
using namespace KIGFX;
|
||||
@@ -694,7 +694,11 @@ void WX_VIEW_CONTROLS::CaptureCursor( bool aEnabled )
|
||||
// Note: for some reason, m_parentPanel->HasCapture() can be false even if CaptureMouse()
|
||||
// was called (i.e. mouse was captured, so when need to test m_MouseCapturedLost to be
|
||||
// sure a wxEVT_MOUSE_CAPTURE_LOST event was fired before. Otherwise wxMSW complains
|
||||
if( aEnabled && !m_parentPanel->HasCapture() && m_parentPanel->m_MouseCapturedLost )
|
||||
// The IsModalDialogFocused is checked because it's possible to start a capture
|
||||
// due to event ordering while a modal dialog was just opened, the mouse capture steels focus
|
||||
// from the modal and causes odd behavior
|
||||
if( aEnabled && !m_parentPanel->HasCapture() && m_parentPanel->m_MouseCapturedLost
|
||||
&& !KIUI::IsModalDialogFocused() )
|
||||
{
|
||||
m_parentPanel->CaptureMouse();
|
||||
|
||||
|
||||
@@ -213,13 +213,15 @@ protected:
|
||||
if( rawValue.IsEmpty() )
|
||||
rawValue = m_preselect;
|
||||
|
||||
wxString symbolId = escapeLibId( rawValue );
|
||||
KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_SYMBOL_CHOOSER, true, m_dlg );
|
||||
wxString symbolId = escapeLibId( rawValue );
|
||||
|
||||
if( frame->ShowModal( &symbolId, m_dlg ) )
|
||||
SetValue( UnescapeString( symbolId ) );
|
||||
if( KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_SYMBOL_CHOOSER, true, m_dlg ) )
|
||||
{
|
||||
if( frame->ShowModal( &symbolId, m_dlg ) )
|
||||
SetValue( UnescapeString( symbolId ) );
|
||||
|
||||
frame->Destroy();
|
||||
frame->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
DIALOG_SHIM* m_dlg;
|
||||
@@ -267,18 +269,26 @@ protected:
|
||||
if( fpid.IsEmpty() )
|
||||
fpid = m_preselect;
|
||||
|
||||
KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg );
|
||||
// Disable the button until we have finished processing it. Normally this is not an issue
|
||||
// but if the footprint chooser is loading for the first time, it can be slow enough that
|
||||
// multiple clicks will cause multiple instances of the footprint loader process to start
|
||||
Disable();
|
||||
|
||||
if( !m_symbolNetlist.empty() )
|
||||
if( KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ) )
|
||||
{
|
||||
KIWAY_EXPRESS event( FRAME_FOOTPRINT_CHOOSER, MAIL_SYMBOL_NETLIST, m_symbolNetlist );
|
||||
frame->KiwayMailIn( event );
|
||||
if( !m_symbolNetlist.empty() )
|
||||
{
|
||||
KIWAY_EXPRESS event( FRAME_FOOTPRINT_CHOOSER, MAIL_SYMBOL_NETLIST, m_symbolNetlist );
|
||||
frame->KiwayMailIn( event );
|
||||
}
|
||||
|
||||
if( frame->ShowModal( &fpid, m_dlg ) )
|
||||
SetValue( fpid );
|
||||
|
||||
frame->Destroy();
|
||||
}
|
||||
|
||||
if( frame->ShowModal( &fpid, m_dlg ) )
|
||||
SetValue( fpid );
|
||||
|
||||
frame->Destroy();
|
||||
Enable();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -725,18 +725,6 @@ void LIB_TREE::onIdle( wxIdleEvent& aEvent )
|
||||
|
||||
if( m_previewItem.IsOk() )
|
||||
{
|
||||
// Scroll checker
|
||||
if( m_tree_ctrl->GetItemRect( m_previewItem ) != m_previewItemRect )
|
||||
{
|
||||
hidePreview();
|
||||
|
||||
m_hoverPos = clientPos;
|
||||
m_hoverItem = item;
|
||||
m_hoverItemRect = m_tree_ctrl->GetItemRect( m_hoverItem );
|
||||
m_hoverTimer.StartOnce( HOVER_TIMER_MILLIS );
|
||||
return;
|
||||
}
|
||||
|
||||
if( item != m_previewItem )
|
||||
{
|
||||
#ifdef __WXGTK__
|
||||
|
||||
@@ -406,14 +406,19 @@ void PROPERTIES_PANEL::onShow( wxShowEvent& aEvent )
|
||||
{
|
||||
if( aEvent.IsShown() )
|
||||
UpdateData();
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
|
||||
void PROPERTIES_PANEL::onCharHook( wxKeyEvent& aEvent )
|
||||
{
|
||||
if( aEvent.GetKeyCode() == WXK_TAB && !aEvent.ShiftDown() )
|
||||
if( aEvent.GetKeyCode() == WXK_TAB && !aEvent.ShiftDown() && m_grid->IsAnyModified() )
|
||||
{
|
||||
m_grid->CommitChangesFromEditor();
|
||||
|
||||
// Pass the tab key on so the default property grid tab behavior is honored.
|
||||
aEvent.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ protected:
|
||||
virtual wxPGProperty* createPGProperty( const PROPERTY_BASE* aProperty ) const = 0;
|
||||
|
||||
// Event handlers
|
||||
virtual void valueChanging( wxPropertyGridEvent& aEvent ) {}
|
||||
virtual void valueChanged( wxPropertyGridEvent& aEvent ) {}
|
||||
virtual void valueChanging( wxPropertyGridEvent& aEvent ) { aEvent.Skip(); }
|
||||
virtual void valueChanged( wxPropertyGridEvent& aEvent ) { aEvent.Skip(); }
|
||||
void onCharHook( wxKeyEvent& aEvent );
|
||||
void onShow( wxShowEvent& aEvent );
|
||||
|
||||
|
||||
@@ -991,8 +991,19 @@ void CVPCB_MAINFRAME::BuildLibrariesList()
|
||||
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
|
||||
PROJECT_FILE& project = Kiway().Prj().GetProjectFile();
|
||||
FP_LIB_TABLE* tbl = PROJECT_PCB::PcbFootprintLibs( &Prj() );
|
||||
std::set<wxString> pinnedMatches;
|
||||
std::set<wxString> otherMatches;
|
||||
|
||||
// Use same sorting algorithm as LIB_TREE_NODE::AssignIntrinsicRanks
|
||||
struct library_sort
|
||||
{
|
||||
bool operator()( const wxString& lhs, const wxString& rhs ) const
|
||||
{
|
||||
return StrNumCmp( lhs, rhs, true ) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
std::set<wxString, library_sort> pinnedMatches;
|
||||
std::set<wxString, library_sort> otherMatches;
|
||||
|
||||
m_librariesListBox->ClearList();
|
||||
|
||||
auto process =
|
||||
|
||||
@@ -176,11 +176,11 @@ int CVPCB_CONTROL::ShowFootprintViewer( const TOOL_EVENT& aEvent )
|
||||
|
||||
fpframe = (DISPLAY_FOOTPRINTS_FRAME*) m_frame->Kiway().Player( FRAME_CVPCB_DISPLAY, true,
|
||||
m_frame );
|
||||
|
||||
// If Kiway() cannot create the eeschema frame, it shows a error message, and
|
||||
// frame is null
|
||||
if( !fpframe )
|
||||
{
|
||||
wxMessageBox( _( "Unable to create the footprint viewer frame" ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
fpframe->Show( true );
|
||||
}
|
||||
|
||||
@@ -397,6 +397,7 @@ set( EESCHEMA_SRCS
|
||||
symbol_tree_model_adapter.cpp
|
||||
symbol_tree_synchronizing_adapter.cpp
|
||||
symbol_viewer_frame.cpp
|
||||
symb_transforms_utils.cpp
|
||||
toolbars_sch_editor.cpp
|
||||
toolbars_symbol_viewer.cpp
|
||||
|
||||
|
||||
@@ -248,15 +248,16 @@ void DIALOG_CHANGE_SYMBOLS::launchMatchIdSymbolBrowser( wxCommandEvent& aEvent )
|
||||
{
|
||||
wxString newName = getLibIdValue( m_specifiedId );
|
||||
|
||||
KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this );
|
||||
|
||||
if( frame->ShowModal( &newName, this ) )
|
||||
if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this ) )
|
||||
{
|
||||
m_specifiedId->SetValue( UnescapeString( newName ) );
|
||||
updateFieldsList();
|
||||
}
|
||||
if( frame->ShowModal( &newName, this ) )
|
||||
{
|
||||
m_specifiedId->SetValue( UnescapeString( newName ) );
|
||||
updateFieldsList();
|
||||
}
|
||||
|
||||
frame->Destroy();
|
||||
frame->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -264,15 +265,16 @@ void DIALOG_CHANGE_SYMBOLS::launchNewIdSymbolBrowser( wxCommandEvent& aEvent )
|
||||
{
|
||||
wxString newName = getLibIdValue( m_newId );
|
||||
|
||||
KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this );
|
||||
|
||||
if( frame->ShowModal( &newName, this ) )
|
||||
if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_SYMBOL_CHOOSER, true, this ) )
|
||||
{
|
||||
m_newId->SetValue( UnescapeString( newName ) );
|
||||
updateFieldsList();
|
||||
}
|
||||
if( frame->ShowModal( &newName, this ) )
|
||||
{
|
||||
m_newId->SetValue( UnescapeString( newName ) );
|
||||
updateFieldsList();
|
||||
}
|
||||
|
||||
frame->Destroy();
|
||||
frame->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
|
||||
m_currentSchematic = &parent->Schematic();
|
||||
|
||||
SetName( DIALOG_ERC_WINDOW_NAME ); // Set a window name to be able to find it
|
||||
KIPLATFORM::UI::SetFloatLevel( this );
|
||||
|
||||
EESCHEMA_SETTINGS* settings = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
|
||||
m_severities = settings->m_Appearance.erc_severities;
|
||||
@@ -466,6 +467,8 @@ void DIALOG_ERC::OnRunERCClick( wxCommandEvent& event )
|
||||
m_ercRun = true;
|
||||
redrawDrawPanel();
|
||||
updateDisplayedCounts();
|
||||
// set float level again, it can be lost due to window events during test run
|
||||
KIPLATFORM::UI::SetFloatLevel( this );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -501,7 +501,7 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
|
||||
|
||||
if( m_sheet->GetScreen() == nullptr ) // New just created sheet.
|
||||
{
|
||||
if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
|
||||
if( !m_frame->AllowCaseSensitiveFileNameClashes( m_sheet->GetFileName(), newAbsoluteFilename ) )
|
||||
return false;
|
||||
|
||||
if( useScreen || loadFromFile ) // Load from existing file.
|
||||
@@ -526,7 +526,7 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
|
||||
{
|
||||
isExistingSheet = true;
|
||||
|
||||
if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
|
||||
if( !m_frame->AllowCaseSensitiveFileNameClashes( m_sheet->GetFileName(), newAbsoluteFilename ) )
|
||||
return false;
|
||||
|
||||
// We are always using here a case insensitive comparison to avoid issues
|
||||
@@ -640,7 +640,7 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
|
||||
|
||||
SCH_SHEET_LIST sheetHierarchy( m_sheet ); // The hierarchy of the loaded file.
|
||||
|
||||
sheetHierarchy.AddNewSymbolInstances( currentSheet );
|
||||
sheetHierarchy.AddNewSymbolInstances( currentSheet, m_frame->Prj().GetProjectName() );
|
||||
sheetHierarchy.AddNewSheetInstances( currentSheet,
|
||||
fullHierarchy.GetLastVirtualPageNumber() );
|
||||
}
|
||||
|
||||
@@ -109,14 +109,15 @@ protected:
|
||||
if( event.GetId() == MYID_SELECT_FOOTPRINT )
|
||||
{
|
||||
// pick a footprint using the footprint picker.
|
||||
wxString fpid = m_grid->GetCellValue( m_grid->GetGridCursorRow(),
|
||||
FOOTPRINT_FIELD );
|
||||
KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg );
|
||||
wxString fpid = m_grid->GetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT_FIELD );
|
||||
|
||||
if( frame->ShowModal( &fpid, m_dlg ) )
|
||||
m_grid->SetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT_FIELD, fpid );
|
||||
if( KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ) )
|
||||
{
|
||||
if( frame->ShowModal( &fpid, m_dlg ) )
|
||||
m_grid->SetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT_FIELD, fpid );
|
||||
|
||||
frame->Destroy();
|
||||
frame->Destroy();
|
||||
}
|
||||
}
|
||||
else if (event.GetId() == MYID_SHOW_DATASHEET )
|
||||
{
|
||||
@@ -305,7 +306,7 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent )
|
||||
case SCOPE::SCOPE_SHEET_RECURSIVE: m_radioRecursive->SetValue( true ); break;
|
||||
}
|
||||
|
||||
m_outputFileName->SetValue( cfg->m_FieldEditorPanel.export_filename );
|
||||
m_outputFileName->SetValue( m_schSettings.m_BomExportFileName );
|
||||
|
||||
Center();
|
||||
|
||||
@@ -1338,12 +1339,13 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnClose( wxCloseEvent& aEvent )
|
||||
|
||||
// Save all our settings since we're really closing
|
||||
savePresetsToSchematic();
|
||||
m_schSettings.m_BomExportFileName = m_outputFileName->GetValue();
|
||||
|
||||
EESCHEMA_SETTINGS* cfg = m_parent->eeconfig();
|
||||
|
||||
cfg->m_FieldEditorPanel.width = GetSize().x;
|
||||
cfg->m_FieldEditorPanel.height = GetSize().y;
|
||||
cfg->m_FieldEditorPanel.page = m_nbPages->GetSelection();
|
||||
cfg->m_FieldEditorPanel.export_filename = m_outputFileName->GetValue();
|
||||
|
||||
if( m_radioHighlight->GetValue() )
|
||||
cfg->m_FieldEditorPanel.selection_mode = 0;
|
||||
|
||||
@@ -102,6 +102,7 @@ void SCH_EDIT_FRAME::ShowSchematicSetupDialog( const wxString& aInitialPage )
|
||||
|
||||
Prj().IncrementTextVarsTicker();
|
||||
Prj().IncrementNetclassesTicker();
|
||||
Pgm().GetSettingsManager().SaveProject();
|
||||
|
||||
GetRenderSettings()->SetDefaultPenWidth( Schematic().Settings().m_DefaultLineWidth );
|
||||
GetRenderSettings()->m_LabelSizeRatio = Schematic().Settings().m_LabelSizeRatio;
|
||||
|
||||
@@ -740,7 +740,7 @@ int EESCHEMA_JOBS_HANDLER::doSymExportSvg( JOB_SYM_EXPORT_SVG* aSvgJob,
|
||||
}
|
||||
|
||||
// Get the symbol bounding box to fit the plot page to it
|
||||
BOX2I symbolBB = symbol->Flatten()->GetUnitBoundingBox( unit, bodyStyle, false );
|
||||
BOX2I symbolBB = symbol->Flatten()->GetUnitBoundingBox( unit, bodyStyle, !aSvgJob->m_includeHiddenFields );
|
||||
PAGE_INFO pageInfo( PAGE_INFO::Custom );
|
||||
pageInfo.SetHeightMils( schIUScale.IUToMils( symbolBB.GetHeight() * 1.2 ) );
|
||||
pageInfo.SetWidthMils( schIUScale.IUToMils( symbolBB.GetWidth() * 1.2 ) );
|
||||
@@ -750,7 +750,7 @@ int EESCHEMA_JOBS_HANDLER::doSymExportSvg( JOB_SYM_EXPORT_SVG* aSvgJob,
|
||||
plotter->SetPageSettings( pageInfo );
|
||||
plotter->SetColorMode( !aSvgJob->m_blackAndWhite );
|
||||
|
||||
VECTOR2I plot_offset;
|
||||
VECTOR2I plot_offset = symbolBB.GetCenter();
|
||||
const double scale = 1.0;
|
||||
|
||||
// Currently, plot units are in decimal
|
||||
|
||||
@@ -946,13 +946,15 @@ void FIELDS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
|
||||
if( event.GetId() == MYID_SELECT_FOOTPRINT )
|
||||
{
|
||||
// pick a footprint using the footprint picker.
|
||||
wxString fpid = m_grid->GetCellValue( FOOTPRINT_FIELD, FDC_VALUE );
|
||||
KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg );
|
||||
wxString fpid = m_grid->GetCellValue( FOOTPRINT_FIELD, FDC_VALUE );
|
||||
|
||||
if( frame->ShowModal( &fpid, m_dlg ) )
|
||||
m_grid->SetCellValue( FOOTPRINT_FIELD, FDC_VALUE, fpid );
|
||||
if( KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ) )
|
||||
{
|
||||
if( frame->ShowModal( &fpid, m_dlg ) )
|
||||
m_grid->SetCellValue( FOOTPRINT_FIELD, FDC_VALUE, fpid );
|
||||
|
||||
frame->Destroy();
|
||||
frame->Destroy();
|
||||
}
|
||||
}
|
||||
else if (event.GetId() == MYID_SHOW_DATASHEET )
|
||||
{
|
||||
|
||||
+13
-2
@@ -61,6 +61,7 @@
|
||||
#include <tools/sch_editor_control.h>
|
||||
#include <tools/sch_navigate_tool.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <widgets/filedlg_import_non_kicad.h>
|
||||
#include <widgets/wx_infobar.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
#include <drawing_sheet/ds_data_model.h>
|
||||
@@ -730,9 +731,14 @@ void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
|
||||
wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString, fileFiltersStr,
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST ); // TODO
|
||||
|
||||
FILEDLG_IMPORT_NON_KICAD importOptions( eeconfig()->m_System.show_import_issues );
|
||||
dlg.SetCustomizeHook( importOptions );
|
||||
|
||||
if( dlg.ShowModal() == wxID_CANCEL )
|
||||
return;
|
||||
|
||||
eeconfig()->m_System.show_import_issues = importOptions.GetShowIssues();
|
||||
|
||||
// Don't leave dangling pointers to previously-opened document.
|
||||
m_toolManager->GetTool<EE_SELECTION_TOOL>()->ClearSelection();
|
||||
ClearUndoRedoList();
|
||||
@@ -1383,7 +1389,11 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
|
||||
std::placeholders::_1 ) );
|
||||
}
|
||||
|
||||
pi->SetReporter( errorReporter.m_Reporter );
|
||||
if( eeconfig()->m_System.show_import_issues )
|
||||
pi->SetReporter( errorReporter.m_Reporter );
|
||||
else
|
||||
pi->SetReporter( &NULL_REPORTER::GetInstance() );
|
||||
|
||||
pi->SetProgressReporter( &progressReporter );
|
||||
|
||||
SCH_SHEET* loadedSheet =
|
||||
@@ -1650,7 +1660,8 @@ void SCH_EDIT_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName )
|
||||
}
|
||||
// Attempt to back up the last schematic file before overwriting it with the auto
|
||||
// save file.
|
||||
else if( !wxCopyFile( recoveredFn.GetFullPath(), backupFn.GetFullPath() ) )
|
||||
else if( recoveredFn.Exists()
|
||||
&& !wxCopyFile( recoveredFn.GetFullPath(), backupFn.GetFullPath() ) )
|
||||
{
|
||||
unrecoveredFiles.Add( recoveredFn.GetFullPath() );
|
||||
}
|
||||
|
||||
@@ -664,6 +664,11 @@ static struct LIB_FIELD_DESC
|
||||
propMgr.Mask( TYPE_HASH( LIB_FIELD ), TYPE_HASH( EDA_TEXT ), _HKI( "Width" ) );
|
||||
propMgr.Mask( TYPE_HASH( LIB_FIELD ), TYPE_HASH( EDA_TEXT ), _HKI( "Height" ) );
|
||||
|
||||
propMgr.AddProperty( new PROPERTY<LIB_FIELD, int>(
|
||||
_HKI( "Text Size" ), &LIB_FIELD::SetLibTextSize,
|
||||
&LIB_FIELD::GetLibTextSize, PROPERTY_DISPLAY::PT_SIZE ),
|
||||
_HKI( "Text Properties" ) );
|
||||
|
||||
propMgr.Mask( TYPE_HASH( LIB_FIELD ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
|
||||
}
|
||||
} _LIB_FIELD_DESC;
|
||||
|
||||
@@ -161,6 +161,9 @@ public:
|
||||
|
||||
wxString GetShownText( bool aAllowExtraText, int aDepth = 0 ) const override;
|
||||
|
||||
int GetLibTextSize() const { return GetTextWidth(); }
|
||||
void SetLibTextSize( int aSize ) { SetTextSize( VECTOR2I( aSize, aSize ) ); }
|
||||
|
||||
SCH_LAYER_ID GetDefaultLayer() const;
|
||||
|
||||
void BeginEdit( const VECTOR2I& aStartPoint ) override;
|
||||
|
||||
@@ -159,6 +159,7 @@ public:
|
||||
virtual void SetName( const wxString& aName );
|
||||
wxString GetName() const override { return m_name; }
|
||||
|
||||
const LIB_ID& LibId() const { return m_libId; }
|
||||
LIB_ID& LibId() { return m_libId; }
|
||||
LIB_ID GetLibId() const override { return m_libId; }
|
||||
void SetLibId( const LIB_ID& aLibId ) { m_libId = aLibId; }
|
||||
|
||||
@@ -479,7 +479,8 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
|
||||
|
||||
auto spiceGenerator = static_cast<const SPICE_GENERATOR_KIBIS&>( kibisModel->SpiceGenerator() );
|
||||
std::string modelData = spiceGenerator.IbisDevice(
|
||||
aItem, m_schematic->Prj(), cacheFn.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
|
||||
aItem, m_schematic->Prj(),
|
||||
cacheFn.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ), aReporter );
|
||||
|
||||
cacheFile.Write( wxString( modelData ) );
|
||||
m_rawIncludes.insert( cacheFn.GetFullPath() );
|
||||
|
||||
+89
-82
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <bitmaps.h>
|
||||
#include <cstddef>
|
||||
#include <core/arraydim.h>
|
||||
#include <magic_enum.hpp>
|
||||
#include <lib_pin.h>
|
||||
#include "pgm_base.h"
|
||||
@@ -47,56 +46,18 @@ struct pinTypeStruct
|
||||
BITMAPS bitmap;
|
||||
};
|
||||
|
||||
|
||||
std::map<ELECTRICAL_PINTYPE, struct pinTypeStruct> g_pinTypes = {
|
||||
{ ELECTRICAL_PINTYPE::PT_INPUT, { _( "Input" ), BITMAPS::pintype_input } },
|
||||
{ ELECTRICAL_PINTYPE::PT_OUTPUT, { _( "Output" ), BITMAPS::pintype_output } },
|
||||
{ ELECTRICAL_PINTYPE::PT_BIDI, { _( "Bidirectional" ), BITMAPS::pintype_bidi } },
|
||||
{ ELECTRICAL_PINTYPE::PT_TRISTATE, { _( "Tri-state" ), BITMAPS::pintype_3states } },
|
||||
{ ELECTRICAL_PINTYPE::PT_PASSIVE, { _( "Passive" ), BITMAPS::pintype_passive } },
|
||||
{ ELECTRICAL_PINTYPE::PT_NIC, { _( "Free" ), BITMAPS::pintype_nic } },
|
||||
{ ELECTRICAL_PINTYPE::PT_UNSPECIFIED, { _( "Unspecified" ), BITMAPS::pintype_notspecif } },
|
||||
{ ELECTRICAL_PINTYPE::PT_POWER_IN, { _( "Power input" ), BITMAPS::pintype_powerinput } },
|
||||
{ ELECTRICAL_PINTYPE::PT_POWER_OUT, { _( "Power output" ), BITMAPS::pintype_poweroutput } },
|
||||
{ ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR,{ _( "Open collector" ), BITMAPS::pintype_opencoll } },
|
||||
{ ELECTRICAL_PINTYPE::PT_OPENEMITTER, { _( "Open emitter" ), BITMAPS::pintype_openemit } },
|
||||
{ ELECTRICAL_PINTYPE::PT_NC, { _( "Unconnected" ), BITMAPS::pintype_noconnect } },
|
||||
};
|
||||
|
||||
|
||||
int g_pinTypesLanguage = wxLANGUAGE_UNKNOWN;
|
||||
|
||||
|
||||
struct pinShapeStruct
|
||||
{
|
||||
wxString name;
|
||||
BITMAPS bitmap;
|
||||
};
|
||||
|
||||
|
||||
// clang-format off
|
||||
const std::map<GRAPHIC_PINSHAPE, struct pinShapeStruct> pinShapes = {
|
||||
{ GRAPHIC_PINSHAPE::LINE, { _( "Line" ), BITMAPS::pinshape_normal } },
|
||||
{ GRAPHIC_PINSHAPE::INVERTED, { _( "Inverted" ), BITMAPS::pinshape_invert } },
|
||||
{ GRAPHIC_PINSHAPE::CLOCK, { _( "Clock" ), BITMAPS::pinshape_clock_normal } },
|
||||
{ GRAPHIC_PINSHAPE::INVERTED_CLOCK, { _( "Inverted clock" ), BITMAPS::pinshape_clock_invert } },
|
||||
{ GRAPHIC_PINSHAPE::INPUT_LOW, { _( "Input low" ), BITMAPS::pinshape_active_low_input } },
|
||||
{ GRAPHIC_PINSHAPE::CLOCK_LOW, { _( "Clock low" ), BITMAPS::pinshape_clock_active_low } },
|
||||
{ GRAPHIC_PINSHAPE::OUTPUT_LOW, { _( "Output low" ), BITMAPS::pinshape_active_low_output } },
|
||||
{ GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK, { _( "Falling edge clock" ), BITMAPS::pinshape_clock_fall } },
|
||||
{ GRAPHIC_PINSHAPE::NONLOGIC, { _( "NonLogic" ), BITMAPS::pinshape_nonlogic } },
|
||||
};
|
||||
// clang-format on
|
||||
static std::map<ELECTRICAL_PINTYPE, struct pinTypeStruct> g_pinElectricalTypes;
|
||||
static std::map<GRAPHIC_PINSHAPE, struct pinShapeStruct> g_pinShapes;
|
||||
static std::map<PIN_ORIENTATION, struct pinShapeStruct> g_pinOrientations;
|
||||
|
||||
|
||||
// clang-format off
|
||||
std::map<PIN_ORIENTATION, struct pinShapeStruct> pinOrientations = {
|
||||
{ PIN_ORIENTATION::PIN_RIGHT, { _( "Right" ), BITMAPS::pinorient_right } },
|
||||
{ PIN_ORIENTATION::PIN_LEFT, { _( "Left" ), BITMAPS::pinorient_left } },
|
||||
{ PIN_ORIENTATION::PIN_UP, { _( "Up" ), BITMAPS::pinorient_up } },
|
||||
{ PIN_ORIENTATION::PIN_DOWN, { _( "Down" ), BITMAPS::pinorient_down } },
|
||||
};
|
||||
// clang-format on
|
||||
static int g_language = wxLANGUAGE_UNKNOWN;
|
||||
|
||||
|
||||
PIN_ORIENTATION PinOrientationCode( size_t index )
|
||||
@@ -119,18 +80,65 @@ int PinOrientationIndex( PIN_ORIENTATION code )
|
||||
|
||||
void InitTables()
|
||||
{
|
||||
// clang-format off
|
||||
g_pinElectricalTypes = {
|
||||
{ ELECTRICAL_PINTYPE::PT_INPUT, { _( "Input" ), BITMAPS::pintype_input } },
|
||||
{ ELECTRICAL_PINTYPE::PT_OUTPUT, { _( "Output" ), BITMAPS::pintype_output } },
|
||||
{ ELECTRICAL_PINTYPE::PT_BIDI, { _( "Bidirectional" ), BITMAPS::pintype_bidi } },
|
||||
{ ELECTRICAL_PINTYPE::PT_TRISTATE, { _( "Tri-state" ), BITMAPS::pintype_3states } },
|
||||
{ ELECTRICAL_PINTYPE::PT_PASSIVE, { _( "Passive" ), BITMAPS::pintype_passive } },
|
||||
{ ELECTRICAL_PINTYPE::PT_NIC, { _( "Free" ), BITMAPS::pintype_nic } },
|
||||
{ ELECTRICAL_PINTYPE::PT_UNSPECIFIED, { _( "Unspecified" ), BITMAPS::pintype_notspecif } },
|
||||
{ ELECTRICAL_PINTYPE::PT_POWER_IN, { _( "Power input" ), BITMAPS::pintype_powerinput } },
|
||||
{ ELECTRICAL_PINTYPE::PT_POWER_OUT, { _( "Power output" ), BITMAPS::pintype_poweroutput } },
|
||||
{ ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR, { _( "Open collector" ), BITMAPS::pintype_opencoll } },
|
||||
{ ELECTRICAL_PINTYPE::PT_OPENEMITTER, { _( "Open emitter" ), BITMAPS::pintype_openemit } },
|
||||
{ ELECTRICAL_PINTYPE::PT_NC, { _( "Unconnected" ), BITMAPS::pintype_noconnect } },
|
||||
};
|
||||
|
||||
g_pinShapes = {
|
||||
{ GRAPHIC_PINSHAPE::LINE, { _( "Line" ), BITMAPS::pinshape_normal } },
|
||||
{ GRAPHIC_PINSHAPE::INVERTED, { _( "Inverted" ), BITMAPS::pinshape_invert } },
|
||||
{ GRAPHIC_PINSHAPE::CLOCK, { _( "Clock" ), BITMAPS::pinshape_clock_normal } },
|
||||
{ GRAPHIC_PINSHAPE::INVERTED_CLOCK, { _( "Inverted clock" ), BITMAPS::pinshape_clock_invert } },
|
||||
{ GRAPHIC_PINSHAPE::INPUT_LOW, { _( "Input low" ), BITMAPS::pinshape_active_low_input } },
|
||||
{ GRAPHIC_PINSHAPE::CLOCK_LOW, { _( "Clock low" ), BITMAPS::pinshape_clock_active_low } },
|
||||
{ GRAPHIC_PINSHAPE::OUTPUT_LOW, { _( "Output low" ), BITMAPS::pinshape_active_low_output } },
|
||||
{ GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK, { _( "Falling edge clock" ), BITMAPS::pinshape_clock_fall } },
|
||||
{ GRAPHIC_PINSHAPE::NONLOGIC, { _( "NonLogic" ), BITMAPS::pinshape_nonlogic } },
|
||||
};
|
||||
|
||||
g_pinOrientations = {
|
||||
{ PIN_ORIENTATION::PIN_RIGHT, { _( "Right" ), BITMAPS::pinorient_right } },
|
||||
{ PIN_ORIENTATION::PIN_LEFT, { _( "Left" ), BITMAPS::pinorient_left } },
|
||||
{ PIN_ORIENTATION::PIN_UP, { _( "Up" ), BITMAPS::pinorient_up } },
|
||||
{ PIN_ORIENTATION::PIN_DOWN, { _( "Down" ), BITMAPS::pinorient_down } },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
g_language = Pgm().GetSelectedLanguageIdentifier();
|
||||
|
||||
g_typeIcons.clear();
|
||||
g_typeNames.clear();
|
||||
|
||||
for( unsigned i = 0; i < ELECTRICAL_PINTYPES_TOTAL; ++i )
|
||||
{
|
||||
g_typeIcons.push_back( ElectricalPinTypeGetBitmap( static_cast<ELECTRICAL_PINTYPE>( i ) ) );
|
||||
g_typeNames.push_back( ElectricalPinTypeGetText( static_cast<ELECTRICAL_PINTYPE>( i ) ) );
|
||||
}
|
||||
|
||||
g_shapeIcons.clear();
|
||||
g_shapeNames.clear();
|
||||
|
||||
for( unsigned i = 0; i < GRAPHIC_PINSHAPES_TOTAL; ++i )
|
||||
{
|
||||
g_shapeIcons.push_back( PinShapeGetBitmap( static_cast<GRAPHIC_PINSHAPE>( i ) ) );
|
||||
g_shapeNames.push_back( PinShapeGetText( static_cast<GRAPHIC_PINSHAPE>( i ) ) );
|
||||
}
|
||||
|
||||
g_orientationIcons.clear();
|
||||
g_orientationNames.clear();
|
||||
|
||||
for( PIN_ORIENTATION orientation : magic_enum::enum_values<PIN_ORIENTATION>() )
|
||||
{
|
||||
g_orientationIcons.push_back( PinOrientationGetBitmap( orientation ) );
|
||||
@@ -141,7 +149,7 @@ void InitTables()
|
||||
|
||||
const wxArrayString& PinTypeNames()
|
||||
{
|
||||
if( g_typeNames.empty() )
|
||||
if( g_typeNames.empty() || g_language != Pgm().GetSelectedLanguageIdentifier() )
|
||||
InitTables();
|
||||
|
||||
return g_typeNames;
|
||||
@@ -159,7 +167,7 @@ const std::vector<BITMAPS>& PinTypeIcons()
|
||||
|
||||
const wxArrayString& PinShapeNames()
|
||||
{
|
||||
if( g_shapeNames.empty() )
|
||||
if( g_shapeNames.empty() || g_language != Pgm().GetSelectedLanguageIdentifier() )
|
||||
InitTables();
|
||||
|
||||
return g_shapeNames;
|
||||
@@ -177,7 +185,7 @@ const std::vector<BITMAPS>& PinShapeIcons()
|
||||
|
||||
const wxArrayString& PinOrientationNames()
|
||||
{
|
||||
if( g_orientationNames.empty() )
|
||||
if( g_orientationNames.empty() || g_language != Pgm().GetSelectedLanguageIdentifier() )
|
||||
InitTables();
|
||||
|
||||
return g_orientationNames;
|
||||
@@ -195,78 +203,77 @@ const std::vector<BITMAPS>& PinOrientationIcons()
|
||||
|
||||
wxString ElectricalPinTypeGetText( ELECTRICAL_PINTYPE aType )
|
||||
{
|
||||
if( g_pinTypesLanguage != Pgm().GetSelectedLanguageIdentifier() )
|
||||
{
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_INPUT].name = _( "Input" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_OUTPUT].name = _( "Output" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_BIDI].name = _( "Bidirectional" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_TRISTATE].name = _( "Tri-state" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_PASSIVE].name = _( "Passive" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_NIC].name = _( "Free" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_UNSPECIFIED].name = _( "Unspecified" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_POWER_IN].name = _( "Power input" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_POWER_OUT].name = _( "Power output" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR].name = _( "Open collector" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_OPENEMITTER].name = _( "Open emitter" );
|
||||
g_pinTypes[ELECTRICAL_PINTYPE::PT_NC].name = _( "Unconnected" );
|
||||
if( g_pinElectricalTypes.empty() || g_language != Pgm().GetSelectedLanguageIdentifier() )
|
||||
InitTables();
|
||||
|
||||
g_pinTypesLanguage = Pgm().GetSelectedLanguageIdentifier();
|
||||
}
|
||||
auto it = g_pinElectricalTypes.find( aType );
|
||||
|
||||
auto findIt = g_pinTypes.find( aType );
|
||||
wxCHECK_MSG( it != g_pinElectricalTypes.end(), wxT( "???" ), wxT( "Pin type not found!" ) );
|
||||
|
||||
wxCHECK_MSG( findIt != g_pinTypes.end(), wxT( "???" ), wxT( "Pin type not found!" ) );
|
||||
|
||||
return findIt->second.name;
|
||||
return it->second.name;
|
||||
}
|
||||
|
||||
|
||||
BITMAPS ElectricalPinTypeGetBitmap( ELECTRICAL_PINTYPE aType )
|
||||
{
|
||||
auto findIt = g_pinTypes.find( aType );
|
||||
if( g_pinElectricalTypes.empty() )
|
||||
InitTables();
|
||||
|
||||
wxCHECK_MSG( findIt != g_pinTypes.end(), BITMAPS::INVALID_BITMAP, wxT( "Pin type not found!" ) );
|
||||
auto it = g_pinElectricalTypes.find( aType );
|
||||
|
||||
return findIt->second.bitmap;
|
||||
wxCHECK_MSG( it != g_pinElectricalTypes.end(), BITMAPS::INVALID_BITMAP, wxT( "Pin type not found!" ) );
|
||||
|
||||
return it->second.bitmap;
|
||||
}
|
||||
|
||||
|
||||
wxString PinShapeGetText( GRAPHIC_PINSHAPE aShape )
|
||||
{
|
||||
auto findIt = pinShapes.find( aShape );
|
||||
if( g_pinShapes.empty() || g_language != Pgm().GetSelectedLanguageIdentifier() )
|
||||
InitTables();
|
||||
|
||||
wxCHECK_MSG( findIt != pinShapes.end(), wxT( "?" ), wxT( "Pin type not found!" ) );
|
||||
auto it = g_pinShapes.find( aShape );
|
||||
|
||||
return findIt->second.name;
|
||||
wxCHECK_MSG( it != g_pinShapes.end(), wxT( "?" ), wxT( "Pin type not found!" ) );
|
||||
|
||||
return it->second.name;
|
||||
}
|
||||
|
||||
|
||||
BITMAPS PinShapeGetBitmap( GRAPHIC_PINSHAPE aShape )
|
||||
{
|
||||
auto findIt = pinShapes.find( aShape );
|
||||
if( g_pinShapes.empty() )
|
||||
InitTables();
|
||||
|
||||
wxCHECK_MSG( findIt != pinShapes.end(), BITMAPS::INVALID_BITMAP, wxT( "Pin type not found!" ) );
|
||||
auto it = g_pinShapes.find( aShape );
|
||||
|
||||
return findIt->second.bitmap;
|
||||
wxCHECK_MSG( it != g_pinShapes.end(), BITMAPS::INVALID_BITMAP, wxT( "Pin type not found!" ) );
|
||||
|
||||
return it->second.bitmap;
|
||||
}
|
||||
|
||||
|
||||
wxString PinOrientationName( PIN_ORIENTATION aOrientation )
|
||||
{
|
||||
auto findIt = pinOrientations.find( aOrientation );
|
||||
if( g_pinOrientations.empty() || g_language != Pgm().GetSelectedLanguageIdentifier() )
|
||||
InitTables();
|
||||
|
||||
wxCHECK_MSG( findIt != pinOrientations.end(), wxT( "?" ), wxT( "Pin orientation not found!" ) );
|
||||
auto it = g_pinOrientations.find( aOrientation );
|
||||
|
||||
return findIt->second.name;
|
||||
wxCHECK_MSG( it != g_pinOrientations.end(), wxT( "?" ), wxT( "Pin orientation not found!" ) );
|
||||
|
||||
return it->second.name;
|
||||
}
|
||||
|
||||
|
||||
BITMAPS PinOrientationGetBitmap( PIN_ORIENTATION aOrientation )
|
||||
{
|
||||
auto findIt = pinOrientations.find( aOrientation );
|
||||
if( g_pinOrientations.empty() )
|
||||
InitTables();
|
||||
|
||||
wxCHECK_MSG( findIt != pinOrientations.end(), BITMAPS::INVALID_BITMAP,
|
||||
wxT( "Pin orientation not found!" ) );
|
||||
auto it = g_pinOrientations.find( aOrientation );
|
||||
|
||||
return findIt->second.bitmap;
|
||||
wxCHECK_MSG( it != g_pinOrientations.end(), BITMAPS::INVALID_BITMAP, wxT( "Pin orientation not found!" ) );
|
||||
|
||||
return it->second.bitmap;
|
||||
}
|
||||
|
||||
+12
-1
@@ -209,9 +209,20 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
|
||||
schematic = schItem->Schematic();
|
||||
|
||||
if( schItem->IsSelected() )
|
||||
{
|
||||
selectedModified = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
schItem->RunOnChildren(
|
||||
[&selectedModified]( SCH_ITEM* aChild )
|
||||
{
|
||||
if( aChild->IsSelected() )
|
||||
selectedModified = true;
|
||||
} );
|
||||
}
|
||||
|
||||
auto updateConnectivityFlag = [&, this]()
|
||||
auto updateConnectivityFlag = [&]()
|
||||
{
|
||||
if( schItem->IsConnectable() )
|
||||
{
|
||||
|
||||
@@ -545,7 +545,7 @@ public:
|
||||
* @param aSchematicFileName is the absolute path and file name of the file to test.
|
||||
* @return true if the user accepts the potential file name clash risk.
|
||||
*/
|
||||
bool AllowCaseSensitiveFileNameClashes( const wxString& aSchematicFileName );
|
||||
bool AllowCaseSensitiveFileNameClashes( const wxString& aOldName, const wxString& aSchematicFileName );
|
||||
|
||||
/**
|
||||
* Edit an existing sheet or add a new sheet to the schematic.
|
||||
|
||||
@@ -4396,20 +4396,40 @@ void SCH_IO_ALTIUM::ParseLibHeader( const ALTIUM_COMPOUND_FILE& aAltiumSchFile,
|
||||
}
|
||||
|
||||
|
||||
void SCH_IO_ALTIUM::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
|
||||
const wxString& aLibraryPath,
|
||||
const STRING_UTF8_MAP* aProperties )
|
||||
void SCH_IO_ALTIUM::doEnumerateSymbolLib( const wxString& aLibraryPath,
|
||||
const STRING_UTF8_MAP* aProperties,
|
||||
std::function<void(const wxString&, LIB_SYMBOL*)> aInserter )
|
||||
{
|
||||
ensureLoadedLibrary( aLibraryPath, aProperties );
|
||||
|
||||
bool powerSymbolsOnly = ( aProperties &&
|
||||
aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly )
|
||||
!= aProperties->end() );
|
||||
|
||||
auto it = m_libCache.find( aLibraryPath );
|
||||
|
||||
if( it != m_libCache.end() )
|
||||
{
|
||||
for( auto& [libnameStr, libSymbol] : it->second )
|
||||
aSymbolNameList.Add( libnameStr );
|
||||
}
|
||||
{
|
||||
if( powerSymbolsOnly && !libSymbol->IsPower() )
|
||||
continue;
|
||||
|
||||
aInserter( libnameStr, libSymbol );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_IO_ALTIUM::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
|
||||
const wxString& aLibraryPath,
|
||||
const STRING_UTF8_MAP* aProperties )
|
||||
{
|
||||
doEnumerateSymbolLib( aLibraryPath, aProperties,
|
||||
[&]( const wxString& aStr, LIB_SYMBOL* )
|
||||
{
|
||||
aSymbolNameList.Add( aStr );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@@ -4417,17 +4437,14 @@ void SCH_IO_ALTIUM::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
|
||||
const wxString& aLibraryPath,
|
||||
const STRING_UTF8_MAP* aProperties )
|
||||
{
|
||||
ensureLoadedLibrary( aLibraryPath, aProperties );
|
||||
|
||||
auto it = m_libCache.find( aLibraryPath );
|
||||
|
||||
if( it != m_libCache.end() )
|
||||
{
|
||||
for( auto& [libnameStr, libSymbol] : it->second )
|
||||
aSymbolList.push_back( libSymbol );
|
||||
}
|
||||
doEnumerateSymbolLib( aLibraryPath, aProperties,
|
||||
[&]( const wxString&, LIB_SYMBOL* aSymbol )
|
||||
{
|
||||
aSymbolList.emplace_back( aSymbol );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
LIB_SYMBOL* SCH_IO_ALTIUM::LoadSymbol( const wxString& aLibraryPath,
|
||||
const wxString& aAliasName,
|
||||
const STRING_UTF8_MAP* aProperties )
|
||||
|
||||
@@ -178,6 +178,9 @@ private:
|
||||
std::map<wxString,LIB_SYMBOL*> ParseLibFile( const ALTIUM_COMPOUND_FILE& aAltiumSchFile );
|
||||
std::vector<LIB_SYMBOL*> ParseLibComponent( const std::map<wxString, wxString>& aProperties );
|
||||
|
||||
void doEnumerateSymbolLib( const wxString& aLibraryPath, const STRING_UTF8_MAP* aProperties,
|
||||
std::function<void(const wxString&, LIB_SYMBOL*)> aInserter );
|
||||
|
||||
private:
|
||||
SCH_SHEET* m_rootSheet; // The root sheet of the schematic being loaded..
|
||||
SCH_SHEET_PATH m_sheetPath;
|
||||
|
||||
@@ -1839,9 +1839,10 @@ void SCH_IO_EAGLE::loadInstance( wxXmlNode* aInstanceNode )
|
||||
|
||||
SCH_FIELD* valueField = symbol->GetField( VALUE_FIELD );
|
||||
bool userValue = m_userValue.at( libIdSymbolName );
|
||||
|
||||
valueField->SetVisible( part->GetFieldById( VALUE_FIELD )->IsVisible() );
|
||||
|
||||
if( userValue && epart->value )
|
||||
if( !userValue && epart->value )
|
||||
{
|
||||
valueField->SetText( *epart->value );
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2023-2024 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
|
||||
@@ -43,12 +43,27 @@
|
||||
#include <wx/base64.h>
|
||||
#include <wx/url.h>
|
||||
#include <wx/mstream.h>
|
||||
#include <core/map_helpers.h>
|
||||
#include <gfx_import_utils.h>
|
||||
#include <import_gfx/svg_import_plugin.h>
|
||||
#include <import_gfx/graphics_importer_lib_symbol.h>
|
||||
#include <import_gfx/graphics_importer_sch.h>
|
||||
|
||||
|
||||
// clang-format off
|
||||
static const std::vector<wxString> c_attributesWhitelist = { "Datasheet",
|
||||
"Manufacturer Part",
|
||||
"Manufacturer",
|
||||
"BOM_Manufacturer Part",
|
||||
"BOM_Manufacturer",
|
||||
"Supplier Part",
|
||||
"Supplier",
|
||||
"BOM_Supplier Part",
|
||||
"BOM_Supplier",
|
||||
"LCSC Part Name" };
|
||||
// clang-format on
|
||||
|
||||
|
||||
SCH_EASYEDA_PARSER::SCH_EASYEDA_PARSER( SCHEMATIC* aSchematic,
|
||||
PROGRESS_REPORTER* aProgressReporter )
|
||||
{
|
||||
@@ -561,97 +576,61 @@ void SCH_EASYEDA_PARSER::ParseSymbolShapes( LIB_SYMBOL* aSymbol
|
||||
wxString fillColor = arr[6].Lower();
|
||||
//bool locked = arr[8] != wxS( "0" );
|
||||
|
||||
VECTOR2D start, end;
|
||||
VECTOR2D rad( 10, 10 );
|
||||
bool isFar = false;
|
||||
bool cw = false;
|
||||
std::vector<SHAPE_LINE_CHAIN> chains =
|
||||
ParseLineChains( data, schIUScale.MilsToIU( 10 ), false );
|
||||
|
||||
size_t pos = 0;
|
||||
auto readNumber = [&]( wxString& aOut )
|
||||
auto transform = []( VECTOR2I aVec )
|
||||
{
|
||||
wxUniChar ch = data[pos];
|
||||
|
||||
while( ch == ' ' || ch == ',' )
|
||||
ch = data[++pos];
|
||||
|
||||
while( isdigit( ch ) || ch == '.' || ch == '-' )
|
||||
{
|
||||
aOut += ch;
|
||||
pos++;
|
||||
|
||||
if( pos == data.size() )
|
||||
break;
|
||||
|
||||
ch = data[pos];
|
||||
}
|
||||
return VECTOR2I( aVec.x, -aVec.y );
|
||||
};
|
||||
|
||||
do
|
||||
for( const SHAPE_LINE_CHAIN& chain : chains )
|
||||
{
|
||||
wxUniChar sym = data[pos++];
|
||||
|
||||
if( sym == 'M' )
|
||||
for( int i = 0; i <= chain.PointCount() && i != -1; i = chain.NextShape( i ) )
|
||||
{
|
||||
wxString xStr, yStr;
|
||||
readNumber( xStr );
|
||||
readNumber( yStr );
|
||||
if( chain.IsArcStart( i ) )
|
||||
{
|
||||
SHAPE_ARC arc = chain.Arc( chain.ArcIndex( i ) );
|
||||
|
||||
start = VECTOR2D( Convert( xStr ), Convert( yStr ) );
|
||||
std::unique_ptr<LIB_SHAPE> shape =
|
||||
std::make_unique<LIB_SHAPE>( aSymbol, SHAPE_T::ARC );
|
||||
|
||||
shape->SetArcGeometry( transform( arc.GetP0() ),
|
||||
transform( arc.GetArcMid() ),
|
||||
transform( arc.GetP1() ) );
|
||||
|
||||
shape->SetUnit( 0 );
|
||||
shape->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
|
||||
|
||||
if( fillColor != wxS( "none" ) )
|
||||
{
|
||||
shape->SetFilled( true );
|
||||
|
||||
if( fillColor == strokeColor )
|
||||
shape->SetFillMode( FILL_T::FILLED_SHAPE );
|
||||
else
|
||||
shape->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
|
||||
}
|
||||
|
||||
aSymbol->AddDrawItem( shape.release() );
|
||||
}
|
||||
else
|
||||
{
|
||||
SEG seg = chain.CSegment( i );
|
||||
|
||||
std::unique_ptr<LIB_SHAPE> shape =
|
||||
std::make_unique<LIB_SHAPE>( aSymbol, SHAPE_T::POLY );
|
||||
|
||||
shape->AddPoint( transform( seg.A ) );
|
||||
shape->AddPoint( transform( seg.B ) );
|
||||
|
||||
shape->SetUnit( 0 );
|
||||
shape->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
|
||||
|
||||
aSymbol->AddDrawItem( shape.release() );
|
||||
}
|
||||
}
|
||||
else if( sym == 'A' )
|
||||
{
|
||||
wxString radX, radY, unknown, farFlag, cwFlag, endX, endY;
|
||||
readNumber( radX );
|
||||
readNumber( radY );
|
||||
readNumber( unknown );
|
||||
readNumber( farFlag );
|
||||
readNumber( cwFlag );
|
||||
readNumber( endX );
|
||||
readNumber( endY );
|
||||
|
||||
isFar = farFlag == wxS( "1" );
|
||||
cw = cwFlag == wxS( "1" );
|
||||
rad = VECTOR2D( Convert( radX ), Convert( radY ) );
|
||||
end = VECTOR2D( Convert( endX ), Convert( endY ) );
|
||||
}
|
||||
} while( pos < data.size() );
|
||||
|
||||
VECTOR2D delta = end - start;
|
||||
|
||||
double avgRad = ( rad.x + rad.y ) / 2;
|
||||
double d = delta.EuclideanNorm();
|
||||
double h = sqrt( std::max( 0.0, avgRad * avgRad - d * d / 4 ) );
|
||||
|
||||
//( !far && cw ) => h
|
||||
//( far && cw ) => -h
|
||||
//( !far && !cw ) => -h
|
||||
//( far && !cw ) => h
|
||||
VECTOR2D arcCenter =
|
||||
start + delta / 2 + delta.Perpendicular().Resize( ( isFar ^ cw ) ? h : -h );
|
||||
|
||||
if( cw )
|
||||
std::swap( start, end );
|
||||
|
||||
std::unique_ptr<LIB_SHAPE> shape = std::make_unique<LIB_SHAPE>( aSymbol, SHAPE_T::ARC );
|
||||
|
||||
shape->SetStart( RelPosSym( start ) );
|
||||
shape->SetEnd( RelPosSym( end ) );
|
||||
shape->SetCenter( RelPosSym( arcCenter ) );
|
||||
|
||||
shape->SetUnit( 0 );
|
||||
shape->SetStroke( STROKE_PARAMS( ScaleSize( lineWidth ), strokeStyle ) );
|
||||
|
||||
if( fillColor != wxS( "none" ) )
|
||||
{
|
||||
shape->SetFilled( true );
|
||||
|
||||
if( fillColor == strokeColor )
|
||||
shape->SetFillMode( FILL_T::FILLED_SHAPE );
|
||||
else
|
||||
shape->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
|
||||
}
|
||||
|
||||
aSymbol->AddDrawItem( shape.release() );
|
||||
}
|
||||
else if( elType == wxS( "R" ) )
|
||||
{
|
||||
@@ -962,22 +941,20 @@ LIB_SYMBOL* SCH_EASYEDA_PARSER::ParseSymbol( const VECTOR2D& aOrigi
|
||||
|
||||
m_relOrigin = aOrigin;
|
||||
|
||||
wxString symbolName = wxS( "Unknown" );
|
||||
std::optional<wxString> valOpt;
|
||||
wxString symbolName = wxS( "Unknown" );
|
||||
|
||||
if( aParams.find( wxS( "name" ) ) != aParams.end() )
|
||||
symbolName = aParams.at( wxS( "name" ) );
|
||||
else if( aParams.find( wxS( "spiceSymbolName" ) ) != aParams.end() )
|
||||
symbolName = aParams.at( wxS( "spiceSymbolName" ) );
|
||||
if( valOpt = get_opt( aParams, wxS( "name" ) ) )
|
||||
symbolName = *valOpt;
|
||||
else if( valOpt = get_opt( aParams, wxS( "spiceSymbolName" ) ) )
|
||||
symbolName = *valOpt;
|
||||
|
||||
wxString symbolPrefix;
|
||||
|
||||
if( aParams.find( wxS( "pre" ) ) != aParams.end() )
|
||||
symbolPrefix = aParams.at( wxS( "pre" ) );
|
||||
else if( aParams.find( wxS( "spicePre" ) ) != aParams.end() )
|
||||
symbolPrefix = aParams.at( wxS( "spicePre" ) );
|
||||
|
||||
if( !symbolPrefix.EndsWith( wxS( "?" ) ) )
|
||||
symbolPrefix += wxS( "?" );
|
||||
if( valOpt = get_opt( aParams, wxS( "pre" ) ) )
|
||||
symbolPrefix = *valOpt;
|
||||
else if( valOpt = get_opt( aParams, wxS( "spicePre" ) ) )
|
||||
symbolPrefix = *valOpt;
|
||||
|
||||
LIB_ID libId = EasyEdaToKiCadLibID( wxEmptyString, symbolName );
|
||||
|
||||
@@ -987,6 +964,31 @@ LIB_SYMBOL* SCH_EASYEDA_PARSER::ParseSymbol( const VECTOR2D& aOrigi
|
||||
ksymbol->GetReferenceField().SetText( symbolPrefix );
|
||||
ksymbol->GetValueField().SetText( symbolName );
|
||||
|
||||
for( wxString attrName : c_attributesWhitelist )
|
||||
{
|
||||
wxString srcName = attrName;
|
||||
|
||||
if( srcName == wxS( "Datasheet" ) )
|
||||
srcName = wxS( "link" );
|
||||
|
||||
if( valOpt = get_opt( aParams, srcName ) )
|
||||
{
|
||||
if( valOpt->empty() )
|
||||
continue;
|
||||
|
||||
LIB_FIELD* fd = ksymbol->FindField( attrName, true );
|
||||
|
||||
if( !fd )
|
||||
{
|
||||
fd = new LIB_FIELD( ksymbol->GetNextAvailableFieldId(), attrName );
|
||||
ksymbol->AddField( fd );
|
||||
}
|
||||
|
||||
fd->SetText( *valOpt );
|
||||
fd->SetVisible( false );
|
||||
}
|
||||
}
|
||||
|
||||
ParseSymbolShapes( ksymbol.get(), aParams, aShapes );
|
||||
|
||||
return ksymbol.release();
|
||||
|
||||
@@ -225,7 +225,19 @@ LIB_SYMBOL* loadSymbol( const wxString& aLibraryPath, nlohmann::json aFileData,
|
||||
{
|
||||
parts.RemoveAt( 0 );
|
||||
|
||||
return parser.ParseSymbol( origin, paramMap, parts );
|
||||
LIB_SYMBOL* ksymbol = parser.ParseSymbol( origin, paramMap, parts );
|
||||
|
||||
// Clear reference numbers
|
||||
LIB_FIELD& refField = ksymbol->GetReferenceField();
|
||||
wxString origRef = refField.GetText();
|
||||
wxString reference;
|
||||
|
||||
for( size_t i = 0; i < origRef.size() && !wxIsdigit( origRef[i] ); i++ )
|
||||
reference << origRef[i];
|
||||
|
||||
refField.SetText( reference );
|
||||
|
||||
return ksymbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,7 +273,19 @@ LIB_SYMBOL* loadSymbol( const wxString& aLibraryPath, nlohmann::json aFileData,
|
||||
|
||||
VECTOR2D origin( topDoc.head.x, topDoc.head.y );
|
||||
|
||||
return parser.ParseSymbol( origin, *c_para, topDoc.shape );
|
||||
LIB_SYMBOL* ksymbol = parser.ParseSymbol( origin, *c_para, topDoc.shape );
|
||||
|
||||
// Clear reference numbers
|
||||
LIB_FIELD& refField = ksymbol->GetReferenceField();
|
||||
wxString origRef = refField.GetText();
|
||||
wxString reference;
|
||||
|
||||
for( size_t i = 0; i < origRef.size() && !wxIsdigit( origRef[i] ); i++ )
|
||||
reference << origRef[i];
|
||||
|
||||
refField.SetText( reference );
|
||||
|
||||
return ksymbol;
|
||||
}
|
||||
}
|
||||
catch( nlohmann::json::exception& e )
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2023-2024 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
|
||||
@@ -52,6 +52,21 @@
|
||||
#include <import_gfx/graphics_importer_sch.h>
|
||||
|
||||
|
||||
// clang-format off
|
||||
static const std::vector<wxString> c_attributesWhitelist = { "Value",
|
||||
"Datasheet",
|
||||
"Manufacturer Part",
|
||||
"Manufacturer",
|
||||
"BOM_Manufacturer Part",
|
||||
"BOM_Manufacturer",
|
||||
"Supplier Part",
|
||||
"Supplier",
|
||||
"BOM_Supplier Part",
|
||||
"BOM_Supplier",
|
||||
"LCSC Part Name" };
|
||||
// clang-format on
|
||||
|
||||
|
||||
SCH_EASYEDAPRO_PARSER::SCH_EASYEDAPRO_PARSER( SCHEMATIC* aSchematic,
|
||||
PROGRESS_REPORTER* aProgressReporter )
|
||||
{
|
||||
@@ -383,7 +398,9 @@ void SCH_EASYEDAPRO_PARSER::ApplyAttrToField( const std::map<wxString, nlohmann:
|
||||
}
|
||||
|
||||
|
||||
EASYEDAPRO::SYM_INFO SCH_EASYEDAPRO_PARSER::ParseSymbol( const std::vector<nlohmann::json>& aLines )
|
||||
EASYEDAPRO::SYM_INFO
|
||||
SCH_EASYEDAPRO_PARSER::ParseSymbol( const std::vector<nlohmann::json>& aLines,
|
||||
const std::map<wxString, wxString>& aDeviceAttributes )
|
||||
{
|
||||
EASYEDAPRO::SYM_INFO symInfo;
|
||||
|
||||
@@ -686,11 +703,35 @@ EASYEDAPRO::SYM_INFO SCH_EASYEDAPRO_PARSER::ParseSymbol( const std::vector<nlohm
|
||||
{
|
||||
wxString symbolPrefix = designatorAttr->value;
|
||||
|
||||
if( !symbolPrefix.EndsWith( wxS( "?" ) ) )
|
||||
symbolPrefix += wxS( "?" );
|
||||
if( symbolPrefix.EndsWith( wxS( "?" ) ) )
|
||||
symbolPrefix.RemoveLast();
|
||||
|
||||
ksymbol->GetReferenceField().SetText( symbolPrefix );
|
||||
}
|
||||
|
||||
for( const wxString& attrName : c_attributesWhitelist )
|
||||
{
|
||||
if( auto valOpt = get_opt( aDeviceAttributes, attrName ) )
|
||||
{
|
||||
if( valOpt->empty() )
|
||||
continue;
|
||||
|
||||
LIB_FIELD* fd = ksymbol->FindField( attrName, true );
|
||||
|
||||
if( !fd )
|
||||
{
|
||||
fd = new LIB_FIELD( ksymbol->GetNextAvailableFieldId(), attrName );
|
||||
ksymbol->AddField( fd );
|
||||
}
|
||||
|
||||
wxString value = *valOpt;
|
||||
|
||||
value.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
|
||||
|
||||
fd->SetText( value );
|
||||
fd->SetVisible( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( auto& [unitId, parentedLines] : unitParentedLines )
|
||||
@@ -1107,7 +1148,7 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
|
||||
if( !deviceAttr )
|
||||
continue;
|
||||
|
||||
nlohmann::json compAttrs =
|
||||
std::map<wxString, wxString> compAttrs =
|
||||
aProject.at( "devices" ).at( deviceAttr->value ).at( "attributes" );
|
||||
|
||||
wxString symbolId;
|
||||
@@ -1115,7 +1156,7 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
|
||||
if( symbolAttr && !symbolAttr->value.IsEmpty() )
|
||||
symbolId = symbolAttr->value;
|
||||
else
|
||||
symbolId = compAttrs.at( "Symbol" ).get<wxString>();
|
||||
symbolId = compAttrs.at( "Symbol" );
|
||||
|
||||
auto it = aSymbolMap.find( symbolId );
|
||||
if( it == aSymbolMap.end() )
|
||||
@@ -1217,6 +1258,30 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const wxString& attrKey : c_attributesWhitelist )
|
||||
{
|
||||
if( auto valOpt = get_opt( compAttrs, attrKey ) )
|
||||
{
|
||||
if( valOpt->empty() )
|
||||
continue;
|
||||
|
||||
SCH_FIELD* text = schSym->FindField( attrKey, true );
|
||||
|
||||
if( !text )
|
||||
{
|
||||
text = schSym->AddField(
|
||||
SCH_FIELD( schSym.get(), schSym->GetFieldCount(), attrKey ) );
|
||||
}
|
||||
|
||||
wxString value = *valOpt;
|
||||
|
||||
value.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
|
||||
|
||||
text->SetText( value );
|
||||
text->SetVisible( false );
|
||||
}
|
||||
}
|
||||
|
||||
auto nameAttr = get_opt( attributes, "Name" );
|
||||
auto valueAttr = get_opt( attributes, "Value" );
|
||||
|
||||
@@ -1265,15 +1330,18 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
|
||||
if( attr.value.IsEmpty() )
|
||||
continue;
|
||||
|
||||
SCH_FIELD* text =
|
||||
new SCH_FIELD( schSym.get(), schSym->GetFieldCount(), attrKey );
|
||||
SCH_FIELD* text = schSym->FindField( attrKey, true );
|
||||
|
||||
if( !text )
|
||||
{
|
||||
text = schSym->AddField(
|
||||
SCH_FIELD( schSym.get(), schSym->GetFieldCount(), attrKey ) );
|
||||
}
|
||||
|
||||
text->SetPosition( schSym->GetPosition() );
|
||||
|
||||
ApplyAttrToField( fontStyles, text, attr, false, true, compAttrs,
|
||||
schSym.get() );
|
||||
|
||||
schSym->AddField( *text );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2023-2024 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
|
||||
@@ -101,7 +101,8 @@ public:
|
||||
|
||||
double SizeToKi( wxString units );
|
||||
|
||||
EASYEDAPRO::SYM_INFO ParseSymbol( const std::vector<nlohmann::json>& aLines );
|
||||
EASYEDAPRO::SYM_INFO ParseSymbol( const std::vector<nlohmann::json>& aLines,
|
||||
const std::map<wxString, wxString>& aDeviceAttributes );
|
||||
|
||||
void ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aRootSheet,
|
||||
const nlohmann::json& aProject,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||
@@ -156,7 +156,11 @@ static LIB_SYMBOL* loadSymbol( nlohmann::json project, const wxString& aLibraryP
|
||||
return nullptr;
|
||||
|
||||
wxString prjSymUuid = prjSymIt->first;
|
||||
wxString fpTitle;
|
||||
|
||||
wxString description;
|
||||
wxString customTags;
|
||||
std::map<wxString, wxString> deviceAttributes;
|
||||
wxString fpTitle;
|
||||
|
||||
for( auto& [key, device] : prjDevices )
|
||||
{
|
||||
@@ -164,6 +168,12 @@ static LIB_SYMBOL* loadSymbol( nlohmann::json project, const wxString& aLibraryP
|
||||
|
||||
if( val && *val == prjSymUuid )
|
||||
{
|
||||
description = device.description;
|
||||
deviceAttributes = device.attributes;
|
||||
|
||||
if( device.custom_tags.is_string() )
|
||||
customTags = device.custom_tags.get<wxString>();
|
||||
|
||||
if( auto fpUuid = get_opt( device.attributes, "Footprint" ) )
|
||||
{
|
||||
if( auto prjFp = get_opt( prjFootprints, *fpUuid ) )
|
||||
@@ -192,7 +202,7 @@ static LIB_SYMBOL* loadSymbol( nlohmann::json project, const wxString& aLibraryP
|
||||
lines.emplace_back( js );
|
||||
}
|
||||
|
||||
EASYEDAPRO::SYM_INFO symInfo = parser.ParseSymbol( lines );
|
||||
EASYEDAPRO::SYM_INFO symInfo = parser.ParseSymbol( lines, deviceAttributes );
|
||||
|
||||
if( !symInfo.libSymbol )
|
||||
EASY_IT_CONTINUE;
|
||||
@@ -202,6 +212,15 @@ static LIB_SYMBOL* loadSymbol( nlohmann::json project, const wxString& aLibraryP
|
||||
symInfo.libSymbol->SetName( aAliasName );
|
||||
symInfo.libSymbol->GetFootprintField().SetText( symLibName + wxS( ":" ) + fpTitle );
|
||||
|
||||
wxString keywords = customTags;
|
||||
keywords.Replace( wxS( ":" ), wxS( " " ), true );
|
||||
|
||||
symInfo.libSymbol->SetKeyWords( keywords );
|
||||
|
||||
description.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
|
||||
|
||||
symInfo.libSymbol->SetDescription( description );
|
||||
|
||||
symbol = symInfo.libSymbol.release();
|
||||
|
||||
EASY_IT_BREAK;
|
||||
@@ -314,13 +333,10 @@ void SCH_IO_EASYEDAPRO::LoadAllDataFromProject( const wxString& aProjectPath )
|
||||
|
||||
if( name.EndsWith( wxS( ".esym" ) ) )
|
||||
{
|
||||
EASYEDAPRO::PRJ_SYMBOL symData = prjSymbols.at( baseName );
|
||||
EASYEDAPRO::SYM_INFO symInfo = parser.ParseSymbol( lines );
|
||||
|
||||
if( !symInfo.libSymbol )
|
||||
EASY_IT_CONTINUE;
|
||||
|
||||
wxString fpTitle;
|
||||
wxString description;
|
||||
wxString customTags;
|
||||
std::map<wxString, wxString> deviceAttributes;
|
||||
wxString fpTitle;
|
||||
|
||||
for( auto& [key, device] : prjDevices )
|
||||
{
|
||||
@@ -328,6 +344,12 @@ void SCH_IO_EASYEDAPRO::LoadAllDataFromProject( const wxString& aProjectPath )
|
||||
|
||||
if( val && *val == baseName )
|
||||
{
|
||||
description = device.description;
|
||||
deviceAttributes = device.attributes;
|
||||
|
||||
if( device.custom_tags.is_string() )
|
||||
customTags = device.custom_tags.get<wxString>();
|
||||
|
||||
if( auto fpUuid = get_opt( device.attributes, "Footprint" ) )
|
||||
{
|
||||
if( auto prjFp = get_opt( prjFootprints, *fpUuid ) )
|
||||
@@ -339,11 +361,26 @@ void SCH_IO_EASYEDAPRO::LoadAllDataFromProject( const wxString& aProjectPath )
|
||||
}
|
||||
}
|
||||
|
||||
EASYEDAPRO::PRJ_SYMBOL symData = prjSymbols.at( baseName );
|
||||
EASYEDAPRO::SYM_INFO symInfo = parser.ParseSymbol( lines, deviceAttributes );
|
||||
|
||||
if( !symInfo.libSymbol )
|
||||
EASY_IT_CONTINUE;
|
||||
|
||||
LIB_ID libID = EASYEDAPRO::ToKiCadLibID( symLibName, symData.title );
|
||||
symInfo.libSymbol->SetLibId( libID );
|
||||
symInfo.libSymbol->SetName( symData.title );
|
||||
symInfo.libSymbol->GetFootprintField().SetText( symLibName + wxS( ":" ) + fpTitle );
|
||||
|
||||
wxString keywords = customTags;
|
||||
keywords.Replace( wxS( ":" ), wxS( " " ), true );
|
||||
|
||||
symInfo.libSymbol->SetKeyWords( keywords );
|
||||
|
||||
description.Replace( wxS( "\u2103" ), wxS( "\u00B0C" ), true ); // ℃ -> °C
|
||||
|
||||
symInfo.libSymbol->SetDescription( description );
|
||||
|
||||
m_projectData->m_Symbols.emplace( baseName, std::move( symInfo ) );
|
||||
}
|
||||
else if( name.EndsWith( wxS( ".eblob" ) ) )
|
||||
|
||||
@@ -539,7 +539,9 @@ void SCH_IO_KICAD_LEGACY_LIB_CACHE::loadField( std::unique_ptr<LIB_SYMBOL>& aSym
|
||||
|
||||
LIB_FIELD* field;
|
||||
|
||||
if( id >= 0 && id < MANDATORY_FIELDS )
|
||||
// Description was not mandatory until v8.0, so any fields with an index
|
||||
// past this point should be user fields
|
||||
if( id >= 0 && id < DESCRIPTION_FIELD )
|
||||
{
|
||||
field = aSymbol->GetFieldById( id );
|
||||
|
||||
@@ -550,6 +552,7 @@ void SCH_IO_KICAD_LEGACY_LIB_CACHE::loadField( std::unique_ptr<LIB_SYMBOL>& aSym
|
||||
}
|
||||
else
|
||||
{
|
||||
id = aSymbol->GetNextAvailableFieldId();
|
||||
field = new LIB_FIELD( aSymbol.get(), id );
|
||||
aSymbol->AddDrawItem( field, false );
|
||||
}
|
||||
|
||||
@@ -783,75 +783,79 @@ void SCH_IO_KICAD_SEXPR::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSche
|
||||
|
||||
if( !aSymbol->GetInstances().empty() )
|
||||
{
|
||||
std::map<KIID, std::vector<SCH_SYMBOL_INSTANCE>> projectInstances;
|
||||
|
||||
m_out->Print( aNestLevel + 1, "(instances\n" );
|
||||
|
||||
wxString projectName;
|
||||
KIID lastProjectUuid;
|
||||
KIID rootSheetUuid = aSchematic.Root().m_Uuid;
|
||||
SCH_SHEET_LIST fullHierarchy = aSchematic.GetSheets();
|
||||
bool project_open = false;
|
||||
|
||||
for( size_t i = 0; i < aSymbol->GetInstances().size(); i++ )
|
||||
for( const SCH_SYMBOL_INSTANCE& inst : aSymbol->GetInstances() )
|
||||
{
|
||||
// Zero length KIID_PATH objects are not valid and will cause a crash below.
|
||||
wxCHECK2( aSymbol->GetInstances()[i].m_Path.size(), continue );
|
||||
wxCHECK2( inst.m_Path.size(), continue );
|
||||
|
||||
// If the instance data is part of this design but no longer has an associated sheet
|
||||
// path, don't save it. This prevents large amounts of orphaned instance data for the
|
||||
// current project from accumulating in the schematic files.
|
||||
//
|
||||
// Keep all instance data when copying to the clipboard. It may be needed on paste.
|
||||
if( !aForClipboard
|
||||
&& ( aSymbol->GetInstances()[i].m_Path[0] == rootSheetUuid )
|
||||
&& !fullHierarchy.GetSheetPathByKIIDPath( aSymbol->GetInstances()[i].m_Path ) )
|
||||
{
|
||||
if( project_open && ( ( i + 1 == aSymbol->GetInstances().size() )
|
||||
|| lastProjectUuid != aSymbol->GetInstances()[i+1].m_Path[0] ) )
|
||||
{
|
||||
m_out->Print( aNestLevel + 2, ")\n" ); // Closes `project`.
|
||||
project_open = false;
|
||||
}
|
||||
bool isOrphaned = ( inst.m_Path[0] == rootSheetUuid )
|
||||
&& !fullHierarchy.GetSheetPathByKIIDPath( inst.m_Path );
|
||||
|
||||
// Keep all instance data when copying to the clipboard. They may be needed on paste.
|
||||
if( !aForClipboard && isOrphaned )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( lastProjectUuid != aSymbol->GetInstances()[i].m_Path[0] )
|
||||
auto it = projectInstances.find( inst.m_Path[0] );
|
||||
|
||||
if( it == projectInstances.end() )
|
||||
{
|
||||
wxString projectName;
|
||||
|
||||
if( aSymbol->GetInstances()[i].m_Path[0] == rootSheetUuid )
|
||||
projectName = aSchematic.Prj().GetProjectName();
|
||||
else
|
||||
projectName = aSymbol->GetInstances()[i].m_ProjectName;
|
||||
|
||||
lastProjectUuid = aSymbol->GetInstances()[i].m_Path[0];
|
||||
m_out->Print( aNestLevel + 2, "(project %s\n",
|
||||
m_out->Quotew( projectName ).c_str() );
|
||||
project_open = true;
|
||||
projectInstances[ inst.m_Path[0] ] = { inst };
|
||||
}
|
||||
|
||||
wxString path;
|
||||
KIID_PATH tmp = aSymbol->GetInstances()[i].m_Path;
|
||||
|
||||
if( aForClipboard && aRelativePath )
|
||||
tmp.MakeRelativeTo( aRelativePath->Path() );
|
||||
|
||||
path = tmp.AsString();
|
||||
|
||||
m_out->Print( aNestLevel + 3, "(path %s\n",
|
||||
m_out->Quotew( path ).c_str() );
|
||||
m_out->Print( aNestLevel + 4, "(reference %s) (unit %d)\n",
|
||||
m_out->Quotew( aSymbol->GetInstances()[i].m_Reference ).c_str(),
|
||||
aSymbol->GetInstances()[i].m_Unit );
|
||||
m_out->Print( aNestLevel + 3, ")\n" );
|
||||
|
||||
if( project_open && ( ( i + 1 == aSymbol->GetInstances().size() )
|
||||
|| lastProjectUuid != aSymbol->GetInstances()[i+1].m_Path[0] ) )
|
||||
else
|
||||
{
|
||||
m_out->Print( aNestLevel + 2, ")\n" ); // Closes `project`.
|
||||
project_open = false;
|
||||
it->second.emplace_back( inst );
|
||||
}
|
||||
}
|
||||
|
||||
for( auto& [uuid, instances] : projectInstances )
|
||||
{
|
||||
wxCHECK2( instances.size(), continue );
|
||||
|
||||
// Sort project instances by KIID_PATH.
|
||||
std::sort( instances.begin(), instances.end(),
|
||||
[]( SCH_SYMBOL_INSTANCE& aLhs, SCH_SYMBOL_INSTANCE& aRhs )
|
||||
{
|
||||
return aLhs.m_Path < aRhs.m_Path;
|
||||
} );
|
||||
|
||||
projectName = instances[0].m_ProjectName;
|
||||
|
||||
m_out->Print( aNestLevel + 2, "(project %s\n",
|
||||
m_out->Quotew( projectName ).c_str() );
|
||||
|
||||
for( const SCH_SYMBOL_INSTANCE& instance : instances )
|
||||
{
|
||||
wxString path;
|
||||
KIID_PATH tmp = instance.m_Path;
|
||||
|
||||
if( aForClipboard && aRelativePath )
|
||||
tmp.MakeRelativeTo( aRelativePath->Path() );
|
||||
|
||||
path = tmp.AsString();
|
||||
|
||||
m_out->Print( aNestLevel + 3, "(path %s\n",
|
||||
m_out->Quotew( path ).c_str() );
|
||||
m_out->Print( aNestLevel + 4, "(reference %s) (unit %d)\n",
|
||||
m_out->Quotew( instance.m_Reference ).c_str(),
|
||||
instance.m_Unit );
|
||||
m_out->Print( aNestLevel + 3, ")\n" );
|
||||
}
|
||||
|
||||
m_out->Print( aNestLevel + 2, ")\n" ); // Closes `project`.
|
||||
}
|
||||
|
||||
m_out->Print( aNestLevel + 1, ")\n" ); // Closes `instances`.
|
||||
}
|
||||
|
||||
|
||||
@@ -892,7 +892,7 @@ wxString SCH_LABEL_BASE::GetShownText( const SCH_SHEET_PATH* aPath, bool aAllowE
|
||||
std::function<bool( wxString* )> textResolver =
|
||||
[&]( wxString* token ) -> bool
|
||||
{
|
||||
return ResolveTextVar( aPath, token, aDepth );
|
||||
return ResolveTextVar( aPath, token, aDepth + 1 );
|
||||
};
|
||||
|
||||
wxString text = EDA_TEXT::GetShownText( aAllowExtraText, aDepth );
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
#include "sch_shape.h"
|
||||
#include "common.h"
|
||||
|
||||
#include "symb_transforms_utils.h"
|
||||
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
@@ -491,8 +493,9 @@ COLOR4D SCH_PAINTER::getRenderColor( const EDA_ITEM* aItem, int aLayer, bool aDr
|
||||
if( aDrawingShadows )
|
||||
color = m_schSettings.GetLayerColor( LAYER_SELECTION_SHADOWS );
|
||||
}
|
||||
else if( aItem->IsSelected()
|
||||
&& ( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_SHEET_BACKGROUND ) )
|
||||
else if( aItem->IsSelected() && ( aLayer == LAYER_DEVICE_BACKGROUND
|
||||
|| aLayer == LAYER_SHEET_BACKGROUND
|
||||
|| aLayer == LAYER_NOTES_BACKGROUND ) )
|
||||
{
|
||||
// Selected items will be painted over all other items, so make backgrounds translucent so
|
||||
// that non-selected overlapping objects are visible
|
||||
@@ -2429,56 +2432,6 @@ void SCH_PAINTER::draw( const SCH_TEXTBOX* aTextBox, int aLayer )
|
||||
}
|
||||
|
||||
|
||||
static void orientSymbol( LIB_SYMBOL* symbol, int orientation )
|
||||
{
|
||||
struct ORIENT
|
||||
{
|
||||
int flag;
|
||||
int n_rots;
|
||||
int mirror_x;
|
||||
int mirror_y;
|
||||
}
|
||||
orientations[] =
|
||||
{
|
||||
{ SYM_ORIENT_0, 0, 0, 0 },
|
||||
{ SYM_ORIENT_90, 1, 0, 0 },
|
||||
{ SYM_ORIENT_180, 2, 0, 0 },
|
||||
{ SYM_ORIENT_270, 3, 0, 0 },
|
||||
{ SYM_MIRROR_X + SYM_ORIENT_0, 0, 1, 0 },
|
||||
{ SYM_MIRROR_X + SYM_ORIENT_90, 1, 1, 0 },
|
||||
{ SYM_MIRROR_Y, 0, 0, 1 },
|
||||
{ SYM_MIRROR_X + SYM_ORIENT_270, 3, 1, 0 },
|
||||
{ SYM_MIRROR_Y + SYM_ORIENT_0, 0, 0, 1 },
|
||||
{ SYM_MIRROR_Y + SYM_ORIENT_90, 1, 0, 1 },
|
||||
{ SYM_MIRROR_Y + SYM_ORIENT_180, 2, 0, 1 },
|
||||
{ SYM_MIRROR_Y + SYM_ORIENT_270, 3, 0, 1 }
|
||||
};
|
||||
|
||||
ORIENT o = orientations[ 0 ];
|
||||
|
||||
for( ORIENT& i : orientations )
|
||||
{
|
||||
if( i.flag == orientation )
|
||||
{
|
||||
o = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( LIB_ITEM& item : symbol->GetDrawItems() )
|
||||
{
|
||||
for( int i = 0; i < o.n_rots; i++ )
|
||||
item.Rotate( VECTOR2I(0, 0 ), true );
|
||||
|
||||
if( o.mirror_x )
|
||||
item.MirrorVertical( VECTOR2I( 0, 0 ) );
|
||||
|
||||
if( o.mirror_y )
|
||||
item.MirrorHorizontal( VECTOR2I( 0, 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wxString SCH_PAINTER::expandLibItemTextVars( const wxString& aSourceText,
|
||||
const SCH_SYMBOL* aSymbolContext )
|
||||
{
|
||||
@@ -2530,7 +2483,7 @@ void SCH_PAINTER::draw( const SCH_SYMBOL* aSymbol, int aLayer )
|
||||
|
||||
tempSymbol.SetFlags( aSymbol->GetFlags() );
|
||||
|
||||
orientSymbol( &tempSymbol, aSymbol->GetOrientation() );
|
||||
OrientAndMirrorSymbolItems( &tempSymbol, aSymbol->GetOrientation() );
|
||||
|
||||
for( LIB_ITEM& tempItem : tempSymbol.GetDrawItems() )
|
||||
{
|
||||
|
||||
@@ -2081,33 +2081,6 @@ bool SCH_SCREENS::HasSchematic( const wxString& aSchematicFileName )
|
||||
}
|
||||
|
||||
|
||||
bool SCH_SCREENS::CanCauseCaseSensitivityIssue( const wxString& aSchematicFileName ) const
|
||||
{
|
||||
wxString lhsLower;
|
||||
wxString rhsLower;
|
||||
wxFileName lhs;
|
||||
wxFileName rhs = aSchematicFileName;
|
||||
|
||||
wxCHECK( rhs.IsAbsolute(), false );
|
||||
|
||||
for( const SCH_SCREEN* screen : m_screens )
|
||||
{
|
||||
lhs = screen->GetFileName();
|
||||
|
||||
if( lhs.GetPath() != rhs.GetPath() )
|
||||
continue;
|
||||
|
||||
lhsLower = lhs.GetFullName().Lower();
|
||||
rhsLower = rhs.GetFullName().Lower();
|
||||
|
||||
if( lhsLower == rhsLower && lhs.GetFullName() != rhs.GetFullName() )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREENS::BuildClientSheetPathList()
|
||||
{
|
||||
SCH_SCREEN* first = GetFirst();
|
||||
|
||||
@@ -812,19 +812,6 @@ public:
|
||||
*/
|
||||
void BuildClientSheetPathList();
|
||||
|
||||
/**
|
||||
* Check \a aSchematicFileName for a potential file name case sensitivity issue.
|
||||
*
|
||||
* On platforms where file names are case sensitive, it is possible to schematic sheet
|
||||
* file names that would cause issues on platforms where file name are case insensitive.
|
||||
* File names foo.sch and Foo.sch are unique files on Linux and MacOS but on Windows
|
||||
* this would result in a broken schematic.
|
||||
*
|
||||
* @param[in] aSchematicFileName is the absolute path and file name of the file to test.
|
||||
* @return true if \a aSchematicFileName would cause an issue.
|
||||
*/
|
||||
bool CanCauseCaseSensitivityIssue( const wxString& aSchematicFileName ) const;
|
||||
|
||||
/**
|
||||
* Update the symbol value and footprint instance data for legacy designs.
|
||||
*/
|
||||
|
||||
@@ -562,8 +562,11 @@ void SCH_SHEET_PATH::SetPageNumber( const wxString& aPageNumber )
|
||||
}
|
||||
|
||||
|
||||
void SCH_SHEET_PATH::AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath )
|
||||
void SCH_SHEET_PATH::AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath,
|
||||
const wxString& aProjectName )
|
||||
{
|
||||
wxCHECK( !aProjectName.IsEmpty(), /* void */ );
|
||||
|
||||
SCH_SHEET_PATH newSheetPath( aPrefixSheetPath );
|
||||
SCH_SHEET_PATH currentSheetPath( *this );
|
||||
|
||||
@@ -580,12 +583,16 @@ void SCH_SHEET_PATH::AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPa
|
||||
|
||||
if( symbol->GetInstance( newSymbolInstance, Path(), true ) )
|
||||
{
|
||||
newSymbolInstance.m_ProjectName = aProjectName;
|
||||
// Use an existing symbol instance for this path if it exists.
|
||||
|
||||
newSymbolInstance.m_Path = newSheetPath.Path();
|
||||
symbol->AddHierarchicalReference( newSymbolInstance );
|
||||
}
|
||||
else if( !symbol->GetInstances().empty() )
|
||||
{
|
||||
newSymbolInstance.m_ProjectName = aProjectName;
|
||||
|
||||
// Use the first symbol instance if any symbol instance data exists.
|
||||
newSymbolInstance = symbol->GetInstances()[0];
|
||||
newSymbolInstance.m_Path = newSheetPath.Path();
|
||||
@@ -593,6 +600,8 @@ void SCH_SHEET_PATH::AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPa
|
||||
}
|
||||
else
|
||||
{
|
||||
newSymbolInstance.m_ProjectName = aProjectName;
|
||||
|
||||
// Fall back to the last saved symbol field and unit settings if there is no
|
||||
// instance data.
|
||||
newSymbolInstance.m_Path = newSheetPath.Path();
|
||||
@@ -1237,10 +1246,11 @@ void SCH_SHEET_LIST::SetInitialPageNumbers()
|
||||
}
|
||||
|
||||
|
||||
void SCH_SHEET_LIST::AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath )
|
||||
void SCH_SHEET_LIST::AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath,
|
||||
const wxString& aProjectName )
|
||||
{
|
||||
for( SCH_SHEET_PATH& sheetPath : *this )
|
||||
sheetPath.AddNewSymbolInstances( aPrefixSheetPath );
|
||||
sheetPath.AddNewSymbolInstances( aPrefixSheetPath, aProjectName );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -395,8 +395,13 @@ public:
|
||||
* from the library symbol.
|
||||
* - If all else fails, set the reference to "U?", the unit to 1, and everything else to
|
||||
* an empty string.
|
||||
*
|
||||
* @param aPrefixSheetPath is the sheet path to prefix to this sheet path for the new symbol
|
||||
* instance.
|
||||
* @param aProjectName is the name of the project for the new symbol instance data.
|
||||
*/
|
||||
void AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath );
|
||||
void AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath,
|
||||
const wxString& aProjectName );
|
||||
|
||||
void RemoveSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath );
|
||||
|
||||
@@ -669,8 +674,10 @@ public:
|
||||
* with \a aPrefixSheetPath.
|
||||
*
|
||||
* @param aPrefixSheetPath is the sheet path to append the new symbol instances to.
|
||||
* @param aProjectName is the name of the project for the new symbol instance data.
|
||||
*/
|
||||
void AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath );
|
||||
void AddNewSymbolInstances( const SCH_SHEET_PATH& aPrefixSheetPath,
|
||||
const wxString& aProjectName );
|
||||
|
||||
void AddNewSheetInstances( const SCH_SHEET_PATH& aPrefixSheetPath,
|
||||
int aLastVirtualPageNumber );
|
||||
|
||||
@@ -1146,6 +1146,29 @@ SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
|
||||
}
|
||||
|
||||
|
||||
const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
|
||||
{
|
||||
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
|
||||
{
|
||||
int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit()
|
||||
: GetUnit();
|
||||
int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle()
|
||||
: GetBodyStyle();
|
||||
|
||||
if( pin_unit > 0 && pin_unit != GetUnit() )
|
||||
continue;
|
||||
|
||||
if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
|
||||
continue;
|
||||
|
||||
if( pin->IsPointClickableAnchor( aPos ) )
|
||||
return pin.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SCH_SYMBOL::GetLibPins( std::vector<LIB_PIN*>& aPinsList ) const
|
||||
{
|
||||
if( m_part )
|
||||
|
||||
@@ -635,6 +635,15 @@ public:
|
||||
*/
|
||||
SCH_PIN* GetPin( LIB_PIN* aLibPin ) const;
|
||||
|
||||
/**
|
||||
* Return the #SCH_PIN object found at \a aPosition.
|
||||
*
|
||||
* @param aPosition is the position of the pin to fetch.
|
||||
*
|
||||
* @return the #SCH_PIN object found at \a aPosition or nullptr.
|
||||
*/
|
||||
const SCH_PIN* GetPin( const VECTOR2I& aPosition ) const;
|
||||
|
||||
/**
|
||||
* Retrieve a list of the SCH_PINs for the given sheet path.
|
||||
*
|
||||
|
||||
@@ -120,6 +120,8 @@ SCHEMATIC::SCHEMATIC( PROJECT* aPrj ) :
|
||||
|
||||
SCHEMATIC::~SCHEMATIC()
|
||||
{
|
||||
PROPERTY_MANAGER::Instance().UnregisterListeners( TYPE_HASH( SCH_FIELD ) );
|
||||
|
||||
delete m_currentSheet;
|
||||
delete m_connectionGraph;
|
||||
}
|
||||
|
||||
@@ -196,6 +196,9 @@ SCHEMATIC_SETTINGS::SCHEMATIC_SETTINGS( JSON_SETTINGS* aParent, const std::strin
|
||||
m_TemplateFieldNames.AddTemplateFieldNames( cfg->m_Drawing.field_names );
|
||||
}, {} ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "bom_export_filename",
|
||||
&m_BomExportFileName, "" ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<BOM_PRESET>( "bom_settings",
|
||||
&m_BomSettings, BOM_PRESET::GroupedByValue() ) );
|
||||
m_params.emplace_back( new PARAM_LIST<BOM_PRESET>( "bom_presets",
|
||||
|
||||
@@ -105,6 +105,8 @@ public:
|
||||
|
||||
TEMPLATES m_TemplateFieldNames;
|
||||
|
||||
wxString m_BomExportFileName;
|
||||
|
||||
/// List of stored BOM presets
|
||||
BOM_PRESET m_BomSettings;
|
||||
std::vector<BOM_PRESET> m_BomPresets;
|
||||
|
||||
+39
-6
@@ -570,7 +570,7 @@ bool SCH_EDIT_FRAME::LoadSheetFromFile( SCH_SHEET* aSheet, SCH_SHEET_PATH* aCurr
|
||||
newScreen->MigrateSimModels();
|
||||
|
||||
// Attempt to create new symbol instances using the instance data loaded above.
|
||||
sheetHierarchy.AddNewSymbolInstances( *aCurrentSheet );
|
||||
sheetHierarchy.AddNewSymbolInstances( *aCurrentSheet, Prj().GetProjectName() );
|
||||
|
||||
// Add new sheet instance data.
|
||||
sheetHierarchy.AddNewSheetInstances( *aCurrentSheet, hierarchy.GetLastVirtualPageNumber() );
|
||||
@@ -688,16 +688,49 @@ void SCH_EDIT_FRAME::DrawCurrentSheetToClipboard()
|
||||
}
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::AllowCaseSensitiveFileNameClashes( const wxString& aSchematicFileName )
|
||||
bool SCH_EDIT_FRAME::AllowCaseSensitiveFileNameClashes( const wxString& aOldName, const wxString& aSchematicFileName )
|
||||
{
|
||||
wxString msg;
|
||||
SCH_SCREENS screens( Schematic().Root() );
|
||||
SCH_SHEET_LIST sheets( &Schematic().Root() );
|
||||
wxFileName fn = aSchematicFileName;
|
||||
|
||||
wxCHECK( fn.IsAbsolute(), false );
|
||||
|
||||
if( eeconfig()->m_Appearance.show_sheet_filename_case_sensitivity_dialog
|
||||
&& screens.CanCauseCaseSensitivityIssue( aSchematicFileName ) )
|
||||
auto can_cause_issues = [&]() -> bool
|
||||
{
|
||||
wxFileName lhs;
|
||||
wxFileName rhs = aSchematicFileName;
|
||||
wxFileName old = aOldName;
|
||||
wxString oldLower = old.GetFullName().Lower();
|
||||
wxString rhsLower = rhs.GetFullName().Lower();
|
||||
wxString lhsLower;
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
wxCHECK( rhs.IsAbsolute(), false );
|
||||
|
||||
for( SCH_SHEET_PATH& sheet : sheets )
|
||||
{
|
||||
lhs = sheet.LastScreen()->GetFileName();
|
||||
|
||||
if( lhs.GetPath() != rhs.GetPath() )
|
||||
continue;
|
||||
|
||||
lhsLower = lhs.GetFullName().Lower();
|
||||
|
||||
if( lhsLower == rhsLower && lhs.GetFullName() != rhs.GetFullName() )
|
||||
count++;
|
||||
}
|
||||
|
||||
// If we are renaming a sheet that is only used once, then we are not going to cause
|
||||
// a case sensitivity issue.
|
||||
if( oldLower == rhsLower )
|
||||
return count > 1;
|
||||
|
||||
return count > 0;
|
||||
};
|
||||
|
||||
if( eeconfig()->m_Appearance.show_sheet_filename_case_sensitivity_dialog && can_cause_issues() )
|
||||
{
|
||||
msg.Printf( _( "The file name '%s' can cause issues with an existing file name\n"
|
||||
"already defined in the schematic on systems that support case\n"
|
||||
@@ -710,7 +743,7 @@ bool SCH_EDIT_FRAME::AllowCaseSensitiveFileNameClashes( const wxString& aSchemat
|
||||
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION );
|
||||
dlg.ShowCheckBox( _( "Do not show this message again." ) );
|
||||
dlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Create New Sheet" ) ),
|
||||
wxMessageDialog::ButtonLabel( _( "Discard New Sheet" ) ) );
|
||||
wxMessageDialog::ButtonLabel( _( "Cancel" ) ) );
|
||||
|
||||
if( dlg.ShowModal() == wxID_NO )
|
||||
return false;
|
||||
|
||||
@@ -867,7 +867,7 @@ void KIBIS_PIN::getKuKdOneWaveform( KIBIS_MODEL& aMod
|
||||
simul += "VmeasPD 0 x1.PD_GND0 0\n";
|
||||
simul += "VmeasPU x1.PU_PWR0 3 0\n";
|
||||
simul += "VmeasPC x1.PC_PWR0 3 0\n";
|
||||
simul += "VmeasGC 0 x1.GC_PWR0 0\n";
|
||||
simul += "VmeasGC 0 x1.GC_GND0 0\n";
|
||||
|
||||
if( aModel.HasPullup() && aModel.HasPulldown() )
|
||||
{
|
||||
@@ -1039,7 +1039,7 @@ void KIBIS_PIN::getKuKdTwoWaveforms( KIBIS_MODEL& aMo
|
||||
simul += "VmeasPD0 0 x1.PD_GND0 0\n";
|
||||
simul += "VmeasPU0 x1.PU_PWR0 3 0\n";
|
||||
simul += "VmeasPC0 x1.PC_PWR0 3 0\n";
|
||||
simul += "VmeasGC0 0 x1.GC_PWR0 0\n";
|
||||
simul += "VmeasGC0 0 x1.GC_GND0 0\n";
|
||||
|
||||
|
||||
simul += "\n x2 3 0 7 DRIVER1 \n";
|
||||
@@ -1060,7 +1060,7 @@ void KIBIS_PIN::getKuKdTwoWaveforms( KIBIS_MODEL& aMo
|
||||
simul += "VmeasPD1 0 x2.PD_GND0 0\n";
|
||||
simul += "VmeasPU1 x2.PU_PWR0 3 0\n";
|
||||
simul += "VmeasPC1 x2.PC_PWR0 3 0\n";
|
||||
simul += "VmeasGC1 0 x2.GC_PWR0 0\n";
|
||||
simul += "VmeasGC1 0 x2.GC_GND0 0\n";
|
||||
|
||||
if( aModel.HasPullup() && aModel.HasPulldown() )
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016-2022 CERN
|
||||
* Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2018-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
@@ -59,6 +59,7 @@ NGSPICE::NGSPICE() :
|
||||
m_ngSpice_Circ( nullptr ),
|
||||
m_ngSpice_Command( nullptr ),
|
||||
m_ngGet_Vec_Info( nullptr ),
|
||||
m_ngCM_Input_Path( nullptr ),
|
||||
m_ngSpice_CurPlot( nullptr ),
|
||||
m_ngSpice_AllPlots( nullptr ),
|
||||
m_ngSpice_AllVecs( nullptr ),
|
||||
@@ -274,21 +275,23 @@ std::vector<double> NGSPICE::GetPhaseVector( const std::string& aName, int aMaxL
|
||||
|
||||
|
||||
bool NGSPICE::Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel, const wxString& aSimCommand,
|
||||
unsigned aSimOptions, REPORTER& aReporter )
|
||||
unsigned aSimOptions, const wxString& aInputPath, REPORTER& aReporter )
|
||||
{
|
||||
SPICE_CIRCUIT_MODEL* model = dynamic_cast<SPICE_CIRCUIT_MODEL*>( aModel.get() );
|
||||
STRING_FORMATTER formatter;
|
||||
|
||||
setCodemodelsInputPath( aInputPath.ToStdString() );
|
||||
|
||||
if( model && model->GetNetlist( aSimCommand, aSimOptions, &formatter, aReporter ) )
|
||||
{
|
||||
SIMULATOR::Attach( aModel, aSimCommand, aSimOptions, aReporter );
|
||||
SIMULATOR::Attach( aModel, aSimCommand, aSimOptions, aInputPath, aReporter );
|
||||
updateNgspiceSettings();
|
||||
LoadNetlist( formatter.GetString() );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SIMULATOR::Attach( nullptr, wxEmptyString, 0, aReporter );
|
||||
SIMULATOR::Attach( nullptr, wxEmptyString, 0, wxEmptyString, aReporter );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -494,6 +497,7 @@ void NGSPICE::init_dll()
|
||||
m_ngSpice_Circ = (ngSpice_Circ) m_dll.GetSymbol( "ngSpice_Circ" );
|
||||
m_ngSpice_Command = (ngSpice_Command) m_dll.GetSymbol( "ngSpice_Command" );
|
||||
m_ngGet_Vec_Info = (ngGet_Vec_Info) m_dll.GetSymbol( "ngGet_Vec_Info" );
|
||||
m_ngCM_Input_Path = (ngCM_Input_Path) m_dll.GetSymbol( "ngCM_Input_Path" );
|
||||
m_ngSpice_CurPlot = (ngSpice_CurPlot) m_dll.GetSymbol( "ngSpice_CurPlot" );
|
||||
m_ngSpice_AllPlots = (ngSpice_AllPlots) m_dll.GetSymbol( "ngSpice_AllPlots" );
|
||||
m_ngSpice_AllVecs = (ngSpice_AllVecs) m_dll.GetSymbol( "ngSpice_AllVecs" );
|
||||
@@ -634,6 +638,19 @@ std::string NGSPICE::findCmPath() const
|
||||
}
|
||||
|
||||
|
||||
bool NGSPICE::setCodemodelsInputPath( const std::string& aPath )
|
||||
{
|
||||
if( !m_ngCM_Input_Path )
|
||||
return false;
|
||||
|
||||
LOCALE_IO c_locale; // ngspice works correctly only with C locale
|
||||
|
||||
m_ngCM_Input_Path( aPath.c_str() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NGSPICE::loadCodemodels( const std::string& aPath )
|
||||
{
|
||||
wxArrayString cmFiles;
|
||||
|
||||
+17
-10
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016-2022 CERN
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
@@ -60,7 +60,8 @@ public:
|
||||
|
||||
///< @copydoc SPICE_SIMULATOR::Attach()
|
||||
bool Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel, const wxString& aSimCommand,
|
||||
unsigned aSimOptions, REPORTER& aReporter ) override final;
|
||||
unsigned aSimOptions, const wxString& aInputPath,
|
||||
REPORTER& aReporter ) override final;
|
||||
|
||||
///< Load a netlist for the simulation
|
||||
bool LoadNetlist( const std::string& aNetlist ) override final;
|
||||
@@ -116,21 +117,24 @@ private:
|
||||
// ngspice library functions
|
||||
typedef void ( *ngSpice_Init )( SendChar*, SendStat*, ControlledExit*, SendData*, SendInitData*,
|
||||
BGThreadRunning*, void* );
|
||||
typedef int ( *ngSpice_Circ )( char** circarray );
|
||||
typedef int ( *ngSpice_Command )( char* command );
|
||||
|
||||
typedef int ( *ngSpice_Circ )( char** circarray );
|
||||
typedef int ( *ngSpice_Command )( char* command );
|
||||
typedef pvector_info ( *ngGet_Vec_Info )( char* vecname );
|
||||
typedef char* ( *ngSpice_CurPlot )( void );
|
||||
typedef char** ( *ngSpice_AllPlots )( void );
|
||||
typedef char** ( *ngSpice_AllVecs )( char* plotname );
|
||||
typedef bool ( *ngSpice_Running )( void );
|
||||
typedef int ( *ngSpice_LockRealloc )( void );
|
||||
typedef int ( *ngSpice_UnlockRealloc )( void );
|
||||
typedef char* ( *ngCM_Input_Path )( const char* path );
|
||||
typedef char* ( *ngSpice_CurPlot )( void );
|
||||
typedef char** ( *ngSpice_AllPlots )( void );
|
||||
typedef char** ( *ngSpice_AllVecs )( char* plotname );
|
||||
typedef bool ( *ngSpice_Running )( void );
|
||||
typedef int ( *ngSpice_LockRealloc )( void );
|
||||
typedef int ( *ngSpice_UnlockRealloc )( void );
|
||||
|
||||
///< Handle to DLL functions
|
||||
ngSpice_Init m_ngSpice_Init;
|
||||
ngSpice_Circ m_ngSpice_Circ;
|
||||
ngSpice_Command m_ngSpice_Command;
|
||||
ngGet_Vec_Info m_ngGet_Vec_Info;
|
||||
ngCM_Input_Path m_ngCM_Input_Path;
|
||||
ngSpice_CurPlot m_ngSpice_CurPlot;
|
||||
ngSpice_AllPlots m_ngSpice_AllPlots;
|
||||
ngSpice_AllVecs m_ngSpice_AllVecs;
|
||||
@@ -168,6 +172,9 @@ private:
|
||||
///< Check a few different locations for codemodel files and returns one if it exists.
|
||||
std::string findCmPath() const;
|
||||
|
||||
///< Send additional search path for codemodels to ngspice.
|
||||
bool setCodemodelsInputPath( const std::string& aPath );
|
||||
|
||||
///< Load codemodel files from a directory.
|
||||
bool loadCodemodels( const std::string& aPath );
|
||||
|
||||
|
||||
@@ -215,6 +215,19 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S
|
||||
}
|
||||
}
|
||||
|
||||
auto getOrCreateField =
|
||||
[&aSymbol, &fields]( const wxString& name ) -> SCH_FIELD*
|
||||
{
|
||||
for( SCH_FIELD& field : fields )
|
||||
{
|
||||
if( field.GetName().IsSameAs( name ) )
|
||||
return &field;
|
||||
}
|
||||
|
||||
fields.emplace_back( &aSymbol, -1, name );
|
||||
return &fields.back();
|
||||
};
|
||||
|
||||
wxString deviceType;
|
||||
wxString modelType;
|
||||
wxString modelParams;
|
||||
@@ -225,20 +238,13 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S
|
||||
if( SIM_MODEL::InferSimModel( aSymbol, &fields, true, SIM_VALUE_GRAMMAR::NOTATION::SI,
|
||||
&deviceType, &modelType, &modelParams, &pinMap ) )
|
||||
{
|
||||
fields.emplace_back( &aSymbol, -1, SIM_DEVICE_FIELD );
|
||||
fields.back().SetText( deviceType );
|
||||
getOrCreateField( SIM_DEVICE_FIELD )->SetText( deviceType );
|
||||
|
||||
if( !modelType.IsEmpty() )
|
||||
{
|
||||
fields.emplace_back( &aSymbol, -1, SIM_DEVICE_SUBTYPE_FIELD );
|
||||
fields.back().SetText( modelType );
|
||||
}
|
||||
getOrCreateField( SIM_DEVICE_SUBTYPE_FIELD )->SetText( modelType );
|
||||
|
||||
fields.emplace_back( &aSymbol, -1, SIM_PARAMS_FIELD );
|
||||
fields.back().SetText( modelParams );
|
||||
|
||||
fields.emplace_back( &aSymbol, -1, SIM_PINS_FIELD );
|
||||
fields.back().SetText( pinMap );
|
||||
getOrCreateField( SIM_PARAMS_FIELD )->SetText( modelParams );
|
||||
getOrCreateField( SIM_PINS_FIELD )->SetText( pinMap );
|
||||
|
||||
storeInValue = true;
|
||||
}
|
||||
|
||||
@@ -1602,6 +1602,8 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
|
||||
}
|
||||
}
|
||||
|
||||
// Up until 8.0.3 we
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ std::vector<std::string> SPICE_GENERATOR_KIBIS::CurrentNames( const SPICE_ITEM&
|
||||
|
||||
|
||||
std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PROJECT& aProject,
|
||||
const wxString& aCacheDir ) const
|
||||
const wxString& aCacheDir,
|
||||
REPORTER& aReporter ) const
|
||||
{
|
||||
std::string ibisLibFilename = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY::LIBRARY_FIELD );
|
||||
std::string ibisCompName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY::NAME_FIELD );
|
||||
@@ -71,6 +72,7 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PR
|
||||
|
||||
KIBIS kibis( std::string( path.c_str() ) );
|
||||
kibis.m_cacheDir = std::string( aCacheDir.c_str() );
|
||||
kibis.m_reporter = &aReporter;
|
||||
|
||||
if( !kibis.m_valid )
|
||||
THROW_IO_ERROR( wxString::Format( _( "Invalid IBIS file '%s'" ), ibisLibFilename ) );
|
||||
@@ -167,10 +169,10 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PR
|
||||
KIBIS_WAVEFORM_RECTANGULAR* waveform = new KIBIS_WAVEFORM_RECTANGULAR( &kibis );
|
||||
|
||||
if( const SIM_MODEL::PARAM* ton = m_model.FindParam( "ton" ) )
|
||||
waveform->m_ton = SIM_VALUE::ToDouble( ton->value, 1 );
|
||||
waveform->m_ton = SIM_VALUE::ToDouble( ton->value, 0 );
|
||||
|
||||
if( const SIM_MODEL::PARAM* toff = m_model.FindParam( "toff" ) )
|
||||
waveform->m_toff = SIM_VALUE::ToDouble( toff->value, 1 );
|
||||
waveform->m_toff = SIM_VALUE::ToDouble( toff->value, 0 );
|
||||
|
||||
if( const SIM_MODEL::PARAM* td = m_model.FindParam( "td" ) )
|
||||
waveform->m_delay = SIM_VALUE::ToDouble( td->value, 0 );
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <project.h>
|
||||
|
||||
class SIM_LIBRARY_KIBIS;
|
||||
class REPORTER;
|
||||
|
||||
|
||||
class SPICE_GENERATOR_KIBIS : public SPICE_GENERATOR
|
||||
@@ -42,7 +43,7 @@ public:
|
||||
std::vector<std::string> CurrentNames( const SPICE_ITEM& aItem ) const override;
|
||||
|
||||
std::string IbisDevice( const SPICE_ITEM& aItem, const PROJECT& aProject,
|
||||
const wxString& aCacheDir ) const;
|
||||
const wxString& aCacheDir, REPORTER& aReporter ) const;
|
||||
|
||||
protected:
|
||||
std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> GetInstanceParams() const override;
|
||||
|
||||
@@ -62,9 +62,9 @@ namespace SIM_MODEL_SERIALIZER_GRAMMAR
|
||||
quotedStringContent,
|
||||
one<'"'>> {};
|
||||
|
||||
struct flagParam : sor<TAO_PEGTL_ISTRING( "off" ), // VDMOS
|
||||
TAO_PEGTL_ISTRING( "thermal" ), // VDMOS
|
||||
TAO_PEGTL_ISTRING( "xpart" )> {}; // BSIM1
|
||||
struct flagParam : sor<seq<TAO_PEGTL_ISTRING( "off" ), not_at<alnum>>, // VDMOS
|
||||
seq<TAO_PEGTL_ISTRING( "thermal" ), not_at<alnum>>, // VDMOS
|
||||
seq<TAO_PEGTL_ISTRING( "xpart" ), not_at<alnum>>> {}; // BSIM1
|
||||
|
||||
struct fieldParamValuePair : sor<flagParam,
|
||||
if_must<param,
|
||||
|
||||
@@ -177,6 +177,9 @@ std::string SPICE_GENERATOR_SOURCE::ItemLine( const SPICE_ITEM& aItem ) const
|
||||
default:
|
||||
for( const SIM_MODEL::PARAM& param : m_model.GetParams() )
|
||||
{
|
||||
if( ac != "" && ( param.Matches( "ac" ) || param.Matches( "ph" ) ) )
|
||||
continue;
|
||||
|
||||
std::string argStr = SIM_VALUE::ToSpice( param.value );
|
||||
|
||||
if( argStr != "" )
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Sylwester Kocjan <s.kocjan@o2.pl>
|
||||
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022-2024 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
|
||||
@@ -59,7 +59,8 @@ public:
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
virtual bool Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel,
|
||||
const wxString& aSimCommand, unsigned aSimOptions, REPORTER& aReporter )
|
||||
const wxString& aSimCommand, unsigned aSimOptions,
|
||||
const wxString& aInputPath, REPORTER& aReporter )
|
||||
{
|
||||
m_simModel = aModel;
|
||||
return true;
|
||||
@@ -87,8 +88,8 @@ public:
|
||||
virtual bool IsRunning() = 0;
|
||||
|
||||
/**
|
||||
* Cleans simulation data (i.e. all vectors)
|
||||
*
|
||||
* Cleans simulation data (i.e. all vectors)
|
||||
*
|
||||
*/
|
||||
virtual void Clean() = 0;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016-2023 CERN
|
||||
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
@@ -61,6 +61,11 @@
|
||||
#include <memory>
|
||||
|
||||
|
||||
// Reporter is stored by pointer in KIBIS, so keep this here to avoid crashes
|
||||
static wxString s_errors;
|
||||
static WX_STRING_REPORTER s_reporter( &s_errors );
|
||||
|
||||
|
||||
class SIM_THREAD_REPORTER : public SIMULATOR_REPORTER
|
||||
{
|
||||
public:
|
||||
@@ -194,7 +199,7 @@ SIMULATOR_FRAME::~SIMULATOR_FRAME()
|
||||
{
|
||||
NULL_REPORTER devnull;
|
||||
|
||||
m_simulator->Attach( nullptr, wxEmptyString, 0, devnull );
|
||||
m_simulator->Attach( nullptr, wxEmptyString, 0, wxEmptyString, devnull );
|
||||
m_simulator->SetReporter( nullptr );
|
||||
delete m_reporter;
|
||||
}
|
||||
@@ -338,8 +343,7 @@ void SIMULATOR_FRAME::UpdateTitle()
|
||||
|
||||
bool SIMULATOR_FRAME::LoadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
|
||||
{
|
||||
wxString errors;
|
||||
WX_STRING_REPORTER reporter( &errors );
|
||||
s_errors.clear();
|
||||
|
||||
if( !m_schematicFrame->ReadyToNetlist( _( "Simulator requires a fully annotated schematic." ) ) )
|
||||
return false;
|
||||
@@ -348,9 +352,10 @@ bool SIMULATOR_FRAME::LoadSimulator( const wxString& aSimCommand, unsigned aSimO
|
||||
if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
|
||||
m_schematicFrame->RecalculateConnections( nullptr, GLOBAL_CLEANUP );
|
||||
|
||||
if( !m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions, reporter ) )
|
||||
if( !m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions, Prj().GetProjectPath(),
|
||||
s_reporter ) )
|
||||
{
|
||||
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" ) + errors );
|
||||
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" ) + s_errors );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -360,12 +365,10 @@ bool SIMULATOR_FRAME::LoadSimulator( const wxString& aSimCommand, unsigned aSimO
|
||||
|
||||
void SIMULATOR_FRAME::ReloadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
|
||||
{
|
||||
wxString errors;
|
||||
WX_STRING_REPORTER reporter( &errors );
|
||||
|
||||
if( !m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions, reporter ) )
|
||||
if( !m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions, Prj().GetProjectPath(),
|
||||
s_reporter ) )
|
||||
{
|
||||
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" ) + errors );
|
||||
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" ) + s_errors );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,6 +441,10 @@ void SIMULATOR_FRAME::StartSimulation()
|
||||
{
|
||||
m_ui->OnSimUpdate();
|
||||
m_simulator->Run();
|
||||
|
||||
// Netlist from schematic may have changed; update signals list, measurements list,
|
||||
// etc.
|
||||
m_ui->OnPlotSettingsChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -544,17 +551,17 @@ bool SIMULATOR_FRAME::EditAnalysis()
|
||||
{
|
||||
SIM_TAB* simTab = m_ui->GetCurrentSimTab();
|
||||
DIALOG_SIM_COMMAND dlg( this, m_circuitModel, m_simulator->Settings() );
|
||||
wxString errors;
|
||||
WX_STRING_REPORTER reporter( &errors );
|
||||
|
||||
s_errors.clear();
|
||||
|
||||
if( !simTab )
|
||||
return false;
|
||||
|
||||
if( !m_circuitModel->ReadSchematicAndLibraries( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS,
|
||||
reporter ) )
|
||||
s_reporter ) )
|
||||
{
|
||||
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" )
|
||||
+ errors );
|
||||
+ s_errors );
|
||||
}
|
||||
|
||||
dlg.SetSimCommand( simTab->GetSimCommand() );
|
||||
|
||||
@@ -104,8 +104,7 @@ namespace SPICE_GRAMMAR
|
||||
one<']'>> {};
|
||||
|
||||
struct bracedExpr : seq<one<'{'>,
|
||||
star<sor<bracedExpr,
|
||||
not_one<'}'>>>,
|
||||
star<not_one<'}'>>,
|
||||
one<'}'>> {};
|
||||
|
||||
// Ngspice has some heuristic logic to allow + and - in tokens. We replicate that here.
|
||||
@@ -132,6 +131,16 @@ namespace SPICE_GRAMMAR
|
||||
sep,
|
||||
paramValue> {};
|
||||
struct paramValuePairs : list<paramValuePair, sep> {};
|
||||
|
||||
struct cplSep : opt<one<' '>> {};
|
||||
struct cplParamValue : sor<list<bracedExpr, cplSep>,
|
||||
vectorExpr,
|
||||
list<token, cplSep>> {};
|
||||
struct cplParamValuePair : seq<param,
|
||||
sep,
|
||||
cplParamValue> {};
|
||||
struct cplParamValuePairs : list<cplParamValuePair, sep> {};
|
||||
|
||||
struct dotModelAko : seq<opt<sep>,
|
||||
if_must<seq<TAO_PEGTL_ISTRING( ".model" ),
|
||||
sep,
|
||||
@@ -147,6 +156,17 @@ namespace SPICE_GRAMMAR
|
||||
opt<sep>,
|
||||
newline>> {};
|
||||
|
||||
struct dotModelCPL : seq<opt<sep>,
|
||||
if_must<seq<TAO_PEGTL_ISTRING( ".model" ),
|
||||
sep,
|
||||
modelName,
|
||||
sep,
|
||||
TAO_PEGTL_ISTRING( "CPL" )>,
|
||||
opt<sep,
|
||||
cplParamValuePairs>,
|
||||
opt<sep>,
|
||||
newline>> {};
|
||||
|
||||
struct dotModel : seq<opt<sep>,
|
||||
if_must<TAO_PEGTL_ISTRING( ".model" ),
|
||||
sep,
|
||||
@@ -157,8 +177,6 @@ namespace SPICE_GRAMMAR
|
||||
paramValuePairs>,
|
||||
opt<sep>,
|
||||
newline>> {};
|
||||
|
||||
|
||||
|
||||
struct dotSubcktParamValuePair : seq<param,
|
||||
// TODO: Check if these `star<space>`s match Ngspice's
|
||||
@@ -176,7 +194,8 @@ namespace SPICE_GRAMMAR
|
||||
struct dotSubcktPinName : seq<not_at<dotSubcktParams>,
|
||||
plus<not_at<space>, any>> {};
|
||||
struct dotSubcktPinSequence : list<dotSubcktPinName, sep> {};
|
||||
struct dotSubcktEnd : seq<TAO_PEGTL_ISTRING( ".ends" ),
|
||||
struct dotSubcktEnd : seq<opt<sep>,
|
||||
TAO_PEGTL_ISTRING( ".ends" ),
|
||||
until<newline>> {};
|
||||
struct spiceUnit;
|
||||
struct dotSubckt : seq<opt<sep>,
|
||||
@@ -195,6 +214,7 @@ namespace SPICE_GRAMMAR
|
||||
|
||||
struct modelUnit : seq<star<commentLine>,
|
||||
sor<dotModelAko,
|
||||
dotModelCPL,
|
||||
dotModel,
|
||||
dotSubckt>> {};
|
||||
|
||||
@@ -284,7 +304,9 @@ namespace SPICE_GRAMMAR
|
||||
"";
|
||||
template <> inline constexpr auto errorMessage<opt<sep, paramValuePairs>> =
|
||||
"";
|
||||
template <> inline constexpr auto errorMessage<opt<sep, dotSubcktPinSequence>> =
|
||||
template <> inline constexpr auto errorMessage<opt<sep, cplParamValuePairs>> =
|
||||
"";
|
||||
template <> inline constexpr auto errorMessage<opt<sep, dotSubcktPinSequence>> =
|
||||
"";
|
||||
template <> inline constexpr auto errorMessage<opt<sep, dotSubcktParams>> =
|
||||
"";
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Author Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2024 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
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "lib_symbol.h"
|
||||
#include "sch_symbol.h"
|
||||
#include "sch_pin.h"
|
||||
|
||||
struct ORIENT_MIRROR
|
||||
{
|
||||
int flag;
|
||||
int n_rots;
|
||||
int mirror_x;
|
||||
int mirror_y;
|
||||
};
|
||||
|
||||
|
||||
// symbols_orientations_list is the list of possible orientation+mirror values
|
||||
// like returned by SCH_SYMBOL::GetOrientation()
|
||||
// Some transforms are equivalent, like rotation 180 + mirror X = mirror Y
|
||||
|
||||
static ORIENT_MIRROR symbols_orientations_list[] =
|
||||
{
|
||||
{ SYM_ORIENT_0, 0, 0, 0 },
|
||||
{ SYM_ORIENT_90, 1, 0, 0 },
|
||||
{ SYM_ORIENT_180, 2, 0, 0 },
|
||||
{ SYM_ORIENT_270, 3, 0, 0 },
|
||||
{ SYM_MIRROR_X + SYM_ORIENT_0, 0, 1, 0 },
|
||||
{ SYM_MIRROR_X + SYM_ORIENT_90, 1, 1, 0 },
|
||||
{ SYM_MIRROR_Y, 0, 0, 1 },
|
||||
{ SYM_MIRROR_X + SYM_ORIENT_270, 3, 1, 0 },
|
||||
{ SYM_MIRROR_Y + SYM_ORIENT_0, 0, 0, 1 },
|
||||
{ SYM_MIRROR_Y + SYM_ORIENT_90, 1, 0, 1 },
|
||||
{ SYM_MIRROR_Y + SYM_ORIENT_180, 2, 0, 1 },
|
||||
{ SYM_MIRROR_Y + SYM_ORIENT_270, 3, 0, 1 }
|
||||
};
|
||||
|
||||
|
||||
void OrientAndMirrorSymbolItems( LIB_SYMBOL* aSymbol, int aOrientation )
|
||||
{
|
||||
ORIENT_MIRROR o = symbols_orientations_list[ 0 ];
|
||||
|
||||
for( ORIENT_MIRROR& i : symbols_orientations_list )
|
||||
{
|
||||
if( i.flag == aOrientation )
|
||||
{
|
||||
o = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( LIB_ITEM& item : aSymbol->GetDrawItems() )
|
||||
{
|
||||
for( int i = 0; i < o.n_rots; i++ )
|
||||
item.Rotate( VECTOR2I( 0, 0 ), true );
|
||||
|
||||
if( o.mirror_x )
|
||||
item.MirrorVertical( VECTOR2I( 0, 0 ) );
|
||||
|
||||
if( o.mirror_y )
|
||||
item.MirrorHorizontal( VECTOR2I( 0, 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Rotate and/or mirror a SCH_PIN according to aOrientMirror.
|
||||
// aOrientMirror is the orientation/mirror of the parent symbol.
|
||||
// The modified pin orientation is the actual pin orientation/mirror
|
||||
// when the parent symbol is drawn.
|
||||
void RotateAndMirrorPin( LIB_PIN& aPin, int aOrientMirror )
|
||||
{
|
||||
ORIENT_MIRROR o = symbols_orientations_list[ 0 ];
|
||||
|
||||
for( ORIENT_MIRROR& i : symbols_orientations_list )
|
||||
{
|
||||
if( i.flag == aOrientMirror )
|
||||
{
|
||||
o = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < o.n_rots; i++ )
|
||||
aPin.Rotate( VECTOR2I( 0, 0 ), true );
|
||||
|
||||
if( o.mirror_x )
|
||||
aPin.MirrorVertical( VECTOR2I( 0, 0 ) );
|
||||
|
||||
if( o.mirror_y )
|
||||
aPin.MirrorHorizontal( VECTOR2I( 0, 0 ) );
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Author Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2024 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
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class LIB_SYMBOL;
|
||||
class LIB_PIN;
|
||||
|
||||
/**
|
||||
* Rotate and/or mirror graphic objects of LIB_SYMBOL aSymbol according to aOrientMirror.
|
||||
* @param aLibSymbol is the LIB_SYMBOL to modify
|
||||
* @param aOrientation is the orientation+mirror value like returned by SCH_SYMBOL::GetOrientation()
|
||||
*/
|
||||
void OrientAndMirrorSymbolItems( LIB_SYMBOL* aLibSymbol, int aOrientation );
|
||||
|
||||
|
||||
/**
|
||||
* Rotate and/or mirror a SCH_PIN according to aOrientMirror.
|
||||
* aOrientMirror is usually the orientation/mirror of the parent symbol.
|
||||
* The modified pin orientation is the actual pin orientation/mirror
|
||||
* when the parent symbol is drawn.
|
||||
* @param aPin is the SCH_PIN to modify
|
||||
* @param aOrientation is the orientation+mirror value like returned by SCH_SYMBOL::GetOrientation()
|
||||
*/
|
||||
void RotateAndMirrorPin( LIB_PIN& aPin, int aOrientMirror );
|
||||
@@ -1282,7 +1282,7 @@ void SYMBOL_EDIT_FRAME::UpdateSymbolMsgPanelInfo()
|
||||
else if( m_bodyStyle == LIB_ITEM::BODY_STYLE::BASE )
|
||||
msg = _( "Standard" );
|
||||
else
|
||||
wxT( "?" );
|
||||
msg = wxT( "?" );
|
||||
|
||||
AppendMsgPanel( _( "Body" ), msg, 8 );
|
||||
|
||||
|
||||
@@ -359,10 +359,9 @@ SYMBOL_LIB_TABLE_ROW* SYMBOL_LIB_TABLE::FindRow( const wxString& aNickname, bool
|
||||
// instantiate a PLUGIN of the proper kind if it is not already in this
|
||||
// SYMBOL_LIB_TABLE_ROW.
|
||||
if( !row->plugin )
|
||||
{
|
||||
row->setPlugin( SCH_IO_MGR::FindPlugin( row->type ) );
|
||||
row->plugin->SetLibTable( this );
|
||||
}
|
||||
|
||||
row->plugin->SetLibTable( this );
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
#include <view/view_controls.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "symb_transforms_utils.h"
|
||||
|
||||
SELECTION_CONDITION EE_CONDITIONS::SingleSymbol = []( const SELECTION& aSel )
|
||||
{
|
||||
@@ -148,6 +149,12 @@ SELECTION_CONDITION EE_CONDITIONS::AllPins = []( const SELECTION& aSel )
|
||||
};
|
||||
|
||||
|
||||
SELECTION_CONDITION EE_CONDITIONS::AllPinsOrSheetPins = []( const SELECTION& aSel )
|
||||
{
|
||||
return aSel.GetSize() >= 1 && aSel.OnlyContains( { SCH_PIN_T, SCH_SHEET_PIN_T } );
|
||||
};
|
||||
|
||||
|
||||
#define HITTEST_THRESHOLD_PIXELS 5
|
||||
|
||||
|
||||
@@ -364,6 +371,42 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
KIID lastRolloverItem = niluuid;
|
||||
EE_GRID_HELPER grid( m_toolMgr );
|
||||
|
||||
auto pinOrientation =
|
||||
[]( EDA_ITEM* aItem )
|
||||
{
|
||||
SCH_PIN* pin = dynamic_cast<SCH_PIN*>( aItem );
|
||||
|
||||
if( pin )
|
||||
{
|
||||
const SCH_SYMBOL* parent = dynamic_cast<const SCH_SYMBOL*>( pin->GetParentSymbol() );
|
||||
|
||||
if( !parent )
|
||||
return pin->GetOrientation();
|
||||
else
|
||||
{
|
||||
LIB_PIN dummy( *pin->GetLibPin() );
|
||||
RotateAndMirrorPin( dummy, parent->GetOrientation() );
|
||||
return dummy.GetOrientation();
|
||||
}
|
||||
}
|
||||
|
||||
SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( aItem );
|
||||
|
||||
if( sheetPin )
|
||||
{
|
||||
switch( sheetPin->GetSide() )
|
||||
{
|
||||
default:
|
||||
case SHEET_SIDE::LEFT: return PIN_ORIENTATION::PIN_RIGHT;
|
||||
case SHEET_SIDE::RIGHT: return PIN_ORIENTATION::PIN_LEFT;
|
||||
case SHEET_SIDE::TOP: return PIN_ORIENTATION::PIN_DOWN;
|
||||
case SHEET_SIDE::BOTTOM: return PIN_ORIENTATION::PIN_UP;
|
||||
}
|
||||
}
|
||||
|
||||
return PIN_ORIENTATION::PIN_LEFT;
|
||||
};
|
||||
|
||||
// Main loop: keep receiving events
|
||||
while( TOOL_EVENT* evt = Wait() )
|
||||
{
|
||||
@@ -621,8 +664,11 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
else if( *evt->GetCommandId() >= ID_POPUP_SCH_PIN_TRICKS_START
|
||||
&& *evt->GetCommandId() <= ID_POPUP_SCH_PIN_TRICKS_END )
|
||||
{
|
||||
if( !m_selection.OnlyContains( { SCH_PIN_T } ) || m_selection.Empty() )
|
||||
if( !m_selection.OnlyContains( { SCH_PIN_T, SCH_SHEET_PIN_T } )
|
||||
|| m_selection.Empty() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Keep track of new items so we make them the new selection at the end
|
||||
EDA_ITEMS newItems;
|
||||
@@ -632,8 +678,7 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
for( EDA_ITEM* item : m_selection )
|
||||
{
|
||||
SCH_PIN* pin = static_cast<SCH_PIN*>( item );
|
||||
SCH_NO_CONNECT* nc = new SCH_NO_CONNECT( pin->GetPosition() );
|
||||
SCH_NO_CONNECT* nc = new SCH_NO_CONNECT( item->GetPosition() );
|
||||
commit.Add( nc, m_frame->GetScreen() );
|
||||
newItems.push_back( nc );
|
||||
}
|
||||
@@ -647,14 +692,13 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
|
||||
for( EDA_ITEM* item : m_selection )
|
||||
{
|
||||
SCH_PIN* pin = static_cast<SCH_PIN*>( item );
|
||||
SCH_LINE* wire = new SCH_LINE( pin->GetPosition(), LAYER_WIRE );
|
||||
SCH_LINE* wire = new SCH_LINE( item->GetPosition(), LAYER_WIRE );
|
||||
|
||||
// Add some length to the wire as nothing in our code base handles
|
||||
// 0 length wires very well, least of all the ortho drag algorithm
|
||||
VECTOR2I stub;
|
||||
|
||||
switch( pin->GetOrientation() )
|
||||
switch( pinOrientation( item ) )
|
||||
{
|
||||
case PIN_ORIENTATION::PIN_LEFT:
|
||||
stub = VECTOR2I( 1 * wireGrid.x, 0 );
|
||||
@@ -670,7 +714,7 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
break;
|
||||
}
|
||||
|
||||
wire->SetEndPoint( pin->GetPosition() + stub );
|
||||
wire->SetEndPoint( item->GetPosition() + stub );
|
||||
|
||||
m_frame->AddToScreen( wire, m_frame->GetScreen() );
|
||||
commit.Added( wire, m_frame->GetScreen() );
|
||||
@@ -702,24 +746,33 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
// selected by the user
|
||||
for( EDA_ITEM* item : m_selection )
|
||||
{
|
||||
SCH_PIN* pin = static_cast<SCH_PIN*>( item );
|
||||
SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item );
|
||||
SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( item );
|
||||
SCH_EDIT_FRAME* sf = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
|
||||
SCH_LABEL_BASE* label = nullptr;
|
||||
|
||||
wxString labelText;
|
||||
|
||||
if( pin )
|
||||
labelText = pin->GetShownName();
|
||||
else if( sheetPin && sf )
|
||||
labelText = sheetPin->GetShownText( &sf->GetCurrentSheet(), false );
|
||||
|
||||
switch( *evt->GetCommandId() )
|
||||
{
|
||||
case ID_POPUP_SCH_PIN_TRICKS_NET_LABEL:
|
||||
label = new SCH_LABEL( pin->GetPosition(), pin->GetShownName() );
|
||||
label = new SCH_LABEL( item->GetPosition(), labelText );
|
||||
break;
|
||||
case ID_POPUP_SCH_PIN_TRICKS_HIER_LABEL:
|
||||
label = new SCH_HIERLABEL( pin->GetPosition(), pin->GetShownName() );
|
||||
label = new SCH_HIERLABEL( item->GetPosition(), labelText );
|
||||
break;
|
||||
case ID_POPUP_SCH_PIN_TRICKS_GLOBAL_LABEL:
|
||||
label = new SCH_GLOBALLABEL( pin->GetPosition(), pin->GetShownName() );
|
||||
label = new SCH_GLOBALLABEL( item->GetPosition(), labelText );
|
||||
break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
switch( pin->GetOrientation() )
|
||||
switch( pinOrientation( item ) )
|
||||
{
|
||||
case PIN_ORIENTATION::PIN_LEFT:
|
||||
label->SetSpinStyle( SPIN_STYLE::SPIN::RIGHT );
|
||||
@@ -735,7 +788,25 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
break;
|
||||
}
|
||||
|
||||
switch( pin->GetType() )
|
||||
ELECTRICAL_PINTYPE pinType = ELECTRICAL_PINTYPE::PT_UNSPECIFIED;
|
||||
|
||||
if( pin )
|
||||
{
|
||||
pinType = pin->GetType();
|
||||
}
|
||||
else if( sheetPin )
|
||||
{
|
||||
switch( sheetPin->GetLabelShape() )
|
||||
{
|
||||
case LABEL_INPUT: pinType = ELECTRICAL_PINTYPE::PT_INPUT; break;
|
||||
case LABEL_OUTPUT: pinType = ELECTRICAL_PINTYPE::PT_OUTPUT; break;
|
||||
case LABEL_BIDI: pinType = ELECTRICAL_PINTYPE::PT_BIDI; break;
|
||||
case LABEL_TRISTATE: pinType = ELECTRICAL_PINTYPE::PT_TRISTATE; break;
|
||||
case LABEL_PASSIVE: pinType = ELECTRICAL_PINTYPE::PT_PASSIVE; break;
|
||||
}
|
||||
}
|
||||
|
||||
switch( pinType )
|
||||
{
|
||||
case ELECTRICAL_PINTYPE::PT_BIDI:
|
||||
label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
|
||||
@@ -953,6 +1024,19 @@ OPT_TOOL_EVENT EE_SELECTION_TOOL::autostartEvent( TOOL_EVENT* aEvent, EE_GRID_HE
|
||||
if( possibleConnection.IsBus() )
|
||||
newEvt = EE_ACTIONS::drawBus.MakeEvent();
|
||||
}
|
||||
else if( aItem->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( aItem );
|
||||
|
||||
wxCHECK( symbol, OPT_TOOL_EVENT() );
|
||||
|
||||
const SCH_PIN* pin = symbol->GetPin( pos );
|
||||
|
||||
wxCHECK( pin, OPT_TOOL_EVENT() );
|
||||
|
||||
if( !pin->IsVisible() && !m_frame->eeconfig()->m_Appearance.show_hidden_pins )
|
||||
return OPT_TOOL_EVENT();
|
||||
}
|
||||
|
||||
newEvt->SetMousePosition( pos );
|
||||
newEvt->SetHasPosition( true );
|
||||
@@ -1354,8 +1438,14 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if( m_frame->GetRenderSettings()->m_ShowPinsElectricalType )
|
||||
item->SetFlags( SHOW_ELEC_TYPE );
|
||||
|
||||
if( item->HitTest( aPos, 0 ) )
|
||||
exactHits.insert( item );
|
||||
|
||||
item->ClearFlags( SHOW_ELEC_TYPE );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1382,6 +1472,11 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
|
||||
BOX2I bbox = item->GetBoundingBox();
|
||||
int dist = INT_MAX / 4;
|
||||
|
||||
// A dominating item is one that would unfairly win distance tests
|
||||
// and mask out other items. For example, a filled rectangle "wins"
|
||||
// with a zero distance over anything inside it.
|
||||
bool dominating = false;
|
||||
|
||||
if( exactHits.count( item ) )
|
||||
{
|
||||
if( item->Type() == SCH_PIN_T || item->Type() == SCH_JUNCTION_T )
|
||||
@@ -1438,6 +1533,9 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
|
||||
|
||||
delete s;
|
||||
}
|
||||
|
||||
// Filled shapes win hit tests anywhere inside them
|
||||
dominating = shape->IsFilled();
|
||||
}
|
||||
else if( symbol )
|
||||
{
|
||||
@@ -1461,15 +1559,21 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
|
||||
rect.Collide( poss, collector.m_Threshold, &dist );
|
||||
}
|
||||
|
||||
if( dist == closestDist )
|
||||
// Don't promote dominating items to be the closest item
|
||||
// (they'll always win) - they'll still be available for selection, but they
|
||||
// won't boot out worthy competitors.
|
||||
if ( !dominating )
|
||||
{
|
||||
if( item->GetParent() == closest )
|
||||
if( dist == closestDist )
|
||||
{
|
||||
if( item->GetParent() == closest )
|
||||
closest = item;
|
||||
}
|
||||
else if( dist < closestDist )
|
||||
{
|
||||
closestDist = dist;
|
||||
closest = item;
|
||||
}
|
||||
else if( dist < closestDist )
|
||||
{
|
||||
closestDist = dist;
|
||||
closest = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
static SELECTION_CONDITION SingleNonExcludedMarker;
|
||||
static SELECTION_CONDITION MultipleSymbolsOrPower;
|
||||
static SELECTION_CONDITION AllPins;
|
||||
static SELECTION_CONDITION AllPinsOrSheetPins;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -308,7 +308,13 @@ int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
|
||||
SYMBOL_LIB_TABLE* libs = PROJECT_SCH::SchSymbolLibTable( &m_frame->Prj() );
|
||||
SYMBOL_LIB* cache = PROJECT_SCH::SchLibs( &m_frame->Prj() )->GetCacheLibrary();
|
||||
|
||||
std::vector<LIB_SYMBOL*> part_list;
|
||||
auto compareByLibID =
|
||||
[]( const LIB_SYMBOL* aFirst, const LIB_SYMBOL* aSecond ) -> bool
|
||||
{
|
||||
return aFirst->LibId().Format() < aSecond->LibId().Format();
|
||||
};
|
||||
|
||||
std::set<LIB_SYMBOL*, decltype( compareByLibID )> part_list( compareByLibID );
|
||||
|
||||
for( SCH_SHEET_PATH& sheet : sheets )
|
||||
{
|
||||
@@ -321,15 +327,12 @@ int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
|
||||
LIB_SYMBOL* libSymbol = SchGetLibSymbol( s->GetLibId(), libs, cache );
|
||||
|
||||
if( libSymbol )
|
||||
part_list.push_back( libSymbol );
|
||||
part_list.insert( libSymbol );
|
||||
}
|
||||
}
|
||||
|
||||
// Remove redundant parts
|
||||
sort( part_list.begin(), part_list.end() );
|
||||
part_list.erase( unique( part_list.begin(), part_list.end() ), part_list.end() );
|
||||
|
||||
std::vector<PICKED_SYMBOL> alreadyPlaced;
|
||||
|
||||
for( LIB_SYMBOL* libSymbol : part_list )
|
||||
{
|
||||
PICKED_SYMBOL pickedSymbol;
|
||||
|
||||
@@ -189,10 +189,11 @@ private:
|
||||
EE_SELECTION_TOOL* selTool = getToolManager()->GetTool<EE_SELECTION_TOOL>();
|
||||
EE_SELECTION& selection = selTool->GetSelection();
|
||||
SCH_PIN* pin = dynamic_cast<SCH_PIN*>( selection.Front() );
|
||||
SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( selection.Front() );
|
||||
|
||||
Clear();
|
||||
|
||||
if( !pin )
|
||||
if( !pin && !sheetPin )
|
||||
return;
|
||||
|
||||
Add( _( "Wire" ), ID_POPUP_SCH_PIN_TRICKS_WIRE, BITMAPS::add_line );
|
||||
@@ -578,7 +579,7 @@ bool SCH_EDIT_TOOL::Init()
|
||||
|
||||
selToolMenu.AddMenu( makeSymbolUnitMenu( m_selectionTool ), E_C::SingleMultiUnitSymbol, 1 );
|
||||
selToolMenu.AddMenu( makePinFunctionMenu( m_selectionTool ), E_C::SingleMultiFunctionPin, 1 );
|
||||
selToolMenu.AddMenu( makePinTricksMenu( m_selectionTool ), E_C::AllPins, 1 );
|
||||
selToolMenu.AddMenu( makePinTricksMenu( m_selectionTool ), E_C::AllPinsOrSheetPins, 1 );
|
||||
|
||||
selToolMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
|
||||
selToolMenu.AddMenu( makeAttributesMenu(), E_C::HasType( SCH_SYMBOL_T ), 200 );
|
||||
@@ -1556,14 +1557,7 @@ void SCH_EDIT_TOOL::editFieldText( SCH_FIELD* aField )
|
||||
|
||||
int SCH_EDIT_TOOL::EditField( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
EE_SELECTION sel;
|
||||
|
||||
if( aEvent.IsAction( &EE_ACTIONS::editReference ) )
|
||||
sel = m_selectionTool->RequestSelection( { SCH_FIELD_LOCATE_REFERENCE_T, SCH_SYMBOL_T } );
|
||||
else if( aEvent.IsAction( &EE_ACTIONS::editValue ) )
|
||||
sel = m_selectionTool->RequestSelection( { SCH_FIELD_LOCATE_VALUE_T, SCH_SYMBOL_T } );
|
||||
else if( aEvent.IsAction( &EE_ACTIONS::editFootprint ) )
|
||||
sel = m_selectionTool->RequestSelection( { SCH_FIELD_LOCATE_FOOTPRINT_T, SCH_SYMBOL_T } );
|
||||
EE_SELECTION sel = m_selectionTool->RequestSelection( { SCH_FIELD_T, SCH_SYMBOL_T } );
|
||||
|
||||
if( sel.Size() != 1 )
|
||||
return 0;
|
||||
@@ -1571,6 +1565,20 @@ int SCH_EDIT_TOOL::EditField( const TOOL_EVENT& aEvent )
|
||||
bool clearSelection = sel.IsHover();
|
||||
EDA_ITEM* item = sel.Front();
|
||||
|
||||
if( item->Type() == SCH_FIELD_T )
|
||||
{
|
||||
SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
|
||||
|
||||
if( ( aEvent.IsAction( &EE_ACTIONS::editReference ) && field->GetId() != REFERENCE_FIELD )
|
||||
|| ( aEvent.IsAction( &EE_ACTIONS::editValue ) && field->GetId() != VALUE_FIELD )
|
||||
|| ( aEvent.IsAction( &EE_ACTIONS::editFootprint ) && field->GetId() != FOOTPRINT_FIELD ) )
|
||||
{
|
||||
item = field->GetParent();
|
||||
m_selectionTool->ClearSelection( true );
|
||||
m_selectionTool->AddItemToSel( item );
|
||||
}
|
||||
}
|
||||
|
||||
if( item->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
@@ -1783,37 +1791,35 @@ int SCH_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
else if( retval == SYMBOL_PROPS_EDIT_SCHEMATIC_SYMBOL )
|
||||
{
|
||||
auto editor = (SYMBOL_EDIT_FRAME*) m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR,
|
||||
true );
|
||||
if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, true ) )
|
||||
{
|
||||
SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( frame );
|
||||
|
||||
wxCHECK( editor, 0 );
|
||||
if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
|
||||
blocking_win->Close( true );
|
||||
|
||||
if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
|
||||
blocking_win->Close( true );
|
||||
// The broken library symbol link indicator cannot be edited.
|
||||
if( symbol->IsMissingLibSymbol() )
|
||||
return 0;
|
||||
|
||||
// The broken library symbol link indicator cannot be edited.
|
||||
if( symbol->IsMissingLibSymbol() )
|
||||
return 0;
|
||||
|
||||
editor->LoadSymbolFromSchematic( symbol );
|
||||
|
||||
editor->Show( true );
|
||||
editor->Raise();
|
||||
editor->LoadSymbolFromSchematic( symbol );
|
||||
editor->Show( true );
|
||||
editor->Raise();
|
||||
}
|
||||
}
|
||||
else if( retval == SYMBOL_PROPS_EDIT_LIBRARY_SYMBOL )
|
||||
{
|
||||
auto editor = (SYMBOL_EDIT_FRAME*) m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR,
|
||||
true );
|
||||
if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, true ) )
|
||||
{
|
||||
SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( frame );
|
||||
|
||||
wxCHECK( editor, 0 );
|
||||
if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
|
||||
blocking_win->Close( true );
|
||||
|
||||
if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
|
||||
blocking_win->Close( true );
|
||||
|
||||
editor->LoadSymbol( symbol->GetLibId(), symbol->GetUnit(), symbol->GetBodyStyle() );
|
||||
|
||||
editor->Show( true );
|
||||
editor->Raise();
|
||||
editor->LoadSymbol( symbol->GetLibId(), symbol->GetUnit(), symbol->GetBodyStyle() );
|
||||
editor->Show( true );
|
||||
editor->Raise();
|
||||
}
|
||||
}
|
||||
else if( retval == SYMBOL_PROPS_WANT_UPDATE_SYMBOL )
|
||||
{
|
||||
|
||||
@@ -536,8 +536,8 @@ int SCH_EDITOR_CONTROL::ExportSymbolsToLibrary( const TOOL_EVENT& aEvent )
|
||||
int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
|
||||
SIMULATOR_FRAME* simFrame = (SIMULATOR_FRAME*) m_frame->Kiway().Player( FRAME_SIMULATOR,
|
||||
false );
|
||||
KIWAY_PLAYER* player = m_frame->Kiway().Player( FRAME_SIMULATOR, false );
|
||||
SIMULATOR_FRAME* simFrame = static_cast<SIMULATOR_FRAME*>( player );
|
||||
|
||||
if( !simFrame ) // Defensive coding; shouldn't happen.
|
||||
return 0;
|
||||
|
||||
@@ -142,6 +142,18 @@ void SCH_MOVE_TOOL::orthoLineDrag( SCH_COMMIT* aCommit, SCH_LINE* line, const VE
|
||||
foundPin = true;
|
||||
break;
|
||||
|
||||
case SCH_SHEET_T:
|
||||
for( const auto& pair : m_specialCaseSheetPins )
|
||||
{
|
||||
if( pair.first->IsConnected( selectedEnd ) )
|
||||
{
|
||||
foundPin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1100,11 +1112,17 @@ void SCH_MOVE_TOOL::getConnectedItems( SCH_ITEM* aOriginalItem, const VECTOR2I&
|
||||
for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( test )->GetPins() )
|
||||
{
|
||||
if( pin->IsConnected( aPoint ) )
|
||||
m_specialCaseSheetPins[ pin ] = { line, line->GetStartPoint() == aPoint };
|
||||
{
|
||||
if( pin->IsSelected() )
|
||||
m_specialCaseSheetPins[pin] = { line,
|
||||
line->GetStartPoint() == aPoint };
|
||||
|
||||
aList.push_back( pin );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KI_FALLTHROUGH;
|
||||
break;
|
||||
|
||||
case SCH_SYMBOL_T:
|
||||
case SCH_JUNCTION_T:
|
||||
@@ -1210,6 +1228,22 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_COMMIT* aCommit, SCH_ITEM* aSelec
|
||||
|
||||
for( SCH_ITEM* item : itemsOverlappingRTree )
|
||||
{
|
||||
if( item->Type() == SCH_SHEET_T )
|
||||
{
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
|
||||
for( SCH_SHEET_PIN* pin : sheet->GetPins() )
|
||||
{
|
||||
if( !pin->IsSelected() && pin->GetPosition() == aSelectedItem->GetPosition()
|
||||
&& pin->CanConnect( aSelectedItem ) )
|
||||
{
|
||||
itemsConnectable.push_back( pin );
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip ourselves, skip already selected items (but not lines, they need both ends tested)
|
||||
// and skip unconnectable items
|
||||
if( item == aSelectedItem || ( item->Type() != SCH_LINE_T && item->IsSelected() )
|
||||
@@ -1404,6 +1438,7 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_COMMIT* aCommit, SCH_ITEM* aSelec
|
||||
case SCH_GLOBAL_LABEL_T:
|
||||
case SCH_HIER_LABEL_T:
|
||||
case SCH_DIRECTIVE_LABEL_T:
|
||||
case SCH_SHEET_PIN_T:
|
||||
// Performance optimization:
|
||||
if( test->HasFlag( SELECTED_BY_DRAG ) )
|
||||
break;
|
||||
|
||||
@@ -211,7 +211,7 @@ int SIMULATOR_CONTROL::ExportPlotAsCSV( const TOOL_EVENT& aEvent )
|
||||
out.Write( wxString::Format( wxT( "%s%c" ), xAxisName, SEPARATOR ) );
|
||||
|
||||
for( const auto& [name, trace] : traces )
|
||||
out.Write( wxString::Format( wxT( "%s%c" ), name, SEPARATOR ) );
|
||||
out.Write( wxString::Format( wxT( "%s%c" ), trace->GetDisplayName(), SEPARATOR ) );
|
||||
|
||||
out.Write( wxS( "\r\n" ) );
|
||||
|
||||
|
||||
@@ -172,8 +172,8 @@ int SYMBOL_EDITOR_CONTROL::AddSymbol( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
SYMBOL_EDIT_FRAME* editFrame = static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
|
||||
|
||||
LIB_ID sel = editFrame->GetTreeLIBID();
|
||||
const wxString& libName = sel.GetLibNickname();
|
||||
LIB_ID target = editFrame->GetTargetLibId();
|
||||
const wxString& libName = target.GetLibNickname();
|
||||
wxString msg;
|
||||
|
||||
if( libName.IsEmpty() )
|
||||
@@ -196,7 +196,7 @@ int SYMBOL_EDITOR_CONTROL::AddSymbol( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
else if( aEvent.IsAction( &EE_ACTIONS::deriveFromExistingSymbol ) )
|
||||
{
|
||||
editFrame->CreateNewSymbol( sel.GetLibItemName() );
|
||||
editFrame->CreateNewSymbol( target.GetLibItemName() );
|
||||
}
|
||||
else if( aEvent.IsAction( &EE_ACTIONS::importSymbol ) )
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2024 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
|
||||
@@ -220,7 +220,7 @@ PANEL_SYMBOL_CHOOSER::PANEL_SYMBOL_CHOOSER( SCH_BASE_FRAME* aFrame, wxWindow* aP
|
||||
detailsPanel->SetSizer( detailsSizer );
|
||||
|
||||
m_details = new HTML_WINDOW( detailsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize );
|
||||
detailsSizer->Add( m_details, 1, wxEXPAND, 5 );
|
||||
detailsSizer->Add( m_details, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
|
||||
detailsPanel->Layout();
|
||||
detailsSizer->Fit( detailsPanel );
|
||||
|
||||
@@ -228,7 +228,7 @@ PANEL_SYMBOL_CHOOSER::PANEL_SYMBOL_CHOOSER( SCH_BASE_FRAME* aFrame, wxWindow* aP
|
||||
m_vsplitter->SetMinimumPaneSize( 20 );
|
||||
m_vsplitter->SplitHorizontally( m_hsplitter, detailsPanel );
|
||||
|
||||
sizer->Add( m_vsplitter, 1, wxEXPAND, 5 );
|
||||
sizer->Add( m_vsplitter, 1, wxEXPAND | wxBOTTOM, 5 );
|
||||
}
|
||||
|
||||
wxPanel* treePanel = new wxPanel( m_hsplitter );
|
||||
@@ -238,7 +238,7 @@ PANEL_SYMBOL_CHOOSER::PANEL_SYMBOL_CHOOSER( SCH_BASE_FRAME* aFrame, wxWindow* aP
|
||||
m_tree = new LIB_TREE( treePanel, m_showPower ? wxT( "power" ) : wxT( "symbols" ),
|
||||
libs, m_adapter, LIB_TREE::FLAGS::ALL_WIDGETS, m_details );
|
||||
|
||||
treeSizer->Add( m_tree, 1, wxEXPAND, 5 );
|
||||
treeSizer->Add( m_tree, 1, wxALL | wxEXPAND, 5 );
|
||||
treePanel->Layout();
|
||||
treeSizer->Fit( treePanel );
|
||||
|
||||
@@ -385,7 +385,7 @@ wxPanel* PANEL_SYMBOL_CHOOSER::constructRightPanel( wxWindow* aParent )
|
||||
{
|
||||
FOOTPRINT_LIST* fp_list = FOOTPRINT_LIST::GetInstance( m_frame->Kiway() );
|
||||
|
||||
sizer->Add( m_symbol_preview, 11, wxEXPAND | wxBOTTOM, 5 );
|
||||
sizer->Add( m_symbol_preview, 11, wxEXPAND | wxALL, 5 );
|
||||
|
||||
if ( fp_list )
|
||||
{
|
||||
@@ -397,14 +397,14 @@ wxPanel* PANEL_SYMBOL_CHOOSER::constructRightPanel( wxWindow* aParent )
|
||||
}
|
||||
|
||||
if( m_fp_sel_ctrl )
|
||||
sizer->Add( m_fp_sel_ctrl, 0, wxEXPAND | wxTOP | wxBOTTOM, 4 );
|
||||
sizer->Add( m_fp_sel_ctrl, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
|
||||
|
||||
if( m_fp_preview )
|
||||
sizer->Add( m_fp_preview, 10, wxEXPAND, 5 );
|
||||
sizer->Add( m_fp_preview, 10, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
|
||||
}
|
||||
else
|
||||
{
|
||||
sizer->Add( m_symbol_preview, 1, wxEXPAND, 5 );
|
||||
sizer->Add( m_symbol_preview, 1, wxEXPAND | wxALL, 5 );
|
||||
}
|
||||
|
||||
panel->SetSizer( sizer );
|
||||
|
||||
@@ -115,11 +115,6 @@ void SCH_PROPERTIES_PANEL::AfterCommit()
|
||||
const SELECTION& selection = selectionTool->GetSelection();
|
||||
|
||||
rebuildProperties( selection );
|
||||
|
||||
CallAfter( [this]()
|
||||
{
|
||||
m_frame->GetCanvas()->SetFocus();
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +170,8 @@ void SCH_PROPERTIES_PANEL::valueChanging( wxPropertyGridEvent& aEvent )
|
||||
aEvent.Veto();
|
||||
return;
|
||||
}
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
|
||||
@@ -204,6 +201,8 @@ void SCH_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
|
||||
|
||||
// Perform grid updates as necessary based on value change
|
||||
AfterCommit();
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -877,7 +877,10 @@ void GERBVIEW_FRAME::SetActiveLayer( int aLayer, bool doLayerWidgetUpdate )
|
||||
UpdateXORLayers();
|
||||
|
||||
if( doLayerWidgetUpdate )
|
||||
{
|
||||
m_LayersManager->SelectLayer( aLayer );
|
||||
m_LayersManager->OnLayerSelected();
|
||||
}
|
||||
|
||||
UpdateTitleAndInfo();
|
||||
|
||||
|
||||
@@ -371,6 +371,11 @@ public:
|
||||
int aClearance, int aError, ERROR_LOC aErrorLoc,
|
||||
bool ignoreLineWidth = false ) const;
|
||||
|
||||
enum COMPARE_FLAGS : int
|
||||
{
|
||||
DRC = 0x01
|
||||
};
|
||||
|
||||
struct ptr_cmp
|
||||
{
|
||||
bool operator() ( const BOARD_ITEM* a, const BOARD_ITEM* b ) const;
|
||||
|
||||
@@ -104,6 +104,11 @@ KICOMMON_API const std::tuple<int, int, int>& GetMajorMinorPatchTuple();
|
||||
*/
|
||||
KICOMMON_API bool IsNightlyVersion();
|
||||
|
||||
/**
|
||||
* A setter for OpenGL info when it's initialized.
|
||||
*/
|
||||
KICOMMON_API void SetOpenGLInfo( const char* aRenderer, const char* aVendor, const char* aVersion );
|
||||
|
||||
/**
|
||||
* Create a version info string for bug reports and the about dialog
|
||||
* @param aTitle is the application title to include at the top of the report
|
||||
|
||||
@@ -96,6 +96,8 @@ private:
|
||||
|
||||
std::string columnsFor( const std::string& aTable );
|
||||
|
||||
bool selectAllAndCache( const std::string& aTable, const std::string& aKey );
|
||||
|
||||
std::unique_ptr<nanodbc::connection> m_conn;
|
||||
|
||||
std::string m_dsn;
|
||||
|
||||
@@ -145,6 +145,18 @@ public:
|
||||
m_endsSwapped = false;
|
||||
}
|
||||
|
||||
void SetCenterY( int y )
|
||||
{
|
||||
m_end.y += y - m_start.y;
|
||||
m_start.y = y;
|
||||
}
|
||||
|
||||
void SetCenterX( int x )
|
||||
{
|
||||
m_end.x += x - m_start.x;
|
||||
m_start.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ending point of the graphic.
|
||||
*/
|
||||
|
||||
+2
-1
@@ -348,7 +348,8 @@ public:
|
||||
const VECTOR2I& aOffset = { 0, 0 } ) const;
|
||||
|
||||
// Support for reading the cache from disk.
|
||||
void SetupRenderCache( const wxString& aResolvedText, const EDA_ANGLE& aAngle );
|
||||
void SetupRenderCache( const wxString& aResolvedText, const KIFONT::FONT* aFont,
|
||||
const EDA_ANGLE& aAngle, const VECTOR2I& aOffset );
|
||||
void AddRenderCacheGlyph( const SHAPE_POLY_SET& aPoly );
|
||||
|
||||
int Compare( const EDA_TEXT* aOther ) const;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user