ADDED direct access to signals & cursors.

ADDED differential cursors.

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

Fixes https://gitlab.com/kicad/code/kicad/issues/6221
This commit is contained in:
Jeff Young 2023-01-29 16:01:03 +00:00
parent e73366db5c
commit 09822c7f18
27 changed files with 916 additions and 1213 deletions

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2015-2017 Chris Pavlina <pavlina.chris@gmail.com> * Copyright (C) 2015-2017 Chris Pavlina <pavlina.chris@gmail.com>
* Copyright (C) 2015-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2015-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -386,6 +386,12 @@ EDA_COMBINED_MATCHER::EDA_COMBINED_MATCHER( const wxString& aPattern,
AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_REGEX_EXPLICIT>() ); AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_REGEX_EXPLICIT>() );
AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_WILDCARD_EXPLICIT>() ); AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_WILDCARD_EXPLICIT>() );
break; break;
case CTX_SIGNAL:
AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_REGEX>() );
AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_WILDCARD>() );
AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_SUBSTR>() );
break;
} }
} }

View File

@ -345,8 +345,6 @@ set( EESCHEMA_COMMON_SRCS
if( KICAD_SPICE ) if( KICAD_SPICE )
set( EESCHEMA_SRCS set( EESCHEMA_SRCS
${EESCHEMA_SRCS} ${EESCHEMA_SRCS}
dialogs/dialog_signal_list.cpp
dialogs/dialog_signal_list_base.cpp
dialogs/dialog_sim_command.cpp dialogs/dialog_sim_command.cpp
dialogs/dialog_sim_command_base.cpp dialogs/dialog_sim_command_base.cpp
dialogs/dialog_sim_model.cpp dialogs/dialog_sim_model.cpp

View File

@ -1,143 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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_signal_list.h"
#include <string_utils.h>
#include <sim/sim_plot_frame.h>
#include <sim/ngspice_circuit_model.h>
#include <sim/spice_generator.h>
DIALOG_SIGNAL_LIST::DIALOG_SIGNAL_LIST( SIM_PLOT_FRAME* aParent,
NGSPICE_CIRCUIT_MODEL* aCircuitModel ) :
DIALOG_SIGNAL_LIST_BASE( aParent ),
m_plotFrame( aParent ),
m_circuitModel( aCircuitModel )
{
}
bool DIALOG_SIGNAL_LIST::TransferDataFromWindow()
{
if( !DIALOG_SIGNAL_LIST_BASE::TransferDataFromWindow() )
return false;
addSelectionToPlotFrame();
return true;
}
bool DIALOG_SIGNAL_LIST::TransferDataToWindow()
{
// Create a list of possible signals
/// TODO: it could include separated mag & phase for AC analysis
if( m_circuitModel )
{
// Voltage list
for( const auto& net : m_circuitModel->GetNets() )
{
// netnames are escaped (can contain "{slash}" for '/') Unscape them:
wxString netname = UnescapeString( net );
if( netname != "GND" && netname != "0" )
m_signals->Append( wxString::Format( "V(%s)", netname ) );
}
auto simType = m_circuitModel->GetSimType();
if( simType == ST_TRANSIENT || simType == ST_DC )
{
for( const SPICE_ITEM& item : m_circuitModel->GetItems() )
{
// Add all possible currents for the primitive.
for( const std::string& name : item.model->SpiceGenerator().CurrentNames( item ) )
m_signals->Append( name );
}
}
}
bool success = DIALOG_SIGNAL_LIST_BASE::TransferDataToWindow();
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
return success;
}
bool DIALOG_SIGNAL_LIST::addSignalToPlotFrame( const wxString& aPlotName )
{
// Get the part in the parentheses
wxString name = aPlotName.AfterFirst( '(' ).BeforeLast( ')' );
if( !name.IsEmpty() )
{
wxUniChar firstChar = aPlotName[0];
if( firstChar == 'V' || firstChar == 'v' )
m_plotFrame->AddVoltagePlot( aPlotName );
else if( firstChar == 'I' || firstChar == 'i' )
m_plotFrame->AddCurrentPlot( aPlotName );
else
return false;
}
else
{
return false;
}
return true;
}
void DIALOG_SIGNAL_LIST::addSelectionToPlotFrame()
{
for( int i = 0; i < (int) m_signals->GetCount(); ++i )
{
if( m_signals->IsSelected( i ) )
{
const wxString& plotName = m_signals->GetString( i );
if( !addSignalToPlotFrame( plotName ) )
wxASSERT_MSG( false, "Unhandled plot type" );
}
}
// Add manually entered signal, if any
const wxString& plotName = m_signalEntry->GetValue();
if( !plotName.IsEmpty() )
{
if( !addSignalToPlotFrame( plotName ) )
m_plotFrame->AddVoltagePlot( plotName ); // Assume it's a V plot by default
m_signalEntry->SetSelection( -1, -1 );
}
}

View File

@ -1,55 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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_SIGNAL_LIST_H
#define DIALOG_SIGNAL_LIST_H
#include "dialog_signal_list_base.h"
class SIM_PLOT_FRAME;
class NGSPICE_CIRCUIT_MODEL;
class DIALOG_SIGNAL_LIST : public DIALOG_SIGNAL_LIST_BASE
{
public:
DIALOG_SIGNAL_LIST( SIM_PLOT_FRAME* aParent, NGSPICE_CIRCUIT_MODEL* aCircuitModel );
bool TransferDataFromWindow() override;
bool TransferDataToWindow() override;
private:
void onSignalAdd( wxCommandEvent& event ) override
{
addSelectionToPlotFrame();
m_sdbSizerCancel->SetLabel( _( "Done" ) );
}
void addSelectionToPlotFrame();
bool addSignalToPlotFrame( const wxString& aPlotName );
SIM_PLOT_FRAME* m_plotFrame;
NGSPICE_CIRCUIT_MODEL* m_circuitModel;
};
#endif /* DIALOG_SIGNAL_LIST_H */

View File

@ -1,64 +0,0 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "dialog_signal_list_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_SIGNAL_LIST_BASE::DIALOG_SIGNAL_LIST_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* bSizer6;
bSizer6 = new wxBoxSizer( wxVERTICAL );
m_signals = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_EXTENDED|wxLB_NEEDED_SB|wxLB_SORT );
m_signals->SetMinSize( wxSize( 450,400 ) );
bSizer6->Add( m_signals, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );
m_staticText1 = new wxStaticText( this, wxID_ANY, _("Add signal by name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1->Wrap( -1 );
bSizer2->Add( m_staticText1, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_signalEntry = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
bSizer2->Add( m_signalEntry, 0, wxALL|wxEXPAND, 5 );
bSizer6->Add( bSizer2, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
m_sdbSizerCancel = new wxButton( this, wxID_CANCEL );
m_sdbSizer->AddButton( m_sdbSizerCancel );
m_sdbSizer->Realize();
bSizer6->Add( m_sdbSizer, 0, wxEXPAND|wxALL, 5 );
this->SetSizer( bSizer6 );
this->Layout();
bSizer6->Fit( this );
this->Centre( wxBOTH );
// Connect Events
m_signals->Connect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( DIALOG_SIGNAL_LIST_BASE::onSignalAdd ), NULL, this );
m_signalEntry->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_SIGNAL_LIST_BASE::onSignalAdd ), NULL, this );
}
DIALOG_SIGNAL_LIST_BASE::~DIALOG_SIGNAL_LIST_BASE()
{
// Disconnect Events
m_signals->Disconnect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( DIALOG_SIGNAL_LIST_BASE::onSignalAdd ), NULL, this );
m_signalEntry->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_SIGNAL_LIST_BASE::onSignalAdd ), NULL, this );
}

View File

@ -1,286 +0,0 @@
<?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_signal_list_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_SIGNAL_LIST_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_SIGNAL_LIST_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title">Add Signals</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">bSizer6</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">1</property>
<object class="wxListBox" 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"></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">450,400</property>
<property name="moveable">1</property>
<property name="name">m_signals</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">wxLB_EXTENDED|wxLB_NEEDED_SB|wxLB_SORT</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnListBoxDClick">onSignalAdd</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer2</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxTOP|wxRIGHT|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">Add signal by name:</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_staticText1</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">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxTextCtrl" 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="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="maxlength"></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_signalEntry</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">wxTE_PROCESS_ENTER</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="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnTextEnter">onSignalAdd</event>
</object>
</object>
</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_sdbSizer</property>
<property name="permission">protected</property>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>

View File

@ -1,55 +0,0 @@
///////////////////////////////////////////////////////////////////////////
// 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/listbox.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_SIGNAL_LIST_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_SIGNAL_LIST_BASE : public DIALOG_SHIM
{
private:
protected:
wxListBox* m_signals;
wxStaticText* m_staticText1;
wxTextCtrl* m_signalEntry;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
// Virtual event handlers, override them in your derived class
virtual void onSignalAdd( wxCommandEvent& event ) { event.Skip(); }
public:
DIALOG_SIGNAL_LIST_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Add Signals"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_SIGNAL_LIST_BASE();
};

View File

@ -1175,6 +1175,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterMouseMoved( wxMouseEvent& aEvent )
SetCursor( wxCURSOR_IBEAM ); SetCursor( wxCURSOR_IBEAM );
} }
void DIALOG_SYMBOL_FIELDS_TABLE::OnFieldsCtrlSelectionChanged( wxDataViewEvent& event ) void DIALOG_SYMBOL_FIELDS_TABLE::OnFieldsCtrlSelectionChanged( wxDataViewEvent& event )
{ {
int row = m_fieldsCtrl->GetSelectedRow(); int row = m_fieldsCtrl->GetSelectedRow();

View File

@ -30,7 +30,7 @@
#include <locale_io.h> #include <locale_io.h>
SIM_PLOT_TYPE NGSPICE_CIRCUIT_MODEL::VectorToSignal( const std::string& aVector, SIM_TRACE_TYPE NGSPICE_CIRCUIT_MODEL::VectorToSignal( const std::string& aVector,
wxString& aSignal ) const wxString& aSignal ) const
{ {
using namespace std; using namespace std;

View File

@ -55,14 +55,14 @@ public:
virtual ~NGSPICE_CIRCUIT_MODEL() {} virtual ~NGSPICE_CIRCUIT_MODEL() {}
/** /**
* Return name of Spice dataset for a specific plot. * Return name of Spice dataset for a specific trace.
* *
* @param aVector is name of the vector produced by ngspice * @param aVector is name of the vector produced by ngspice
* @param [out] aSignal is output in form: V(R1), Ib(Q2), I(L8) * @param [out] aSignal is output in form: V(R1), Ib(Q2), I(L8)
* @return [SPT_VOLTAGE, SPT_CURRENT]. Otherwise SPT_UNKNOWN if vector is * @return [SPT_VOLTAGE, SPT_CURRENT]. Otherwise SPT_UNKNOWN if vector is of different,
* of different, unsupported type. * unsupported type.
*/ */
SIM_PLOT_TYPE VectorToSignal( const std::string& aVector, wxString& aSignal ) const; SIM_TRACE_TYPE VectorToSignal( const std::string& aVector, wxString& aSignal ) const;
void SetSimOptions( int aOptions ) { m_options = aOptions; } void SetSimOptions( int aOptions ) { m_options = aOptions; }
int GetSimOptions() const { return m_options; } int GetSimOptions() const { return m_options; }

View File

@ -38,6 +38,10 @@
#include <bitmaps.h> #include <bitmaps.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <widgets/tuner_slider.h> #include <widgets/tuner_slider.h>
#include <widgets/grid_color_swatch_helpers.h>
#include <widgets/wx_grid.h>
#include <grid_tricks.h>
#include <eda_pattern_match.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tool/tool_dispatcher.h> #include <tool/tool_dispatcher.h>
#include <tool/action_manager.h> #include <tool/action_manager.h>
@ -58,11 +62,11 @@
#include <memory> #include <memory>
SIM_PLOT_TYPE operator|( SIM_PLOT_TYPE aFirst, SIM_PLOT_TYPE aSecond ) SIM_TRACE_TYPE operator|( SIM_TRACE_TYPE aFirst, SIM_TRACE_TYPE aSecond )
{ {
int res = (int) aFirst | (int) aSecond; int res = (int) aFirst | (int) aSecond;
return (SIM_PLOT_TYPE) res; return (SIM_TRACE_TYPE) res;
} }
@ -106,6 +110,25 @@ private:
}; };
enum SIGNALS_GRID_COLUMNS
{
COL_SIGNAL_NAME = 0,
COL_SIGNAL_SHOW,
COL_SIGNAL_COLOR,
COL_CURSOR_1,
COL_CURSOR_2
};
enum CURSORS_GRID_COLUMNS
{
COL_CURSOR_NAME = 0,
COL_CURSOR_SIGNAL,
COL_CURSOR_X,
COL_CURSOR_Y
};
SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
SIM_PLOT_FRAME_BASE( aParent ), SIM_PLOT_FRAME_BASE( aParent ),
m_lastSimPlot( nullptr ), m_lastSimPlot( nullptr ),
@ -114,7 +137,6 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_simFinished( false ) m_simFinished( false )
{ {
SetKiway( this, aKiway ); SetKiway( this, aKiway );
m_signalsIconColorList = nullptr;
m_schematicFrame = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false ); m_schematicFrame = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
wxASSERT( m_schematicFrame ); wxASSERT( m_schematicFrame );
@ -130,6 +152,36 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
// Get the previous size and position of windows: // Get the previous size and position of windows:
LoadSettings( config() ); LoadSettings( config() );
m_signalsGrid->wxGrid::SetLabelFont( KIUI::GetStatusFont( this ) );
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetColAttr( COL_SIGNAL_NAME, attr );
attr = new wxGridCellAttr;
attr->SetRenderer( new wxGridCellBoolRenderer() );
attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetColAttr( COL_SIGNAL_SHOW, attr );
m_signalsGrid->PushEventHandler( new GRID_TRICKS( m_signalsGrid ) );
m_cursorsGrid->wxGrid::SetLabelFont( KIUI::GetStatusFont( this ) );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_cursorsGrid->SetColAttr( COL_CURSOR_NAME, attr );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_cursorsGrid->SetColAttr( COL_CURSOR_SIGNAL, attr );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_cursorsGrid->SetColAttr( COL_CURSOR_Y, attr );
m_cursorsGrid->PushEventHandler( new GRID_TRICKS( m_cursorsGrid ) );
// Prepare the color list to plot traces // Prepare the color list to plot traces
SIM_PLOT_COLORS::FillDefaultColorList( m_darkMode ); SIM_PLOT_COLORS::FillDefaultColorList( m_darkMode );
@ -184,12 +236,15 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
SIM_PLOT_FRAME::~SIM_PLOT_FRAME() SIM_PLOT_FRAME::~SIM_PLOT_FRAME()
{ {
// Delete the GRID_TRICKS.
m_signalsGrid->PopEventHandler( true );
m_cursorsGrid->PopEventHandler( true );
NULL_REPORTER devnull; NULL_REPORTER devnull;
m_simulator->Attach( nullptr, devnull ); m_simulator->Attach( nullptr, devnull );
m_simulator->SetReporter( nullptr ); m_simulator->SetReporter( nullptr );
delete m_reporter; delete m_reporter;
delete m_signalsIconColorList;
} }
@ -230,10 +285,16 @@ void SIM_PLOT_FRAME::ShowChangedLanguage()
m_workbook->SetPageText( ii, pageTitle ); m_workbook->SetPageText( ii, pageTitle );
} }
m_staticTextSignals->SetLabel( _( "Signals" ) ); m_signalsGrid->SetColLabelValue( COL_SIGNAL_NAME, _( "Signal" ) );
updateSignalList(); m_signalsGrid->SetColLabelValue( COL_SIGNAL_SHOW, _( "Plot" ) );
m_signalsGrid->SetColLabelValue( COL_SIGNAL_COLOR, _( "Color" ) );
m_signalsGrid->SetColLabelValue( COL_CURSOR_1, _( "Cursor 1" ) );
m_signalsGrid->SetColLabelValue( COL_CURSOR_2, _( "Cursor 2" ) );
m_staticTextCursors->SetLabel( _( "Cursors" ) ); m_cursorsGrid->SetColLabelValue( COL_CURSOR_NAME, _( "Cursor" ) );
m_cursorsGrid->SetColLabelValue( COL_CURSOR_SIGNAL, _( "Signal" ) );
m_cursorsGrid->SetColLabelValue( COL_CURSOR_X, _( "Time" ) );
m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, _( "Voltage / Current" ) );
wxCommandEvent dummy; wxCommandEvent dummy;
onCursorUpdate( dummy ); onCursorUpdate( dummy );
@ -373,6 +434,73 @@ void SIM_PLOT_FRAME::setSubWindowsSashSize()
} }
void SIM_PLOT_FRAME::rebuildSignalsGrid( wxString aFilter )
{
m_signalsGrid->ClearRows();
if( aFilter.IsEmpty() )
aFilter = wxS( "*" );
EDA_COMBINED_MATCHER matcher( aFilter, CTX_SIGNAL );
int row = 0;
for( const wxString& signal : m_signals )
{
int matches;
int offset;
if( matcher.Find( signal, matches, offset ) && offset == 0 )
{
m_signalsGrid->AppendRows( 1 );
m_signalsGrid->SetCellValue( row, COL_SIGNAL_NAME, signal );
if( TRACE* trace = GetCurrentPlot()->GetTrace( signal ) )
{
m_signalsGrid->SetCellValue( row, COL_SIGNAL_SHOW, wxS( "1" ) );
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetRenderer( new GRID_CELL_COLOR_RENDERER( this ) );
attr->SetEditor( new GRID_CELL_COLOR_SELECTOR( this, m_signalsGrid ) );
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetAttr( row, COL_SIGNAL_COLOR, attr );
KIGFX::COLOR4D color( trace->GetPen().GetColour() );
m_signalsGrid->SetCellValue( row, COL_SIGNAL_COLOR, color.ToCSSString() );
attr = new wxGridCellAttr;
attr->SetRenderer( new wxGridCellBoolRenderer() );
attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetAttr( row, COL_CURSOR_1, attr );
attr = new wxGridCellAttr;
attr->SetRenderer( new wxGridCellBoolRenderer() );
attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetAttr( row, COL_CURSOR_2, attr );
}
else
{
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_SIGNAL_COLOR, attr );
m_signalsGrid->SetCellValue( row, COL_SIGNAL_COLOR, wxEmptyString );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_CURSOR_1, attr );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_CURSOR_2, attr );
}
row++;
}
}
}
void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand ) void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
{ {
if( m_circuitModel->CommandToSimType( GetCurrentSimCommand() ) == ST_UNKNOWN ) if( m_circuitModel->CommandToSimType( GetCurrentSimCommand() ) == ST_UNKNOWN )
@ -423,12 +551,45 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
} }
} }
if( !plotWindow || plotWindow->GetType() != m_circuitModel->GetSimType() )
{
plotWindow = NewPlotPanel( m_circuitModel->GetSimCommand(),
m_circuitModel->GetSimOptions() );
}
std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock ); std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
if( simulatorLock.owns_lock() ) if( simulatorLock.owns_lock() )
{ {
wxBusyCursor toggle; wxBusyCursor toggle;
m_signals.clear();
// Add voltages
for( const std::string& net : m_circuitModel->GetNets() )
{
// netnames are escaped (can contain "{slash}" for '/') Unscape them:
wxString netname = UnescapeString( net );
if( netname != "GND" && netname != "0" )
m_signals.push_back( wxString::Format( "V(%s)", netname ) );
}
auto simType = m_circuitModel->GetSimType();
// Add currents
if( simType == ST_TRANSIENT || simType == ST_DC )
{
for( const SPICE_ITEM& item : m_circuitModel->GetItems() )
{
// Add all possible currents for the primitive.
for( const std::string& name : item.model->SpiceGenerator().CurrentNames( item ) )
m_signals.push_back( name );
}
}
rebuildSignalsGrid( m_filter->GetValue() );
applyTuners(); applyTuners();
// Prevents memory leak on succeding simulations by deleting old vectors // Prevents memory leak on succeding simulations by deleting old vectors
@ -442,25 +603,22 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
} }
SIM_PANEL_BASE* SIM_PLOT_FRAME::NewPlotPanel( wxString aSimCommand, int aOptions ) SIM_PANEL_BASE* SIM_PLOT_FRAME::NewPlotPanel( const wxString& aSimCommand, int aOptions )
{ {
SIM_PANEL_BASE* plotPanel = nullptr; SIM_PANEL_BASE* plotPanel = nullptr;
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( aSimCommand ); SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( aSimCommand );
if( SIM_PANEL_BASE::IsPlottable( simType ) ) if( SIM_PANEL_BASE::IsPlottable( simType ) )
{ {
SIM_PLOT_PANEL* panel; SIM_PLOT_PANEL* panel = new SIM_PLOT_PANEL( aSimCommand, aOptions, m_workbook, wxID_ANY );
panel = new SIM_PLOT_PANEL( aSimCommand, aOptions, m_workbook, wxID_ANY );
panel->GetPlotWin()->EnableMouseWheelPan(
Pgm().GetCommonSettings()->m_Input.scroll_modifier_zoom != 0 );
plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel ); plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
COMMON_SETTINGS::INPUT cfg = Pgm().GetCommonSettings()->m_Input;
panel->GetPlotWin()->EnableMouseWheelPan( cfg.scroll_modifier_zoom != 0 );
} }
else else
{ {
SIM_NOPLOT_PANEL* panel; SIM_NOPLOT_PANEL* panel = new SIM_NOPLOT_PANEL( aSimCommand, aOptions, m_workbook, wxID_ANY );
panel = new SIM_NOPLOT_PANEL( aSimCommand, aOptions, m_workbook, wxID_ANY );
plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel ); plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
} }
@ -473,15 +631,131 @@ SIM_PANEL_BASE* SIM_PLOT_FRAME::NewPlotPanel( wxString aSimCommand, int aOptions
} }
void SIM_PLOT_FRAME::OnFilterText( wxCommandEvent& aEvent )
{
rebuildSignalsGrid( m_filter->GetValue() );
}
void SIM_PLOT_FRAME::OnFilterMouseMoved( wxMouseEvent& aEvent )
{
wxPoint pos = aEvent.GetPosition();
wxRect ctrlRect = m_filter->GetScreenRect();
int buttonWidth = ctrlRect.GetHeight(); // Presume buttons are square
if( m_filter->IsSearchButtonVisible() && pos.x < buttonWidth )
SetCursor( wxCURSOR_ARROW );
else if( m_filter->IsCancelButtonVisible() && pos.x > ctrlRect.GetWidth() - buttonWidth )
SetCursor( wxCURSOR_ARROW );
else
SetCursor( wxCURSOR_IBEAM );
}
void SIM_PLOT_FRAME::onSignalsGridCellChanged( wxGridEvent& aEvent )
{
int row = aEvent.GetRow();
int col = aEvent.GetCol();
wxString text = m_signalsGrid->GetCellValue( row, col );
if( col == COL_SIGNAL_SHOW )
{
if( text == wxS( "1" ) )
{
wxString signalName = m_signalsGrid->GetCellValue( row, COL_SIGNAL_NAME );
if( !signalName.IsEmpty() )
{
wxUniChar firstChar = signalName[0];
if( firstChar == 'V' || firstChar == 'v' )
addTrace( signalName, SPT_VOLTAGE );
else if( firstChar == 'I' || firstChar == 'i' )
addTrace( signalName, SPT_CURRENT );
}
if( !GetCurrentPlot()->GetTrace( signalName ) )
{
aEvent.Veto();
return;
}
}
else
{
removeTrace( m_signalsGrid->GetCellValue( row, COL_SIGNAL_NAME ) );
}
}
else if( col == COL_CURSOR_1 || col == COL_CURSOR_2 )
{
SIM_PLOT_PANEL* plot = GetCurrentPlot();
for( int ii = 0; ii < m_signalsGrid->GetNumberRows(); ++ii )
{
wxString signalName = m_signalsGrid->GetCellValue( ii, COL_SIGNAL_NAME );
bool enable = ii == row && text == wxS( "1" );
plot->EnableCursor( signalName, col == COL_CURSOR_1 ? 1 : 2, enable );
}
}
updateSignalsGrid();
}
void SIM_PLOT_FRAME::onCursorsGridCellChanged( wxGridEvent& aEvent )
{
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
if( !plotPanel )
return;
int row = aEvent.GetRow();
int col = aEvent.GetCol();
wxString text = m_cursorsGrid->GetCellValue( row, col );
wxString cursorName = m_cursorsGrid->GetCellValue( row, COL_CURSOR_NAME );
if( col == COL_CURSOR_X )
{
CURSOR* cursor1 = nullptr;
CURSOR* cursor2 = nullptr;
for( const auto& [name, trace] : plotPanel->GetTraces() )
{
if( CURSOR* cursor = trace->GetCursor( 1 ) )
cursor1 = cursor;
if( CURSOR* cursor = trace->GetCursor( 2 ) )
cursor2 = cursor;
}
double value = SPICE_VALUE( text ).ToDouble();
if( cursorName == wxS( "1" ) && cursor1 )
cursor1->SetCoordX( value );
else if( cursorName == wxS( "2" ) && cursor2 )
cursor2->SetCoordX( value );
else if( cursorName == _( "Diff" ) && cursor1 && cursor2 )
cursor2->SetCoordX( cursor1->GetCoords().x + value );
wxCommandEvent dummy;
onCursorUpdate( dummy );
}
else
{
wxFAIL_MSG( wxT( "All other columns are supposed to be read-only!" ) );
}
}
void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName ) void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName )
{ {
addPlot( aNetName, SPT_VOLTAGE ); addTrace( aNetName, SPT_VOLTAGE );
} }
void SIM_PLOT_FRAME::AddCurrentPlot( const wxString& aDeviceName ) void SIM_PLOT_FRAME::AddCurrentPlot( const wxString& aDeviceName )
{ {
addPlot( aDeviceName, SPT_CURRENT ); addTrace( aDeviceName, SPT_CURRENT );
} }
@ -579,7 +853,7 @@ const NGSPICE_CIRCUIT_MODEL* SIM_PLOT_FRAME::GetExporter() const
} }
void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType ) void SIM_PLOT_FRAME::addTrace( const wxString& aName, SIM_TRACE_TYPE aType )
{ {
SIM_TYPE simType = m_circuitModel->GetSimType(); SIM_TYPE simType = m_circuitModel->GetSimType();
@ -611,7 +885,7 @@ void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType )
return; return;
bool updated = false; bool updated = false;
SIM_PLOT_TYPE xAxisType = getXAxisType( simType ); SIM_TRACE_TYPE xAxisType = getXAxisType( simType );
if( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY ) if( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY )
{ {
@ -620,52 +894,52 @@ void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType )
// If magnitude or phase wasn't specified, then add both // If magnitude or phase wasn't specified, then add both
if( baseType == aType ) if( baseType == aType )
{ {
updated |= updatePlot( aName, ( SIM_PLOT_TYPE )( baseType | SPT_AC_MAG ), plotPanel ); updated |= updateTrace( aName, (SIM_TRACE_TYPE) ( baseType | SPT_AC_MAG ), plotPanel );
updated |= updatePlot( aName, ( SIM_PLOT_TYPE )( baseType | SPT_AC_PHASE ), plotPanel ); updated |= updateTrace( aName, (SIM_TRACE_TYPE) ( baseType | SPT_AC_PHASE ), plotPanel );
} }
else else
{ {
updated |= updatePlot( aName, ( SIM_PLOT_TYPE )( aType ), plotPanel ); updated |= updateTrace( aName, (SIM_TRACE_TYPE) ( aType ), plotPanel );
} }
} }
else else
{ {
updated = updatePlot( aName, aType, plotPanel ); updated = updateTrace( aName, aType, plotPanel );
} }
if( updated ) if( updated )
updateSignalList(); updateSignalsGrid();
} }
void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName ) void SIM_PLOT_FRAME::removeTrace( const wxString& aSignalName )
{ {
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
if( !plotPanel ) if( !plotPanel )
return; return;
wxASSERT( plotPanel->TraceShown( aPlotName ) ); wxASSERT( plotPanel->TraceShown( aSignalName ) );
m_workbook->DeleteTrace( plotPanel, aPlotName ); m_workbook->DeleteTrace( plotPanel, aSignalName );
plotPanel->GetPlotWin()->Fit(); plotPanel->GetPlotWin()->Fit();
updateSignalList(); updateSignalsGrid();
wxCommandEvent dummy; wxCommandEvent dummy;
onCursorUpdate( dummy ); onCursorUpdate( dummy );
} }
bool SIM_PLOT_FRAME::updatePlot( const wxString& aName, SIM_PLOT_TYPE aType, bool SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
SIM_PLOT_PANEL* aPlotPanel ) SIM_PLOT_PANEL* aPlotPanel )
{ {
SIM_TYPE simType = m_circuitModel->GetSimType(); SIM_TYPE simType = m_circuitModel->GetSimType();
wxString plotTitle = aName; wxString traceTitle = aName;
if( aType & SPT_AC_MAG ) if( aType & SPT_AC_MAG )
plotTitle += _( " (mag)" ); traceTitle += _( " (mag)" );
else if( aType & SPT_AC_PHASE ) else if( aType & SPT_AC_PHASE )
plotTitle += _( " (phase)" ); traceTitle += _( " (phase)" );
if( !SIM_PANEL_BASE::IsPlottable( simType ) ) if( !SIM_PANEL_BASE::IsPlottable( simType ) )
{ {
@ -739,7 +1013,7 @@ bool SIM_PLOT_FRAME::updatePlot( const wxString& aName, SIM_PLOT_TYPE aType,
for( size_t idx = 0; idx <= outer; idx++ ) for( size_t idx = 0; idx <= outer; idx++ )
{ {
name = wxString::Format( wxT( "%s (%s = %s V)" ), name = wxString::Format( wxT( "%s (%s = %s V)" ),
plotTitle, traceTitle,
source2.m_source, source2.m_source,
v.ToString() ); v.ToString() );
@ -759,74 +1033,74 @@ bool SIM_PLOT_FRAME::updatePlot( const wxString& aName, SIM_PLOT_TYPE aType,
} }
} }
m_workbook->AddTrace( aPlotPanel, plotTitle, aName, size, data_x.data(), data_y.data(), aType ); m_workbook->AddTrace( aPlotPanel, traceTitle, aName, size, data_x.data(), data_y.data(), aType );
return true; return true;
} }
void SIM_PLOT_FRAME::updateSignalList() void SIM_PLOT_FRAME::updateSignalsGrid()
{ {
m_signals->ClearAll(); SIM_PLOT_PANEL* plot = GetCurrentPlot();
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); for( int row = 0; row < m_signalsGrid->GetNumberRows(); ++row )
{
wxString signal = m_signalsGrid->GetCellValue( row, COL_SIGNAL_NAME );
if( !plotPanel ) if( TRACE* trace = plot->GetTrace( signal ) )
return; {
m_signalsGrid->SetCellValue( row, COL_SIGNAL_SHOW, wxS( "1" ) );
wxSize size = m_signals->GetClientSize(); wxGridCellAttr* attr = new wxGridCellAttr;
m_signals->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x ); attr->SetRenderer( new GRID_CELL_COLOR_RENDERER( this ) );
attr->SetEditor( new GRID_CELL_COLOR_SELECTOR( this, m_signalsGrid ) );
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetAttr( row, COL_SIGNAL_COLOR, attr );
// Build an image list, to show the color of the corresponding trace KIGFX::COLOR4D color( trace->GetPen().GetColour() );
// in the plot panel m_signalsGrid->SetCellValue( row, COL_SIGNAL_COLOR, color.ToCSSString() );
// This image list is used for trace and cursor lists
wxMemoryDC bmDC;
const int isize = bmDC.GetCharHeight();
if( m_signalsIconColorList == nullptr ) attr = new wxGridCellAttr;
m_signalsIconColorList = new wxImageList( isize, isize, false ); attr->SetRenderer( new wxGridCellBoolRenderer() );
attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetAttr( row, COL_CURSOR_1, attr );
attr = new wxGridCellAttr;
attr->SetRenderer( new wxGridCellBoolRenderer() );
attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetAttr( row, COL_CURSOR_2, attr );
if( trace->HasCursor( 1 ) )
m_signalsGrid->SetCellValue( row, COL_CURSOR_1, wxS( "1" ) );
else else
m_signalsIconColorList->RemoveAll(); m_signalsGrid->SetCellValue( row, COL_CURSOR_1, wxEmptyString );
for( const auto& [name, trace] : GetCurrentPlot()->GetTraces() ) if( trace->HasCursor( 2 ) )
{ m_signalsGrid->SetCellValue( row, COL_CURSOR_2, wxS( "1" ) );
wxBitmap bitmap( isize, isize ); else
bmDC.SelectObject( bitmap ); m_signalsGrid->SetCellValue( row, COL_CURSOR_2, wxEmptyString );
wxColour tcolor = trace->GetPen().GetColour();
wxColour bgColor = m_signals->wxWindow::GetBackgroundColour();
bmDC.SetPen( wxPen( bgColor ) );
bmDC.SetBrush( wxBrush( bgColor ) );
bmDC.DrawRectangle( 0, 0, isize, isize ); // because bmDC.Clear() does not work in wxGTK
bmDC.SetPen( wxPen( tcolor ) );
bmDC.SetBrush( wxBrush( tcolor ) );
bmDC.DrawRectangle( 0, isize / 4 + 1, isize, isize / 2 );
bmDC.SelectObject( wxNullBitmap ); // Needed to initialize bitmap
bitmap.SetMask( new wxMask( bitmap, *wxBLACK ) );
m_signalsIconColorList->Add( bitmap );
} }
else
if( bmDC.IsOk() )
{ {
bmDC.SetBrush( wxNullBrush ); m_signalsGrid->SetCellValue( row, COL_SIGNAL_SHOW, wxEmptyString );
bmDC.SetPen( wxNullPen );
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_SIGNAL_COLOR, attr );
m_signalsGrid->SetCellValue( row, COL_SIGNAL_COLOR, wxEmptyString );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_CURSOR_1, attr );
m_signalsGrid->SetCellValue( row, COL_CURSOR_1, wxEmptyString );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_CURSOR_2, attr );
m_signalsGrid->SetCellValue( row, COL_CURSOR_2, wxEmptyString );
} }
m_signals->SetImageList( m_signalsIconColorList, wxIMAGE_LIST_SMALL );
// Fill the signals listctrl. Keep the order of names and
// the order of icon color identical, because the icons
// are also used in cursor list, and the color index is
// calculated from the trace name index
int imgidx = 0;
for( const auto& [name, trace] : plotPanel->GetTraces() )
{
m_signals->InsertItem( imgidx, name, imgidx );
imgidx++;
} }
} }
@ -1002,7 +1276,7 @@ bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath )
} }
#endif #endif
addPlot( name, (SIM_PLOT_TYPE) traceType ); addTrace( name, (SIM_TRACE_TYPE) traceType );
} }
} }
@ -1102,7 +1376,7 @@ bool SIM_PLOT_FRAME::SaveWorkbook( const wxString& aPath )
} }
SIM_PLOT_TYPE SIM_PLOT_FRAME::getXAxisType( SIM_TYPE aType ) const SIM_TRACE_TYPE SIM_PLOT_FRAME::getXAxisType( SIM_TYPE aType ) const
{ {
switch( aType ) switch( aType )
{ {
@ -1112,7 +1386,7 @@ SIM_PLOT_TYPE SIM_PLOT_FRAME::getXAxisType( SIM_TYPE aType ) const
case ST_TRANSIENT: return SPT_TIME; case ST_TRANSIENT: return SPT_TIME;
default: default:
wxASSERT_MSG( false, wxT( "Unhandled simulation type" ) ); wxASSERT_MSG( false, wxT( "Unhandled simulation type" ) );
return (SIM_PLOT_TYPE) 0; return (SIM_TRACE_TYPE) 0;
} }
} }
@ -1146,23 +1420,17 @@ void SIM_PLOT_FRAME::onPlotClose( wxAuiNotebookEvent& event )
void SIM_PLOT_FRAME::onPlotClosed( wxAuiNotebookEvent& event ) void SIM_PLOT_FRAME::onPlotClosed( wxAuiNotebookEvent& event )
{ {
if( m_workbook->GetPageCount() == 0 ) m_signals.clear();
{ rebuildSignalsGrid( m_filter->GetValue() );
m_signals->ClearAll();
m_cursors->ClearAll();
}
else
{
updateSignalList();
wxCommandEvent dummy; wxCommandEvent dummy;
onCursorUpdate( dummy ); onCursorUpdate( dummy );
}
} }
void SIM_PLOT_FRAME::onPlotChanged( wxAuiNotebookEvent& event ) void SIM_PLOT_FRAME::onPlotChanged( wxAuiNotebookEvent& event )
{ {
updateSignalList(); rebuildSignalsGrid( m_filter->GetValue() );
wxCommandEvent dummy; wxCommandEvent dummy;
onCursorUpdate( dummy ); onCursorUpdate( dummy );
} }
@ -1173,52 +1441,6 @@ void SIM_PLOT_FRAME::onPlotDragged( wxAuiNotebookEvent& event )
} }
void SIM_PLOT_FRAME::onSignalDblClick( wxMouseEvent& event )
{
// Remove signal from the plot panel when double clicked
long idx = m_signals->GetFocusedItem();
if( idx != wxNOT_FOUND )
removePlot( m_signals->GetItemText( idx, 0 ) );
}
void SIM_PLOT_FRAME::onSignalRClick( wxListEvent& aEvent )
{
long idx = aEvent.GetIndex();
if( idx != wxNOT_FOUND )
m_signals->Select( idx );
idx = m_signals->GetFirstSelected();
if( idx != wxNOT_FOUND )
{
const wxString& netName = m_signals->GetItemText( idx, 0 );
SIGNAL_CONTEXT_MENU ctxMenu( netName, this );
m_signals->PopupMenu( &ctxMenu );
}
}
void SIM_PLOT_FRAME::onCursorRClick( wxListEvent& aEvent )
{
long idx = aEvent.GetIndex();
if( idx != wxNOT_FOUND )
m_signals->Select( idx );
idx = m_signals->GetFirstSelected();
if( idx != wxNOT_FOUND )
{
const wxString& netName = m_signals->GetItemText( idx, 0 );
CURSOR_CONTEXT_MENU ctxMenu( netName, this );
m_signals->PopupMenu( &ctxMenu );
}
}
void SIM_PLOT_FRAME::onWorkbookModified( wxCommandEvent& event ) void SIM_PLOT_FRAME::onWorkbookModified( wxCommandEvent& event )
{ {
updateTitle(); updateTitle();
@ -1315,18 +1537,10 @@ bool SIM_PLOT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
filename.SetFullName( Prj().GetProjectName() + wxT( ".wbk" ) ); filename.SetFullName( Prj().GetProjectName() + wxT( ".wbk" ) );
} }
#if 0 // TODO: Enable once 8.0 opens for dev return HandleUnsavedChanges( this, _( "Save changes to workbook?" ),
wxString msg = _( "Save changes to workbook?" );
#else
wxString fullFilename = filename.GetFullName();
wxString msg = _( "Save changes to '%s' before closing?" );
msg.Printf( msg, fullFilename );
#endif
return HandleUnsavedChanges( this, msg,
[&]() -> bool [&]() -> bool
{ {
return SaveWorkbook( Prj().AbsolutePath( fullFilename ) ); return SaveWorkbook( Prj().AbsolutePath( filename.GetFullName() ) );
} ); } );
} }
@ -1355,49 +1569,106 @@ void SIM_PLOT_FRAME::doCloseWindow()
void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event ) void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
{ {
wxSize size = m_cursors->GetClientSize(); m_cursorsGrid->ClearRows();
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
m_cursors->ClearAll();
if( !plotPanel ) if( !plotPanel )
return; return;
if( m_signalsIconColorList ) // Set up the labels
m_cursors->SetImageList(m_signalsIconColorList, wxIMAGE_LIST_SMALL); m_cursorsGrid->SetColLabelValue( COL_CURSOR_X, plotPanel->GetLabelX() );
// Fill the signals listctrl
m_cursors->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x / 2 );
const long X_COL = m_cursors->AppendColumn( plotPanel->GetLabelX(), wxLIST_FORMAT_LEFT,
size.x / 4 );
wxString labelY1 = plotPanel->GetLabelY1(); wxString labelY1 = plotPanel->GetLabelY1();
wxString labelY2 = plotPanel->GetLabelY2(); wxString labelY2 = plotPanel->GetLabelY2();
wxString labelY;
if( !labelY2.IsEmpty() ) if( labelY2.IsEmpty() )
labelY = labelY1 + wxT( " / " ) + labelY2; m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, labelY1 );
else else
labelY = labelY1; m_cursorsGrid->SetColLabelValue( COL_CURSOR_Y, labelY1 + wxT( " / " ) + labelY2 );
const long Y_COL = m_cursors->AppendColumn( labelY, wxLIST_FORMAT_LEFT, size.x / 4 ); 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 // Update cursor values
int itemidx = 0; wxString unitsX = plotPanel->GetUnitsX();
CURSOR* cursor1 = nullptr;
wxString unitsY1;
CURSOR* cursor2 = nullptr;
wxString unitsY2;
#define SET_CELL( r, c, v ) m_cursorsGrid->SetCellValue( r, c, v )
for( const auto& [name, trace] : plotPanel->GetTraces() ) for( const auto& [name, trace] : plotPanel->GetTraces() )
{ {
if( CURSOR* cursor = trace->GetCursor() ) if( CURSOR* cursor = trace->GetCursor( 1 ) )
{ {
// Find the right icon color in list. cursor1 = cursor;
// It is the icon used in m_signals list for the same trace unitsY1 = getUnitsY( trace );
long iconColor = m_signals->FindItem( -1, name );
const wxRealPoint coords = cursor->GetCoords(); wxRealPoint coords = cursor->GetCoords();
long idx = m_cursors->InsertItem( itemidx++, name, iconColor ); int row = m_cursorsGrid->GetNumberRows();
m_cursors->SetItem( idx, X_COL, SPICE_VALUE( coords.x ).ToSpiceString() );
m_cursors->SetItem( idx, Y_COL, SPICE_VALUE( coords.y ).ToSpiceString() ); 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 );
break;
} }
} }
for( const auto& [name, trace] : plotPanel->GetTraces() )
{
if( CURSOR* cursor = trace->GetCursor( 2 ) )
{
cursor2 = cursor;
unitsY2 = getUnitsY( trace );
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 );
break;
}
}
if( cursor1 && cursor2 && unitsY1 == unitsY2 )
{
const wxRealPoint coords = cursor2->GetCoords() - cursor1->GetCoords();
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 );
}
#undef SET_CELL
} }
@ -1471,7 +1742,6 @@ void SIM_PLOT_FRAME::setupUIConditions()
mgr->SetConditions( EE_ACTIONS::simCommand, ENABLE( SELECTION_CONDITIONS::ShowAlways ) ); mgr->SetConditions( EE_ACTIONS::simCommand, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
mgr->SetConditions( EE_ACTIONS::runSimulation, ENABLE( !simRunning ) ); mgr->SetConditions( EE_ACTIONS::runSimulation, ENABLE( !simRunning ) );
mgr->SetConditions( EE_ACTIONS::stopSimulation, ENABLE( simRunning ) ); mgr->SetConditions( EE_ACTIONS::stopSimulation, ENABLE( simRunning ) );
mgr->SetConditions( EE_ACTIONS::addSignals, ENABLE( simFinished ) );
mgr->SetConditions( EE_ACTIONS::simProbe, ENABLE( simFinished ) ); mgr->SetConditions( EE_ACTIONS::simProbe, ENABLE( simFinished ) );
mgr->SetConditions( EE_ACTIONS::simTune, ENABLE( simFinished ) ); mgr->SetConditions( EE_ACTIONS::simTune, ENABLE( simFinished ) );
mgr->SetConditions( EE_ACTIONS::showNetlist, ENABLE( SELECTION_CONDITIONS::ShowAlways ) ); mgr->SetConditions( EE_ACTIONS::showNetlist, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
@ -1532,7 +1802,7 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
struct TRACE_DESC struct TRACE_DESC
{ {
wxString m_name; ///< Name of the measured net/device wxString m_name; ///< Name of the measured net/device
SIM_PLOT_TYPE m_type; ///< Type of the signal SIM_TRACE_TYPE m_type; ///< Type of the signal
}; };
std::vector<struct TRACE_DESC> traceInfo; std::vector<struct TRACE_DESC> traceInfo;
@ -1549,11 +1819,11 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
for( const struct TRACE_DESC& trace : traceInfo ) for( const struct TRACE_DESC& trace : traceInfo )
{ {
if( !updatePlot( trace.m_name, trace.m_type, plotPanel ) ) if( !updateTrace( trace.m_name, trace.m_type, plotPanel ) )
removePlot( trace.m_name ); removeTrace( trace.m_name );
} }
updateSignalList(); rebuildSignalsGrid( m_filter->GetValue() );
plotPanel->GetPlotWin()->UpdateAll(); plotPanel->GetPlotWin()->UpdateAll();
plotPanel->ResetScales(); plotPanel->ResetScales();
} }
@ -1571,7 +1841,7 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
double val = val_list.at( 0 ); double val = val_list.at( 0 );
wxString outLine, signal; wxString outLine, signal;
SIM_PLOT_TYPE type = m_circuitModel->VectorToSignal( vec, signal ); SIM_TRACE_TYPE type = m_circuitModel->VectorToSignal( vec, signal );
const size_t tab = 25; //characters const size_t tab = 25; //characters
size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1; size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
@ -1643,64 +1913,6 @@ void SIM_PLOT_FRAME::onSimReport( wxCommandEvent& aEvent )
} }
SIM_PLOT_FRAME::SIGNAL_CONTEXT_MENU::SIGNAL_CONTEXT_MENU( const wxString& aSignal,
SIM_PLOT_FRAME* aPlotFrame ) :
m_signal( aSignal ),
m_plotFrame( aPlotFrame )
{
SIM_PLOT_PANEL* plot = m_plotFrame->GetCurrentPlot();
AddMenuItem( this, REMOVE_SIGNAL, _( "Remove Signal" ), _( "Remove the signal from the plot" ),
KiBitmap( BITMAPS::trash ) );
TRACE* trace = plot->GetTrace( m_signal );
AppendSeparator();
if( trace->HasCursor() )
AddMenuItem( this, HIDE_CURSOR, _( "Hide Cursor" ), KiBitmap( BITMAPS::pcb_target ) );
else
AddMenuItem( this, SHOW_CURSOR, _( "Show Cursor" ), KiBitmap( BITMAPS::pcb_target ) );
Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( SIGNAL_CONTEXT_MENU::onMenuEvent ),
nullptr, this );
}
void SIM_PLOT_FRAME::SIGNAL_CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
{
SIM_PLOT_PANEL* plot = m_plotFrame->GetCurrentPlot();
switch( aEvent.GetId() )
{
case REMOVE_SIGNAL: m_plotFrame->removePlot( m_signal ); break;
case SHOW_CURSOR: plot->EnableCursor( m_signal, true ); break;
case HIDE_CURSOR: plot->EnableCursor( m_signal, false ); break;
}
}
SIM_PLOT_FRAME::CURSOR_CONTEXT_MENU::CURSOR_CONTEXT_MENU( const wxString& aSignal,
SIM_PLOT_FRAME* aPlotFrame ) :
m_signal( aSignal ),
m_plotFrame( aPlotFrame )
{
AddMenuItem( this, HIDE_CURSOR, _( "Hide Cursor" ), KiBitmap( BITMAPS::pcb_target ) );
Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( CURSOR_CONTEXT_MENU::onMenuEvent ),
nullptr, this );
}
void SIM_PLOT_FRAME::CURSOR_CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
{
SIM_PLOT_PANEL* plot = m_plotFrame->GetCurrentPlot();
if( aEvent.GetId() == HIDE_CURSOR )
plot->EnableCursor( m_signal, false );
}
void SIM_PLOT_FRAME::onExit( wxCommandEvent& event ) void SIM_PLOT_FRAME::onExit( wxCommandEvent& event )
{ {
Kiway().OnKiCadExit(); Kiway().OnKiCadExit();

View File

@ -71,7 +71,7 @@ public:
* @param aSimOptions netlisting options * @param aSimOptions netlisting options
* @return The new plot panel. * @return The new plot panel.
*/ */
SIM_PANEL_BASE* NewPlotPanel( wxString aSimCommand, int aSimOptions ); SIM_PANEL_BASE* NewPlotPanel( const wxString& aSimCommand, int aSimOptions );
/** /**
* Shows a dialog for editing the current tab's simulation command, or creating a new tab * Shows a dialog for editing the current tab's simulation command, or creating a new tab
@ -209,18 +209,18 @@ private:
* @param aType describes the type of plot. * @param aType describes the type of plot.
* @param aParam is the parameter for the device/net (e.g. I, Id, V). * @param aParam is the parameter for the device/net (e.g. I, Id, V).
*/ */
void addPlot( const wxString& aName, SIM_PLOT_TYPE aType ); void addTrace( const wxString& aName, SIM_TRACE_TYPE aType );
/** /**
* Remove a plot with a specific title. * Remove a plot with a specific title.
* *
* @param aPlotName is the full plot title (e.g. I(Net-C1-Pad1)). * @param aSignalName is the full plot title (e.g. I(Net-C1-Pad1)).
*/ */
void removePlot( const wxString& aPlotName ); void removeTrace( const wxString& aSignalName );
/** /**
* Update plot in a particular SIM_PLOT_PANEL. If the panel does not contain * Update a trace in a particular SIM_PLOT_PANEL. If the panel does not contain the given
* the plot, it will be added. * trace, then add it.
* *
* @param aName is the device/net name. * @param aName is the device/net name.
* @param aType describes the type of plot. * @param aType describes the type of plot.
@ -228,12 +228,17 @@ private:
* @param aPlotPanel is the panel that should receive the update. * @param aPlotPanel is the panel that should receive the update.
* @return True if a plot was successfully added/updated. * @return True if a plot was successfully added/updated.
*/ */
bool updatePlot( const wxString& aName, SIM_PLOT_TYPE aType, SIM_PLOT_PANEL* aPlotPanel ); bool updateTrace( const wxString& aName, SIM_TRACE_TYPE aType, SIM_PLOT_PANEL* aPlotPanel );
/** /**
* Update the list of currently plotted signals. * Rebuild the filtered list of signals in the signals grid.
*/ */
void updateSignalList(); void rebuildSignalsGrid( wxString aFilter );
/**
* Update the values in the signals grid.
*/
void updateSignalsGrid();
/** /**
* Apply component values specified using tuner sliders to the current netlist. * Apply component values specified using tuner sliders to the current netlist.
@ -254,7 +259,7 @@ private:
/** /**
* Return X axis for a given simulation type. * Return X axis for a given simulation type.
*/ */
SIM_PLOT_TYPE getXAxisType( SIM_TYPE aType ) const; SIM_TRACE_TYPE getXAxisType( SIM_TYPE aType ) const;
// Event handlers // Event handlers
void onPlotClose( wxAuiNotebookEvent& event ) override; void onPlotClose( wxAuiNotebookEvent& event ) override;
@ -262,10 +267,11 @@ private:
void onPlotChanged( wxAuiNotebookEvent& event ) override; void onPlotChanged( wxAuiNotebookEvent& event ) override;
void onPlotDragged( wxAuiNotebookEvent& event ) override; void onPlotDragged( wxAuiNotebookEvent& event ) override;
void onSignalDblClick( wxMouseEvent& event ) override; void OnFilterText( wxCommandEvent& aEvent ) override;
void onSignalRClick( wxListEvent& aEvent ) override; void OnFilterMouseMoved( wxMouseEvent& aEvent ) override;
void onCursorRClick( wxListEvent& aEvent ) override; void onSignalsGridCellChanged( wxGridEvent& aEvent ) override;
void onCursorsGridCellChanged( wxGridEvent& aEvent ) override;
void onWorkbookModified( wxCommandEvent& event ); void onWorkbookModified( wxCommandEvent& event );
void onWorkbookClrModified( wxCommandEvent& event ); void onWorkbookClrModified( wxCommandEvent& event );
@ -287,54 +293,18 @@ private:
// frame is initialized (end of the Ctor) // frame is initialized (end of the Ctor)
void setSubWindowsSashSize(); void setSubWindowsSashSize();
enum CONTEXT_MENU_EVENTS
{
REMOVE_SIGNAL = 944,
SHOW_CURSOR,
HIDE_CURSOR
};
// Right click context menu for signals in the listbox
class SIGNAL_CONTEXT_MENU : public wxMenu
{
public:
SIGNAL_CONTEXT_MENU( const wxString& aSignal, SIM_PLOT_FRAME* aPlotFrame );
private:
void onMenuEvent( wxMenuEvent& aEvent );
const wxString& m_signal;
SIM_PLOT_FRAME* m_plotFrame;
};
// Right click context menu for cursors in the listbox
class CURSOR_CONTEXT_MENU : public wxMenu
{
public:
CURSOR_CONTEXT_MENU( const wxString& aSignal, SIM_PLOT_FRAME* aPlotFrame );
private:
void onMenuEvent( wxMenuEvent& aEvent );
const wxString& m_signal;
SIM_PLOT_FRAME* m_plotFrame;
};
private: private:
SCH_EDIT_FRAME* m_schematicFrame; SCH_EDIT_FRAME* m_schematicFrame;
std::shared_ptr<NGSPICE_CIRCUIT_MODEL> m_circuitModel; std::shared_ptr<NGSPICE_CIRCUIT_MODEL> m_circuitModel;
std::shared_ptr<SPICE_SIMULATOR> m_simulator; std::shared_ptr<SPICE_SIMULATOR> m_simulator;
SIM_THREAD_REPORTER* m_reporter; SIM_THREAD_REPORTER* m_reporter;
std::vector<wxString> m_signals;
std::list<TUNER_SLIDER*> m_tuners; std::list<TUNER_SLIDER*> m_tuners;
///< Panel that was used as the most recent one for simulations ///< Panel that was used as the most recent one for simulations
SIM_PANEL_BASE* m_lastSimPlot; SIM_PANEL_BASE* m_lastSimPlot;
///< imagelists used to add a small colored icon to signal names
///< and cursors name, the same color as the corresponding signal traces
wxImageList* m_signalsIconColorList;
// Variables for temporary storage: // Variables for temporary storage:
int m_splitterLeftRightSashPosition; int m_splitterLeftRightSashPosition;
int m_splitterPlotAndConsoleSashPosition; int m_splitterPlotAndConsoleSashPosition;

View File

@ -6,6 +6,7 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
#include "tool/action_toolbar.h" #include "tool/action_toolbar.h"
#include "widgets/wx_grid.h"
#include "sim_plot_frame_base.h" #include "sim_plot_frame_base.h"
@ -87,25 +88,67 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
m_panelSignals = new wxPanel( m_splitterSignals, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_panelSignals = new wxPanel( m_splitterSignals, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_panelSignals->SetMinSize( wxSize( -1,100 ) ); m_panelSignals->SetMinSize( wxSize( -1,100 ) );
wxBoxSizer* bSizer10; wxBoxSizer* bSignalsSizer;
bSizer10 = new wxBoxSizer( wxVERTICAL ); bSignalsSizer = new wxBoxSizer( wxVERTICAL );
m_staticTextSignals = new wxStaticText( m_panelSignals, wxID_ANY, _("Signals"), wxDefaultPosition, wxDefaultSize, 0 ); wxBoxSizer* bFiltersSizer;
m_staticTextSignals->Wrap( -1 ); bFiltersSizer = new wxBoxSizer( wxHORIZONTAL );
bSizer10->Add( m_staticTextSignals, 0, wxTOP|wxRIGHT, 5 );
m_signals = new wxListView( m_panelSignals, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_HEADER|wxLC_REPORT|wxLC_SINGLE_SEL ); m_filter = new wxSearchCtrl( m_panelSignals, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
bSizer10->Add( m_signals, 1, wxEXPAND, 5 ); #ifndef __WXMAC__
m_filter->ShowSearchButton( true );
#endif
m_filter->ShowCancelButton( true );
bFiltersSizer->Add( m_filter, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_panelSignals->SetSizer( bSizer10 ); bSignalsSizer->Add( bFiltersSizer, 0, wxEXPAND, 5 );
m_signalsGrid = new WX_GRID( m_panelSignals, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
// Grid
m_signalsGrid->CreateGrid( 0, 5 );
m_signalsGrid->EnableEditing( true );
m_signalsGrid->EnableGridLines( true );
m_signalsGrid->EnableDragGridSize( false );
m_signalsGrid->SetMargins( 0, 0 );
// Columns
m_signalsGrid->SetColSize( 0, 196 );
m_signalsGrid->SetColSize( 1, 50 );
m_signalsGrid->SetColSize( 2, 50 );
m_signalsGrid->SetColSize( 3, 54 );
m_signalsGrid->SetColSize( 4, 54 );
m_signalsGrid->EnableDragColMove( false );
m_signalsGrid->EnableDragColSize( true );
m_signalsGrid->SetColLabelValue( 0, _("Signal") );
m_signalsGrid->SetColLabelValue( 1, _("Plot") );
m_signalsGrid->SetColLabelValue( 2, _("Color") );
m_signalsGrid->SetColLabelValue( 3, _("Cursor 1") );
m_signalsGrid->SetColLabelValue( 4, _("Cursor 2") );
m_signalsGrid->SetColLabelSize( -1 );
m_signalsGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_signalsGrid->EnableDragRowSize( true );
m_signalsGrid->SetRowLabelSize( 0 );
m_signalsGrid->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_signalsGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP );
bSignalsSizer->Add( m_signalsGrid, 1, wxEXPAND, 5 );
m_panelSignals->SetSizer( bSignalsSizer );
m_panelSignals->Layout(); m_panelSignals->Layout();
bSizer10->Fit( m_panelSignals ); bSignalsSizer->Fit( m_panelSignals );
m_panelCursorsAndTune = new wxPanel( m_splitterSignals, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_panelCursorsAndTune = new wxPanel( m_splitterSignals, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_panelCursorsAndTune->SetMinSize( wxSize( -1,300 ) ); m_panelCursorsAndTune->SetMinSize( wxSize( -1,300 ) );
wxBoxSizer* bSizer9; wxBoxSizer* bCursorsSizer;
bSizer9 = new wxBoxSizer( wxVERTICAL ); bCursorsSizer = new wxBoxSizer( wxVERTICAL );
m_splitterTuneValues = new wxSplitterWindow( m_panelCursorsAndTune, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3DSASH|wxSP_LIVE_UPDATE|wxBORDER_NONE ); m_splitterTuneValues = new wxSplitterWindow( m_panelCursorsAndTune, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3DSASH|wxSP_LIVE_UPDATE|wxBORDER_NONE );
m_splitterTuneValues->SetSashGravity( 0.5 ); m_splitterTuneValues->SetSashGravity( 0.5 );
@ -118,12 +161,39 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer12; wxBoxSizer* bSizer12;
bSizer12 = new wxBoxSizer( wxVERTICAL ); bSizer12 = new wxBoxSizer( wxVERTICAL );
m_staticTextCursors = new wxStaticText( m_panelCursors, wxID_ANY, _("Cursors"), wxDefaultPosition, wxDefaultSize, 0 ); m_cursorsGrid = new WX_GRID( m_panelCursors, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCursors->Wrap( -1 );
bSizer12->Add( m_staticTextCursors, 0, wxTOP|wxRIGHT, 5 );
m_cursors = new wxListCtrl( m_panelCursors, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL ); // Grid
bSizer12->Add( m_cursors, 1, wxEXPAND, 5 ); m_cursorsGrid->CreateGrid( 0, 4 );
m_cursorsGrid->EnableEditing( true );
m_cursorsGrid->EnableGridLines( true );
m_cursorsGrid->EnableDragGridSize( false );
m_cursorsGrid->SetMargins( 0, 0 );
// Columns
m_cursorsGrid->SetColSize( 0, 44 );
m_cursorsGrid->SetColSize( 1, 140 );
m_cursorsGrid->SetColSize( 2, 110 );
m_cursorsGrid->SetColSize( 3, 110 );
m_cursorsGrid->EnableDragColMove( false );
m_cursorsGrid->EnableDragColSize( true );
m_cursorsGrid->SetColLabelValue( 0, _("Cursor") );
m_cursorsGrid->SetColLabelValue( 1, _("Signal") );
m_cursorsGrid->SetColLabelValue( 2, _("Time") );
m_cursorsGrid->SetColLabelValue( 3, _("Voltage / Current") );
m_cursorsGrid->SetColLabelSize( -1 );
m_cursorsGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_cursorsGrid->EnableDragRowSize( true );
m_cursorsGrid->SetRowLabelSize( 0 );
m_cursorsGrid->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_cursorsGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP );
bSizer12->Add( m_cursorsGrid, 1, wxEXPAND, 5 );
m_panelCursors->SetSizer( bSizer12 ); m_panelCursors->SetSizer( bSizer12 );
@ -149,12 +219,12 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
m_tunePanel->Layout(); m_tunePanel->Layout();
bSizer13->Fit( m_tunePanel ); bSizer13->Fit( m_tunePanel );
m_splitterTuneValues->SplitHorizontally( m_panelCursors, m_tunePanel, 0 ); m_splitterTuneValues->SplitHorizontally( m_panelCursors, m_tunePanel, 0 );
bSizer9->Add( m_splitterTuneValues, 1, wxEXPAND, 5 ); bCursorsSizer->Add( m_splitterTuneValues, 1, wxEXPAND, 5 );
m_panelCursorsAndTune->SetSizer( bSizer9 ); m_panelCursorsAndTune->SetSizer( bCursorsSizer );
m_panelCursorsAndTune->Layout(); m_panelCursorsAndTune->Layout();
bSizer9->Fit( m_panelCursorsAndTune ); bCursorsSizer->Fit( m_panelCursorsAndTune );
m_splitterSignals->SplitHorizontally( m_panelSignals, m_panelCursorsAndTune, 0 ); m_splitterSignals->SplitHorizontally( m_panelSignals, m_panelCursorsAndTune, 0 );
m_sideSizer->Add( m_splitterSignals, 1, wxEXPAND, 5 ); m_sideSizer->Add( m_splitterSignals, 1, wxEXPAND, 5 );
@ -176,9 +246,10 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotChanged ), NULL, this ); m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotChanged ), NULL, this );
m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClose ), NULL, this ); m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClose ), NULL, this );
m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClosed ), NULL, this ); m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClosed ), NULL, this );
m_signals->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( SIM_PLOT_FRAME_BASE::onSignalDblClick ), NULL, this ); m_filter->Connect( wxEVT_MOTION, wxMouseEventHandler( SIM_PLOT_FRAME_BASE::OnFilterMouseMoved ), NULL, this );
m_signals->Connect( wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, wxListEventHandler( SIM_PLOT_FRAME_BASE::onSignalRClick ), NULL, this ); m_filter->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::OnFilterText ), NULL, this );
m_cursors->Connect( wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, wxListEventHandler( SIM_PLOT_FRAME_BASE::onCursorRClick ), NULL, this ); m_signalsGrid->Connect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( SIM_PLOT_FRAME_BASE::onSignalsGridCellChanged ), NULL, this );
m_cursorsGrid->Connect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( SIM_PLOT_FRAME_BASE::onCursorsGridCellChanged ), NULL, this );
} }
SIM_PLOT_FRAME_BASE::~SIM_PLOT_FRAME_BASE() SIM_PLOT_FRAME_BASE::~SIM_PLOT_FRAME_BASE()
@ -188,8 +259,9 @@ SIM_PLOT_FRAME_BASE::~SIM_PLOT_FRAME_BASE()
m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotChanged ), NULL, this ); m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotChanged ), NULL, this );
m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClose ), NULL, this ); m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClose ), NULL, this );
m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClosed ), NULL, this ); m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClosed ), NULL, this );
m_signals->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( SIM_PLOT_FRAME_BASE::onSignalDblClick ), NULL, this ); m_filter->Disconnect( wxEVT_MOTION, wxMouseEventHandler( SIM_PLOT_FRAME_BASE::OnFilterMouseMoved ), NULL, this );
m_signals->Disconnect( wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, wxListEventHandler( SIM_PLOT_FRAME_BASE::onSignalRClick ), NULL, this ); m_filter->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::OnFilterText ), NULL, this );
m_cursors->Disconnect( wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, wxListEventHandler( SIM_PLOT_FRAME_BASE::onCursorRClick ), NULL, this ); m_signalsGrid->Disconnect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( SIM_PLOT_FRAME_BASE::onSignalsGridCellChanged ), NULL, this );
m_cursorsGrid->Disconnect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( SIM_PLOT_FRAME_BASE::onCursorsGridCellChanged ), NULL, this );
} }

View File

@ -731,75 +731,23 @@
<property name="window_style">wxTAB_TRAVERSAL</property> <property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="1"> <object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">bSizer10</property> <property name="name">bSignalsSizer</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="0"> <object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxTOP|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<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">Signals</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_staticTextSignals</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="0">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND</property> <property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bFiltersSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">1</property> <property name="proportion">1</property>
<object class="wxListCtrl" expanded="0"> <object class="wxSearchCtrl" expanded="1">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -810,6 +758,7 @@
<property name="aui_row"></property> <property name="aui_row"></property>
<property name="best_size"></property> <property name="best_size"></property>
<property name="bg"></property> <property name="bg"></property>
<property name="cancel_button">1</property>
<property name="caption"></property> <property name="caption"></property>
<property name="caption_visible">1</property> <property name="caption_visible">1</property>
<property name="center_pane">0</property> <property name="center_pane">0</property>
@ -834,7 +783,7 @@
<property name="minimize_button">0</property> <property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property> <property name="minimum_size">-1,-1</property>
<property name="moveable">1</property> <property name="moveable">1</property>
<property name="name">m_signals</property> <property name="name">m_filter</property>
<property name="pane_border">1</property> <property name="pane_border">1</property>
<property name="pane_position"></property> <property name="pane_position"></property>
<property name="pane_size"></property> <property name="pane_size"></property>
@ -842,21 +791,114 @@
<property name="pin_button">1</property> <property name="pin_button">1</property>
<property name="pos"></property> <property name="pos"></property>
<property name="resize">Resizable</property> <property name="resize">Resizable</property>
<property name="search_button">1</property>
<property name="show">1</property> <property name="show">1</property>
<property name="size"></property> <property name="size"></property>
<property name="style">wxLC_NO_HEADER|wxLC_REPORT|wxLC_SINGLE_SEL</property> <property name="style"></property>
<property name="subclass">wxListView; </property> <property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property> <property name="toolbar_pane">0</property>
<property name="tooltip"></property> <property name="tooltip"></property>
<property name="validator_data_type"></property> <property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property> <property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property> <property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property> <property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<event name="OnLeftDClick">onSignalDblClick</event> <event name="OnMotion">OnFilterMouseMoved</event>
<event name="OnListItemRightClick">onSignalRClick</event> <event name="OnText">OnFilterText</event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxGrid" 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="autosize_cols">0</property>
<property name="autosize_rows">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="cell_bg"></property>
<property name="cell_font"></property>
<property name="cell_horiz_alignment">wxALIGN_LEFT</property>
<property name="cell_text"></property>
<property name="cell_vert_alignment">wxALIGN_TOP</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size">-1</property>
<property name="col_label_values">&quot;Signal&quot; &quot;Plot&quot; &quot;Color&quot; &quot;Cursor 1&quot; &quot;Cursor 2&quot;</property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">5</property>
<property name="column_sizes">196,50,50,54,54</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_col_move">0</property>
<property name="drag_col_size">1</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">1</property>
<property name="editing">1</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="grid_line_color"></property>
<property name="grid_lines">1</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label_bg"></property>
<property name="label_font"></property>
<property name="label_text"></property>
<property name="margin_height">0</property>
<property name="margin_width">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_signalsGrid</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="row_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="row_label_size">0</property>
<property name="row_label_values"></property>
<property name="row_label_vert_alignment">wxALIGN_CENTER</property>
<property name="row_sizes"></property>
<property name="rows">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">WX_GRID; widgets/wx_grid.h; 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>
<event name="OnGridCellChange">onSignalsGridCellChanged</event>
</object> </object>
</object> </object>
</object> </object>
@ -916,7 +958,7 @@
<property name="window_style">wxTAB_TRAVERSAL</property> <property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="1"> <object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">bSizer9</property> <property name="name">bCursorsSizer</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
@ -1037,11 +1079,11 @@
<property name="name">bSizer12</property> <property name="name">bSizer12</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="0"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxTOP|wxRIGHT</property> <property name="flag">wxEXPAND</property>
<property name="proportion">0</property> <property name="proportion">1</property>
<object class="wxStaticText" expanded="0"> <object class="wxGrid" expanded="1">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -1050,27 +1092,50 @@
<property name="aui_name"></property> <property name="aui_name"></property>
<property name="aui_position"></property> <property name="aui_position"></property>
<property name="aui_row"></property> <property name="aui_row"></property>
<property name="autosize_cols">0</property>
<property name="autosize_rows">0</property>
<property name="best_size"></property> <property name="best_size"></property>
<property name="bg"></property> <property name="bg"></property>
<property name="caption"></property> <property name="caption"></property>
<property name="caption_visible">1</property> <property name="caption_visible">1</property>
<property name="cell_bg"></property>
<property name="cell_font"></property>
<property name="cell_horiz_alignment">wxALIGN_LEFT</property>
<property name="cell_text"></property>
<property name="cell_vert_alignment">wxALIGN_TOP</property>
<property name="center_pane">0</property> <property name="center_pane">0</property>
<property name="close_button">1</property> <property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size">-1</property>
<property name="col_label_values">&quot;Cursor&quot; &quot;Signal&quot; &quot;Time&quot; &quot;Voltage / Current&quot;</property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">4</property>
<property name="column_sizes">44,140,110,110</property>
<property name="context_help"></property> <property name="context_help"></property>
<property name="context_menu">1</property> <property name="context_menu">1</property>
<property name="default_pane">0</property> <property name="default_pane">0</property>
<property name="dock">Dock</property> <property name="dock">Dock</property>
<property name="dock_fixed">0</property> <property name="dock_fixed">0</property>
<property name="docking">Left</property> <property name="docking">Left</property>
<property name="drag_col_move">0</property>
<property name="drag_col_size">1</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">1</property>
<property name="editing">1</property>
<property name="enabled">1</property> <property name="enabled">1</property>
<property name="fg"></property> <property name="fg"></property>
<property name="floatable">1</property> <property name="floatable">1</property>
<property name="font"></property> <property name="font"></property>
<property name="grid_line_color"></property>
<property name="grid_lines">1</property>
<property name="gripper">0</property> <property name="gripper">0</property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">Cursors</property> <property name="label_bg"></property>
<property name="markup">0</property> <property name="label_font"></property>
<property name="label_text"></property>
<property name="margin_height">0</property>
<property name="margin_width">0</property>
<property name="max_size"></property> <property name="max_size"></property>
<property name="maximize_button">0</property> <property name="maximize_button">0</property>
<property name="maximum_size"></property> <property name="maximum_size"></property>
@ -1078,7 +1143,7 @@
<property name="minimize_button">0</property> <property name="minimize_button">0</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="moveable">1</property> <property name="moveable">1</property>
<property name="name">m_staticTextCursors</property> <property name="name">m_cursorsGrid</property>
<property name="pane_border">1</property> <property name="pane_border">1</property>
<property name="pane_position"></property> <property name="pane_position"></property>
<property name="pane_size"></property> <property name="pane_size"></property>
@ -1086,79 +1151,21 @@
<property name="pin_button">1</property> <property name="pin_button">1</property>
<property name="pos"></property> <property name="pos"></property>
<property name="resize">Resizable</property> <property name="resize">Resizable</property>
<property name="row_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="row_label_size">0</property>
<property name="row_label_values"></property>
<property name="row_label_vert_alignment">wxALIGN_CENTER</property>
<property name="row_sizes"></property>
<property name="rows">0</property>
<property name="show">1</property> <property name="show">1</property>
<property name="size"></property> <property name="size"></property>
<property name="style"></property> <property name="subclass">WX_GRID; widgets/wx_grid.h; forward_declare</property>
<property name="subclass">; forward_declare</property>
<property name="toolbar_pane">0</property> <property name="toolbar_pane">0</property>
<property name="tooltip"></property> <property name="tooltip"></property>
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<property name="wrap">-1</property> <event name="OnGridCellChange">onCursorsGridCellChanged</event>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxListCtrl" expanded="0">
<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="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">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_cursors</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">wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnListItemRightClick">onCursorRClick</event>
</object> </object>
</object> </object>
</object> </object>

View File

@ -11,7 +11,7 @@
#include <wx/xrc/xmlres.h> #include <wx/xrc/xmlres.h>
#include <wx/intl.h> #include <wx/intl.h>
class ACTION_TOOLBAR; class ACTION_TOOLBAR;
class wxListView; class WX_GRID;
#include "sim_workbook.h" #include "sim_workbook.h"
#include "kiway_player.h" #include "kiway_player.h"
@ -27,8 +27,9 @@ class wxListView;
#include <wx/panel.h> #include <wx/panel.h>
#include <wx/textctrl.h> #include <wx/textctrl.h>
#include <wx/splitter.h> #include <wx/splitter.h>
#include <wx/srchctrl.h>
#include <wx/grid.h>
#include <wx/stattext.h> #include <wx/stattext.h>
#include <wx/listctrl.h>
#include <wx/frame.h> #include <wx/frame.h>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -58,13 +59,12 @@ class SIM_PLOT_FRAME_BASE : public KIWAY_PLAYER
wxBoxSizer* m_sideSizer; wxBoxSizer* m_sideSizer;
wxSplitterWindow* m_splitterSignals; wxSplitterWindow* m_splitterSignals;
wxPanel* m_panelSignals; wxPanel* m_panelSignals;
wxStaticText* m_staticTextSignals; wxSearchCtrl* m_filter;
wxListView* m_signals; WX_GRID* m_signalsGrid;
wxPanel* m_panelCursorsAndTune; wxPanel* m_panelCursorsAndTune;
wxSplitterWindow* m_splitterTuneValues; wxSplitterWindow* m_splitterTuneValues;
wxPanel* m_panelCursors; wxPanel* m_panelCursors;
wxStaticText* m_staticTextCursors; WX_GRID* m_cursorsGrid;
wxListCtrl* m_cursors;
wxPanel* m_tunePanel; wxPanel* m_tunePanel;
wxStaticText* m_staticTextTune; wxStaticText* m_staticTextTune;
wxBoxSizer* m_tuneSizer; wxBoxSizer* m_tuneSizer;
@ -74,9 +74,10 @@ class SIM_PLOT_FRAME_BASE : public KIWAY_PLAYER
virtual void onPlotChanged( wxAuiNotebookEvent& event ) { event.Skip(); } virtual void onPlotChanged( wxAuiNotebookEvent& event ) { event.Skip(); }
virtual void onPlotClose( wxAuiNotebookEvent& event ) { event.Skip(); } virtual void onPlotClose( wxAuiNotebookEvent& event ) { event.Skip(); }
virtual void onPlotClosed( wxAuiNotebookEvent& event ) { event.Skip(); } virtual void onPlotClosed( wxAuiNotebookEvent& event ) { event.Skip(); }
virtual void onSignalDblClick( wxMouseEvent& event ) { event.Skip(); } virtual void OnFilterMouseMoved( wxMouseEvent& event ) { event.Skip(); }
virtual void onSignalRClick( wxListEvent& event ) { event.Skip(); } virtual void OnFilterText( wxCommandEvent& event ) { event.Skip(); }
virtual void onCursorRClick( wxListEvent& event ) { event.Skip(); } virtual void onSignalsGridCellChanged( wxGridEvent& event ) { event.Skip(); }
virtual void onCursorsGridCellChanged( wxGridEvent& event ) { event.Skip(); }
public: public:

View File

@ -134,6 +134,9 @@ public:
m_unit( unit ) m_unit( unit )
{}; {};
wxString GetUnits() const { return m_unit; }
private:
void formatLabels() override void formatLabels() override
{ {
double maxVis = parent::AbsVisibleMaxValue(); double maxVis = parent::AbsVisibleMaxValue();
@ -175,6 +178,9 @@ public:
m_unit( unit ) m_unit( unit )
{}; {};
wxString GetUnits() const { return m_unit; }
private:
void formatLabels() override void formatLabels() override
{ {
wxString suffix; wxString suffix;
@ -196,24 +202,35 @@ private:
}; };
void CURSOR::Plot( wxDC& aDC, mpWindow& aWindow ) void CURSOR::SetCoordX( double aValue )
{ {
if( !m_window ) wxRealPoint oldCoords = m_coords;
m_window = &aWindow;
if( !m_visible ) doSetCoordX( aValue );
return; m_updateRequired = false;
m_updateRef = true;
const auto& dataX = m_trace->GetDataX(); if( m_window )
const auto& dataY = m_trace->GetDataY(); {
wxRealPoint delta = m_coords - oldCoords;
mpInfoLayer::Move( wxPoint( m_window->x2p( m_trace->x2s( delta.x ) ),
m_window->y2p( m_trace->y2s( delta.y ) ) ) );
m_window->Refresh();
}
}
void CURSOR::doSetCoordX( double aValue )
{
m_coords.x = aValue;
const std::vector<double>& dataX = m_trace->GetDataX();
const std::vector<double>& dataY = m_trace->GetDataY();
if( dataX.size() <= 1 ) if( dataX.size() <= 1 )
return; return;
if( m_updateRequired )
{
m_coords.x = m_trace->s2x( aWindow.p2x( m_dim.x ) );
// Find the closest point coordinates // Find the closest point coordinates
auto maxXIt = std::upper_bound( dataX.begin(), dataX.end(), m_coords.x ); auto maxXIt = std::upper_bound( dataX.begin(), dataX.end(), m_coords.x );
int maxIdx = maxXIt - dataX.begin(); int maxIdx = maxXIt - dataX.begin();
@ -240,6 +257,20 @@ void CURSOR::Plot( wxDC& aDC, mpWindow& aWindow )
// Linear interpolation // Linear interpolation
m_coords.y = leftY + ( rightY - leftY ) / ( rightX - leftX ) * ( m_coords.x - leftX ); m_coords.y = leftY + ( rightY - leftY ) / ( rightX - leftX ) * ( m_coords.x - leftX );
}
void CURSOR::Plot( wxDC& aDC, mpWindow& aWindow )
{
if( !m_window )
m_window = &aWindow;
if( !m_visible || m_trace->GetDataX().size() <= 1 )
return;
if( m_updateRequired )
{
doSetCoordX( m_trace->s2x( aWindow.p2x( m_dim.x ) ) );
m_updateRequired = false; m_updateRequired = false;
// Notify the parent window about the changes // Notify the parent window about the changes
@ -339,6 +370,20 @@ SIM_PLOT_PANEL::~SIM_PLOT_PANEL()
} }
wxString SIM_PLOT_PANEL::GetUnitsX() const
{
LOG_SCALE<mpScaleXLog>* logScale = dynamic_cast<LOG_SCALE<mpScaleXLog>*>( m_axis_x );
LIN_SCALE<mpScaleX>* linScale = dynamic_cast<LIN_SCALE<mpScaleX>*>( m_axis_x );
if( logScale )
return logScale->GetUnits();
else if( linScale )
return linScale->GetUnits();
else
return wxEmptyString;
}
void SIM_PLOT_PANEL::updateAxes() void SIM_PLOT_PANEL::updateAxes()
{ {
bool skipAddToView = false; bool skipAddToView = false;
@ -497,9 +542,12 @@ void SIM_PLOT_PANEL::UpdatePlotColors()
// Update color of all traces // Update color of all traces
for( auto& [ name, trace ] : m_traces ) for( auto& [ name, trace ] : m_traces )
{ {
if( CURSOR* cursor = trace->GetCursor() ) for( auto& [ id, cursor ] : trace->GetCursors() )
{
if( cursor )
cursor->SetPen( wxPen( m_colors.GetPlotColor( SIM_PLOT_COLORS::COLOR_SET::CURSOR ) ) ); cursor->SetPen( wxPen( m_colors.GetPlotColor( SIM_PLOT_COLORS::COLOR_SET::CURSOR ) ) );
} }
}
m_plotWin->UpdateAll(); m_plotWin->UpdateAll();
} }
@ -523,7 +571,7 @@ void SIM_PLOT_PANEL::UpdateTraceStyle( TRACE* trace )
bool SIM_PLOT_PANEL::addTrace( const wxString& aTitle, const wxString& aName, int aPoints, bool SIM_PLOT_PANEL::addTrace( const wxString& aTitle, const wxString& aName, int aPoints,
const double* aX, const double* aY, SIM_PLOT_TYPE aType ) const double* aX, const double* aY, SIM_TRACE_TYPE aType )
{ {
TRACE* trace = nullptr; TRACE* trace = nullptr;
@ -609,8 +657,11 @@ bool SIM_PLOT_PANEL::deleteTrace( const wxString& aName )
TRACE* trace = it->second; TRACE* trace = it->second;
m_traces.erase( it ); m_traces.erase( it );
if( CURSOR* cursor = trace->GetCursor() ) for( auto& [ id, cursor ] : trace->GetCursors() )
{
if( cursor )
m_plotWin->DelLayer( cursor, true ); m_plotWin->DelLayer( cursor, true );
}
m_plotWin->DelLayer( trace, true, true ); m_plotWin->DelLayer( trace, true, true );
ResetScales(); ResetScales();
@ -622,30 +673,32 @@ bool SIM_PLOT_PANEL::deleteTrace( const wxString& aName )
} }
void SIM_PLOT_PANEL::EnableCursor( const wxString& aName, bool aEnable ) void SIM_PLOT_PANEL::EnableCursor( const wxString& aName, int aCursorId, bool aEnable )
{ {
TRACE* t = GetTrace( aName ); TRACE* t = GetTrace( aName );
if( t == nullptr || t->HasCursor() == aEnable ) if( t == nullptr || t->HasCursor( aCursorId ) == aEnable )
return; return;
if( aEnable ) if( aEnable )
{ {
CURSOR* c = new CURSOR( t, this ); CURSOR* cursor = new CURSOR( t, this );
int plotCenter = GetPlotWin()->GetMarginLeft() mpWindow* win = GetPlotWin();
+ ( GetPlotWin()->GetXScreen() - GetPlotWin()->GetMarginLeft() int width = win->GetXScreen() - win->GetMarginLeft() - win->GetMarginRight();
- GetPlotWin()->GetMarginRight() ) int center = win->GetMarginLeft() + KiROUND( width * ( aCursorId == 1 ? 0.4 : 0.6 ) );
/ 2;
c->SetX( plotCenter ); cursor->SetName( aName );
c->SetPen( wxPen( m_colors.GetPlotColor( SIM_PLOT_COLORS::COLOR_SET::CURSOR ) ) ); cursor->SetX( center );
t->SetCursor( c ); cursor->SetPen( wxPen( m_colors.GetPlotColor( SIM_PLOT_COLORS::COLOR_SET::CURSOR ) ) );
m_plotWin->AddLayer( c );
t->SetCursor( aCursorId, cursor );
m_plotWin->AddLayer( cursor );
} }
else else
{ {
CURSOR* c = t->GetCursor(); CURSOR* cursor = t->GetCursor( aCursorId );
t->SetCursor( nullptr ); t->SetCursor( aCursorId, nullptr );
m_plotWin->DelLayer( c, true ); m_plotWin->DelLayer( cursor, true );
} }
// Notify the parent window about the changes // Notify the parent window about the changes

View File

@ -84,6 +84,11 @@ public:
return m_coords; return m_coords;
} }
void SetCoordX( double aValue );
private:
void doSetCoordX( double aValue );
private: private:
const TRACE* m_trace; const TRACE* m_trace;
bool m_updateRequired; bool m_updateRequired;
@ -98,9 +103,8 @@ private:
class TRACE : public mpFXYVector class TRACE : public mpFXYVector
{ {
public: public:
TRACE( const wxString& aName, SIM_PLOT_TYPE aType ) : TRACE( const wxString& aName, SIM_TRACE_TYPE aType ) :
mpFXYVector( aName ), mpFXYVector( aName ),
m_cursor( nullptr ),
m_type( aType ) m_type( aType )
{ {
SetContinuity( true ); SetContinuity( true );
@ -116,8 +120,11 @@ public:
*/ */
void SetData( const std::vector<double>& aX, const std::vector<double>& aY ) override void SetData( const std::vector<double>& aX, const std::vector<double>& aY ) override
{ {
if( m_cursor ) for( auto& [ idx, cursor ] : m_cursors )
m_cursor->Update(); {
if( cursor )
cursor->Update();
}
mpFXYVector::SetData( aX, aY ); mpFXYVector::SetData( aX, aY );
} }
@ -132,27 +139,32 @@ public:
return m_ys; return m_ys;
} }
bool HasCursor() const bool HasCursor( int aCursorId )
{ {
return m_cursor != nullptr; return m_cursors[ aCursorId ] != nullptr;
} }
void SetCursor( CURSOR* aCursor ) void SetCursor( int aCursorId, CURSOR* aCursor )
{ {
m_cursor = aCursor; m_cursors[ aCursorId ] = aCursor;
} }
CURSOR* GetCursor() const CURSOR* GetCursor( int aCursorId )
{ {
return m_cursor; return m_cursors[ aCursorId ];
} }
SIM_PLOT_TYPE GetType() const std::map<int, CURSOR*>& GetCursors()
{
return m_cursors;
}
SIM_TRACE_TYPE GetType() const
{ {
return m_type; return m_type;
} }
void SetTraceColour( wxColour aColour ) void SetTraceColour( const wxColour& aColour )
{ {
m_traceColour = aColour; m_traceColour = aColour;
} }
@ -169,8 +181,8 @@ public:
protected: protected:
CURSOR* m_cursor; std::map<int, CURSOR*> m_cursors; // No ownership; the mpWindow owns the CURSORs
SIM_PLOT_TYPE m_type; SIM_TRACE_TYPE m_type;
wxColour m_traceColour; wxColour m_traceColour;
private: private:
@ -192,19 +204,21 @@ public:
wxString GetLabelX() const wxString GetLabelX() const
{ {
return m_axis_x ? m_axis_x->GetName() : ""; return m_axis_x ? m_axis_x->GetName() : wxS( "" );
} }
wxString GetLabelY1() const wxString GetLabelY1() const
{ {
return m_axis_y1 ? m_axis_y1->GetName() : ""; return m_axis_y1 ? m_axis_y1->GetName() : wxS( "" );
} }
wxString GetLabelY2() const wxString GetLabelY2() const
{ {
return m_axis_y2 ? m_axis_y2->GetName() : ""; return m_axis_y2 ? m_axis_y2->GetName() : wxS( "" );
} }
wxString GetUnitsX() const;
bool TraceShown( const wxString& aName ) const bool TraceShown( const wxString& aName ) const
{ {
return m_traces.count( aName ) > 0; return m_traces.count( aName ) > 0;
@ -269,7 +283,7 @@ public:
} }
///< Toggle cursor for a particular trace. ///< Toggle cursor for a particular trace.
void EnableCursor( const wxString& aName, bool aEnable ); void EnableCursor( const wxString& aName, int aCursorId, bool aEnable );
///< Reset scale ranges to fit the current traces. ///< Reset scale ranges to fit the current traces.
void ResetScales(); void ResetScales();
@ -290,7 +304,7 @@ public:
protected: protected:
bool addTrace( const wxString& aTitle, const wxString& aName, int aPoints, const double* aX, bool addTrace( const wxString& aTitle, const wxString& aName, int aPoints, const double* aX,
const double* aY, SIM_PLOT_TYPE aType ); const double* aY, SIM_TRACE_TYPE aType );
bool deleteTrace( const wxString& aName ); bool deleteTrace( const wxString& aName );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016 CERN * Copyright (C) 2016 CERN
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* *
@ -43,7 +43,7 @@ enum SIM_TYPE
}; };
///< Possible plot types ///< Possible plot types
enum SIM_PLOT_TYPE enum SIM_TRACE_TYPE
{ {
// Y axis // Y axis
SPT_VOLTAGE = 0x01, SPT_VOLTAGE = 0x01,

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2021 Mikołaj Wielgus <wielgusmikolaj@gmail.com> * Copyright (C) 2021 Mikołaj Wielgus <wielgusmikolaj@gmail.com>
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -89,7 +89,7 @@ bool SIM_WORKBOOK::DeletePage( size_t page )
bool SIM_WORKBOOK::AddTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aTitle, bool SIM_WORKBOOK::AddTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aTitle,
const wxString& aName, int aPoints, const double* aX, const double* aY, const wxString& aName, int aPoints, const double* aX, const double* aY,
SIM_PLOT_TYPE aType ) SIM_TRACE_TYPE aType )
{ {
if( aPoints && aPlotPanel->addTrace( aTitle, aName, aPoints, aX, aY, aType ) ) if( aPoints && aPlotPanel->addTrace( aTitle, aName, aPoints, aX, aY, aType ) )
{ {

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2021 Mikołaj Wielgus <wielgusmikolaj@gmail.com> * Copyright (C) 2021 Mikołaj Wielgus <wielgusmikolaj@gmail.com>
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -49,7 +49,7 @@ public:
// Custom methods // Custom methods
bool AddTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aTitle, const wxString& aName, bool AddTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aTitle, const wxString& aName,
int aPoints, const double* aX, const double* aY, SIM_PLOT_TYPE aType ); int aPoints, const double* aX, const double* aY, SIM_TRACE_TYPE aType );
bool DeleteTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aName ); bool DeleteTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aName );
void SetSimCommand( SIM_PANEL_BASE* aPlotPanel, const wxString& aSimCommand ) void SetSimCommand( SIM_PANEL_BASE* aPlotPanel, const wxString& aSimCommand )

View File

@ -58,7 +58,6 @@ void SIM_PLOT_FRAME::ReCreateHToolbar()
m_toolBar->Add( ACTIONS::zoomFitScreen ); m_toolBar->Add( ACTIONS::zoomFitScreen );
m_toolBar->AddScaledSeparator( this ); m_toolBar->AddScaledSeparator( this );
m_toolBar->Add( EE_ACTIONS::addSignals );
m_toolBar->Add( EE_ACTIONS::simProbe ); m_toolBar->Add( EE_ACTIONS::simProbe );
m_toolBar->Add( EE_ACTIONS::simTune ); m_toolBar->Add( EE_ACTIONS::simTune );
@ -123,7 +122,6 @@ void SIM_PLOT_FRAME::doReCreateMenuBar()
simulationMenu->Add( EE_ACTIONS::runSimulation ); simulationMenu->Add( EE_ACTIONS::runSimulation );
simulationMenu->AppendSeparator(); simulationMenu->AppendSeparator();
simulationMenu->Add( EE_ACTIONS::addSignals );
simulationMenu->Add( EE_ACTIONS::simProbe ); simulationMenu->Add( EE_ACTIONS::simProbe );
simulationMenu->Add( EE_ACTIONS::simTune ); simulationMenu->Add( EE_ACTIONS::simTune );

View File

@ -962,12 +962,6 @@ TOOL_ACTION EE_ACTIONS::stopSimulation( "eeschema.Simulation.stopSimulation",
_( "Stop Simulation" ), "", _( "Stop Simulation" ), "",
BITMAPS::sim_stop ); BITMAPS::sim_stop );
TOOL_ACTION EE_ACTIONS::addSignals( "eeschema.Simulation.addSignals",
AS_GLOBAL,
'A', "",
_( "Add Signals..." ), "",
BITMAPS::sim_add_signal );
TOOL_ACTION EE_ACTIONS::simProbe( "eeschema.Simulation.probe", TOOL_ACTION EE_ACTIONS::simProbe( "eeschema.Simulation.probe",
AS_GLOBAL, AS_GLOBAL,
'P', "", 'P', "",

View File

@ -256,7 +256,6 @@ public:
static TOOL_ACTION simCommand; static TOOL_ACTION simCommand;
static TOOL_ACTION runSimulation; static TOOL_ACTION runSimulation;
static TOOL_ACTION stopSimulation; static TOOL_ACTION stopSimulation;
static TOOL_ACTION addSignals;
static TOOL_ACTION showNetlist; static TOOL_ACTION showNetlist;
// Net highlighting // Net highlighting

View File

@ -35,7 +35,6 @@
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/ee_actions.h> #include <tools/ee_actions.h>
#include <tools/simulator_control.h> #include <tools/simulator_control.h>
#include <dialogs/dialog_signal_list.h>
#include <scintilla_tricks.h> #include <scintilla_tricks.h>
@ -290,23 +289,6 @@ int SIMULATOR_CONTROL::RunSimulation( const TOOL_EVENT& aEvent )
} }
int SIMULATOR_CONTROL::AddSignals( const TOOL_EVENT& aEvent )
{
SIM_PLOT_PANEL* plotPanel = m_plotFrame->GetCurrentPlot();
if( !plotPanel || !m_circuitModel || plotPanel->GetType() != m_circuitModel->GetSimType() )
{
DisplayInfoMessage( m_plotFrame, _( "You need to run plot-providing simulation first." ) );
return -1;
}
DIALOG_SIGNAL_LIST dialog( m_plotFrame, m_circuitModel.get() );
dialog.ShowModal();
return 0;
}
int SIMULATOR_CONTROL::Probe( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::Probe( const TOOL_EVENT& aEvent )
{ {
if( m_schematicFrame == nullptr ) if( m_schematicFrame == nullptr )
@ -435,7 +417,6 @@ void SIMULATOR_CONTROL::setTransitions()
Go( &SIMULATOR_CONTROL::EditSimCommand, EE_ACTIONS::simCommand.MakeEvent() ); Go( &SIMULATOR_CONTROL::EditSimCommand, EE_ACTIONS::simCommand.MakeEvent() );
Go( &SIMULATOR_CONTROL::RunSimulation, EE_ACTIONS::runSimulation.MakeEvent() ); Go( &SIMULATOR_CONTROL::RunSimulation, EE_ACTIONS::runSimulation.MakeEvent() );
Go( &SIMULATOR_CONTROL::RunSimulation, EE_ACTIONS::stopSimulation.MakeEvent() ); Go( &SIMULATOR_CONTROL::RunSimulation, EE_ACTIONS::stopSimulation.MakeEvent() );
Go( &SIMULATOR_CONTROL::AddSignals, EE_ACTIONS::addSignals.MakeEvent() );
Go( &SIMULATOR_CONTROL::Probe, EE_ACTIONS::simProbe.MakeEvent() ); Go( &SIMULATOR_CONTROL::Probe, EE_ACTIONS::simProbe.MakeEvent() );
Go( &SIMULATOR_CONTROL::Tune, EE_ACTIONS::simTune.MakeEvent() ); Go( &SIMULATOR_CONTROL::Tune, EE_ACTIONS::simTune.MakeEvent() );

View File

@ -67,7 +67,6 @@ public:
int EditSimCommand( const TOOL_EVENT& aEvent ); int EditSimCommand( const TOOL_EVENT& aEvent );
int RunSimulation( const TOOL_EVENT& aEvent ); int RunSimulation( const TOOL_EVENT& aEvent );
int AddSignals( const TOOL_EVENT& aEvent );
int Probe( const TOOL_EVENT& aEvent ); int Probe( const TOOL_EVENT& aEvent );
int Tune( const TOOL_EVENT& aEvent ); int Tune( const TOOL_EVENT& aEvent );

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2015-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2015-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -177,7 +177,8 @@ protected:
enum COMBINED_MATCHER_CONTEXT enum COMBINED_MATCHER_CONTEXT
{ {
CTX_LIBITEM, CTX_LIBITEM,
CTX_NETCLASS CTX_NETCLASS,
CTX_SIGNAL
}; };

View File

@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE( VectorToSignal )
{ {
std::string vector; std::string vector;
wxString signal; wxString signal;
SIM_PLOT_TYPE type; SIM_TRACE_TYPE type;
}; };
std::vector<struct TEST_DATA> testData = { std::vector<struct TEST_DATA> testData = {
@ -190,7 +190,7 @@ BOOST_AUTO_TEST_CASE( VectorToSignal )
for( auto& step : testData ) for( auto& step : testData )
{ {
wxString outputSignalName; wxString outputSignalName;
SIM_PLOT_TYPE retVal; SIM_TRACE_TYPE retVal;
retVal = m_exporter.VectorToSignal( step.vector, outputSignalName ); retVal = m_exporter.VectorToSignal( step.vector, outputSignalName );