void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event ) { wxSize size = m_cursors->GetClientSize(); SIM_PLOT_PANEL* plotPanel = CurrentPlot(); m_cursors->ClearAll(); if( !plotPanel ) return; if( m_signalsIconColorList ) m_cursors->SetImageList(m_signalsIconColorList, wxIMAGE_LIST_SMALL); // 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 labelY2 = plotPanel->GetLabelY2(); wxString labelY; if( !labelY2.IsEmpty() ) labelY = labelY1 + " / " + labelY2; else labelY = labelY1; const long Y_COL = m_cursors->AppendColumn( labelY, wxLIST_FORMAT_LEFT, size.x / 4 ); // Update cursor values int itemidx = 0; for( const auto& trace : plotPanel->GetTraces() ) { if( CURSOR* cursor = trace.second->GetCursor() ) { // Find the right icon color in list. // It is the icon used in m_signals list for the same trace long iconColor = m_signals->FindItem( -1, trace.first ); const wxRealPoint coords = cursor->GetCoords(); long idx = m_cursors->InsertItem( itemidx++, trace.first, iconColor ); m_cursors->SetItem( idx, X_COL, SPICE_VALUE( coords.x ).ToSpiceString() ); m_cursors->SetItem( idx, Y_COL, SPICE_VALUE( coords.y ).ToSpiceString() ); } } }
bool DIALOG_SPICE_MODEL::generatePowerSource( wxString& aTarget ) const { wxString acdc, trans; wxWindow* page = m_powerNotebook->GetCurrentPage(); bool useTrans = true; // shall we use the transient command part? // Variables for generic processing bool genericProcessing = false; unsigned int genericReqParamsCount = 0; std::vector<wxTextCtrl*> genericControls; /// DC / AC section // If SPICE_VALUE can be properly constructed, then it is a valid value try { if( !empty( m_genDc ) ) acdc += wxString::Format( "dc %s ", SPICE_VALUE( m_genDc->GetValue() ).ToSpiceString() ); } catch( ... ) { DisplayError( NULL, wxT( "Invalid DC value" ) ); return false; } try { if( !empty( m_genAcMag ) ) { acdc += wxString::Format( "ac %s ", SPICE_VALUE( m_genAcMag->GetValue() ).ToSpiceString() ); if( !empty( m_genAcPhase ) ) acdc += wxString::Format( "%s ", SPICE_VALUE( m_genAcPhase->GetValue() ).ToSpiceString() ); } } catch( ... ) { DisplayError( NULL, wxT( "Invalid AC magnitude or phase" ) ); return false; } /// Transient section if( page == m_pwrPulse ) { if( !m_pwrPulse->Validate() ) return false; genericProcessing = true; trans += "pulse"; genericReqParamsCount = 2; genericControls = { m_pulseInit, m_pulseNominal, m_pulseDelay, m_pulseRise, m_pulseFall, m_pulseWidth, m_pulsePeriod }; } else if( page == m_pwrSin ) { if( !m_pwrSin->Validate() ) return false; genericProcessing = true; trans += "sin"; genericReqParamsCount = 2; genericControls = { m_sinOffset, m_sinAmplitude, m_sinFreq, m_sinDelay, m_sinDampFactor }; } else if( page == m_pwrExp ) { if( !m_pwrExp->Validate() ) return false; genericProcessing = true; trans += "exp"; genericReqParamsCount = 2; genericControls = { m_expInit, m_expPulsed, m_expRiseDelay, m_expRiseConst, m_expFallDelay, m_expFallConst }; } else if( page == m_pwrPwl ) { if( m_pwlValList->GetItemCount() > 0 ) { trans += "pwl("; for( int i = 0; i < m_pwlValList->GetItemCount(); ++i ) { trans += wxString::Format( "%s %s ", m_pwlValList->GetItemText( i, m_pwlTimeCol ), m_pwlValList->GetItemText( i, m_pwlValueCol ) ); } trans.Trim(); trans += ")"; } } if( genericProcessing ) { trans += "("; auto first_empty = std::find_if( genericControls.begin(), genericControls.end(), empty ); auto first_not_empty = std::find_if( genericControls.begin(), genericControls.end(), []( const wxTextCtrl* c ){ return !empty( c ); } ); if( std::distance( first_not_empty, genericControls.end() ) == 0 ) { // all empty useTrans = false; } else if( std::distance( genericControls.begin(), first_empty ) < (int)genericReqParamsCount ) { DisplayError( nullptr, wxString::Format( wxT( "You need to specify at least the " "first %d parameters for the transient source" ), genericReqParamsCount ) ); return false; } else if( std::find_if_not( first_empty, genericControls.end(), empty ) != genericControls.end() ) { DisplayError( nullptr, wxT( "You cannot leave interleaved empty fields " "when defining a transient source" ) ); return false; } else { std::for_each( genericControls.begin(), first_empty, [&trans] ( wxTextCtrl* ctrl ) { trans += wxString::Format( "%s ", ctrl->GetValue() ); } ); } trans.Trim(); trans += ")"; } aTarget = acdc; if( useTrans ) aTarget += trans; // Remove whitespaces from left and right side aTarget.Trim( false ); aTarget.Trim( true ); return true; }
bool DIALOG_SPICE_MODEL::parsePowerSource( const wxString& aModel ) { if( aModel.IsEmpty() ) return false; wxStringTokenizer tokenizer( aModel, " ()" ); wxString tkn = tokenizer.GetNextToken().Lower(); while( tokenizer.HasMoreTokens() ) { // Variables used for generic values processing (filling out wxTextCtrls in sequence) bool genericProcessing = false; unsigned int genericReqParamsCount = 0; std::vector<wxTextCtrl*> genericControls; if( tkn == "dc" ) { // There might be an optional "dc" or "trans" directive, skip it if( tkn == "dc" || tkn == "trans" ) tkn = tokenizer.GetNextToken().Lower(); // DC value try { m_genDc->SetValue( SPICE_VALUE( tkn ).ToSpiceString() ); } catch( ... ) { return false; } } else if( tkn == "ac" ) { // AC magnitude try { tkn = tokenizer.GetNextToken().Lower(); m_genAcMag->SetValue( SPICE_VALUE( tkn ).ToSpiceString() ); } catch( ... ) { return false; } // AC phase (optional) try { tkn = tokenizer.GetNextToken().Lower(); m_genAcPhase->SetValue( SPICE_VALUE( tkn ).ToSpiceString() ); } catch( ... ) { continue; // perhaps another directive } } else if( tkn == "pulse" ) { m_powerNotebook->SetSelection( m_powerNotebook->FindPage( m_pwrPulse ) ); genericProcessing = true; genericReqParamsCount = 2; genericControls = { m_pulseInit, m_pulseNominal, m_pulseDelay, m_pulseRise, m_pulseFall, m_pulseWidth, m_pulsePeriod }; } else if( tkn == "sin" ) { m_powerNotebook->SetSelection( m_powerNotebook->FindPage( m_pwrSin ) ); genericProcessing = true; genericReqParamsCount = 2; genericControls = { m_sinOffset, m_sinAmplitude, m_sinFreq, m_sinDelay, m_sinDampFactor }; } else if( tkn == "exp" ) { m_powerNotebook->SetSelection( m_powerNotebook->FindPage( m_pwrExp ) ); genericProcessing = true; genericReqParamsCount = 2; genericControls = { m_expInit, m_expPulsed, m_expRiseDelay, m_expRiseConst, m_expFallDelay, m_expFallConst }; } else if( tkn == "pwl" ) { m_powerNotebook->SetSelection( m_powerNotebook->FindPage( m_pwrPwl ) ); try { while( tokenizer.HasMoreTokens() ) { tkn = tokenizer.GetNextToken(); SPICE_VALUE time( tkn ); tkn = tokenizer.GetNextToken(); SPICE_VALUE value( tkn ); addPwlValue( time.ToSpiceString(), value.ToSpiceString() ); } } catch( ... ) { return false; } } else { // Unhandled power source type wxASSERT_MSG( false, "Unhandled power source type" ); return false; } if( genericProcessing ) { try { for( unsigned int i = 0; i < genericControls.size(); ++i ) { // If there are no more tokens, let's check if we got at least required fields if( !tokenizer.HasMoreTokens() ) return ( i >= genericReqParamsCount ); tkn = tokenizer.GetNextToken().Lower(); genericControls[i]->SetValue( SPICE_VALUE( tkn ).ToSpiceString() ); } } catch( ... ) { return false; } } // Get the next token now, so if any of the branches catches an expection, try to // process it in another branch tkn = tokenizer.GetNextToken().Lower(); } return true; }