LIB_ID FOOTPRINT_EDIT_FRAME::GetLoadedFPID() const { MODULE* module = GetBoard()->m_Modules; if( module ) return LIB_ID( module->GetFPID().GetLibNickname(), m_footprintNameWhenLoaded ); else return LIB_ID(); }
bool FOOTPRINT_EDIT_FRAME::saveFootprintInLibrary( MODULE* aModule, const wxString& aLibraryName ) { try { aModule->SetFPID( LIB_ID( wxEmptyString, aModule->GetFPID().GetLibItemName() ) ); Prj().PcbFootprintLibs()->FootprintSave( aLibraryName, aModule ); aModule->SetFPID( LIB_ID( aLibraryName, aModule->GetFPID().GetLibItemName() ) ); return true; } catch( const IO_ERROR& ioe ) { DisplayError( this, ioe.What() ); aModule->SetFPID( LIB_ID( aLibraryName, aModule->GetFPID().GetLibItemName() ) ); return false; } }
void LIB_EDIT_FRAME::OnPasteDuplicatePart( wxCommandEvent& aEvent ) { int dummyUnit; LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit ); wxString lib = libId.GetLibNickname(); if( !m_libMgr->LibraryExists( lib ) ) return; LIB_PART* srcPart = nullptr; LIB_PART* newPart = nullptr; if( aEvent.GetId() == ID_LIBEDIT_DUPLICATE_PART ) { srcPart = m_libMgr->GetBufferedPart( libId.GetLibItemName(), lib ); newPart = new LIB_PART( *srcPart ); } else if( aEvent.GetId() == ID_LIBEDIT_PASTE_PART ) { auto clipboard = wxTheClipboard; wxClipboardLocker clipboardLock( clipboard ); if( !clipboardLock || ! clipboard->IsSupported( wxDF_TEXT ) ) return; wxTextDataObject data; clipboard->GetData( data ); wxString partSource = data.GetText(); STRING_LINE_READER reader( TO_UTF8( partSource ), "Clipboard" ); try { reader.ReadLine(); newPart = SCH_LEGACY_PLUGIN::ParsePart( reader ); } catch( IO_ERROR& e ) { wxLogError( wxString::Format( "Malformed clipboard: %s" ), GetChars( e.What() ) ); return; } } else wxFAIL; if( !newPart ) return; fixDuplicateAliases( newPart, lib ); m_libMgr->UpdatePart( newPart, lib ); SyncLibraries( false ); m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newPart->GetName() ) ); delete newPart; }
void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event ) { wxString cmp_name; LIB_ALIAS* libEntry = NULL; m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); if( GetScreen()->IsModify() && !IsOK( this, _( "The current component is not saved.\n\nDiscard current changes?" ) ) ) return; PART_LIB* lib = GetCurLib(); // No current lib, ask user for the library to use. if( !lib ) { SelectActiveLibrary(); lib = GetCurLib(); if( !lib ) return; } // Get the name of the current part to preselect it LIB_PART* current_part = GetCurPart(); wxString part_name = current_part ? current_part->GetName() : wxString( wxEmptyString ); wxArrayString dummyHistoryList; int dummyLastUnit; SCHLIB_FILTER filter; filter.LoadFrom( lib->GetName() ); cmp_name = SelectComponentFromLibrary( &filter, dummyHistoryList, dummyLastUnit, true, NULL, NULL, part_name ); if( cmp_name.IsEmpty() ) return; GetScreen()->ClrModify(); m_lastDrawItem = m_drawItem = NULL; // Delete previous library component, if any SetCurPart( NULL ); m_aliasName.Empty(); // Load the new library component libEntry = lib->FindAlias( cmp_name ); PART_LIB* searchLib = lib; if( !libEntry ) { // Not found in the active library: search inside the full list // (can happen when using Viewlib to load a component) libEntry = Prj().SchLibs()->FindLibraryAlias( LIB_ID( wxEmptyString, cmp_name ) ); if( libEntry ) { searchLib = libEntry->GetLib(); // The entry to load is not in the active lib // Ask for a new active lib wxString msg = _( "The selected component is not in the active library." ); msg += "\n\n"; msg += _( "Do you want to change the active library?" ); if( IsOK( this, msg ) ) SelectActiveLibrary( searchLib ); } } if( !libEntry ) { wxString msg = wxString::Format( _( "Part name '%s' not found in library '%s'" ), GetChars( cmp_name ), GetChars( searchLib->GetName() ) ); DisplayError( this, msg ); return; } PART_LIB* old = SetCurLib( searchLib ); LoadComponentFromCurrentLib( libEntry ); SetCurLib( old ); DisplayLibInfos(); }
MODULE* CreateMicrowaveInductor( PCB_EDIT_FRAME* aPcbFrame, wxString& aErrorMessage ) { /* Build a microwave inductor footprint. * - Length Mself.lng * - Extremities Mself.m_Start and Mself.m_End * We must determine: * Mself.nbrin = number of segments perpendicular to the direction * (The coil nbrin will demicercles + 1 + 2 1 / 4 circle) * Mself.lbrin = length of a strand * Mself.radius = radius of rounded parts of the coil * Mself.delta = segments extremities connection between him and the coil even * * The equations are * Mself.m_Size.x = 2 * Mself.radius + Mself.lbrin * Mself.m_Size.y * Mself.delta = 2 + 2 * Mself.nbrin * Mself.radius * Mself.lng = 2 * Mself.delta / / connections to the coil + (Mself.nbrin-2) * Mself.lbrin / / length of the strands except 1st and last + (Mself.nbrin 1) * (PI * Mself.radius) / / length of rounded * Mself.lbrin + / 2 - Melf.radius * 2) / / length of 1st and last bit * * The constraints are: * Nbrin >= 2 * Mself.radius < Mself.m_Size.x * Mself.m_Size.y = Mself.radius * 4 + 2 * Mself.raccord * Mself.lbrin> Mself.radius * 2 * * The calculation is conducted in the following way: * Initially: * Nbrin = 2 * Radius = 4 * m_Size.x (arbitrarily fixed value) * Then: * Increasing the number of segments to the desired length * (Radius decreases if necessary) */ D_PAD* pad; int ll; wxString msg; wxASSERT( s_inductor_pattern.m_Flag ); s_inductor_pattern.m_Flag = false; wxPoint pt = s_inductor_pattern.m_End - s_inductor_pattern.m_Start; int min_len = KiROUND( EuclideanNorm( pt ) ); s_inductor_pattern.m_length = min_len; // Enter the desired length. msg = StringFromValue( g_UserUnit, s_inductor_pattern.m_length ); wxTextEntryDialog dlg( NULL, wxEmptyString, _( "Length of Trace:" ), msg ); if( dlg.ShowModal() != wxID_OK ) return NULL; // canceled by user msg = dlg.GetValue(); s_inductor_pattern.m_length = ValueFromString( g_UserUnit, msg ); // Control values (ii = minimum length) if( s_inductor_pattern.m_length < min_len ) { aErrorMessage = _( "Requested length < minimum length" ); return NULL; } // Calculate the elements. std::vector <wxPoint> buffer; ll = BuildCornersList_S_Shape( buffer, s_inductor_pattern.m_Start, s_inductor_pattern.m_End, s_inductor_pattern.m_length, s_inductor_pattern.m_Width ); if( !ll ) { aErrorMessage = _( "Requested length too large" ); return NULL; } // Generate footprint. the value is also used as footprint name. msg.Empty(); wxTextEntryDialog cmpdlg( NULL, wxEmptyString, _( "Component Value:" ), msg ); cmpdlg.SetTextValidator( FILE_NAME_CHAR_VALIDATOR( &msg ) ); if( ( cmpdlg.ShowModal() != wxID_OK ) || msg.IsEmpty() ) return NULL; // Aborted by user MODULE* module = aPcbFrame->CreateNewModule( msg ); // here the module is already in the BOARD, CreateNewModule() does that. module->SetFPID( LIB_ID( std::string( "mw_inductor" ) ) ); module->SetAttributes( MOD_VIRTUAL | MOD_CMS ); module->ClearFlags(); module->SetPosition( s_inductor_pattern.m_End ); // Generate segments for( unsigned jj = 1; jj < buffer.size(); jj++ ) { EDGE_MODULE* PtSegm; PtSegm = new EDGE_MODULE( module ); PtSegm->SetStart( buffer[jj - 1] ); PtSegm->SetEnd( buffer[jj] ); PtSegm->SetWidth( s_inductor_pattern.m_Width ); PtSegm->SetLayer( module->GetLayer() ); PtSegm->SetShape( S_SEGMENT ); PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() ); PtSegm->SetEnd0( PtSegm->GetEnd() - module->GetPosition() ); module->GraphicalItems().PushBack( PtSegm ); } // Place a pad on each end of coil. pad = new D_PAD( module ); module->Pads().PushFront( pad ); pad->SetPadName( wxT( "1" ) ); pad->SetPosition( s_inductor_pattern.m_End ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); pad->SetSize( wxSize( s_inductor_pattern.m_Width, s_inductor_pattern.m_Width ) ); pad->SetLayerSet( LSET( module->GetLayer() ) ); pad->SetAttribute( PAD_ATTRIB_SMD ); pad->SetShape( PAD_SHAPE_CIRCLE ); D_PAD* newpad = new D_PAD( *pad ); module->Pads().Insert( newpad, pad->Next() ); pad = newpad; pad->SetPadName( wxT( "2" ) ); pad->SetPosition( s_inductor_pattern.m_Start ); pad->SetPos0( pad->GetPosition() - module->GetPosition() ); // Modify text positions. wxPoint refPos( ( s_inductor_pattern.m_Start.x + s_inductor_pattern.m_End.x ) / 2, ( s_inductor_pattern.m_Start.y + s_inductor_pattern.m_End.y ) / 2 ); wxPoint valPos = refPos; refPos.y -= module->Reference().GetSize().y; module->Reference().SetPosition( refPos ); valPos.y += module->Value().GetSize().y; module->Value().SetPosition( valPos ); module->CalculateBoundingBox(); return module; }
void LIB_EDIT_FRAME::savePartAs() { LIB_ID old_lib_id = getTargetLibId(); wxString old_name = old_lib_id.GetLibItemName(); wxString old_lib = old_lib_id.GetLibNickname(); LIB_PART* part = m_libMgr->GetBufferedPart( old_name, old_lib ); if( part ) { SYMBOL_LIB_TABLE* tbl = Prj().SchSymbolLibTable(); wxArrayString headers; std::vector< wxArrayString > itemsToDisplay; std::vector< wxString > libNicknames = tbl->GetLogicalLibs(); headers.Add( _( "Nickname" ) ); headers.Add( _( "Description" ) ); for( const auto& name : libNicknames ) { wxArrayString item; item.Add( name ); item.Add( tbl->GetDescription( name ) ); itemsToDisplay.push_back( item ); } EDA_LIST_DIALOG dlg( this, _( "Save Copy of Symbol" ), headers, itemsToDisplay, old_lib, nullptr, nullptr, /* sort */ false, /* show headers */ false ); dlg.SetListLabel( _( "Save in library:" ) ); dlg.SetOKLabel( _( "Save" ) ); wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL ); wxStaticText* label = new wxStaticText( &dlg, wxID_ANY, _( "Name:" ), wxDefaultPosition, wxDefaultSize, 0 ); bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); wxTextCtrl* nameTextCtrl = new wxTextCtrl( &dlg, wxID_ANY, old_name, wxDefaultPosition, wxDefaultSize, 0 ); bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); wxSizer* mainSizer = dlg.GetSizer(); mainSizer->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 ); // Move nameTextCtrl to the head of the tab-order if( dlg.GetChildren().DeleteObject( nameTextCtrl ) ) dlg.GetChildren().Insert( nameTextCtrl ); dlg.SetInitialFocus( nameTextCtrl ); dlg.Layout(); mainSizer->Fit( &dlg ); if( dlg.ShowModal() != wxID_OK ) return; // canceled by user wxString new_lib = dlg.GetTextSelection(); if( new_lib.IsEmpty() ) { DisplayError( NULL, _( "No library specified. Symbol could not be saved." ) ); return; } wxString new_name = nameTextCtrl->GetValue(); new_name.Trim( true ); new_name.Trim( false ); new_name.Replace( " ", "_" ); if( new_name.IsEmpty() ) { DisplayError( NULL, _( "No symbol name specified. Symbol could not be saved." ) ); return; } // Test if there is a component with this name already. if( m_libMgr->PartExists( new_name, new_lib ) ) { wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ), new_name, new_lib ); DisplayError( this, msg ); return; } LIB_PART new_part( *part ); new_part.SetName( new_name ); fixDuplicateAliases( &new_part, new_lib ); m_libMgr->UpdatePart( &new_part, new_lib ); SyncLibraries( false ); m_treePane->GetLibTree()->SelectLibId( LIB_ID( new_lib, new_part.GetName() ) ); if( isCurrentPart( old_lib_id ) ) loadPart( new_name, new_lib, m_unit ); } }
bool FOOTPRINT_EDIT_FRAME::SaveFootprintAs( MODULE* aModule ) { if( aModule == NULL ) return false; FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs(); SetMsgPanel( aModule ); wxString libraryName = aModule->GetFPID().GetLibNickname(); wxString footprintName = aModule->GetFPID().GetLibItemName(); bool updateValue = ( aModule->GetValue() == footprintName ); wxArrayString headers; std::vector<wxArrayString> itemsToDisplay; std::vector<wxString> nicknames = tbl->GetLogicalLibs(); headers.Add( _( "Nickname" ) ); headers.Add( _( "Description" ) ); for( unsigned i = 0; i < nicknames.size(); i++ ) { wxArrayString item; item.Add( nicknames[i] ); item.Add( tbl->GetDescription( nicknames[i] ) ); itemsToDisplay.push_back( item ); } EDA_LIST_DIALOG dlg( this, FMT_SAVE_MODULE, headers, itemsToDisplay, libraryName, nullptr, nullptr, /* sort */ false, /* show headers */ false ); dlg.SetListLabel( _( "Save in library:" ) ); dlg.SetOKLabel( _( "Save" ) ); wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL ); wxStaticText* label = new wxStaticText( &dlg, wxID_ANY, _( "Name:" ), wxDefaultPosition, wxDefaultSize, 0 ); bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); wxTextCtrl* nameTextCtrl = new wxTextCtrl( &dlg, wxID_ANY, footprintName, wxDefaultPosition, wxDefaultSize, 0 ); bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); wxTextValidator nameValidator( wxFILTER_EXCLUDE_CHAR_LIST ); nameValidator.SetCharExcludes( MODULE::StringLibNameInvalidChars( false ) ); nameTextCtrl->SetValidator( nameValidator ); wxSizer* mainSizer = dlg.GetSizer(); mainSizer->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 ); // Move nameTextCtrl to the head of the tab-order if( dlg.GetChildren().DeleteObject( nameTextCtrl ) ) dlg.GetChildren().Insert( nameTextCtrl ); dlg.SetInitialFocus( nameTextCtrl ); dlg.Layout(); mainSizer->Fit( &dlg ); if( dlg.ShowModal() != wxID_OK ) return false; // canceled by user libraryName = dlg.GetTextSelection(); if( libraryName.IsEmpty() ) { DisplayError( NULL, _( "No library specified. Footprint could not be saved." ) ); return false; } footprintName = nameTextCtrl->GetValue(); footprintName.Trim( true ); footprintName.Trim( false ); if( footprintName.IsEmpty() ) { DisplayError( NULL, _( "No footprint name specified. Footprint could not be saved." ) ); return false; } aModule->SetFPID( LIB_ID( libraryName, footprintName ) ); if( updateValue ) aModule->SetValue( footprintName ); // Legacy libraries are readable, but modifying legacy format is not allowed // So prompt the user if he try to add/replace a footprint in a legacy lib wxString libfullname = Prj().PcbFootprintLibs()->FindRow( libraryName )->GetFullURI(); IO_MGR::PCB_FILE_T piType = IO_MGR::GuessPluginTypeFromLibPath( libfullname ); if( piType == IO_MGR::LEGACY ) { DisplayInfoMessage( this, INFO_LEGACY_LIB_WARN_EDIT ); return false; } bool module_exists = tbl->FootprintExists( libraryName, footprintName ); if( module_exists ) { wxString msg = wxString::Format( _( "Footprint %s already exists in %s." ), footprintName, libraryName ); KIDIALOG chkdlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING ); chkdlg.SetOKLabel( _( "Overwrite" ) ); if( chkdlg.ShowModal() == wxID_CANCEL ) return false; } if( !saveFootprintInLibrary( aModule, libraryName ) ) return false; // Once saved-as a board footprint is no longer a board footprint aModule->SetLink( 0 ); wxString fmt = module_exists ? _( "Component \"%s\" replaced in \"%s\"" ) : _( "Component \"%s\" added in \"%s\"" ); wxString msg = wxString::Format( fmt, footprintName.GetData(), libraryName.GetData() ); SetStatusText( msg ); updateTitle(); return true; }
MODULE* FOOTPRINT_EDIT_FRAME::Import_Module( const wxString& aName ) { wxString lastOpenedPathForLoading = m_mruPath; wxConfigBase* cfg = Kiface().KifaceSettings(); if( cfg ) cfg->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading ); wxFileName fn; if( aName != wxT("") ) fn = aName; else fn = getFootprintFilenameFromUser( this, lastOpenedPathForLoading ); if( !fn.IsOk() ) return NULL; FILE* fp = wxFopen( fn.GetFullPath(), wxT( "rt" ) ); if( !fp ) { wxString msg = wxString::Format( FMT_FILE_NOT_FOUND, GetChars( fn.GetFullPath() ) ); DisplayError( this, msg ); return NULL; } if( cfg ) // Save file path { lastOpenedPathForLoading = fn.GetPath(); cfg->Write( EXPORT_IMPORT_LASTPATH_KEY, lastOpenedPathForLoading ); } wxString moduleName; IO_MGR::PCB_FILE_T fileType = detect_file_type( fp, fn.GetFullPath(), &moduleName ); if( fileType == IO_MGR::FILE_TYPE_NONE ) { DisplayError( this, FMT_NOT_MODULE ); return NULL; } MODULE* module = NULL; try { module = try_load_footprint( fn, fileType, moduleName ); if( !module ) { wxString msg = wxString::Format( FMT_MOD_NOT_FOUND, GetChars( moduleName ), GetChars( fn.GetFullPath() ) ); DisplayError( this, msg ); return NULL; } } catch( const IO_ERROR& ioe ) { DisplayError( this, ioe.What() ); // if the footprint is not loaded, exit. // However, even if an error happens, it can be loaded, because in KICAD and GPCB format, // a fp library is a set of separate files, and the error(s) are not necessary when // reading the selected file if( !module ) return NULL; } module->SetFPID( LIB_ID( wxEmptyString, moduleName ) ); // Insert footprint in list AddModuleToBoard( module ); // Display info : SetMsgPanel( module ); PlaceModule( module, NULL ); if( IsGalCanvasActive() ) module->SetPosition( wxPoint( 0, 0 ) ); GetBoard()->m_Status_Pcb = 0; GetBoard()->BuildListOfNets(); updateView(); return module; }
MODULE* PCB_BASE_FRAME::CreateNewModule( const wxString& aModuleName ) { // Creates a new footprint at position 0,0 which contains the minimal items: // the reference and the value. // Value : initialized to the footprint name. // put on fab layer (front side) // Reference : initialized to a default value (REF**). // put on silkscreen layer (front side) wxString moduleName = aModuleName; // Ask for the new module name if( moduleName.IsEmpty() ) { WX_TEXT_ENTRY_DIALOG dlg( this, FMT_MOD_REF, FMT_MOD_CREATE, moduleName ); dlg.SetTextValidator( FILE_NAME_CHAR_VALIDATOR( &moduleName ) ); if( dlg.ShowModal() != wxID_OK ) return NULL; //Aborted by user } moduleName.Trim( true ); moduleName.Trim( false ); if( moduleName.IsEmpty() ) { DisplayInfoMessage( this, FMT_NO_REF_ABORTED ); return NULL; } // Creates the new module and add it to the head of the linked list of modules MODULE* module = new MODULE( GetBoard() ); // Update parameters: timestamp ... module->SetLastEditTime(); // Update its name in lib module->SetFPID( LIB_ID( wxEmptyString, moduleName ) ); wxPoint default_pos; BOARD_DESIGN_SETTINGS& settings = GetDesignSettings(); // Update reference: if( settings.m_RefDefaultText.IsEmpty() ) module->SetReference( moduleName ); else module->SetReference( settings.m_RefDefaultText ); PCB_LAYER_ID layer = ToLAYER_ID( settings.m_RefDefaultlayer ); module->Reference().SetThickness( settings.GetTextThickness( layer ) ); module->Reference().SetTextSize( settings.GetTextSize( layer ) ); module->Reference().SetItalic( settings.GetTextItalic( layer ) ); module->Reference().SetKeepUpright( settings.GetTextUpright( layer ) ); default_pos.y = GetDesignSettings().GetTextSize( layer ).y / 2; module->Reference().SetPosition( default_pos ); module->Reference().SetLayer( layer ); module->Reference().SetVisible( settings.m_RefDefaultVisibility ); // Set the value field to a default value if( settings.m_ValueDefaultText.IsEmpty() ) module->SetValue( moduleName ); else module->SetValue( settings.m_ValueDefaultText ); layer = ToLAYER_ID( settings.m_ValueDefaultlayer ); module->Value().SetThickness( settings.GetTextThickness( layer ) ); module->Value().SetTextSize( settings.GetTextSize( layer ) ); module->Value().SetItalic( settings.GetTextItalic( layer ) ); module->Value().SetKeepUpright( settings.GetTextUpright( layer ) ); default_pos.y = -default_pos.y; module->Value().SetPosition( default_pos ); module->Value().SetLayer( layer ); module->Value().SetVisible( settings.m_ValueDefaultVisibility ); SetMsgPanel( module ); return module; }