7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 14:11:41 +00:00

ADDED operating point text variables for labels and symbols.

ADDED formatting for cursors and operationg points

Also fixes a bunch of bugs to make the new cursors work with .ac sims.

Fixes https://gitlab.com/kicad/code/kicad/issues/11253

Fixes https://gitlab.com/kicad/code/kicad/issues/6965
This commit is contained in:
Jeff Young 2023-02-05 20:47:27 +00:00
parent b3ffbd6258
commit 2a5bb71fbd
30 changed files with 1422 additions and 129 deletions

View File

@ -289,11 +289,11 @@ void GRID_TRICKS::getSelectedArea()
}
void GRID_TRICKS::onGridCellRightClick( wxGridEvent& )
void GRID_TRICKS::onGridCellRightClick( wxGridEvent& aEvent )
{
wxMenu menu;
showPopupMenu( menu );
showPopupMenu( menu, aEvent );
}
@ -320,7 +320,7 @@ void GRID_TRICKS::onGridLabelRightClick( wxGridEvent& )
}
void GRID_TRICKS::showPopupMenu( wxMenu& menu )
void GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
{
menu.Append( GRIDTRICKS_ID_CUT, _( "Cut" ) + "\tCtrl+X",
_( "Clear selected cells placing original contents on clipboard" ) );

View File

@ -24,7 +24,7 @@ LIB_TABLE_GRID_TRICKS::LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid ) : GRID_TRICKS( aG
{
}
void LIB_TABLE_GRID_TRICKS::showPopupMenu( wxMenu& menu )
void LIB_TABLE_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
{
bool showActivate = false;
bool showDeactivate = false;
@ -33,13 +33,9 @@ void LIB_TABLE_GRID_TRICKS::showPopupMenu( wxMenu& menu )
for( int row = m_sel_row_start; row < m_sel_row_start + m_sel_row_count; ++row )
{
if( tbl->GetValueAsBool( row, 0 ) )
{
showDeactivate = true;
}
else
{
showActivate = true;
}
if( showActivate && showDeactivate )
break;
@ -47,24 +43,25 @@ void LIB_TABLE_GRID_TRICKS::showPopupMenu( wxMenu& menu )
if( showActivate )
menu.Append( LIB_TABLE_GRID_TRICKS_ACTIVATE_SELECTED, _( "Activate selected" ) );
if( showDeactivate )
menu.Append( LIB_TABLE_GRID_TRICKS_DEACTIVATE_SELECTED, _( "Deactivate selected" ) );
menu.AppendSeparator();
GRID_TRICKS::showPopupMenu( menu );
GRID_TRICKS::showPopupMenu( menu, aEvent );
}
void LIB_TABLE_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
{
int menu_id = event.GetId();
if( menu_id == LIB_TABLE_GRID_TRICKS_ACTIVATE_SELECTED
|| menu_id == LIB_TABLE_GRID_TRICKS_DEACTIVATE_SELECTED )
{
LIB_TABLE_GRID* tbl = (LIB_TABLE_GRID*) m_grid->GetTable();
for( int row = m_sel_row_start; row < m_sel_row_start + m_sel_row_count; ++row )
{
tbl->SetValueAsBool( row, 0, menu_id == LIB_TABLE_GRID_TRICKS_ACTIVATE_SELECTED );
}
}
else
{

View File

@ -347,6 +347,8 @@ if( KICAD_SPICE )
${EESCHEMA_SRCS}
dialogs/dialog_sim_command.cpp
dialogs/dialog_sim_command_base.cpp
dialogs/dialog_sim_format_value.cpp
dialogs/dialog_sim_format_value_base.cpp
dialogs/dialog_sim_model.cpp
dialogs/dialog_sim_model_base.cpp
tools/simulator_control.cpp

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 2016 Wayne Stambaugh, stambaughw@gmail.com
* Copyright (C) 2004-2022 KiCad Developers, see AITHORS.txt for contributors.
* Copyright (C) 2004-2023 KiCad Developers, see AITHORS.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 <sch_edit_frame.h>
#include <ee_collectors.h>
#include <sch_symbol.h>
#include <sch_label.h>
#include <lib_field.h>
#include <template_fieldnames.h>
#include <symbol_library.h>
@ -44,6 +45,8 @@
#include <sch_text.h>
#include <scintilla_tricks.h>
#include <wildcards_and_files_ext.h>
#include <sim/sim_model.h>
#include <sim/sim_lib_mgr.h>
DIALOG_FIELD_PROPERTIES::DIALOG_FIELD_PROPERTIES( SCH_BASE_FRAME* aParent, const wxString& aTitle,
@ -584,32 +587,52 @@ void DIALOG_SCH_FIELD_PROPERTIES::onScintillaCharAdded( wxStyledTextEvent &aEven
{
partial = m_StyledTextCtrl->GetRange( start, pos );
wxString ref = m_StyledTextCtrl->GetRange( refStart, start - 1 );
SCH_SHEET_LIST sheets = editFrame->Schematic().GetSheets();
SCH_REFERENCE_LIST refs;
SCH_SYMBOL* refSymbol = nullptr;
wxString ref = m_StyledTextCtrl->GetRange( refStart, start - 1 );
sheets.GetSymbols( refs );
for( size_t jj = 0; jj < refs.GetCount(); jj++ )
if( ref == wxS( "OP" ) )
{
if( refs[ jj ].GetSymbol()->GetRef( &refs[ jj ].GetSheetPath(), true ) == ref )
// SPICE operating points use ':' syntax for ports
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_field->GetParent() );
SCH_SHEET_PATH& sheet = editFrame->Schematic().CurrentSheet();
if( symbol )
{
refSymbol = refs[ jj ].GetSymbol();
break;
SIM_LIB_MGR mgr( &Prj() );
SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol ).model;
for( const std::string& pin : model.GetPinNames() )
autocompleteTokens.push_back( pin );
}
}
else
{
SCH_SHEET_LIST sheets = editFrame->Schematic().GetSheets();
SCH_REFERENCE_LIST refs;
SCH_SYMBOL* refSymbol = nullptr;
if( refSymbol )
refSymbol->GetContextualTextVars( &autocompleteTokens );
sheets.GetSymbols( refs );
for( size_t jj = 0; jj < refs.GetCount(); jj++ )
{
if( refs[ jj ].GetSymbol()->GetRef( &refs[ jj ].GetSheetPath(), true ) == ref )
{
refSymbol = refs[ jj ].GetSymbol();
break;
}
}
if( refSymbol )
refSymbol->GetContextualTextVars( &autocompleteTokens );
}
}
}
else if( textVarRef( start ) )
{
partial = m_StyledTextCtrl->GetTextRange( start, pos );
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_field->GetParent() );
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_field->GetParent() );
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_field->GetParent() );
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_field->GetParent() );
SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( m_field->GetParent() );
if( symbol )
{
@ -624,6 +647,9 @@ void DIALOG_SCH_FIELD_PROPERTIES::onScintillaCharAdded( wxStyledTextEvent &aEven
if( sheet )
sheet->GetContextualTextVars( &autocompleteTokens );
if( label )
label->GetContextualTextVars( &autocompleteTokens );
for( std::pair<wxString, wxString> entry : Prj().GetTextVars() )
autocompleteTokens.push_back( entry.first );
}

View File

@ -0,0 +1,97 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the 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, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <dialog_sim_format_value.h>
#include "sim/spice_value.h"
DIALOG_SIM_FORMAT_VALUE::DIALOG_SIM_FORMAT_VALUE( wxWindow* aParent, int* aPrecision,
wxString* aRange ) :
DIALOG_SIM_FORMAT_VALUE_BASE( aParent ),
m_precision( aPrecision ),
m_range( aRange )
{
m_units = aRange->Right( 1 );
if( m_units == wxS( "V" ) )
{
SetTitle( wxString::Format( GetTitle(), _( "Voltage" ) ) );
}
else if( m_units == wxS( "A" ) )
{
SetTitle( wxString::Format( GetTitle(), _( "Current" ) ) );
}
else if( m_units == wxS( "s" ) )
{
SetTitle( wxString::Format( GetTitle(), _( "Time" ) ) );
}
else if( aRange->Right( 2 ) == wxS( "Hz" ) )
{
m_units = aRange->Right( 2 );
SetTitle( wxString::Format( GetTitle(), _( "Frequency" ) ) );
}
else if( aRange->Right( 3 ) == wxS( "dBV" ) )
{
m_units = aRange->Right( 3 );
SetTitle( wxString::Format( GetTitle(), _( "Gain" ) ) );
}
else if( m_units == wxS( "°" ) )
{
SetTitle( wxString::Format( GetTitle(), _( "Phase" ) ) );
}
else
{
if( aRange->GetChar( 0 ) == '~' )
m_units = aRange->Right( aRange->Length() - 1 );
else if( SPICE_VALUE::ParseSIPrefix( aRange->GetChar( 0 ) ) != SPICE_VALUE::PFX_NONE )
m_units = aRange->Right( aRange->Length() - 1 );
else
m_units = *aRange;
SetTitle( wxString::Format( GetTitle(), _( "Value" ) ) );
}
m_precisionCtrl->SetValue( *aPrecision );
for( int ii = 1; ii < (int) m_rangeCtrl->GetCount(); ++ii )
m_rangeCtrl->SetString( ii, m_rangeCtrl->GetString( ii ) + m_units );
if( aRange->GetChar( 0 ) == '~' )
m_rangeCtrl->SetSelection( 0 );
else
m_rangeCtrl->SetStringSelection( *aRange );
}
bool DIALOG_SIM_FORMAT_VALUE::TransferDataFromWindow()
{
*m_precision = m_precisionCtrl->GetValue();
if( m_rangeCtrl->GetSelection() == 0 )
*m_range = wxS( "~" ) + m_units;
else
*m_range = m_rangeCtrl->GetStringSelection();
return true;
}

View File

@ -0,0 +1,44 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the 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, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef DIALOG_SIM_FORMAT_VALUE_H
#define DIALOG_SIM_FORMAT_VALUE_H
#include <dialog_sim_format_value_base.h>
class DIALOG_SIM_FORMAT_VALUE : public DIALOG_SIM_FORMAT_VALUE_BASE
{
public:
DIALOG_SIM_FORMAT_VALUE( wxWindow* aParent, int* aPrecision, wxString* aRange );
private:
bool TransferDataFromWindow() override;
private:
int* m_precision;
wxString* m_range;
wxString m_units;
};
#endif /* DIALOG_SIM_FORMAT_VALUE_H */

View File

@ -0,0 +1,76 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "dialog_sim_format_value_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_SIM_FORMAT_VALUE_BASE::DIALOG_SIM_FORMAT_VALUE_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxVERTICAL );
wxFlexGridSizer* fgSizer;
fgSizer = new wxFlexGridSizer( 3, 2, 8, 0 );
fgSizer->AddGrowableCol( 1 );
fgSizer->SetFlexibleDirection( wxBOTH );
fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_precisionLabel = new wxStaticText( this, wxID_ANY, _("Significant digits:"), wxDefaultPosition, wxDefaultSize, 0 );
m_precisionLabel->Wrap( -1 );
fgSizer->Add( m_precisionLabel, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_precisionCtrl = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 10, 3 );
fgSizer->Add( m_precisionCtrl, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_rangeLabel = new wxStaticText( this, wxID_ANY, _("Range:"), wxDefaultPosition, wxDefaultSize, 0 );
m_rangeLabel->Wrap( -1 );
fgSizer->Add( m_rangeLabel, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
wxString m_rangeCtrlChoices[] = { _("auto"), _("f"), _("p"), _("n"), _("u"), _("m"), wxEmptyString, _("K"), _("M"), _("G"), _("T"), _("P") };
int m_rangeCtrlNChoices = sizeof( m_rangeCtrlChoices ) / sizeof( wxString );
m_rangeCtrl = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_rangeCtrlNChoices, m_rangeCtrlChoices, 0 );
m_rangeCtrl->SetSelection( 0 );
fgSizer->Add( m_rangeCtrl, 0, wxEXPAND|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
fgSizer->Add( 0, 0, 1, wxEXPAND, 5 );
bMainSizer->Add( fgSizer, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 );
wxBoxSizer* bBottomSizer;
bBottomSizer = new wxBoxSizer( wxHORIZONTAL );
bBottomSizer->Add( 50, 0, 1, wxEXPAND, 5 );
m_sdbSizer1 = new wxStdDialogButtonSizer();
m_sdbSizer1OK = new wxButton( this, wxID_OK );
m_sdbSizer1->AddButton( m_sdbSizer1OK );
m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL );
m_sdbSizer1->AddButton( m_sdbSizer1Cancel );
m_sdbSizer1->Realize();
bBottomSizer->Add( m_sdbSizer1, 0, wxEXPAND|wxALL, 5 );
bMainSizer->Add( bBottomSizer, 0, wxEXPAND, 5 );
this->SetSizer( bMainSizer );
this->Layout();
bMainSizer->Fit( this );
this->Centre( wxBOTH );
}
DIALOG_SIM_FORMAT_VALUE_BASE::~DIALOG_SIM_FORMAT_VALUE_BASE()
{
}

View File

@ -0,0 +1,382 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="16" />
<object class="Project" expanded="1">
<property name="class_decoration">; </property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">dialog_sim_format_value_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">DIALOG_SIM_FORMAT_VALUE_BASE</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="center">wxBOTH</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="extra_style"></property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size">-1,-1</property>
<property name="name">DIALOG_SIM_FORMAT_VALUE_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h; forward_declare</property>
<property name="title">Format %s</property>
<property name="tooltip"></property>
<property name="two_step_creation">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bMainSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">10</property>
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxFlexGridSizer" expanded="1">
<property name="cols">2</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">1</property>
<property name="growablerows"></property>
<property name="hgap">0</property>
<property name="minimum_size"></property>
<property name="name">fgSizer</property>
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="permission">none</property>
<property name="rows">3</property>
<property name="vgap">8</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Significant digits:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_precisionLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxSpinCtrl" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="initial">3</property>
<property name="max">10</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min">1</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_precisionCtrl</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxSP_ARROW_KEYS</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Range:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_rangeLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices">&quot;auto&quot; &quot;f&quot; &quot;p&quot; &quot;n&quot; &quot;u&quot; &quot;m&quot; &quot;&quot; &quot;K&quot; &quot;M&quot; &quot;G&quot; &quot;T&quot; &quot;P&quot;</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_rangeCtrl</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bBottomSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">50</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">0</property>
<object class="wxStdDialogButtonSizer" expanded="1">
<property name="Apply">0</property>
<property name="Cancel">1</property>
<property name="ContextHelp">0</property>
<property name="Help">0</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<property name="minimum_size"></property>
<property name="name">m_sdbSizer1</property>
<property name="permission">protected</property>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>

View File

@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include "dialog_shim.h"
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/spinctrl.h>
#include <wx/choice.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_SIM_FORMAT_VALUE_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_SIM_FORMAT_VALUE_BASE : public DIALOG_SHIM
{
private:
protected:
wxStaticText* m_precisionLabel;
wxSpinCtrl* m_precisionCtrl;
wxStaticText* m_rangeLabel;
wxChoice* m_rangeCtrl;
wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK;
wxButton* m_sdbSizer1Cancel;
public:
DIALOG_SIM_FORMAT_VALUE_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Format %s"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_SIM_FORMAT_VALUE_BASE();
};

View File

@ -79,7 +79,7 @@ public:
{}
protected:
void showPopupMenu( wxMenu& menu ) override
void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) override
{
if( m_grid->GetGridCursorCol() == FOOTPRINT_FIELD )
{
@ -94,7 +94,7 @@ protected:
menu.AppendSeparator();
}
GRID_TRICKS::showPopupMenu( menu );
GRID_TRICKS::showPopupMenu( menu, aEvent );
}
void doPopupSelection( wxCommandEvent& event ) override

View File

@ -856,7 +856,7 @@ template class FIELDS_GRID_TABLE<SCH_FIELD>;
template class FIELDS_GRID_TABLE<LIB_FIELD>;
void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu )
void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
{
if( m_grid->GetGridCursorRow() == FOOTPRINT_FIELD && m_grid->GetGridCursorCol() == FDC_VALUE )
{
@ -871,7 +871,7 @@ void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu )
menu.AppendSeparator();
}
GRID_TRICKS::showPopupMenu( menu );
GRID_TRICKS::showPopupMenu( menu, aEvent );
}

View File

@ -44,7 +44,7 @@ public:
{}
protected:
virtual void showPopupMenu( wxMenu& menu ) override;
virtual void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) override;
virtual void doPopupSelection( wxCommandEvent& event ) override;
DIALOG_SHIM* m_dlg;
};

View File

@ -1256,6 +1256,45 @@ void SCH_EDIT_FRAME::PrintPage( const RENDER_SETTINGS* aSettings )
}
void SCH_EDIT_FRAME::RefreshOperatingPointDisplay()
{
GetCanvas()->GetView()->UpdateAllItemsConditionally(
[&]( KIGFX::VIEW_ITEM* aItem ) -> int
{
int flags = 0;
if( SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aItem ) )
{
item->RunOnChildren(
[&flags]( SCH_ITEM* aChild )
{
EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aChild );
if( text && text->HasTextVars() )
{
text->ClearRenderCache();
text->ClearBoundingBoxCache();
flags |= KIGFX::GEOMETRY | KIGFX::REPAINT;
}
} );
EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
if( text && text->HasTextVars() )
{
text->ClearRenderCache();
text->ClearBoundingBoxCache();
flags |= KIGFX::GEOMETRY | KIGFX::REPAINT;
}
}
return flags;
} );
GetCanvas()->ForceRefresh();
}
void SCH_EDIT_FRAME::AutoRotateItem( SCH_SCREEN* aScreen, SCH_ITEM* aItem )
{
if( aItem->IsType( { SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T } ) )

View File

@ -187,6 +187,11 @@ public:
void KiwayMailIn( KIWAY_EXPRESS& aEvent ) override;
/**
* Refresh the display of any operating points. Called after a .op simulation completes.
*/
void RefreshOperatingPointDisplay();
/**
* Automatically set the rotation of an item (if the item supports it)
*/

View File

@ -479,11 +479,50 @@ void SCH_LABEL_BASE::GetIntersheetRefs( std::vector<std::pair<wxString, wxString
}
void SCH_LABEL_BASE::GetContextualTextVars( wxArrayString* aVars ) const
{
for( const SCH_FIELD& field : m_fields )
aVars->push_back( field.GetCanonicalName().Upper() );
aVars->push_back( wxT( "OP" ) );
aVars->push_back( wxT( "CONNECTION_TYPE" ) );
aVars->push_back( wxT( "SHORT_NET_NAME" ) );
aVars->push_back( wxT( "NET_NAME" ) );
aVars->push_back( wxT( "NET_CLASS" ) );
}
bool SCH_LABEL_BASE::ResolveTextVar( wxString* token, int aDepth ) const
{
static wxRegEx operatingPoint( wxT( "^"
"OP"
"(.([0-9])?([a-zA-Z]*))?"
"$" ) );
if( !Schematic() )
return false;
if( operatingPoint.Matches( *token ) )
{
int precision = 3;
wxString precisionStr( operatingPoint.GetMatch( *token, 2 ) );
wxString range( operatingPoint.GetMatch( *token, 3 ) );
if( !precisionStr.IsEmpty() )
precision = precisionStr[0] - '0';
if( range.IsEmpty() )
range = wxS( "~V" );
const SCH_CONNECTION* connection = Connection();
*token = wxS( "?" );
if( connection )
*token = Schematic()->GetOperatingPoint( connection->Name( false ), precision, range );
return true;
}
if( token->Contains( ':' ) )
{
if( Schematic()->ResolveCrossReference( token, aDepth + 1 ) )
@ -528,11 +567,11 @@ bool SCH_LABEL_BASE::ResolveTextVar( wxString* token, int aDepth ) const
return true;
}
for( size_t i = 0; i < m_fields.size(); ++i )
for( const SCH_FIELD& field : m_fields)
{
if( token->IsSameAs( m_fields[i].GetName() ) )
if( token->IsSameAs( field.GetName() ) )
{
*token = m_fields[i].GetShownText( aDepth + 1 );
*token = field.GetShownText( aDepth + 1 );
return true;
}
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -126,6 +126,16 @@ public:
*/
void GetIntersheetRefs( std::vector<std::pair<wxString, wxString>>* pages );
/**
* Return the list of system text vars & fields for this label.
*/
void GetContextualTextVars( wxArrayString* aVars ) const;
/**
* Resolve any references to system tokens supported by the label.
*
* @param aDepth a counter to limit recursion and circular references.
*/
virtual bool ResolveTextVar( wxString* token, int aDepth ) const;
wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;

View File

@ -1117,6 +1117,7 @@ void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
for( size_t i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
aVars->push_back( m_fields[i].GetName() );
aVars->push_back( wxT( "OP" ) );
aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
aVars->push_back( wxT( "UNIT" ) );
@ -1132,12 +1133,38 @@ void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
bool SCH_SYMBOL::ResolveTextVar( wxString* token, int aDepth ) const
{
static wxRegEx operatingPoint( wxT( "^"
"OP"
"(:[a-zA-Z]*)?" // port
"(.([0-9])?([a-zA-Z]*))?" // format
"$" ) );
SCHEMATIC* schematic = Schematic();
// SCH_SYMOL object has no context outside a schematic.
if( !schematic )
return false;
if( operatingPoint.Matches( *token ) )
{
wxString port( operatingPoint.GetMatch( *token, 1 ) );
wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
wxString range( operatingPoint.GetMatch( *token, 4 ) );
wxString signal = GetRef( &schematic->CurrentSheet() ) + port;
int precision = 3;
if( !precisionStr.IsEmpty() )
precision = precisionStr[0] - '0';
if( range.IsEmpty() )
range = wxS( "~A" );
*token = Schematic()->GetOperatingPoint( signal.Lower(), precision, range );
return true;
}
if( token->Contains( ':' ) )
{
if( schematic->ResolveCrossReference( token, aDepth + 1 ) )

View File

@ -31,6 +31,7 @@
#include <sch_screen.h>
#include <sim/spice_settings.h>
#include <sch_label.h>
#include <sim/spice_value.h>
SCHEMATIC::SCHEMATIC( PROJECT* aPrj ) :
EDA_ITEM( nullptr, SCHEMATIC_T ),
@ -625,6 +626,20 @@ void SCHEMATIC::RecomputeIntersheetRefs( const std::function<void( SCH_GLOBALLAB
}
wxString SCHEMATIC::GetOperatingPoint( const wxString& aNetName, int aPrecision,
const wxString& aRange )
{
auto it = m_operatingPoints.find( aNetName );
if( it != m_operatingPoints.end() )
return SPICE_VALUE( it->second ).ToString( aPrecision, aRange );
else if( m_operatingPoints.empty() )
return wxS( "--" );
else
return wxS( "?" );
}
void SCHEMATIC::FixupJunctions()
{
for( const SCH_SHEET_PATH& sheet : GetSheets() )

View File

@ -204,6 +204,24 @@ public:
*/
void RecomputeIntersheetRefs( const std::function<void( SCH_GLOBALLABEL* )>& aItemCallback );
/**
* Clear operating points from a .op simulation.
*/
void ClearOperatingPoints()
{
m_operatingPoints.clear();
}
/**
* Set operating points from a .op simulation. Called after the simulation completes.
*/
void SetOperatingPoint( const wxString& aSignal, double aValue )
{
m_operatingPoints[ aSignal ] = aValue;
}
wxString GetOperatingPoint( const wxString& aNetName, int aPrecision, const wxString& aRange );
/**
* Add junctions to this schematic where required. This function is needed for some plugins
* (e.g. Legacy and Cadstar) in order to retain connectivity after loading.
@ -243,6 +261,11 @@ private:
* Properties for text variable substitution (and perhaps other uses in future).
*/
std::map<wxString, wxString> m_properties;
/**
* Simulation operating points for text variable substitution.
*/
std::map<wxString, double> m_operatingPoints;
};
#endif

View File

@ -33,17 +33,24 @@
SIM_TRACE_TYPE NGSPICE_CIRCUIT_MODEL::VectorToSignal( const std::string& aVector,
wxString& aSignal ) const
{
using namespace std;
static wxString BRANCH( wxS( "#branch" ) );
// See ngspice manual chapt. 31.1 "Accessing internal device parameters"
wxRegEx internalDevParameter( "^@(\\w*[\\.\\w+]*)\\[(\\w*)\\]$", wxRE_ADVANCED );
static wxRegEx internalDevParameter( wxS( "^@(\\w*[\\.\\w+]*)\\[(\\w*)\\]$" ), wxRE_ADVANCED );
wxString vector( aVector );
if( !internalDevParameter.Matches( vector ) )
{
// any text is a node name, which returns voltage
aSignal = wxT( "V(" ) + aVector + wxT( ")" );
return SPT_VOLTAGE;
if( vector.EndsWith( BRANCH ) )
{
aSignal = wxT( "I(" ) + vector.Left( vector.Length() - BRANCH.Length() ) + wxT( ")" );
return SPT_CURRENT;
}
else
{
aSignal = wxT( "V(" ) + vector + wxT( ")" );
return SPT_VOLTAGE;
}
}
else
{

View File

@ -56,7 +56,7 @@
#include "sim_plot_panel.h"
#include "spice_simulator.h"
#include "spice_reporter.h"
#include <menus_helpers.h>
#include <dialog_sim_format_value.h>
#include <eeschema_settings.h>
#include <memory>
@ -129,6 +129,73 @@ enum CURSORS_GRID_COLUMNS
};
enum
{
MYID_FORMAT_VALUE = GRIDTRICKS_FIRST_CLIENT_ID
};
class CURSORS_GRID_TRICKS : public GRID_TRICKS
{
public:
CURSORS_GRID_TRICKS( SIM_PLOT_FRAME* aParent, WX_GRID* aGrid ) :
GRID_TRICKS( aGrid ),
m_parent( aParent )
{}
protected:
void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) override;
void doPopupSelection( wxCommandEvent& event ) override;
protected:
SIM_PLOT_FRAME* m_parent;
int m_menuRow;
int m_menuCol;
};
void CURSORS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
{
m_menuRow = aEvent.GetRow();
m_menuCol = aEvent.GetCol();
if( m_menuCol == COL_CURSOR_X || m_menuCol == COL_CURSOR_Y )
{
wxString msg = m_grid->GetColLabelValue( m_menuCol );
menu.Append( MYID_FORMAT_VALUE, wxString::Format( _( "Format..." ), msg ),
wxString::Format( _( "Specify %s precision and range" ), msg.Lower() ) );
menu.AppendSeparator();
}
GRID_TRICKS::showPopupMenu( menu, aEvent );
}
void CURSORS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
{
if( event.GetId() == MYID_FORMAT_VALUE )
{
int cursorId = m_menuRow;
int cursorAxis = m_menuCol - COL_CURSOR_X;
int precision = m_parent->GetCursorPrecision( cursorId, cursorAxis );
wxString range = m_parent->GetCursorRange( cursorId, cursorAxis );
DIALOG_SIM_FORMAT_VALUE formatDialog( m_parent, &precision, &range );
if( formatDialog.ShowModal() == wxID_OK )
{
m_parent->SetCursorPrecision( cursorId, cursorAxis, precision );
m_parent->SetCursorRange( cursorId, cursorAxis, range );
}
}
else
{
GRID_TRICKS::doPopupSelection( event );
}
}
SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
SIM_PLOT_FRAME_BASE( aParent ),
m_lastSimPlot( nullptr ),
@ -180,7 +247,15 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
attr->SetReadOnly();
m_cursorsGrid->SetColAttr( COL_CURSOR_Y, attr );
m_cursorsGrid->PushEventHandler( new GRID_TRICKS( m_cursorsGrid ) );
m_cursorsGrid->PushEventHandler( new CURSORS_GRID_TRICKS( this, m_cursorsGrid ) );
for( int cursorId = 0; cursorId < 3; ++cursorId )
{
m_cursorPrecision[ cursorId ][ 0 ] = 3;
m_cursorRange[ cursorId ][ 0 ] = wxS( "~s" );
m_cursorPrecision[ cursorId ][ 1 ] = 3;
m_cursorRange[ cursorId ][ 1 ] = wxS( "~V" );
}
// Prepare the color list to plot traces
SIM_PLOT_COLORS::FillDefaultColorList( m_darkMode );
@ -438,6 +513,9 @@ void SIM_PLOT_FRAME::rebuildSignalsGrid( wxString aFilter )
{
m_signalsGrid->ClearRows();
if( !GetCurrentPlot() )
return;
if( aFilter.IsEmpty() )
aFilter = wxS( "*" );
@ -567,6 +645,8 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
unconnected.Replace( '(', '_' ); // Convert to SPICE markup
m_signals.clear();
auto simType = m_circuitModel->GetSimType();
// Add voltages
for( const std::string& net : m_circuitModel->GetNets() )
{
@ -574,11 +654,19 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
wxString netname = UnescapeString( net );
if( netname != "GND" && netname != "0" && !netname.StartsWith( unconnected ) )
m_signals.push_back( wxString::Format( "V(%s)", netname ) );
{
if( simType == ST_AC )
{
m_signals.push_back( wxString::Format( _( "V(%s) (gain)" ), netname ) );
m_signals.push_back( wxString::Format( _( "V(%s) (phase)" ), netname ) );
}
else
{
m_signals.push_back( wxString::Format( "V(%s)", netname ) );
}
}
}
auto simType = m_circuitModel->GetSimType();
// Add currents
if( simType == ST_TRANSIENT || simType == ST_DC )
{
@ -666,15 +754,33 @@ void SIM_PLOT_FRAME::onSignalsGridCellChanged( wxGridEvent& aEvent )
if( text == wxS( "1" ) )
{
wxString signalName = m_signalsGrid->GetCellValue( row, COL_SIGNAL_NAME );
wxString baseSignal = signalName;
if( !signalName.IsEmpty() )
{
wxString gainSuffix = _( " (gain)" );
wxString phaseSuffix = _( " (phase)" );
wxUniChar firstChar = signalName[0];
int traceType = SPT_UNKNOWN;
if( firstChar == 'V' || firstChar == 'v' )
addTrace( signalName, SPT_VOLTAGE );
traceType = SPT_VOLTAGE;
else if( firstChar == 'I' || firstChar == 'i' )
addTrace( signalName, SPT_CURRENT );
traceType = SPT_CURRENT;
if( signalName.EndsWith( gainSuffix ) )
{
traceType |= SPT_AC_MAG;
baseSignal = signalName.Left( signalName.Length() - gainSuffix.Length() );
}
else if( signalName.EndsWith( phaseSuffix ) )
{
traceType |= SPT_AC_PHASE;
baseSignal = signalName.Left( signalName.Length() - phaseSuffix.Length() );
}
if( traceType != SPT_UNKNOWN )
addTrace( baseSignal, (SIM_TRACE_TYPE) traceType );
}
if( !GetCurrentPlot()->GetTrace( signalName ) )
@ -955,7 +1061,7 @@ bool SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
wxString traceTitle = aName;
if( aType & SPT_AC_MAG )
traceTitle += _( " (mag)" );
traceTitle += _( " (gain)" );
else if( aType & SPT_AC_PHASE )
traceTitle += _( " (phase)" );
@ -1605,17 +1711,6 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
else
m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, labelY1 + wxT( " / " ) + labelY2 );
auto getUnitsY =
[&]( TRACE* aTrace ) -> wxString
{
if( aTrace->GetType() == SPT_VOLTAGE )
return wxS( "V" );
else if( aTrace->GetType() == SPT_CURRENT )
return wxS( "A" );
else
return wxEmptyString;
};
// Update cursor values
wxString unitsX = plotPanel->GetUnitsX();
CURSOR* cursor1 = nullptr;
@ -1623,7 +1718,32 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
CURSOR* cursor2 = nullptr;
wxString unitsY2;
#define SET_CELL( r, c, v ) m_cursorsGrid->SetCellValue( r, c, v )
auto getUnitsY =
[&]( TRACE* aTrace ) -> wxString
{
if( ( aTrace->GetType() & SPT_AC_PHASE ) || ( aTrace->GetType() & SPT_CURRENT ) )
return plotPanel->GetUnitsY2();
else
return plotPanel->GetUnitsY1();
};
auto updateRangeUnits =
[]( wxString* aRange, const wxString& aUnits )
{
if( aRange->GetChar( 0 ) == '~' )
*aRange = aRange->Left( 1 ) + aUnits;
else if( SPICE_VALUE::ParseSIPrefix( aRange->GetChar( 0 ) ) != SPICE_VALUE::PFX_NONE )
*aRange = aRange->Left( 1 ) + aUnits;
else
*aRange = aUnits;
};
auto formatValue =
[this]( double aValue, int aCursorId, int aCol ) -> wxString
{
return SPICE_VALUE( aValue ).ToString( m_cursorPrecision[ aCursorId ][ aCol ],
m_cursorRange[ aCursorId ][ aCol ] );
};
for( const auto& [name, trace] : plotPanel->GetTraces() )
{
@ -1635,12 +1755,14 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
wxRealPoint coords = cursor->GetCoords();
int row = m_cursorsGrid->GetNumberRows();
m_cursorsGrid->AppendRows( 1 );
SET_CELL( row, COL_CURSOR_NAME, wxS( "1" ) );
SET_CELL( row, COL_CURSOR_SIGNAL, cursor->GetName() );
SET_CELL( row, COL_CURSOR_X, SPICE_VALUE( coords.x ).ToSpiceString() + unitsX );
SET_CELL( row, COL_CURSOR_Y, SPICE_VALUE( coords.y ).ToSpiceString() + unitsY1 );
updateRangeUnits( &m_cursorRange[0][0], unitsX );
updateRangeUnits( &m_cursorRange[0][1], unitsY1 );
m_cursorsGrid->AppendRows( 1 );
m_cursorsGrid->SetCellValue( row, COL_CURSOR_NAME, wxS( "1" ) );
m_cursorsGrid->SetCellValue( row, COL_CURSOR_SIGNAL, cursor->GetName() );
m_cursorsGrid->SetCellValue( row, COL_CURSOR_X, formatValue( coords.x, 0, 0 ) );
m_cursorsGrid->SetCellValue( row, COL_CURSOR_Y, formatValue( coords.y, 0, 1 ) );
break;
}
}
@ -1655,38 +1777,37 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
wxRealPoint coords = cursor->GetCoords();
int row = m_cursorsGrid->GetNumberRows();
m_cursorsGrid->AppendRows( 1 );
SET_CELL( row, COL_CURSOR_NAME, wxS( "2" ) );
SET_CELL( row, COL_CURSOR_SIGNAL, cursor->GetName() );
SET_CELL( row, COL_CURSOR_X, SPICE_VALUE( coords.x ).ToSpiceString() + unitsX );
SET_CELL( row, COL_CURSOR_Y, SPICE_VALUE( coords.y ).ToSpiceString() + unitsY2 );
updateRangeUnits( &m_cursorRange[1][0], unitsX );
updateRangeUnits( &m_cursorRange[1][1], unitsY2 );
m_cursorsGrid->AppendRows( 1 );
m_cursorsGrid->SetCellValue( row, COL_CURSOR_NAME, wxS( "2" ) );
m_cursorsGrid->SetCellValue( row, COL_CURSOR_SIGNAL, cursor->GetName() );
m_cursorsGrid->SetCellValue( row, COL_CURSOR_X, formatValue( coords.x, 1, 0 ) );
m_cursorsGrid->SetCellValue( row, COL_CURSOR_Y, formatValue( coords.y, 1, 1 ) );
break;
}
}
if( cursor1 && cursor2 && unitsY1 == unitsY2 )
{
const wxRealPoint coords = cursor2->GetCoords() - cursor1->GetCoords();
wxRealPoint coords = cursor2->GetCoords() - cursor1->GetCoords();
wxString signal;
updateRangeUnits( &m_cursorRange[2][0], unitsX );
updateRangeUnits( &m_cursorRange[2][1], unitsY1 );
if( cursor1->GetName() == cursor2->GetName() )
signal = wxString::Format( wxS( "%s[2 - 1]" ), cursor2->GetName() );
else
signal = wxString::Format( wxS( "%s - %s" ), cursor2->GetName(), cursor1->GetName() );
m_cursorsGrid->AppendRows( 1 );
SET_CELL( 2, COL_CURSOR_NAME, _( "Diff" ) );
if( cursor1->GetName() == cursor2->GetName() )
{
SET_CELL( 2, COL_CURSOR_SIGNAL, wxString::Format( wxS( "%s[2 - 1]" ),
cursor2->GetName() ) );
}
else
{
SET_CELL( 2, COL_CURSOR_SIGNAL, wxString::Format( wxS( "%s - %s" ),
cursor2->GetName(),
cursor1->GetName() ) );
}
SET_CELL( 2, COL_CURSOR_X, SPICE_VALUE( coords.x ).ToSpiceString() + unitsX );
SET_CELL( 2, COL_CURSOR_Y, SPICE_VALUE( coords.y ).ToSpiceString() + unitsY1 );
m_cursorsGrid->SetCellValue( 2, COL_CURSOR_NAME, _( "Diff" ) );
m_cursorsGrid->SetCellValue( 2, COL_CURSOR_SIGNAL, signal );
m_cursorsGrid->SetCellValue( 2, COL_CURSOR_X, formatValue( coords.x, 2, 0 ) );
m_cursorsGrid->SetCellValue( 2, COL_CURSOR_Y, formatValue( coords.y, 2, 1 ) );
}
#undef SET_CELL
}
@ -1847,6 +1968,9 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
}
else if( simType == ST_OP )
{
SCHEMATIC& schematic = m_schematicFrame->Schematic();
schematic.ClearOperatingPoints();
m_simConsole->AppendText( _( "\n\nSimulation results:\n\n" ) );
m_simConsole->SetInsertionPointEnd();
@ -1857,23 +1981,28 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
if( val_list.size() == 0 ) // The list of values can be empty!
continue;
double val = val_list.at( 0 );
wxString outLine, signal;
wxString value = SPICE_VALUE( val_list.at( 0 ) ).ToSpiceString();
wxString msg;
wxString signal;
SIM_TRACE_TYPE type = m_circuitModel->VectorToSignal( vec, signal );
const size_t tab = 25; //characters
size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
outLine.Printf( wxT( "%s%s" ),
( signal + wxT( ":" ) ).Pad( padding, wxUniChar( ' ' ) ),
SPICE_VALUE( val ).ToSpiceString() );
value.Append( type == SPT_CURRENT ? wxS( "A" ) : wxS( "V" ) );
outLine.Append( type == SPT_CURRENT ? wxT( "A\n" ) : wxT( "V\n" ) );
msg.Printf( wxT( "%s%s\n" ),
( signal + wxT( ":" ) ).Pad( padding, wxUniChar( ' ' ) ),
value );
m_simConsole->AppendText( outLine );
m_simConsole->AppendText( msg );
m_simConsole->SetInsertionPointEnd();
// @todo display calculated values on the schematic
if( signal.StartsWith( wxS( "V(" ) ) || signal.StartsWith( wxS( "I(" ) ) )
signal = signal.SubString( 2, signal.Length() - 2 );
schematic.SetOperatingPoint( signal, val_list.at( 0 ) );
m_schematicFrame->RefreshOperatingPointDisplay();
}
}

View File

@ -94,6 +94,41 @@ public:
*/
void AddCurrentPlot( const wxString& aDeviceName );
/**
* Get/Set the number of decimal places to show in a cursor value.
* @param aValueCol 0 indicates the X value column; 1 the Y value.
*/
int GetCursorPrecision( int aCursorId, int aValueCol ) const
{
return m_cursorPrecision[ aCursorId ][ aValueCol ];
}
void SetCursorPrecision( int aCursorId, int aValueCol, int aPrecision )
{
m_cursorPrecision[ aCursorId ][ aValueCol ] = aPrecision;
wxCommandEvent dummy;
onCursorUpdate( dummy );
}
/**
* Get/Set the range of a cursor value.
* @param aValueCol 0 indicates the X value column; 1 the Y value.
* @param aScale "~" + unit indicates automatic; the rest are SI prefix + unit.
*/
wxString GetCursorRange( int aCursorId, int aValueCol ) const
{
return m_cursorRange[ aCursorId ][ aValueCol ];
}
void SetCursorRange( int aCursorId, int aValueCol, const wxString& aRange )
{
m_cursorRange[ aCursorId ][ aValueCol ] = aRange;
wxCommandEvent dummy;
onCursorUpdate( dummy );
}
/**
* Add a tuner for a symbol.
*/
@ -313,6 +348,9 @@ private:
bool m_darkMode;
unsigned int m_plotNumber;
bool m_simFinished;
int m_cursorPrecision[3][2];
wxString m_cursorRange[3][2];
};
// Commands

View File

@ -427,6 +427,28 @@ wxString SIM_PLOT_PANEL::GetUnitsX() const
}
wxString SIM_PLOT_PANEL::GetUnitsY1() const
{
LIN_SCALE<mpScaleY>* linScale = dynamic_cast<LIN_SCALE<mpScaleY>*>( m_axis_y1 );
if( linScale )
return linScale->GetUnits();
else
return wxEmptyString;
}
wxString SIM_PLOT_PANEL::GetUnitsY2() const
{
LIN_SCALE<mpScaleY>* linScale = dynamic_cast<LIN_SCALE<mpScaleY>*>( m_axis_y2 );
if( linScale )
return linScale->GetUnits();
else
return wxEmptyString;
}
void SIM_PLOT_PANEL::updateAxes()
{
bool skipAddToView = false;

View File

@ -220,6 +220,8 @@ public:
}
wxString GetUnitsX() const;
wxString GetUnitsY1() const;
wxString GetUnitsY2() const;
bool TraceShown( const wxString& aName ) const
{

View File

@ -23,6 +23,7 @@
*/
#include "spice_value.h"
#include "math/util.h"
#include <stdexcept>
#include <cmath>
@ -34,6 +35,7 @@
#include <ki_exception.h>
#include <locale_io.h>
SPICE_VALUE::SPICE_VALUE( const wxString& aString )
{
char buf[8] = { 0, };
@ -107,20 +109,56 @@ void SPICE_VALUE::Normalize()
}
wxString prefix( SPICE_VALUE::UNIT_PREFIX aPrefix )
wxString spice_prefix( SPICE_VALUE::UNIT_PREFIX aPrefix )
{
switch( aPrefix )
{
case SPICE_VALUE::PFX_FEMTO: return wxT( "f" );
case SPICE_VALUE::PFX_PICO: return wxT( "p" );
case SPICE_VALUE::PFX_NANO: return wxT( "n" );
case SPICE_VALUE::PFX_MICRO: return wxT( "u" );
case SPICE_VALUE::PFX_MILI: return wxT( "m" );
case SPICE_VALUE::PFX_NONE: return wxEmptyString;
case SPICE_VALUE::PFX_KILO: return wxT( "k" );
case SPICE_VALUE::PFX_MEGA: return wxT( "Meg" );
case SPICE_VALUE::PFX_GIGA: return wxT( "G" );
case SPICE_VALUE::PFX_TERA: return wxT( "T" );
case SPICE_VALUE::PFX_FEMTO: return wxT( "f" );
case SPICE_VALUE::PFX_PICO: return wxT( "p" );
case SPICE_VALUE::PFX_NANO: return wxT( "n" );
case SPICE_VALUE::PFX_MICRO: return wxT( "u" );
case SPICE_VALUE::PFX_MILI: return wxT( "m" );
case SPICE_VALUE::PFX_NONE: return wxEmptyString;
case SPICE_VALUE::PFX_KILO: return wxT( "k" );
case SPICE_VALUE::PFX_MEGA: return wxT( "Meg" );
case SPICE_VALUE::PFX_GIGA: return wxT( "G" );
case SPICE_VALUE::PFX_TERA: return wxT( "T" );
}
}
wxString si_prefix( SPICE_VALUE::UNIT_PREFIX aPrefix )
{
switch( aPrefix )
{
case SPICE_VALUE::PFX_FEMTO: return wxT( "f" );
case SPICE_VALUE::PFX_PICO: return wxT( "p" );
case SPICE_VALUE::PFX_NANO: return wxT( "n" );
case SPICE_VALUE::PFX_MICRO: return wxT( "u" );
case SPICE_VALUE::PFX_MILI: return wxT( "m" );
case SPICE_VALUE::PFX_NONE: return wxEmptyString;
case SPICE_VALUE::PFX_KILO: return wxT( "K" );
case SPICE_VALUE::PFX_MEGA: return wxT( "M" );
case SPICE_VALUE::PFX_GIGA: return wxT( "G" );
case SPICE_VALUE::PFX_TERA: return wxT( "T" );
}
}
SPICE_VALUE::UNIT_PREFIX SPICE_VALUE::ParseSIPrefix( wxChar c )
{
switch( c )
{
case 'f': return SPICE_VALUE::PFX_FEMTO;
case 'p': return SPICE_VALUE::PFX_PICO;
case 'n': return SPICE_VALUE::PFX_NANO;
case 'u': return SPICE_VALUE::PFX_MICRO;
case 'm': return SPICE_VALUE::PFX_MILI;
case 'K': return SPICE_VALUE::PFX_KILO;
case 'M': return SPICE_VALUE::PFX_MEGA;
case 'G': return SPICE_VALUE::PFX_GIGA;
case 'T': return SPICE_VALUE::PFX_TERA;
default: return SPICE_VALUE::PFX_NONE;
}
}
@ -129,7 +167,7 @@ double SPICE_VALUE::ToNormalizedDouble( wxString* aPrefix )
{
Normalize();
*aPrefix = prefix( m_prefix );
*aPrefix = spice_prefix( m_prefix );
return m_base;
}
@ -153,11 +191,52 @@ wxString SPICE_VALUE::ToString() const
}
wxString SPICE_VALUE::ToString( int aPrecision, const wxString& aRange )
{
wxString range( aRange );
if( range.StartsWith( wxS( "~" ) ) )
{
Normalize();
range = si_prefix( m_prefix ) + range.Right( range.Length() - 1 );
}
else
{
SPICE_VALUE::UNIT_PREFIX rangePrefix = ParseSIPrefix( aRange[0] );
m_base = m_base * std::pow( 10, m_prefix - rangePrefix );
m_prefix = rangePrefix;
}
double mantissa = m_base;
int scale = 0;
while( std::fabs( mantissa ) >= 10.0 )
{
mantissa *= 0.1;
scale += 1;
}
while( mantissa != 0.0 && std::fabs( mantissa ) < 1.0 )
{
mantissa *= 10;
scale -= 1;
}
mantissa = KiROUND( mantissa * std::pow( 10, aPrecision - 1 ) );
mantissa *= std::pow( 10, scale - aPrecision + 1 );
wxString res = wxString::FromCDouble( mantissa );
StripZeros( res );
return res + range;
}
wxString SPICE_VALUE::ToSpiceString() const
{
wxString res = wxString::FromCDouble( m_base );
StripZeros( res );
res += prefix( m_prefix );
res += spice_prefix( m_prefix );
return res;
}

Some files were not shown because too many files have changed in this diff Show More